/** * @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 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; } } }