/** * @brief Show item description in bdef menu * @note it handles items in both slots and storage */ static void BDEF_SelectItem_f (void) { aircraftSlot_t* slot; installation_t* installation = INS_GetCurrentSelectedInstallation(); base_t* base = B_GetCurrentSelectedBase(); aircraftItemType_t bdefType; int slotIDX; int itemIDX; if (cgi->Cmd_Argc() < 4) { Com_Printf("Usage: %s <type> <slotIDX> <itemIDX>\n", cgi->Cmd_Argv(0)); return; } bdefType = BDEF_GetItemTypeFromID(cgi->Cmd_Argv(1)); slotIDX = atoi(cgi->Cmd_Argv(2)); itemIDX = atoi(cgi->Cmd_Argv(3)); if (bdefType == MAX_ACITEMS) { Com_Printf("BDEF_AddItem_f: Invalid defence type.\n"); return; } if (slotIDX >= 0) { const objDef_t* item; slot = (installation) ? BDEF_GetInstallationSlotByIDX(installation, bdefType, slotIDX) : BDEF_GetBaseSlotByIDX(base, bdefType, slotIDX); item = (slot) ? ( (slot->nextItem) ? slot->nextItem : slot->item ) : nullptr; UP_AircraftItemDescription(item); } else if (itemIDX >= 0) { technology_t** list; technology_t* itemTech = nullptr; int i = 0; slot = (installation) ? BDEF_GetInstallationSlotByIDX(installation, bdefType, 0) : BDEF_GetBaseSlotByIDX(base, bdefType, 0); list = AII_GetCraftitemTechsByType(bdefType); while (*list && i <= itemIDX) { if (AIM_SelectableCraftItem(slot, *list)) { itemTech = *list; i++; break; } list++; } UP_AircraftItemDescription((itemTech) ? INVSH_GetItemByIDSilent(itemTech->provides) : nullptr); } else { Com_Printf("BDEF_AddItem_f: Invalid item-space.\n"); } }
/** * @brief Select one entry on the list. * @sa BS_MarketScroll_f * @sa BS_AddToList */ static void BS_MarketClick_f (void) { int num; if (Cmd_Argc() < 2) { Com_Printf("Usage: %s <num>\n", Cmd_Argv(0)); return; } num = atoi(Cmd_Argv(1)); if (num >= buyList.length || num < 0) return; Cvar_Set("mn_item", ""); switch (buyCat) { case FILTER_AIRCRAFT: assert(buyList.l[num].aircraft); BS_MarketAircraftDescription(buyList.l[num].aircraft->tpl); break; case FILTER_CRAFTITEM: UP_AircraftItemDescription(buyList.l[num].item); Cvar_Set("mn_aircraftname", ""); break; case MAX_FILTERTYPES: break; default: if (buyList.l[num].item->craftitem.type != MAX_ACITEMS) UP_AircraftItemDescription(buyList.l[num].item); else INV_ItemDescription(buyList.l[num].item); currentSelectedMenuEntry = buyList.l[num].item; break; } /* update selected element */ UI_ExecuteConfunc("buy_selectitem %i", num); }
/** * @brief Update the item description according to the tech and the slot selected */ static void AIM_UpdateItemDescription (bool fromList, bool fromSlot) { int status; aircraft_t *aircraft; aircraftSlot_t *slot; base_t *base = B_GetCurrentSelectedBase(); assert(base); aircraft = base->aircraftCurrent; assert(aircraft); slot = AII_SelectAircraftSlot(aircraft, airequipID); /* update mini ufopedia */ /** @todo we should clone the text, and not using the ufopedia text */ if (fromList) UP_AircraftItemDescription(INVSH_GetItemByIDSilent(aimSelectedTechnology ? aimSelectedTechnology->provides : NULL)); else if (fromSlot) { if (airequipID == AC_ITEM_AMMO) UP_AircraftItemDescription(slot->ammo); else UP_AircraftItemDescription(slot->item); } /* update status */ status = AIM_CheckTechnologyIntoSlot(slot, aimSelectedTechnology); switch (status) { case AIM_LOADING_NOSLOTSELECTED: Cvar_Set("mn_aircraft_item_warning", _("No slot selected.")); break; case AIM_LOADING_NOTECHNOLOGYSELECTED: Cvar_Set("mn_aircraft_item_warning", _("No item selected.")); break; case AIM_LOADING_ALIENTECH: Cvar_Set("mn_aircraft_item_warning", _("You can't equip an alien technology.")); break; case AIM_LOADING_TECHNOLOGYNOTRESEARCHED: Cvar_Set("mn_aircraft_item_warning", _("Technology requested is not yet completed.")); break; case AIM_LOADING_TOOHEAVY: Cvar_Set("mn_aircraft_item_warning", _("This item is too heavy for the selected slot.")); break; case AIM_LOADING_NOWEAPON: Cvar_Set("mn_aircraft_item_warning", _("Equip a weapon first.")); break; case AIM_LOADING_NOTUSABLEWITHWEAPON: Cvar_Set("mn_aircraft_item_warning", _("Ammo not usable with current weapon.")); break; case AIM_LOADING_UNKNOWNPROBLEM: Cvar_Set("mn_aircraft_item_warning", _("Unknown problem.")); break; case AIM_LOADING_OK: Cvar_Set("mn_aircraft_item_warning", _("Ok")); break; } if (*Cvar_GetString("mn_item") == '\0') { cgi->UI_ExecuteConfunc("airequip_no_item"); } else { if (fromSlot) { cgi->UI_ExecuteConfunc("airequip_installed_item"); } else { if (status == AIM_LOADING_OK) cgi->UI_ExecuteConfunc("airequip_installable_item"); else cgi->UI_ExecuteConfunc("airequip_noinstallable_item"); } } }
/** * @brief Show information about item/aircaft/ugv in the market */ static void BS_ShowInfo_f (void) { const char* itemid; const aircraft_t* aircraft; const ugv_t* ugv; const objDef_t* od; if (cgi->Cmd_Argc() < 2) { cgi->Com_Printf("Usage: %s <item-id>\n", cgi->Cmd_Argv(0)); return; } itemid = cgi->Cmd_Argv(1); if (char const* const rest = Q_strstart(itemid, "aircraft_")) { /* PHALANX aircraft - with aircraft golbal idx */ int idx = atoi(rest); aircraft = AIR_AircraftGetFromIDX(idx); if (!aircraft) { cgi->Com_Printf("Invalid aircraft index!\n"); return; } /** @todo show specialized info about PHALANX aircraft */ BS_MarketAircraftDescription(aircraft->tpl); return; } if (char const* const rest = Q_strstart(itemid, "ugv-")) { /* PHALANX ugv - with unique character number index */ int ucn = atoi(rest); Employee* robot = E_GetEmployeeByTypeFromChrUCN(EMPL_ROBOT, ucn); if (!robot) { cgi->Com_Printf("Invalid UCN for UGV!\n"); return; } /** @todo show specialized info about PHLANX UGVs */ UP_UGVDescription(robot->getUGV()); return; } aircraft = AIR_GetAircraftSilent(itemid); if (aircraft) { BS_MarketAircraftDescription(aircraft->tpl); return; } ugv = cgi->Com_GetUGVByIDSilent(itemid); if (ugv) { UP_UGVDescription(ugv); return; } /* item */ od = INVSH_GetItemByID(cgi->Cmd_Argv(1)); if (od) { if (!BS_IsOnMarket(od)) return; if (od->craftitem.type != MAX_ACITEMS) UP_AircraftItemDescription(od); else cgi->INV_ItemDescription(od); return; } cgi->Com_Printf("Invalid item ID\n"); }
/** * @brief Display only the TEXT_UFOPEDIA part for a given technology * @param[in] tech The technology_t pointer to print the UFOpaedia article for * @param[in] mail The mail parameters in case we produce a mail * @sa UP_Article */ static void UP_Article (technology_t* tech, eventMail_t* mail) { UP_ChangeDisplay(UFOPEDIA_ARTICLE); if (tech) { if (tech->mdl) cgi->Cvar_Set("mn_upmodel_top", "%s", tech->mdl); else cgi->Cvar_Set("mn_upmodel_top", ""); if (tech->image) cgi->Cvar_Set("mn_upimage_top", "%s", tech->image); else cgi->Cvar_Set("mn_upimage_top", ""); cgi->Cvar_Set("mn_upmodel_bottom", ""); if (tech->type == RS_WEAPON) UP_DrawAssociatedAmmo(tech); cgi->Cvar_Set("mn_uprequirement", ""); cgi->Cvar_Set("mn_upmetadata", ""); } cgi->UI_ResetData(TEXT_UFOPEDIA); cgi->UI_ResetData(TEXT_UFOPEDIA_REQUIREMENT); if (mail) { /* event mail */ cgi->Cvar_SetValue("mn_uppreavailable", 0); cgi->Cvar_SetValue("mn_updisplay", UFOPEDIA_CHAPTERS); UP_SetMailHeader(nullptr, TECHMAIL_PRE, mail); cgi->UI_RegisterText(TEXT_UFOPEDIA, _(mail->body)); /* This allows us to use the index button in the UFOpaedia, * eventMails don't have any chapter to go back to. */ upDisplay = UFOPEDIA_INDEX; } else if (tech) { currentChapter = tech->upChapter; upCurrentTech = tech; /* Reset itemdescription */ cgi->UI_ExecuteConfunc("itemdesc_view 0 0;"); if (RS_IsResearched_ptr(tech)) { cgi->Cvar_Set("mn_uptitle", _("UFOpaedia: %s (complete)"), _(tech->name)); /* If researched -> display research text */ cgi->UI_RegisterText(TEXT_UFOPEDIA, _(RS_GetDescription(&tech->description))); if (tech->preDescription.numDescriptions > 0) { /* Display pre-research text and the buttons if a pre-research text is available. */ if (mn_uppretext->integer) { cgi->UI_RegisterText(TEXT_UFOPEDIA, _(RS_GetDescription(&tech->preDescription))); UP_SetMailHeader(tech, TECHMAIL_PRE, nullptr); } else { UP_SetMailHeader(tech, TECHMAIL_RESEARCHED, nullptr); } cgi->Cvar_SetValue("mn_uppreavailable", 1); } else { /* Do not display the pre-research-text button if none is available (no need to even bother clicking there). */ cgi->Cvar_SetValue("mn_uppreavailable", 0); cgi->Cvar_SetValue("mn_updisplay", UFOPEDIA_CHAPTERS); UP_SetMailHeader(tech, TECHMAIL_RESEARCHED, nullptr); } switch (tech->type) { case RS_ARMOUR: case RS_WEAPON: for (int i = 0; i < cgi->csi->numODs; i++) { const objDef_t* od = INVSH_GetItemByIDX(i); if (Q_streq(tech->provides, od->id)) { cgi->INV_ItemDescription(od); UP_DisplayTechTree(tech); cgi->Cvar_Set("mn_upmetadata", "1"); break; } } break; case RS_TECH: UP_DisplayTechTree(tech); break; case RS_CRAFT: UP_AircraftDescription(tech); break; case RS_CRAFTITEM: UP_AircraftItemDescription(INVSH_GetItemByID(tech->provides)); break; case RS_BUILDING: UP_BuildingDescription(tech); break; case RS_UGV: UP_UGVDescription(cgi->Com_GetUGVByIDSilent(tech->provides)); break; default: break; } /* see also UP_TechGetsDisplayed */ } else if (RS_Collected_(tech) || (tech->statusResearchable && tech->preDescription.numDescriptions > 0)) { /* This tech has something collected or has a research proposal. (i.e. pre-research text) */ cgi->Cvar_Set("mn_uptitle", _("UFOpaedia: %s"), _(tech->name)); /* Not researched but some items collected -> display pre-research text if available. */ if (tech->preDescription.numDescriptions > 0) { cgi->UI_RegisterText(TEXT_UFOPEDIA, _(RS_GetDescription(&tech->preDescription))); UP_SetMailHeader(tech, TECHMAIL_PRE, nullptr); } else { cgi->UI_RegisterText(TEXT_UFOPEDIA, _("No pre-research description available.")); } } else { cgi->Cvar_Set("mn_uptitle", _("UFOpaedia: %s"), _(tech->name)); cgi->UI_ResetData(TEXT_UFOPEDIA); } } else { cgi->Com_Error(ERR_DROP, "UP_Article: No mail or tech given"); } }
/** * @brief Updates the Buy/Sell menu list. * @param[in] base Pointer to the base to buy/sell at * @sa BS_BuyType_f */ static void BS_BuyType (const base_t *base) { const objDef_t *od; int i, j = 0; char tmpbuf[MAX_VAR]; if (!base || buyCat >= MAX_FILTERTYPES || buyCat < 0) return; CP_UpdateCredits(ccs.credits); bsMarketNames = NULL; bsMarketStorage = NULL; bsMarketMarket = NULL; bsMarketPrices = NULL; UI_ResetData(TEXT_ITEMDESCRIPTION); /* hide autosell checkboxes by default */ for (i = 0; i < MAX_MARKET_MENU_ENTRIES; i++) { UI_ExecuteConfunc("buy_autoselli %i", i); } switch (buyCat) { case FILTER_AIRCRAFT: /* Aircraft */ { const aircraft_t *aircraftTemplate; for (i = 0, j = 0, aircraftTemplate = ccs.aircraftTemplates; i < ccs.numAircraftTemplates; i++, aircraftTemplate++) { if (!BS_AircraftIsOnMarket(aircraftTemplate)) continue; assert(aircraftTemplate->tech); if (BS_GetStorageAmountInBase(base, aircraftTemplate->id) + BS_GetAircraftOnMarket(aircraftTemplate) > 0) { if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) { UI_ExecuteConfunc("buy_show %i", j - buyList.scroll); } BS_AddToList(aircraftTemplate->name, BS_GetStorageAmountInBase(base, aircraftTemplate->id), BS_GetAircraftOnMarket(aircraftTemplate), BS_GetAircraftBuyingPrice(aircraftTemplate)); if (j >= MAX_BUYLIST) Com_Error(ERR_DROP, "Increase the MAX_BUYLIST value to handle that much items\n"); buyList.l[j].item = NULL; buyList.l[j].aircraft = aircraftTemplate; buyList.length = j + 1; BS_UpdateItem(base, j - buyList.scroll); j++; } } } break; case FILTER_CRAFTITEM: /* Aircraft items */ /* get item list */ for (i = 0, j = 0, od = csi.ods; i < csi.numODs; i++, od++) { if (!BS_IsOnMarket(od)) continue; /* Check whether the item matches the proper filter, storage in current base and market. */ if ((B_ItemInBase(od, base) || ccs.eMarket.numItems[i]) && INV_ItemMatchesFilter(od, FILTER_CRAFTITEM)) { if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) { const technology_t *tech = RS_GetTechForItem(od); UI_ExecuteConfunc("buy_show %i", j - buyList.scroll); if (RS_IsResearched_ptr(tech)) { if (ccs.eMarket.autosell[i]) UI_ExecuteConfunc("buy_autoselle %i", j - buyList.scroll); else UI_ExecuteConfunc("buy_autoselld %i", j - buyList.scroll); } } BS_AddToList(od->name, B_ItemInBase(od, base), ccs.eMarket.numItems[i], BS_GetItemBuyingPrice(od)); if (j >= MAX_BUYLIST) Com_Error(ERR_DROP, "Increase the MAX_FILTERLIST value to handle that much items\n"); buyList.l[j].item = od; buyList.l[j].aircraft = NULL; buyList.length = j + 1; BS_UpdateItem(base, j - buyList.scroll); j++; } } break; default: /* Normal items */ if (buyCat < MAX_SOLDIER_FILTERTYPES || buyCat == FILTER_DUMMY) { /* get item list */ for (i = 0, j = 0, od = csi.ods; i < csi.numODs; i++, od++) { if (!BS_IsOnMarket(od)) continue; /* Check whether the item matches the proper filter, storage in current base and market. */ if ((B_ItemInBase(od, base) || ccs.eMarket.numItems[i]) && INV_ItemMatchesFilter(od, buyCat)) { BS_AddToList(od->name, B_ItemInBase(od, base), ccs.eMarket.numItems[i], BS_GetItemBuyingPrice(od)); /* Set state of Autosell button. */ if (j >= buyList.scroll && j < MAX_MARKET_MENU_ENTRIES) { const technology_t *tech = RS_GetTechForItem(od); UI_ExecuteConfunc("buy_show %i", j - buyList.scroll); if (RS_IsResearched_ptr(tech)) { if (ccs.eMarket.autosell[i]) UI_ExecuteConfunc("buy_autoselle %i", j - buyList.scroll); else UI_ExecuteConfunc("buy_autoselld %i", j - buyList.scroll); } } if (j >= MAX_BUYLIST) Com_Error(ERR_DROP, "Increase the MAX_BUYLIST value to handle that much items\n"); buyList.l[j].item = od; buyList.l[j].aircraft = NULL; buyList.length = j + 1; BS_UpdateItem(base, j - buyList.scroll); j++; } } } break; } for (; j < MAX_MARKET_MENU_ENTRIES; j++) { /* Hide the rest of the entries. */ UI_ExecuteConfunc("buy_hide %i", j); } /* Update some menu cvars. */ /* Set up base capacities. */ Com_sprintf(tmpbuf, sizeof(tmpbuf), "%i/%i", CAP_GetCurrent(base, CAP_ITEMS), CAP_GetMax(base, CAP_ITEMS)); Cvar_Set("mn_bs_storage", tmpbuf); /* select first item */ if (buyList.length) { switch (buyCat) { /** @sa BS_MarketClick_f */ case FILTER_AIRCRAFT: BS_MarketAircraftDescription(buyList.l[0].aircraft); break; case FILTER_CRAFTITEM: Cvar_Set("mn_aircraftname", ""); /** @todo Use craftitem name here? See also BS_MarketClick_f */ /* Select current item or first one. */ if (currentSelectedMenuEntry) UP_AircraftItemDescription(currentSelectedMenuEntry); else UP_AircraftItemDescription(buyList.l[0].item); break; default: assert(buyCat != MAX_FILTERTYPES); /* Select current item or first one. */ if (currentSelectedMenuEntry) INV_ItemDescription(currentSelectedMenuEntry); else INV_ItemDescription(buyList.l[0].item); break; } } else { /* reset description */ INV_ItemDescription(NULL); } UI_RegisterLinkedListText(TEXT_MARKET_NAMES, bsMarketNames); UI_RegisterLinkedListText(TEXT_MARKET_STORAGE, bsMarketStorage); UI_RegisterLinkedListText(TEXT_MARKET_MARKET, bsMarketMarket); UI_RegisterLinkedListText(TEXT_MARKET_PRICES, bsMarketPrices); }