UFO: Alien Invasion
cp_alienbase.cpp
Go to the documentation of this file.
1
6/*
7Copyright (C) 2002-2022 UFO: Alien Invasion.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23*/
24
25#include "../../cl_shared.h"
26#include "cp_campaign.h"
27#include "cp_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
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
171static 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.getDateAsDays() % 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
298void 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
322static void AB_AlienBaseDiscovered_f (void)
323{
324 AB_Foreach(base) {
325 base->stealth = -10.0f;
327 }
328}
329
334static 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
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};
413void AB_InitStartup (void)
414{
415 cgi->Cmd_TableAddList(debugAlienBaseCmds);
416}
417
421void AB_Shutdown (void)
422{
423 cgi->LIST_Delete(&ccs.alienBases);
424
425 cgi->Cmd_TableRemoveList(debugAlienBaseCmds);
426}
CGAME_HARD_LINKED_FUNCTIONS linkedList_t * LIST_Add(linkedList_t **listDest, void const *data, size_t length)
int getDateAsDays() const
Return the date part of the DateTime as days.
Definition: DateTime.cpp:46
#define ERR_FATAL
Definition: common.h:210
bool AIR_IsAircraftOnGeoscape(const aircraft_t *aircraft)
Checks whether given aircraft is on geoscape.
#define AIR_ForeachFromBase(var, base)
iterates trough all aircraft from a specific homebase
Definition: cp_aircraft.h:202
@ INTERESTCATEGORY_ALIENBASE
@ INTERESTCATEGORY_SUPPLY
bool AB_CheckSupplyMissionPossible(void)
Check if a supply mission is possible.
void AB_SupplyBase(alienBase_t *base, bool decreaseStealth)
Supply a base.
int AB_GetAlienBaseNumber(void)
Check number of alien bases.
void AB_SetAlienBasePosition(vec2_t pos)
Set new base position.
void CP_SpawnAlienBaseMission(alienBase_t *alienBase)
Spawn a new alien base mission after it has been discovered.
bool AB_SaveXML(xmlNode_t *p)
Save callback for alien base data.
void AB_InitStartup(void)
Init actions for alienbase-subsystem.
void AB_DestroyBase(alienBase_t *base)
Destroy an alien base.
#define MAPDEF_ALIENBASE
void AB_Shutdown(void)
Closing actions for alienbase-subsystem.
static void AB_UpdateStealthForOneBase(const aircraft_t *aircraft, alienBase_t *base)
Update stealth value of one alien base due to one aircraft.
static const cmdList_t debugAlienBaseCmds[]
void AB_UpdateStealthForAllBase(void)
Update stealth value of every base for every aircraft.
alienBase_t * AB_ChooseBaseToSupply(void)
Choose Alien Base that should be supplied.
alienBase_t * AB_BuildBase(const vec2_t pos)
Build a new alien base.
void AB_BaseSearchedByNations(void)
Nations help in searching alien base.
bool AB_LoadXML(xmlNode_t *p)
Load callback for alien base data.
alienBase_t * AB_GetByIDX(int baseIDX)
Get Alien Base per Idx.
#define AB_Exists()
Definition: cp_alienbase.h:39
#define AB_Foreach(var)
Definition: cp_alienbase.h:36
base_t * B_GetNext(base_t *lastBase)
Iterates through founded bases.
Definition: cp_base.cpp:286
const int DETECTION_INTERVAL
delay between actions that must be executed independently of time scale
Definition: cp_campaign.cpp:75
ccs_t ccs
Definition: cp_campaign.cpp:63
Header file for single player campaign control.
const cgame_import_t * cgi
void CP_TriggerEvent(campaignTriggerEventType_t type, const void *userdata)
Triggers a campaign event with a special type.
Definition: cp_event.cpp:310
@ ALIENBASE_DISCOVERED
Definition: cp_event.h:83
nation_t * GEO_GetNation(const vec2_t pos)
Translate nation map color to nation.
base_t * GEO_PositionCloseToBase(const vec2_t pos)
Check if given pos is close to an existing base.
void CP_GetRandomPosOnGeoscape(vec2_t pos, bool noWater)
Determines a random position on geoscape.
Header for Geoscape management.
mission_t * CP_CreateNewMission(interestCategory_t category, bool beginNow)
Create a new mission of given category.
void CP_MissionAddToGeoscape(mission_t *mission, bool force)
Add a mission to geoscape: make it visible and stop time.
void CP_MissionDisableTimeLimit(mission_t *mission)
Disable time limit for given mission.
Campaign missions headers.
@ STAGE_BASE_DISCOVERED
Definition: cp_missions.h:48
const nationInfo_t * NAT_GetCurrentMonthInfo(const nation_t *const nation)
Get the current month nation stats.
Definition: cp_nation.cpp:133
double GetDistanceOnGlobe(const vec2_t pos1, const vec2_t pos2)
Calculate distance on the geoscape.
Definition: mathlib.cpp:171
QGL_EXTERN GLint i
Definition: r_gl.h:113
XML tag constants for savegame.
#define SAVE_ALIENBASE_ALIENBASES
#define SAVE_ALIENBASE_IDX
#define SAVE_ALIENBASE_STEALTH
#define SAVE_ALIENBASE_SUPPLY
#define SAVE_ALIENBASE_POS
#define SAVE_ALIENBASE_BASE
#define OBJZERO(obj)
Definition: shared.h:178
An aircraft with all it's data.
Definition: cp_aircraft.h:115
vec3_t pos
Definition: cp_aircraft.h:132
struct radar_s radar
Definition: cp_aircraft.h:159
Alien Base.
Definition: cp_alienbase.h:28
float stealth
Definition: cp_alienbase.h:32
vec2_t pos
Definition: cp_alienbase.h:30
A base with all it's data.
Definition: cp_base.h:84
stats_t campaignStats
Definition: cp_campaign.h:379
class DateTime date
Definition: cp_campaign.h:246
linkedList_t * alienBases
Definition: cp_campaign.h:293
int interest[INTERESTCATEGORY_MAX]
Definition: cp_campaign.h:240
xmlNode_t *IMPORT * XML_GetNode(xmlNode_t *parent, const char *name)
xmlNode_t *IMPORT * XML_GetNextNode(xmlNode_t *current, xmlNode_t *parent, const char *name)
xmlNode_t *IMPORT * XML_AddNode(xmlNode_t *parent, const char *name)
mapDef_t *IMPORT * Com_GetMapDefinitionByID(const char *mapDefID)
xmlNode_t *IMPORT * XML_GetPos2(xmlNode_t *parent, const char *name, vec2_t pos)
Definition: cmd.h:86
mission definition
Definition: cp_missions.h:86
mapDef_t * mapDef
Definition: cp_missions.h:89
missionStage_t stage
Definition: cp_missions.h:99
vec2_t pos
Definition: cp_missions.h:105
union mission_t::missionData_t data
bool posAssigned
Definition: cp_missions.h:112
Nation definition.
Definition: cp_nation.h:46
Detailed information about the nation relationship (currently per month, but could be used elsewhere)...
Definition: cp_nation.h:35
int xviInfection
Definition: cp_nation.h:40
int alienBasesBuilt
Definition: cp_statistics.h:47
vec_t vec2_t[2]
Definition: ufotypes.h:38
alienBase_t * alienBase
Definition: cp_missions.h:95
#define Vector2Copy(src, dest)
Definition: vector.h:52
#define xmlNode_t
Definition: xml.h:24