/** * @brief Run actions on finishing production of one item/aircraft/UGV.. * @param base The base to produce in * @param prod The production that is running */ static void PR_FinishProduction (base_t* base, production_t* prod) { const char* name = PR_GetName(&prod->data); technology_t* tech = PR_GetTech(&prod->data); prod->frame = 0; prod->amount--; if (PR_IsItem(prod)) { CP_UpdateCredits(ccs.credits - PR_GetPrice(prod->data.data.item)); /* Now add it to equipment and update capacity. */ B_AddToStorage(base, prod->data.data.item, 1); } else if (PR_IsAircraft(prod)) { CP_UpdateCredits(ccs.credits - PR_GetPrice(prod->data.data.aircraft)); /* Now add new aircraft. */ AIR_NewAircraft(base, prod->data.data.aircraft); } if (prod->amount > 0) return; Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Work on %s at %s has finished."), name, base->name); MSO_CheckAddNewMessage(NT_PRODUCTION_FINISHED, _("Production finished"), cp_messageBuffer, MSG_PRODUCTION, tech); /* queue the next production */ PR_QueueNext(base); }
/** * @brief Update storage, the market, and the player's credits * @note Don't update capacity here because we can sell items directly from aircraft (already removed from storage). */ static void BS_ProcessCraftItemSale (const objDef_t* craftitem, const int numItems) { if (craftitem) { BS_AddItemToMarket(craftitem, numItems); CP_UpdateCredits(ccs.credits + BS_GetItemSellingPrice(craftitem) * numItems); } }
/** * @brief Sells the given aircraft with all the equipment. * @param aircraft The aircraft to sell * @return @c true if the aircraft could get sold, @c false otherwise */ bool BS_SellAircraft (aircraft_t* aircraft) { int j; if (AIR_GetTeamSize(aircraft) > 0) return false; if (!AIR_IsAircraftInBase(aircraft)) return false; /* sell off any items which are mounted on it */ for (j = 0; j < aircraft->maxWeapons; j++) { const aircraftSlot_t* slot = &aircraft->weapons[j]; BS_ProcessCraftItemSale(slot->item, 1); BS_ProcessCraftItemSale(slot->ammo, 1); } BS_ProcessCraftItemSale(aircraft->shield.item, 1); /* there should be no ammo here, but checking can't hurt */ BS_ProcessCraftItemSale(aircraft->shield.ammo, 1); for (j = 0; j < aircraft->maxElectronics; j++) { const aircraftSlot_t* slot = &aircraft->electronics[j]; BS_ProcessCraftItemSale(slot->item, 1); /* there should be no ammo here, but checking can't hurt */ BS_ProcessCraftItemSale(slot->ammo, 1); } /* the capacities are also updated here */ BS_AddAircraftToMarket(aircraft, 1); CP_UpdateCredits(ccs.credits + BS_GetAircraftSellingPrice(aircraft)); AIR_DeleteAircraft(aircraft); return true; }
/** * @brief Buys the given UGV * @param[in] ugv The ugv template of the UGV to buy * @param[out] base Base to buy at * @return @c true if the ugv could get bought, @c false otherwise * @todo Implement this correctly once we have UGV */ bool BS_BuyUGV (const ugv_t* ugv, base_t* base) { const objDef_t* ugvWeapon; if (!ugv) cgi->Com_Error(ERR_DROP, "BS_BuyUGV: Called on nullptr UGV!"); if (!base) cgi->Com_Error(ERR_DROP, "BS_BuyUGV: Called on nullptr base!"); ugvWeapon = INVSH_GetItemByID(ugv->weapon); if (!ugvWeapon) cgi->Com_Error(ERR_DROP, "BS_BuyItem_f: Could not get weapon '%s' for ugv/tank '%s'.", ugv->weapon, ugv->id); if (ccs.credits < ugv->price) return false; if (E_CountUnhiredRobotsByType(ugv) <= 0) return false; if (BS_GetItemOnMarket(ugvWeapon) <= 0) return false; if (CAP_GetFreeCapacity(base, CAP_ITEMS) < UGV_SIZE + ugvWeapon->size) return false; if (!E_HireRobot(base, ugv)) return false; BS_RemoveItemFromMarket(ugvWeapon, 1); CP_UpdateCredits(ccs.credits - ugv->price); B_AddToStorage(base, ugvWeapon, 1); return true; }
/** * @brief Sells the given UGV with all the equipment. * @param robot The employee record of the UGV to sell * @return @c true if the ugv could get sold, @c false otherwise * @todo Implement this correctly once we have UGV */ bool BS_SellUGV (Employee* robot) { const objDef_t* ugvWeapon; const ugv_t* ugv; base_t* base; if (!robot) cgi->Com_Error(ERR_DROP, "Selling nullptr UGV!"); if (!robot->getUGV()) cgi->Com_Error(ERR_DROP, "Selling invalid UGV with UCN: %i", robot->chr.ucn); ugv = robot->getUGV(); base = robot->baseHired; /* Check if we have a weapon for this ugv in the market to sell it. */ ugvWeapon = INVSH_GetItemByID(ugv->weapon); if (!ugvWeapon) cgi->Com_Error(ERR_DROP, "BS_BuyItem_f: Could not get wepaon '%s' for ugv/tank '%s'.", ugv->weapon, ugv->id); if (!robot->unhire()) { /** @todo message - Couldn't fire employee. */ Com_DPrintf(DEBUG_CLIENT, "Couldn't sell/fire robot/ugv.\n"); return false; } BS_AddItemToMarket(ugvWeapon, 1); CP_UpdateCredits(ccs.credits + ugv->price); B_AddToStorage(base, ugvWeapon, -1); return true; }
/** * @brief Constructs a new installation. */ static void INS_BuildInstallation_f (void) { const installationTemplate_t* installationTemplate; if (cgi->Cmd_Argc() < 1) { Com_Printf("Usage: %s <installationType>\n", cgi->Cmd_Argv(0)); return; } /* We shouldn't build more installations than the actual limit */ if (B_GetInstallationLimit() <= INS_GetCount()) return; installationTemplate = INS_GetInstallationTemplateByID(cgi->Cmd_Argv(1)); if (!installationTemplate) { Com_Printf("The installation type %s passed for %s is not valid.\n", cgi->Cmd_Argv(1), cgi->Cmd_Argv(0)); return; } assert(installationTemplate->cost >= 0); if (ccs.credits - installationTemplate->cost > 0) { /* set up the installation */ installation_t* installation = INS_Build(installationTemplate, ccs.newBasePos, cgi->Cvar_GetString("mn_installation_title")); CP_UpdateCredits(ccs.credits - installationTemplate->cost); /* this cvar is used for disabling the installation build button on geoscape if MAX_INSTALLATIONS was reached */ cgi->Cvar_SetValue("mn_installation_count", INS_GetCount()); const nation_t* nation = GEO_GetNation(installation->pos); if (nation) Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("A new installation has been built: %s (nation: %s)"), installation->name, _(nation->name)); else Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("A new installation has been built: %s"), installation->name); MSO_CheckAddNewMessage(NT_INSTALLATION_BUILDSTART, _("Installation building"), cp_messageBuffer, MSG_CONSTRUCTION); } else { if (installationTemplate->type == INSTALLATION_RADAR) { if (GEO_IsRadarOverlayActivated()) GEO_SetOverlay("radar"); } if (ccs.mapAction == MA_NEWINSTALLATION) ccs.mapAction = MA_NONE; CP_Popup(_("Notice"), _("Not enough credits to set up a new installation.")); } ccs.mapAction = MA_NONE; }
/** * @brief Function to start UFO selling process. * @note Command to call this: cp_uforecovery_sell_start. */ static void UR_DialogStartSell_f (void) { int price = -1; const nation_t *nation; int i; if (!ufoRecovery.nation) return; nation = ufoRecovery.nation; i = UR_DialogGetCurrentNationIndex(); price = ufoRecovery.ufoNations[i].price; assert(price >= 0); #if 0 if (ufoRecovery.selectedStorage) { Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Sold previously recovered %s from %s to nation %s, gained %i credits."), UFO_TypeToName( ufoRecovery.selectedStorage->ufoTemplate->ufotype), ufoRecovery.selectedStorage->base->name, _(nation->name), price); } else #endif { Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Recovered %s from the battlefield. UFO sold to nation %s, gained %i credits."), UFO_GetName(ufoRecovery.ufoTemplate), _(nation->name), price); } MS_AddNewMessage(_("UFO Recovery"), cp_messageBuffer); CP_UpdateCredits(ccs.credits + price); /* update nation happiness */ for (i = 0; i < ccs.numNations; i++) { nation_t *nat = NAT_GetNationByIDX(i); float ufoHappiness; assert(nat); if (nat == nation) /* nation is happy because it got the UFO */ ufoHappiness = HAPPINESS_UFO_SALE_GAIN; else /* nation is unhappy because it wanted the UFO */ ufoHappiness = HAPPINESS_UFO_SALE_LOSS; NAT_SetHappiness(ccs.curCampaign->minhappiness, nat, nat->stats[0].happiness + ufoHappiness); } /* UFO recovery process is done, disable buttons. */ UR_DialogRecoveryDone(); }
void SetUp() { campaign_t* campaign; CP_ResetCampaignData(); CP_ParseCampaignData(); campaign = GetCampaign(); CP_ReadCampaignData(campaign); ResetInventoryList(); CP_UpdateCredits(MAX_CREDITS); GEO_Shutdown(); GEO_Init(campaign->map); ccs.curCampaign = campaign; }
/** * @brief Buys an aircraft * @param[in] aircraftTemplate The aircraft template to buy * @param[out] base Base to buy at * @return @c true if the aircraft could get bought, @c false otherwise */ bool BS_BuyAircraft (const aircraft_t* aircraftTemplate, base_t* base) { if (!base) cgi->Com_Error(ERR_DROP, "BS_BuyAircraft: No base given."); if (!aircraftTemplate) cgi->Com_Error(ERR_DROP, "BS_BuyAircraft: No aircraft template given."); int price = BS_GetAircraftBuyingPrice(aircraftTemplate); if (ccs.credits < price) return false; /* Hangar capacities are being updated in AIR_NewAircraft().*/ BS_RemoveAircraftFromMarket(aircraftTemplate, 1); CP_UpdateCredits(ccs.credits - price); AIR_NewAircraft(base, aircraftTemplate); return true; }
/** * @brief Sell one item of a given type. * @sa BS_BuyItem_f * @sa BS_SellAircraft_f * @sa BS_BuyAircraft_f */ static void BS_SellItem_f (void) { int num; base_t *base = B_GetCurrentSelectedBase(); if (Cmd_Argc() < 2) { Com_Printf("Usage: %s <num>\n", Cmd_Argv(0)); return; } if (!base) return; if (buyCat == FILTER_AIRCRAFT) { Com_DPrintf(DEBUG_CLIENT, "BS_SellItem_f: Redirects to BS_SellAircraft_f\n"); BS_SellAircraft_f(); return; } num = atoi(Cmd_Argv(1)); if (num < 0 || num >= buyList.length) return; UI_ExecuteConfunc("buy_selectitem %i", num + buyList.scroll); { const objDef_t *item = BS_GetObjectDefition(&buyList.l[num + buyList.scroll]); /* don't sell more items than we have */ const int numItems = min(B_ItemInBase(item, base), BS_GetBuySellFactor()); /* Normal item (or equipment for UGVs/Robots if buyCategory==BUY_HEAVY) */ assert(item); currentSelectedMenuEntry = item; INV_ItemDescription(item); /* don't sell more items than we have */ if (numItems) { /* reinit the menu */ B_UpdateStorageAndCapacity(base, item, -numItems, qfalse); BS_AddItemToMarket(item, numItems); BS_BuyType(base); CP_UpdateCredits(ccs.credits + BS_GetItemSellingPrice(item) * numItems); BS_UpdateItem(base, num); } } }
/** * @brief Constructs a new base. * @sa B_NewBase */ static void B_BuildBase_f (void) { const campaign_t* campaign = ccs.curCampaign; if (ccs.mapAction == MA_NEWBASE) ccs.mapAction = MA_NONE; if (ccs.credits - campaign->basecost > 0) { const nation_t* nation; const char* baseName = mn_base_title->string; base_t* base; /* there may be no " in the base name */ if (!Com_IsValidName(baseName)) baseName = _("Base"); base = B_Build(campaign, ccs.newBasePos, baseName); if (!base) cgi->Com_Error(ERR_DROP, "Cannot build base"); CP_UpdateCredits(ccs.credits - campaign->basecost); nation = GEO_GetNation(base->pos); if (nation) Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("A new base has been built: %s (nation: %s)"), mn_base_title->string, _(nation->name)); else Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("A new base has been built: %s"), mn_base_title->string); MS_AddNewMessage(_("Base built"), cp_messageBuffer, MSG_CONSTRUCTION); /* First base */ if (ccs.campaignStats.basesBuilt == 1) B_SetUpFirstBase(campaign, base); cgi->Cvar_SetValue("mn_base_count", B_GetCount()); B_SelectBase(base); } else { /** @todo Why is this needed? Also see bug #5401 */ if (GEO_IsRadarOverlayActivated()) GEO_SetOverlay("radar", 0); CP_PopupList(_("Notice"), _("Not enough credits to set up a new base.")); } }
/** * @brief Sells items from the market * @param[in] od pointer to the item (Object Definition record) * @param[out] base Base to sell at * @param[in ] count Number of items to sell * @return @c true if the ugv could get sold, @c false otherwise */ bool BS_SellItem (const objDef_t* od, base_t* base, int count) { if (!od) cgi->Com_Error(ERR_DROP, "BS_SellItem: Called on nullptr objDef!"); if (count <= 0) return false; if (!BS_IsOnMarket(od)) return false; if (base) { if (B_ItemInBase(od, base) < count) return false; B_AddToStorage(base, od, -count); } BS_AddItemToMarket(od, count); CP_UpdateCredits(ccs.credits + BS_GetItemSellingPrice(od) * count); return true; }
/** * @brief Buys items from the market * @param[in] od pointer to the item (Object Definition record) * @param[out] base Base to buy at * @param[in ] count Number of items to buy * @return @c true if the ugv could get bought, @c false otherwise */ bool BS_BuyItem (const objDef_t* od, base_t* base, int count) { if (!od) cgi->Com_Error(ERR_DROP, "BS_BuyItem: Called on nullptr objDef!"); if (!base) cgi->Com_Error(ERR_DROP, "BS_BuyItem: Called on nullptr base!"); if (count <= 0) return false; if (!BS_IsOnMarket(od)) return false; if (ccs.credits < BS_GetItemBuyingPrice(od) * count) return false; if (BS_GetItemOnMarket(od) < count) return false; if (CAP_GetFreeCapacity(base, CAP_ITEMS) < od->size * count) return false; B_AddToStorage(base, od, count); BS_RemoveItemFromMarket(od, count); CP_UpdateCredits(ccs.credits - BS_GetItemBuyingPrice(od) * count); return true; }
/** * @brief Initialises base. * @note This command is executed in the init node of the base menu. * It is called everytime the base menu pops up and sets the cvars. * @todo integrate building status tooltips from B_CheckBuildingStatusForMenu_f into this one */ static void B_BaseInit_f (void) { int i; base_t *base = B_GetCurrentSelectedBase(); if (!base) return; /* make sure the credits cvar is up-to-date */ CP_UpdateCredits(ccs.credits); cgi->Cvar_SetValue("mn_base_num_aircraft", AIR_BaseCountAircraft(base)); /* activate or deactivate the aircraft button */ if (AIR_AircraftAllowed(base)) { if (AIR_BaseHasAircraft(base)) cgi->UI_ExecuteConfunc("update_basebutton aircraft false \"%s\"", _("Aircraft management and crew equipment")); else cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("Buy or produce at least one aircraft first.")); } else { cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("No Hangar functional in base.")); } if (BS_BuySellAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton buysell false \"%s\"", _("Buy/Sell equipment, aircraft and UGV")); else cgi->UI_ExecuteConfunc("update_basebutton buysell true \"%s\"", va(_("No %s functional in base."), _("Storage"))); if (B_GetCount() > 1) cgi->UI_ExecuteConfunc("update_basebutton transfer false \"%s\"", _("Transfer equipment, vehicles, aliens and employees to other bases")); else cgi->UI_ExecuteConfunc("update_basebutton transfer true \"%s\"", _("Build at least a second base to transfer equipment or personnel")); if (RS_ResearchAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton research false \"%s\"", _("Research new technology")); else cgi->UI_ExecuteConfunc("update_basebutton research true \"%s\"", va(_("No %s functional in base."), _("Laboratory"))); if (PR_ProductionAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton production false \"%s\"", _("Produce equipment, aircraft and UGV")); else cgi->UI_ExecuteConfunc("update_basebutton production true \"%s\"", va(_("No %s functional in base."), _("Workshop"))); if (E_HireAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton hire false \"%s\"", _("Hire or dismiss employees")); else cgi->UI_ExecuteConfunc("update_basebutton hire true \"%s\"", va(_("No %s functional in base."), _("Living Quarters"))); if (AC_ContainmentAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton containment false \"%s\"", _("Manage captured aliens")); else cgi->UI_ExecuteConfunc("update_basebutton containment true \"%s\"", va(_("No %s functional in base."), _("Containment"))); if (HOS_HospitalAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton hospital false \"%s\"", _("Treat wounded soldiers and perform implant surgery")); else cgi->UI_ExecuteConfunc("update_basebutton hospital true \"%s\"", va(_("No %s functional in base."), _("Hospital"))); /* * Gather data on current/max space for living quarters, storage, lab and workshop * clear_bld_space ensures 0/0 data for facilities which may not exist in base */ cgi->UI_ExecuteConfunc("clear_bld_space"); for (i = 0; i < ccs.numBuildingTemplates; i++) { const building_t* b = &ccs.buildingTemplates[i]; const baseCapacities_t capType = B_GetCapacityFromBuildingType(b->buildingType); capacities_t cap; if (capType == MAX_CAP) continue; /* Check if building matches one of our four types */ if (b->buildingType != B_QUARTERS && b->buildingType != B_STORAGE && b->buildingType != B_WORKSHOP && b->buildingType != B_LAB && b->buildingType != B_ANTIMATTER) continue; /* only show already researched buildings */ if (!RS_IsResearched_ptr(b->tech)) continue; cap = *CAP_Get(base, capType); assert(b->tpl); const int count = B_GetNumberOfBuildingsInBaseByTemplate(base, b->tpl); if (count < 1) continue; cgi->UI_ExecuteConfunc("show_bld_space \"%s\" \"%s\" %i %i %i %i", _(b->name), b->id, cap.cur, cap.max, count, b->tpl->maxCount); } /* * Get the number of different employees in the base * @todo: Get the number of injured soldiers if hospital exists */ cgi->UI_ExecuteConfunc("current_employees %i %i %i %i", E_CountHired(base, EMPL_SOLDIER), E_CountHired(base, EMPL_PILOT), E_CountHired(base, EMPL_SCIENTIST), E_CountHired(base, EMPL_WORKER)); /* * List the first five aircraft in the base if they exist */ cgi->UI_ExecuteConfunc("clear_aircraft"); if (AIR_AircraftAllowed(base)) { if (AIR_BaseHasAircraft(base)) { i = 0; AIR_ForeachFromBase(aircraft, base) { if (i > 5) break; /* * UI node should use global IDX to identify aircraft but it uses order of aircraft in base (i) * See @todo in cp_aircraft_callbacks.c in AIR_AircraftSelect() */ cgi->UI_ExecuteConfunc("show_aircraft %i \"%s\" \"%s\" \"%s\" %i", i, aircraft->name, aircraft->id, AIR_AircraftStatusToName(aircraft), AIR_IsAircraftInBase(aircraft)); i++; } } } /* Get the research item closest to completion in the base if it exists */ cgi->UI_ExecuteConfunc("clear_research"); if (RS_ResearchAllowed(base)) { const technology_t *closestTech = NULL; double finished = -1; for (i = 0; i < ccs.numTechnologies; i++) { const technology_t *tech = RS_GetTechByIDX(i); if (!tech) continue; if (tech->base != base) continue; if (tech->statusResearch == RS_RUNNING) { const double percent = (1 - tech->time / tech->overallTime) * 100; if (percent > finished) { finished = percent; closestTech = tech; } } } if (closestTech != NULL) cgi->UI_ExecuteConfunc("show_research \"%s\" %i %3.0f", closestTech->name, closestTech->scientists, finished); } /* Get the production item closest to completion in the base if it exists */ cgi->UI_ExecuteConfunc("clear_production"); if (PR_ProductionAllowed(base)) { const production_queue_t *queue = PR_GetProductionForBase(base); if (queue->numItems > 0) { const production_t *production = &queue->items[0]; cgi->UI_ExecuteConfunc("show_production \"%s\" %3.0f", PR_GetName(&production->data), PR_GetProgress(production) * 100); } } }
/** * @brief Buys aircraft or craftitem. * @sa BS_SellAircraft_f */ static void BS_BuyAircraft_f (void) { int num; const aircraft_t *aircraftTemplate; base_t *base = B_GetCurrentSelectedBase(); if (Cmd_Argc() < 2) { Com_Printf("Usage: %s <num>\n", Cmd_Argv(0)); return; } if (!base) return; num = atoi(Cmd_Argv(1)); if (num < 0 || num >= buyList.length) return; if (buyCat == FILTER_AIRCRAFT) { int freeSpace; if (!B_GetBuildingStatus(base, B_COMMAND)) { CP_Popup(_("Note"), _("No command centre in this base.\nHangars are not functional.\n")); return; } /* We cannot buy aircraft if there is no power in our base. */ if (!B_GetBuildingStatus(base, B_POWER)) { CP_Popup(_("Note"), _("No power supplies in this base.\nHangars are not functional.")); return; } /* We cannot buy aircraft without any hangar. */ if (!AIR_AircraftAllowed(base)) { CP_Popup(_("Note"), _("Build a hangar first.")); return; } aircraftTemplate = buyList.l[num].aircraft; freeSpace = AIR_CalculateHangarStorage(aircraftTemplate, base, 0); /* Check free space in hangars. */ if (freeSpace < 0) { Com_Printf("BS_BuyAircraft_f: something bad happened, AIR_CalculateHangarStorage returned -1!\n"); return; } if (freeSpace == 0) { CP_Popup(_("Notice"), _("You cannot buy this aircraft.\nNot enough space in hangars.\n")); return; } else { const int price = BS_GetAircraftBuyingPrice(aircraftTemplate); if (ccs.credits < price) { CP_Popup(_("Notice"), _("You cannot buy this aircraft.\nNot enough credits.\n")); return; } else { /* Hangar capacities are being updated in AIR_NewAircraft().*/ BS_RemoveAircraftFromMarket(aircraftTemplate, 1); CP_UpdateCredits(ccs.credits - price); AIR_NewAircraft(base, aircraftTemplate); Cmd_ExecuteString(va("buy_type %s", INV_GetFilterType(FILTER_AIRCRAFT))); } } } }
/** * @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); }
/** * @brief Initialises base. * @note This command is executed in the init node of the base menu. * It is called everytime the base menu pops up and sets the cvars. * @todo integrate building status tooltips from B_CheckBuildingStatusForMenu_f into this one */ static void B_BaseInit_f (void) { base_t* base = B_GetCurrentSelectedBase(); if (!base) return; /* make sure the credits cvar is up-to-date */ CP_UpdateCredits(ccs.credits); /* activate or deactivate the aircraft button */ if (AIR_AircraftAllowed(base)) { if (AIR_BaseHasAircraft(base)) cgi->UI_ExecuteConfunc("update_basebutton aircraft false \"%s\"", _("Aircraft management and crew equipment")); else cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("Buy or produce at least one aircraft first.")); } else { cgi->UI_ExecuteConfunc("update_basebutton aircraft true \"%s\"", _("No Hangar functional in base.")); } if (BS_BuySellAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton buysell false \"%s\"", _("Buy/Sell equipment, aircraft and UGV")); else cgi->UI_ExecuteConfunc("update_basebutton buysell true \"%s\"", va(_("No %s functional in base."), _("Storage"))); if (B_GetCount() > 1) cgi->UI_ExecuteConfunc("update_basebutton transfer false \"%s\"", _("Transfer equipment, vehicles, aliens and employees to other bases")); else cgi->UI_ExecuteConfunc("update_basebutton transfer true \"%s\"", _("Build at least a second base to transfer equipment or personnel")); if (RS_ResearchAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton research false \"%s\"", _("Research new technology")); else cgi->UI_ExecuteConfunc("update_basebutton research true \"%s\"", va(_("No %s functional in base."), _("Laboratory"))); if (PR_ProductionAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton production false \"%s\"", _("Produce equipment, aircraft and UGV")); else cgi->UI_ExecuteConfunc("update_basebutton production true \"%s\"", va(_("No %s functional in base."), _("Workshop"))); if (E_HireAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton hire false \"%s\"", _("Hire or dismiss employees")); else cgi->UI_ExecuteConfunc("update_basebutton hire true \"%s\"", va(_("No %s functional in base."), _("Living Quarters"))); if (AC_ContainmentAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton containment false \"%s\"", _("Manage captured aliens")); else cgi->UI_ExecuteConfunc("update_basebutton containment true \"%s\"", va(_("No %s functional in base."), _("Containment"))); if (HOS_HospitalAllowed(base)) cgi->UI_ExecuteConfunc("update_basebutton hospital false \"%s\"", _("Treat wounded soldiers and perform implant surgery")); else cgi->UI_ExecuteConfunc("update_basebutton hospital true \"%s\"", va(_("No %s functional in base."), _("Hospital"))); /* * Gather data on current/max space for living quarters, storage, lab and workshop * clear_bld_space ensures 0/0 data for facilities which may not exist in base */ cgi->UI_ExecuteConfunc("clear_bld_space"); for (int i = 0; i < ccs.numBuildingTemplates; i++) { const building_t* b = &ccs.buildingTemplates[i]; /* Check if building matches one of our four types */ if (b->buildingType != B_QUARTERS && b->buildingType != B_STORAGE && b->buildingType != B_WORKSHOP && b->buildingType != B_LAB && b->buildingType != B_ANTIMATTER) continue; /* only show already researched buildings */ if (!RS_IsResearched_ptr(b->tech)) continue; const baseCapacities_t capType = B_GetCapacityFromBuildingType(b->buildingType); if (capType == MAX_CAP) continue; const int count = B_GetNumberOfBuildingsInBaseByTemplate(base, b->tpl); if (count < 1) continue; const capacities_t& cap = *CAP_Get(base, capType); cgi->UI_ExecuteConfunc("show_bld_space \"%s\" \"%s\" %i %i %i %i", _(b->name), b->id, cap.cur, cap.max, count, b->tpl->maxCount); } /* * Get the number of different employees in the base * @todo: Get the number of injured soldiers if hospital exists */ cgi->UI_ExecuteConfunc("current_employees %i %i %i %i", E_CountHired(base, EMPL_SOLDIER), E_CountHired(base, EMPL_PILOT), E_CountHired(base, EMPL_SCIENTIST), E_CountHired(base, EMPL_WORKER)); /* * List the first five aircraft in the base if they exist */ cgi->UI_ExecuteConfunc("clear_aircraft"); if (AIR_AircraftAllowed(base)) { AIR_ForeachFromBase(aircraft, base) { cgi->UI_ExecuteConfunc("show_aircraft %i \"%s\" \"%s\" \"%s\" %i", aircraft->idx, aircraft->name, aircraft->id, AIR_AircraftStatusToName(aircraft), AIR_IsAircraftInBase(aircraft)); } }