Bug Summary

File:client/cgame/campaign/cp_building.cpp
Location:line 211, column 6
Description:Value stored to 'token' is never read

Annotated Source Code

1/**
2 * @file
3 * @brief Base building related stuff.
4 */
5
6/*
7Copyright (C) 2002-2011 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 "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 */
36bool 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 */
55float 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 */
70buildingType_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 */
112static 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 */
147void 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 */
257bool 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 */
289building_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 */
309building_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 */
327bool 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 */
347bool 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}