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 Check if the ufo can shoot back at phalanx aircraft
 * @param[in] campaign The campaign data structure
 * @param[in,out] ufo The ufo to check the shotting for
 * @param[in,out] phalanxAircraft The possible target
 */
void UFO_CheckShootBack (const campaign_t* campaign, aircraft_t *ufo, aircraft_t* phalanxAircraft)
{
	/* check if the ufo is already attacking an aircraft */
	if (ufo->aircraftTarget) {
		/* check if the target flee in a base */
		if (AIR_IsAircraftOnGeoscape(ufo->aircraftTarget))
			AIRFIGHT_ExecuteActions(campaign, ufo, ufo->aircraftTarget);
		else {
			ufo->aircraftTarget = NULL;
			CP_UFOProceedMission(campaign, ufo);
		}
	} else {
		/* check that aircraft is flying */
		if (AIR_IsAircraftOnGeoscape(phalanxAircraft))
			UFO_SendPursuingAircraft(ufo, phalanxAircraft);
	}
}
Ejemplo n.º 3
0
/**
 * @brief Check if the ufo can shoot at a PHALANX aircraft
 */
static void UFO_SearchAircraftTarget (const campaign_t* campaign, aircraft_t *ufo)
{
	float distance = 999999.;

	/* UFO never try to attack a PHALANX aircraft except if they came on earth in that aim */
	if (ufo->mission->stage != STAGE_INTERCEPT) {
		/* Check if UFO is defending itself */
		if (ufo->aircraftTarget)
			UFO_CheckShootBack(campaign, ufo, ufo->aircraftTarget);
		return;
	}

	/* check if the ufo is already attacking an aircraft */
	if (ufo->aircraftTarget) {
		/* check if the target disappeared from geoscape (fled in a base) */
		if (AIR_IsAircraftOnGeoscape(ufo->aircraftTarget))
			AIRFIGHT_ExecuteActions(campaign, ufo, ufo->aircraftTarget);
		else
			ufo->aircraftTarget = NULL;
		return;
	}

	ufo->status = AIR_TRANSIT;
	AIR_Foreach(phalanxAircraft) {
		/* check that aircraft is flying */
		if (AIR_IsAircraftOnGeoscape(phalanxAircraft)) {
			/* get the distance from ufo to aircraft */
			const float dist = GetDistanceOnGlobe(ufo->pos, phalanxAircraft->pos);
			/* check out of reach */
			if (dist > MAX_DETECTING_RANGE)
				continue;
			/* choose the nearest target */
			if (dist < distance) {
				distance = dist;
				if (UFO_SendPursuingAircraft(ufo, phalanxAircraft) && UFO_IsUFOSeenOnGeoscape(ufo)) {
					/* stop time and notify */
					MSO_CheckAddNewMessage(NT_UFO_ATTACKING, _("Notice"), va(_("A UFO is flying toward %s"), phalanxAircraft->name), qfalse,
						MSG_STANDARD, NULL);
					/** @todo present a popup with possible orders like: return to base, attack the ufo, try to flee the rockets */
				}
			}
		}
	}
}
Ejemplo n.º 4
0
/**
 * @brief Check events for UFOs: Appears or disappears on radars
 * @return qtrue if any new ufo was detected during this iteration, qfalse otherwise
 */
qboolean UFO_CampaignCheckEvents (void)
{
	qboolean newDetection;
	aircraft_t *ufo;

	newDetection = qfalse;

	/* For each ufo in geoscape */
	ufo = NULL;
	while ((ufo = UFO_GetNext(ufo)) != NULL) {
		char detectedBy[MAX_VAR] = "";
		float minDistance = -1;
		/* detected tells us whether or not a UFO is detected NOW, whereas ufo->detected tells
		 * us whether or not the UFO was detected PREVIOUSLY. */
		qboolean detected = qfalse;
		base_t *base;

		/* don't update UFO status id UFO is landed or crashed */
		if (ufo->landed)
			continue;

		/* note: We can't exit these loops as soon as we found the UFO detected
		 * RADAR_CheckUFOSensored registers the UFO in every radars' detection list
		 * which detect it */

		/* Check if UFO is detected by an aircraft */
		AIR_Foreach(aircraft) {
			if (!AIR_IsAircraftOnGeoscape(aircraft))
				continue;
			/* maybe the ufo is already detected, don't reset it */
			if (RADAR_CheckUFOSensored(&aircraft->radar, aircraft->pos, ufo, detected | ufo->detected)) {
				const int distance = GetDistanceOnGlobe(aircraft->pos, ufo->pos);
				detected = qtrue;
				if (minDistance < 0 || minDistance > distance) {
					minDistance = distance;
					Q_strncpyz(detectedBy, aircraft->name, sizeof(detectedBy));
				}
			}
		}

		/* Check if UFO is detected by a base */
		base = NULL;
		while ((base = B_GetNext(base)) != NULL) {
			if (!B_GetBuildingStatus(base, B_POWER))
				continue;

			/* maybe the ufo is already detected, don't reset it */
			if (RADAR_CheckUFOSensored(&base->radar, base->pos, ufo, detected | ufo->detected)) {
				const int distance = GetDistanceOnGlobe(base->pos, ufo->pos);
				detected = qtrue;
				if (minDistance < 0 || minDistance > distance) {
					minDistance = distance;
					Q_strncpyz(detectedBy, base->name, sizeof(detectedBy));
				}
			}

		}

		/* Check if UFO is detected by a radartower */
		INS_Foreach(installation) {
			/* maybe the ufo is already detected, don't reset it */
			if (RADAR_CheckUFOSensored(&installation->radar, installation->pos, ufo, detected | ufo->detected)) {
				const int distance = GetDistanceOnGlobe(installation->pos, ufo->pos);
				detected = qtrue;
				if (minDistance < 0 || minDistance > distance) {
					minDistance = distance;
					Q_strncpyz(detectedBy, installation->name, sizeof(detectedBy));
				}
			}
		}

		/* Check if ufo appears or disappears on radar */
		if (detected != ufo->detected) {
			if (detected) {
				/* if UFO is aiming a PHALANX aircraft, warn player */
				if (ufo->aircraftTarget) {
					/* stop time and notify */
					MSO_CheckAddNewMessage(NT_UFO_ATTACKING, _("Notice"), va(_("A UFO is flying toward %s"), ufo->aircraftTarget->name), qfalse,
							MSG_STANDARD, NULL);
					/** @todo present a popup with possible orders like: return to base, attack the ufo, try to flee the rockets
					 * @sa UFO_SearchAircraftTarget */
				} else {
					MSO_CheckAddNewMessage(NT_UFO_SPOTTED, _("Notice"), va(_("Our radar detected a new UFO near %s"), detectedBy), qfalse,
							MSG_UFOSPOTTED, NULL);
				}
				newDetection = qtrue;
				UFO_DetectNewUFO(ufo);
			} else if (!detected) {
				MSO_CheckAddNewMessage(NT_UFO_SIGNAL_LOST, _("Notice"), _("Our radar has lost the tracking on a UFO"), qfalse, MSG_UFOLOST, NULL);
				/* Make this UFO undetected */
				ufo->detected = qfalse;
				/* Notify that ufo disappeared */
				AIR_AircraftsUFODisappear(ufo);
				MAP_NotifyUFODisappear(ufo);

				/* Deactivate Radar overlay */
				RADAR_DeactivateRadarOverlay();
			}
		}
	}
	return newDetection;
}
Ejemplo n.º 5
0
/**
 * @brief Check if the ufo can shoot at a PHALANX aircraft and whether it should follow another ufo
 */
static void UFO_SearchAircraftTarget (const campaign_t* campaign, aircraft_t* ufo, float maxDetectionRange = MAX_DETECTING_RANGE)
{
	float distance = 999999.;

	/* UFO never try to attack a PHALANX aircraft except if they came on earth in that aim */
	if (ufo->mission->stage != STAGE_INTERCEPT) {
		/* Check if UFO is defending itself */
		if (ufo->aircraftTarget)
			UFO_CheckShootBack(campaign, ufo, ufo->aircraftTarget);
		return;
	}

	/* check if the ufo is already attacking an aircraft */
	if (ufo->aircraftTarget) {
		/* check if the target disappeared from geoscape (fled in a base) */
		if (AIR_IsAircraftOnGeoscape(ufo->aircraftTarget))
			AIRFIGHT_ExecuteActions(campaign, ufo, ufo->aircraftTarget);
		else
			ufo->aircraftTarget = nullptr;
		return;
	}

	ufo->status = AIR_TRANSIT;
	AIR_Foreach(phalanxAircraft) {
		/* check that aircraft is flying */
		if (AIR_IsAircraftOnGeoscape(phalanxAircraft)) {
			/* get the distance from ufo to aircraft */
			const float dist = GetDistanceOnGlobe(ufo->pos, phalanxAircraft->pos);
			/* check out of reach */
			if (dist > maxDetectionRange)
				continue;
			/* choose the nearest target */
			if (dist < distance) {
				distance = dist;
				if (UFO_SendPursuingAircraft(ufo, phalanxAircraft) && UFO_IsUFOSeenOnGeoscape(ufo)) {
					/* stop time and notify */
					MSO_CheckAddNewMessage(NT_UFO_ATTACKING, _("Notice"), va(_("A UFO is flying toward %s"), phalanxAircraft->name));
					/** @todo present a popup with possible orders like: return to base, attack the ufo, try to flee the rockets */
					return;
				}
			}
		}
	}

	/* if this ufo is a leader, it does not try to search another one */
	if (ufo->leader)
		return;
	aircraft_t* otherUFO = nullptr;
	const float polarCoordinatesOffset = 1.0f;
	while ((otherUFO = UFO_GetNextOnGeoscape(otherUFO)) != nullptr) {
		if (otherUFO == ufo)
			continue;
		if (otherUFO->leader) {
			vec2_t dest;
			AIR_GetDestinationWhilePursuing(ufo, otherUFO, dest);
			dest[0] += polarCoordinatesOffset;
			dest[1] += polarCoordinatesOffset;
			GEO_CalcLine(ufo->pos, dest, &ufo->route);
			ufo->time = 0;
			ufo->point = 0;
			break;
		}
	}
}