/** * @brief Choose Base that will be attacked * @return Pointer to the base, NULL if no base set * @note Base attack mission -- Stage 1 */ static base_t *CP_BaseAttackChooseBase (void) { float randomNumber; float sum = 0.0f; base_t *base = NULL; /* Choose randomly a base depending on alienInterest values for those bases */ while ((base = B_GetNext(base)) != NULL) sum += base->alienInterest; randomNumber = frand() * sum; while ((base = B_GetNext(base)) != NULL) { randomNumber -= base->alienInterest; if (randomNumber < 0) break; } /* Make sure we have a base */ assert(base && (randomNumber < 0)); /* base is already under attack */ if (B_IsUnderAttack(base)) return NULL; /* base not (yet) working */ if (!B_GetBuildingStatus(base, B_COMMAND)) return NULL; return base; }
/** * @brief Run base defences. * @param[in] dt Time elapsed since last call of this function. */ void AIRFIGHT_CampaignRunBaseDefence (int dt) { base_t* base; base = nullptr; while ((base = B_GetNext(base)) != nullptr) { int idx; if (B_IsUnderAttack(base)) continue; for (idx = 0; idx < base->numBatteries; idx++) { baseWeapon_t* battery = &base->batteries[idx]; aircraftSlot_t* slot = &battery->slot; if (slot->delayNextShot > 0) slot->delayNextShot -= dt; if (slot->ammoLeft <= 0) AII_ReloadWeapon(slot); } for (idx = 0; idx < base->numLasers; idx++) { baseWeapon_t* battery = &base->lasers[idx]; aircraftSlot_t* slot = &battery->slot; if (slot->delayNextShot > 0) slot->delayNextShot -= dt; if (slot->ammoLeft <= 0) AII_ReloadWeapon(slot); } if (AII_BaseCanShoot(base)) { if (B_GetBuildingStatus(base, B_DEFENCE_MISSILE)) AIRFIGHT_BaseShoot(base, base->batteries, base->numBatteries); if (B_GetBuildingStatus(base, B_DEFENCE_LASER)) AIRFIGHT_BaseShoot(base, base->lasers, base->numLasers); } } INS_Foreach(installation) { if (installation->installationStatus != INSTALLATION_WORKING) continue; if (installation->installationTemplate->maxBatteries <= 0) continue; for (int idx = 0; idx < installation->installationTemplate->maxBatteries; idx++) { baseWeapon_t* battery = &installation->batteries[idx]; aircraftSlot_t* slot = &battery->slot; if (slot->delayNextShot > 0) slot->delayNextShot -= dt; if (slot->ammoLeft <= 0) AII_ReloadWeapon(slot); } if (AII_InstallationCanShoot(installation)) { AIRFIGHT_InstallationShoot(installation, installation->batteries, installation->installationTemplate->maxBatteries); } } }
/** * @brief Returns true if you can buy or sell equipment * @param[in] base Pointer to base to check on * @sa B_BaseInit_f */ bool BS_BuySellAllowed (const base_t* base) { return !B_IsUnderAttack(base) && B_GetBuildingStatus(base, B_STORAGE); }
/** * @brief Returns true if the current base is able to produce items * @param[in] base Pointer to the base. * @sa B_BaseInit_f */ bool PR_ProductionAllowed (const base_t* base) { assert(base); return !B_IsUnderAttack(base) && B_GetBuildingStatus(base, B_WORKSHOP) && E_CountHired(base, EMPL_WORKER) > 0; }
/** * @brief Checks why a button in base menu is disabled, and create a popup to inform player */ static void B_CheckBuildingStatusForMenu_f (void) { int num; const char *buildingID; const building_t *building; const base_t *base = B_GetCurrentSelectedBase(); if (cgi->Cmd_Argc() != 2) { Com_Printf("Usage: %s <buildingID>\n", cgi->Cmd_Argv(0)); return; } buildingID = cgi->Cmd_Argv(1); building = B_GetBuildingTemplate(buildingID); if (!building || !base) return; /* Maybe base is under attack ? */ if (B_IsUnderAttack(base)) { CP_Popup(_("Notice"), _("Base is under attack, you can't access this building !")); return; } if (building->buildingType == B_HANGAR) { /* this is an exception because you must have a small or large hangar to enter aircraft menu */ CP_Popup(_("Notice"), _("You need at least one Hangar (and its dependencies) to use aircraft.")); return; } num = B_GetNumberOfBuildingsInBaseByBuildingType(base, building->buildingType); if (num > 0) { int numUnderConstruction; /* maybe all buildings of this type are under construction ? */ B_CheckBuildingTypeStatus(base, building->buildingType, B_STATUS_UNDER_CONSTRUCTION, &numUnderConstruction); if (numUnderConstruction == num) { int minDay = 99999; building_t *b = NULL; while ((b = B_GetNextBuildingByType(base, b, building->buildingType))) { if (b->buildingStatus == B_STATUS_UNDER_CONSTRUCTION) { const float remaining = B_GetConstructionTimeRemain(b); minDay = std::min(minDay, (int)std::max(0.0f, remaining)); } } CP_Popup(_("Notice"), ngettext("Construction of building will be over in %i day.\nPlease wait to enter.", "Construction of building will be over in %i days.\nPlease wait to enter.", minDay), minDay); return; } if (!B_CheckBuildingDependencesStatus(building)) { const building_t *dependenceBuilding = building->dependsBuilding; assert(building->dependsBuilding); if (B_GetNumberOfBuildingsInBaseByBuildingType(base, dependenceBuilding->buildingType) <= 0) { /* the dependence of the building is not built */ CP_Popup(_("Notice"), _("You need a building %s to make building %s functional."), _(dependenceBuilding->name), _(building->name)); return; } else { /* maybe the dependence of the building is under construction * note that we can't use B_STATUS_UNDER_CONSTRUCTION here, because this value * is not use for every building (for exemple Command Centre) */ building_t *b = NULL; while ((b = B_GetNextBuildingByType(base, b, dependenceBuilding->buildingType))) { if (!B_IsBuildingBuiltUp(b)) { CP_Popup(_("Notice"), _("Building %s is not finished yet, and is needed to use building %s."), _(dependenceBuilding->name), _(building->name)); return; } } /* the dependence is built but doesn't work - must be because of their dependendes */ CP_Popup(_("Notice"), _("Make sure that the dependencies of building %s (%s) are operational, so that building %s may be used."), _(dependenceBuilding->name), _(dependenceBuilding->dependsBuilding->name), _(building->name)); return; } } /* all buildings are OK: employees must be missing */ if (building->buildingType == B_WORKSHOP && E_CountHired(base, EMPL_WORKER) <= 0) { CP_Popup(_("Notice"), _("You need to recruit %s to use building %s."), E_GetEmployeeString(EMPL_WORKER, 2), _(building->name)); return; } else if (building->buildingType == B_LAB && E_CountHired(base, EMPL_SCIENTIST) <= 0) { CP_Popup(_("Notice"), _("You need to recruit %s to use building %s."), E_GetEmployeeString(EMPL_SCIENTIST, 2), _(building->name)); return; } } else { CP_Popup(_("Notice"), _("Build a %s first."), _(building->name)); return; } }
/** * @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 Returns true if you can enter in the hospital * @sa B_BaseInit_f */ bool HOS_HospitalAllowed (const base_t* base) { return !B_IsUnderAttack(base) && B_GetBuildingStatus(base, B_HOSPITAL); }