00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00242 distance = GetDistanceOnGlobe(ufo->pos, base->pos);
00243 if (distance > MAX_DETECTING_RANGE)
00244 return;
00245
00246
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
00260 if (distance > decreasingDistance)
00261 probability /= decreasingFactor;
00262
00263
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
00284 distance = GetDistanceOnGlobe(ufo->pos, installation->pos);
00285 if (distance > MAX_DETECTING_RANGE)
00286 return;
00287
00288
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
00302 if (distance > decreasingDistance)
00303 probability /= decreasingFactor;
00304
00305
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
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
00355 if (ufo->mission->stage != STAGE_INTERCEPT) {
00356
00357 if (ufo->aircraftTarget)
00358 UFO_CheckShootBack(ufo, ufo->aircraftTarget);
00359 return;
00360 }
00361
00362
00363 if (ufo->aircraftTarget) {
00364
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
00380 phalanxAircraft = NULL;
00381 while ((phalanxAircraft = AIR_GetNextFromBase(base, phalanxAircraft)) != NULL) {
00382
00383 if (AIR_IsAircraftOnGeoscape(phalanxAircraft)) {
00384
00385 const float dist = GetDistanceOnGlobe(ufo->pos, phalanxAircraft->pos);
00386
00387 if (dist > MAX_DETECTING_RANGE)
00388 continue;
00389
00390 if (dist < distance) {
00391 distance = dist;
00392 if (UFO_SendPursuingAircraft(ufo, phalanxAircraft) && UFO_IsUFOSeenOnGeoscape(ufo)) {
00393
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
00419 slotIdx = AIRFIGHT_ChooseWeapon(ufo->weapons, ufo->maxWeapons, ufo->pos, aircraft->pos);
00420 if (slotIdx == AIRFIGHT_WEAPON_CAN_NEVER_SHOOT) {
00421
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
00458 if (ufo->aircraftTarget) {
00459
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
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
00484 if (!deltaTime)
00485 return;
00486
00487
00488 for (ufoIdx = ccs.numUFOs - 1; ufoIdx >= 0; ufoIdx--) {
00489 aircraft_t *ufo = UFO_GetByIDX(ufoIdx);
00490
00491 if (ufo->landed)
00492 continue;
00493
00494
00495 assert(ufo->mission);
00496
00497
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
00505 UFO_SetRandomDestAround(ufo, ufo->mission->pos);
00506 } else
00507 UFO_SetRandomDest(ufo);
00508 if (CP_CheckNextStageDestination(ufo))
00509
00510 continue;
00511
00512 if (ufoIdx == ccs.numUFOs)
00513 continue;
00514 }
00515
00516
00517 UFO_SearchAircraftTarget(ufo);
00518
00519
00520 if (ufo->fuel <= 0)
00521 ufo->fuel = ufo->stats[AIR_STATS_FUELSIZE];
00522
00523
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
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
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
00619 AII_UpdateAircraftStats(ufo);
00620
00621 ufo->damage = ufo->stats[AIR_STATS_DAMAGE];
00622
00623 assert(ufo->damage);
00624
00625
00626 assert(mission);
00627
00628
00629 UFO_SetRandomPos(ufo);
00630 AII_ReloadAircraftWeapons(ufo);
00631 ufo->landed = qfalse;
00632 ufo->detected = qfalse;
00633 ufo->mission = mission;
00634 if (destination)
00635 UFO_SendToDestination(ufo, destination);
00636 else
00637 UFO_SetRandomDest(ufo);
00638
00639 return ufo;
00640 }
00641
00648 void UFO_RemoveFromGeoscape (aircraft_t* ufo)
00649 {
00650
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
00679 ufocraft->detected = qtrue;
00680 if (!ufocraft->detectionIdx) {
00681 ufocraft->detectionIdx = ++ccs.campaignStats.ufosDetected;
00682 }
00683 ufocraft->lastSpotted = ccs.date;
00684
00685
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
00705 for (ufo = ccs.ufos + ccs.numUFOs - 1; ufo >= ccs.ufos; ufo--) {
00706 char detectedBy[MAX_VAR] = "";
00707 float minDistance = -1;
00708
00709
00710 qboolean detected = qfalse;
00711
00712
00713 if (ufo->landed)
00714 continue;
00715
00716
00717
00718
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
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
00737 aircraft = NULL;
00738 while ((aircraft = AIR_GetNextFromBase(base, aircraft)) != NULL) {
00739 if (!AIR_IsAircraftOnGeoscape(aircraft))
00740 continue;
00741
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
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
00770 if (detected != ufo->detected) {
00771 if (detected) {
00772
00773 if (ufo->aircraftTarget) {
00774
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
00788 ufo->detected = qfalse;
00789
00790 AIR_AircraftsUFODisappear(ufo);
00791 MAP_NotifyUFODisappear(ufo);
00792
00793
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 }