/** * @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 Solve the result of one projectile hitting an aircraft. * @param[in] campaign The campaign data structure * @param[in] projectile Pointer to the projectile. * @note the target loose (base damage - shield of target) hit points */ static void AIRFIGHT_ProjectileHits (const campaign_t* campaign, aircraftProjectile_t *projectile) { aircraft_t *target; int damage = 0; assert(projectile); target = projectile->aimedAircraft; assert(target); /* if the aircraft is not on geoscape anymore, do nothing (returned to base) */ if (AIR_IsAircraftInBase(target)) return; damage = AIRFIGHT_GetDamage(projectile->aircraftItem, target); /* apply resulting damages - but only if damage > 0 - because the target might * already be destroyed, and we don't want to execute the actions after airfight * for every projectile */ if (damage > 0) { assert(target->damage > 0); target->damage -= damage; if (target->damage <= 0) { /* Target is destroyed */ AIRFIGHT_ActionsAfterAirfight(campaign, projectile->attackingAircraft, target, target->type == AIRCRAFT_UFO); S_StartLocalSample("geoscape/combat-explosion", 1.0f); } else { S_StartLocalSample("geoscape/combat-rocket-exp", 1.0f); } } }
/** * @brief Actions to perform when destroying one hangar. * @param[in] base Pointer to the base where hangar is destroyed. * @param[in] capacity Type of hangar capacity: CAP_AIRCRAFT_SMALL or CAP_AIRCRAFT_BIG * @note called when player destroy its building or hangar is destroyed during base attack. * @note These actions will be performed after we actually remove the building. * @pre we checked before calling this function that all parameters are valid. * @pre building is not under construction. * @sa B_BuildingDestroy_f * @todo If player choose to destroy the building, a popup should ask him if he wants to sell aircraft in it. */ void CAP_RemoveAircraftExceedingCapacity (base_t* base, baseCapacities_t capacity) { linkedList_t *awayAircraft = nullptr; int numAwayAircraft; int randomNum; /* destroy aircraft only if there's not enough hangar (hangar is already destroyed) */ if (CAP_GetFreeCapacity(base, capacity) >= 0) return; /* destroy one aircraft (must not be sold: may be destroyed by aliens) */ AIR_ForeachFromBase(aircraft, base) { const int aircraftSize = aircraft->size; switch (aircraftSize) { case AIRCRAFT_SMALL: if (capacity != CAP_AIRCRAFT_SMALL) continue; break; case AIRCRAFT_LARGE: if (capacity != CAP_AIRCRAFT_BIG) continue; break; default: cgi->Com_Error(ERR_DROP, "B_RemoveAircraftExceedingCapacity: Unknown type of aircraft '%i'", aircraftSize); } /* Only aircraft in hangar will be destroyed by hangar destruction */ if (!AIR_IsAircraftInBase(aircraft)) { if (AIR_IsAircraftOnGeoscape(aircraft)) cgi->LIST_AddPointer(&awayAircraft, (void*)aircraft); continue; } /* Remove aircraft and aircraft items, but do not fire employees */ AIR_DeleteAircraft(aircraft); cgi->LIST_Delete(&awayAircraft); return; } numAwayAircraft = cgi->LIST_Count(awayAircraft); if (!numAwayAircraft) return; /* All aircraft are away from base, pick up one and change it's homebase */ randomNum = rand() % numAwayAircraft; if (!CL_DisplayHomebasePopup((aircraft_t*)cgi->LIST_GetByIdx(awayAircraft, randomNum), false)) { aircraft_t *aircraft = (aircraft_t*)cgi->LIST_GetByIdx(awayAircraft, randomNum); /* No base can hold this aircraft */ UFO_NotifyPhalanxAircraftRemoved(aircraft); if (!MapIsWater(GEO_GetColor(aircraft->pos, MAPTYPE_TERRAIN, nullptr))) CP_SpawnRescueMission(aircraft, nullptr); else { /* Destroy the aircraft and everything onboard - the aircraft pointer * is no longer valid after this point */ /* Pilot skills; really kill pilot in this case? */ AIR_DestroyAircraft(aircraft); } } cgi->LIST_Delete(&awayAircraft); }
/** * @brief Tells you if a employee is away from his home base (gone in mission). * @param[in] employee Pointer to the employee. * @return qboolean qtrue if the employee is away in mission, qfalse if he is not or he is unhired. */ qboolean E_IsAwayFromBase (const employee_t *employee) { const base_t *base; aircraft_t *aircraft; assert(employee); /* Check that employee is hired */ if (!E_IsHired(employee)) return qfalse; /* Check if employee is currently transferred. */ if (employee->transfer) return qtrue; /* for now only soldiers, ugvs and pilots can be assigned to an aircraft */ if (employee->type != EMPL_SOLDIER && employee->type != EMPL_ROBOT && employee->type != EMPL_PILOT) return qfalse; base = employee->baseHired; /* Crashed aircraft no longer belongs to any base but poor pilot/soldiers assigned * to it are definetly away from the base so we need to iterate trought all aircraft */ AIR_Foreach(aircraft) { if (aircraft->homebase != base) continue; if (!AIR_IsAircraftInBase(aircraft) && AIR_IsEmployeeInAircraft(employee, aircraft)) return qtrue; } return qfalse; }
/** * @brief Sells aircraft or craftitem. * @sa BS_BuyAircraft_f */ static void BS_SellAircraft_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; num = atoi(Cmd_Argv(1)); if (num < 0 || num >= buyList.length) return; if (buyCat == FILTER_AIRCRAFT) { const aircraft_t *aircraftTemplate = buyList.l[num].aircraft; qboolean aircraftOutNote = qfalse; qboolean teamNote = qfalse; aircraft_t *aircraft = NULL; if (!aircraftTemplate) return; AIR_ForeachFromBase(a, base) { if (Q_streq(a->id, aircraftTemplate->id)) { if (AIR_GetTeamSize(a) > 0) { teamNote = qtrue; continue; } if (!AIR_IsAircraftInBase(a)) { /* aircraft is not in base */ aircraftOutNote = qtrue; continue; } aircraft = a; break; } } if (aircraft) { BS_SellAircraft(aircraft); /* reinit the menu */ BS_BuyType(base); } else { if (teamNote) CP_Popup(_("Note"), _("You can't sell an aircraft if it still has a team assigned")); else if (aircraftOutNote) CP_Popup(_("Note"), _("You can't sell an aircraft that is not in base")); else Com_DPrintf(DEBUG_CLIENT, "BS_SellAircraft_f: There are no aircraft available (with no team assigned) for selling\n"); } } }
/** * @brief Sets aircraftCurrent and updates related cvars and menutexts. * @param[in] aircraft Pointer to given aircraft that should be selected in the menu. */ void AIR_AircraftSelect (aircraft_t* aircraft) { static char aircraftInfo[256]; base_t *base; int id; if (aircraft != NULL) base = aircraft->homebase; else base = NULL; if (!AIR_BaseHasAircraft(base)) { UI_ResetData(TEXT_AIRCRAFT_INFO); return; } assert(aircraft); assert(aircraft->homebase == base); CP_UpdateActorAircraftVar(aircraft, EMPL_SOLDIER); Cvar_SetValue("mn_equipsoldierstate", CL_EquipSoldierState(aircraft)); Cvar_Set("mn_aircraftstatus", AIR_AircraftStatusToName(aircraft)); Cvar_Set("mn_aircraftinbase", AIR_IsAircraftInBase(aircraft) ? "1" : "0"); Cvar_Set("mn_aircraftname", aircraft->name); if (!aircraft->tech) Com_Error(ERR_DROP, "No technology assigned to aircraft '%s'", aircraft->id); Cvar_Set("mn_aircraft_model", aircraft->tech->mdl); Cvar_Set("mn_aircraft_health", va("%3.0f" , aircraft->stats[AIR_STATS_DAMAGE] > 0 ? (double)aircraft->damage * 100 / aircraft->stats[AIR_STATS_DAMAGE] : 0)); /* generate aircraft info text */ Com_sprintf(aircraftInfo, sizeof(aircraftInfo), _("Speed:\t%i km/h\n"), AIR_AircraftMenuStatsValues(aircraft->stats[AIR_STATS_SPEED], AIR_STATS_SPEED)); Q_strcat(aircraftInfo, va(_("Fuel:\t%i/%i\n"), AIR_AircraftMenuStatsValues(aircraft->fuel, AIR_STATS_FUELSIZE), AIR_AircraftMenuStatsValues(aircraft->stats[AIR_STATS_FUELSIZE], AIR_STATS_FUELSIZE)), sizeof(aircraftInfo)); Q_strcat(aircraftInfo, va(_("Operational range:\t%i km\n"), AIR_GetOperationRange(aircraft)), sizeof(aircraftInfo)); Q_strcat(aircraftInfo, va(_("Weapons:\t%i on %i\n"), AIR_GetSlotItems(AC_ITEM_WEAPON, aircraft), aircraft->maxWeapons), sizeof(aircraftInfo)); Q_strcat(aircraftInfo, va(_("Armour:\t%i on 1\n"), AIR_GetSlotItems(AC_ITEM_SHIELD, aircraft)), sizeof(aircraftInfo)); Q_strcat(aircraftInfo, va(_("Electronics:\t%i on %i"), AIR_GetSlotItems(AC_ITEM_ELECTRONICS, aircraft), aircraft->maxElectronics), sizeof(aircraftInfo)); UI_RegisterText(TEXT_AIRCRAFT_INFO, aircraftInfo); /** @todo This shouldn't exists. UI should use the global idx as reference */ /* compute the ID and... */ id = 0; AIR_ForeachFromBase(aircraftInBase, base) { if (aircraft == aircraftInBase) break; id++; } base->aircraftCurrent = aircraft; Cvar_SetValue("mn_aircraft_id", id); /* ...update the GUI */ UI_ExecuteConfunc("aircraft_change %i", id); }
/** * @brief Determines the state of the equip soldier menu button: * @returns SOLIDER_EQUIP_MENU_BUTTON_NO_AIRCRAFT_IN_BASE if no aircraft in base * @returns SOLIDER_EQUIP_MENU_BUTTON_NO_SOLDIES_AVAILABLE if no soldiers available * @returns SOLIDER_EQUIP_MENU_BUTTON_OK if none of the above is true */ static int CL_EquipSoldierState (const aircraft_t * aircraft) { if (!AIR_IsAircraftInBase(aircraft)) return SOLDIER_EQUIP_MENU_BUTTON_NO_AIRCRAFT_IN_BASE; if (E_CountHired(aircraft->homebase, EMPL_SOLDIER) <= 0) return SOLDIER_EQUIP_MENU_BUTTON_NO_SOLDIES_AVAILABLE; return SOLDIER_EQUIP_MENU_BUTTON_OK; }
/** * @brief Update aircraft selection list with the current base aircraft names */ static void AIR_AircraftFillList_f (void) { base_t* base = B_GetCurrentSelectedBase(); cgi->UI_ExecuteConfunc("ui_aircraft_clear"); int idx = 0; AIR_ForeachFromBase(aircraft, base) { const float health = aircraft->stats[AIR_STATS_DAMAGE] > 0 ? (float)aircraft->damage * 100.0f / aircraft->stats[AIR_STATS_DAMAGE] : 0.0f; const char* inBase = AIR_IsAircraftInBase(aircraft) ? "1" : "0"; char teamStr[MAX_VAR]; Com_sprintf(teamStr, sizeof(teamStr), _("%i of %i"), AIR_GetTeamSize(aircraft), aircraft->maxTeamSize); cgi->UI_ExecuteConfunc("ui_aircraft_add %i \"%s\" %3.0f %s \"%s\" \"%s\"", idx, _(aircraft->name), health, inBase, AIR_AircraftStatusToName(aircraft), teamStr); idx++; } }
/** * @brief Starts an aircraft or stops the current mission and let the aircraft idle around. */ static void AIM_AircraftStart_f (void) { aircraft_t *aircraft; base_t *base = B_GetCurrentSelectedBase(); if (!base) return; if (!base->aircraftCurrent) { Com_DPrintf(DEBUG_CLIENT, "Error - there is no current aircraft in this base\n"); return; } /* Aircraft cannot start without Command Centre operational. */ if (!B_GetBuildingStatus(base, B_COMMAND)) { CP_Popup(_("Notice"), _("No operational Command Centre in this base.\n\nAircraft can not start.\n")); return; } aircraft = base->aircraftCurrent; /* Aircraft cannot start without a pilot. */ if (!AIR_GetPilot(aircraft)) { CP_Popup(_("Notice"), _("There is no pilot assigned to this aircraft.\n\nAircraft can not start.\n")); return; } if (AIR_IsAircraftInBase(aircraft)) { /* reload its ammunition */ AII_ReloadAircraftWeapons(aircraft); } MS_AddNewMessage(_("Notice"), _("Aircraft started"), qfalse, MSG_STANDARD, NULL); aircraft->status = AIR_IDLE; MAP_SelectAircraft(aircraft); /* Return to geoscape. */ UI_PopWindow(qfalse); UI_PopWindow(qfalse); }
/** * @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 Fill market item list */ static void BS_FillMarket_f (void) { const base_t* base = B_GetCurrentSelectedBase(); itemFilterTypes_t type; if (cgi->Cmd_Argc() < 2) { cgi->Com_Printf("Usage: %s <category>\n", cgi->Cmd_Argv(0)); return; } if (cgi->Cmd_Argc() >= 3) base = B_GetFoundedBaseByIDX(atoi(cgi->Cmd_Argv(2))); if (!base) { cgi->Com_Printf("No/invalid base selected.\n"); return; } type = cgi->INV_GetFilterTypeID(cgi->Cmd_Argv(1)); cgi->UI_ExecuteConfunc("ui_market_clear"); switch (type) { case FILTER_UGVITEM: /* show own UGV */ E_Foreach(EMPL_ROBOT, robot) { const ugv_t* ugv = robot->getUGV(); const technology_t* tech = RS_GetTechByProvided(ugv->id); if (!robot->isHiredInBase(base)) continue; cgi->UI_ExecuteConfunc("ui_market_add \"ugv-%d\" \"%s\" 1 0 0 %d - \"%s\"", robot->chr.ucn, _(tech->name), ugv->price, robot->isAwayFromBase() ? _("UGV is away from home") : "-"); } /* show buyable UGV */ for (int i = 0; i < cgi->csi->numUGV; i++) { const ugv_t* ugv = &cgi->csi->ugvs[i]; const technology_t* tech = RS_GetTechByProvided(ugv->id); const objDef_t* ugvWeapon = INVSH_GetItemByID(ugv->weapon); const int buyable = std::min(E_CountUnhiredRobotsByType(ugv), BS_GetItemOnMarket(ugvWeapon)); assert(tech); if (!RS_IsResearched_ptr(tech)) continue; if (buyable <= 0) continue; cgi->UI_ExecuteConfunc("ui_market_add %s \"%s\" 0 %d %d %d - -", ugv->id, _(tech->name), buyable, ugv->price, ugv->price); } /* show (UGV) items, fall through */ case FILTER_S_PRIMARY: case FILTER_S_SECONDARY: case FILTER_S_HEAVY: case FILTER_S_IMPLANT: case FILTER_S_MISC: case FILTER_S_ARMOUR: case FILTER_DUMMY: case FILTER_CRAFTITEM: case MAX_FILTERTYPES: { for (int i = 0; i < cgi->csi->numODs; i++) { const objDef_t* od = &cgi->csi->ods[i]; const technology_t* tech = RS_GetTechForItem(od); if (!BS_IsOnMarket(od)) continue; if (B_ItemInBase(od, base) + BS_GetItemOnMarket(od) <= 0) continue; if (type != MAX_FILTERTYPES && !cgi->INV_ItemMatchesFilter(od, type)) continue; cgi->UI_ExecuteConfunc("ui_market_add %s \"%s\" %d %d %d %d %s -", od->id, _(od->name), B_ItemInBase(od, base), BS_GetItemOnMarket(od), BS_GetItemBuyingPrice(od), BS_GetItemSellingPrice(od), RS_IsResearched_ptr(tech) ? va("%d", ccs.eMarket.autosell[i]) : "-"); } break; } case FILTER_AIRCRAFT: { AIR_ForeachFromBase(aircraft, base) { cgi->UI_ExecuteConfunc("ui_market_add \"aircraft_%d\" \"%s\" 1 0 0 %d - \"%s\"", aircraft->idx, aircraft->name, BS_GetAircraftSellingPrice(aircraft), AIR_IsAircraftInBase(aircraft) ? "-" : _("Aircraft is away from home")); } for (int i = 0; i < ccs.numAircraftTemplates; i++) { const aircraft_t* aircraft = &ccs.aircraftTemplates[i]; if (!BS_AircraftIsOnMarket(aircraft)) continue; if (!RS_IsResearched_ptr(aircraft->tech)) continue; if (BS_GetAircraftOnMarket(aircraft) <= 0) continue; cgi->UI_ExecuteConfunc("ui_market_add \"%s\" \"%s\" 0 %d %d %d - -", aircraft->id, _(aircraft->tech->name), BS_GetAircraftOnMarket(aircraft), BS_GetAircraftBuyingPrice(aircraft), BS_GetAircraftSellingPrice(aircraft)); } break; } default: break; }
/** * @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)); } }