UFO: Alien Invasion
Doxygen documentation generating
cp_installation.cpp
Go to the documentation of this file.
1 
7 /*
8 Copyright (C) 2002-2023 UFO: Alien Invasion.
9 
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 
19 See the GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 
25 */
26 
27 #include "../../DateTime.h"
28 #include "../../cl_shared.h"
29 #include "../../../shared/parse.h"
30 #include "cp_campaign.h"
31 #include "cp_mapfightequip.h"
32 #include "cp_aircraft.h"
33 #include "cp_missions.h"
34 #include "cp_installation.h"
35 #include "save/save_installation.h"
36 
40 int INS_GetCount (void)
41 {
42  return cgi->LIST_Count(ccs.installations);
43 }
44 
46 {
47  if (Q_streq(type, "samsite"))
48  return INSTALLATION_DEFENCE;
49  else if (Q_streq(type, "ufoyard"))
50  return INSTALLATION_UFOYARD;
51  else if (Q_streq(type, "radartower"))
52  return INSTALLATION_RADAR;
53  else if (Q_streq(type, "orbit"))
54  return INSTALLATION_ORBIT;
55 
56  cgi->Com_Printf("unknown type given '%s'\n", type);
57  return INSTALLATION_RADAR;
58 }
59 
65 {
66  INS_Foreach(installation) {
67  if (status == INSTALLATION_NOT_USED || installation->installationStatus == status)
68  return true;
69  }
70 
71  return false;
72 }
73 
80 {
81  INS_ForeachOfType(installation, type) {
82  if (status == INSTALLATION_NOT_USED || installation->installationStatus == status)
83  return true;
84  }
85 
86  return false;
87 }
88 
95 {
96  INS_Foreach(installation) {
97  if (installation->idx == idx)
98  return installation;
99  }
100 
101  return nullptr;
102 }
103 
110 {
111  int idx;
112 
113  for (idx = 0; idx < ccs.numInstallationTemplates; idx++) {
115  if (Q_streq(t->id, id))
116  return t;
117  }
118 
119  return nullptr;
120 }
121 
128 {
129  int idx;
130 
131  for (idx = 0; idx < ccs.numInstallationTemplates; idx++) {
133  if (t->type == type)
134  return t;
135  }
136 
137  return nullptr;
138 }
139 
146 installation_t* INS_Build (const installationTemplate_t* installationTemplate, const vec2_t pos, const char* name)
147 {
148  installation_t installation;
149  const int newInstallationAlienInterest = 1.0f;
150 
151  OBJZERO(installation);
152 
153  Vector2Copy(pos, installation.pos);
154  Q_strncpyz(installation.name, name, sizeof(installation.name));
155  installation.idx = ccs.campaignStats.installationsBuilt;
157  installation.installationTemplate = installationTemplate;
158  installation.buildStart = ccs.date.getDateAsDays();
159 
160  /* a new installation is not discovered (yet) */
161  installation.alienInterest = newInstallationAlienInterest;
162 
163  /* intialise hit points */
164  installation.installationDamage = installation.installationTemplate->maxDamage;
165 
166  /* Reset Radar */
167  RADAR_Initialise(&(installation.radar), 0.0f, 0.0f, 0.0f, false);
168 
170  return &LIST_Add(&ccs.installations, installation);
171 }
172 
178 {
179  if (!installation)
180  return;
181  /* Disable radar */
182  RADAR_UpdateInstallationRadarCoverage(installation, 0, 0);
183  /* Destroy stored UFOs */
184  if (installation->ufoCapacity.max > 0) {
185  installation->ufoCapacity.max = 0;
186  US_RemoveUFOsExceedingCapacity(installation);
187  }
189 
190  Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("Installation %s was destroyed."), installation->name);
192 
193  cgi->LIST_Remove(&ccs.installations, installation);
194  cgi->Cvar_Set("mn_installation_count", "%i", INS_GetCount());
195 }
196 
201 {
202  INS_Foreach(installation) {
203  if (installation->selected)
204  return installation;
205  }
206 
207  return nullptr;
208 }
209 
216 {
217  INS_Foreach(ins)
218  ins->selected = (ins == installation);
219 
220  if (installation) {
221  cgi->Cvar_Set("mn_installation_title", "%s", installation->name);
222  cgi->Cvar_Set("mn_installation_type", "%s", installation->installationTemplate->id);
223  } else {
224  cgi->Cvar_Set("mn_installation_title", "");
225  cgi->Cvar_Set("mn_installation_type", "");
226  }
227 }
228 
235 static void INS_FinishInstallation (installation_t* installation)
236 {
237  if (!installation)
238  cgi->Com_Error(ERR_DROP, "INS_FinishInstallation: No Installation.\n");
239  if (!installation->installationTemplate)
240  cgi->Com_Error(ERR_DROP, "INS_FinishInstallation: No Installation template.\n");
242  cgi->Com_DPrintf(DEBUG_CLIENT, "INS_FinishInstallation: Installation is not being built.\n");
243  return;
244  }
245 
247  /* if Radar Tower */
249  /* if SAM Site */
250  installation->numBatteries = installation->installationTemplate->maxBatteries;
251  BDEF_InitialiseInstallationSlots(installation);
252  /* if UFO Yard */
253  installation->ufoCapacity.max = installation->installationTemplate->maxUFOsStored;
254 }
255 
256 #ifdef DEBUG
257 
263 static void INS_InstallationList_f (void)
264 {
265  INS_Foreach(installation) {
266  cgi->Com_Printf("Installation idx %i\n", installation->idx);
267  cgi->Com_Printf("Installation name %s\n", installation->name);
268  cgi->Com_Printf("Installation pos %.02f:%.02f\n", installation->pos[0], installation->pos[1]);
269  cgi->Com_Printf("Installation Alien interest %f\n", installation->alienInterest);
270 
271  cgi->Com_Printf("\nInstallation sensorWidth %i\n", installation->radar.range);
272  cgi->Com_Printf("\nInstallation trackingWidth %i\n", installation->radar.trackingRange);
273  cgi->Com_Printf("Installation numSensoredAircraft %i\n\n", installation->radar.numUFOs);
274 
275  cgi->Com_Printf("\nInstallation numBatteries %i\n", installation->numBatteries);
278  cgi->Com_Printf("\nInstallation stored UFOs %i/%i\n", installation->ufoCapacity.cur, installation->ufoCapacity.max);
281  cgi->Com_Printf("\n\n");
282  }
283 }
284 
288 static void INS_ConstructionFinished_f (void)
289 {
290  int idx = -1;
291 
292  if (cgi->Cmd_Argc() == 2) {
293  idx = atoi(cgi->Cmd_Argv(1));
294  if (idx < 0) {
295  cgi->Com_Printf("Usage: %s [installationIDX]\nWithout parameter it builds up all.\n", cgi->Cmd_Argv(0));
296  return;
297  }
298  }
299 
300  INS_Foreach(ins) {
301  if (idx >= 0 && ins->idx != idx)
302  continue;
303 
305  }
306 }
307 #endif
308 
315 {
316  INS_ForeachOfType(installation, INSTALLATION_UFOYARD) {
317  if (free && installation->ufoCapacity.cur >= installation->ufoCapacity.max)
318  continue;
319 
320  return installation;
321  }
322 
323  return nullptr;
324 }
325 
327 #ifdef DEBUG
328  {"debug_listinstallation", INS_InstallationList_f, "Print installation information to the game console"},
329  {"debug_finishinstallation", INS_ConstructionFinished_f, "Finish construction of a specified or every installation"},
330 #endif
331  {nullptr, nullptr, nullptr}
332 };
336 void INS_InitStartup (void)
337 {
338  cgi->Cmd_TableAddList(debugInstallationCmds);
339 }
340 
344 void INS_Shutdown (void)
345 {
346  cgi->LIST_Delete(&ccs.installations);
347  cgi->Cmd_TableRemoveList(debugInstallationCmds);
348 }
349 
355 {
356  INS_Foreach(installation) {
357  if (installation->installationStatus == INSTALLATION_UNDER_CONSTRUCTION
358  && installation->buildStart
359  && installation->buildStart + installation->installationTemplate->buildTime <= ccs.date.getDateAsDays()) {
360  INS_FinishInstallation(installation);
361 
362  Com_sprintf(cp_messageBuffer, lengthof(cp_messageBuffer), _("Construction of installation %s finished."), installation->name);
364  }
365  }
366 }
367 
368 static const value_t installation_vals[] = {
369  {"name", V_TRANSLATION_STRING, offsetof(installationTemplate_t, name), 0},
370  {"description", V_TRANSLATION_STRING, offsetof(installationTemplate_t, description), 0},
371  {"radar_range", V_INT, offsetof(installationTemplate_t, radarRange), MEMBER_SIZEOF(installationTemplate_t, radarRange)},
372  {"radar_tracking_range", V_INT, offsetof(installationTemplate_t, trackingRange), MEMBER_SIZEOF(installationTemplate_t, trackingRange)},
373  {"max_batteries", V_INT, offsetof(installationTemplate_t, maxBatteries), MEMBER_SIZEOF(installationTemplate_t, maxBatteries)},
374  {"max_ufo_stored", V_INT, offsetof(installationTemplate_t, maxUFOsStored), MEMBER_SIZEOF(installationTemplate_t, maxUFOsStored)},
375  {"max_damage", V_INT, offsetof(installationTemplate_t, maxDamage), MEMBER_SIZEOF(installationTemplate_t, maxDamage)},
376  {"cost", V_INT, offsetof(installationTemplate_t, cost), MEMBER_SIZEOF(installationTemplate_t, cost)},
377  {"buildtime", V_INT, offsetof(installationTemplate_t, buildTime), MEMBER_SIZEOF(installationTemplate_t, buildTime)},
378  {"once", V_BOOL, offsetof(installationTemplate_t, once), MEMBER_SIZEOF(installationTemplate_t, once)},
379  {"model", V_HUNK_STRING, offsetof(installationTemplate_t, model), 0},
380  {"image", V_HUNK_STRING, offsetof(installationTemplate_t, image), 0},
381 
382  {nullptr, V_NULL, 0, 0}
383 };
384 
392 void INS_ParseInstallations (const char* name, const char** text)
393 {
394  /* get id list body */
395  const char* token = Com_Parse(text);
396  if (!*text || *token != '{') {
397  cgi->Com_Printf("INS_ParseInstallations: installation \"%s\" without body ignored\n", name);
398  return;
399  }
400 
401  if (!name) {
402  cgi->Com_Printf("INS_ParseInstallations: installation name not specified.\n");
403  return;
404  }
405 
407  cgi->Com_Printf("INS_ParseInstallations: too many installation templates\n");
408  ccs.numInstallationTemplates = MAX_INSTALLATION_TEMPLATES; /* just in case it's bigger. */
409  return;
410  }
411 
412  for (int i = 0; i < ccs.numInstallationTemplates; i++) {
414  cgi->Com_Printf("INS_ParseInstallations: Second installation with same name found (%s) - second ignored\n", name);
415  return;
416  }
417  }
418 
419  /* new entry */
421  OBJZERO(*installation);
422  installation->id = cgi->PoolStrDup(name, cp_campaignPool, 0);
423  installation->type = INSTALLATION_RADAR;
424 
425  cgi->Com_DPrintf(DEBUG_CLIENT, "...found installation %s\n", installation->id);
426 
428  const char* errhead = "INS_ParseInstallations: unexpected end of file (names ";
429  do {
430  /* get the name type */
431  token = cgi->Com_EParse(text, errhead, name);
432  if (!*text)
433  break;
434  if (*token == '}')
435  break;
436 
437  /* check for some standard values */
438  if (!cgi->Com_ParseBlockToken(name, text, installation, installation_vals, cp_campaignPool, token)) {
439  /* other values */
440  if (Q_streq(token, "type")) {
441  token = cgi->Com_EParse(text, errhead, name);
442  if (!*text)
443  return;
444 
445  installation->type = INS_GetType(token);
446  }
447  }
448  } while (*text);
449 }
450 
452 {
453  for (int i = 0; i < ccs.numInstallationTemplates; i++) {
455  technology_t* techLink = RS_GetTechByProvided(ins->id);
456  if (techLink)
457  ins->tech = techLink;
458  }
459 }
460 
468 {
470  cgi->Com_RegisterConstList(saveInstallationConstants);
471  INS_Foreach(inst) {
472  xmlNode_t* s, *ss;
473 
475  cgi->XML_AddString(s, SAVE_INSTALLATION_TEMPLATEID, inst->installationTemplate->id);
476  cgi->XML_AddInt(s, SAVE_INSTALLATION_IDX, inst->idx);
477  cgi->XML_AddString(s, SAVE_INSTALLATION_NAME, inst->name);
478  cgi->XML_AddPos3(s, SAVE_INSTALLATION_POS, inst->pos);
479  cgi->XML_AddString(s, SAVE_INSTALLATION_STATUS, cgi->Com_GetConstVariable(SAVE_INSTALLATIONSTATUS_NAMESPACE, inst->installationStatus));
480  cgi->XML_AddInt(s, SAVE_INSTALLATION_DAMAGE, inst->installationDamage);
481  cgi->XML_AddFloat(s, SAVE_INSTALLATION_ALIENINTEREST, inst->alienInterest);
482  cgi->XML_AddInt(s, SAVE_INSTALLATION_BUILDSTART, inst->buildStart);
483 
485  cgi->XML_AddIntValue(ss, SAVE_INSTALLATION_NUM, inst->numBatteries);
486  B_SaveBaseSlotsXML(inst->batteries, inst->numBatteries, ss);
487  }
488  cgi->Com_UnregisterConstList(saveInstallationConstants);
489  return true;
490 }
491 
500 {
502  xmlNode_t* s;
503  bool success = true;
504 
505  if (!n)
506  return false;
507 
508  cgi->Com_RegisterConstList(saveInstallationConstants);
510  xmlNode_t* ss;
511  installation_t inst;
512  const char* instID = cgi->XML_GetString(s, SAVE_INSTALLATION_TEMPLATEID);
513  const char* instStat = cgi->XML_GetString(s, SAVE_INSTALLATION_STATUS);
514 
515  OBJZERO(inst);
516  inst.idx = cgi->XML_GetInt(s, SAVE_INSTALLATION_IDX, -1);
517  if (inst.idx < 0) {
518  cgi->Com_Printf("Invalid installation index %i\n", inst.idx);
519  success = false;
520  break;
521  }
522  const installationType_t type = INS_GetType(instID);
524  if (!inst.installationTemplate) {
525  cgi->Com_Printf("Could not find installation template '%s'\n", instID);
526  success = false;
527  break;
528  }
529 
530  if (!cgi->Com_GetConstIntFromNamespace(SAVE_INSTALLATIONSTATUS_NAMESPACE, instStat, (int*) &inst.installationStatus)) {
531  cgi->Com_Printf("Invalid installation status '%s'\n", instStat);
532  success = false;
533  break;
534  }
535 
536  Q_strncpyz(inst.name, cgi->XML_GetString(s, SAVE_INSTALLATION_NAME), sizeof(inst.name));
538 
539  inst.installationDamage = cgi->XML_GetInt(s, SAVE_INSTALLATION_DAMAGE, 0);
540  inst.alienInterest = cgi->XML_GetFloat(s, SAVE_INSTALLATION_ALIENINTEREST, 0.0);
541  inst.buildStart = cgi->XML_GetInt(s, SAVE_INSTALLATION_BUILDSTART, 0);
542 
543  /* Radar */
545  RADAR_Initialise(&(inst.radar), 0.0f, 0.0f, 1.0f, true);
548  /* UFO Yard */
550  } else {
551  inst.ufoCapacity.max = 0;
552  }
553  inst.ufoCapacity.cur = 0;
554 
555  /* read battery slots */
557  if (!ss) {
558  cgi->Com_Printf("INS_LoadXML: Batteries not defined!\n");
559  success = false;
560  break;
561  }
562  inst.numBatteries = cgi->XML_GetInt(ss, SAVE_INSTALLATION_NUM, 0);
564  cgi->Com_Printf("Installation has more batteries than possible, using upper bound\n");
566  }
567 
568  installation_t& instp = LIST_Add(&ccs.installations, inst);
570  B_LoadBaseSlotsXML(instp.batteries, instp.numBatteries, ss);
571  }
572  cgi->Com_UnregisterConstList(saveInstallationConstants);
573  cgi->Cvar_Set("mn_installation_count", "%i", INS_GetCount());
574 
575  return success;
576 }
xmlNode_t *IMPORT * XML_GetNode(xmlNode_t *parent, const char *name)
#define SAVE_INSTALLATION_NAME
installationType_t INS_GetType(const char *type)
void INS_LinkTechnologies(void)
void RADAR_Initialise(radar_t *radar, float range, float trackingRange, float level, bool updateSourceRadarMap)
Set radar range to new value.
Definition: cp_radar.cpp:239
void INS_InitStartup(void)
Resets console commands.
uiMessageListNodeMessage_t * MSO_CheckAddNewMessage(const notify_t messagecategory, const char *title, const char *text, messageType_t type, technology_t *pedia, bool popup)
Adds a new message to message stack. It uses message settings to verify whether sound should be playe...
const installationTemplate_t * INS_GetInstallationTemplateByType(installationType_t type)
Returns the installation Template for a given installation type.
void BDEF_InitialiseInstallationSlots(installation_t *installation)
Initialise all values of installation slot defence.
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
cvar_t *IMPORT * Cvar_Set(const char *varName, const char *value,...) __attribute__((format(__printf__
installationStatus_t
Possible installation states.
bool INS_HasType(installationType_t type, installationStatus_t status)
Checks whether the given installation type is available.
installationStatus_t installationStatus
#define _(String)
Definition: cl_shared.h:44
void INS_UpdateInstallationData(void)
Check if some installation are build.
#define SAVE_INSTALLATION_BATTERIES
#define SAVE_INSTALLATION_DAMAGE
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
Header for installation management related stuff.
#define SAVE_INSTALLATION_INSTALLATIONS
void INS_SetCurrentSelectedInstallation(const installation_t *installation)
Sets the currently selected installation.
#define SAVE_INSTALLATION_NUM
bool INS_SaveXML(xmlNode_t *p)
Save callback for savegames in xml.
#define INS_ForeachOfType(var, installationType)
const char *IMPORT * Cmd_Argv(int n)
bool INS_HasAny(installationStatus_t status)
Checks whether any installation is available.
void RADAR_UpdateInstallationRadarCoverage(installation_t *installation, const float radarRange, const float trackingRadarRange)
Update radar coverage when building/destroying new radar.
Definition: cp_radar.cpp:311
void US_RemoveUFOsExceedingCapacity(installation_t *installation)
Removes ufos which are over the storing capacity.
A installation with all it&#39;s data.
int INS_GetCount(void)
Get number of installations.
memPool_t * cp_campaignPool
Definition: cp_campaign.cpp:62
char *IMPORT * PoolStrDup(const char *in, memPool_t *pool, const int tagNum)
#define INS_Foreach(var)
#define xmlNode_t
Definition: xml.h:24
void RADAR_InitialiseUFOs(radar_t *radar)
Reset UFO sensored on radar.
Definition: cp_radar.cpp:265
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
void INS_Shutdown(void)
Closing operations for installations subsystem.
#define ERR_DROP
Definition: common.h:211
installationType_t
#define DEBUG_CLIENT
Definition: defines.h:59
xmlNode_t *IMPORT * XML_GetPos3(xmlNode_t *parent, const char *name, vec3_t pos)
#define OBJZERO(obj)
Definition: shared.h:178
void INS_ParseInstallations(const char *name, const char **text)
Copies an entry from the installation description file into the list of installation templates...
Campaign missions headers.
capacities_t ufoCapacity
const char *IMPORT * XML_GetString(xmlNode_t *parent, const char *name)
const cgame_import_t * cgi
static const constListEntry_t saveInstallationConstants[]
ccs_t ccs
Definition: cp_campaign.cpp:63
void B_SaveBaseSlotsXML(const baseWeapon_t *weapons, const int numWeapons, xmlNode_t *node)
Saves the missile and laser slots of a base or sam site.
Definition: cp_base.cpp:2228
#define SAVE_INSTALLATION_INSTALLATION
xmlNode_t *IMPORT * XML_GetNextNode(xmlNode_t *current, xmlNode_t *parent, const char *name)
bool INS_LoadXML(xmlNode_t *p)
Load callback for savegames.
#define SAVE_INSTALLATION_STATUS
#define MAX_INSTALLATION_TEMPLATES
baseWeapon_t batteries[MAX_INSTALLATION_BATTERIES]
installation_t * INS_Build(const installationTemplate_t *installationTemplate, const vec2_t pos, const char *name)
Build a new installation.
#define SAVE_INSTALLATION_IDX
char cp_messageBuffer[MAX_MESSAGE_TEXT]
Definition: cp_messages.cpp:33
XML tag constants for savegame.
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
installationType_t type
#define SAVE_INSTALLATION_TEMPLATEID
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition: parse.cpp:107
static const cmdList_t debugInstallationCmds[]
Definition: scripts.h:49
static const value_t installation_vals[]
Header file for aircraft stuff.
int B_LoadBaseSlotsXML(baseWeapon_t *weapons, int max, xmlNode_t *p)
Loads the missile and laser slots of a base or sam site.
Definition: cp_base.cpp:2347
char name[MAX_VAR]
stats_t campaignStats
Definition: cp_campaign.h:379
QGL_EXTERN GLint i
Definition: r_gl.h:113
installation_t * INS_GetFirstUFOYard(bool free)
returns the first installation with (free) ufostoring capacity
Definition: scripts.h:50
Header for slot management related stuff.
void CP_MissionNotifyInstallationDestroyed(const installation_t *installation)
Notify missions that an installation has been destroyed.
#define SAVE_INSTALLATIONSTATUS_NAMESPACE
This is the technology parsed from research.ufo.
Definition: cp_research.h:139
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
class DateTime date
Definition: cp_campaign.h:246
static void INS_FinishInstallation(installation_t *installation)
Finishes an installation.
linkedList_t * installations
Definition: cp_campaign.h:352
int installationsBuilt
Definition: cp_statistics.h:34
#define MEMBER_SIZEOF(TYPE, MEMBER)
Definition: scripts.h:34
installation_t * INS_GetCurrentSelectedInstallation(void)
Returns the current selected installation.
int numInstallationTemplates
Definition: cp_campaign.h:349
#define Vector2Copy(src, dest)
Definition: vector.h:52
vec_t vec2_t[2]
Definition: ufotypes.h:38
Header file for single player campaign control.
Definition: scripts.h:52
#define SAVE_INSTALLATION_ALIENINTEREST
technology_t * RS_GetTechByProvided(const char *idProvided)
returns a pointer to the item tech (as listed in "provides")
#define lengthof(x)
Definition: shared.h:105
xmlNode_t *IMPORT * XML_AddNode(xmlNode_t *parent, const char *name)
#define Q_streq(a, b)
Definition: shared.h:136
struct radar_s radar
installationTemplate_t installationTemplates[MAX_INSTALLATION_TEMPLATES]
Definition: cp_campaign.h:348
#define SAVE_INSTALLATION_POS
const char *IMPORT * Com_GetConstVariable(const char *space, int value)
const char *IMPORT * Com_EParse(const char **text, const char *errhead, const char *errinfo)
struct technology_s * tech
const installationTemplate_t * installationTemplate
const installationTemplate_t * INS_GetInstallationTemplateByID(const char *id)
Returns the installation Template for a given installation ID.
void INS_DestroyInstallation(installation_t *installation)
Destroys an installation.
#define SAVE_INSTALLATION_BUILDSTART
Definition: cmd.h:86
installation_t * INS_GetByIDX(int idx)
Get installation by it&#39;s index.