/** * @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 Actions to execute when a fight is done. * @param[in] campaign The campaign data structure * @param[in] shooter Pointer to the aircraft that fired the projectile. * @param[in] aircraft Pointer to the aircraft which was destroyed (alien or phalanx). * @param[in] phalanxWon qtrue if PHALANX won, qfalse if UFO won. * @note Some of these mission values are redone (and not reloaded) in CP_Load * @note shooter may be NULL * @sa UFO_DestroyAllUFOsOnGeoscape_f * @sa CP_Load * @sa CP_SpawnCrashSiteMission */ void AIRFIGHT_ActionsAfterAirfight (const campaign_t* campaign, aircraft_t *shooter, aircraft_t* aircraft, qboolean phalanxWon) { if (phalanxWon) { const byte *color; assert(aircraft); /* change destination of other projectiles aiming aircraft */ AIRFIGHT_RemoveProjectileAimingAircraft(aircraft); /* now update the projectile for the destroyed aircraft, too */ AIRFIGHT_UpdateProjectileForDestroyedAircraft(aircraft); /* don't remove ufo from global array: the mission is not over yet * UFO are removed from game only at the end of the mission * (in case we need to know what item to collect e.g.) */ /* get the color value of the map at the crash position */ color = MAP_GetColor(aircraft->pos, MAPTYPE_TERRAIN, NULL); /* if this color value is not the value for water ... * and we hit the probability to spawn a crashsite mission */ if (!MapIsWater(color)) { CP_SpawnCrashSiteMission(aircraft); } else { Com_DPrintf(DEBUG_CLIENT, "AIRFIGHT_ActionsAfterAirfight: zone: %s (%i:%i:%i)\n", MAP_GetTerrainType(color), color[0], color[1], color[2]); MS_AddNewMessage(_("Interception"), _("UFO interception successful -- UFO lost to sea."), qfalse, MSG_STANDARD, NULL); CP_MissionIsOverByUFO(aircraft); } } else { /* change destination of other projectiles aiming aircraft */ AIRFIGHT_RemoveProjectileAimingAircraft(aircraft); /* and now update the projectile pointers (there still might be some in the air * of the current destroyed aircraft) - this is needed not send the aircraft * back to base as soon as the projectiles will hit their target */ AIRFIGHT_UpdateProjectileForDestroyedAircraft(aircraft); /* notify UFOs that a phalanx aircraft has been destroyed */ UFO_NotifyPhalanxAircraftRemoved(aircraft); if (!MapIsWater(MAP_GetColor(aircraft->pos, MAPTYPE_TERRAIN, NULL))) CP_SpawnRescueMission(aircraft, shooter); else { /* Destroy the aircraft and everything onboard - the aircraft pointer * is no longer valid after this point */ AIR_DestroyAircraft(aircraft); } /* Make UFO proceed with its mission, if it has not been already destroyed */ if (shooter) CP_UFOProceedMission(campaign, shooter); MS_AddNewMessage(_("Interception"), _("You've lost the battle"), qfalse, MSG_DEATH, NULL); } }
/** * @brief Actions to execute when a fight is done. * @param[in] campaign The campaign data structure * @param[in] shooter Pointer to the aircraft that fired the projectile. * @param[in] aircraft Pointer to the aircraft which was destroyed (alien or phalanx). * @param[in] phalanxWon true if PHALANX won, false if UFO won. * @note Some of these mission values are redone (and not reloaded) in CP_Load * @note shooter may be nullptr * @sa UFO_DestroyAllUFOsOnGeoscape_f * @sa CP_Load * @sa CP_SpawnCrashSiteMission */ void AIRFIGHT_ActionsAfterAirfight (const campaign_t* campaign, aircraft_t* shooter, aircraft_t* aircraft, bool phalanxWon) { if (phalanxWon) { const byte* color; assert(aircraft); /* change destination of other projectiles aiming aircraft */ AIRFIGHT_RemoveProjectileAimingAircraft(aircraft); /* now update the projectile for the destroyed aircraft, too */ AIRFIGHT_UpdateProjectileForDestroyedAircraft(aircraft); /* don't remove ufo from global array: the mission is not over yet * UFO are removed from game only at the end of the mission * (in case we need to know what item to collect e.g.) */ /* get the color value of the map at the crash position */ color = GEO_GetColor(aircraft->pos, MAPTYPE_TERRAIN, nullptr); /* if this color value is not the value for water ... * and we hit the probability to spawn a crashsite mission */ if (!MapIsWater(color)) { CP_SpawnCrashSiteMission(aircraft); } else { Com_DPrintf(DEBUG_CLIENT, "AIRFIGHT_ActionsAfterAirfight: zone: %s (%i:%i:%i)\n", cgi->csi->terrainDefs.getTerrainName(color), color[0], color[1], color[2]); MS_AddNewMessage(_("Interception"), _("UFO interception successful -- UFO lost to sea.")); CP_MissionIsOverByUFO(aircraft); } /* skill increase (for aircraft only, base defences skip) */ if (shooter) { /* Increase targeting skill of pilot who destroyed UFO. Never more than 70, see AIRFIGHT_ProbabilityToHit() */ shooter->pilot->chr.score.skills[SKILL_TARGETING] += 1; shooter->pilot->chr.score.skills[SKILL_TARGETING] = std::min(shooter->pilot->chr.score.skills[SKILL_TARGETING], 70); /* Increase evasion skill of pilot who destroyed UFO if the aircraft it attacked can carry weapons. * Never more than 70, see AIRFIGHT_ProbabilityToHit() */ if (aircraft->maxWeapons > 0) { shooter->pilot->chr.score.skills[SKILL_EVADING] += 1; shooter->pilot->chr.score.skills[SKILL_EVADING] = std::min(shooter->pilot->chr.score.skills[SKILL_EVADING], 70); } } } else { /* change destination of other projectiles aiming aircraft */ AIRFIGHT_RemoveProjectileAimingAircraft(aircraft); /* and now update the projectile pointers (there still might be some in the air * of the current destroyed aircraft) - this is needed not send the aircraft * back to base as soon as the projectiles will hit their target */ AIRFIGHT_UpdateProjectileForDestroyedAircraft(aircraft); /* notify UFOs that a phalanx aircraft has been destroyed */ UFO_NotifyPhalanxAircraftRemoved(aircraft); if (!MapIsWater(GEO_GetColor(aircraft->pos, MAPTYPE_TERRAIN, nullptr))) { CP_SpawnRescueMission(aircraft, shooter); } else { /* Destroy the aircraft and everything onboard - the aircraft pointer * is no longer valid after this point */ bool pilotSurvived = false; if (AIR_PilotSurvivedCrash(aircraft)) pilotSurvived = true; AIR_DestroyAircraft(aircraft, pilotSurvived); if (pilotSurvived) MS_AddNewMessage(_("Interception"), _("Pilot ejected from craft"), MSG_STANDARD); else MS_AddNewMessage(_("Interception"), _("Pilot killed in action"), MSG_STANDARD); } /* Make UFO proceed with its mission, if it has not been already destroyed */ if (shooter) CP_UFOProceedMission(campaign, shooter); MS_AddNewMessage(_("Interception"), _("A PHALANX craft has been destroyed"), MSG_DEATH); } }