cp_ufo.c

Go to the documentation of this file.
00001 
00006 /*
00007  Copyright (C) 2002-2010 UFO: Alien Invasion.
00008 
00009  This program is free software; you can redistribute it and/or
00010  modify it under the terms of the GNU General Public License
00011  as published by the Free Software Foundation; either version 2
00012  of the License, or (at your option) any later version.
00013 
00014  This program is distributed in the hope that it will be useful,
00015  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018  See the GNU General Public License for more details.
00019 
00020  You should have received a copy of the GNU General Public License
00021  along with this program; if not, write to the Free Software
00022  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024  */
00025 
00026 #include "../cl_shared.h"
00027 #include "cp_campaign.h"
00028 #include "cp_map.h"
00029 #include "cp_ufo.h"
00030 #include "cp_aircraft.h"
00031 #include "cp_mapfightequip.h"
00032 
00033 static const float MAX_DETECTING_RANGE = 25.0f; 
00039 aircraft_t* UFO_GetByIDX (const int idx)
00040 {
00041     assert(idx >= 0 && idx < MAX_UFOONGEOSCAPE);
00042     return &ccs.ufos[idx];
00043 }
00044 
00051 const technology_t* UFO_GetTechnologyFromType (const ufoType_t type)
00052 {
00053     const char *id = Com_UFOTypeToShortName(type);
00054     const technology_t *tech = RS_GetTechByProvided(id);
00055     return tech;
00056 }
00057 
00063 const aircraft_t* UFO_GetByType (const ufoType_t type)
00064 {
00065     int i;
00066 
00067     for (i = 0; i < ccs.numAircraftTemplates; i++) {
00068         aircraft_t *ufo = &ccs.aircraftTemplates[i];
00069         if (ufo->ufotype == type)
00070             return ufo;
00071     }
00072 
00073     Com_Error(ERR_DROP, "No ufo with type %i found", type);
00074 }
00075 
00081 qboolean UFO_ShouldAppearOnGeoscape (const ufoType_t type)
00082 {
00083     const aircraft_t *ufo = UFO_GetByType(type);
00084 
00085     return ufo->ufoInterestOnGeoscape <= ccs.overallInterest;
00086 }
00087 
00095 const char* UFO_TypeToName (ufoType_t type)
00096 {
00097     const technology_t *tech = UFO_GetTechnologyFromType(type);
00098     if (tech)
00099         return _(tech->name);
00100     Com_Error(ERR_DROP, "UFO_TypeToName(): Unknown UFO type %i\n", type);
00101 }
00106 const char* UFO_AircraftToIDOnGeoscape (const aircraft_t *ufocraft)
00107 {
00108     const technology_t *tech = ufocraft->tech;
00109 
00110     assert(tech);
00111 
00112     if (ufocraft->detectionIdx)
00113         return va("%s #%i", (RS_IsResearched_ptr(tech)) ? _(ufocraft->name) : _("UFO"), ufocraft->detectionIdx);
00114     return (RS_IsResearched_ptr(tech)) ? _(ufocraft->name) : _("UFO");
00115 }
00116 
00121 const char* UFO_MissionResultToString (void)
00122 {
00123     const char *ufoName = Com_UFOTypeToShortName(ccs.missionResults.ufotype);
00124     const aircraft_t *aircraft = AIR_GetAircraft(ufoName);
00125     const char *geoscapeName = UFO_AircraftToIDOnGeoscape(aircraft);
00126     if (ccs.missionResults.crashsite)
00127         return va(_("\nSecured crashed %s (%.0f%%)\n"), geoscapeName, ccs.missionResults.ufoCondition * 100);
00128     else
00129         return va(_("\nSecured landed %s\n"), geoscapeName);
00130 }
00131 
00137 void UFO_SetRandomDest (aircraft_t* ufocraft)
00138 {
00139     vec2_t pos;
00140 
00141     CP_GetRandomPosOnGeoscape(pos, qfalse);
00142 
00143     UFO_SendToDestination(ufocraft, pos);
00144 }
00145 
00152 void UFO_SetRandomDestAround (aircraft_t* ufocraft, vec2_t pos)
00153 {
00154     vec2_t dest;
00155     const float spread = 2.0f;
00156     float rand1, rand2;
00157 
00158     gaussrand(&rand1, &rand2);
00159     rand1 *= spread;
00160     rand2 *= spread;
00161 
00162     Vector2Set(dest, pos[0] + rand1, pos[1] + rand2);
00163 
00164     UFO_SendToDestination(ufocraft, dest);
00165 }
00166 
00172 static void UFO_SetRandomPos (aircraft_t* ufocraft)
00173 {
00174     vec2_t pos;
00175 
00176     CP_GetRandomPosOnGeoscape(pos, qfalse);
00177 
00178     Vector2Copy(pos, ufocraft->pos);
00179 }
00180 
00187 static int UFO_IsTargetOfBase (const aircraft_t const *ufo, const base_t const *base)
00188 {
00189     int i;
00190 
00191     for (i = 0; i < base->numBatteries; i++) {
00192         if (base->batteries[i].target == ufo)
00193             return UFO_IS_TARGET_OF_MISSILE;
00194     }
00195 
00196     for (i = 0; i < base->numLasers; i++) {
00197         if (base->lasers[i].target == ufo)
00198             return UFO_IS_TARGET_OF_LASER;
00199     }
00200 
00201     return UFO_IS_NO_TARGET;
00202 }
00203 
00210 static int UFO_IsTargetOfInstallation (const aircraft_t const *ufo, const installation_t const *installation)
00211 {
00212     int i;
00213 
00214     for (i = 0; i < installation->numBatteries; i++) {
00215         if (installation->batteries[i].target == ufo)
00216             return UFO_IS_TARGET_OF_MISSILE;
00217     }
00218 
00219     return UFO_IS_NO_TARGET;
00220 }
00221 
00233 static void UFO_UpdateAlienInterestForOneBase (const aircraft_t const *ufo, base_t *base)
00234 {
00235     float probability;
00236     float distance;
00237     const float decreasingDistance = 10.0f; 
00239     const float decreasingFactor = 5.0f;
00240 
00241     /* ufo can't find base if it's too far */
00242     distance = GetDistanceOnGlobe(ufo->pos, base->pos);
00243     if (distance > MAX_DETECTING_RANGE)
00244         return;
00245 
00246     /* UFO has an increased probability to find a base if it is firing at it */
00247     switch (UFO_IsTargetOfBase(ufo, base)) {
00248     case UFO_IS_TARGET_OF_MISSILE:
00249         probability = 0.01f;
00250         break;
00251     case UFO_IS_TARGET_OF_LASER:
00252         probability = 0.001f;
00253         break;
00254     default:
00255         probability = 0.0001f;
00256         break;
00257     }
00258 
00259     /* decrease probability if the ufo is far from base */
00260     if (distance > decreasingDistance)
00261         probability /= decreasingFactor;
00262 
00263     /* probability must depend on DETECTION_INTERVAL (in case we change the value) */
00264     probability *= DETECTION_INTERVAL;
00265 
00266     base->alienInterest += probability;
00267 }
00268 
00275 static void UFO_UpdateAlienInterestForOneInstallation (const aircraft_t const *ufo, installation_t *installation)
00276 {
00277     float probability;
00278     float distance;
00279     const float decreasingDistance = 10.0f; 
00281     const float decreasingFactor = 5.0f;
00282 
00283     /* ufo can't find base if it's too far */
00284     distance = GetDistanceOnGlobe(ufo->pos, installation->pos);
00285     if (distance > MAX_DETECTING_RANGE)
00286         return;
00287 
00288     /* UFO has an increased probability to find a base if it is firing at it */
00289     switch (UFO_IsTargetOfInstallation(ufo, installation)) {
00290     case UFO_IS_TARGET_OF_MISSILE:
00291         probability = 0.01f;
00292         break;
00293     case UFO_IS_TARGET_OF_LASER:
00294         probability = 0.001f;
00295         break;
00296     default:
00297         probability = 0.0001f;
00298         break;
00299     }
00300 
00301     /* decrease probability if the ufo is far from base */
00302     if (distance > decreasingDistance)
00303         probability /= decreasingFactor;
00304 
00305     /* probability must depend on DETECTION_INTERVAL (in case we change the value) */
00306     probability *= DETECTION_INTERVAL;
00307 
00308     installation->alienInterest += probability;
00309 }
00310 
00317 void UFO_UpdateAlienInterestForAllBasesAndInstallations (void)
00318 {
00319     int ufoIdx;
00320 
00321     for (ufoIdx = 0; ufoIdx < ccs.numUFOs; ufoIdx++) {
00322         const aircraft_t const *ufo = UFO_GetByIDX(ufoIdx);
00323         int idx;
00324 
00325         /* landed UFO can't detect any phalanx base or installation */
00326         if (ufo->landed)
00327             continue;
00328 
00329         for (idx = 0; idx < MAX_BASES; idx++) {
00330             base_t *base = B_GetFoundedBaseByIDX(idx);
00331             if (!base)
00332                 continue;
00333             UFO_UpdateAlienInterestForOneBase(ufo, base);
00334         }
00335 
00336         for (idx = 0; idx < MAX_INSTALLATIONS; idx++) {
00337             installation_t *installation = INS_GetFoundedInstallationByIDX(idx);
00338             if (!installation)
00339                 continue;
00340             UFO_UpdateAlienInterestForOneInstallation(ufo, installation);
00341         }
00342     }
00343 }
00344 
00348 static void UFO_SearchAircraftTarget (aircraft_t *ufo)
00349 {
00350     int baseIdx;
00351     aircraft_t* phalanxAircraft;
00352     float distance = 999999.;
00353 
00354     /* UFO never try to attack a PHALANX aircraft except if they came on earth in that aim */
00355     if (ufo->mission->stage != STAGE_INTERCEPT) {
00356         /* Check if UFO is defending itself */
00357         if (ufo->aircraftTarget)
00358             UFO_CheckShootBack(ufo, ufo->aircraftTarget);
00359         return;
00360     }
00361 
00362     /* check if the ufo is already attacking an aircraft */
00363     if (ufo->aircraftTarget) {
00364         /* check if the target disappeared from geoscape (fled in a base) */
00365         if (AIR_IsAircraftOnGeoscape(ufo->aircraftTarget))
00366             AIRFIGHT_ExecuteActions(ufo, ufo->aircraftTarget);
00367         else
00368             ufo->aircraftTarget = NULL;
00369         return;
00370     }
00371 
00372     ufo->status = AIR_TRANSIT;
00373     for (baseIdx = 0; baseIdx < MAX_BASES; baseIdx++) {
00374         const base_t *base = B_GetFoundedBaseByIDX(baseIdx);
00375 
00376         if (!base)
00377             continue;
00378 
00379         /* check if the ufo can attack an aircraft */
00380         phalanxAircraft = NULL;
00381         while ((phalanxAircraft = AIR_GetNextFromBase(base, phalanxAircraft)) != NULL) {
00382             /* check that aircraft is flying */
00383             if (AIR_IsAircraftOnGeoscape(phalanxAircraft)) {
00384                 /* get the distance from ufo to aircraft */
00385                 const float dist = GetDistanceOnGlobe(ufo->pos, phalanxAircraft->pos);
00386                 /* check out of reach */
00387                 if (dist > MAX_DETECTING_RANGE)
00388                     continue;
00389                 /* choose the nearest target */
00390                 if (dist < distance) {
00391                     distance = dist;
00392                     if (UFO_SendPursuingAircraft(ufo, phalanxAircraft) && UFO_IsUFOSeenOnGeoscape(ufo)) {
00393                         /* stop time and notify */
00394                         MSO_CheckAddNewMessage(NT_UFO_ATTACKING, _("Notice"), va(_("A UFO is flying toward %s"), phalanxAircraft->name), qfalse,
00395                                 MSG_STANDARD, NULL);
00397                     }
00398                 }
00399             }
00400         }
00401     }
00402 }
00403 
00410 qboolean UFO_SendPursuingAircraft (aircraft_t* ufo, aircraft_t* aircraft)
00411 {
00412     int slotIdx;
00413     vec2_t dest;
00414 
00415     assert(ufo);
00416     assert(aircraft);
00417 
00418     /* check whether the ufo can shoot the aircraft - if not, don't try it even */
00419     slotIdx = AIRFIGHT_ChooseWeapon(ufo->weapons, ufo->maxWeapons, ufo->pos, aircraft->pos);
00420     if (slotIdx == AIRFIGHT_WEAPON_CAN_NEVER_SHOOT) {
00421         /* no ammo left: stop attack */
00422         ufo->status = AIR_TRANSIT;
00423         return qfalse;
00424     }
00425 
00426     AIR_GetDestinationWhilePursuing(ufo, aircraft, &dest);
00427     MAP_MapCalcLine(ufo->pos, dest, &ufo->route);
00428     ufo->status = AIR_UFO;
00429     ufo->time = 0;
00430     ufo->point = 0;
00431     ufo->aircraftTarget = aircraft;
00432 
00433     return qtrue;
00434 }
00435 
00442 void UFO_SendToDestination (aircraft_t* ufo, vec2_t dest)
00443 {
00444     assert(ufo);
00445 
00446     MAP_MapCalcLine(ufo->pos, dest, &ufo->route);
00447     ufo->status = AIR_TRANSIT;
00448     ufo->time = 0;
00449     ufo->point = 0;
00450 }
00451 
00455 void UFO_CheckShootBack (aircraft_t *ufo, aircraft_t* phalanxAircraft)
00456 {
00457     /* check if the ufo is already attacking an aircraft */
00458     if (ufo->aircraftTarget) {
00459         /* check if the target flee in a base */
00460         if (AIR_IsAircraftOnGeoscape(ufo->aircraftTarget))
00461             AIRFIGHT_ExecuteActions(ufo, ufo->aircraftTarget);
00462         else {
00463             ufo->aircraftTarget = NULL;
00464             CP_UFOProceedMission(ufo);
00465         }
00466     } else {
00467         /* check that aircraft is flying */
00468         if (AIR_IsAircraftOnGeoscape(phalanxAircraft))
00469             UFO_SendPursuingAircraft(ufo, phalanxAircraft);
00470     }
00471 }
00472 
00477 void UFO_CampaignRunUFOs (int deltaTime)
00478 {
00479     int ufoIdx, k;
00480 
00481     assert(deltaTime >= 0);
00482 
00483     /* deltaTime may be 0 if a UFO has been detection occurred */
00484     if (!deltaTime)
00485         return;
00486 
00487     /* now the ufos are flying around, too - cycle backward - ufo might be destroyed */
00488     for (ufoIdx = ccs.numUFOs - 1; ufoIdx >= 0; ufoIdx--) {
00489         aircraft_t *ufo = UFO_GetByIDX(ufoIdx);
00490         /* don't run a landed ufo */
00491         if (ufo->landed)
00492             continue;
00493 
00494         /* Every UFO on geoscape should have a mission assigned */
00495         assert(ufo->mission);
00496 
00497         /* reached target and not following a phalanx aircraft? then we need a new destination */
00498         if (AIR_AircraftMakeMove(deltaTime, ufo) && ufo->status != AIR_UFO) {
00499             float *end;
00500             end = ufo->route.point[ufo->route.numPoints - 1];
00501             Vector2Copy(end, ufo->pos);
00502             MAP_CheckPositionBoundaries(ufo->pos);
00503             if (ufo->mission->stage == STAGE_INTERCEPT && ufo->mission->data) {
00504                 /* Attacking an installation: fly over this installation */
00505                 UFO_SetRandomDestAround(ufo, ufo->mission->pos);
00506             } else
00507                 UFO_SetRandomDest(ufo);
00508             if (CP_CheckNextStageDestination(ufo))
00509                 /* UFO has been removed from game */
00510                 continue;
00511             /* UFO was destroyed (maybe because the mission was removed) */
00512             if (ufoIdx == ccs.numUFOs)
00513                 continue;
00514         }
00515 
00516         /* is there a PHALANX aircraft to shoot at ? */
00517         UFO_SearchAircraftTarget(ufo);
00518 
00519         /* antimatter tanks */
00520         if (ufo->fuel <= 0)
00521             ufo->fuel = ufo->stats[AIR_STATS_FUELSIZE];
00522 
00523         /* Update delay to launch next projectile */
00524         for (k = 0; k < ufo->maxWeapons; k++) {
00525             aircraftSlot_t *slot = &ufo->weapons[k];
00526             if (slot->delayNextShot > 0)
00527                 slot->delayNextShot -= deltaTime;
00528         }
00529     }
00530 }
00531 
00532 #ifdef DEBUG
00533 
00536 static void UFO_DestroyUFOs_f (void)
00537 {
00538     aircraft_t* ufo;
00539 
00540     for (ufo = ccs.ufos; ufo < ccs.ufos + ccs.numUFOs; ufo++) {
00541         AIRFIGHT_ActionsAfterAirfight(NULL, ufo, qtrue);
00542     }
00543 }
00544 
00549 static void UFO_ListOnGeoscape_f (void)
00550 {
00551     aircraft_t* ufo;
00552     int k;
00553 
00554     Com_Printf("There are %i UFOs in game\n", ccs.numUFOs);
00555     for (ufo = ccs.ufos; ufo < ccs.ufos + ccs.numUFOs; ufo++) {
00556         Com_Printf("..%s (%s) - status: %i - pos: %.0f:%0.f\n", ufo->name, ufo->id, ufo->status, ufo->pos[0], ufo->pos[1]);
00557         Com_Printf("...route length: %i (current: %i), time: %i, distance: %.2f, speed: %i\n",
00558                 ufo->route.numPoints, ufo->point, ufo->time, ufo->route.distance, ufo->stats[AIR_STATS_SPEED]);
00559         Com_Printf("...linked to mission '%s'\n", ufo->mission ? ufo->mission->id : "no mission");
00560         Com_Printf("... UFO is %s and %s\n", ufo->landed ? "landed" : "flying", ufo->detected ? "detected" : "undetected");
00561         Com_Printf("... damage: %i\n", ufo->damage);
00562         Com_Printf("...%i weapon slots: ", ufo->maxWeapons);
00563         for (k = 0; k < ufo->maxWeapons; k++) {
00564             aircraftSlot_t const* const w = &ufo->weapons[k];
00565             if (w->item) {
00566                 char const* const state = w->ammo && w->ammoLeft > 0 ?
00567                 "(loaded)" : "(unloaded)";
00568                 Com_Printf("%s %s / ", w->item->id, state);
00569             } else
00570             Com_Printf("empty / ");
00571         }
00572         Com_Printf("\n");
00573     }
00574 }
00575 #endif
00576 
00585 aircraft_t *UFO_AddToGeoscape (ufoType_t ufoType, vec2_t destination, mission_t *mission)
00586 {
00587     int newUFONum;
00588     aircraft_t *ufo;
00589 
00590     if (ufoType == UFO_MAX) {
00591         Com_Printf("UFO_AddToGeoscape: ufotype does not exist\n");
00592         return NULL;
00593     }
00594 
00595     /* check max amount */
00596     if (ccs.numUFOs >= MAX_UFOONGEOSCAPE) {
00597         Com_DPrintf(DEBUG_CLIENT, "UFO_AddToGeoscape: Too many UFOs on geoscape\n");
00598         return NULL;
00599     }
00600 
00601     for (newUFONum = 0; newUFONum < ccs.numAircraftTemplates; newUFONum++) {
00602         const aircraft_t *tpl = &ccs.aircraftTemplates[newUFONum];
00603         if (tpl->type == AIRCRAFT_UFO && ufoType == tpl->ufotype && !tpl->notOnGeoscape)
00604             break;
00605     }
00606 
00607     if (newUFONum == ccs.numAircraftTemplates) {
00608         Com_DPrintf(DEBUG_CLIENT, "Could not add ufo type %i to geoscape\n", ufoType);
00609         return NULL;
00610     }
00611 
00612     /* Create ufo */
00613     ufo = UFO_GetByIDX(ccs.numUFOs);
00614     *ufo = ccs.aircraftTemplates[newUFONum];
00615     Com_DPrintf(DEBUG_CLIENT, "New UFO on geoscape: '%s' (ccs.numUFOs: %i, newUFONum: %i)\n", ufo->id, ccs.numUFOs, newUFONum);
00616     ufo->idx = ccs.numUFOs++;
00617 
00618     /* Update Stats of UFO */
00619     AII_UpdateAircraftStats(ufo);
00620     /* Give it HP */
00621     ufo->damage = ufo->stats[AIR_STATS_DAMAGE];
00622     /* Check for 0 damage which cause invulerable UFOs */
00623     assert(ufo->damage);
00624 
00625     /* Every ufo on geoscape needs a mission assigned */
00626     assert(mission);
00627 
00628     /* Initialise ufo data */
00629     UFO_SetRandomPos(ufo);
00630     AII_ReloadAircraftWeapons(ufo); /* Load its weapons */
00631     ufo->landed = qfalse;
00632     ufo->detected = qfalse; /* Not visible in radars (just for now) */
00633     ufo->mission = mission;
00634     if (destination)
00635         UFO_SendToDestination(ufo, destination);
00636     else
00637         UFO_SetRandomDest(ufo); /* Random destination */
00638 
00639     return ufo;
00640 }
00641 
00648 void UFO_RemoveFromGeoscape (aircraft_t* ufo)
00649 {
00650     /* Remove ufo from ufos list */
00651     const ptrdiff_t num = (ptrdiff_t) (ufo - ccs.ufos);
00652 
00653     Com_DPrintf(DEBUG_CLIENT, "Remove ufo from geoscape: '%s'\n", ufo->id);
00654 
00655     REMOVE_ELEM_ADJUST_IDX(ccs.ufos, num, ccs.numUFOs);
00656 }
00657 
00658 #ifdef DEBUG
00659 
00662 static void UFO_RemoveFromGeoscape_f (void)
00663 {
00664     if (ccs.numUFOs > 0)
00665     UFO_RemoveFromGeoscape(ccs.ufos);
00666 }
00667 #endif
00668 
00673 void UFO_DetectNewUFO (aircraft_t *ufocraft)
00674 {
00675     if (ufocraft->detected)
00676         return;
00677 
00678     /* Make this UFO detected */
00679     ufocraft->detected = qtrue;
00680     if (!ufocraft->detectionIdx) {
00681         ufocraft->detectionIdx = ++ccs.campaignStats.ufosDetected;
00682     }
00683     ufocraft->lastSpotted = ccs.date;
00684 
00685     /* If this is the first UFO on geoscape, activate radar */
00686     if (!MAP_IsRadarOverlayActivated())
00687         MAP_SetOverlay("radar");
00688 
00689     MAP_UpdateGeoscapeDock();
00690 }
00691 
00696 qboolean UFO_CampaignCheckEvents (void)
00697 {
00698     qboolean newDetection;
00699     int baseIdx, installationIdx;
00700     aircraft_t *ufo, *aircraft;
00701 
00702     newDetection = qfalse;
00703 
00704     /* For each ufo in geoscape */
00705     for (ufo = ccs.ufos + ccs.numUFOs - 1; ufo >= ccs.ufos; ufo--) {
00706         char detectedBy[MAX_VAR] = "";
00707         float minDistance = -1;
00708         /* detected tells us whether or not a UFO is detected NOW, whereas ufo->detected tells
00709          * us whether or not the UFO was detected PREVIOUSLY. */
00710         qboolean detected = qfalse;
00711 
00712         /* don't update UFO status id UFO is landed or crashed */
00713         if (ufo->landed)
00714             continue;
00715 
00716         /* note: We can't exit these loops as soon as we found the UFO detected
00717          * RADAR_CheckUFOSensored registers the UFO in every radars' detection list
00718          * which detect it */
00719         for (baseIdx = 0; baseIdx < ccs.numBases; baseIdx++) {
00720             base_t *base = B_GetFoundedBaseByIDX(baseIdx);
00721             if (!base)
00722                 continue;
00723             if (!B_GetBuildingStatus(base, B_POWER))
00724                 continue;
00725 
00726             /* maybe the ufo is already detected, don't reset it */
00727             if (RADAR_CheckUFOSensored(&base->radar, base->pos, ufo, detected | ufo->detected)) {
00728                 const int distance = GetDistanceOnGlobe(base->pos, ufo->pos);
00729                 detected = qtrue;
00730                 if (minDistance < 0 || minDistance > distance) {
00731                     minDistance = distance;
00732                     Q_strncpyz(detectedBy, base->name, sizeof(detectedBy));
00733                 }
00734             }
00735 
00736             /* Check if UFO is detected by an aircraft */
00737             aircraft = NULL;
00738             while ((aircraft = AIR_GetNextFromBase(base, aircraft)) != NULL) {
00739                 if (!AIR_IsAircraftOnGeoscape(aircraft))
00740                     continue;
00741                 /* maybe the ufo is already detected, don't reset it */
00742                 if (RADAR_CheckUFOSensored(&aircraft->radar, aircraft->pos, ufo, detected | ufo->detected)) {
00743                     const int distance = GetDistanceOnGlobe(aircraft->pos, ufo->pos);
00744                     detected = qtrue;
00745                     if (minDistance < 0 || minDistance > distance) {
00746                         minDistance = distance;
00747                         Q_strncpyz(detectedBy, aircraft->name, sizeof(detectedBy));
00748                     }
00749                 }
00750             }
00751         }
00752 
00753         for (installationIdx = 0; installationIdx < ccs.numInstallations; installationIdx++) {
00754             installation_t *installation = INS_GetFoundedInstallationByIDX(installationIdx);
00755             if (!installation)
00756                 continue;
00757 
00758             /* maybe the ufo is already detected, don't reset it */
00759             if (RADAR_CheckUFOSensored(&installation->radar, installation->pos, ufo, detected | ufo->detected)) {
00760                 const int distance = GetDistanceOnGlobe(installation->pos, ufo->pos);
00761                 detected = qtrue;
00762                 if (minDistance < 0 || minDistance > distance) {
00763                     minDistance = distance;
00764                     Q_strncpyz(detectedBy, installation->name, sizeof(detectedBy));
00765                 }
00766             }
00767         }
00768 
00769         /* Check if ufo appears or disappears on radar */
00770         if (detected != ufo->detected) {
00771             if (detected) {
00772                 /* if UFO is aiming a PHALANX aircraft, warn player */
00773                 if (ufo->aircraftTarget) {
00774                     /* stop time and notify */
00775                     MSO_CheckAddNewMessage(NT_UFO_ATTACKING, _("Notice"), va(_("A UFO is flying toward %s"), ufo->aircraftTarget->name), qfalse,
00776                             MSG_STANDARD, NULL);
00779                 } else {
00780                     MSO_CheckAddNewMessage(NT_UFO_SPOTTED, _("Notice"), va(_("Our radar detected a new UFO near %s"), detectedBy), qfalse,
00781                             MSG_UFOSPOTTED, NULL);
00782                 }
00783                 newDetection = qtrue;
00784                 UFO_DetectNewUFO(ufo);
00785             } else if (!detected) {
00786                 MSO_CheckAddNewMessage(NT_UFO_SIGNAL_LOST, _("Notice"), _("Our radar has lost the tracking on a UFO"), qfalse, MSG_UFOSPOTTED, NULL);
00787                 /* Make this UFO undetected */
00788                 ufo->detected = qfalse;
00789                 /* Notify that ufo disappeared */
00790                 AIR_AircraftsUFODisappear(ufo);
00791                 MAP_NotifyUFODisappear(ufo);
00792 
00793                 /* Deactivate Radar overlay */
00794                 RADAR_DeactivateRadarOverlay();
00795             }
00796         }
00797     }
00798     return newDetection;
00799 }
00800 
00805 void UFO_NotifyPhalanxAircraftRemoved (const aircraft_t * const aircraft)
00806 {
00807     int ufoIdx;
00808 
00809     assert(aircraft);
00810 
00811     for (ufoIdx = 0; ufoIdx < ccs.numUFOs; ufoIdx++) {
00812         aircraft_t *ufo = UFO_GetByIDX(ufoIdx);
00813 
00814         if (ufo->aircraftTarget == aircraft)
00815             ufo->aircraftTarget = NULL;
00816     }
00817 }
00818 
00823 qboolean UFO_IsUFOSeenOnGeoscape (const aircraft_t const *ufo)
00824 {
00825 #ifdef DEBUG
00826     if (ufo->notOnGeoscape)
00827     Com_Error(ERR_DROP, "UFO_IsUFOSeenOnGeoscape: ufo %s can't be used on geoscape", ufo->id);
00828 #endif
00829     return (!ufo->landed && ufo->detected);
00830 }
00831 
00835 void UFO_InitStartup (void)
00836 {
00837 #ifdef DEBUG
00838     Cmd_AddCommand("debug_destroyufos", UFO_DestroyUFOs_f, "Destroys all UFOs on the geoscape");
00839     Cmd_AddCommand("debug_listufo", UFO_ListOnGeoscape_f, "Print UFO information to game console");
00840     Cmd_AddCommand("removeufo", UFO_RemoveFromGeoscape_f, "Remove a UFO from geoscape");
00841     Cvar_Get("debug_showufos", "0", CVAR_DEVELOPER, "Show all UFOs on geoscape");
00842 #endif
00843 }

Generated by  doxygen 1.6.2