/** * @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); } } }
/** * @sa AIR_IsAircraftOnGeoscape */ aircraft_t *UFO_GetNextOnGeoscape (aircraft_t *lastUFO) { aircraft_t* ufo = lastUFO; while ((ufo = UFO_GetNext(ufo)) != NULL) { if (UFO_IsUFOSeenOnGeoscape(ufo) #ifdef DEBUG || Cvar_GetInteger("debug_showufos") #endif ) return ufo; } return NULL; }
/** * @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 */ } } } } }
/** * @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; } } }