UFO: Alien Invasion
Loading...
Searching...
No Matches
cp_building.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 2002-2025 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 "../../DateTime.h"
26#include "cp_building.h"
27#include "../../cl_shared.h"
29#include "cp_campaign.h"
30#include "cp_time.h"
31
37bool 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
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
56static const struct buildingTypeMapping_s {
57 const char* id;
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
98static 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)},
112
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
133void 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
147 if (ccs.numBuildingTemplates >= MAX_BUILDINGS)
148 cgi->Com_Error(ERR_DROP, "B_ParseBuildings: too many buildings");
149
150 if (!link) {
151 for (int i = 0; i < ccs.numBuildingTemplates; i++) {
152 if (Q_streq(ccs.buildingTemplates[i].id, name)) {
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 */
159 building = &ccs.buildingTemplates[ccs.numBuildingTemplates];
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;
170 building->dependsBuilding = nullptr;
171 building->maxCount = -1; /* Default: no limit */
172 building->size[0] = 1;
173 building->size[1] = 1;
174
175 ccs.numBuildingTemplates++;
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
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]);
207 ccs.numBuildingTemplates--;
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
274building_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
292building_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
344bool 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}
DateTime class definition.
Share stuff between the different cgame implementations.
Class describing a point of time.
Definition DateTime.h:31
static const int SECONDS_PER_DAY
Definition DateTime.h:43
int getTimeAsSeconds() const
Return the time part of the DateTime as seconds.
Definition DateTime.cpp:54
int getDateAsDays() const
Return the date part of the DateTime as days.
Definition DateTime.cpp:46
#define ERR_DROP
Definition common.h:211
bool B_GetBuildingStatus(const base_t *const base, const buildingType_t buildingType)
Get the status associated to a building.
Definition cp_base.cpp:478
#define BASE_SIZE
Definition cp_base.h:38
#define MAX_BUILDINGS
Definition cp_base.h:34
bool B_FireEvent(const building_t *buildingTemplate, const base_t *base, buildingEvent_t eventType)
Run eventhandler script for a building.
bool B_CheckBuildingDependencesStatus(const building_t *building)
Check that the dependences of a building is operationnal.
static const struct buildingTypeMapping_s buildingTypeMapping[]
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...
static const value_t valid_building_vars[]
Holds the names of valid entries in the basemanagement.ufo file.
bool B_BuildingScriptSanityCheck(void)
Checks the parsed buildings for errors.
const building_t * B_GetBuildingTemplateByType(buildingType_t type)
Returns the building template in the global building-types list for a buildingType.
building_t * B_GetBuildingTemplateSilent(const char *buildingName)
Returns the building in the global building-types list that has the unique name buildingID.
bool B_IsBuildingBuiltUp(const building_t *building)
Returns if a building is fully buildt up.
float B_GetConstructionTimeRemain(const building_t *building)
Returns the time remaining time of a building construction.
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.
building_t * B_GetBuildingTemplate(const char *buildingName)
Returns the building in the global building-types list that has the unique name buildingID.
Header for base building related stuff.
buildingEvent_t
Building events.
Definition cp_building.h:41
@ B_ONDISABLE
Definition cp_building.h:44
@ B_ONENABLE
Definition cp_building.h:43
@ B_ONCONSTRUCT
Definition cp_building.h:42
@ B_ONDESTROY
Definition cp_building.h:45
buildingType_t
All different building types.
Definition cp_building.h:51
@ B_ENTRANCE
Definition cp_building.h:64
@ B_QUARTERS
Definition cp_building.h:54
@ B_DEFENCE_LASER
Definition cp_building.h:66
@ B_COMMAND
Definition cp_building.h:62
@ B_RADAR
Definition cp_building.h:67
@ B_HANGAR
Definition cp_building.h:58
@ MAX_BUILDING_TYPE
Definition cp_building.h:69
@ B_POWER
Definition cp_building.h:61
@ B_STORAGE
Definition cp_building.h:55
@ B_LAB
Definition cp_building.h:53
@ B_HOSPITAL
Definition cp_building.h:57
@ B_WORKSHOP
Definition cp_building.h:56
@ B_SMALL_HANGAR
Definition cp_building.h:60
@ B_DEFENCE_MISSILE
Definition cp_building.h:65
@ B_ALIEN_CONTAINMENT
Definition cp_building.h:59
@ B_ANTIMATTER
Definition cp_building.h:63
memPool_t * cp_campaignPool
ccs_t ccs
Header file for single player campaign control.
const cgame_import_t * cgi
technology_t * RS_GetTechByID(const char *id)
return a pointer to the technology identified by given id string
technology_t * RS_GetTechByProvided(const char *idProvided)
returns a pointer to the item tech (as listed in "provides")
Campaign geoscape time header.
#define DEBUG_CLIENT
Definition defines.h:59
level_locals_t level
Definition g_main.cpp:38
voidpf void uLong size
Definition ioapi.h:42
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
Shared parsing functions.
QGL_EXTERN int GLboolean GLfloat * v
Definition r_gl.h:120
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLint GLenum type
Definition r_gl.h:94
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
@ V_BOOL
Definition scripts.h:50
@ V_FLOAT
Definition scripts.h:54
@ V_TRANSLATION_STRING
Definition scripts.h:59
@ V_HUNK_STRING
Definition scripts.h:69
@ V_NULL
Definition scripts.h:49
@ V_INT
Definition scripts.h:52
@ V_POS
Definition scripts.h:55
#define MEMBER_SIZEOF(TYPE, MEMBER)
Definition scripts.h:34
#define Q_strvalid(string)
Definition shared.h:141
#define Q_streq(a, b)
Definition shared.h:136
#define OBJZERO(obj)
Definition shared.h:178
A base with all it's data.
Definition cp_base.h:84
int idx
Definition cp_base.h:85
A building with all it's data.
Definition cp_building.h:73
struct building_s * tpl
Definition cp_building.h:75
vec2_t size
Definition cp_building.h:82
const char * image
Definition cp_building.h:80
char * name
Definition cp_building.h:79
const struct building_s * dependsBuilding
char * onEnable
Definition cp_building.h:99
buildingType_t buildingType
struct base_s * base
Definition cp_building.h:76
char * onDisable
class DateTime timeStart
Definition cp_building.h:91
const char * pedia
Definition cp_building.h:80
const char * id
Definition cp_building.h:78
char * onConstruct
Definition cp_building.h:97
char * onDestroy
Definition cp_building.h:98
struct technology_s * tech
buildingType_t type
This is the technology parsed from research.ufo.