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