Beispiel #1
0
/**
 * @brief Decide what an attacking aircraft can do.
 * @param[in] campaign The campaign data structure
 * @param[in] shooter The aircraft we attack with.
 * @param[in] target The ufo we are going to attack.
 * @todo Implement me and display an attack popup.
 */
void AIRFIGHT_ExecuteActions (const campaign_t* campaign, aircraft_t* shooter, aircraft_t* target)
{
	/* some asserts */
	assert(shooter);
	assert(target);

	/* Check if the attacking aircraft can shoot */
	const int slotIdx = AIRFIGHT_ChooseWeapon(shooter->weapons, shooter->maxWeapons, shooter->pos, target->pos);

	/* if weapon found that can shoot */
	if (slotIdx >= AIRFIGHT_WEAPON_CAN_SHOOT) {
		aircraftSlot_t* weaponSlot = &shooter->weapons[slotIdx];
		const objDef_t* ammo = weaponSlot->ammo;

		/* shoot */
		if (AIRFIGHT_AddProjectile(nullptr, nullptr, shooter, target, weaponSlot)) {
			/* will we miss the target ? */
			const float probability = frand();
			Com_DPrintf(DEBUG_CLIENT, "AIRFIGHT_ExecuteActions: %s - Random probability to hit: %f\n", shooter->name, probability);
			weaponSlot->delayNextShot = ammo->craftitem.weaponDelay;

			const float calculatedProbability = AIRFIGHT_ProbabilityToHit(shooter, target, shooter->weapons + slotIdx);
			Com_DPrintf(DEBUG_CLIENT, "AIRFIGHT_ExecuteActions: %s - Calculated probability to hit: %f\n", shooter->name, calculatedProbability);

			if (probability > calculatedProbability)
				AIRFIGHT_MissTarget(&ccs.projectiles[ccs.numProjectiles - 1]);

			if (shooter->type != AIRCRAFT_UFO) {
				/* Maybe UFO is going to shoot back ? */
				UFO_CheckShootBack(campaign, target, shooter);
			} else {
				/* an undetected UFO within radar range and firing should become detected */
				if (!shooter->detected && RADAR_CheckRadarSensored(shooter->pos)) {
					/* stop time and notify */
					MSO_CheckAddNewMessage(NT_UFO_ATTACKING, _("Notice"), va(_("A UFO is shooting at %s"), target->name));
					RADAR_AddDetectedUFOToEveryRadar(shooter);
					UFO_DetectNewUFO(shooter);
				}
			}
		}
	} else if (slotIdx == AIRFIGHT_WEAPON_CAN_NOT_SHOOT_AT_THE_MOMENT) {
		/* no ammo to fire atm (too far or reloading), pursue target */
		if (shooter->type == AIRCRAFT_UFO) {
			/** @todo This should be calculated only when target destination changes, or when aircraft speed changes.
			 *  @sa AIR_GetDestination */
			UFO_SendPursuingAircraft(shooter, target);
		} else
			AIR_SendAircraftPursuingUFO(shooter, target);
	} else {
		/* no ammo left, or no weapon, proceed with mission */
		if (shooter->type == AIRCRAFT_UFO) {
			shooter->aircraftTarget = nullptr;		/* reset target */
			CP_UFOProceedMission(campaign, shooter);
		} else {
			MS_AddNewMessage(_("Notice"), _("Our aircraft has no more ammo left - returning to home base now."));
			AIR_AircraftReturnToBase(shooter);
		}
	}
}
/**
 * @brief Set all projectile aiming a given aircraft to an idle destination.
 * @param[in] aircraft Pointer to the aimed aircraft.
 * @note This function is called when @c aircraft is destroyed.
 * @sa AIRFIGHT_ActionsAfterAirfight
 */
void AIRFIGHT_RemoveProjectileAimingAircraft (const aircraft_t * aircraft)
{
	aircraftProjectile_t *projectile;
	int idx = 0;

	if (!aircraft)
		return;

	for (projectile = ccs.projectiles; idx < ccs.numProjectiles; projectile++, idx++) {
		if (projectile->aimedAircraft == aircraft)
			AIRFIGHT_MissTarget(projectile, qtrue);
	}
}
/**
 * @brief Check if one type of battery (missile or laser) can shoot now.
 * @param[in] installation Pointer to the firing intallation.
 * @param[in] weapons The installation weapon to check and fire.
 */
static void AIRFIGHT_InstallationShoot (const installation_t *installation, baseWeapon_t *weapons, int maxWeapons)
{
	int i, test;
	float distance;

	for (i = 0; i < maxWeapons; i++) {
		aircraft_t *target = weapons[i].target;
		aircraftSlot_t *slot = &(weapons[i].slot);
		/* if no target, can't shoot */
		if (!target)
			continue;

		/* If the weapon is not ready in base, can't shoot. */
		if (slot->installationTime > 0)
			continue;

		/* if weapon is reloading, can't shoot */
		if (slot->delayNextShot > 0)
			continue;

		/* check that the ufo is still visible */
		if (!UFO_IsUFOSeenOnGeoscape(target)) {
			weapons[i].target = NULL;
			continue;
		}

		/* Check if we can still fire on this target. */
		distance = GetDistanceOnGlobe(installation->pos, target->pos);
		test = AIRFIGHT_CheckWeapon(slot, distance);
		/* weapon unable to shoot, reset target */
		if (test == AIRFIGHT_WEAPON_CAN_NEVER_SHOOT) {
			weapons[i].target = NULL;
			continue;
		}
		/* we can't shoot with this weapon atm, wait to see if UFO comes closer */
		else if (test == AIRFIGHT_WEAPON_CAN_NOT_SHOOT_AT_THE_MOMENT)
			continue;
		/* target is too far, wait to see if UFO comes closer */
		else if (distance > slot->ammo->craftitem.stats[AIR_STATS_WRANGE])
			continue;

		/* shoot */
		if (AIRFIGHT_AddProjectile(NULL, installation, NULL, target, slot)) {
			slot->delayNextShot = slot->ammo->craftitem.weaponDelay;
			/* will we miss the target ? */
			if (frand() > AIRFIGHT_ProbabilityToHit(NULL, target, slot))
				AIRFIGHT_MissTarget(&ccs.projectiles[ccs.numProjectiles - 1], qfalse);
		}
	}
}
Beispiel #4
0
/**
 * @brief Set all projectile aiming a given aircraft to an idle destination.
 * @param[in] aircraft Pointer to the aimed aircraft.
 * @note This function is called when @c aircraft is destroyed.
 * @sa AIRFIGHT_ActionsAfterAirfight
 */
void AIRFIGHT_RemoveProjectileAimingAircraft (const aircraft_t* aircraft)
{
	aircraftProjectile_t* projectile;
	int idx = 0;

	if (!aircraft)
		return;

	for (projectile = ccs.projectiles; idx < ccs.numProjectiles; projectile++, idx++) {
		if (projectile->aimedAircraft != aircraft)
			continue;

		AIRFIGHT_MissTarget(projectile);
		if (projectile->attackingAircraft && projectile->attackingAircraft->homebase) {
			assert(!AIR_IsUFO(projectile->attackingAircraft));
			AIR_AircraftReturnToBase(projectile->attackingAircraft);
		}
	}
}