/** * @brief Update the display of building space for all researched facilities * @sa B_BaseInit_f */ static void B_BuildingSpace_f (void) { int i; base_t *base = B_GetCurrentSelectedBase(); if (!base) return; // Clear existing entries from the UI panel 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; /* skip mandatory buildings (like Entrance) which are built automatically */ if (b->mandatory) continue; /* only show already researched buildings */ if (!RS_IsResearched_ptr(b->tech)) continue; if (capType != MAX_CAP) cap = *CAP_Get(base, capType); else OBJZERO(cap); assert(b->tpl); const int count = B_GetNumberOfBuildingsInBaseByTemplate(base, b->tpl); cgi->UI_ExecuteConfunc("show_bld_space \"%s\" \"%s\" %i %i %i %i", _(b->name), b->id, cap.cur, cap.max, count, b->tpl->maxCount); } }
/** * @brief Base Summary menu init function. * @note Should be called whenever the Base Summary menu gets active. */ static void BaseSummary_Init (const base_t *base) { static char textStatsBuffer[1024]; static char textInfoBuffer[256]; const aliensCont_t *containment = base->alienscont; int i; baseCapacities_t cap; const production_queue_t *queue; const technology_t *tech; int tmp; /* wipe away old buffers */ textStatsBuffer[0] = textInfoBuffer[0] = 0; Q_strcat(textInfoBuffer, _("^BAircraft\n"), sizeof(textInfoBuffer)); for (i = 0; i <= MAX_HUMAN_AIRCRAFT_TYPE; i++) { const aircraftType_t airType = (aircraftType_t)i; const int count = AIR_CountTypeInBase(base, airType); if (count == 0) continue; Q_strcat(textInfoBuffer, va("\t%s:\t\t\t\t%i\n", AIR_GetAircraftString(airType), count), sizeof(textInfoBuffer)); } Q_strcat(textInfoBuffer, "\n", sizeof(textInfoBuffer)); Q_strcat(textInfoBuffer, _("^BEmployees\n"), sizeof(textInfoBuffer)); for (i = 0; i < MAX_EMPL; i++) { const employeeType_t emplType = (employeeType_t)i; tmp = E_CountHired(base, emplType); if (tmp == 0) continue; Q_strcat(textInfoBuffer, va("\t%s:\t\t\t\t%i\n", E_GetEmployeeString(emplType, tmp), tmp), sizeof(textInfoBuffer)); } Q_strcat(textInfoBuffer, "\n", sizeof(textInfoBuffer)); Q_strcat(textInfoBuffer, _("^BAliens\n"), sizeof(textInfoBuffer)); for (i = 0; i < ccs.numAliensTD; i++) { if (!containment[i].amountAlive && !containment[i].amountDead) continue; Q_strcat(textInfoBuffer, va("\t%s:\t\t\t\t%i/%i\n", _(containment[i].teamDef->name), containment[i].amountAlive, containment[i].amountDead), sizeof(textInfoBuffer)); } /* link into the menu */ cgi->UI_RegisterText(TEXT_STANDARD, textInfoBuffer); Q_strcat(textStatsBuffer, _("^BBuildings\t\t\t\t\t\tCapacity\t\t\t\tAmount\n"), sizeof(textStatsBuffer)); for (i = 0; i < ccs.numBuildingTemplates; i++) { const building_t* b = &ccs.buildingTemplates[i]; /* only show already researched buildings */ if (!RS_IsResearched_ptr(b->tech)) continue; cap = B_GetCapacityFromBuildingType(b->buildingType); if (cap == MAX_CAP) continue; if (!B_GetNumberOfBuildingsInBaseByBuildingType(base, b->buildingType)) continue; /* Check if building is functional (see comments in B_UpdateBaseCapacities) */ if (B_GetBuildingStatus(base, b->buildingType)) { Q_strcat(textStatsBuffer, va("%s:\t\t\t\t\t\t%i/%i", _(b->name), CAP_GetCurrent(base, cap), CAP_GetMax(base, cap)), sizeof(textStatsBuffer)); } else { if (b->buildingStatus == B_STATUS_UNDER_CONSTRUCTION) { const float remaining = B_GetConstructionTimeRemain(b); const float timeLeft = std::max(0.0f, remaining); Q_strcat(textStatsBuffer, va("%s:\t\t\t\t\t\t%3.1f %s", _(b->name), timeLeft, ngettext("day", "days", timeLeft)), sizeof(textStatsBuffer)); } else { Q_strcat(textStatsBuffer, va("%s:\t\t\t\t\t\t%i/%i", _(b->name), CAP_GetCurrent(base, cap), 0), sizeof(textStatsBuffer)); } } Q_strcat(textStatsBuffer, va("\t\t\t\t%i\n", B_GetNumberOfBuildingsInBaseByBuildingType(base, b->buildingType)), sizeof(textStatsBuffer)); } Q_strcat(textStatsBuffer, "\n", sizeof(textStatsBuffer)); Q_strcat(textStatsBuffer, _("^BProduction\t\t\t\t\t\tQuantity\t\t\t\tPercent\n"), sizeof(textStatsBuffer)); queue = PR_GetProductionForBase(base); if (queue->numItems > 0) { for (i = 0; i < queue->numItems; i++) { const production_t *production = &queue->items[i]; const char *name = PR_GetName(&production->data); /** @todo use the same method as we do in PR_ProductionInfo */ Q_strcat(textStatsBuffer, va(_("%s\t\t\t\t\t\t%d\t\t\t\t%.2f%%\n"), name, production->amount, PR_GetProgress(production) * 100), sizeof(textStatsBuffer)); } } else { Q_strcat(textStatsBuffer, _("Nothing\n"), sizeof(textStatsBuffer)); } Q_strcat(textStatsBuffer, "\n", sizeof(textStatsBuffer)); Q_strcat(textStatsBuffer, _("^BResearch\t\t\t\t\t\tScientists\t\t\t\tPercent\n"), sizeof(textStatsBuffer)); tmp = 0; for (i = 0; i < ccs.numTechnologies; i++) { tech = RS_GetTechByIDX(i); if (tech->base == base && (tech->statusResearch == RS_RUNNING || tech->statusResearch == RS_PAUSED)) { Q_strcat(textStatsBuffer, va(_("%s\t\t\t\t\t\t%d\t\t\t\t%1.2f%%\n"), _(tech->name), tech->scientists, (1 - tech->time / tech->overallTime) * 100), sizeof(textStatsBuffer)); tmp++; } } if (!tmp) Q_strcat(textStatsBuffer, _("Nothing\n"), sizeof(textStatsBuffer)); /* link into the menu */ cgi->UI_RegisterText(TEXT_STATS_BASESUMMARY, textStatsBuffer); }
/** * @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)); } }