File: | client/cgame/campaign/cp_building.cpp |
Location: | line 211, column 6 |
Description: | Value stored to 'token' is never read |
1 | /** |
2 | * @file |
3 | * @brief Base building related stuff. |
4 | */ |
5 | |
6 | /* |
7 | Copyright (C) 2002-2011 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 | |
31 | /** |
32 | * @brief Returns if a building is fully buildt up |
33 | * @param[in] building Pointer to the building to check |
34 | * @note it always return @c true for buildings with {0, 0} timeStart |
35 | */ |
36 | bool B_IsBuildingBuiltUp (const building_t *building) |
37 | { |
38 | date_t due; |
39 | |
40 | if (!building) |
41 | return false; |
42 | if (building->timeStart.day == 0 && building->timeStart.sec == 0) |
43 | return true; |
44 | due = building->timeStart; |
45 | due.day += building->buildTime; |
46 | if (Date_IsDue(&due)) |
47 | return true; |
48 | return false; |
49 | } |
50 | |
51 | /** |
52 | * @brief Returns the time remaining time of a building construction |
53 | * @param[in] building Pointer to the building to check |
54 | */ |
55 | float B_GetConstructionTimeRemain (const building_t * building) |
56 | { |
57 | date_t diff = Date_Substract(building->timeStart, ccs.date); |
58 | diff.day += building->buildTime; |
59 | return diff.day + (float)diff.sec / SECONDS_PER_DAY86400; |
60 | } |
61 | |
62 | /** |
63 | * @brief Returns the building type for a given building identified by its building id |
64 | * from the ufo script files |
65 | * @sa B_ParseBuildings |
66 | * @sa B_GetBuildingType |
67 | * @param[in] buildingID The script building id that should get converted into the enum value |
68 | * @note Do not use B_GetBuildingType here, this is also used for parsing the types! |
69 | */ |
70 | buildingType_t B_GetBuildingTypeByBuildingID (const char *buildingID) |
71 | { |
72 | if (Q_streq(buildingID, "lab")(strcmp(buildingID, "lab") == 0)) { |
73 | return B_LAB; |
74 | } else if (Q_streq(buildingID, "hospital")(strcmp(buildingID, "hospital") == 0)) { |
75 | return B_HOSPITAL; |
76 | } else if (Q_streq(buildingID, "aliencont")(strcmp(buildingID, "aliencont") == 0)) { |
77 | return B_ALIEN_CONTAINMENT; |
78 | } else if (Q_streq(buildingID, "workshop")(strcmp(buildingID, "workshop") == 0)) { |
79 | return B_WORKSHOP; |
80 | } else if (Q_streq(buildingID, "storage")(strcmp(buildingID, "storage") == 0)) { |
81 | return B_STORAGE; |
82 | } else if (Q_streq(buildingID, "hangar")(strcmp(buildingID, "hangar") == 0)) { |
83 | return B_HANGAR; |
84 | } else if (Q_streq(buildingID, "smallhangar")(strcmp(buildingID, "smallhangar") == 0)) { |
85 | return B_SMALL_HANGAR; |
86 | } else if (Q_streq(buildingID, "quarters")(strcmp(buildingID, "quarters") == 0)) { |
87 | return B_QUARTERS; |
88 | } else if (Q_streq(buildingID, "power")(strcmp(buildingID, "power") == 0)) { |
89 | return B_POWER; |
90 | } else if (Q_streq(buildingID, "command")(strcmp(buildingID, "command") == 0)) { |
91 | return B_COMMAND; |
92 | } else if (Q_streq(buildingID, "amstorage")(strcmp(buildingID, "amstorage") == 0)) { |
93 | return B_ANTIMATTER; |
94 | } else if (Q_streq(buildingID, "entrance")(strcmp(buildingID, "entrance") == 0)) { |
95 | return B_ENTRANCE; |
96 | } else if (Q_streq(buildingID, "missile")(strcmp(buildingID, "missile") == 0)) { |
97 | return B_DEFENCE_MISSILE; |
98 | } else if (Q_streq(buildingID, "laser")(strcmp(buildingID, "laser") == 0)) { |
99 | return B_DEFENCE_LASER; |
100 | } else if (Q_streq(buildingID, "radar")(strcmp(buildingID, "radar") == 0)) { |
101 | return B_RADAR; |
102 | } |
103 | return MAX_BUILDING_TYPE; |
104 | } |
105 | |
106 | /** |
107 | * @brief Holds the names of valid entries in the basemanagement.ufo file. |
108 | * |
109 | * The valid definition names for BUILDINGS (building_t) in the basemanagement.ufo file. |
110 | * to the appropriate values in the corresponding struct |
111 | */ |
112 | static const value_t valid_building_vars[] = { |
113 | {"map_name", V_HUNK_STRING, offsetof(building_t, mapPart)__builtin_offsetof(building_t, mapPart), 0}, /**< Name of the map file for generating basemap. */ |
114 | {"max_count", V_INT, offsetof(building_t, maxCount)__builtin_offsetof(building_t, maxCount), MEMBER_SIZEOF(building_t, maxCount)sizeof(((building_t *)0)->maxCount)}, /**< How many building of the same type allowed? */ |
115 | {"level", V_FLOAT, offsetof(building_t, level)__builtin_offsetof(building_t, level), MEMBER_SIZEOF(building_t, level)sizeof(((building_t *)0)->level)}, /**< building level */ |
116 | {"name", V_TRANSLATION_STRING, offsetof(building_t, name)__builtin_offsetof(building_t, name), 0}, /**< The displayed building name. */ |
117 | {"tech", V_HUNK_STRING, offsetof(building_t, pedia)__builtin_offsetof(building_t, pedia), 0}, /**< The pedia-id string for the associated pedia entry. */ |
118 | {"status", V_INT, offsetof(building_t, buildingStatus)__builtin_offsetof(building_t, buildingStatus), MEMBER_SIZEOF(building_t, buildingStatus)sizeof(((building_t *)0)->buildingStatus)}, /**< The current status of the building. */ |
119 | {"image", V_HUNK_STRING, offsetof(building_t, image)__builtin_offsetof(building_t, image), 0}, /**< Identifies the image for the building. */ |
120 | {"size", V_POS, offsetof(building_t, size)__builtin_offsetof(building_t, size), MEMBER_SIZEOF(building_t, size)sizeof(((building_t *)0)->size)}, /**< Building size. */ |
121 | {"fixcosts", V_INT, offsetof(building_t, fixCosts)__builtin_offsetof(building_t, fixCosts), MEMBER_SIZEOF(building_t, fixCosts)sizeof(((building_t *)0)->fixCosts)}, /**< Cost to build. */ |
122 | {"varcosts", V_INT, offsetof(building_t, varCosts)__builtin_offsetof(building_t, varCosts), MEMBER_SIZEOF(building_t, varCosts)sizeof(((building_t *)0)->varCosts)}, /**< Costs that will come up by using the building. */ |
123 | {"build_time", V_INT, offsetof(building_t, buildTime)__builtin_offsetof(building_t, buildTime), MEMBER_SIZEOF(building_t, buildTime)sizeof(((building_t *)0)->buildTime)}, /**< How many days it takes to construct the building. */ |
124 | {"starting_employees", V_INT, offsetof(building_t, maxEmployees)__builtin_offsetof(building_t, maxEmployees), MEMBER_SIZEOF(building_t, maxEmployees)sizeof(((building_t *)0)->maxEmployees)}, /**< How many employees to hire on construction in the first base. */ |
125 | {"capacity", V_INT, offsetof(building_t, capacity)__builtin_offsetof(building_t, capacity), MEMBER_SIZEOF(building_t, capacity)sizeof(((building_t *)0)->capacity)}, /**< A size value that is used by many buildings in a different way. */ |
126 | |
127 | /*event handler functions */ |
128 | {"onconstruct", V_HUNK_STRING, offsetof(building_t, onConstruct)__builtin_offsetof(building_t, onConstruct), 0}, /**< Event handler. */ |
129 | {"ondestroy", V_HUNK_STRING, offsetof(building_t, onDestroy)__builtin_offsetof(building_t, onDestroy), 0}, /**< Event handler. */ |
130 | {"onenable", V_HUNK_STRING, offsetof(building_t, onEnable)__builtin_offsetof(building_t, onEnable), 0}, /**< Event handler. */ |
131 | {"ondisable", V_HUNK_STRING, offsetof(building_t, onDisable)__builtin_offsetof(building_t, onDisable), 0}, /**< Event handler. */ |
132 | {"mandatory", V_BOOL, offsetof(building_t, mandatory)__builtin_offsetof(building_t, mandatory), MEMBER_SIZEOF(building_t, mandatory)sizeof(((building_t *)0)->mandatory)}, /**< Automatically construct this building when a base is set up. Must also set the pos-flag. */ |
133 | {NULL__null, V_NULL, 0, 0} |
134 | }; |
135 | |
136 | /** |
137 | * @brief Copies an entry from the building description file into the list of building types. |
138 | * @note Parses one "building" entry in the basemanagement.ufo file and writes |
139 | * it into the next free entry in bmBuildings[0], which is the list of buildings |
140 | * in the first base (building_t). |
141 | * @param[in] name Unique script id of a building. This is parsed from "building xxx" -> id=xxx. |
142 | * @param[in] text the whole following text that is part of the "building" item definition in .ufo. |
143 | * @param[in] link Bool value that decides whether to link the tech pointer in or not |
144 | * @sa CL_ParseScriptFirst (link is false here) |
145 | * @sa CL_ParseScriptSecond (link it true here) |
146 | */ |
147 | void B_ParseBuildings (const char *name, const char **text, bool link) |
148 | { |
149 | building_t *building; |
150 | technology_t *techLink; |
151 | const char *errhead = "B_ParseBuildings: unexpected end of file (names "; |
152 | const char *token; |
153 | |
154 | /* get id list body */ |
155 | token = Com_Parse(text); |
156 | if (!*text || *token != '{') { |
157 | Com_Printf("B_ParseBuildings: building \"%s\" without body ignored\n", name); |
158 | return; |
159 | } |
160 | |
161 | if (ccs.numBuildingTemplates >= MAX_BUILDINGS32) |
162 | Com_Error(ERR_DROP1, "B_ParseBuildings: too many buildings"); |
163 | |
164 | if (!link) { |
165 | int i; |
166 | for (i = 0; i < ccs.numBuildingTemplates; i++) { |
167 | if (Q_streq(ccs.buildingTemplates[i].id, name)(strcmp(ccs.buildingTemplates[i].id, name) == 0)) { |
168 | Com_Printf("B_ParseBuildings: Second building with same name found (%s) - second ignored\n", name); |
169 | return; |
170 | } |
171 | } |
172 | |
173 | /* new entry */ |
174 | building = &ccs.buildingTemplates[ccs.numBuildingTemplates]; |
175 | OBJZERO(*building)(memset(&((*building)), (0), sizeof((*building)))); |
176 | building->id = Mem_PoolStrDup(name, cp_campaignPool, 0)_Mem_PoolStrDup((name),(cp_campaignPool),(0),"src/client/cgame/campaign/cp_building.cpp" ,176); |
177 | |
178 | Com_DPrintf(DEBUG_CLIENT0x20, "...found building %s\n", building->id); |
179 | |
180 | /* set standard values */ |
181 | building->tpl = building; /* Self-link just in case ... this way we can check if it is a template or not. */ |
182 | building->idx = -1; /* No entry in buildings list (yet). */ |
183 | building->base = NULL__null; |
184 | building->buildingType = MAX_BUILDING_TYPE; |
185 | building->dependsBuilding = NULL__null; |
186 | building->maxCount = -1; /* Default: no limit */ |
187 | building->size[0] = 1; |
188 | building->size[1] = 1; |
189 | |
190 | ccs.numBuildingTemplates++; |
191 | do { |
192 | /* get the name type */ |
193 | token = Com_EParse(text, errhead, name); |
194 | if (!*text) |
195 | break; |
196 | if (*token == '}') |
197 | break; |
198 | |
199 | /* get values */ |
200 | if (Q_streq(token, "type")(strcmp(token, "type") == 0)) { |
201 | token = Com_EParse(text, errhead, name); |
202 | if (!*text) |
203 | return; |
204 | |
205 | building->buildingType = B_GetBuildingTypeByBuildingID(token); |
206 | if (building->buildingType >= MAX_BUILDING_TYPE) |
207 | Com_Printf("didn't find buildingType '%s'\n", token); |
208 | } else { |
209 | /* no linking yet */ |
210 | if (Q_streq(token, "depends")(strcmp(token, "depends") == 0)) { |
211 | token = Com_EParse(text, errhead, name); |
Value stored to 'token' is never read | |
212 | if (!*text) |
213 | return; |
214 | } else { |
215 | if (!Com_ParseBlockToken(name, text, building, valid_building_vars, cp_campaignPool, token)) |
216 | Com_Printf("B_ParseBuildings: unknown token \"%s\" ignored (building %s)\n", token, name); |
217 | } |
218 | } |
219 | } while (*text); |
220 | if (building->size[0] < 1 || building->size[1] < 1 || building->size[0] >= BASE_SIZE5 || building->size[1] >= BASE_SIZE5) { |
221 | Com_Printf("B_ParseBuildings: Invalid size for building %s (%i, %i)\n", building->id, (int)building->size[0], (int)building->size[1]); |
222 | ccs.numBuildingTemplates--; |
223 | } |
224 | } else { |
225 | building = B_GetBuildingTemplate(name); |
226 | if (!building) |
227 | Com_Error(ERR_DROP1, "B_ParseBuildings: Could not find building with id %s\n", name); |
228 | |
229 | techLink = RS_GetTechByProvided(name); |
230 | if (techLink) |
231 | building->tech = techLink; |
232 | |
233 | do { |
234 | /* get the name type */ |
235 | token = Com_EParse(text, errhead, name); |
236 | if (!*text) |
237 | break; |
238 | if (*token == '}') |
239 | break; |
240 | /* get values */ |
241 | if (Q_streq(token, "depends")(strcmp(token, "depends") == 0)) { |
242 | const building_t *dependsBuilding = B_GetBuildingTemplate(Com_EParse(text, errhead, name)); |
243 | if (!dependsBuilding) |
244 | Com_Error(ERR_DROP1, "Could not find building depend of %s\n", building->id); |
245 | building->dependsBuilding = dependsBuilding; |
246 | if (!*text) |
247 | return; |
248 | } |
249 | } while (*text); |
250 | } |
251 | } |
252 | |
253 | /** |
254 | * @brief Checks the parsed buildings for errors |
255 | * @return false if there are errors - true otherwise |
256 | */ |
257 | bool B_BuildingScriptSanityCheck (void) |
258 | { |
259 | int i, error = 0; |
260 | building_t* b; |
261 | |
262 | for (i = 0, b = ccs.buildingTemplates; i < ccs.numBuildingTemplates; i++, b++) { |
263 | if (!b->name) { |
264 | error++; |
265 | Com_Printf("...... no name for building '%s' given\n", b->id); |
266 | } |
267 | if (!b->image) { |
268 | error++; |
269 | Com_Printf("...... no image for building '%s' given\n", b->id); |
270 | } |
271 | if (!b->pedia) { |
272 | error++; |
273 | Com_Printf("...... no pedia link for building '%s' given\n", b->id); |
274 | } else if (!RS_GetTechByID(b->pedia)) { |
275 | error++; |
276 | Com_Printf("...... could not get pedia entry tech (%s) for building '%s'\n", b->pedia, b->id); |
277 | } |
278 | } |
279 | |
280 | return !error; |
281 | } |
282 | |
283 | /** |
284 | * @brief Returns the building in the global building-types list that has the unique name buildingID. |
285 | * @param[in] buildingName The unique id of the building (building_t->id). |
286 | * @return Building template pointer if found, NULL otherwise |
287 | * @todo make the returned pointer const |
288 | */ |
289 | building_t *B_GetBuildingTemplateSilent (const char *buildingName) |
290 | { |
291 | int i = 0; |
292 | |
293 | if (!buildingName) |
294 | return NULL__null; |
295 | for (i = 0; i < ccs.numBuildingTemplates; i++) { |
296 | building_t *buildingTemplate = &ccs.buildingTemplates[i]; |
297 | if (Q_streq(buildingTemplate->id, buildingName)(strcmp(buildingTemplate->id, buildingName) == 0)) |
298 | return buildingTemplate; |
299 | } |
300 | return NULL__null; |
301 | } |
302 | |
303 | /** |
304 | * @brief Returns the building in the global building-types list that has the unique name buildingID. |
305 | * @param[in] buildingName The unique id of the building (building_t->id). |
306 | * @return Building template pointer if found, NULL otherwise |
307 | * @todo make the returned pointer const |
308 | */ |
309 | building_t *B_GetBuildingTemplate (const char *buildingName) |
310 | { |
311 | if (!buildingName || buildingName[0] == '\0') { |
312 | Com_Printf("No, or empty building ID\n"); |
313 | return NULL__null; |
314 | } |
315 | |
316 | building_t *buildingTemplate = B_GetBuildingTemplateSilent(buildingName); |
317 | if (!buildingTemplate) |
318 | Com_Printf("Building %s not found\n", buildingName); |
319 | return buildingTemplate; |
320 | } |
321 | |
322 | /** |
323 | * @brief Check that the dependences of a building is operationnal |
324 | * @param[in] building Pointer to the building to check |
325 | * @return true if base contains needed dependence for entering building |
326 | */ |
327 | bool B_CheckBuildingDependencesStatus (const building_t* building) |
328 | { |
329 | assert(building)(__builtin_expect(!(building), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_building.cpp" , 329, "building") : (void)0); |
330 | |
331 | if (!building->dependsBuilding) |
332 | return true; |
333 | |
334 | /* Make sure the dependsBuilding pointer is really a template .. just in case. */ |
335 | assert(building->dependsBuilding == building->dependsBuilding->tpl)(__builtin_expect(!(building->dependsBuilding == building-> dependsBuilding->tpl), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_building.cpp" , 335, "building->dependsBuilding == building->dependsBuilding->tpl" ) : (void)0); |
336 | |
337 | return B_GetBuildingStatus(building->base, building->dependsBuilding->buildingType); |
338 | } |
339 | |
340 | /** |
341 | * @brief Run eventhandler script for a building |
342 | * @param[in] buildingTemplate Building type (template) to run event for |
343 | * @param[in] base The base to run it at |
344 | * @param[in] eventType Type of the event to run |
345 | * @return @c true if an event was fired @c false otherwise (the building may not have one) |
346 | */ |
347 | bool B_FireEvent (const building_t * buildingTemplate, const base_t * base, buildingEvent_t eventType) |
348 | { |
349 | const char *command = NULL__null; |
350 | |
351 | assert(buildingTemplate)(__builtin_expect(!(buildingTemplate), 0) ? __assert_rtn(__func__ , "src/client/cgame/campaign/cp_building.cpp", 351, "buildingTemplate" ) : (void)0); |
352 | assert(base)(__builtin_expect(!(base), 0) ? __assert_rtn(__func__, "src/client/cgame/campaign/cp_building.cpp" , 352, "base") : (void)0); |
353 | |
354 | switch (eventType) { |
355 | case B_ONCONSTRUCT: |
356 | command = buildingTemplate->onConstruct; |
357 | break; |
358 | case B_ONENABLE: |
359 | command = buildingTemplate->onEnable; |
360 | break; |
361 | case B_ONDISABLE: |
362 | command = buildingTemplate->onDisable; |
363 | break; |
364 | case B_ONDESTROY: |
365 | command = buildingTemplate->onDestroy; |
366 | break; |
367 | default: |
368 | Com_Error(ERR_DROP1, "B_FireEvent: Invalid Event\n"); |
369 | } |
370 | |
371 | if (command && command[0] != '\0') { |
372 | Cmd_ExecuteString(va("%s %i %i", command, base->idx, buildingTemplate->buildingType)); |
373 | return true; |
374 | } |
375 | |
376 | return false; |
377 | } |