/** * @brief Make the specified UFO pursue a phalanx aircraft. * @param[in,out] ufo Pointer to the UFO. * @param[in,out] aircraft Pointer to the target aircraft. * @sa UFO_SendAttackBase */ qboolean UFO_SendPursuingAircraft (aircraft_t* ufo, aircraft_t* aircraft) { int slotIdx; vec2_t dest; assert(ufo); assert(aircraft); /* check whether the ufo can shoot the aircraft - if not, don't try it even */ slotIdx = AIRFIGHT_ChooseWeapon(ufo->weapons, ufo->maxWeapons, ufo->pos, aircraft->pos); if (slotIdx == AIRFIGHT_WEAPON_CAN_NEVER_SHOOT) { /* no ammo left: stop attack */ ufo->status = AIR_TRANSIT; return qfalse; } AIR_GetDestinationWhilePursuing(ufo, aircraft, &dest); MAP_MapCalcLine(ufo->pos, dest, &ufo->route); ufo->status = AIR_UFO; ufo->time = 0; ufo->point = 0; ufo->aircraftTarget = aircraft; return qtrue; }
/** * @brief Determine what action should be performed when a Intercept mission stage ends. * @param[in] mission Pointer to the mission which stage ended. */ void CP_InterceptNextStage (mission_t* mission) { switch (mission->stage) { case STAGE_NOT_ACTIVE: /* Create Intercept mission */ CP_MissionBegin(mission); break; case STAGE_COME_FROM_ORBIT: /* UFO start looking for target */ CP_InterceptMissionSet(mission); break; case STAGE_MISSION_GOTO: CP_InterceptAttackInstallation(mission); break; case STAGE_INTERCEPT: assert(mission->ufo); /* Leave earth */ if (AIRFIGHT_ChooseWeapon(mission->ufo->weapons, mission->ufo->maxWeapons, mission->ufo->pos, mission->ufo->pos) != AIRFIGHT_WEAPON_CAN_NEVER_SHOOT && mission->ufo->status == AIR_UFO && !mission->data.installation) { /* UFO is fighting and has still ammo, wait a little bit before leaving (UFO is not attacking an installation) */ const date_t AdditionalDelay = {0, 3600}; /* check every hour if there is still ammos */ mission->finalDate = Date_Add(ccs.date, AdditionalDelay); } else CP_InterceptMissionLeave(mission, true); break; case STAGE_RETURN_TO_ORBIT: /* mission is over, remove mission */ CP_InterceptMissionIsSuccess(mission); break; default: Com_Printf("CP_InterceptNextStage: Unknown stage: %i, removing mission.\n", mission->stage); CP_MissionRemove(mission); break; } }
/** * @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); } } }