UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_ufo.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 2002-2025 UFO: Alien Invasion.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23*/
24
25#include "../../cl_shared.h"
26#include "cp_campaign.h"
27#include "cp_geoscape.h"
28#include "cp_ufo.h"
29#include "cp_aircraft.h"
30#include "cp_mapfightequip.h"
31#include "cp_missions.h"
32#include "cp_ufo_callbacks.h"
33
34static const float MAX_DETECTING_RANGE = 25.0f;
35
36
42{
43 aircraft_t* endOfUFOs = &ccs.ufos[ccs.numUFOs];
44 aircraft_t* ufo;
45
46 if (!ccs.numUFOs)
47 return nullptr;
48
49 if (!lastUFO)
50 return ccs.ufos;
51 assert(lastUFO >= ccs.ufos);
52 assert(lastUFO < endOfUFOs);
53
54 ufo = lastUFO;
55
56 ufo++;
57 if (ufo >= endOfUFOs)
58 return nullptr;
59 else
60 return ufo;
61}
62
67{
68 aircraft_t* ufo = lastUFO;
69 while ((ufo = UFO_GetNext(ufo)) != nullptr) {
71#ifdef DEBUG
72 || cgi->Cvar_GetInteger("debug_showufos")
73#endif
74 )
75 return ufo;
76 }
77
78 return nullptr;
79}
80
85aircraft_t* UFO_GetByIDX (const int idx)
86{
87 assert(idx >= 0 && idx < MAX_UFOONGEOSCAPE);
88 return &ccs.ufos[idx];
89}
90
98{
99 const char* id = cgi->Com_UFOTypeToShortName(type);
100 const technology_t* tech = RS_GetTechByProvided(id);
101 return tech;
102}
103
110{
111 for (int i = 0; i < ccs.numAircraftTemplates; i++) {
112 aircraft_t* ufo = &ccs.aircraftTemplates[i];
113 if (ufo->getUfoType() == type)
114 return ufo;
115 }
116
117 cgi->Com_Error(ERR_DROP, "No ufo with type %i found", type);
118}
119
126{
127 const aircraft_t* ufo = UFO_GetByType(type);
128
129 return ufo->ufoInterestOnGeoscape <= ccs.overallInterest;
130}
131
137bool UFO_CanDoMission (const ufoType_t uType, const char* mType)
138{
139 const aircraft_t* ufo = UFO_GetByType(uType);
140 if (cgi->LIST_ContainsString(ufo->missionTypes, mType))
141 return true;
142
143 return false;
144}
145
153int UFO_GetAvailableUFOsForMission (const interestCategory_t missionType, ufoType_t* ufoTypes, bool checkInterest)
154{
155 int num = 0;
156
157 const short ufoIdsNum = cgi->Com_GetUFOIdsNum();
158 for (int i = 0; i < ufoIdsNum; i++) {
159 ufoType_t uType = i;
160 switch (missionType) {
162 if (!UFO_CanDoMission(uType, "recon"))
163 continue;
164 break;
166 if (!UFO_CanDoMission(uType, "baseattack"))
167 continue;
168 break;
170 if (!UFO_CanDoMission(uType, "supply"))
171 continue;
172 break;
174 if (!UFO_CanDoMission(uType, "harvest"))
175 continue;
176 break;
178 if (!UFO_CanDoMission(uType, "xvi"))
179 continue;
180 break;
182 if (!UFO_CanDoMission(uType, "terror"))
183 continue;
184 break;
186 if (!UFO_CanDoMission(uType, "intercept"))
187 continue;
188 break;
190 if (!UFO_CanDoMission(uType, "interceptbombing"))
191 continue;
192 break;
194 if (!UFO_CanDoMission(uType, "building"))
195 continue;
196 break;
198 if (!UFO_CanDoMission(uType, "subvert"))
199 continue;
200 break;
201 default:
202 continue;
203 }
204 if (!checkInterest || UFO_ShouldAppearOnGeoscape(uType))
205 ufoTypes[num++] = uType;
206 }
207
208 return num;
209}
210
217int UFO_GetOneAvailableUFOForMission (const interestCategory_t missionType, bool checkInterest)
218{
219 ufoType_t ufoTypes[UFO_MAX];
220 int numTypes = UFO_GetAvailableUFOsForMission(missionType, ufoTypes, checkInterest);
221 return numTypes ? ufoTypes[0] : UFO_NONE;
222}
223
231const char* UFO_TypeToName (const ufoType_t type)
232{
234 if (tech)
235 return _(tech->name);
236 cgi->Com_Error(ERR_DROP, "UFO_TypeToName(): Unknown UFO type %i\n", type);
237}
238
243const char* UFO_GetName (const aircraft_t* ufocraft)
244{
245 const technology_t* tech = ufocraft->tech;
246
247 assert(tech);
248
249 if (ufocraft->detectionIdx)
250 return va("%s #%i", (RS_IsResearched_ptr(tech)) ? _(ufocraft->name) : _("UFO"), ufocraft->detectionIdx);
251 return (RS_IsResearched_ptr(tech)) ? _(ufocraft->name) : _("UFO");
252}
253
260{
261 vec2_t pos;
262
263 CP_GetRandomPosOnGeoscape(pos, false);
264
265 UFO_SendToDestination(ufocraft, pos);
266}
267
274void UFO_SetRandomDestAround (aircraft_t* ufocraft, const vec2_t pos)
275{
276 vec2_t dest;
277 const float spread = 2.0f;
278 float rand1, rand2;
279
280 gaussrand(&rand1, &rand2);
281 rand1 *= spread;
282 rand2 *= spread;
283
284 Vector2Set(dest, pos[0] + rand1, pos[1] + rand2);
285
286 UFO_SendToDestination(ufocraft, dest);
287}
288
294static void UFO_SetRandomPos (aircraft_t* ufocraft)
295{
296 vec2_t pos;
297
298 CP_GetRandomPosOnGeoscape(pos, false);
299
300 Vector2Copy(pos, ufocraft->pos);
301}
302
309static int UFO_IsTargetOfBase (const aircraft_t* ufo, const base_t* base)
310{
311 int i;
312
313 for (i = 0; i < base->numBatteries; i++) {
314 if (base->batteries[i].target == ufo)
316 }
317
318 for (i = 0; i < base->numLasers; i++) {
319 if (base->lasers[i].target == ufo)
321 }
322
323 return UFO_IS_NO_TARGET;
324}
325
332static int UFO_IsTargetOfInstallation (const aircraft_t* ufo, const installation_t* installation)
333{
334 for (int i = 0; i < installation->numBatteries; i++) {
335 if (installation->batteries[i].target == ufo)
337 }
338
339 return UFO_IS_NO_TARGET;
340}
341
354{
355 float probability;
356 float distance;
357 const float decreasingDistance = 10.0f;
359 const float decreasingFactor = 5.0f;
360
361 /* ufo can't find base if it's too far */
362 distance = GetDistanceOnGlobe(ufo->pos, base->pos);
363 if (distance > MAX_DETECTING_RANGE)
364 return;
365
366 /* UFO has an increased probability to find a base if it is firing at it */
367 switch (UFO_IsTargetOfBase(ufo, base)) {
369 probability = 0.01f;
370 break;
372 probability = 0.001f;
373 break;
374 default:
375 probability = 0.0001f;
376 break;
377 }
378
379 /* decrease probability if the ufo is far from base */
380 if (distance > decreasingDistance)
381 probability /= decreasingFactor;
382
383 /* probability must depend on DETECTION_INTERVAL (in case we change the value) */
384 probability *= DETECTION_INTERVAL;
385
386 base->alienInterest += probability;
387}
388
396{
397 float probability;
398 float distance;
399 const float decreasingDistance = 10.0f;
401 const float decreasingFactor = 5.0f;
402
403 /* ufo can't find base if it's too far */
404 distance = GetDistanceOnGlobe(ufo->pos, installation->pos);
405 if (distance > MAX_DETECTING_RANGE)
406 return;
407
408 /* UFO has an increased probability to find a base if it is firing at it */
409 switch (UFO_IsTargetOfInstallation(ufo, installation)) {
411 probability = 0.01f;
412 break;
414 probability = 0.001f;
415 break;
416 default:
417 probability = 0.0001f;
418 break;
419 }
420
421 /* decrease probability if the ufo is far from base */
422 if (distance > decreasingDistance)
423 probability /= decreasingFactor;
424
425 /* probability must depend on DETECTION_INTERVAL (in case we change the value) */
426 probability *= DETECTION_INTERVAL;
427
428 installation->alienInterest += probability;
429}
430
438{
439 aircraft_t* ufo;
440
441 ufo = nullptr;
442 while ((ufo = UFO_GetNext(ufo)) != nullptr) {
443 base_t* base;
444
445 /* landed UFO can't detect any phalanx base or installation */
446 if (ufo->landed)
447 continue;
448
449 base = nullptr;
450 while ((base = B_GetNext(base)) != nullptr)
452
453 INS_Foreach(installation)
455 }
456}
457
461static void UFO_SearchAircraftTarget (const campaign_t* campaign, aircraft_t* ufo, float maxDetectionRange = MAX_DETECTING_RANGE)
462{
463 float distance = 999999.;
464
465 /* UFO never try to attack a PHALANX aircraft except if they came on earth in that aim */
466 if (ufo->mission->stage != STAGE_INTERCEPT) {
467 /* Check if UFO is defending itself */
468 if (ufo->aircraftTarget)
469 UFO_CheckShootBack(campaign, ufo, ufo->aircraftTarget);
470 return;
471 }
472
473 /* check if the ufo is already attacking an aircraft */
474 if (ufo->aircraftTarget) {
475 /* check if the target disappeared from geoscape (fled in a base) */
477 AIRFIGHT_ExecuteActions(campaign, ufo, ufo->aircraftTarget);
478 else
479 ufo->aircraftTarget = nullptr;
480 return;
481 }
482
483 ufo->status = AIR_TRANSIT;
484 AIR_Foreach(phalanxAircraft) {
485 /* check that aircraft is flying */
486 if (AIR_IsAircraftOnGeoscape(phalanxAircraft)) {
487 /* get the distance from ufo to aircraft */
488 const float dist = GetDistanceOnGlobe(ufo->pos, phalanxAircraft->pos);
489 /* check out of reach */
490 if (dist > maxDetectionRange)
491 continue;
492 /* choose the nearest target */
493 if (dist < distance) {
494 distance = dist;
495 if (UFO_SendPursuingAircraft(ufo, phalanxAircraft) && UFO_IsUFOSeenOnGeoscape(ufo)) {
496 /* stop time and notify */
497 MSO_CheckAddNewMessage(NT_UFO_ATTACKING, _("Notice"), va(_("A UFO is flying toward %s"), phalanxAircraft->name));
499 return;
500 }
501 }
502 }
503 }
504
505 /* if this ufo is a leader, it does not try to search another one */
506 if (ufo->leader)
507 return;
508 aircraft_t* otherUFO = nullptr;
509 const float polarCoordinatesOffset = 1.0f;
510 while ((otherUFO = UFO_GetNextOnGeoscape(otherUFO)) != nullptr) {
511 if (otherUFO == ufo)
512 continue;
513 if (otherUFO->leader) {
514 vec2_t dest;
516 dest[0] += polarCoordinatesOffset;
517 dest[1] += polarCoordinatesOffset;
518 GEO_CalcLine(ufo->pos, dest, &ufo->route);
519 ufo->time = 0;
520 ufo->point = 0;
521 break;
522 }
523 }
524}
525
533{
534 assert(ufo);
535 assert(aircraft);
536
537 /* check whether the ufo can shoot the aircraft - if not, don't try it even */
538 const int slotIdx = AIRFIGHT_ChooseWeapon(ufo->weapons, ufo->maxWeapons, ufo->pos, aircraft->pos);
539 if (slotIdx == AIRFIGHT_WEAPON_CAN_NEVER_SHOOT) {
540 /* no ammo left: stop attack */
541 ufo->status = AIR_TRANSIT;
542 return false;
543 }
544
545 vec2_t dest;
547 GEO_CalcLine(ufo->pos, dest, &ufo->route);
548 ufo->status = AIR_UFO;
549 ufo->time = 0;
550 ufo->point = 0;
551 ufo->aircraftTarget = aircraft;
552
553 return true;
554}
555
563{
564 assert(ufo);
565
566 GEO_CalcLine(ufo->pos, dest, &ufo->route);
567 ufo->status = AIR_TRANSIT;
568 ufo->time = 0;
569 ufo->point = 0;
570}
571
578void UFO_CheckShootBack (const campaign_t* campaign, aircraft_t* ufo, aircraft_t* phalanxAircraft)
579{
580 /* check if the ufo is already attacking an aircraft */
581 if (ufo->aircraftTarget) {
582 /* check if the target flee in a base */
584 AIRFIGHT_ExecuteActions(campaign, ufo, ufo->aircraftTarget);
585 else {
586 ufo->aircraftTarget = nullptr;
587 CP_UFOProceedMission(campaign, ufo);
588 }
589 } else {
590 /* check that aircraft is flying */
591 if (AIR_IsAircraftOnGeoscape(phalanxAircraft))
592 UFO_SendPursuingAircraft(ufo, phalanxAircraft);
593 }
594}
595
601void UFO_CampaignRunUFOs (const campaign_t* campaign, int deltaTime)
602{
603 /* now the ufos are flying around, too - cycle backward - ufo might be destroyed */
604 for (int ufoIdx = ccs.numUFOs - 1; ufoIdx >= 0; ufoIdx--) {
605 aircraft_t* ufo = UFO_GetByIDX(ufoIdx);
606 /* don't run a landed ufo */
607 if (ufo->landed)
608 continue;
609
610 /* Every UFO on geoscape should have a mission assigned */
611 assert(ufo->mission);
612
613 /* reached target and not following a phalanx aircraft? then we need a new destination */
614 if (AIR_AircraftMakeMove(deltaTime, ufo) && ufo->status != AIR_UFO) {
615 const vec2_t& end = ufo->route.point[ufo->route.numPoints - 1];
616 Vector2Copy(end, ufo->pos);
618 if (ufo->mission->stage == STAGE_INTERCEPT && ufo->mission->data.aircraft) {
619 /* Attacking an installation: fly over this installation */
620 UFO_SetRandomDestAround(ufo, ufo->mission->pos);
621 } else
623 if (CP_CheckNextStageDestination(campaign, ufo))
624 /* UFO has been removed from game */
625 continue;
626 /* UFO was destroyed (maybe because the mission was removed) */
627 if (ufoIdx == ccs.numUFOs)
628 continue;
629 }
630
631 /* Search the next target? */
632 UFO_SearchAircraftTarget(campaign, ufo);
633
634 /* antimatter tanks */
635 if (ufo->fuel <= 0)
636 ufo->fuel = ufo->stats[AIR_STATS_FUELSIZE];
637
638 /* Update delay to launch next projectile */
639 for (int k = 0; k < ufo->maxWeapons; k++) {
640 aircraftSlot_t* slot = &ufo->weapons[k];
641 if (slot->delayNextShot > 0)
642 slot->delayNextShot -= deltaTime;
643 }
644 }
645}
646
647#ifdef DEBUG
651static void UFO_DestroyUFOs_f (void)
652{
653 aircraft_t* ufo;
654 campaign_t* campaign = ccs.curCampaign;
655
656 for (ufo = ccs.ufos; ufo < ccs.ufos + ccs.numUFOs; ufo++) {
657 AIRFIGHT_ActionsAfterAirfight(campaign, nullptr, ufo, true);
658 }
659}
660
665static void UFO_ListOnGeoscape_f (void)
666{
667 cgi->Com_Printf("There are %i UFOs in game\n", ccs.numUFOs);
668 for (aircraft_t* ufo = ccs.ufos; ufo < ccs.ufos + ccs.numUFOs; ufo++) {
669 cgi->Com_Printf("..%s (%s) - status: %i - pos: %.0f:%0.f\n", ufo->name, ufo->id, ufo->status, ufo->pos[0], ufo->pos[1]);
670 cgi->Com_Printf("...route length: %i (current: %i), time: %i, distance: %.2f, speed: %i\n",
671 ufo->route.numPoints, ufo->point, ufo->time, ufo->route.distance, ufo->stats[AIR_STATS_SPEED]);
672 cgi->Com_Printf("...linked to mission '%s'\n", ufo->mission ? ufo->mission->id : "no mission");
673 cgi->Com_Printf("... UFO is %s and %s\n", ufo->landed ? "landed" : "flying", ufo->detected ? "detected" : "undetected");
674 cgi->Com_Printf("... damage: %i\n", ufo->damage);
675 cgi->Com_Printf("...%i weapon slots: ", ufo->maxWeapons);
676 for (int k = 0; k < ufo->maxWeapons; k++) {
677 aircraftSlot_t const* const w = &ufo->weapons[k];
678 if (w->item) {
679 char const* const state = w->ammo && w->ammoLeft > 0 ?
680 "(loaded)" : "(unloaded)";
681 cgi->Com_Printf("%s %s / ", w->item->id, state);
682 } else
683 cgi->Com_Printf("empty / ");
684 }
685 cgi->Com_Printf("\n");
686 }
687}
688#endif
689
696{
697 int newUFONum;
698
699 for (newUFONum = 0; newUFONum < ccs.numAircraftTemplates; newUFONum++) {
700 const aircraft_t* tpl = &ccs.aircraftTemplates[newUFONum];
701 if (AIR_IsUFO(tpl) && ufoType == tpl->getUfoType())
702 break;
703 }
704
705 /* not found */
706 if (newUFONum == ccs.numAircraftTemplates)
707 return nullptr;
708
709 return &ccs.aircraftTemplates[newUFONum];
710}
711
719{
720 int newUFONum;
721
722 for (newUFONum = 0; newUFONum < ccs.numAircraftTemplates; newUFONum++) {
723 const aircraft_t* tpl = &ccs.aircraftTemplates[newUFONum];
724 if (AIR_IsUFO(tpl) && ufoType == tpl->getUfoType() && !tpl->notOnGeoscape)
725 break;
726 }
727
728 /* not found */
729 if (newUFONum == ccs.numAircraftTemplates)
730 return nullptr;
731
732 return &ccs.aircraftTemplates[newUFONum];
733}
734
742{
743 aircraft_t* ufo;
744
745 if (ufoTemplate == nullptr)
746 return nullptr;
747
748 /* check max amount */
749 if (ccs.numUFOs >= MAX_UFOONGEOSCAPE)
750 return nullptr;
751
752 /* must be an ufo */
753 assert(AIR_IsUFO(ufoTemplate));
754
755 /* get a new free slot */
756 ufo = UFO_GetByIDX(ccs.numUFOs);
757 /* copy the data */
758 *ufo = *ufoTemplate;
759 /* assign an unique index */
760 ufo->idx = ccs.numUFOs++;
761
762 return ufo;
763}
764
773aircraft_t* UFO_AddToGeoscape (ufoType_t ufoType, const vec2_t destination, mission_t* mission)
774{
775 aircraft_t* ufo;
776 const aircraft_t* ufoTemplate;
777
778 ufoTemplate = UFO_GetTemplateForGeoscape(ufoType);
779 if (ufoTemplate == nullptr)
780 return nullptr;
781
782 /* Create ufo */
783 ufo = UFO_CreateFromTemplate(ufoTemplate);
784 if (ufo == nullptr)
785 return nullptr;
786
787 /* Update Stats of UFO */
789 /* Give it HP */
790 ufo->damage = ufo->stats[AIR_STATS_DAMAGE];
791 /* Check for 0 damage which cause invulerable UFOs */
792 assert(ufo->damage);
793
794 /* Every ufo on geoscape needs a mission assigned */
795 assert(mission);
796
797 /* Initialise ufo data */
798 UFO_SetRandomPos(ufo);
799 AII_ReloadAircraftWeapons(ufo); /* Load its weapons */
800 ufo->landed = false;
801 ufo->detected = false; /* Not visible in radars (just for now) */
802 ufo->mission = mission;
803 if (destination)
804 UFO_SendToDestination(ufo, destination);
805 else
806 UFO_SetRandomDest(ufo); /* Random destination */
807
808 return ufo;
809}
810
818{
819 /* Remove ufo from ufos list */
820 const ptrdiff_t num = (ptrdiff_t) (ufo - ccs.ufos);
821
822 cgi->Com_DPrintf(DEBUG_CLIENT, "Remove ufo from geoscape: '%s'\n", ufo->id);
823
824 REMOVE_ELEM_ADJUST_IDX(ccs.ufos, num, ccs.numUFOs);
825}
826
827#ifdef DEBUG
831static void UFO_RemoveFromGeoscape_f (void)
832{
833 if (ccs.numUFOs > 0)
835}
836#endif
837
843{
844 if (ufocraft->detected)
845 return;
846
847 /* Make this UFO detected */
848 if (!ufocraft->detectionIdx) {
849 ufocraft->detectionIdx = ++ccs.campaignStats.ufosDetected;
850 }
851 ufocraft->detected = true;
852 ufocraft->lastSpotted = ccs.date;
853
854 /* If this is the first UFO on geoscape, activate radar */
856 GEO_SetOverlay("radar", 1);
857
858 CP_TriggerEvent(UFO_DETECTION, cgi->Com_UFOTypeToShortName(ufocraft->getUfoType()));
859
861}
862
868{
869 bool newDetection;
870 aircraft_t* ufo;
871
872 newDetection = false;
873
874 /* For each ufo in geoscape */
875 ufo = nullptr;
876 while ((ufo = UFO_GetNext(ufo)) != nullptr) {
877 char detectedBy[MAX_VAR] = "";
878 float minDistance = -1;
879 /* detected tells us whether or not a UFO is detected NOW, whereas ufo->detected tells
880 * us whether or not the UFO was detected PREVIOUSLY. */
881 bool detected = false;
882 base_t* base;
883
884 /* don't update UFO status id UFO is landed or crashed */
885 if (ufo->landed)
886 continue;
887
888 /* note: We can't exit these loops as soon as we found the UFO detected
889 * RADAR_CheckUFOSensored registers the UFO in every radars' detection list
890 * which detect it */
891
892 /* Check if UFO is detected by an aircraft */
893 AIR_Foreach(aircraft) {
894 if (!AIR_IsAircraftOnGeoscape(aircraft))
895 continue;
896 /* maybe the ufo is already detected, don't reset it */
897 if (RADAR_CheckUFOSensored(&aircraft->radar, aircraft->pos, ufo, detected | ufo->detected)) {
898 const int distance = GetDistanceOnGlobe(aircraft->pos, ufo->pos);
899 detected = true;
900 if (minDistance < 0 || minDistance > distance) {
901 minDistance = distance;
902 Q_strncpyz(detectedBy, aircraft->name, sizeof(detectedBy));
903 }
904 }
905 }
906
907 /* Check if UFO is detected by a base */
908 base = nullptr;
909 while ((base = B_GetNext(base)) != nullptr) {
910 if (!B_GetBuildingStatus(base, B_POWER))
911 continue;
912
913 /* maybe the ufo is already detected, don't reset it */
914 if (RADAR_CheckUFOSensored(&base->radar, base->pos, ufo, detected | ufo->detected)) {
915 const int distance = GetDistanceOnGlobe(base->pos, ufo->pos);
916 detected = true;
917 if (minDistance < 0 || minDistance > distance) {
918 minDistance = distance;
919 Q_strncpyz(detectedBy, base->name, sizeof(detectedBy));
920 }
921 }
922
923 }
924
925 /* Check if UFO is detected by a radartower */
926 INS_Foreach(installation) {
927 /* maybe the ufo is already detected, don't reset it */
928 if (RADAR_CheckUFOSensored(&installation->radar, installation->pos, ufo, detected | ufo->detected)) {
929 const int distance = GetDistanceOnGlobe(installation->pos, ufo->pos);
930 detected = true;
931 if (minDistance < 0 || minDistance > distance) {
932 minDistance = distance;
933 Q_strncpyz(detectedBy, installation->name, sizeof(detectedBy));
934 }
935 }
936 }
937
938 /* Check if ufo appears or disappears on radar */
939 if (detected != ufo->detected) {
940 if (detected) {
941 UFO_DetectNewUFO(ufo);
942 /* if UFO is aiming a PHALANX aircraft, warn player */
943 if (ufo->aircraftTarget) {
944 /* stop time and notify */
945 MSO_CheckAddNewMessage(NT_UFO_ATTACKING, _("Notice"), va(_("%s is flying toward %s"), UFO_GetName(ufo), ufo->aircraftTarget->name));
948 } else {
949 MSO_CheckAddNewMessage(NT_UFO_SPOTTED, _("Notice"), va(_("Our radar detected %s near %s"), UFO_GetName(ufo), detectedBy), MSG_UFOSPOTTED);
950 }
951 newDetection = true;
952 } else if (!detected) {
953 MSO_CheckAddNewMessage(NT_UFO_SIGNAL_LOST, _("Notice"), va(_("Our radar has lost the tracking on %s"), UFO_GetName(ufo)), MSG_UFOLOST);
954 /* Make this UFO undetected */
955 ufo->detected = false;
956 /* Notify that ufo disappeared */
959
960 /* Deactivate Radar overlay */
962 }
963 }
964 }
965 return newDetection;
966}
967
973{
974 assert(aircraft);
975
976 for (int ufoIdx = 0; ufoIdx < ccs.numUFOs; ufoIdx++) {
977 aircraft_t* ufo = UFO_GetByIDX(ufoIdx);
978
979 if (ufo->aircraftTarget == aircraft)
980 ufo->aircraftTarget = nullptr;
981 }
982}
983
990{
991 bool seen = !ufo->landed && ufo->detected;
992#ifdef DEBUG
993 if (seen && ufo->notOnGeoscape)
994 cgi->Com_Error(ERR_DROP, "UFO_IsUFOSeenOnGeoscape: ufo %s can't be used on geoscape", ufo->id);
995#endif
996 return seen;
997}
998
999static const cmdList_t ufoDebugCallbacks[] = {
1000#ifdef DEBUG
1001 {"debug_destroyufos", UFO_DestroyUFOs_f, "Destroys all UFOs on the geoscape"},
1002 {"debug_listufo", UFO_ListOnGeoscape_f, "Print UFO information to game console"},
1003 {"debug_removeufo", UFO_RemoveFromGeoscape_f, "Remove a UFO from geoscape"},
1004#endif
1005 {nullptr, nullptr, nullptr}
1006};
1007
1012{
1014 cgi->Cmd_TableAddList(ufoDebugCallbacks);
1015#ifdef DEBUG
1016 cgi->Cvar_Get("debug_showufos", "0", CVAR_DEVELOPER, "Show all UFOs on geoscape");
1017#endif
1018}
1019
1023void UFO_Shutdown (void)
1024{
1026 cgi->Cmd_TableRemoveList(ufoDebugCallbacks);
1027}
Share stuff between the different cgame implementations.
#define _(String)
Definition cl_shared.h:44
#define REMOVE_ELEM_ADJUST_IDX(array, index, n)
Definition common.h:396
#define ERR_DROP
Definition common.h:211
bool AIR_IsAircraftOnGeoscape(const aircraft_t *aircraft)
Checks whether given aircraft is on geoscape.
void AIR_AircraftsUFODisappear(const aircraft_t *const ufo)
Notify that a UFO disappear from radars.
void AIR_GetDestinationWhilePursuing(const aircraft_t *shooter, const aircraft_t *target, vec2_t dest)
Calculates the point where aircraft should go to intecept a moving target.
bool AIR_AircraftMakeMove(int dt, aircraft_t *aircraft)
Moves given aircraft.
Header file for aircraft stuff.
#define AIR_Foreach(var)
iterates trough all aircraft
@ AIR_UFO
@ AIR_TRANSIT
#define AIR_IsUFO(aircraft)
void AIRFIGHT_ExecuteActions(const campaign_t *campaign, aircraft_t *shooter, aircraft_t *target)
Decide what an attacking aircraft can do.
int AIRFIGHT_ChooseWeapon(const aircraftSlot_t *slot, int maxSlot, const vec2_t pos, const vec2_t targetPos)
Choose the weapon an attacking aircraft will use to fire on a target.
void AIRFIGHT_ActionsAfterAirfight(const campaign_t *campaign, aircraft_t *shooter, aircraft_t *aircraft, bool phalanxWon)
Actions to execute when a fight is done.
#define AIRFIGHT_WEAPON_CAN_NEVER_SHOOT
Definition cp_airfight.h:38
interestCategory_t
@ INTERESTCATEGORY_BASE_ATTACK
@ INTERESTCATEGORY_INTERCEPTBOMBING
@ INTERESTCATEGORY_BUILDING
@ INTERESTCATEGORY_SUBVERT
@ INTERESTCATEGORY_SUPPLY
@ INTERESTCATEGORY_RECON
@ INTERESTCATEGORY_XVI
@ INTERESTCATEGORY_TERROR_ATTACK
@ INTERESTCATEGORY_INTERCEPT
@ INTERESTCATEGORY_HARVEST
base_t * B_GetNext(base_t *lastBase)
Iterates through founded bases.
Definition cp_base.cpp:286
bool B_GetBuildingStatus(const base_t *const base, const buildingType_t buildingType)
Get the status associated to a building.
Definition cp_base.cpp:478
@ B_POWER
Definition cp_building.h:61
const int DETECTION_INTERVAL
delay between actions that must be executed independently of time scale
ccs_t ccs
Header file for single player campaign control.
const cgame_import_t * cgi
void CP_TriggerEvent(campaignTriggerEventType_t type, const void *userdata)
Triggers a campaign event with a special type.
Definition cp_event.cpp:310
@ UFO_DETECTION
Definition cp_event.h:80
void GEO_SetOverlay(const char *overlayID, int status)
Turn overlay on/off.
bool GEO_IsRadarOverlayActivated(void)
void GEO_UpdateGeoscapeDock(void)
Will add missions and UFOs to the geoscape dock panel.
void GEO_CalcLine(const vec2_t start, const vec2_t end, mapline_t *line)
Calculate the shortest way to go from start to end on a sphere.
void CP_GetRandomPosOnGeoscape(vec2_t pos, bool noWater)
Determines a random position on geoscape.
void GEO_NotifyUFODisappear(const aircraft_t *ufo)
Notify that a UFO disappears on radars.
void GEO_CheckPositionBoundaries(float *pos)
Check that a position (in latitude / longitude) is within boundaries.
Header for Geoscape management.
#define INS_Foreach(var)
void AII_ReloadAircraftWeapons(aircraft_t *aircraft)
Reload the weapons of an aircraft.
void AII_UpdateAircraftStats(aircraft_t *aircraft)
Update the value of stats array of an aircraft.
Header for slot management related stuff.
uiMessageListNodeMessage_t * MSO_CheckAddNewMessage(const notify_t messagecategory, const char *title, const char *text, messageType_t type, technology_t *pedia, bool popup)
Adds a new message to message stack. It uses message settings to verify whether sound should be playe...
@ NT_UFO_SPOTTED
@ NT_UFO_SIGNAL_LOST
@ NT_UFO_ATTACKING
@ MSG_UFOSPOTTED
Definition cp_messages.h:40
@ MSG_UFOLOST
Definition cp_messages.h:41
void CP_UFOProceedMission(const campaign_t *campaign, aircraft_t *ufo)
Make UFO proceed with its mission when the fight with another aircraft is over (and UFO survived).
bool CP_CheckNextStageDestination(const campaign_t *campaign, aircraft_t *ufocraft)
Check if a stage mission is over when UFO reached destination.
Campaign missions headers.
@ STAGE_INTERCEPT
Definition cp_missions.h:47
void RADAR_DeactivateRadarOverlay(void)
Deactivate Radar overlay if there is no more UFO on geoscape.
Definition cp_radar.cpp:106
bool RADAR_CheckUFOSensored(radar_t *radar, const vec2_t posRadar, const aircraft_t *ufo, bool detected)
Check if the specified UFO is inside the sensor range of the given radar.
Definition cp_radar.cpp:408
#define MAX_UFOONGEOSCAPE
Definition cp_radar.h:27
bool RS_IsResearched_ptr(const technology_t *tech)
Checks whether an item is already researched.
technology_t * RS_GetTechByProvided(const char *idProvided)
returns a pointer to the item tech (as listed in "provides")
void UFO_NotifyPhalanxAircraftRemoved(const aircraft_t *const aircraft)
Notify to UFOs that a Phalanx aircraft has been destroyed.
Definition cp_ufo.cpp:972
static const float MAX_DETECTING_RANGE
Definition cp_ufo.cpp:34
aircraft_t * UFO_GetByIDX(const int idx)
returns the UFO on the geoscape with a certain index
Definition cp_ufo.cpp:85
void UFO_CampaignRunUFOs(const campaign_t *campaign, int deltaTime)
Make the UFOs run.
Definition cp_ufo.cpp:601
void UFO_SendToDestination(aircraft_t *ufo, const vec2_t dest)
Make the specified UFO go to destination.
Definition cp_ufo.cpp:562
void UFO_SetRandomDestAround(aircraft_t *ufocraft, const vec2_t pos)
Give a random destination to the given UFO close to a position, and make him to move there.
Definition cp_ufo.cpp:274
void UFO_CheckShootBack(const campaign_t *campaign, aircraft_t *ufo, aircraft_t *phalanxAircraft)
Check if the ufo can shoot back at phalanx aircraft.
Definition cp_ufo.cpp:578
static int UFO_IsTargetOfInstallation(const aircraft_t *ufo, const installation_t *installation)
Check if a UFO is the target of an installation.
Definition cp_ufo.cpp:332
int UFO_GetOneAvailableUFOForMission(const interestCategory_t missionType, bool checkInterest)
Get a suitable UFO for the mission type.
Definition cp_ufo.cpp:217
const char * UFO_TypeToName(const ufoType_t type)
Translate UFO type to name.
Definition cp_ufo.cpp:231
bool UFO_CampaignCheckEvents(void)
Check events for UFOs: Appears or disappears on radars.
Definition cp_ufo.cpp:867
const char * UFO_GetName(const aircraft_t *ufocraft)
Returns name of the UFO if UFO has been researched.
Definition cp_ufo.cpp:243
void UFO_InitStartup(void)
Init actions for ufo-subsystem.
Definition cp_ufo.cpp:1011
static void UFO_UpdateAlienInterestForOneBase(const aircraft_t *ufo, base_t *base)
Update alien interest for one PHALANX base.
Definition cp_ufo.cpp:353
static const aircraft_t * UFO_GetTemplateForGeoscape(ufoType_t ufoType)
Get the template data for the given ufo type.
Definition cp_ufo.cpp:718
void UFO_DetectNewUFO(aircraft_t *ufocraft)
Perform actions when a new UFO is detected.
Definition cp_ufo.cpp:842
const aircraft_t * UFO_GetByType(const ufoType_t type)
Get the aircraft template for a given UFO type.
Definition cp_ufo.cpp:109
void UFO_UpdateAlienInterestForAllBasesAndInstallations(void)
Update alien interest for all PHALANX bases.
Definition cp_ufo.cpp:437
bool UFO_IsUFOSeenOnGeoscape(const aircraft_t *ufo)
Check if an aircraft should be seen on geoscape.
Definition cp_ufo.cpp:989
bool UFO_CanDoMission(const ufoType_t uType, const char *mType)
Check if the UFO type is available for the given mission type.
Definition cp_ufo.cpp:137
aircraft_t * UFO_AddToGeoscape(ufoType_t ufoType, const vec2_t destination, mission_t *mission)
Add a UFO to geoscape.
Definition cp_ufo.cpp:773
aircraft_t * UFO_CreateFromTemplate(const aircraft_t *ufoTemplate)
Creates a new ufo on the geoscape from the given aircraft template.
Definition cp_ufo.cpp:741
static void UFO_SearchAircraftTarget(const campaign_t *campaign, aircraft_t *ufo, float maxDetectionRange=MAX_DETECTING_RANGE)
Check if the ufo can shoot at a PHALANX aircraft and whether it should follow another ufo.
Definition cp_ufo.cpp:461
void UFO_Shutdown(void)
Closing actions for ufo-subsystem.
Definition cp_ufo.cpp:1023
const technology_t * UFO_GetTechnologyFromType(const ufoType_t type)
Get the technology for a given UFO type.
Definition cp_ufo.cpp:97
void UFO_SetRandomDest(aircraft_t *ufocraft)
Give a random destination to the given UFO, and make him to move there.
Definition cp_ufo.cpp:259
bool UFO_ShouldAppearOnGeoscape(const ufoType_t type)
Some UFOs may only appear if after some interest level in the current running campaign is reached.
Definition cp_ufo.cpp:125
aircraft_t * UFO_GetNext(aircraft_t *lastUFO)
Iterates through the UFOs.
Definition cp_ufo.cpp:41
const aircraft_t * UFO_GetTemplate(ufoType_t ufoType)
Get the template data for the given ufo type.
Definition cp_ufo.cpp:695
static void UFO_SetRandomPos(aircraft_t *ufocraft)
Give a random position to the given UFO.
Definition cp_ufo.cpp:294
aircraft_t * UFO_GetNextOnGeoscape(aircraft_t *lastUFO)
Definition cp_ufo.cpp:66
static const cmdList_t ufoDebugCallbacks[]
Definition cp_ufo.cpp:999
static int UFO_IsTargetOfBase(const aircraft_t *ufo, const base_t *base)
Check if a UFO is the target of a base.
Definition cp_ufo.cpp:309
int UFO_GetAvailableUFOsForMission(const interestCategory_t missionType, ufoType_t *ufoTypes, bool checkInterest)
Fill an array with available UFOs for the mission type.
Definition cp_ufo.cpp:153
bool UFO_SendPursuingAircraft(aircraft_t *ufo, aircraft_t *aircraft)
Make the specified UFO pursue a phalanx aircraft.
Definition cp_ufo.cpp:532
void UFO_RemoveFromGeoscape(aircraft_t *ufo)
Remove the specified ufo from geoscape.
Definition cp_ufo.cpp:817
static void UFO_UpdateAlienInterestForOneInstallation(const aircraft_t *ufo, installation_t *installation)
Update alien interest for one PHALANX installation (radar tower, SAM, ...).
Definition cp_ufo.cpp:395
@ UFO_IS_TARGET_OF_LASER
Definition cp_ufo.h:30
@ UFO_IS_NO_TARGET
Definition cp_ufo.h:28
@ UFO_IS_TARGET_OF_MISSILE
Definition cp_ufo.h:29
void UFO_InitCallbacks(void)
void UFO_ShutdownCallbacks(void)
Header file for menu related console command callbacks.
#define CVAR_DEVELOPER
Definition cvar.h:45
#define DEBUG_CLIENT
Definition defines.h:59
@ AIR_STATS_FUELSIZE
Definition inv_shared.h:232
@ AIR_STATS_SPEED
Definition inv_shared.h:226
@ AIR_STATS_DAMAGE
Definition inv_shared.h:230
void gaussrand(float *gauss1, float *gauss2)
generate two gaussian distributed random numbers with median at 0 and stdev of 1
Definition mathlib.cpp:529
double GetDistanceOnGlobe(const vec2_t pos1, const vec2_t pos2)
Calculate distance on the geoscape.
Definition mathlib.cpp:171
QGL_EXTERN GLenum GLuint * dest
Definition r_gl.h:101
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLint GLenum type
Definition r_gl.h:94
#define UFO_MAX
Definition scripts.h:146
#define UFO_NONE
Definition scripts.h:148
short ufoType_t
Definition scripts.h:145
#define MAX_VAR
Definition shared.h:36
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
const char * va(const char *format,...)
does a varargs printf into a temp buffer, so I don't need to have varargs versions of all text functi...
Definition shared.cpp:410
An aircraft with all it's data.
aircraftSlot_t weapons[MAX_AIRCRAFTSLOT]
bool notOnGeoscape
struct aircraft_s * aircraftTarget
int ufoInterestOnGeoscape
aircraftStatus_t status
int stats[AIR_STATS_MAX]
struct mission_s * mission
class DateTime lastSpotted
mapline_t route
char name[MAX_VAR]
linkedList_t * missionTypes
ufoType_t getUfoType() const
struct technology_s * tech
slot of aircraft
Definition cp_aircraft.h:78
const objDef_t * item
Definition cp_aircraft.h:85
const objDef_t * ammo
Definition cp_aircraft.h:86
A base with all it's data.
Definition cp_base.h:84
int numLasers
Definition cp_base.h:120
struct radar_s radar
Definition cp_base.h:106
baseWeapon_t batteries[MAX_BASE_SLOT]
Definition cp_base.h:116
baseWeapon_t lasers[MAX_BASE_SLOT]
Definition cp_base.h:119
float alienInterest
Definition cp_base.h:104
char name[MAX_VAR]
Definition cp_base.h:86
vec3_t pos
Definition cp_base.h:91
int numBatteries
Definition cp_base.h:117
aircraft_t * target
Definition cp_base.h:79
A installation with all it's data.
baseWeapon_t batteries[MAX_INSTALLATION_BATTERIES]
float distance
Definition cp_aircraft.h:41
vec2_t point[LINE_MAXPTS]
Definition cp_aircraft.h:43
int numPoints
Definition cp_aircraft.h:40
mission definition
Definition cp_missions.h:86
const char * id
Definition inv_shared.h:268
This is the technology parsed from research.ufo.
vec_t vec2_t[2]
Definition ufotypes.h:38
#define Vector2Set(v, x, y)
Definition vector.h:61
#define Vector2Copy(src, dest)
Definition vector.h:52