UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cp_missions.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 "../../cl_team.h"
27 #include "../cl_game.h"
28 #include "../../ui/ui_dataids.h"
29 #include "cp_campaign.h"
30 #include "cp_character.h"
31 #include "cp_geoscape.h"
32 #include "cp_ufo.h"
33 #include "cp_alienbase.h"
34 #include "cp_alien_interest.h"
35 #include "cp_missions.h"
36 #include "cp_mission_triggers.h"
37 #include "cp_time.h"
38 #include "cp_xvi.h"
39 #include "save/save_missions.h"
40 #include "save/save_interest.h"
41 #include "cp_mission_callbacks.h"
52 
59 
61 const int MAX_POS_LOOP = 10;
62 
64 static const float MIN_CRASHEDUFO_CONDITION = 0.2f;
65 static const float MAX_CRASHEDUFO_CONDITION = 0.81f;
66 
67 /*====================================
68 *
69 * Prepare battlescape
70 *
71 ====================================*/
72 
78 void BATTLE_SetVars (const battleParam_t* battleParameters)
79 {
80  cgi->Cvar_SetValue("ai_singleplayeraliens", battleParameters->aliens);
81  cgi->Cvar_SetValue("ai_numcivilians", battleParameters->civilians);
82  cgi->Cvar_Set("ai_civilianteam", "%s", battleParameters->civTeam);
83  cgi->Cvar_Set("ai_equipment", "%s", battleParameters->alienEquipment);
84 
85  /* now store the alien teams in the shared cgi->csi->struct to let the game dll
86  * have access to this data, too */
87  cgi->csi->numAlienTeams = 0;
88  for (int i = 0; i < battleParameters->alienTeamGroup->numAlienTeams; i++) {
89  cgi->csi->alienTeams[i] = battleParameters->alienTeamGroup->alienTeams[i];
90  cgi->csi->alienChrTemplates[i] = battleParameters->alienTeamGroup->alienChrTemplates[i];
91  cgi->csi->numAlienTeams++;
93  break;
94  }
95 }
96 
106 void BATTLE_Start (mission_t* mission, const battleParam_t* battleParameters)
107 {
108  assert(mission->mapDef->mapTheme);
109 
110  /* set the mapZone - this allows us to replace the ground texture
111  * with the suitable terrain texture - just use tex_terrain/dummy for the
112  * brushes you want the terrain textures on
113  * @sa R_ModLoadTexinfo */
114  cgi->Cvar_Set("sv_mapzone", "%s", battleParameters->zoneType);
115 
116  /* do a quicksave */
117  cgi->Cmd_ExecuteString("game_quicksave");
118 
119  if (mission->crashed)
120  cgi->Cvar_Set("sv_hurtaliens", "1");
121  else
122  cgi->Cvar_Set("sv_hurtaliens", "0");
123 
124  cgi->Cvar_Set("r_overridematerial", "");
125 
126  /* base attack maps starts with a dot */
127  if (mission->mapDef->mapTheme[0] == '.') {
128  const base_t* base = mission->data.base;
129 
130  if (mission->category != INTERESTCATEGORY_BASE_ATTACK)
131  cgi->Com_Printf("Baseattack map on non-baseattack mission! (id=%s, category=%d)\n", mission->id, mission->category);
132  /* assemble a random base */
133  if (!base)
134  cgi->Com_Error(ERR_DROP, "Baseattack map without base!");
135  /* base must be under attack and might not have been destroyed in the meantime. */
136  char maps[2048];
137  char coords[2048];
138  B_AssembleMap(maps, sizeof(maps), coords, sizeof(coords), base);
139  cgi->Cvar_Set("r_overridematerial", "baseattack");
140  cgi->Cbuf_AddText("map %s \"%s\" \"%s\"\n", (GEO_IsNight(base->pos) ? "night" : "day"), maps, coords);
141 
142  return;
143  }
144 
145  /* Set difficulty level for the battle */
146  assert(ccs.curCampaign);
147  cgi->Cvar_Delete("g_difficulty");
148  cgi->Cvar_SetValue("g_difficulty", ccs.curCampaign->difficulty);
149 
150  const char* param = battleParameters->param ? battleParameters->param : (const char*)cgi->LIST_GetRandom(mission->mapDef->params);
151  cgi->Cbuf_AddText("map %s %s %s\n", (GEO_IsNight(mission->pos) ? "night" : "day"),
152  mission->mapDef->mapTheme, param ? param : "");
153 }
154 
161 static bool CP_IsAlienTeamForCategory (const alienTeamCategory_t* cat, const interestCategory_t missionCat)
162 {
163  for (int i = 0; i < cat->numMissionCategories; i++) {
164  if (missionCat == cat->missionCategories[i])
165  return true;
166  }
167 
168  return false;
169 }
170 
176 static void CP_SetAlienTeamByInterest (mission_t* mission, battleParam_t* battleParameters)
177 {
178  const int MAX_AVAILABLE_GROUPS = 4;
179  alienTeamGroup_t* availableGroups[MAX_AVAILABLE_GROUPS];
180  int numAvailableGroup = 0;
181 
182  /* Find all available alien team groups */
183  for (int i = 0; i < ccs.numAlienCategories; i++) {
185 
186  /* Check if this alien team category may be used */
187  if (!CP_IsAlienTeamForCategory(cat, mission->category))
188  continue;
189 
190  /* Find all available team groups for current alien interest
191  * use mission->initialOverallInterest and not ccs.overallInterest:
192  * the alien team should not change depending on when you encounter it */
193  for (int j = 0; j < cat->numAlienTeamGroups; j++) {
194  if (cat->alienTeamGroups[j].minInterest <= mission->initialOverallInterest
195  && cat->alienTeamGroups[j].maxInterest >= mission->initialOverallInterest)
196  availableGroups[numAvailableGroup++] = &cat->alienTeamGroups[j];
197  }
198  }
199 
200  if (!numAvailableGroup) {
201  CP_MissionRemove(mission);
202  cgi->Com_Error(ERR_DROP, "CP_SetAlienTeamByInterest: no available alien team for mission '%s': interest = %i -- category = %i",
203  mission->id, mission->initialOverallInterest, mission->category);
204  }
205 
206  /* Pick up one group randomly */
207  int pick = rand() % numAvailableGroup;
208 
209  /* store this group for latter use */
210  battleParameters->alienTeamGroup = availableGroups[pick];
211 }
212 
220 static bool CP_IsAlienEquipmentSelectable (const mission_t* mission, const equipDef_t* equip, linkedList_t* equipPack)
221 {
222  if (mission->initialOverallInterest > equip->maxInterest || mission->initialOverallInterest < equip->minInterest)
223  return false;
224 
225  LIST_Foreach(equipPack, const char, name) {
226  if (Q_strstart(equip->id, name))
227  return true;
228  }
229 
230  return false;
231 }
232 
242 static void CP_SetAlienEquipmentByInterest (const mission_t* mission, linkedList_t* equipPack, battleParam_t* battleParameters)
243 {
244  int i, availableEquipDef = 0;
245 
246  /* look for all available fitting alien equipment definitions
247  * use mission->initialOverallInterest and not ccs.overallInterest: the alien equipment should not change depending on
248  * when you encounter it */
249  for (i = 0; i < cgi->csi->numEDs; i++) {
250  const equipDef_t* ed = &cgi->csi->eds[i];
251  if (CP_IsAlienEquipmentSelectable(mission, ed, equipPack))
252  availableEquipDef++;
253  }
254 
255  cgi->Com_DPrintf(DEBUG_CLIENT, "CP_SetAlienEquipmentByInterest: %i available equipment packs for mission %s\n", availableEquipDef, mission->id);
256 
257  if (!availableEquipDef)
258  cgi->Com_Error(ERR_DROP, "CP_SetAlienEquipmentByInterest: no available alien equipment for mission '%s'", mission->id);
259 
260  /* Choose an alien equipment definition -- between 0 and availableStage - 1 */
261  const int randomNum = rand() % availableEquipDef;
262 
263  availableEquipDef = 0;
264  for (i = 0; i < cgi->csi->numEDs; i++) {
265  const equipDef_t* ed = &cgi->csi->eds[i];
266  if (CP_IsAlienEquipmentSelectable(mission, ed, equipPack)) {
267  if (availableEquipDef == randomNum) {
268  Com_sprintf(battleParameters->alienEquipment, sizeof(battleParameters->alienEquipment), "%s", ed->id);
269  break;
270  }
271  availableEquipDef++;
272  }
273  }
274 }
275 
282 static void MIS_CreateAlienTeam (mission_t* mission, battleParam_t* battleParam)
283 {
284  int numAliens;
285 
286  assert(mission->posAssigned);
287 
288  CP_SetAlienTeamByInterest(mission, battleParam);
290 
291  const int min = battleParam->alienTeamGroup->minAlienCount;
292  const int max = battleParam->alienTeamGroup->maxAlienCount;
293  const int diff = max - min;
294 
295  numAliens = min + rand() % (diff + 1);
296  numAliens = std::max(1, numAliens);
297  if (mission->ufo && mission->ufo->maxTeamSize && numAliens > mission->ufo->maxTeamSize)
298  numAliens = mission->ufo->maxTeamSize;
299  if (numAliens > mission->mapDef->maxAliens)
300  numAliens = mission->mapDef->maxAliens;
301  battleParam->aliens = numAliens;
302 }
303 
309 static void CP_CreateCivilianTeam (const mission_t* mission, battleParam_t* param)
310 {
311  nation_t* nation;
312 
313  assert(mission->posAssigned);
314 
315  param->civilians = GEO_GetCivilianNumberByPosition(mission->pos);
316 
317  nation = GEO_GetNation(mission->pos);
318  param->nation = nation;
319  if (mission->mapDef->civTeam != nullptr) {
320  Q_strncpyz(param->civTeam, mission->mapDef->civTeam, sizeof(param->civTeam));
321  } else if (nation) {
323  Q_strncpyz(param->civTeam, nation->id, sizeof(param->civTeam));
324  } else {
325  Q_strncpyz(param->civTeam, "europe", sizeof(param->civTeam));
326  }
327 }
328 
338 void CP_CreateBattleParameters (mission_t* mission, battleParam_t* param, const aircraft_t* aircraft)
339 {
340  assert(mission->posAssigned);
341  assert(mission->mapDef);
342 
343  MIS_CreateAlienTeam(mission, param);
344  CP_CreateCivilianTeam(mission, param);
345 
346  /* Reset parameters */
347  cgi->Free(param->param);
348  param->param = nullptr;
349  param->retriable = true;
350 
351  cgi->Cvar_Set("rm_ufo", "");
352  cgi->Cvar_Set("rm_drop", "");
353  cgi->Cvar_Set("rm_crashed", "");
354 
355  param->mission = mission;
356  const byte* color = GEO_GetColor(mission->pos, MAPTYPE_TERRAIN, nullptr);
357  param->zoneType = cgi->csi->terrainDefs.getTerrainName(color); /* store to terrain type for texture replacement */
358  /* Hack: Alienbase is fully indoors (underground) so no weather effects, maybe this should be a mapdef property? */
359  if (mission->category == INTERESTCATEGORY_ALIENBASE)
360  cgi->Cvar_Set("r_weather", "0");
361  else
362  cgi->Cvar_Set("r_weather", "%s", cgi->csi->terrainDefs.getWeather(color));
363 
364  /* Is there a UFO to recover ? */
365  if (mission->ufo) {
366  const aircraft_t* ufo = mission->ufo;
367  const char* shortUFOType;
368  float ufoCondition;
369 
370  if (mission->crashed) {
371  shortUFOType = cgi->Com_UFOCrashedTypeToShortName(ufo->getUfoType());
372  /* Set random map UFO if this is a random map */
373  if (mission->mapDef->mapTheme[0] == '+') {
374  /* set battleParameters.param to the ufo type: used for ufocrash random map */
375  if (Q_streq(mission->mapDef->id, "ufocrash"))
376  param->param = cgi->PoolStrDup(shortUFOType, cp_campaignPool, 0);
377  }
379  } else {
380  shortUFOType = cgi->Com_UFOTypeToShortName(ufo->getUfoType());
381  ufoCondition = 1.0f;
382  }
383 
384  Com_sprintf(mission->onwin, sizeof(mission->onwin), "ui_push popup_uforecovery \"%s\" \"%s\" \"%s\" \"%s\" %3.2f",
385  UFO_GetName(ufo), ufo->id, ufo->model, (mission->crashed ? _("landed") : _("crashed")), ufoCondition);
386  /* Set random map UFO if this is a random map */
387  if (mission->mapDef->mapTheme[0] == '+' && !cgi->LIST_IsEmpty(mission->mapDef->ufos)) {
388  /* set rm_ufo to the ufo type used */
389  cgi->Cvar_Set("rm_ufo", "%s", cgi->Com_GetRandomMapAssemblyNameForCraft(shortUFOType));
390  }
391  }
392 
393  /* Set random map aircraft if this is a random map */
394  if (mission->mapDef->mapTheme[0] == '+') {
395  if (mission->category == INTERESTCATEGORY_RESCUE) {
396  cgi->Cvar_Set("rm_crashed", "%s", cgi->Com_GetRandomMapAssemblyNameForCrashedCraft(mission->data.aircraft->id));
397  }
398  if (cgi->LIST_ContainsString(mission->mapDef->aircraft, aircraft->id))
399  cgi->Cvar_Set("rm_drop", "%s", cgi->Com_GetRandomMapAssemblyNameForCraft(aircraft->id));
400  }
401 }
402 
403 /*====================================
404 *
405 * Get information from mission list
406 *
407 ====================================*/
408 
414 mission_t* CP_GetMissionByIDSilent (const char* missionId)
415 {
416  if (!missionId)
417  return nullptr;
418 
419  MIS_Foreach(mission) {
420  if (Q_streq(mission->id, missionId))
421  return mission;
422  }
423 
424  return nullptr;
425 }
426 
432 mission_t* CP_GetMissionByID (const char* missionId)
433 {
434  mission_t* mission = CP_GetMissionByIDSilent(missionId);
435 
436  if (!missionId)
437  cgi->Com_Printf("CP_GetMissionByID: missionId was nullptr!\n");
438  else if (!mission)
439  cgi->Com_Printf("CP_GetMissionByID: Could not find mission %s\n", missionId);
440 
441  return mission;
442 }
443 
448 {
449  MIS_Foreach(mission) {
450  if (mission->idx == id)
451  return mission;
452  }
453 
454  return nullptr;
455 }
456 
460 int MIS_GetIdx (const mission_t* mis)
461 {
462  return mis->idx;
463 }
464 
469 const char* MIS_GetName (const mission_t* mission)
470 {
471  assert(mission);
472 
473  if (mission->category == INTERESTCATEGORY_RESCUE)
474  if (mission->data.aircraft)
475  return va(_("Crashed %s"), mission->data.aircraft->name);
476 
477  const nation_t* nation = GEO_GetNation(mission->pos);
478  switch (mission->stage) {
480  if (mission->data.city)
481  return va(_("Alien terror in %s"), _(mission->data.city->name));
482  else
483  return _("Alien terror");
484  case STAGE_BASE_ATTACK:
485  if (mission->data.base)
486  return va(_("Base attacked: %s"), mission->data.base->name);
487  else
488  return _("Base attack");
490  if (nation)
491  return va(_("Alien base in %s"), _(nation->name));
492  else
493  return _("Alien base");
494  default:
495  break;
496  }
497 
498  /* mission has an ufo */
499  if (mission->ufo) {
500  /* which is crashed */
501  if (mission->crashed)
502  return va(_("Crashed %s"), UFO_GetName(mission->ufo));
503  /* not crashed but detected */
504  if (mission->ufo->detected && mission->ufo->landed)
505  return va(_("Landed %s"), UFO_GetName(mission->ufo));
506  }
507 
508  /* we know nothing about the mission, maybe only it's location */
509  if (nation)
510  return va(_("Alien activity in %s"), _(nation->name));
511  else
512  return _("Alien activity");
513 }
514 
515 #ifdef DEBUG
516 
520 static const char* CP_MissionStageToName (const missionStage_t stage)
521 {
522  switch (stage) {
523  case STAGE_NOT_ACTIVE:
524  return "Not active yet";
526  return "UFO coming from orbit";
527  case STAGE_RECON_AIR:
528  return "Aerial recon underway";
529  case STAGE_MISSION_GOTO:
530  return "Going to mission position";
531  case STAGE_RECON_GROUND:
532  return "Ground recon mission underway";
534  return "Terror mission underway";
535  case STAGE_BUILD_BASE:
536  return "Building base";
537  case STAGE_BASE_ATTACK:
538  return "Attacking a base";
539  case STAGE_SUBVERT_GOV:
540  return "Subverting a government";
541  case STAGE_SUPPLY:
542  return "Supplying";
543  case STAGE_SPREAD_XVI:
544  return "Spreading XVI";
545  case STAGE_INTERCEPT:
546  return "Intercepting or attacking installation";
548  return "Leaving earth";
550  return "Base visible";
551  case STAGE_HARVEST:
552  return "Harvesting";
553  case STAGE_OVER:
554  return "Mission over";
555  }
556 
557  /* Can't reach this point */
558  return "";
559 }
560 #endif
561 
567 {
568  int counterVisibleMission = 0;
569 
570  MIS_Foreach(mission) {
571  if (mission->onGeoscape) {
572  counterVisibleMission++;
573  }
574  }
575 
576  return counterVisibleMission;
577 }
578 
579 
580 /*====================================
581 * Functions relative to geoscape
582 *====================================*/
583 
589 const char* MIS_GetModel (const mission_t* mission)
590 {
591  /* Mission shouldn't be drawn on geoscape if mapDef is not defined */
592  assert(mission->mapDef);
593 
594  if (mission->crashed)
595  return "geoscape/ufocrash";
596 
597  if (mission->mapDef->storyRelated && mission->category != INTERESTCATEGORY_ALIENBASE)
598  return "geoscape/icon_story";
599 
600  cgi->Com_DPrintf(DEBUG_CLIENT, "Mission is %s, %d\n", mission->id, mission->category);
601  switch (mission->category) {
603  return "geoscape/icon_rescue";
606  return "geoscape/icon_build_alien_base";
609  return "geoscape/alienbase";
611  return "geoscape/icon_recon";
613  return "geoscape/icon_xvi";
615  return "geoscape/icon_harvest";
617  return "geoscape/icon_ufocarrier";
619  return "geoscape/icon_terror";
620  /* Should not be reached, these mission categories are not drawn on geoscape */
622  return "geoscape/base2";
628  break;
629  }
630  cgi->Com_Error(ERR_DROP, "Unknown mission interest category");
631 }
632 
639 {
640  /* This function could be called before position of the mission is defined */
641  if (!mission->posAssigned)
643 
644  if (mission->crashed)
645  return MISDET_ALWAYS_DETECTED;
646 
647  if (mission->ufo && mission->ufo->detected && mission->ufo->landed)
648  return MISDET_ALWAYS_DETECTED;
649 
650  if (mission->category == INTERESTCATEGORY_RESCUE)
651  return MISDET_ALWAYS_DETECTED;
652 
653  switch (mission->stage) {
656  return MISDET_ALWAYS_DETECTED;
657  case STAGE_RECON_GROUND:
658  case STAGE_SUBVERT_GOV:
659  case STAGE_SPREAD_XVI:
660  case STAGE_HARVEST:
661  if (RADAR_CheckRadarSensored(mission->pos))
662  return MISDET_MAY_BE_DETECTED;
663  break;
665  case STAGE_MISSION_GOTO:
666  case STAGE_INTERCEPT:
667  case STAGE_RECON_AIR:
669  case STAGE_NOT_ACTIVE:
670  case STAGE_BUILD_BASE:
671  case STAGE_BASE_ATTACK:
672  case STAGE_OVER:
673  case STAGE_SUPPLY:
674  break;
675  }
677 }
678 
683 {
684  if (!mission->onGeoscape && mission->category != INTERESTCATEGORY_BASE_ATTACK)
685  return;
686 
687  mission->onGeoscape = false;
688 
689  /* Notifications */
690  GEO_NotifyMissionRemoved(mission);
692 }
693 
699 static inline messageType_t CP_MissionGetMessageLevel (const mission_t* mission)
700 {
701  switch (mission->stage) {
702  case STAGE_BASE_ATTACK:
703  return MSG_BASEATTACK;
705  return MSG_TERRORSITE;
706  default:
707  break;
708  }
709 
710  if (mission->crashed)
711  return MSG_CRASHSITE;
712  return MSG_STANDARD;
713 }
714 
720 static inline const char* CP_MissionGetMessage (const mission_t* mission)
721 {
722  if (mission->category == INTERESTCATEGORY_RESCUE) {
723  Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Go on a rescue mission for %s to save your soldiers, some of whom may still be alive."), mission->data.aircraft->name);
724  } else {
725  const nation_t* nation = GEO_GetNation(mission->pos);
726  if (nation)
727  Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Alien activity has been detected in %s."), _(nation->name));
728  else
729  Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Alien activity has been detected."));
730  }
731  return cp_messageBuffer;
732 }
733 
740 void CP_MissionAddToGeoscape (mission_t* mission, bool force)
741 {
743 
744  /* don't show a mission spawned by a undetected ufo, unless forced : this may be done at next detection stage */
745  if (status == MISDET_CANT_BE_DETECTED || (!force && status == MISDET_MAY_BE_DETECTED && mission->ufo && !mission->ufo->detected))
746  return;
747 
748 #ifdef DEBUG
749  /* UFO that spawned this mission should be close of mission */
750  if (mission->ufo && ((fabs(mission->ufo->pos[0] - mission->pos[0]) > 1.0f) || (fabs(mission->ufo->pos[1] - mission->pos[1]) > 1.0f))) {
751  cgi->Com_Printf("Error: mission (stage: %s) spawned is not at the same location as UFO\n", CP_MissionStageToName(mission->stage));
752  }
753 #endif
754 
755  /* Notify the player */
756  MS_AddNewMessage(_("Notice"), CP_MissionGetMessage(mission), CP_MissionGetMessageLevel(mission));
757 
758  mission->onGeoscape = true;
759  CP_GameTimeStop();
761 }
762 
770 {
771  /* Probability to detect UFO each DETECTION_INTERVAL
772  * This correspond to 40 percents each 30 minutes (coded this way to be able to
773  * change DETECTION_INTERVAL without changing the way radar works) */
774  const float missionDetectionProbability = 0.000125f * DETECTION_INTERVAL;
775  bool newDetection = false;
776 
777  MIS_Foreach(mission) {
779 
780  /* only check mission that can be detected, and that are not already detected */
781  if (status != MISDET_MAY_BE_DETECTED || mission->onGeoscape)
782  continue;
783 
784  /* if there is a ufo assigned, it must not be detected */
785  assert(!mission->ufo || !mission->ufo->detected);
786 
787  if (frand() <= missionDetectionProbability) {
788  /* if mission has a UFO, detect the UFO when it takes off */
789  if (mission->ufo)
790  UFO_DetectNewUFO(mission->ufo);
791 
792  /* mission is detected */
793  CP_MissionAddToGeoscape(mission, true);
794 
795  newDetection = true;
796  }
797  }
798  return newDetection;
799 }
800 
807 {
808  MIS_Foreach(mission) {
809  if (mission->onGeoscape && CP_CheckMissionVisibleOnGeoscape(mission) == MISDET_CANT_BE_DETECTED) {
810  /* remove a mission when radar is destroyed */
812  } else if (!mission->onGeoscape && CP_CheckMissionVisibleOnGeoscape(mission) == MISDET_ALWAYS_DETECTED) {
813  /* only show mission that are always detected: mission that have a probability to be detected will be
814  * tested at next half hour */
815  CP_MissionAddToGeoscape(mission, false);
816  }
817  }
818 }
819 
827 void CP_UFORemoveFromGeoscape (mission_t* mission, bool destroyed)
828 {
829  assert(mission->ufo);
830 
831  /* UFO is landed even if it's destroyed: crash site mission is spawned */
832  mission->ufo->landed = true;
833 
834  /* Notications */
835  AIR_AircraftsNotifyUFORemoved(mission->ufo, destroyed);
836  GEO_NotifyUFORemoved(mission->ufo, destroyed);
838 
839  if (destroyed) {
840  /* remove UFO from radar and update idx of ufo in radar array */
841  RADAR_NotifyUFORemoved(mission->ufo, true);
842 
843  /* Update UFO idx */
845  MIS_Foreach(removedMission) {
846  if (removedMission->ufo && (removedMission->ufo > mission->ufo))
847  removedMission->ufo--;
848  }
849 
850  UFO_RemoveFromGeoscape(mission->ufo);
851  mission->ufo = nullptr;
852  } else if (mission->ufo->detected && !RADAR_CheckRadarSensored(mission->ufo->pos)) {
853  /* maybe we use a high speed time: UFO was detected, but flied out of radar
854  * range since last calculation, and mission is spawned outside radar range */
855  RADAR_NotifyUFORemoved(mission->ufo, false);
856  }
857 }
858 
859 
860 /*====================================
861 *
862 * Handling missions
863 *
864 *====================================*/
865 
871 {
872  /* Destroy UFO */
873  if (mission->ufo)
874  CP_UFORemoveFromGeoscape(mission, true); /* for the notifications */
875 
876  /* Remove from battle parameters */
877  if (mission == ccs.battleParameters.mission)
878  ccs.battleParameters.mission = nullptr;
879 
880  /* Notifications */
882 
883  if (!cgi->LIST_Remove(&ccs.missions, mission))
884  cgi->Com_Error(ERR_DROP, "CP_MissionRemove: Could not find mission '%s' to remove.\n", mission->id);
885 }
886 
894 {
895  mission->finalDate.day = 0;
896 }
897 
905 {
906  return mission->finalDate.day != 0;
907 }
908 
909 
910 /*====================================
911 *
912 * Notifications
913 *
914 ====================================*/
915 
920 {
921  MIS_Foreach(mission) {
922  /* Check if this is a base attack mission attacking this base */
923  if (mission->category == INTERESTCATEGORY_BASE_ATTACK && mission->data.base) {
924  if (base == mission->data.base) {
925  /* Aimed base has been destroyed, abort mission */
926  CP_BaseAttackMissionLeave(mission);
927  }
928  }
929  }
930 }
931 
937 {
938  MIS_Foreach(mission) {
939  if (mission->category == INTERESTCATEGORY_INTERCEPT && mission->data.installation) {
940  if (mission->data.installation == installation)
941  CP_InterceptMissionLeave(mission, false);
942  }
943  }
944 }
945 
946 /*====================================
947 *
948 * Functions common to several mission type
949 *
950 ====================================*/
951 
959 static bool CP_MapIsSelectable (const mission_t* mission, const mapDef_t* md, const vec2_t pos)
960 {
961  if (md->storyRelated)
962  return false;
963 
964  if (!mission->ufo) {
965  /* a mission without UFO should not use a map with UFO */
966  if (!cgi->LIST_IsEmpty(md->ufos))
967  return false;
968  } else if (!cgi->LIST_IsEmpty(md->ufos)) {
969  /* A mission with UFO should use a map with UFO
970  * first check that list is not empty */
971  const ufoType_t type = mission->ufo->getUfoType();
972  const char* ufoID;
973 
974  if (mission->crashed)
975  ufoID = cgi->Com_UFOCrashedTypeToShortName(type);
976  else
977  ufoID = cgi->Com_UFOTypeToShortName(type);
978 
979  if (!cgi->LIST_ContainsString(md->ufos, ufoID))
980  return false;
981  }
982 
983  if (pos && !GEO_PositionFitsTCPNTypes(pos, md->terrains, md->cultures, md->populations, nullptr))
984  return false;
985 
986  return true;
987 }
988 
995 bool CP_ChooseMap (mission_t* mission, const vec2_t pos)
996 {
997  if (mission->mapDef)
998  return true;
999 
1000  int countMinimal = 0;
1001  int minMapDefAppearance = -1;
1002  mapDef_t* md = nullptr;
1004  /* Check if mission fulfill conditions */
1005  if (!CP_MapIsSelectable(mission, md, pos))
1006  continue;
1007 
1008  if (minMapDefAppearance < 0 || md->timesAlreadyUsed < minMapDefAppearance) {
1009  minMapDefAppearance = md->timesAlreadyUsed;
1010  countMinimal = 1;
1011  continue;
1012  }
1013  if (md->timesAlreadyUsed > minMapDefAppearance)
1014  continue;
1015  countMinimal++;
1016  }
1017 
1018  if (countMinimal == 0) {
1019  /* no map fulfill the conditions */
1020  if (mission->category == INTERESTCATEGORY_RESCUE) {
1021  /* default map for rescue mission is the rescue random map assembly */
1022  mission->mapDef = cgi->Com_GetMapDefinitionByID("rescue");
1023  if (!mission->mapDef)
1024  cgi->Com_Error(ERR_DROP, "Could not find mapdef: rescue");
1025  mission->mapDef->timesAlreadyUsed++;
1026  return true;
1027  }
1028  if (mission->crashed) {
1029  /* default map for crashsite mission is the crashsite random map assembly */
1030  mission->mapDef = cgi->Com_GetMapDefinitionByID("ufocrash");
1031  if (!mission->mapDef)
1032  cgi->Com_Error(ERR_DROP, "Could not find mapdef: ufocrash");
1033  mission->mapDef->timesAlreadyUsed++;
1034  return true;
1035  }
1036 
1037  cgi->Com_Printf("CP_ChooseMap: Could not find map with required conditions:\n");
1038  cgi->Com_Printf(" ufo: %s -- pos: ", mission->ufo ? cgi->Com_UFOTypeToShortName(mission->ufo->getUfoType()) : "none");
1039  if (pos)
1040  cgi->Com_Printf("%s", MapIsWater(GEO_GetColor(pos, MAPTYPE_TERRAIN, nullptr)) ? " (in water) " : "");
1041  if (pos)
1042  cgi->Com_Printf("(%.02f, %.02f)\n", pos[0], pos[1]);
1043  else
1044  cgi->Com_Printf("none\n");
1045  return false;
1046  }
1047 
1048  /* select a map randomly from the selected */
1049  int randomNum = rand() % countMinimal;
1050  md = nullptr;
1052  /* Check if mission fulfill conditions */
1053  if (!CP_MapIsSelectable(mission, md, pos))
1054  continue;
1055  if (md->timesAlreadyUsed > minMapDefAppearance)
1056  continue;
1057  /* There shouldn't be mission fulfilling conditions used less time than minMissionAppearance */
1058  assert(md->timesAlreadyUsed == minMapDefAppearance);
1059 
1060  if (randomNum == 0) {
1061  mission->mapDef = md;
1062  break;
1063  } else {
1064  randomNum--;
1065  }
1066  }
1067 
1068  /* A mission must have been selected */
1069  mission->mapDef->timesAlreadyUsed++;
1070  if (cp_missiontest->integer)
1071  cgi->Com_Printf("Selected map '%s' (among %i possible maps)\n", mission->mapDef->id, countMinimal);
1072  else
1073  cgi->Com_DPrintf(DEBUG_CLIENT, "Selected map '%s' (among %i possible maps)\n", mission->mapDef->id, countMinimal);
1074 
1075  return true;
1076 }
1077 
1083 void CP_MissionStageEnd (const campaign_t* campaign, mission_t* mission)
1084 {
1085  cgi->Com_DPrintf(DEBUG_CLIENT, "Ending mission category %i, stage %i (time: %i day, %i sec)\n",
1086  mission->category, mission->stage, ccs.date.day, ccs.date.sec);
1087 
1088  /* Crash mission is on the map for too long: aliens die or go away. End mission */
1089  if (mission->crashed) {
1090  CP_MissionIsOver(mission);
1091  return;
1092  }
1093 
1094  switch (mission->category) {
1096  CP_ReconMissionNextStage(mission);
1097  break;
1099  CP_TerrorMissionNextStage(mission);
1100  break;
1103  break;
1106  CP_BuildBaseMissionNextStage(campaign, mission);
1107  break;
1109  CP_SupplyMissionNextStage(mission);
1110  break;
1111  case INTERESTCATEGORY_XVI:
1112  CP_XVIMissionNextStage(mission);
1113  break;
1116  CP_InterceptNextStage(mission);
1117  break;
1119  CP_HarvestMissionNextStage(mission);
1120  break;
1122  CP_RescueNextStage(mission);
1123  break;
1125  CP_UFOCarrierNextStage(mission);
1126  break;
1128  case INTERESTCATEGORY_NONE:
1129  case INTERESTCATEGORY_MAX:
1130  cgi->Com_Printf("CP_MissionStageEnd: Invalid type of mission (%i), remove mission '%s'\n", mission->category, mission->id);
1131  CP_MissionRemove(mission);
1132  }
1133 }
1134 
1140 {
1141  switch (mission->category) {
1143  CP_ReconMissionIsFailure(mission);
1144  break;
1146  CP_TerrorMissionIsFailure(mission);
1147  break;
1149  if (mission->stage <= STAGE_BASE_ATTACK)
1151  else
1153  break;
1156  if (mission->stage <= STAGE_BUILD_BASE)
1158  else
1160  break;
1162  if (mission->stage <= STAGE_SUPPLY)
1163  CP_SupplyMissionIsFailure(mission);
1164  else
1165  CP_SupplyMissionIsSuccess(mission);
1166  break;
1167  case INTERESTCATEGORY_XVI:
1168  if (mission->stage <= STAGE_SPREAD_XVI)
1169  CP_XVIMissionIsFailure(mission);
1170  else
1171  CP_XVIMissionIsSuccess(mission);
1172  break;
1175  if (mission->stage <= STAGE_INTERCEPT)
1177  else
1179  break;
1181  CP_HarvestMissionIsFailure(mission);
1182  break;
1185  break;
1187  CP_MissionRemove(mission);
1188  break;
1190  case INTERESTCATEGORY_NONE:
1191  case INTERESTCATEGORY_MAX:
1192  cgi->Com_Printf("CP_MissionIsOver: Invalid type of mission (%i), remove mission\n", mission->category);
1193  CP_MissionRemove(mission);
1194  break;
1195  }
1196 }
1197 
1203 {
1204  assert(ufocraft->mission);
1205  CP_MissionIsOver(ufocraft->mission);
1206 }
1207 
1214 void CP_MissionEndActions (mission_t* mission, aircraft_t* aircraft, bool won)
1215 {
1216  /* handle base attack mission */
1217  if (mission->stage == STAGE_BASE_ATTACK) {
1218  if (won) {
1219  /* fake an aircraft return to collect goods and aliens */
1220  B_DumpAircraftToHomeBase(aircraft);
1221 
1222  Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Defence of base: %s successful!"),
1223  aircraft->homebase->name);
1224  MS_AddNewMessage(_("Notice"), cp_messageBuffer);
1226  } else
1228 
1229  return;
1230  }
1231 
1232  if (mission->category == INTERESTCATEGORY_RESCUE) {
1233  CP_EndRescueMission(mission, aircraft, won);
1234  }
1235 
1236  AIR_AircraftReturnToBase(aircraft);
1237  if (won)
1238  CP_MissionIsOver(mission);
1239 }
1240 
1249 void CP_MissionEnd (const campaign_t* campaign, mission_t* mission, const battleParam_t* battleParameters, bool won)
1250 {
1251  base_t* base;
1252  aircraft_t* aircraft;
1253  int numberOfSoldiers = 0; /* DEBUG */
1254 
1255  if (mission->stage == STAGE_BASE_ATTACK) {
1256  base = mission->data.base;
1257  assert(base);
1258  /* HACK */
1259  aircraft = base->aircraftCurrent;
1260  } else {
1261  aircraft = GEO_GetMissionAircraft();
1262  base = aircraft->homebase;
1263  }
1264 
1265  /* add the looted goods to base storage and market */
1266  base->storage = ccs.eMission;
1267 
1269 
1270  CP_HandleNationData(campaign->minhappiness, mission, battleParameters->nation, &(mission->missionResults), won);
1271  CP_CheckLostCondition(campaign);
1272 
1273  /* update the character stats */
1275  cgi->LIST_Delete(&ccs.updateCharacters);
1276 
1277  /* update stats */
1278  CHAR_UpdateStats(base, aircraft);
1279 
1280  E_Foreach(EMPL_SOLDIER, employee) {
1281  if (AIR_IsEmployeeInAircraft(employee, aircraft))
1282  numberOfSoldiers++;
1283 
1285  if (employee->isHiredInBase(base) && (employee->chr.HP <= 0))
1286  E_DeleteEmployee(employee);
1287  }
1288  cgi->Com_DPrintf(DEBUG_CLIENT, "CP_MissionEnd - num %i\n", numberOfSoldiers);
1289 
1290  CP_ExecuteMissionTrigger(mission, won);
1291  CP_MissionEndActions(mission, aircraft, won);
1292 }
1293 
1301 bool CP_CheckNextStageDestination (const campaign_t* campaign, aircraft_t* ufocraft)
1302 {
1303  mission_t* mission;
1304 
1305  mission = ufocraft->mission;
1306  assert(mission);
1307 
1308  switch (mission->stage) {
1309  case STAGE_COME_FROM_ORBIT:
1310  case STAGE_MISSION_GOTO:
1311  CP_MissionStageEnd(campaign, mission);
1312  return false;
1313  case STAGE_RETURN_TO_ORBIT:
1314  CP_MissionStageEnd(campaign, mission);
1315  return true;
1316  default:
1317  /* Do nothing */
1318  return false;
1319  }
1320 }
1321 
1327 void CP_UFOProceedMission (const campaign_t* campaign, aircraft_t* ufo)
1328 {
1329  /* Every UFO on geoscape must have a mission assigned */
1330  assert(ufo->mission);
1331 
1333  const int slotIndex = AIRFIGHT_ChooseWeapon(ufo->weapons, ufo->maxWeapons, ufo->pos, ufo->pos);
1334  /* This is an Intercept mission where UFO attacks aircraft (not installations) */
1335  /* Keep on looking targets until mission is over, unless no more ammo */
1336  ufo->status = AIR_TRANSIT;
1337  if (slotIndex != AIRFIGHT_WEAPON_CAN_NEVER_SHOOT)
1338  UFO_SetRandomDest(ufo);
1339  else
1340  CP_MissionStageEnd(campaign, ufo->mission);
1341  } else if (ufo->mission->stage < STAGE_MISSION_GOTO ||
1342  ufo->mission->stage >= STAGE_RETURN_TO_ORBIT) {
1343  UFO_SetRandomDest(ufo);
1344  } else {
1345  UFO_SendToDestination(ufo, ufo->mission->pos);
1346  }
1347 }
1348 
1354 {
1355  const date_t minCrashDelay = {7, 0};
1356  /* How long the crash mission will stay before aliens leave / die */
1357  const date_t crashDelay = {14, 0};
1358  mission_t* mission;
1359 
1360  mission = ufo->mission;
1361  if (!mission)
1362  cgi->Com_Error(ERR_DROP, "CP_SpawnCrashSiteMission: No mission correspond to ufo '%s'", ufo->id);
1363 
1364  mission->crashed = true;
1365 
1366  /* Reset mapDef. CP_ChooseMap don't overwrite if set */
1367  mission->mapDef = nullptr;
1368  if (!CP_ChooseMap(mission, ufo->pos)) {
1369  cgi->Com_Printf("CP_SpawnCrashSiteMission: No map found, remove mission.\n");
1370  CP_MissionRemove(mission);
1371  return;
1372  }
1373 
1374  Vector2Copy(ufo->pos, mission->pos);
1375  mission->posAssigned = true;
1376 
1377  mission->finalDate = Date_Add(ccs.date, Date_Random(minCrashDelay, crashDelay));
1378  /* ufo becomes invisible on geoscape, but don't remove it from ufo global array
1379  * (may be used to know what items are collected from battlefield)*/
1380  CP_UFORemoveFromGeoscape(mission, false);
1381  /* mission appear on geoscape, player can go there */
1382  CP_MissionAddToGeoscape(mission, false);
1383 }
1384 
1385 
1395 {
1396  mission_t* mission;
1397  mission_t* oldMission;
1398  int survivors = 0;
1399 
1400  /* Handle events about crash */
1401  /* Do this first, if noone survived the crash => no mission to spawn */
1402 
1403  bool pilotSurvived = AIR_PilotSurvivedCrash(aircraft);
1404  if (!pilotSurvived) {
1405  Employee* pilot = AIR_GetPilot(aircraft);
1407  E_DeleteEmployee(pilot);
1408  }
1409 
1410  LIST_Foreach(aircraft->acTeam, Employee, employee) {
1411 #if 0
1412  const character_t* chr = &employee->chr;
1413  const chrScoreGlobal_t* score = &chr->score;
1415  E_DeleteEmployee(employee);
1416 #else
1417  (void)employee;
1418 #endif
1419  survivors++;
1420  }
1421 
1422  aircraft->status = AIR_CRASHED;
1423 
1424  /* after we set this to AIR_CRASHED we can get the next 'valid'
1425  * aircraft to correct the pointer in the homebase */
1426  if (aircraft->homebase->aircraftCurrent == aircraft)
1427  aircraft->homebase->aircraftCurrent = AIR_GetFirstFromBase(aircraft->homebase);
1428 
1429  /* a crashed aircraft is no longer using capacity of the hangars */
1430  const baseCapacities_t capType = AIR_GetHangarCapacityType(aircraft);
1431  if (capType != MAX_CAP)
1432  CAP_AddCurrent(aircraft->homebase, capType, -1);
1433 
1434  if (GEO_IsAircraftSelected(aircraft))
1435  GEO_SetSelectedAircraft(nullptr);
1436 
1437  /* Check if ufo was destroyed too */
1438  if (!ufo) {
1439  cgi->Com_Printf("CP_SpawnRescueMission: UFO was also destroyed.\n");
1441  AIR_DestroyAircraft(aircraft, pilotSurvived);
1442  return;
1443  }
1444 
1445  if (survivors == 0) {
1446  AIR_DestroyAircraft(aircraft, pilotSurvived);
1447  return;
1448  }
1449 
1450  /* create the mission */
1452  if (!mission)
1453  cgi->Com_Error(ERR_DROP, "CP_SpawnRescueMission: mission could not be created");
1454 
1455  /* Reset mapDef. CP_ChooseMap don't overwrite if set */
1456  mission->mapDef = nullptr;
1457  if (!CP_ChooseMap(mission, aircraft->pos)) {
1458  cgi->Com_Printf("CP_SpawnRescueMission: Cannot set mapDef for mission %s, removing.\n", mission->id);
1459  CP_MissionRemove(mission);
1460  return;
1461  }
1462 
1463  mission->data.aircraft = aircraft;
1464 
1465  /* UFO drops it's previous mission and goes for the crashed aircraft */
1466  oldMission = ufo->mission;
1467  oldMission->ufo = nullptr;
1468  ufo->mission = mission;
1469  CP_MissionRemove(oldMission);
1470 
1471  mission->ufo = ufo;
1472  mission->stage = STAGE_MISSION_GOTO;
1473  Vector2Copy(aircraft->pos, mission->pos);
1474 
1475  /* Stage will finish when UFO arrives at destination */
1476  CP_MissionDisableTimeLimit(mission);
1477 }
1478 
1479 /*====================================
1480 *
1481 * Spawn new missions
1482 *
1483 ====================================*/
1484 
1489 static bool MIS_IsSpawnedFromGround (const mission_t* mission)
1490 {
1491  assert(mission);
1492 
1493  switch (mission->category) {
1494  /* missions can't be spawned from ground */
1501  return false;
1502  /* missions can be spawned from ground */
1506  case INTERESTCATEGORY_XVI:
1507  break;
1508  /* missions not spawned this way */
1512  case INTERESTCATEGORY_NONE:
1513  case INTERESTCATEGORY_MAX:
1514  cgi->Com_Error(ERR_DROP, "MIS_IsSpawnedFromGround: Wrong mission category %i", mission->category);
1515  }
1516 
1517  /* Roll the random number */
1518  const float XVI_PARAM = 10.0f;
1519  float groundProbability;
1520  float randNumber = frand();
1521 
1522  /* The higher the XVI rate, the higher the probability to have a mission spawned from ground */
1523  groundProbability = 1.0f - exp(-CP_GetAverageXVIRate() / XVI_PARAM);
1524  groundProbability = std::max(0.1f, groundProbability);
1525 
1526  return randNumber < groundProbability;
1527 }
1528 
1537 {
1538  mission->stage = STAGE_COME_FROM_ORBIT;
1539 
1540  if (MIS_IsSpawnedFromGround(mission)) {
1541  mission->ufo = nullptr;
1542  /* Mission starts from ground: no UFO. Go to next stage on next frame (skip UFO arrives on earth) */
1543  mission->finalDate = ccs.date;
1544  } else {
1545  ufoType_t ufoType = CP_MissionChooseUFO(mission);
1546  if (ufoType == UFO_NONE) {
1547  CP_MissionRemove(mission);
1548  return false;
1549  }
1550  mission->ufo = UFO_AddToGeoscape(ufoType, nullptr, mission);
1551  if (!mission->ufo) {
1552  cgi->Com_Printf("CP_MissionBegin: Could not add UFO '%s', remove mission %s\n",
1553  cgi->Com_UFOTypeToShortName(ufoType), mission->id);
1554  CP_MissionRemove(mission);
1555  return false;
1556  }
1557  /* Stage will finish when UFO arrives at destination */
1558  CP_MissionDisableTimeLimit(mission);
1559  }
1560 
1561  mission->idx = ++ccs.campaignStats.missions;
1562  return true;
1563 }
1564 
1573 {
1574  ufoType_t ufoTypes[UFO_MAX];
1575  int numTypes = 0;
1576 
1577  switch (mission->category) {
1579  numTypes = UFO_GetAvailableUFOsForMission(mission->category, ufoTypes);
1580  break;
1582  numTypes = UFO_GetAvailableUFOsForMission(mission->category, ufoTypes);
1583  break;
1585  numTypes = UFO_GetAvailableUFOsForMission(mission->category, ufoTypes);
1586  break;
1590  /* This is a subverting government mission */
1592  } else {
1593  /* This is a Building base mission */
1595  }
1596  break;
1598  numTypes = UFO_GetAvailableUFOsForMission(mission->category, ufoTypes);
1599  break;
1600  case INTERESTCATEGORY_XVI:
1601  numTypes = UFO_GetAvailableUFOsForMission(mission->category, ufoTypes);
1602  break;
1605  numTypes = UFO_GetAvailableUFOsForMission(mission->category, ufoTypes);
1606  break;
1608  numTypes = UFO_GetAvailableUFOsForMission(mission->category, ufoTypes);
1609  break;
1611  /* can't be spawned: alien base is the result of base building mission */
1614  case INTERESTCATEGORY_NONE:
1615  case INTERESTCATEGORY_MAX:
1616  cgi->Com_Error(ERR_DROP, "CP_MissionChooseUFO: Wrong mission category %i", mission->category);
1617  }
1618 
1619  const short ufoIdsNum = cgi->Com_GetUFOIdsNum();
1620  if (numTypes > ufoIdsNum)
1621  cgi->Com_Error(ERR_DROP, "CP_MissionChooseUFO: Too many values UFOs (%i/%i)", numTypes, ufoIdsNum);
1622 
1623  if (numTypes <= 0)
1624  return UFO_NONE;
1625 
1626  /* Roll the random number */
1627  const float randNumber = frand();
1628 
1629  /* If we reached this point, then mission will be spawned from space: choose UFO */
1630  int idx = (int) (numTypes * randNumber);
1631  if (idx >= numTypes) {
1632  idx = numTypes -1;
1633  }
1634 
1635  return ufoTypes[idx];
1636 }
1637 
1644 static inline void CP_SetMissionName (mission_t* mission)
1645 {
1646  int num = 0;
1647 
1648  do {
1649  Com_sprintf(mission->id, sizeof(mission->id), "cat%i_interest%i_%i",
1650  mission->category, mission->initialOverallInterest, num);
1651 
1652  /* if mission list is empty, the id is unique for sure */
1653  if (cgi->LIST_IsEmpty(ccs.missions))
1654  return;
1655 
1656  /* check whether a mission with the same id already exists in the list
1657  * if so, generate a new name by using an increased num values - otherwise
1658  * just use the mission->id we just stored - it should be unique now */
1659  if (!CP_GetMissionByIDSilent(mission->id))
1660  break;
1661 
1662  num++;
1663  } while (num); /* fake condition */
1664 }
1665 
1674 {
1675  mission_t mission;
1676  const date_t minNextSpawningDate = {0, 0};
1677  const date_t nextSpawningDate = {3, 0}; /* Delay between 2 mission spawning */
1678 
1679  /* Some event are non-occurrence */
1680  if (category <= INTERESTCATEGORY_NONE || category >= INTERESTCATEGORY_MAX)
1681  return nullptr;
1682 
1683  OBJZERO(mission);
1684 
1685  /* First fill common datas between all type of missions */
1686  mission.category = category;
1688  mission.initialIndividualInterest = ccs.interest[category];
1689  mission.stage = STAGE_NOT_ACTIVE;
1690  mission.ufo = nullptr;
1691  if (beginNow) {
1692  mission.startDate.day = ccs.date.day;
1693  mission.startDate.sec = ccs.date.sec;
1694  } else
1695  mission.startDate = Date_Add(ccs.date, Date_Random(minNextSpawningDate, nextSpawningDate));
1696  mission.finalDate = mission.startDate;
1697  mission.idx = ++ccs.campaignStats.missions;
1698 
1699  CP_SetMissionName(&mission);
1700 
1701  /* Handle mission specific, spawn-time routines */
1702  if (mission.category == INTERESTCATEGORY_BUILDING)
1704  else if (mission.category == INTERESTCATEGORY_BASE_ATTACK)
1706  else if (mission.category == INTERESTCATEGORY_TERROR_ATTACK)
1708 
1709  /* Add mission to global array */
1710  return &LIST_Add(&ccs.missions, mission);
1711 }
1712 
1718 {
1719  int sum = 0;
1720  int i, randomNumber;
1721 
1722  for (i = 0; i < INTERESTCATEGORY_MAX; i++)
1723  sum += ccs.interest[i];
1724 
1725  randomNumber = (int) (frand() * (float) sum);
1726 
1727  for (i = 0; randomNumber >= 0; i++)
1728  randomNumber -= ccs.interest[i];
1729 
1730  return (interestCategory_t)(i - 1);
1731 }
1732 
1739 {
1740  int spawn_delay = DELAY_BETWEEN_MISSION_SPAWNING;
1742 
1743  /* Halve the spawn delay in the early game so players see UFOs and get right into action */
1745  spawn_delay = (int) (spawn_delay / 3);
1746  }
1747 
1748  if (ccs.lastMissionSpawnedDelay > spawn_delay) {
1749  float nonOccurrence;
1750  /* Select the amount of missions that will be spawned in the next cycle. */
1751 
1752  /* Each mission has a certain probability to not occur. This provides some randomness to the mission density.
1753  * However, once the campaign passes a certain point, this effect rapidly diminishes. This means that by the
1754  * end of the game, ALL missions will spawn, quickly overrunning the player. */
1756  nonOccurrence = ccs.curCampaign->ufoReductionRate / pow(((ccs.overallInterest - FINAL_OVERALL_INTEREST / 30) + 1.0f), 2);
1757  else
1758  nonOccurrence = ccs.curCampaign->ufoReductionRate;
1759 
1760  /* Increase the alien's interest in supplying their bases for this cycle.
1761  * The more bases, the greater their interest in supplying them. */
1763 
1764  /* Calculate the amount of missions to be spawned this cycle.
1765  * Note: This is a function over css.overallInterest. It looks like this:
1766  * http://www.wolframalpha.com/input/?i=Plot%5B40%2B%285-40%29%2A%28%28x-1000%29%2F%2820-1000%29%29%5E2%2C+%7Bx%2C+0%2C+1100%7D%5D
1767  */
1769  cgi->Com_DPrintf(DEBUG_CLIENT, "interest = %d, new missions = %d\n", ccs.overallInterest, newMissionNum);
1770  for (int i = 0; i < newMissionNum; i++) {
1771  if (frand() > nonOccurrence) {
1773  CP_CreateNewMission(type, false);
1774  }
1775  }
1776 
1777  ccs.lastMissionSpawnedDelay -= spawn_delay;
1778  }
1779 }
1780 
1787 {
1789 
1791 }
1792 
1793 
1794 /*====================================
1795 *
1796 * Debug functions
1797 *
1798 ====================================*/
1799 
1800 #ifdef DEBUG
1801 
1804 static void MIS_SpawnNewMissions_f (void)
1805 {
1806  interestCategory_t category;
1807  int type = 0;
1808 
1809  if (cgi->Cmd_Argc() < 2) {
1810  cgi->Com_Printf("Usage: %s <category> [<type>]\n", cgi->Cmd_Argv(0));
1811  for (int i = INTERESTCATEGORY_RECON; i < INTERESTCATEGORY_MAX; i++) {
1812  category = (interestCategory_t)i;
1813  cgi->Com_Printf("...%i: %s", category, INT_InterestCategoryToName(category));
1814  if (category == INTERESTCATEGORY_RECON)
1815  cgi->Com_Printf(" <0:Random, 1:Aerial, 2:Ground>");
1816  else if (category == INTERESTCATEGORY_BUILDING)
1817  cgi->Com_Printf(" <0:Subverse Government, 1:Build Base>");
1818  else if (category == INTERESTCATEGORY_INTERCEPT)
1819  cgi->Com_Printf(" <0:Intercept aircraft, 1:Attack installation>");
1820  cgi->Com_Printf("\n");
1821  }
1822  return;
1823  }
1824 
1825  if (cgi->Cmd_Argc() >= 3)
1826  type = atoi(cgi->Cmd_Argv(2));
1827 
1828  category = (interestCategory_t)atoi(cgi->Cmd_Argv(1));
1829 
1830  if (category == INTERESTCATEGORY_MAX)
1831  return;
1832 
1833  if (category == INTERESTCATEGORY_ALIENBASE) {
1834  /* spawning an alien base is special */
1835  vec2_t pos;
1836  alienBase_t* base;
1837  AB_SetAlienBasePosition(pos); /* get base position */
1838  base = AB_BuildBase(pos); /* build base */
1839  if (!base) {
1840  cgi->Com_Printf("CP_BuildBaseSetUpBase: could not create base\n");
1841  return;
1842  }
1843  CP_SpawnAlienBaseMission(base); /* make base visible */
1844  return;
1845  } else if (category == INTERESTCATEGORY_RESCUE) {
1846  const base_t* base = B_GetFoundedBaseByIDX(0);
1847  aircraft_t* aircraft;
1848  if (!base) {
1849  cgi->Com_Printf("No base yet\n");
1850  return;
1851  }
1852 
1853  aircraft = AIR_GetFirstFromBase(base);
1854  if (!aircraft) {
1855  cgi->Com_Printf("No aircraft in base\n");
1856  return;
1857  }
1858  CP_SpawnRescueMission(aircraft, nullptr);
1859  return;
1860  }
1861 
1862  mission_t* mission = CP_CreateNewMission(category, true);
1863  if (!mission) {
1864  cgi->Com_Printf("CP_SpawnNewMissions_f: Could not add mission, abort\n");
1865  return;
1866  }
1867 
1868  if (type) {
1869  switch (category) {
1871  /* Start mission */
1872  if (!CP_MissionBegin(mission))
1873  return;
1874  if (type == 1 && mission->ufo)
1875  /* Aerial mission */
1876  CP_ReconMissionAerial(mission);
1877  else
1878  /* This is a ground mission */
1879  CP_ReconMissionGroundGo(mission);
1880  break;
1882  if (type == 1)
1884  break;
1886  /* Start mission */
1887  if (!CP_MissionBegin(mission))
1888  return;
1889  if (type == 1) {
1890  ufoType_t ufoType = UFO_GetOneAvailableUFOForMission(INTERESTCATEGORY_INTERCEPTBOMBING); /* the first one will do */
1891  mission->ufo->setUfoType(ufoType);
1893  } else {
1895  }
1896  break;
1897  default:
1898  cgi->Com_Printf("Type is not implemented for this category.\n");
1899  }
1900  }
1901  cgi->Com_Printf("Spawned mission with id '%s'\n", mission->id);
1902 }
1903 
1907 static void MIS_MissionSetMap_f (void)
1908 {
1909  mapDef_t* mapDef;
1910  mission_t* mission;
1911  if (cgi->Cmd_Argc() < 3) {
1912  cgi->Com_Printf("Usage: %s <missionid> <mapdef>\n", cgi->Cmd_Argv(0));
1913  return;
1914  }
1915  mission = CP_GetMissionByID(cgi->Cmd_Argv(1));
1916  mapDef = cgi->Com_GetMapDefinitionByID(cgi->Cmd_Argv(2));
1917  if (mapDef == nullptr) {
1918  cgi->Com_Printf("Could not find mapdef for %s\n", cgi->Cmd_Argv(2));
1919  return;
1920  }
1921  mission->mapDef = mapDef;
1922 }
1923 
1928 static void MIS_MissionList_f (void)
1929 {
1930  bool noMission = true;
1931 
1932  MIS_Foreach(mission) {
1933  cgi->Com_Printf("mission: '%s'\n", mission->id);
1934  cgi->Com_Printf("...category %i. '%s' -- stage %i. '%s'\n", mission->category,
1935  INT_InterestCategoryToName(mission->category), mission->stage, CP_MissionStageToName(mission->stage));
1936  cgi->Com_Printf("...mapDef: '%s'\n", mission->mapDef ? mission->mapDef->id : "No mapDef defined");
1937  cgi->Com_Printf("...start (day = %i, sec = %i), ends (day = %i, sec = %i)\n",
1938  mission->startDate.day, mission->startDate.sec, mission->finalDate.day, mission->finalDate.sec);
1939  cgi->Com_Printf("...pos (%.02f, %.02f)%s -- mission %son Geoscape\n", mission->pos[0], mission->pos[1], mission->posAssigned ? "(assigned Pos)" : "", mission->onGeoscape ? "" : "not ");
1940  if (mission->ufo)
1941  cgi->Com_Printf("...UFO: %s (%i/%i)\n", mission->ufo->id, (int) (mission->ufo - ccs.ufos), ccs.numUFOs - 1);
1942  else
1943  cgi->Com_Printf("...UFO: no UFO\n");
1944  noMission = false;
1945  }
1946  if (noMission)
1947  cgi->Com_Printf("No mission currently in game.\n");
1948 }
1949 
1954 static void MIS_DeleteMissions_f (void)
1955 {
1956  MIS_Foreach(mission) {
1957  CP_MissionRemove(mission);
1958  }
1959 
1960  if (ccs.numUFOs != 0) {
1961  cgi->Com_Printf("CP_DeleteMissions_f: Error, there are still %i UFO in game afer removing all missions. Force removal.\n", ccs.numUFOs);
1962  while (ccs.numUFOs)
1964  }
1965 }
1966 
1971 static void MIS_DeleteMission_f (void)
1972 {
1973  mission_t* mission;
1974 
1975  if (cgi->Cmd_Argc() < 2) {
1976  cgi->Com_Printf("Usage: %s <missionid>\n", cgi->Cmd_Argv(0));
1977  return;
1978  }
1979  mission = CP_GetMissionByID(cgi->Cmd_Argv(1));
1980 
1981  if (!mission)
1982  return;
1983 
1984  CP_MissionRemove(mission);
1985 }
1986 #endif
1987 
1992 bool MIS_SaveXML (xmlNode_t* parent)
1993 {
1994  xmlNode_t* missionsNode = cgi->XML_AddNode(parent, SAVE_MISSIONS);
1995 
1996  cgi->Com_RegisterConstList(saveInterestConstants);
1997  cgi->Com_RegisterConstList(saveMissionConstants);
1998  MIS_Foreach(mission) {
1999  xmlNode_t* missionNode = cgi->XML_AddNode(missionsNode, SAVE_MISSIONS_MISSION);
2000 
2001  cgi->XML_AddInt(missionNode, SAVE_MISSIONS_MISSION_IDX, mission->idx);
2002  cgi->XML_AddString(missionNode, SAVE_MISSIONS_ID, mission->id);
2003  if (mission->mapDef)
2004  cgi->XML_AddString(missionNode, SAVE_MISSIONS_MAPDEF_ID, mission->mapDef->id);
2005  cgi->XML_AddBool(missionNode, SAVE_MISSIONS_ACTIVE, mission->active);
2006  cgi->XML_AddBool(missionNode, SAVE_MISSIONS_POSASSIGNED, mission->posAssigned);
2007  cgi->XML_AddBool(missionNode, SAVE_MISSIONS_CRASHED, mission->crashed);
2008  cgi->XML_AddString(missionNode, SAVE_MISSIONS_ONWIN, mission->onwin);
2009  cgi->XML_AddString(missionNode, SAVE_MISSIONS_ONLOSE, mission->onlose);
2010  cgi->XML_AddString(missionNode, SAVE_MISSIONS_CATEGORY, cgi->Com_GetConstVariable(SAVE_INTERESTCAT_NAMESPACE, mission->category));
2011  cgi->XML_AddString(missionNode, SAVE_MISSIONS_STAGE, cgi->Com_GetConstVariable(SAVE_MISSIONSTAGE_NAMESPACE, mission->stage));
2012  switch (mission->category) {
2014  if (mission->stage == STAGE_MISSION_GOTO || mission->stage == STAGE_BASE_ATTACK) {
2015  const base_t* base = mission->data.base;
2016  /* save IDX of base under attack if required */
2017  cgi->XML_AddShort(missionNode, SAVE_MISSIONS_BASEINDEX, base->idx);
2018  }
2019  break;
2021  if (mission->stage == STAGE_MISSION_GOTO || mission->stage == STAGE_INTERCEPT) {
2022  const installation_t* installation = mission->data.installation;
2023  if (installation)
2024  cgi->XML_AddShort(missionNode, SAVE_MISSIONS_INSTALLATIONINDEX, installation->idx);
2025  }
2026  break;
2028  {
2029  const aircraft_t* aircraft = mission->data.aircraft;
2030  cgi->XML_AddShort(missionNode, SAVE_MISSIONS_CRASHED_AIRCRAFT, aircraft->idx);
2031  }
2032  break;
2036  {
2037  /* save IDX of alien base if required */
2038  const alienBase_t* base = mission->data.alienBase;
2039  /* there may be no base is the mission is a subverting government */
2040  if (base)
2041  cgi->XML_AddShort(missionNode, SAVE_MISSIONS_ALIENBASEINDEX, base->idx);
2042  }
2043  break;
2044  default:
2045  break;
2046  }
2047  cgi->XML_AddShort(missionNode, SAVE_MISSIONS_INITIALOVERALLINTEREST, mission->initialOverallInterest);
2048  cgi->XML_AddShort(missionNode, SAVE_MISSIONS_INITIALINDIVIDUALINTEREST, mission->initialIndividualInterest);
2049  cgi->XML_AddDate(missionNode, SAVE_MISSIONS_STARTDATE, mission->startDate.day, mission->startDate.sec);
2050  cgi->XML_AddDate(missionNode, SAVE_MISSIONS_FINALDATE, mission->finalDate.day, mission->finalDate.sec);
2051  cgi->XML_AddPos2(missionNode, SAVE_MISSIONS_POS, mission->pos);
2052  cgi->XML_AddBoolValue(missionNode, SAVE_MISSIONS_ONGEOSCAPE, mission->onGeoscape);
2053  }
2054  cgi->Com_UnregisterConstList(saveInterestConstants);
2055  cgi->Com_UnregisterConstList(saveMissionConstants);
2056 
2057  return true;
2058 }
2059 
2064 bool MIS_LoadXML (xmlNode_t* parent)
2065 {
2066  xmlNode_t* missionNode;
2067  xmlNode_t* node;
2068 
2069  cgi->Com_RegisterConstList(saveInterestConstants);
2070  cgi->Com_RegisterConstList(saveMissionConstants);
2071  missionNode = cgi->XML_GetNode(parent, SAVE_MISSIONS);
2072  for (node = cgi->XML_GetNode(missionNode, SAVE_MISSIONS_MISSION); node;
2073  node = cgi->XML_GetNextNode(node, missionNode, SAVE_MISSIONS_MISSION)) {
2074  const char* name;
2075  mission_t mission;
2076  bool defaultAssigned = false;
2077  const char* categoryId = cgi->XML_GetString(node, SAVE_MISSIONS_CATEGORY);
2078  const char* stageId = cgi->XML_GetString(node, SAVE_MISSIONS_STAGE);
2079 
2080  OBJZERO(mission);
2081 
2082  Q_strncpyz(mission.id, cgi->XML_GetString(node, SAVE_MISSIONS_ID), sizeof(mission.id));
2083  mission.idx = cgi->XML_GetInt(node, SAVE_MISSIONS_MISSION_IDX, 0);
2084  if (mission.idx <= 0) {
2085  cgi->Com_Printf("mission has invalid or no index\n");
2086  continue;
2087  }
2088 
2089  name = cgi->XML_GetString(node, SAVE_MISSIONS_MAPDEF_ID);
2090  if (name && name[0] != '\0') {
2091  mission.mapDef = cgi->Com_GetMapDefinitionByID(name);
2092  if (!mission.mapDef) {
2093  cgi->Com_Printf("Warning: mapdef \"%s\" for mission \"%s\" doesn't exist. Removing mission!\n", name, mission.id);
2094  continue;
2095  }
2096  } else {
2097  mission.mapDef = nullptr;
2098  }
2099 
2100  if (!cgi->Com_GetConstIntFromNamespace(SAVE_INTERESTCAT_NAMESPACE, categoryId, (int*) &mission.category)) {
2101  cgi->Com_Printf("Invalid mission category '%s'\n", categoryId);
2102  continue;
2103  }
2104 
2105  if (!cgi->Com_GetConstIntFromNamespace(SAVE_MISSIONSTAGE_NAMESPACE, stageId, (int*) &mission.stage)) {
2106  cgi->Com_Printf("Invalid mission stage '%s'\n", stageId);
2107  continue;
2108  }
2109 
2110  mission.active = cgi->XML_GetBool(node, SAVE_MISSIONS_ACTIVE, false);
2111  Q_strncpyz(mission.onwin, cgi->XML_GetString(node, SAVE_MISSIONS_ONWIN), sizeof(mission.onwin));
2112  Q_strncpyz(mission.onlose, cgi->XML_GetString(node, SAVE_MISSIONS_ONLOSE), sizeof(mission.onlose));
2113 
2114  mission.initialOverallInterest = cgi->XML_GetInt(node, SAVE_MISSIONS_INITIALOVERALLINTEREST, 0);
2116 
2117  cgi->XML_GetPos2(node, SAVE_MISSIONS_POS, mission.pos);
2118 
2119  switch (mission.category) {
2121  if (mission.stage == STAGE_MISSION_GOTO || mission.stage == STAGE_BASE_ATTACK) {
2122  /* Load IDX of base under attack */
2123  base_t* base = B_GetBaseByIDX(cgi->XML_GetInt(node, SAVE_MISSIONS_BASEINDEX, -1));
2124  if (base) {
2125  if (mission.stage == STAGE_BASE_ATTACK && !B_IsUnderAttack(base))
2126  cgi->Com_Printf("......warning: base %i (%s) is supposedly under attack but base status doesn't match!\n", base->idx, base->name);
2127  mission.data.base = base;
2128  } else
2129  cgi->Com_Printf("......warning: Missing BaseIndex\n");
2130  }
2131  break;
2133  if (mission.stage == STAGE_MISSION_GOTO || mission.stage == STAGE_INTERCEPT) {
2134  installation_t* installation = INS_GetByIDX(cgi->XML_GetInt(node, SAVE_MISSIONS_INSTALLATIONINDEX, -1));
2135  if (installation)
2136  mission.data.installation = installation;
2137  else {
2138  cgi->Com_Printf("Mission on non-existent installation\n");
2139  continue;
2140  }
2141  }
2142  break;
2144  {
2145  const int aircraftIdx = cgi->XML_GetInt(node, SAVE_MISSIONS_CRASHED_AIRCRAFT, -1);
2146  mission.data.aircraft = AIR_AircraftGetFromIDX(aircraftIdx);
2147  if (mission.data.aircraft == nullptr) {
2148  cgi->Com_Printf("Error while loading rescue mission (missionidx %i, aircraftidx: %i, category: %i, stage: %i)\n",
2149  mission.idx, aircraftIdx, mission.category, mission.stage);
2150  continue;
2151  }
2152  }
2153  break;
2155  if (mission.stage == STAGE_MISSION_GOTO || mission.stage == STAGE_TERROR_MISSION)
2156  mission.data.city = CITY_GetByPos(mission.pos);
2157  break;
2161  {
2162  int baseIdx = cgi->XML_GetInt(node, SAVE_MISSIONS_ALIENBASEINDEX, -1);
2163  alienBase_t* alienBase = AB_GetByIDX(baseIdx);
2164  if (alienBase)
2165  mission.data.alienBase = alienBase;
2166  if (!mission.data.alienBase && !CP_BasemissionIsSubvertingGovernmentMission(&mission) && mission.stage >= STAGE_BUILD_BASE) {
2167  cgi->Com_Printf("Error loading Alien Base mission (missionidx %i, baseidx: %i, category: %i, stage: %i): no such base\n",
2168  mission.idx, baseIdx, mission.category, mission.stage);
2169  continue;
2170  }
2171  }
2172  break;
2173  default:
2174  break;
2175  }
2176 
2177  cgi->XML_GetDate(node, SAVE_MISSIONS_STARTDATE, &mission.startDate.day, &mission.startDate.sec);
2178  cgi->XML_GetDate(node, SAVE_MISSIONS_FINALDATE, &mission.finalDate.day, &mission.finalDate.sec);
2179  cgi->XML_GetPos2(node, SAVE_MISSIONS_POS, mission.pos);
2180 
2181  mission.crashed = cgi->XML_GetBool(node, SAVE_MISSIONS_CRASHED, false);
2182  mission.onGeoscape = cgi->XML_GetBool(node, SAVE_MISSIONS_ONGEOSCAPE, false);
2183 
2184  if (mission.pos[0] > 0.001 || mission.pos[1] > 0.001)
2185  defaultAssigned = true;
2186  mission.posAssigned = cgi->XML_GetBool(node, SAVE_MISSIONS_POSASSIGNED, defaultAssigned);
2187  /* Add mission to global array */
2188  LIST_Add(&ccs.missions, mission);
2189  }
2190  cgi->Com_UnregisterConstList(saveInterestConstants);
2191  cgi->Com_UnregisterConstList(saveMissionConstants);
2192 
2193  return true;
2194 }
2195 
2196 static const cmdList_t debugMissionCmds[] = {
2197 #ifdef DEBUG
2198  {"debug_missionsetmap", MIS_MissionSetMap_f, "Changes the map for a spawned mission"},
2199  {"debug_missionadd", MIS_SpawnNewMissions_f, "Add a new mission"},
2200  {"debug_missiondeleteall", MIS_DeleteMissions_f, "Remove all missions from global array"},
2201  {"debug_missiondelete", MIS_DeleteMission_f, "Remove mission by a given name"},
2202  {"debug_missionlist", MIS_MissionList_f, "Debug function to show all missions"},
2203 #endif
2204  {nullptr, nullptr, nullptr}
2205 };
2210 void MIS_InitStartup (void)
2211 {
2213  cgi->Cmd_TableAddList(debugMissionCmds);
2214 }
2215 
2219 void MIS_Shutdown (void)
2220 {
2221  cgi->LIST_Delete(&ccs.missions);
2222 
2224  cgi->Cmd_TableRemoveList(debugMissionCmds);
2225 }
void AIR_AircraftsNotifyUFORemoved(const aircraft_t *const ufo, bool destroyed)
Notify that a UFO has been removed.
static const float MAX_CRASHEDUFO_CONDITION
Definition: cp_missions.cpp:65
bool crashed
Definition: cp_missions.h:107
aircraft_t ufos[MAX_UFOONGEOSCAPE]
Definition: cp_campaign.h:354
int CP_GetAverageXVIRate(void)
Return the average XVI rate.
Definition: cp_xvi.cpp:163
void GEO_UpdateGeoscapeDock(void)
Will add missions and UFOs to the geoscape dock panel.
alienTeamCategory_t alienCategories[ALIENCATEGORY_MAX]
Definition: cp_campaign.h:317
void CP_TerrorMissionNextStage(mission_t *mission)
Determine what action should be performed when a Terror attack mission stage ends.
bool CP_CheckNewMissionDetectedOnGeoscape(void)
Check if mission has been detected by radar.
#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
void CP_BuildBaseMissionOnSpawn(void)
Run when the mission is spawned.
linkedList_t * terrains
Definition: q_shared.h:486
#define GEO_SetSelectedAircraft(aircraft)
Definition: cp_geoscape.h:62
int numEDs
Definition: q_shared.h:541
void CP_InterceptMissionIsFailure(mission_t *mission)
Intercept mission is over and is a failure: change interest values.
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
chrScoreGlobal_t score
Definition: chr_shared.h:387
alien team category definition
Definition: cp_campaign.h:124
Nation definition.
Definition: cp_nation.h:44
void MIS_Shutdown(void)
Closing actions for missions-subsystem.
Header file for character (soldier, alien) related campaign functions.
Campaign mission headers.
A installation with all it's data.
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
bool CP_CheckMissionLimitedInTime(const mission_t *mission)
Check if mission should end because of limited time.
bool CP_CheckNextStageDestination(const campaign_t *campaign, aircraft_t *ufocraft)
Check if a stage mission is over when UFO reached destination.
static const constListEntry_t saveInterestConstants[]
Definition: save_interest.h:38
void CP_MissionStageEnd(const campaign_t *campaign, mission_t *mission)
Determine what action should be performed when a mission stage ends.
#define DELAY_BETWEEN_MISSION_SPAWNING
The length of a single mission spawn cycle.
Definition: cp_campaign.h:77
char * id
Definition: cp_aircraft.h:119
bool CP_ChooseMap(mission_t *mission, const vec2_t pos)
Choose a map for given mission.
int numAlienCategories
Definition: cp_campaign.h:318
#define SAVE_INTERESTCAT_NAMESPACE
Definition: save_interest.h:37
missionSpawnFunction_t missionSpawnCallback
Definition: cp_campaign.h:386
char * id
Definition: q_shared.h:463
void CP_InterceptNextStage(mission_t *mission)
Determine what action should be performed when a Intercept mission stage ends.
void CP_SupplyMissionNextStage(mission_t *mission)
Determine what action should be performed when a Supply mission stage ends.
void CP_HarvestMissionNextStage(mission_t *mission)
Determine what action should be performed when a Harvesting mission stage ends.
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
void CP_BuildBaseMissionIsFailure(mission_t *mission)
Build Base mission is over and is a failure (from an alien point of view): change interest values...
void CAP_AddCurrent(base_t *base, baseCapacities_t capacity, int value)
Changes the current (used) capacity on a base.
#define E_Foreach(employeeType, var)
Definition: cp_employee.h:122
const aircraft_t * AIR_IsEmployeeInAircraft(const Employee *employee, const aircraft_t *aircraft)
Tells you if an employee is assigned to an aircraft.
header file UI callbacks for missions.
#define MIS_Foreach(var)
iterates through missions
Definition: cp_missions.h:118
#define _(String)
Definition: cl_shared.h:43
char id[MAX_VAR]
Definition: cp_missions.h:87
const char * name
Definition: cp_nation.h:70
void CP_ReconMissionGroundGo(mission_t *mission)
Set ground mission, and go to ground mission pos.
void *IMPORT * LIST_GetRandom(linkedList_t *list)
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
#define B_IsUnderAttack(base)
Definition: cp_base.h:53
int initialInterest
Definition: cp_campaign.h:207
void AB_SetAlienBasePosition(vec2_t pos)
Set new base position.
linkedList_t * populations
Definition: q_shared.h:487
void CP_BaseAttackMissionLeave(mission_t *mission)
Base attack mission ends: UFO leave earth.
char name[MAX_VAR]
Definition: cp_base.h:86
const teamDef_t * alienTeams[MAX_TEAMS_PER_MISSION]
Definition: cp_campaign.h:113
bool posAssigned
Definition: cp_missions.h:111
int maxTeamSize
Definition: cp_aircraft.h:138
short ufoType_t
Definition: scripts.h:146
csi_t * csi
Definition: cgame.h:100
#define SAVE_MISSIONS_INITIALINDIVIDUALINTEREST
Definition: save_missions.h:43
ufoType_t getUfoType() const
Definition: cp_aircraft.h:179
mission_t * CP_GetMissionByID(const char *missionId)
Get a mission in ccs.missions by Id.
const char * getWeather(const byte *const color)
Translate color value to terrain type to random weather code.
Definition: q_shared.cpp:78
int initialIndividualInterest
Definition: cp_missions.h:100
void CHAR_UpdateData(linkedList_t *updateCharacters)
Transforms the battlescape values to the character.
int day
Definition: common.h:291
date_t date
Definition: cp_campaign.h:245
static bool CP_IsAlienEquipmentSelectable(const mission_t *mission, const equipDef_t *equip, linkedList_t *equipPack)
Check if an alien equipment may be used with a mission.
void INT_ChangeIndividualInterest(float interestFactor, interestCategory_t category)
Change individual interest value.
static void CP_SetAlienTeamByInterest(mission_t *mission, battleParam_t *battleParameters)
Sets the alien races used for a mission.
#define SAVE_MISSIONS
Definition: save_missions.h:27
void GEO_NotifyMissionRemoved(const mission_t *mission)
Notify that a mission has been removed.
aircraft_t * AIR_AircraftGetFromIDX(int aircraftIdx)
Returns aircraft for a given global index.
void CP_RescueNextStage(mission_t *mission)
Determine what action should be performed when a Rescue mission stage ends.
equipDef_t eds[MAX_EQUIPDEFS]
Definition: q_shared.h:540
Campaign mission headers.
Campaign mission headers.
aircraft_t * UFO_AddToGeoscape(ufoType_t ufoType, const vec2_t destination, mission_t *mission)
Add a UFO to geoscape.
Definition: cp_ufo.cpp:773
void CP_HarvestMissionIsFailure(mission_t *mission)
Harvesting mission is over and is a failure: change interest values.
void AIR_AircraftsNotifyMissionRemoved(const mission_t *const mission)
Notify aircraft that a mission has been removed.
const byte * GEO_GetColor(const vec2_t pos, mapType_t type, bool *coast)
Returns the color value from geoscape of a certain mask (terrain, culture or population) at a given p...
static bool MIS_IsSpawnedFromGround(const mission_t *mission)
Decides if the mission should be spawned from the ground (without UFO)
#define SAVE_MISSIONSTAGE_NAMESPACE
Definition: save_missions.h:50
void CP_SpawnCrashSiteMission(aircraft_t *ufo)
Spawn a new crash site after a UFO has been destroyed.
#define SAVE_MISSIONS_INITIALOVERALLINTEREST
Definition: save_missions.h:42
char civTeam[MAX_VAR]
Definition: cp_campaign.h:144
void CP_ReconMissionIsFailure(mission_t *mission)
Recon mission is over and is a failure: change interest values.
installation_t * installation
Definition: cp_missions.h:93
int AB_GetAlienBaseNumber(void)
Check number of alien bases.
#define SAVE_MISSIONS_CRASHED
Definition: save_missions.h:34
void CP_SpawnNewMissions(void)
Spawn new missions.
int CP_CountMissionOnGeoscape(void)
Count the number of mission active and displayed on geoscape.
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
void CP_SupplyMissionIsSuccess(mission_t *mission)
Supply mission is over and is a success (from an alien point of view): change interest values...
char name[MAX_VAR]
Definition: cp_aircraft.h:120
messageType_t
Definition: cp_messages.h:30
const char * name
Definition: cp_nation.h:46
const char * id
Definition: cp_nation.h:45
const char * UFO_GetName(const aircraft_t *ufocraft)
Returns name of the UFO if UFO has been researched.
Definition: cp_ufo.cpp:243
void CP_MissionNotifyBaseDestroyed(const base_t *base)
Notify that a base has been removed.
static void MIS_CreateAlienTeam(mission_t *mission, battleParam_t *battleParam)
Set number of aliens in mission.
int missionsWon
Definition: cp_statistics.h:30
static void CP_CreateCivilianTeam(const mission_t *mission, battleParam_t *param)
Create civilian team.
date_t startDate
Definition: cp_missions.h:101
mission definition
Definition: cp_missions.h:85
#define SAVE_MISSIONS_ONLOSE
Definition: save_missions.h:36
linkedList_t * equipment
Definition: cp_campaign.h:130
linkedList_t * acTeam
Definition: cp_aircraft.h:139
void CP_EndRescueMission(mission_t *mission, aircraft_t *aircraft, bool won)
Actions to be done when rescue mission finished/expired.
bool RADAR_CheckRadarSensored(const vec2_t pos)
Check if the specified position is within base radar range.
Definition: cp_radar.cpp:377
baseCapacities_t AIR_GetHangarCapacityType(const aircraft_t *aircraft)
Returns capacity type needed for an aircraft.
alienTeamGroup_t alienTeamGroups[MAX_ALIEN_GROUP_PER_CATEGORY]
Definition: cp_campaign.h:132
int integer
Definition: cvar.h:81
equipDef_t storage
Definition: cp_base.h:112
uiMessageListNodeMessage_t * MS_AddNewMessage(const char *title, const char *text, messageType_t type, technology_t *pedia, bool popup, bool playSound)
Adds a new message to message stack.
Definition: cp_messages.cpp:61
struct mission_s * mission
Definition: cp_aircraft.h:152
#define SAVE_MISSIONS_ACTIVE
Definition: save_missions.h:32
int qFILE * f
Definition: cgame.h:283
void CP_BuildBaseMissionNextStage(const campaign_t *campaign, mission_t *mission)
Determine what action should be performed when a Build Base mission stage ends.
memPool_t * cp_campaignPool
Definition: cp_campaign.cpp:61
void CP_GameTimeStop(void)
Stop game time speed.
Definition: cp_time.cpp:126
void BATTLE_Start(mission_t *mission, const battleParam_t *battleParameters)
Select the mission type and start the map from mission definition.
int alienBaseInterest
Definition: cp_campaign.h:208
void CP_MissionEndActions(mission_t *mission, aircraft_t *aircraft, bool won)
Actions to be done after mission finished.
void CP_InitializeSpawningDelay(void)
Initialize spawning delay.
A base with all it's data.
Definition: cp_base.h:84
base_t * B_GetFoundedBaseByIDX(int baseIdx)
Array bound check for the base index.
Definition: cp_base.cpp:325
void CP_HandleNationData(float minHappiness, mission_t *mis, const nation_t *affectedNation, const missionResults_t *results, bool won)
Updates each nation's happiness. Should be called at the completion or expiration of every mission...
Definition: cp_nation.cpp:263
void BATTLE_SetVars(const battleParam_t *battleParameters)
Set some needed cvars from a battle definition.
Definition: cp_missions.cpp:78
int GEO_GetCivilianNumberByPosition(const vec2_t pos)
Get number of civilian on a map at given position.
const int MAX_POS_LOOP
Definition: cp_missions.cpp:61
const linkedList_t *IMPORT * LIST_ContainsString(const linkedList_t *list, const char *string)
const char *IMPORT * Com_UFOCrashedTypeToShortName(ufoType_t type)
#define xmlNode_t
Definition: xml.h:24
const teamDef_t * alienTeams[MAX_TEAMS_PER_MISSION]
Definition: q_shared.h:553
char onlose[256]
Definition: cp_missions.h:110
bool E_DeleteEmployee(Employee *employee)
Removes the employee completely from the game (buildings + global list).
void CP_InterceptMissionLeave(mission_t *mission, bool destroyed)
Intercept mission ends: UFO leave earth.
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
void setUfoType(ufoType_t ufoT)
Definition: cp_aircraft.h:182
const chrTemplate_t * alienChrTemplates[MAX_TEAMS_PER_MISSION]
Definition: cp_campaign.h:115
xmlNode_t *IMPORT * XML_GetDate(xmlNode_t *parent, const char *name, int *day, int *sec)
static const char * CP_MissionGetMessage(const mission_t *mission)
Assembles a message that is send to the gamer once the given mission is added to geoscape.
void CP_XVIMissionIsSuccess(mission_t *mission)
XVI Spreading mission is over and is a success: change interest values.
Campaign XVI header.
cvar_t *IMPORT * Cvar_Set(const char *varName, const char *value,...) __attribute__((format(__printf__
static missionDetectionStatus_t CP_CheckMissionVisibleOnGeoscape(const mission_t *mission)
Check if a mission should be visible on geoscape.
void CP_InterceptAircraftMissionSet(mission_t *mission)
Set Intercept mission: UFO looks for new aircraft target.
aircraft_t * aircraftCurrent
Definition: cp_base.h:100
Campaign mission headers.
#define SAVE_MISSIONS_STARTDATE
Definition: save_missions.h:44
struct mission_s * mission
Definition: cp_campaign.h:139
Campaign mission triggers.
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
void B_DumpAircraftToHomeBase(aircraft_t *aircraft)
Will unload all cargo to the homebase.
Definition: cp_base.cpp:2085
void CP_TerrorMissionIsFailure(mission_t *mission)
Terror attack mission is over and is a failure: change interest values.
#define DEBUG_CLIENT
Definition: defines.h:59
date_t finalDate
Definition: cp_missions.h:102
#define SAVE_MISSIONS_MISSION
Definition: save_missions.h:28
Campaign mission headers.
void GEO_NotifyUFORemoved(const aircraft_t *ufo, bool destroyed)
Notify that a UFO has been removed.
char onwin[256]
Definition: cp_missions.h:109
#define OBJZERO(obj)
Definition: shared.h:178
equipDef_t eMission
Definition: cp_campaign.h:229
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
aircraft_t * AIR_GetFirstFromBase(const base_t *b)
Iterates through the aircraft of a base.
Definition: cp_aircraft.cpp:50
aircraft_t * ufo
Definition: cp_missions.h:105
battleParam_t battleParameters
Definition: cp_campaign.h:235
int MIS_GetIdx(const mission_t *mis)
Find idx corresponding to mission.
bool AIR_PilotSurvivedCrash(const aircraft_t *aircraft)
Determine if an aircraft's pilot survived a crash, based on his piloting skill (and a bit of randomne...
void AIR_AircraftReturnToBase(aircraft_t *aircraft)
Calculates the way back to homebase for given aircraft and returns it.
mapDef_t *IMPORT * Com_GetMapDefinitionByID(const char *mapDefID)
void CP_ExecuteMissionTrigger(const mission_t *mission, bool won)
Executes console commands after a mission.
void CP_InterceptGoToInstallation(mission_t *mission)
Set Intercept mission: UFO chooses an installation an flies to it.
ufoType_t CP_MissionChooseUFO(const mission_t *mission)
Choose UFO type for a given mission category.
Campaign missions headers.
void CP_XVIMissionNextStage(mission_t *mission)
Determine what action should be performed when a XVI Spreading mission stage ends.
void CP_BaseAttackMissionIsFailure(mission_t *mission)
Base attack mission is over and is a failure (from an alien point of view): change interest values...
#define SAVE_MISSIONS_BASEINDEX
Definition: save_missions.h:39
static messageType_t CP_MissionGetMessageLevel(const mission_t *mission)
Decides which message level to take for the given mission.
Campaign mission header.
const cgame_import_t * cgi
bool CP_MissionBegin(mission_t *mission)
mission begins: UFO arrive on earth.
#define SAVE_MISSIONS_ID
Definition: save_missions.h:30
#define SAVE_MISSIONS_ONWIN
Definition: save_missions.h:35
static const cmdList_t debugMissionCmds[]
int idx
Definition: cp_base.h:85
bool GEO_PositionFitsTCPNTypes(const vec2_t pos, const linkedList_t *terrainTypes, const linkedList_t *cultureTypes, const linkedList_t *populationTypes, const linkedList_t *nations)
Checks for a given location, if it fulfills all criteria given via parameters (terrain, culture, population, nation type)
const char *IMPORT * Com_UFOTypeToShortName(ufoType_t type)
void CP_MissionRemove(mission_t *mission)
Removes a mission from mission global array.
#define UFO_MAX
Definition: scripts.h:147
char alienEquipment[MAX_VAR]
Definition: cp_campaign.h:143
void RADAR_NotifyUFORemoved(const aircraft_t *ufo, bool destroyed)
Notify to every radar that the specified ufo has been removed from geoscape.
Definition: cp_radar.cpp:213
bool storyRelated
Definition: q_shared.h:489
void CP_MissionAddToGeoscape(mission_t *mission, bool force)
Add a mission to geoscape: make it visible and stop time.
const char *IMPORT * Com_GetConstVariable(const char *space, int value)
linkedList_t * aircraft
Definition: q_shared.h:492
bool CP_BasemissionIsSubvertingGovernmentMission(const mission_t *mission)
char const * Q_strstart(char const *str, char const *start)
Matches the start of a string.
Definition: shared.cpp:587
void CP_SupplyMissionIsFailure(mission_t *mission)
Supply mission is over and is a failure (from an alien point of view): change interest values...
ccs_t ccs
Definition: cp_campaign.cpp:62
stats_t campaignStats
Definition: cp_campaign.h:378
Definition: cmd.h:86
Engine-side time information in the game.
Definition: common.h:290
enum missionStage_s missionStage_t
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)...
Employee * AIR_GetPilot(const aircraft_t *aircraft)
Get pilot of an aircraft.
missionDetectionStatus_s
possible mission detection status
Definition: cp_missions.cpp:54
void CP_MissionEnd(const campaign_t *campaign, mission_t *mission, const battleParam_t *battleParameters, bool won)
Closing actions after fighting a battle.
void CP_CreateBattleParameters(mission_t *mission, battleParam_t *param, const aircraft_t *aircraft)
Create parameters needed for battle. This is the data that is used for starting the tactical part of ...
static const float MIN_CRASHEDUFO_CONDITION
Definition: cp_missions.cpp:64
void MIS_InitStartup(void)
Init actions for missions-subsystem.
base_t * B_GetBaseByIDX(int baseIdx)
Array bound check for the base index. Will also return unfounded bases as long as the index is in the...
Definition: cp_base.cpp:312
Campaign geoscape time header.
void CP_UFOCarrierNextStage(mission_t *mission)
Determine what action should be performed when a UFOCarriering mission stage ends.
alien team group definition.
Definition: cp_campaign.h:105
#define MapDef_ForeachSingleplayerCampaign(var)
Definition: cl_shared.h:83
alienBase_t * alienBase
Definition: cp_missions.h:94
aircraftSlot_t weapons[MAX_AIRCRAFTSLOT]
Definition: cp_aircraft.h:143
date_t Date_Add(date_t a, const date_t &b)
Add two dates and return the result.
Definition: cp_time.cpp:272
Header for Geoscape management.
void CP_UpdateMissionVisibleOnGeoscape(void)
Update all mission visible on geoscape (in base radar range).
static bool CP_MapIsSelectable(const mission_t *mission, const mapDef_t *md, const vec2_t pos)
Check if a map may be selected for mission.
char id[MAX_VAR]
Definition: inv_shared.h:606
int numAlienTeams
Definition: q_shared.h:555
bool MIS_SaveXML(xmlNode_t *parent)
Save callback for savegames in XML Format.
bool active
Definition: cp_missions.h:89
int sec
Definition: common.h:292
int initialOverallInterest
Definition: cp_missions.h:99
#define GEO_GetMissionAircraft()
Definition: cp_geoscape.h:60
char cp_messageBuffer[MAX_MESSAGE_TEXT]
Definition: cp_messages.cpp:31
void CP_InterceptMissionIsSuccess(mission_t *mission)
Intercept mission is over and is a success: change interest values.
void CP_ReconMissionNextStage(mission_t *mission)
Determine what action should be performed when a Recon mission stage ends.
const GLuint *typedef void(APIENTRY *GenRenderbuffersEXT_t)(GLsizei
Definition: r_gl.h:189
Campaign mission header.
void CP_BaseAttackMissionDestroyBase(mission_t *mission)
Base attack mission ends: UFO leave earth.
bool GEO_IsNight(const vec2_t pos)
Check whether given position is Day or Night.
CGAME_HARD_LINKED_FUNCTIONS linkedList_t * LIST_Add(linkedList_t **listDest, void const *data, size_t length)
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define SAVE_MISSIONS_ONGEOSCAPE
Definition: save_missions.h:48
Campaign mission headers.
linkedList_t * updateCharacters
Definition: cp_campaign.h:389
struct base_s * homebase
Definition: cp_aircraft.h:149
void CP_MissionIsOverByUFO(aircraft_t *ufocraft)
Mission is finished because Phalanx team ended it.
static bool CP_IsAlienTeamForCategory(const alienTeamCategory_t *cat, const interestCategory_t missionCat)
Check if an alien team category may be used for a mission category.
baseCapacities_t
All possible capacities in base.
Definition: cp_capacity.h:27
Structure of all stats collected for an actor over time.
Definition: chr_shared.h:119
char * mapTheme
Definition: q_shared.h:464
union mission_s::missionData_t data
void AIR_DestroyAircraft(aircraft_t *aircraft, bool killPilot)
Removes an aircraft from its base and the game.
#define SAVE_MISSIONS_ALIENBASEINDEX
Definition: save_missions.h:41
void CP_SpawnRescueMission(aircraft_t *aircraft, aircraft_t *ufo)
Spawn a new rescue mission for a crashed (phalanx) aircraft.
#define SAVE_MISSIONS_CATEGORY
Definition: save_missions.h:37
int maxInterest
Definition: inv_shared.h:612
xmlNode_t *IMPORT * XML_GetPos2(xmlNode_t *parent, const char *name, vec2_t pos)
float ufoReductionRate
Definition: cp_campaign.h:203
const char *IMPORT * Com_GetRandomMapAssemblyNameForCraft(const char *craftID)
int maxWeapons
Definition: cp_aircraft.h:144
Campaign mission headers.
enum interestCategory_s interestCategory_t
#define SAVE_MISSIONS_MISSION_IDX
Definition: save_missions.h:29
float frand(void)
Return random values between 0 and 1.
Definition: mathlib.cpp:506
void CP_BaseAttackMissionNextStage(mission_t *mission)
Determine what action should be performed when a Base Attack mission stage ends.
QGL_EXTERN GLint i
Definition: r_gl.h:113
void MIS_InitCallbacks(void)
Init UI callbacks for missions-subsystem.
#define FINAL_OVERALL_INTEREST
Definition: cp_campaign.h:72
signed int difficulty
Definition: cp_campaign.h:185
xmlNode_t *IMPORT * XML_GetNextNode(xmlNode_t *current, xmlNode_t *parent, const char *name)
int overallInterest
Definition: cp_campaign.h:238
char * civTeam
Definition: q_shared.h:471
bool detected
Definition: cp_aircraft.h:166
void CP_MissionNotifyInstallationDestroyed(const installation_t *installation)
Notify missions that an installation has been destroyed.
const char *IMPORT * Com_GetRandomMapAssemblyNameForCrashedCraft(const char *craftID)
interestCategory_t category
Definition: cp_missions.h:97
int minMissions
Definition: cp_campaign.h:201
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
int missions
Definition: cp_statistics.h:29
TerrainDefs terrainDefs
Definition: q_shared.h:574
int maxMissions
Definition: cp_campaign.h:202
void CP_CheckLostCondition(const campaign_t *campaign)
Checks whether the player has lost the campaign.
alienBase_t * AB_GetByIDX(int baseIDX)
Get Alien Base per Idx.
#define SAVE_MISSIONS_FINALDATE
Definition: save_missions.h:45
#define MAX_TEAMS_PER_MISSION
Definition: inv_shared.h:618
aircraftStatus_t status
Definition: cp_aircraft.h:125
void CP_SpawnAlienBaseMission(alienBase_t *alienBase)
Spawn a new alien base mission after it has been discovered.
void CP_TerrorMissionOnSpawn(void)
Run when the mission is spawned.
#define SAVE_MISSIONS_INSTALLATIONINDEX
Definition: save_missions.h:40
int numUFOs
Definition: cp_campaign.h:355
linkedList_t * ufos
Definition: q_shared.h:491
int minInterest
Definition: inv_shared.h:611
int timesAlreadyUsed
Definition: q_shared.h:490
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
static void CP_SetMissionName(mission_t *mission)
Set mission name.
alienBase_t * AB_BuildBase(const vec2_t pos)
Build a new alien base.
void CP_UFORemoveFromGeoscape(mission_t *mission, bool destroyed)
Removes (temporarily or permanently) a UFO from geoscape: make it land and call notify functions...
#define MapIsWater(color)
Definition: cp_geoscape.h:32
linkedList_t * cultures
Definition: q_shared.h:488
#define SAVE_MISSIONS_CRASHED_AIRCRAFT
Definition: save_missions.h:47
missionResults_t missionResults
Definition: cp_missions.h:112
#define LIST_Foreach(list, type, var)
Iterates over a linked list, it's safe to delete the returned entry from the list while looping over ...
Definition: list.h:41
#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 UFO_SendToDestination(aircraft_t *ufo, const vec2_t dest)
Make the specified UFO go to destination.
Definition: cp_ufo.cpp:562
int missionsLost
Definition: cp_statistics.h:31
static const constListEntry_t saveMissionConstants[]
Definition: save_missions.h:51
xmlNode_t *IMPORT * XML_AddNode(xmlNode_t *parent, const char *name)
void CP_BuildBaseMissionBaseDestroyed(mission_t *mission)
Alien base has been destroyed: change interest values.
Campaign mission headers.
bool B_AssembleMap(char *maps, size_t mapsLength, char *coords, size_t coordsLength, const base_t *base)
Perform the base assembling in case of an alien attack.
Definition: cp_base.cpp:562
Alien Base.
Definition: cp_alienbase.h:28
const char * zoneType
Definition: cp_campaign.h:146
#define SAVE_MISSIONS_POS
Definition: save_missions.h:46
#define Q_streq(a, b)
Definition: shared.h:136
vec3_t pos
Definition: cp_base.h:91
const chrTemplate_t * alienChrTemplates[MAX_TEAMS_PER_MISSION]
Definition: q_shared.h:554
#define SAVE_MISSIONS_STAGE
Definition: save_missions.h:38
static void CP_SetAlienEquipmentByInterest(const mission_t *mission, linkedList_t *equipPack, battleParam_t *battleParameters)
Set alien equipment for a mission (depends on the interest values)
void CP_ReconMissionAerial(mission_t *mission)
Set aerial mission.
const char * MIS_GetName(const mission_t *mission)
Returns a short translated name for a mission.
char *IMPORT * PoolStrDup(const char *in, memPool_t *pool, const int tagNum)
date_t Date_Random(date_t minFrame, date_t maxFrame)
Return a random relative date which lies between a lower and upper limit.
Definition: cp_time.cpp:302
An aircraft with all it's data.
Definition: cp_aircraft.h:114
city_t * CITY_GetByPos(vec2_t pos)
Finds a city by it's geoscape coordinates.
Definition: cp_nation.cpp:424
void CHAR_UpdateStats(const base_t *base, const aircraft_t *aircraft)
Update employees stats after mission.
mapDef_t * mapDef
Definition: cp_missions.h:88
campaign_t * curCampaign
Definition: cp_campaign.h:377
int lastMissionSpawnedDelay
Definition: cp_campaign.h:240
XML tag constants for savegame.
linkedList_t * missions
Definition: cp_campaign.h:233
void CP_BaseAttackMissionIsSuccess(mission_t *mission)
Base attack mission is over and is a success (from an alien point of view): change interest values...
void UFO_RemoveFromGeoscape(aircraft_t *ufo)
Remove the specified ufo from geoscape.
Definition: cp_ufo.cpp:817
#define EARLY_UFO_RUSH_INTEREST
Determines the early game period during which DELAY_BETWEEN_MISSION_SPAWNING is halved.
Definition: cp_campaign.h:83
void MIS_ShutdownCallbacks(void)
Close UI callbacks for missions-subsystem.
uint8_t byte
Definition: ufotypes.h:34
mission_t * CP_GetMissionByIDSilent(const char *missionId)
Get a mission in ccs.missions by Id without error messages.
void CP_XVIMissionIsFailure(mission_t *mission)
XVI Spreading mission is over and is a failure: change interest values.
void CP_MissionRemoveFromGeoscape(mission_t *mission)
Removes a mission from geoscape: make it non visible and call notify functions.
struct nation_s * nation
Definition: cp_campaign.h:148
mission_t * MIS_GetByIdx(int id)
Find mission corresponding to idx.
enum missionDetectionStatus_s missionDetectionStatus_t
possible mission detection status
Alien interest header.
float minhappiness
Definition: cp_campaign.h:186
void CP_MissionDisableTimeLimit(mission_t *mission)
Disable time limit for given mission.
char * model
Definition: cp_aircraft.h:123
vec2_t pos
Definition: cp_missions.h:104
cvar_t * cp_missiontest
Definition: cp_campaign.cpp:63
nation_t * GEO_GetNation(const vec2_t pos)
Translate nation map color to nation.
const char *IMPORT * Cmd_Argv(int n)
alienTeamGroup_t * alienTeamGroup
Definition: cp_campaign.h:140
interestCategory_t missionCategories[INTERESTCATEGORY_MAX]
Definition: cp_campaign.h:126
#define SAVE_MISSIONS_POSASSIGNED
Definition: save_missions.h:33
static interestCategory_t CP_SelectNewMissionType(void)
Select new mission type.
bool onGeoscape
Definition: cp_missions.h:106
const char *IMPORT * XML_GetString(xmlNode_t *parent, const char *name)
xmlNode_t *IMPORT * XML_GetNode(xmlNode_t *parent, const char *name)
void AIRFIGHT_RemoveProjectileAimingAircraft(const aircraft_t *aircraft)
Set all projectile aiming a given aircraft to an idle destination.
void CP_BaseAttackMissionOnSpawn(void)
Run when the mission is spawned.
const char * MIS_GetModel(const mission_t *mission)
Get mission model that should be shown on the geoscape.
#define SAVE_MISSIONS_MAPDEF_ID
Definition: save_missions.h:31
#define UFO_NONE
Definition: scripts.h:149
int maxAliens
Definition: q_shared.h:483
mission_t * CP_CreateNewMission(interestCategory_t category, bool beginNow)
Create a new mission of given category.
void CP_BuildBaseMissionIsSuccess(mission_t *mission)
Build Base mission is over and is a success (from an alien point of view): change interest values...
bool MIS_LoadXML(xmlNode_t *parent)
Load callback for savegames in XML Format.
int interest[INTERESTCATEGORY_MAX]
Definition: cp_campaign.h:239
missionStage_t stage
Definition: cp_missions.h:98
void CP_MissionIsOver(mission_t *mission)
Mission is finished because Phalanx team won it.
#define GEO_IsAircraftSelected(aircraft)
Definition: cp_geoscape.h:51
linkedList_t * params
Definition: q_shared.h:465
XML tag constants for savegame.
installation_t * INS_GetByIDX(int idx)
Get installation by it's index.
Describes a character with all its attributes.
Definition: chr_shared.h:369
const char * getTerrainName(const byte *const color) const
Translate color value to terrain type.
Definition: q_shared.h:455