UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cp_ufo.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2020 UFO: Alien Invasion.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 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 
34 static const float MAX_DETECTING_RANGE = 25.0f;
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 
85 aircraft_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++) {
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 
130 }
131 
137 bool 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 
153 int 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 
217 int 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 
231 const char* UFO_TypeToName (const ufoType_t type)
232 {
233  const technology_t* tech = UFO_GetTechnologyFromType(type);
234  if (tech)
235  return _(tech->name);
236  cgi->Com_Error(ERR_DROP, "UFO_TypeToName(): Unknown UFO type %i\n", type);
237 }
238 
243 const 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 
274 void 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 
294 static 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 
309 static 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)
320  return UFO_IS_TARGET_OF_LASER;
321  }
322 
323  return UFO_IS_NO_TARGET;
324 }
325 
332 static 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 
353 static void UFO_UpdateAlienInterestForOneBase (const aircraft_t* ufo, base_t* base)
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 
461 static 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;
515  AIR_GetDestinationWhilePursuing(ufo, otherUFO, 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;
546  AIR_GetDestinationWhilePursuing(ufo, aircraft, 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 
578 void 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 
601 void 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
622  UFO_SetRandomDest(ufo);
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
648 
651 static 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 
665 static 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 */
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 
773 aircraft_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 
825 }
826 
827 #ifdef DEBUG
828 
831 static void UFO_RemoveFromGeoscape_f (void)
832 {
833  if (ccs.numUFOs > 0)
835 }
836 #endif
837 
842 void UFO_DetectNewUFO (aircraft_t* ufocraft)
843 {
844  if (ufocraft->detected)
845  return;
846 
847  /* Make this UFO detected */
848  if (!ufocraft->detectionIdx) {
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 
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 
972 void UFO_NotifyPhalanxAircraftRemoved (const aircraft_t* const aircraft)
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 
999 static 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 
1011 void UFO_InitStartup (void)
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 
1023 void UFO_Shutdown (void)
1024 {
1026  cgi->Cmd_TableRemoveList(ufoDebugCallbacks);
1027 }
float distance
Definition: cp_aircraft.h:40
aircraft_t ufos[MAX_UFOONGEOSCAPE]
Definition: cp_campaign.h:354
void GEO_UpdateGeoscapeDock(void)
Will add missions and UFOs to the geoscape dock panel.
bool notOnGeoscape
Definition: cp_aircraft.h:170
#define AIRFIGHT_WEAPON_CAN_NEVER_SHOOT
Definition: cp_airfight.h:38
int UFO_GetOneAvailableUFOForMission(const interestCategory_t missionType, bool checkInterest)
Get a suitable UFO for the mission type.
Definition: cp_ufo.cpp:217
#define MAX_UFOONGEOSCAPE
Definition: cp_radar.h:27
void UFO_InitCallbacks(void)
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...
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 RS_IsResearched_ptr(const technology_t *tech)
Checks whether an item is already researched.
A installation with all it's data.
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
bool B_GetBuildingStatus(const base_t *const base, const buildingType_t buildingType)
Get the status associated to a building.
Definition: cp_base.cpp:477
bool CP_CheckNextStageDestination(const campaign_t *campaign, aircraft_t *ufocraft)
Check if a stage mission is over when UFO reached destination.
char * id
Definition: cp_aircraft.h:119
int detectionIdx
Definition: cp_aircraft.h:173
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
static const cmdList_t ufoDebugCallbacks[]
Definition: cp_ufo.cpp:999
aircraft_t * UFO_GetNext(aircraft_t *lastUFO)
Iterates through the UFOs.
Definition: cp_ufo.cpp:41
void AII_UpdateAircraftStats(aircraft_t *aircraft)
Update the value of stats array of an aircraft.
#define _(String)
Definition: cl_shared.h:43
static void UFO_SetRandomPos(aircraft_t *ufocraft)
Give a random position to the given UFO.
Definition: cp_ufo.cpp:294
char id[MAX_VAR]
Definition: cp_missions.h:87
void UFO_CampaignRunUFOs(const campaign_t *campaign, int deltaTime)
Make the UFOs run.
Definition: cp_ufo.cpp:601
bool UFO_IsUFOSeenOnGeoscape(const aircraft_t *ufo)
Check if an aircraft should be seen on geoscape.
Definition: cp_ufo.cpp:989
void GEO_NotifyUFODisappear(const aircraft_t *ufo)
Notify that a UFO disappears on radars.
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.
char name[MAX_VAR]
Definition: cp_base.h:86
#define REMOVE_ELEM_ADJUST_IDX(array, index, n)
Definition: common.h:419
short ufoType_t
Definition: scripts.h:146
ufoType_t getUfoType() const
Definition: cp_aircraft.h:179
date_t date
Definition: cp_campaign.h:245
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
aircraft_t * UFO_AddToGeoscape(ufoType_t ufoType, const vec2_t destination, mission_t *mission)
Add a UFO to geoscape.
Definition: cp_ufo.cpp:773
bool GEO_IsRadarOverlayActivated(void)
Definition: cp_geoscape.cpp:84
char name[MAX_VAR]
Definition: cp_aircraft.h:120
const char * UFO_GetName(const aircraft_t *ufocraft)
Returns name of the UFO if UFO has been researched.
Definition: cp_ufo.cpp:243
aircraft_t * UFO_GetNextOnGeoscape(aircraft_t *lastUFO)
Definition: cp_ufo.cpp:66
void UFO_Shutdown(void)
Closing actions for ufo-subsystem.
Definition: cp_ufo.cpp:1023
mission definition
Definition: cp_missions.h:85
void AIRFIGHT_ExecuteActions(const campaign_t *campaign, aircraft_t *shooter, aircraft_t *target)
Decide what an attacking aircraft can do.
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
mapline_t route
Definition: cp_aircraft.h:134
int numAircraftTemplates
Definition: cp_campaign.h:384
struct mission_s * mission
Definition: cp_aircraft.h:152
A base with all it's data.
Definition: cp_base.h:84
const linkedList_t *IMPORT * LIST_ContainsString(const linkedList_t *list, const char *string)
#define INS_Foreach(var)
linkedList_t * missionTypes
Definition: cp_aircraft.h:172
bool UFO_SendPursuingAircraft(aircraft_t *ufo, aircraft_t *aircraft)
Make the specified UFO pursue a phalanx aircraft.
Definition: cp_ufo.cpp:532
struct technology_s * tech
Definition: cp_aircraft.h:162
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.
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
void AII_ReloadAircraftWeapons(aircraft_t *aircraft)
Reload the weapons of an aircraft.
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
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.
#define ERR_DROP
Definition: common.h:211
#define DEBUG_CLIENT
Definition: defines.h:59
const aircraft_t * UFO_GetTemplate(ufoType_t ufoType)
Get the template data for the given ufo type.
Definition: cp_ufo.cpp:695
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
vec3_t pos
Definition: cp_aircraft.h:131
#define MAX_VAR
Definition: shared.h:36
const aircraft_t * UFO_GetByType(const ufoType_t type)
Get the aircraft template for a given UFO type.
Definition: cp_ufo.cpp:109
#define Vector2Set(v, x, y)
Definition: vector.h:61
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 ufosDetected
Definition: cp_statistics.h:46
int numLasers
Definition: cp_base.h:120
Campaign missions headers.
const objDef_t * ammo
Definition: cp_aircraft.h:85
base_t * B_GetNext(base_t *lastBase)
Iterates through founded bases.
Definition: cp_base.cpp:285
const cgame_import_t * cgi
void UFO_NotifyPhalanxAircraftRemoved(const aircraft_t *const aircraft)
Notify to UFOs that a Phalanx aircraft has been destroyed.
Definition: cp_ufo.cpp:972
struct radar_s radar
Definition: cp_base.h:106
const char *IMPORT * Com_UFOTypeToShortName(ufoType_t type)
#define UFO_MAX
Definition: scripts.h:147
struct aircraft_s * aircraftTarget
Definition: cp_aircraft.h:156
const char * UFO_TypeToName(const ufoType_t type)
Translate UFO type to name.
Definition: cp_ufo.cpp:231
This is the technology parsed from research.ufo.
Definition: cp_research.h:137
ccs_t ccs
Definition: cp_campaign.cpp:62
stats_t campaignStats
Definition: cp_campaign.h:378
int ufoInterestOnGeoscape
Definition: cp_aircraft.h:171
static const aircraft_t * UFO_GetTemplateForGeoscape(ufoType_t ufoType)
Get the template data for the given ufo type.
Definition: cp_ufo.cpp:718
Definition: cmd.h:86
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 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
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)...
void CP_TriggerEvent(campaignTriggerEventType_t type, const void *userdata)
Triggers a campaign event with a special type.
Definition: cp_event.cpp:311
bool UFO_CampaignCheckEvents(void)
Check events for UFOs: Appears or disappears on radars.
Definition: cp_ufo.cpp:867
aircraft_t aircraftTemplates[MAX_AIRCRAFT]
Definition: cp_campaign.h:383
aircraftSlot_t weapons[MAX_AIRCRAFTSLOT]
Definition: cp_aircraft.h:143
Header for Geoscape management.
cvar_t *IMPORT * Cvar_Get(const char *varName, const char *value, int flags, const char *desc)
QGL_EXTERN GLenum GLuint * dest
Definition: r_gl.h:101
slot of aircraft
Definition: cp_aircraft.h:77
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.
int numPoints
Definition: cp_aircraft.h:39
union mission_s::missionData_t data
baseWeapon_t batteries[MAX_BASE_SLOT]
Definition: cp_base.h:116
vec2_t point[LINE_MAXPTS]
Definition: cp_aircraft.h:42
void gaussrand(float *gauss1, float *gauss2)
generate two gaussian distributed random numbers with median at 0 and stdev of 1
Definition: mathlib.cpp:529
aircraft_t * UFO_GetByIDX(const int idx)
returns the UFO on the geoscape with a certain index
Definition: cp_ufo.cpp:85
static void UFO_UpdateAlienInterestForOneBase(const aircraft_t *ufo, base_t *base)
Update alien interest for one PHALANX base.
Definition: cp_ufo.cpp:353
int maxWeapons
Definition: cp_aircraft.h:144
void UFO_UpdateAlienInterestForAllBasesAndInstallations(void)
Update alien interest for all PHALANX bases.
Definition: cp_ufo.cpp:437
enum interestCategory_s interestCategory_t
void CP_GetRandomPosOnGeoscape(vec2_t pos, bool noWater)
Determines a random position on geoscape.
Header file for aircraft stuff.
void UFO_ShutdownCallbacks(void)
QGL_EXTERN GLint i
Definition: r_gl.h:113
#define AIR_IsUFO(aircraft)
Definition: cp_aircraft.h:205
int overallInterest
Definition: cp_campaign.h:238
Header for slot management related stuff.
bool detected
Definition: cp_aircraft.h:166
Header file for menu related console command callbacks.
#define CVAR_DEVELOPER
Definition: cvar.h:45
float alienInterest
Definition: cp_base.h:104
void GEO_CheckPositionBoundaries(float *pos)
Check that a position (in latitude / longitude) is within boundaries.
aircraftStatus_t status
Definition: cp_aircraft.h:125
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
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
int numUFOs
Definition: cp_campaign.h:355
void UFO_DetectNewUFO(aircraft_t *ufocraft)
Perform actions when a new UFO is detected.
Definition: cp_ufo.cpp:842
const int DETECTION_INTERVAL
delay between actions that must be executed independently of time scale
Definition: cp_campaign.cpp:74
#define Vector2Copy(src, dest)
Definition: vector.h:52
vec_t vec2_t[2]
Definition: ufotypes.h:38
Header file for single player campaign control.
void AIRFIGHT_ActionsAfterAirfight(const campaign_t *campaign, aircraft_t *shooter, aircraft_t *aircraft, bool phalanxWon)
Actions to execute when a fight is done.
void UFO_SendToDestination(aircraft_t *ufo, const vec2_t dest)
Make the specified UFO go to destination.
Definition: cp_ufo.cpp:562
baseWeapon_t lasers[MAX_BASE_SLOT]
Definition: cp_base.h:119
technology_t * RS_GetTechByProvided(const char *idProvided)
returns a pointer to the item tech (as listed in "provides")
vec3_t pos
Definition: cp_base.h:91
int stats[AIR_STATS_MAX]
Definition: cp_aircraft.h:159
#define AIR_Foreach(var)
iterates trough all aircraft
Definition: cp_aircraft.h:192
An aircraft with all it's data.
Definition: cp_aircraft.h:114
void UFO_InitStartup(void)
Init actions for ufo-subsystem.
Definition: cp_ufo.cpp:1011
const technology_t * UFO_GetTechnologyFromType(const ufoType_t type)
Get the technology for a given UFO type.
Definition: cp_ufo.cpp:97
campaign_t * curCampaign
Definition: cp_campaign.h:377
void GEO_SetOverlay(const char *overlayID, int status)
Turn overlay on/off.
void UFO_RemoveFromGeoscape(aircraft_t *ufo)
Remove the specified ufo from geoscape.
Definition: cp_ufo.cpp:817
date_t lastSpotted
Definition: cp_aircraft.h:174
aircraft_t * target
Definition: cp_base.h:79
vec2_t pos
Definition: cp_missions.h:104
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
const objDef_t * item
Definition: cp_aircraft.h:84
static const float MAX_DETECTING_RANGE
Definition: cp_ufo.cpp:34
const char * id
Definition: inv_shared.h:268
baseWeapon_t batteries[MAX_INSTALLATION_BATTERIES]
int numBatteries
Definition: cp_base.h:117
#define UFO_NONE
Definition: scripts.h:149
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
double GetDistanceOnGlobe(const vec2_t pos1, const vec2_t pos2)
Calculate distance on the geoscape.
Definition: mathlib.cpp:171
bool AIR_AircraftMakeMove(int dt, aircraft_t *aircraft)
Moves given aircraft.
missionStage_t stage
Definition: cp_missions.h:98
void RADAR_DeactivateRadarOverlay(void)
Deactivate Radar overlay if there is no more UFO on geoscape.
Definition: cp_radar.cpp:106