UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
cp_alienbase.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_alienbase.h"
28 #include "cp_geoscape.h"
29 #include "cp_missions.h"
30 #include "save/save_alienbase.h"
31 
32 #define MAPDEF_ALIENBASE "alienbase"
33 
42 {
43  int counter;
44  vec2_t randomPos;
45  float minDistance = 0.0f;
46  const int maxLoopPosition = 6;
48  counter = 0;
49  while (counter < maxLoopPosition) {
50  float distance = 0.0f;
51 
52  /* Get a random position */
53  CP_GetRandomPosOnGeoscape(randomPos, true);
54 
55  /* Alien base must not be too close from phalanx base */
56  if (GEO_PositionCloseToBase(randomPos))
57  continue;
58 
59  /* If this is the first alien base, there's no further condition: select this pos and quit */
60  if (AB_Exists()) {
61  Vector2Copy(randomPos, pos);
62  return;
63  }
64 
65  /* Calculate minimim distance between THIS position (pos) and all alien bases */
66  AB_Foreach(base) {
67  const float currentDistance = GetDistanceOnGlobe(base->pos, randomPos);
68  if (distance < currentDistance) {
69  distance = currentDistance;
70  }
71  }
72 
73  /* If this position is farther than previous ones, select it */
74  if (minDistance < distance) {
75  Vector2Copy(randomPos, pos);
76  minDistance = distance;
77  }
78 
79  counter++;
80  }
81  if (counter == maxLoopPosition)
82  Vector2Copy(randomPos, pos);
83 }
84 
91 {
92  alienBase_t base;
93  const float initialStealthValue = 50.0f;
95  OBJZERO(base);
96  Vector2Copy(pos, base.pos);
97  base.stealth = initialStealthValue;
99 
100  return &LIST_Add(&ccs.alienBases, base);
101 }
102 
108 {
109  assert(base);
110 
111  cgi->LIST_Remove(&ccs.alienBases, (void*)base);
112 
113  /* Alien loose all their interest in supply if there's no base to send the supply */
114  if (!AB_Exists())
116 }
117 
123 alienBase_t* AB_GetByIDX (int baseIDX)
124 {
125  AB_Foreach(base) {
126  if (base->idx == baseIDX)
127  return base;
128  }
129  return nullptr;
130 }
131 
136 {
137  mission_t* mission;
138 
140  if (!mission) {
141  cgi->Com_Printf("CP_SpawnAlienBaseMission: Could not add mission, abort\n");
142  return;
143  }
144 
145  mission->stage = STAGE_BASE_DISCOVERED;
146  mission->data.alienBase = alienBase;
147 
149  if (!mission->mapDef)
150  cgi->Com_Error(ERR_FATAL, "Could not find mapdef " MAPDEF_ALIENBASE);
151 
152  Vector2Copy(alienBase->pos, mission->pos);
153  mission->posAssigned = true;
154 
155  /* Alien base stay until it's destroyed */
157  /* mission appears on geoscape, player can go there */
158  CP_MissionAddToGeoscape(mission, false);
159 
161 }
162 
171 static void AB_UpdateStealthForOneBase (const aircraft_t* aircraft, alienBase_t* base)
172 {
173  float distance;
174  float probability = 0.0001f;
175  const float radarratio = 0.4f;
176  const float decreasingFactor = 5.0f;
178  /* base is already discovered */
179  if (base->stealth < 0)
180  return;
181 
182  /* aircraft can't find base if it's too far */
183  distance = GetDistanceOnGlobe(aircraft->pos, base->pos);
184  if (distance > aircraft->radar.range)
185  return;
186 
187  /* the bigger the base, the higher the probability to find it */
188  probability *= base->supply;
189 
190  /* decrease probability if the base is far from aircraft */
191  if (distance > aircraft->radar.range * radarratio)
192  probability /= decreasingFactor;
193 
194  /* probability must depend on DETECTION_INTERVAL (in case we change the value) */
195  probability *= DETECTION_INTERVAL;
196 
197  base->stealth -= probability;
198 
199  /* base discovered ? */
200  if (base->stealth < 0) {
201  base->stealth = -10.0f; /* just to avoid rounding errors */
203  }
204 }
205 
213 {
214  base_t* base = nullptr;
215  while ((base = B_GetNext(base)) != nullptr) {
216  AIR_ForeachFromBase(aircraft, base) {
217  /* Only aircraft on geoscape can detect alien bases */
218  if (!AIR_IsAircraftOnGeoscape(aircraft))
219  continue;
220 
221  AB_Foreach(alienBase)
222  AB_UpdateStealthForOneBase(aircraft, alienBase);
223  }
224  }
225 }
226 
233 {
234  const int daysPerWeek = 7;
235  float probability = 1.0f;
236  const float xviLevel = 20.0f;
239  /* Stealth is updated only once a week */
240  if (ccs.date.day % daysPerWeek)
241  return;
242 
243  AB_Foreach(base) {
244  const nation_t* nation = GEO_GetNation(base->pos);
245 
246  /* If nation is a lot infected, it won't help in finding base (government infected) */
247  if (nation) {
248  const nationInfo_t* stats = NAT_GetCurrentMonthInfo(nation);
249  if (stats->xviInfection)
250  probability /= 1.0f + stats->xviInfection / xviLevel;
251  }
252 
253  /* the bigger the base, the higher the probability to find it */
254  probability *= base->supply;
255 
256  base->stealth -= probability;
257  }
258 }
259 
265 {
266  return AB_Exists();
267 }
268 
274 {
275  const int baseCount = AB_GetAlienBaseNumber();
276 
277  if (baseCount <= 0) {
278  cgi->Com_Printf("AB_ChooseBaseToSupply: no bases exists (basecount: %d)\n", baseCount);
279  return nullptr;
280  }
281 
282  const int selected = rand() % baseCount;
283 
284  int i = 0;
285  AB_Foreach(alienBase) {
286  if (i == selected)
287  return alienBase;
288  i++;
289  }
290  return nullptr;
291 }
292 
298 void AB_SupplyBase (alienBase_t* base, bool decreaseStealth)
299 {
300  const float decreasedStealthValue = 5.0f;
302  assert(base);
303 
304  base->supply++;
305  if (decreaseStealth && base->stealth >= 0.0f)
306  base->stealth -= decreasedStealthValue;
307 }
308 
314 {
315  return cgi->LIST_Count(ccs.alienBases);
316 }
317 
318 #ifdef DEBUG
319 
322 static void AB_AlienBaseDiscovered_f (void)
323 {
324  AB_Foreach(base) {
325  base->stealth = -10.0f;
327  }
328 }
329 
334 static void AB_AlienBaseList_f (void)
335 {
336  AB_Foreach(base) {
337  cgi->Com_Printf("Alien Base: %i\n", base->idx);
338  cgi->Com_Printf("...pos: (%f, %f)\n", base->pos[0], base->pos[1]);
339  cgi->Com_Printf("...supply: %i\n", base->supply);
340  if (base->stealth < 0)
341  cgi->Com_Printf("...base discovered\n");
342  else
343  cgi->Com_Printf("...stealth: %f\n", base->stealth);
344  }
345 }
346 #endif
347 
354 {
355  int i;
356  xmlNode_t* n, *s;
357 
359  if (!n)
360  return false;
361 
362  for (i = 0, s = cgi->XML_GetNode(n, SAVE_ALIENBASE_BASE); s; i++, s = cgi->XML_GetNextNode(s, n, SAVE_ALIENBASE_BASE)) {
363  alienBase_t base;
364 
365  base.idx = cgi->XML_GetInt(s, SAVE_ALIENBASE_IDX, -1);
366  if (base.idx < 0) {
367  cgi->Com_Printf("Invalid or no IDX defined for Alienbase %d.\n", i);
368  return false;
369  }
370  if (!cgi->XML_GetPos2(s, SAVE_ALIENBASE_POS, base.pos)) {
371  cgi->Com_Printf("Position is invalid for Alienbase (idx %d)\n", base.idx);
372  return false;
373  }
374  base.supply = cgi->XML_GetInt(s, SAVE_ALIENBASE_SUPPLY, 0);
375  base.stealth = cgi->XML_GetFloat(s, SAVE_ALIENBASE_STEALTH, 0.0);
376  LIST_Add(&ccs.alienBases, base);
377  }
378 
379  return true;
380 }
381 
388 {
390 
391  AB_Foreach(base) {
393  cgi->XML_AddInt(s, SAVE_ALIENBASE_IDX, base->idx);
394  cgi->XML_AddPos2(s, SAVE_ALIENBASE_POS, base->pos);
395  cgi->XML_AddIntValue(s, SAVE_ALIENBASE_SUPPLY, base->supply);
396  cgi->XML_AddFloatValue(s, SAVE_ALIENBASE_STEALTH, base->stealth);
397  }
398 
399  return true;
400 }
401 
402 static const cmdList_t debugAlienBaseCmds[] = {
403 #ifdef DEBUG
404  {"debug_listalienbase", AB_AlienBaseList_f, "Print Alien Bases information to game console"},
405  {"debug_alienbasevisible", AB_AlienBaseDiscovered_f, "Set all alien bases to discovered"},
406 #endif
407  {nullptr, nullptr, nullptr}
408 };
413 void AB_InitStartup (void)
414 {
415  cgi->Cmd_TableAddList(debugAlienBaseCmds);
416 }
417 
421 void AB_Shutdown (void)
422 {
423  cgi->LIST_Delete(&ccs.alienBases);
424 
425  cgi->Cmd_TableRemoveList(debugAlienBaseCmds);
426 }
const nationInfo_t * NAT_GetCurrentMonthInfo(const nation_t *const nation)
Get the current month nation stats.
Definition: cp_nation.cpp:132
Nation definition.
Definition: cp_nation.h:44
void AB_Shutdown(void)
Closing actions for alienbase-subsystem.
void AB_SetAlienBasePosition(vec2_t pos)
Set new base position.
bool posAssigned
Definition: cp_missions.h:111
#define SAVE_ALIENBASE_STEALTH
void AB_BaseSearchedByNations(void)
Nations help in searching alien base.
int xviInfection
Definition: cp_nation.h:38
int day
Definition: common.h:291
date_t date
Definition: cp_campaign.h:245
static const cmdList_t debugAlienBaseCmds[]
#define SAVE_ALIENBASE_BASE
void AB_InitStartup(void)
Init actions for alienbase-subsystem.
int AB_GetAlienBaseNumber(void)
Check number of alien bases.
mission definition
Definition: cp_missions.h:85
#define SAVE_ALIENBASE_SUPPLY
#define ERR_FATAL
Definition: common.h:210
A base with all it's data.
Definition: cp_base.h:84
bool AB_LoadXML(xmlNode_t *p)
Load callback for alien base data.
static void AB_UpdateStealthForOneBase(const aircraft_t *aircraft, alienBase_t *base)
Update stealth value of one alien base due to one aircraft.
struct radar_s radar
Definition: cp_aircraft.h:158
#define xmlNode_t
Definition: xml.h:24
#define SAVE_ALIENBASE_ALIENBASES
bool AB_CheckSupplyMissionPossible(void)
Check if a supply mission is possible.
alienBase_t * AB_ChooseBaseToSupply(void)
Choose Alien Base that should be supplied.
#define SAVE_ALIENBASE_POS
#define OBJZERO(obj)
Definition: shared.h:178
vec3_t pos
Definition: cp_aircraft.h:131
mapDef_t *IMPORT * Com_GetMapDefinitionByID(const char *mapDefID)
base_t * GEO_PositionCloseToBase(const vec2_t pos)
Check if given pos is close to an existing base.
Campaign missions headers.
base_t * B_GetNext(base_t *lastBase)
Iterates through founded bases.
Definition: cp_base.cpp:285
const cgame_import_t * cgi
void CP_MissionAddToGeoscape(mission_t *mission, bool force)
Add a mission to geoscape: make it visible and stop time.
XML tag constants for savegame.
void AB_UpdateStealthForAllBase(void)
Update stealth value of every base for every aircraft.
#define MAPDEF_ALIENBASE
ccs_t ccs
Definition: cp_campaign.cpp:62
stats_t campaignStats
Definition: cp_campaign.h:378
Definition: cmd.h:86
void CP_TriggerEvent(campaignTriggerEventType_t type, const void *userdata)
Triggers a campaign event with a special type.
Definition: cp_event.cpp:311
alienBase_t * alienBase
Definition: cp_missions.h:94
Header for Geoscape management.
bool AIR_IsAircraftOnGeoscape(const aircraft_t *aircraft)
Checks whether given aircraft is on geoscape.
CGAME_HARD_LINKED_FUNCTIONS linkedList_t * LIST_Add(linkedList_t **listDest, void const *data, size_t length)
#define AIR_ForeachFromBase(var, base)
iterates trough all aircraft from a specific homebase
Definition: cp_aircraft.h:201
union mission_s::missionData_t data
xmlNode_t *IMPORT * XML_GetPos2(xmlNode_t *parent, const char *name, vec2_t pos)
void CP_GetRandomPosOnGeoscape(vec2_t pos, bool noWater)
Determines a random position on geoscape.
QGL_EXTERN GLint i
Definition: r_gl.h:113
xmlNode_t *IMPORT * XML_GetNextNode(xmlNode_t *current, xmlNode_t *parent, const char *name)
alienBase_t * AB_GetByIDX(int baseIDX)
Get Alien Base per Idx.
int range
Definition: cp_radar.h:35
void CP_SpawnAlienBaseMission(alienBase_t *alienBase)
Spawn a new alien base mission after it has been discovered.
int alienBasesBuilt
Definition: cp_statistics.h:47
const int DETECTION_INTERVAL
delay between actions that must be executed independently of time scale
Definition: cp_campaign.cpp:74
alienBase_t * AB_BuildBase(const vec2_t pos)
Build a new alien base.
#define Vector2Copy(src, dest)
Definition: vector.h:52
vec_t vec2_t[2]
Definition: ufotypes.h:38
Header file for single player campaign control.
xmlNode_t *IMPORT * XML_AddNode(xmlNode_t *parent, const char *name)
Alien Base.
Definition: cp_alienbase.h:28
void AB_SupplyBase(alienBase_t *base, bool decreaseStealth)
Supply a base.
#define AB_Exists()
Definition: cp_alienbase.h:39
vec2_t pos
Definition: cp_alienbase.h:30
An aircraft with all it's data.
Definition: cp_aircraft.h:114
mapDef_t * mapDef
Definition: cp_missions.h:88
#define AB_Foreach(var)
Definition: cp_alienbase.h:36
linkedList_t * alienBases
Definition: cp_campaign.h:292
void AB_DestroyBase(alienBase_t *base)
Destroy an alien base.
void CP_MissionDisableTimeLimit(mission_t *mission)
Disable time limit for given mission.
vec2_t pos
Definition: cp_missions.h:104
nation_t * GEO_GetNation(const vec2_t pos)
Translate nation map color to nation.
float stealth
Definition: cp_alienbase.h:32
#define SAVE_ALIENBASE_IDX
bool AB_SaveXML(xmlNode_t *p)
Save callback for alien base data.
xmlNode_t *IMPORT * XML_GetNode(xmlNode_t *parent, const char *name)
mission_t * CP_CreateNewMission(interestCategory_t category, bool beginNow)
Create a new mission of given category.
double GetDistanceOnGlobe(const vec2_t pos1, const vec2_t pos2)
Calculate distance on the geoscape.
Definition: mathlib.cpp:171
int interest[INTERESTCATEGORY_MAX]
Definition: cp_campaign.h:239
missionStage_t stage
Definition: cp_missions.h:98
Detailed information about the nation relationship (currently per month, but could be used elsewhere)...
Definition: cp_nation.h:33