UFO: Alien Invasion
Doxygen documentation generating
cp_building.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 2002-2023 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 "../../DateTime.h"
26 #include "cp_building.h"
27 #include "../../cl_shared.h"
28 #include "../../../shared/parse.h"
29 #include "cp_campaign.h"
30 #include "cp_time.h"
31 
37 bool B_IsBuildingBuiltUp (const building_t* building)
38 {
39  if (!building)
40  return false;
41  if (building->timeStart == DateTime(0, 0))
42  return true;
43  return (building->timeStart + DateTime(building->buildTime, 0)) <= ccs.date;
44 }
45 
50 float B_GetConstructionTimeRemain (const building_t* building)
51 {
52  DateTime diff = building->timeStart + DateTime(building->buildTime, 0) - ccs.date;
53  return diff.getDateAsDays() + (float)diff.getTimeAsSeconds() / DateTime::SECONDS_PER_DAY;
54 }
55 
56 static const struct buildingTypeMapping_s {
57  const char* id;
59 } buildingTypeMapping[] = {
60  { "lab", B_LAB },
61  { "hospital", B_HOSPITAL },
62  { "aliencont", B_ALIEN_CONTAINMENT },
63  { "workshop",B_WORKSHOP },
64  { "storage", B_STORAGE },
65  { "hangar", B_HANGAR },
66  { "smallhangar",B_SMALL_HANGAR },
67  { "quarters", B_QUARTERS },
68  { "power", B_POWER },
69  { "command", B_COMMAND },
70  { "amstorage", B_ANTIMATTER },
71  { "entrance", B_ENTRANCE },
72  { "missile", B_DEFENCE_MISSILE },
73  { "laser", B_DEFENCE_LASER },
74  { "radar", B_RADAR },
75  { NULL, MAX_BUILDING_TYPE }
76 };
77 
85 {
86  for (const struct buildingTypeMapping_s* v = buildingTypeMapping; v->id; v++)
87  if (Q_streq(buildingID, v->id))
88  return v->type;
89  return MAX_BUILDING_TYPE;
90 }
91 
98 static const value_t valid_building_vars[] = {
99  {"map_name", V_HUNK_STRING, offsetof(building_t, mapPart), 0},
100  {"max_count", V_INT, offsetof(building_t, maxCount), MEMBER_SIZEOF(building_t, maxCount)},
101  {"level", V_FLOAT, offsetof(building_t, level), MEMBER_SIZEOF(building_t, level)},
102  {"name", V_TRANSLATION_STRING, offsetof(building_t, name), 0},
103  {"tech", V_HUNK_STRING, offsetof(building_t, pedia), 0},
104  {"status", V_INT, offsetof(building_t, buildingStatus), MEMBER_SIZEOF(building_t, buildingStatus)},
105  {"image", V_HUNK_STRING, offsetof(building_t, image), 0},
106  {"size", V_POS, offsetof(building_t, size), MEMBER_SIZEOF(building_t, size)},
107  {"fixcosts", V_INT, offsetof(building_t, fixCosts), MEMBER_SIZEOF(building_t, fixCosts)},
108  {"varcosts", V_INT, offsetof(building_t, varCosts), MEMBER_SIZEOF(building_t, varCosts)},
109  {"build_time", V_INT, offsetof(building_t, buildTime), MEMBER_SIZEOF(building_t, buildTime)},
110  {"starting_employees", V_INT, offsetof(building_t, maxEmployees), MEMBER_SIZEOF(building_t, maxEmployees)},
111  {"capacity", V_INT, offsetof(building_t, capacity), MEMBER_SIZEOF(building_t, capacity)},
113  /*event handler functions */
114  {"onconstruct", V_HUNK_STRING, offsetof(building_t, onConstruct), 0},
115  {"ondestroy", V_HUNK_STRING, offsetof(building_t, onDestroy), 0},
116  {"onenable", V_HUNK_STRING, offsetof(building_t, onEnable), 0},
117  {"ondisable", V_HUNK_STRING, offsetof(building_t, onDisable), 0},
118  {"mandatory", V_BOOL, offsetof(building_t, mandatory), MEMBER_SIZEOF(building_t, mandatory)},
119  {nullptr, V_NULL, 0, 0}
120 };
121 
133 void B_ParseBuildings (const char* name, const char** text, bool link)
134 {
135  building_t* building;
136  technology_t* techLink;
137  const char* errhead = "B_ParseBuildings: unexpected end of file (names ";
138  const char* token;
139 
140  /* get id list body */
141  token = Com_Parse(text);
142  if (!*text || *token != '{') {
143  cgi->Com_Printf("B_ParseBuildings: building \"%s\" without body ignored\n", name);
144  return;
145  }
146 
148  cgi->Com_Error(ERR_DROP, "B_ParseBuildings: too many buildings");
149 
150  if (!link) {
151  for (int i = 0; i < ccs.numBuildingTemplates; i++) {
153  cgi->Com_Printf("B_ParseBuildings: Second building with same name found (%s) - second ignored\n", name);
154  return;
155  }
156  }
157 
158  /* new entry */
160  OBJZERO(*building);
161  building->id = cgi->PoolStrDup(name, cp_campaignPool, 0);
162 
163  cgi->Com_DPrintf(DEBUG_CLIENT, "...found building %s\n", building->id);
164 
165  /* set standard values */
166  building->tpl = building; /* Self-link just in case ... this way we can check if it is a template or not. */
167  building->idx = -1; /* No entry in buildings list (yet). */
168  building->base = nullptr;
169  building->buildingType = MAX_BUILDING_TYPE;
170  building->dependsBuilding = nullptr;
171  building->maxCount = -1; /* Default: no limit */
172  building->size[0] = 1;
173  building->size[1] = 1;
174 
176  do {
177  /* get the name type */
178  token = cgi->Com_EParse(text, errhead, name);
179  if (!*text)
180  break;
181  if (*token == '}')
182  break;
183 
184  /* get values */
185  if (Q_streq(token, "type")) {
186  token = cgi->Com_EParse(text, errhead, name);
187  if (!*text)
188  return;
189 
190  building->buildingType = B_GetBuildingTypeByBuildingID(token);
191  if (building->buildingType >= MAX_BUILDING_TYPE)
192  cgi->Com_Printf("didn't find buildingType '%s'\n", token);
193  } else {
194  /* no linking yet */
195  if (Q_streq(token, "depends")) {
196  cgi->Com_EParse(text, errhead, name);
197  if (!*text)
198  return;
199  } else {
200  if (!cgi->Com_ParseBlockToken(name, text, building, valid_building_vars, cp_campaignPool, token))
201  cgi->Com_Printf("B_ParseBuildings: unknown token \"%s\" ignored (building %s)\n", token, name);
202  }
203  }
204  } while (*text);
205  if (building->size[0] < 1 || building->size[1] < 1 || building->size[0] >= BASE_SIZE || building->size[1] >= BASE_SIZE) {
206  cgi->Com_Printf("B_ParseBuildings: Invalid size for building %s (%i, %i)\n", building->id, (int)building->size[0], (int)building->size[1]);
208  }
209  } else {
210  building = B_GetBuildingTemplate(name);
211  if (!building)
212  cgi->Com_Error(ERR_DROP, "B_ParseBuildings: Could not find building with id %s\n", name);
213 
214  techLink = RS_GetTechByProvided(name);
215  if (techLink)
216  building->tech = techLink;
217 
218  do {
219  /* get the name type */
220  token = cgi->Com_EParse(text, errhead, name);
221  if (!*text)
222  break;
223  if (*token == '}')
224  break;
225  /* get values */
226  if (Q_streq(token, "depends")) {
227  const building_t* dependsBuilding = B_GetBuildingTemplate(cgi->Com_EParse(text, errhead, name));
228  if (!dependsBuilding)
229  cgi->Com_Error(ERR_DROP, "Could not find building depend of %s\n", building->id);
230  building->dependsBuilding = dependsBuilding;
231  if (!*text)
232  return;
233  }
234  } while (*text);
235  }
236 }
237 
243 {
244  int i, error = 0;
245  building_t* b;
246 
247  for (i = 0, b = ccs.buildingTemplates; i < ccs.numBuildingTemplates; i++, b++) {
248  if (!b->name) {
249  error++;
250  cgi->Com_Printf("...... no name for building '%s' given\n", b->id);
251  }
252  if (!b->image) {
253  error++;
254  cgi->Com_Printf("...... no image for building '%s' given\n", b->id);
255  }
256  if (!b->pedia) {
257  error++;
258  cgi->Com_Printf("...... no pedia link for building '%s' given\n", b->id);
259  } else if (!RS_GetTechByID(b->pedia)) {
260  error++;
261  cgi->Com_Printf("...... could not get pedia entry tech (%s) for building '%s'\n", b->pedia, b->id);
262  }
263  }
264 
265  return !error;
266 }
267 
274 building_t* B_GetBuildingTemplateSilent (const char* buildingName)
275 {
276  if (!buildingName)
277  return nullptr;
278  for (int i = 0; i < ccs.numBuildingTemplates; i++) {
279  building_t* buildingTemplate = &ccs.buildingTemplates[i];
280  if (Q_streq(buildingTemplate->id, buildingName))
281  return buildingTemplate;
282  }
283  return nullptr;
284 }
285 
292 building_t* B_GetBuildingTemplate (const char* buildingName)
293 {
294  if (!buildingName || buildingName[0] == '\0') {
295  cgi->Com_Printf("No, or empty building ID\n");
296  return nullptr;
297  }
298 
299  building_t* buildingTemplate = B_GetBuildingTemplateSilent(buildingName);
300  if (!buildingTemplate)
301  cgi->Com_Printf("Building %s not found\n", buildingName);
302  return buildingTemplate;
303 }
304 
310 {
311  for (int i = 0; i < ccs.numBuildingTemplates; i++) {
312  const building_t* buildingTemplate = &ccs.buildingTemplates[i];
313  if (buildingTemplate->buildingType == type)
314  return buildingTemplate;
315  }
316  return nullptr;
317 }
318 
325 {
326  assert(building);
327 
328  if (!building->dependsBuilding)
329  return true;
330 
331  /* Make sure the dependsBuilding pointer is really a template .. just in case. */
332  assert(building->dependsBuilding == building->dependsBuilding->tpl);
333 
334  return B_GetBuildingStatus(building->base, building->dependsBuilding->buildingType);
335 }
336 
344 bool B_FireEvent (const building_t* buildingTemplate, const base_t* base, buildingEvent_t eventType)
345 {
346  const char* command = nullptr;
347 
348  assert(buildingTemplate);
349  assert(base);
350 
351  switch (eventType) {
352  case B_ONCONSTRUCT:
353  command = buildingTemplate->onConstruct;
354  break;
355  case B_ONENABLE:
356  command = buildingTemplate->onEnable;
357  break;
358  case B_ONDISABLE:
359  command = buildingTemplate->onDisable;
360  break;
361  case B_ONDESTROY:
362  command = buildingTemplate->onDestroy;
363  break;
364  default:
365  cgi->Com_Error(ERR_DROP, "B_FireEvent: Invalid Event\n");
366  }
367 
368  if (Q_strvalid(command)) {
369  cgi->Cmd_ExecuteString("%s %i %i", command, base->idx, buildingTemplate->buildingType);
370  return true;
371  }
372 
373  return false;
374 }
char * onConstruct
Definition: cp_building.h:97
Class describing a point of time.
Definition: DateTime.h:30
building_t buildingTemplates[MAX_BUILDINGS]
Definition: cp_campaign.h:339
float B_GetConstructionTimeRemain(const building_t *building)
Returns the time remaining time of a building construction.
Definition: cp_building.cpp:50
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
bool B_GetBuildingStatus(const base_t *const base, const buildingType_t buildingType)
Get the status associated to a building.
Definition: cp_base.cpp:478
A base with all it&#39;s data.
Definition: cp_base.h:84
struct building_s * tpl
Definition: cp_building.h:75
struct technology_s * tech
Definition: cp_building.h:111
const building_t * B_GetBuildingTemplateByType(buildingType_t type)
Returns the building template in the global building-types list for a buildingType.
#define BASE_SIZE
Definition: cp_base.h:38
struct base_s * base
Definition: cp_building.h:76
voidpf void uLong size
Definition: ioapi.h:42
void B_ParseBuildings(const char *name, const char **text, bool link)
Copies an entry from the building description file into the list of building types.
buildingType_t
All different building types.
Definition: cp_building.h:51
building_t * B_GetBuildingTemplate(const char *buildingName)
Returns the building in the global building-types list that has the unique name buildingID.
memPool_t * cp_campaignPool
Definition: cp_campaign.cpp:62
char * onDisable
Definition: cp_building.h:100
char * onDestroy
Definition: cp_building.h:98
#define Q_strvalid(string)
Definition: shared.h:141
char *IMPORT * PoolStrDup(const char *in, memPool_t *pool, const int tagNum)
int idx
Definition: cp_base.h:85
static const value_t valid_building_vars[]
Holds the names of valid entries in the basemanagement.ufo file.
Definition: cp_building.cpp:98
#define MAX_BUILDINGS
Definition: cp_base.h:34
int buildTime
Definition: cp_building.h:92
static const int SECONDS_PER_DAY
Definition: DateTime.h:43
#define ERR_DROP
Definition: common.h:211
#define DEBUG_CLIENT
Definition: defines.h:59
int numBuildingTemplates
Definition: cp_campaign.h:340
#define OBJZERO(obj)
Definition: shared.h:178
class DateTime timeStart
Definition: cp_building.h:91
bool B_CheckBuildingDependencesStatus(const building_t *building)
Check that the dependences of a building is operationnal.
const cgame_import_t * cgi
int getTimeAsSeconds() const
Return the time part of the DateTime as seconds.
Definition: DateTime.cpp:54
ccs_t ccs
Definition: cp_campaign.cpp:63
Campaign geoscape time header.
Header for base building related stuff.
building_t * B_GetBuildingTemplateSilent(const char *buildingName)
Returns the building in the global building-types list that has the unique name buildingID.
technology_t * RS_GetTechByID(const char *id)
return a pointer to the technology identified by given id string
char * name
Definition: cp_building.h:79
char * onEnable
Definition: cp_building.h:99
int getDateAsDays() const
Return the date part of the DateTime as days.
Definition: DateTime.cpp:46
bool B_IsBuildingBuiltUp(const building_t *building)
Returns if a building is fully buildt up.
Definition: cp_building.cpp:37
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
Definition: scripts.h:49
vec2_t size
Definition: cp_building.h:82
bool B_BuildingScriptSanityCheck(void)
Checks the parsed buildings for errors.
const char * image
Definition: cp_building.h:80
QGL_EXTERN GLint i
Definition: r_gl.h:113
static const struct buildingTypeMapping_s buildingTypeMapping[]
buildingEvent_t
Building events.
Definition: cp_building.h:41
Definition: scripts.h:50
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
const char * id
Definition: cp_building.h:78
buildingType_t type
Definition: cp_building.cpp:58
const char * pedia
Definition: cp_building.h:80
const struct building_s * dependsBuilding
Definition: cp_building.h:112
#define MEMBER_SIZEOF(TYPE, MEMBER)
Definition: scripts.h:34
buildingType_t buildingType
Definition: cp_building.h:110
Header file for single player campaign control.
Definition: scripts.h:52
technology_t * RS_GetTechByProvided(const char *idProvided)
returns a pointer to the item tech (as listed in "provides")
A building with all it&#39;s data.
Definition: cp_building.h:73
#define Q_streq(a, b)
Definition: shared.h:136
buildingType_t B_GetBuildingTypeByBuildingID(const char *buildingID)
Returns the building type for a given building identified by its building id from the ufo script file...
Definition: cp_building.cpp:84
const char *IMPORT * Com_EParse(const char **text, const char *errhead, const char *errinfo)
QGL_EXTERN int GLboolean GLfloat * v
Definition: r_gl.h:120
Definition: scripts.h:55
bool B_FireEvent(const building_t *buildingTemplate, const base_t *base, buildingEvent_t eventType)
Run eventhandler script for a building.
level_locals_t level
Definition: g_main.cpp:38