/** * @brief Sets the title of the base to a cvar to prepare the rename menu. */ static void B_SetBaseTitle_f (void) { int baseCount = B_GetCount(); if (baseCount < MAX_BASES) { char baseName[MAX_VAR]; if (baseCount > 0) { int j; int i = 2; do { j = 0; Com_sprintf(baseName, lengthof(baseName), _("Base #%i"), i); while (j <= baseCount && !Q_streq(baseName, ccs.bases[j].name)) { j++; } } while (i++ <= baseCount && j <= baseCount); } else { Q_strncpyz(baseName, _("Home"), lengthof(baseName)); } cgi->Cvar_Set("mn_base_title", baseName); } else { MS_AddNewMessage(_("Notice"), _("You've reached the base limit.")); cgi->UI_PopWindow(false); /* remove the new base popup */ } }
/** @todo unify the names into mn_base_* */ void B_InitCallbacks (void) { mn_base_title = cgi->Cvar_Get("mn_base_title", "", 0, "The title of the current base"); cl_start_buildings = cgi->Cvar_Get("cl_start_buildings", "1", CVAR_ARCHIVE, "Start with initial buildings in your first base"); cgi->Cvar_Set("mn_base_cost", va(_("%i c"), ccs.curCampaign->basecost)); cgi->Cvar_SetValue("mn_base_count", B_GetCount()); cgi->Cvar_SetValue("mn_base_max", MAX_BASES); cgi->Cmd_AddCommand("basemapshot", B_MakeBaseMapShot_f, "Command to make a screenshot for the baseview with the correct angles"); cgi->Cmd_AddCommand("mn_base_prev", B_PrevBase_f, "Go to the previous base"); cgi->Cmd_AddCommand("mn_base_next", B_NextBase_f, "Go to the next base"); cgi->Cmd_AddCommand("mn_base_select", B_SelectBase_f, "Select a founded base by index"); cgi->Cmd_AddCommand("mn_base_build", B_BuildBase_f, NULL); cgi->Cmd_AddCommand("mn_set_base_title", B_SetBaseTitle_f, NULL); cgi->Cmd_AddCommand("base_changename", B_ChangeBaseName_f, "Called after editing the cvar base name"); cgi->Cmd_AddCommand("base_init", B_BaseInit_f, NULL); cgi->Cmd_AddCommand("base_assemble", B_AssembleMap_f, "Called to assemble the current selected base"); cgi->Cmd_AddCommand("base_building_space", B_BuildingSpace_f, "Called to display building capacity in current selected base"); cgi->Cmd_AddCommand("building_init", B_BuildingInit_f, NULL); cgi->Cmd_AddCommand("building_status", B_BuildingStatus_f, NULL); cgi->Cmd_AddCommand("building_destroy", B_BuildingDestroy_f, "Function to destroy a building (select via right click in baseview first)"); cgi->Cmd_AddCommand("building_amdestroy", B_Destroy_AntimaterStorage_f, "Function called if antimatter storage destroyed"); cgi->Cmd_AddCommand("building_ufopedia", B_BuildingInfoClick_f, "Opens the UFOpedia for the current selected building"); cgi->Cmd_AddCommand("check_building_status", B_CheckBuildingStatusForMenu_f, "Create a popup to inform player why he can't use a button"); cgi->Cmd_AddCommand("buildings_click", B_BuildingClick_f, "Opens the building information window in construction mode"); cgi->Cmd_AddCommand("reset_building_current", B_ResetBuildingCurrent_f, NULL); cgi->Cmd_AddCommand("basesummary_selectbase", BaseSummary_SelectBase_f, "Opens Base Statistics menu in base"); }
/** * @brief Fills create installation / installation type selection popup */ static void INS_FillTypes_f (void) { cgi->UI_ExecuteConfunc("installationtype_clear"); if (INS_GetCount() < B_GetInstallationLimit()) { for (int i = 0; i < ccs.numInstallationTemplates; i++) { const installationTemplate_t* tpl = &ccs.installationTemplates[i]; if (tpl->once && INS_HasType(tpl->type, INSTALLATION_NOT_USED)) continue; if (tpl->tech == nullptr || RS_IsResearched_ptr(tpl->tech)) { cgi->UI_ExecuteConfunc("installationtype_add \"%s\" \"%s\" \"%s\" \"%d c\"", tpl->id, _(tpl->name), (tpl->buildTime > 0) ? va("%d %s", tpl->buildTime, ngettext("day", "days", tpl->buildTime)) : "-", tpl->cost); } } } /** @todo Move this out from installations code */ if (B_GetCount() < MAX_BASES) cgi->UI_ExecuteConfunc("installationtype_add base \"%s\" - \"%d c\"", _("Base"), ccs.curCampaign->basecost); }
/** * @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 Shows the current stats from stats_t stats * @todo This is very redundant with NAT_HandleBudget Ivestigate and clean up. */ void CP_StatsUpdate_f (void) { char *pos; static char statsBuffer[MAX_STATS_BUFFER]; int hired[MAX_EMPL]; int i, costs = 0, sum = 0, totalfunds = 0; base_t *base; const campaign_t *campaign = ccs.curCampaign; const salary_t *salary = &campaign->salaries; const rank_t *rank; /* delete buffer */ OBJZERO(statsBuffer); OBJZERO(hired); pos = statsBuffer; /* missions */ cgi->UI_RegisterText(TEXT_STATS_MISSION, pos); Com_sprintf(pos, MAX_STATS_BUFFER, _("Won:\t%i\nLost:\t%i\n\n"), ccs.campaignStats.missionsWon, ccs.campaignStats.missionsLost); /* bases */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_STATS_BASES, pos); Com_sprintf(pos, (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos), _("Built:\t%i\nActive:\t%i\nAttacked:\t%i\n"), ccs.campaignStats.basesBuilt, B_GetCount(), ccs.campaignStats.basesAttacked), /* installations */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_STATS_INSTALLATIONS, pos); INS_Foreach(inst) { Q_strcat(pos, va("%s\n", inst->name), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); } /* nations */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_STATS_NATIONS, pos); for (i = 0; i < ccs.numNations; i++) { const nation_t *nation = NAT_GetNationByIDX(i); Q_strcat(pos, va(_("%s\t%s\n"), _(nation->name), NAT_GetHappinessString(nation)), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); totalfunds += NAT_GetFunding(nation, 0); } Q_strcat(pos, va(_("\nFunding this month:\t%d"), totalfunds), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); /* costs */ for (i = 0; i < MAX_EMPL; i++) { E_Foreach(i, employee) { const employeeType_t type = (employeeType_t)i; if (!E_IsHired(employee)) continue; rank = CL_GetRankByIdx(employee->chr.score.rank); costs += CP_GetSalaryBaseEmployee(salary, type) + rank->level * CP_GetSalaryRankBonusEmployee(salary, type); hired[employee->type]++; } } /* employees - this is between the two costs parts to count the hired employees */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_STATS_EMPLOYEES, pos); for (i = 0; i < MAX_EMPL; i++) { const employeeType_t type = (employeeType_t)i; Q_strcat(pos, va(_("%s\t%i\n"), E_GetEmployeeString(type, hired[i]), hired[i]), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); } /* costs - second part */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_STATS_COSTS, pos); Q_strcat(pos, va(_("Employees:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); sum += costs; costs = 0; AIR_Foreach(aircraft) { if (aircraft->status == AIR_CRASHED) continue; costs += aircraft->price * salary->aircraftFactor / salary->aircraftDivisor; } Q_strcat(pos, va(_("Aircraft:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); sum += costs; base = NULL; while ((base = B_GetNext(base)) != NULL) { costs = CP_GetSalaryUpKeepBase(salary, base); Q_strcat(pos, va(_("Base (%s):\t%i c\n"), base->name, costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); sum += costs; } costs = CP_GetSalaryAdministrative(salary); Q_strcat(pos, va(_("Administrative costs:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); sum += costs; if (ccs.credits < 0) { const float interest = ccs.credits * campaign->salaries.debtInterest; costs = (int)ceil(interest); Q_strcat(pos, va(_("Debt:\t%i c\n"), costs), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); sum += costs; } Q_strcat(pos, va(_("\n\t-------\nSum:\t%i c\n"), sum), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); /* campaign */ pos += (strlen(pos) + 1); cgi->UI_RegisterText(TEXT_GENERIC, pos); Q_strcat(pos, va(_("Max. allowed debts: %ic\n"), campaign->negativeCreditsUntilLost), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); /* only show the xvi spread data when it's available */ if (CP_IsXVIVisible()) { Q_strcat(pos, va(_("Max. allowed eXtraterrestial Viral Infection: %i%%\n" "Current eXtraterrestial Viral Infection: %i%%"), campaign->maxAllowedXVIRateUntilLost, CP_GetAverageXVIRate()), (ptrdiff_t)(&statsBuffer[MAX_STATS_BUFFER] - pos)); } }
/** * @brief Remove a defence system from base. * @note 1st argument is the basedefence system type to destroy (sa basedefenceType_t). * @note 2nd argument is the idx of the base in which you want the battery to be destroyed. * @note if the first argument is BASEDEF_RANDOM, the type of the battery to destroy is randomly selected * @note the building must already be removed from ccs.buildings[baseIdx][] */ static void BDEF_RemoveBattery_f (void) { basedefenceType_t basedefType; int baseIdx; base_t* base; if (cgi->Cmd_Argc() < 3) { Com_Printf("Usage: %s <basedefType> <baseIdx>", cgi->Cmd_Argv(0)); return; } else { char type[MAX_VAR]; Q_strncpyz(type, cgi->Cmd_Argv(1), sizeof(type)); if (Q_streq(type, "missile")) basedefType = BASEDEF_MISSILE; else if (Q_streq(type, "laser")) basedefType = BASEDEF_LASER; else if (Q_streq(type, "random")) basedefType = BASEDEF_RANDOM; else return; baseIdx = atoi(cgi->Cmd_Argv(2)); } /* Check that the baseIdx exists */ if (baseIdx < 0 || baseIdx >= B_GetCount()) { Com_Printf("BDEF_RemoveBattery_f: baseIdx %i doesn't exist: there is only %i bases in game.\n", baseIdx, B_GetCount()); return; } base = B_GetFoundedBaseByIDX(baseIdx); if (!base) { Com_Printf("BDEF_RemoveBattery_f: baseIdx %i is not founded.\n", baseIdx); return; } if (basedefType == BASEDEF_RANDOM) { /* Type of base defence to destroy is randomly selected */ if (base->numBatteries <= 0 && base->numLasers <= 0) { Com_Printf("No base defence to destroy\n"); return; } else if (base->numBatteries <= 0) { /* only laser battery is possible */ basedefType = BASEDEF_LASER; } else if (base->numLasers <= 0) { /* only missile battery is possible */ basedefType = BASEDEF_MISSILE; } else { /* both type are possible, choose one randomly */ basedefType = (basedefenceType_t)(rand() % 2 + BASEDEF_MISSILE); } } else { /* Check if the removed building was under construction */ buildingType_t type; int workingNum, max; building_t* building; switch (basedefType) { case BASEDEF_MISSILE: type = B_DEFENCE_MISSILE; max = base->numBatteries; break; case BASEDEF_LASER: type = B_DEFENCE_LASER; max = base->numLasers; break; default: Com_Printf("BDEF_RemoveBattery_f: base defence type %i doesn't exist.\n", basedefType); return; } building = nullptr; workingNum = 0; while ((building = B_GetNextBuildingByType(base, building, type))) if (building->buildingStatus == B_STATUS_WORKING) workingNum++; if (workingNum == max) { /* Removed building was under construction, do nothing */ return; } else if (workingNum != max - 1) { /* Should never happen, we only remove building one by one */ Com_Printf("BDEF_RemoveBattery_f: Error while checking number of batteries (%i instead of %i) in base '%s'.\n", workingNum, max, base->name); return; } /* If we reached this point, that means we are removing a working building: continue */ } BDEF_RemoveBattery(base, basedefType, -1); }
/** * @brief Mark a building for destruction - you only have to confirm it now * @param[in] building Pointer to the base to destroy */ static void B_MarkBuildingDestroy (building_t* building) { baseCapacities_t cap; base_t *base = building->base; /* you can't destroy buildings if base is under attack */ if (B_IsUnderAttack(base)) { CP_Popup(_("Notice"), _("Base is under attack, you can't destroy buildings!")); return; } cap = B_GetCapacityFromBuildingType(building->buildingType); /* store the pointer to the building you wanna destroy */ base->buildingCurrent = building; /** @todo: make base destroyable by destroying entrance */ if (building->buildingType == B_ENTRANCE) { CP_Popup(_("Destroy Entrance"), _("You can't destroy the entrance of the base!")); return; } if (!B_IsBuildingDestroyable(building)) { CP_Popup(_("Notice"), _("You can't destroy this building! It is the only connection to other buildings!")); return; } if (building->buildingStatus == B_STATUS_WORKING) { const bool hasMoreBases = B_GetCount() > 1; switch (building->buildingType) { case B_HANGAR: case B_SMALL_HANGAR: if (CAP_GetFreeCapacity(base, cap) <= 0) { cgi->UI_PopupButton(_("Destroy Hangar"), _("If you destroy this hangar, you will also destroy the aircraft inside.\nAre you sure you want to destroy this building?"), "ui_pop;ui_push aircraft;aircraft_select;", _("Go to hangar"), _("Go to hangar without destroying building"), va("building_destroy %i %i confirmed; ui_pop;", base->idx, building->idx), _("Destroy"), _("Destroy the building"), hasMoreBases ? "ui_pop;ui_push transfer;" : NULL, hasMoreBases ? _("Transfer") : NULL, _("Go to transfer menu without destroying the building")); return; } break; case B_QUARTERS: if (CAP_GetFreeCapacity(base, cap) < building->capacity) { cgi->UI_PopupButton(_("Destroy Quarter"), _("If you destroy this Quarters, every employee inside will be killed.\nAre you sure you want to destroy this building?"), "ui_pop;ui_push employees;employee_list 0;", _("Dismiss"), _("Go to hiring menu without destroying building"), va("building_destroy %i %i confirmed; ui_pop;", base->idx, building->idx), _("Destroy"), _("Destroy the building"), hasMoreBases ? "ui_pop;ui_push transfer;" : NULL, hasMoreBases ? _("Transfer") : NULL, _("Go to transfer menu without destroying the building")); return; } break; case B_STORAGE: if (CAP_GetFreeCapacity(base, cap) < building->capacity) { cgi->UI_PopupButton(_("Destroy Storage"), _("If you destroy this Storage, every items inside will be destroyed.\nAre you sure you want to destroy this building?"), "ui_pop;ui_push market;buy_type *mn_itemtype", _("Go to storage"), _("Go to buy/sell menu without destroying building"), va("building_destroy %i %i confirmed; ui_pop;", base->idx, building->idx), _("Destroy"), _("Destroy the building"), hasMoreBases ? "ui_pop;ui_push transfer;" : NULL, hasMoreBases ? _("Transfer") : NULL, _("Go to transfer menu without destroying the building")); return; } break; default: break; } } cgi->UI_PopupButton(_("Destroy building"), _("Are you sure you want to destroy this building?"), NULL, NULL, NULL, va("building_destroy %i %i confirmed; ui_pop;", base->idx, building->idx), _("Destroy"), _("Destroy the building"), NULL, NULL, NULL); }
/** * @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 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)); } }