Ejemplo n.º 1
0
/**
 * @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);
}
Ejemplo n.º 2
0
/**
 * @brief Update xviInfection value for each nation, using the XVI overlay.
 * @note should be executed after all daily event that could change XVI overlay
 */
void CP_UpdateNationXVIInfection (void)
{
	/* No need to update XVI levels if the overlay didn't change */
	if (!xviNationInfectionNeedsUpdate)
		return;

	/* width in pixel of the XVI overlay */
	int width;
	/* height in pixel of the XVI overlay */
	int height;
	CP_GetXVIMapDimensions(&width, &height);

	const float heightPerDegree = height / 180.0f;
	const float widthPerDegree = width / 360.0f;
	/* parameter used to normalize nation XVI level.
	 * decrease this factor to increase XVI level per nation */
	const float AREA_FACTOR = 650.0f;
	/* area used to normalized XVI infection level for each nation.
	 * depend on overlay size so that if we change resolution of
	 * overlay it doesn't impact nation XIInfection */
	const float normalizingArea = width * height / AREA_FACTOR;

	/* temporary array to store the XVI levels */
	float xviInfection[MAX_NATIONS];
	/* Initialize array */
	OBJZERO(xviInfection);

	for (int y = 0; y < height; y++) {
		int sum[MAX_NATIONS];
		const byte* previousNationColor;
		const nation_t* nation;
		/* current position (in latitude / longitude) */
		vec2_t currentPos;

		OBJZERO(sum);

		Vector2Set(currentPos, 180.0f, 90.0f - y / heightPerDegree);
		previousNationColor = GEO_GetColor(currentPos, MAPTYPE_NATIONS, nullptr);
		nation = GEO_GetNation(currentPos);

		for (int x = 0; x < width; x++) {
			const byte* nationColor;
			currentPos[0] = 180.0f - x / widthPerDegree;
			nationColor = GEO_GetColor(currentPos, MAPTYPE_NATIONS, nullptr);
			if (!VectorCompare(nationColor, previousNationColor)) {
				previousNationColor = nationColor;
				nation = GEO_GetNation(currentPos);
			}
			if (nation) {
				const int xviLevel = CP_GetXVILevel(x, y);
				if (xviLevel > 0)
					sum[nation->idx] += xviLevel;
			}
		}
		/* divide the total XVI infection by the area of a pixel
		 * because pixel are smaller as you go closer from the pole */
		for (int nationIdx = 0; nationIdx < ccs.numNations; nationIdx++)
			xviInfection[nationIdx] += ((float) sum[nationIdx]) / (cos(torad * currentPos[1]) * normalizingArea);
	}

	/* copy the new values of XVI infection level into nation array */
	for (int nationIdx = 0; nationIdx < ccs.numNations; nationIdx++) {
		nation_t* nation = NAT_GetNationByIDX(nationIdx);
		nation->stats[0].xviInfection = ceil(xviInfection[nation->idx]);
	}

	xviNationInfectionNeedsUpdate = false;
}
Ejemplo n.º 3
0
/**
 * @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);
	}
}