File: | tools/ufo2map/check/checkentities.cpp |
Location: | line 197, column 2 |
Description: | Function call argument is an uninitialized value |
1 | /** |
2 | * @file |
3 | */ |
4 | |
5 | /* |
6 | All original material Copyright (C) 2002-2011 UFO: Alien Invasion. |
7 | |
8 | Copyright (C) 1997-2001 Id Software, Inc. |
9 | |
10 | This program is free software; you can redistribute it and/or |
11 | modify it under the terms of the GNU General Public License |
12 | as published by the Free Software Foundation; either version 2 |
13 | of the License, or (at your option) any later version. |
14 | |
15 | This program is distributed in the hope that it will be useful, |
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
18 | |
19 | See the GNU General Public License for more details. |
20 | |
21 | You should have received a copy of the GNU General Public License |
22 | along with this program; if not, write to the Free Software |
23 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
24 | |
25 | */ |
26 | |
27 | #include "checkentities.h" |
28 | #include "../../../shared/mathlib.h" |
29 | #include "../../../shared/entitiesdef.h" |
30 | #include "../common/shared.h" |
31 | #include "../bsp.h" |
32 | #include "checklib.h" |
33 | |
34 | #define MIN_TILE_SIZE256 256 /**< @todo take this datum from the correct place */ |
35 | |
36 | static int numToMoveToWorldspawn = 0; |
37 | |
38 | static void Check_MapSize (vec3_t mapSize); |
39 | mapbrush_t **Check_ExtraBrushesForWorldspawn (int *numBrushes); |
40 | |
41 | |
42 | /** |
43 | * @brief see if the entity is am actor start point |
44 | * @note starts with "info_" and contains "_start" |
45 | * @return true if this is a start point |
46 | */ |
47 | static bool Check_IsInfoStart(const char *classname) |
48 | { |
49 | return Q_strstart(classname, "info_") && strstr(classname, "_start"); |
50 | } |
51 | |
52 | /** |
53 | * @brief check alignment using abstract size and mandatory origin |
54 | * @return true if OK |
55 | * @todo check for brush intersection as well as alignment, and move |
56 | * to a good position if bad. |
57 | */ |
58 | static bool Check_InfoStartAligned (const entityDef_t *ed, const entity_t *e) |
59 | { |
60 | static int size[6]; |
61 | const entityKeyDef_t *sizeKd = ED_GetKeyDefEntity(ed, "size", 1); /* 1 means find abstract version of key */ |
62 | if (ED_GetIntVector(sizeKd, size, (int)(sizeof(size) / sizeof(int))) == ED_ERROR-1) |
63 | Sys_Error("%s", ED_GetLastError()); |
64 | |
65 | return (((int)e->origin[0] - size[0]) % UNIT_SIZE32 == 0) |
66 | && (((int)e->origin[1] - size[1]) % UNIT_SIZE32 == 0); |
67 | } |
68 | |
69 | /** |
70 | * @brief check targets exist (targetname), and check targetnames are targetted (target) |
71 | * @return false if there is a problem. |
72 | */ |
73 | static bool Check_TargetExists (const epair_t *kvp) |
74 | { |
75 | const char *thisKey = kvp->key; |
76 | const char *value = kvp->value; |
77 | const char *otherKey = Q_streq("target", thisKey)(strcmp("target", thisKey) == 0) ? "targetname" : "target"; |
78 | int i; |
79 | |
80 | for (i = 0; i < num_entities; i++) { |
81 | const entity_t *e = &entities[i]; |
82 | const char *searchVal = ValueForKey(e, otherKey); |
83 | |
84 | if (searchVal && Q_streq(searchVal, value)(strcmp(searchVal, value) == 0)) |
85 | return true; |
86 | } |
87 | |
88 | return false; |
89 | } |
90 | |
91 | static void Check_EntityWithBrushes (entity_t *e, const char *classname, int entnum) |
92 | { |
93 | if (!e->numbrushes) { |
94 | Check_Printf(VERB_CHECK, true, entnum, -1, "%s with no brushes given - will be deleted\n", classname); |
95 | e->skip = true; |
96 | return; |
97 | } |
98 | |
99 | if (e->numbrushes > 1 && Q_streq(classname, "func_breakable")(strcmp(classname, "func_breakable") == 0)) { |
100 | Check_Printf(VERB_CHECK, false, entnum, -1, "func_breakable with more than one brush given (might break pathfinding)\n"); |
101 | } |
102 | |
103 | if (e->numbrushes == 1 && Q_streq(classname, "func_group")(strcmp(classname, "func_group") == 0)) { |
104 | Check_Printf(VERB_CHECK, true, entnum, -1, "%s with one brush only - will be moved to worldspawn\n", classname); |
105 | numToMoveToWorldspawn++; |
106 | e->skip = true; |
107 | } |
108 | } |
109 | |
110 | /** |
111 | * @brief Perform an entity check |
112 | */ |
113 | void CheckEntities (void) |
114 | { |
115 | int i; |
116 | |
117 | Check_InitEntityDefs(); |
118 | |
119 | for (i = 0; i < num_entities; i++) { |
120 | entity_t *e = &entities[i]; |
121 | const char *name = ValueForKey(e, "classname"); |
122 | const entityDef_t *ed = ED_GetEntityDef(name); |
123 | const epair_t *kvp; |
124 | const entityKeyDef_t *kd; |
125 | |
126 | if (!ed) { /* check that a definition exists */ |
127 | Check_Printf(VERB_CHECK, false, i, -1, "Not defined in entities.ufo: %s\n", name); |
128 | continue; |
129 | } |
130 | |
131 | /* check alignment of info_.+_start */ |
132 | if (Check_IsInfoStart(name) && !Check_InfoStartAligned(ed, e)) |
133 | Check_Printf(VERB_CHECK, false, i, -1, "Misaligned %s\n", name); |
134 | |
135 | if (Q_strstart(name, "func_")) /* func_* entities should have brushes */ |
136 | Check_EntityWithBrushes(e, name, i); |
137 | |
138 | /* check all keys in the entity - make sure they are OK */ |
139 | for (kvp = e->epairs; kvp; kvp = kvp->next) { |
140 | kd = ED_GetKeyDefEntity(ed, kvp->key, 0); /* zero means ignore abstract (radiant only) keys */ |
141 | |
142 | if (!kd) { /* make sure it has a definition */ |
143 | Check_Printf(VERB_CHECK, false, i, -1, "Not defined in entities.ufo: %s in %s\n", kvp->key,name); |
144 | continue; |
145 | } |
146 | |
147 | if (ED_CheckKey(kd, kvp->value) == ED_ERROR-1) { /* check values against type and range definitions in entities.ufo */ |
148 | Check_Printf(VERB_CHECK, false, i, -1, "%s\n", ED_GetLastError()); |
149 | continue; |
150 | } |
151 | |
152 | if (Q_streq("target", kvp->key)(strcmp("target", kvp->key) == 0) || Q_streq("targetname", kvp->key)(strcmp("targetname", kvp->key) == 0)) { |
153 | if (!Check_TargetExists(kvp)) { |
154 | Check_Printf(VERB_CHECK, false, i, -1, |
155 | "%s with %s of %s: no corresponding entity with %s with matching value\n", |
156 | ed->classname, kvp->key, kvp->value, Q_streq("target", kvp->key)(strcmp("target", kvp->key) == 0) ? "targetname" : "target"); |
157 | } |
158 | } |
159 | } |
160 | |
161 | /* check keys in the entity definition - make sure mandatory ones are present */ |
162 | for (kd = ed->keyDefs; kd->name; kd++) { |
163 | if (kd->flags & ED_MANDATORY(1<<1)) { |
164 | const char *keyNameInEnt = ValueForKey(e, kd->name); |
165 | if (keyNameInEnt[0] == '\0') { |
166 | const char *defaultVal = kd->defaultVal; |
167 | const bool hasDefault = defaultVal ? true : false; |
168 | Check_Printf(VERB_CHECK, hasDefault, i, -1, "Mandatory key missing from entity: %s in %s", kd->name, name); |
169 | if (defaultVal) { |
170 | Check_Printf(VERB_CHECK, hasDefault, i, -1, ", supplying default: %s", defaultVal); |
171 | SetKeyValue(e, kd->name, defaultVal); |
172 | } |
173 | Check_Printf(VERB_CHECK, hasDefault, i, -1, "\n"); |
174 | } |
175 | } |
176 | } |
177 | } |
178 | } |
179 | |
180 | |
181 | /** |
182 | * @brief print map stats on -stats |
183 | */ |
184 | void Check_Stats(void) { |
185 | vec3_t worldSize; |
186 | int i, j; |
187 | int *entNums; |
188 | |
189 | Check_InitEntityDefs(); |
190 | |
191 | entNums = Mem_AllocTypeN(int, numEntityDefs)((int*)_Mem_Alloc(((sizeof(int) * (numEntityDefs))),true,(com_genericPool ),(0),"src/tools/ufo2map/check/checkentities.cpp",191)); |
192 | |
193 | Check_MapSize(worldSize); |
194 | Verb_Printf(VERB_NORMAL, " Number of brushes: %i\n",nummapbrushes); |
195 | Verb_Printf(VERB_NORMAL, " Number of planes: %i\n",nummapplanes); |
196 | Verb_Printf(VERB_NORMAL, " Number of brush sides: %i\n",nummapbrushsides); |
197 | Verb_Printf(VERB_NORMAL, " Map size (units): %.0f %.0f %.0f\n", worldSize[0], worldSize[1], worldSize[2]); |
Function call argument is an uninitialized value | |
198 | Verb_Printf(VERB_NORMAL, " Map size (fields): %.0f %.0f %.0f\n", worldSize[0] / UNIT_SIZE32, worldSize[1] / UNIT_SIZE32, worldSize[2] / UNIT_HEIGHT64); |
199 | Verb_Printf(VERB_NORMAL, " Map size (tiles): %.0f %.0f %.0f\n", worldSize[0] / (MIN_TILE_SIZE256), worldSize[1] / (MIN_TILE_SIZE256), worldSize[2] / UNIT_HEIGHT64); |
200 | Verb_Printf(VERB_NORMAL, " Number of entities: %i\n", num_entities); |
201 | |
202 | /* count number of each type of entity */ |
203 | for (i = 0; i < num_entities; i++) { |
204 | const char *name = ValueForKey(&entities[i], "classname"); |
205 | |
206 | for (j = 0; j < numEntityDefs; j++) |
207 | if (Q_streq(name, entityDefs[j].classname)(strcmp(name, entityDefs[j].classname) == 0)) { |
208 | entNums[j]++; |
209 | break; |
210 | } |
211 | if (j == numEntityDefs) { |
212 | Com_Printf("Check_Stats: entity '%s' not recognised\n", name); |
213 | } |
214 | |
215 | } |
216 | |
217 | /* print number of each type of entity */ |
218 | for (j = 0; j < numEntityDefs; j++) |
219 | if (entNums[j]) |
220 | Com_Printf("%27s: %i\n", entityDefs[j].classname, entNums[j]); |
221 | |
222 | Mem_Free(entNums)_Mem_Free((entNums),"src/tools/ufo2map/check/checkentities.cpp" ,222); |
223 | } |
224 | |
225 | |
226 | /** needs to be done here, on map brushes as worldMins and worldMaxs from levels.c |
227 | * are only calculated on BSPing |
228 | * @param[out] mapSize the returned size in map units |
229 | */ |
230 | static void Check_MapSize (vec3_t mapSize) |
231 | { |
232 | int i, bi, vi; |
233 | vec3_t mins, maxs; |
234 | |
235 | VectorSet(mins, 0, 0, 0)((mins)[0]=(0), (mins)[1]=(0), (mins)[2]=(0)); |
236 | VectorSet(maxs, 0, 0, 0)((maxs)[0]=(0), (maxs)[1]=(0), (maxs)[2]=(0)); |
237 | |
238 | for (i = 0; i < nummapbrushes; i++) { |
239 | const mapbrush_t *brush = &mapbrushes[i]; |
240 | |
241 | for (bi = 0; bi < brush->numsides; bi++) { |
242 | const winding_t *winding = brush->original_sides[bi].winding; |
243 | |
244 | for (vi = 0; vi < winding->numpoints; vi++) |
245 | AddPointToBounds(winding->p[vi], mins, maxs); |
246 | } |
247 | } |
248 | |
249 | VectorSubtract(maxs, mins, mapSize)((mapSize)[0]=(maxs)[0]-(mins)[0],(mapSize)[1]=(maxs)[1]-(mins )[1],(mapSize)[2]=(maxs)[2]-(mins)[2]); |
250 | } |
251 | |
252 | /** |
253 | * @brief single brushes in func_groups are moved to worldspawn. this function allocates space for |
254 | * pointers to those brushes. called when the .map is written back in map.c |
255 | * @return a pointer to the array of pointers to brushes to be included in worldspawn. |
256 | * @param[out] numBrushes the number of brushes |
257 | */ |
258 | mapbrush_t **Check_ExtraBrushesForWorldspawn (int *numBrushes) |
259 | { |
260 | int i, j; |
261 | mapbrush_t **brushesToMove; |
262 | |
263 | *numBrushes = numToMoveToWorldspawn; |
264 | |
265 | if (!numToMoveToWorldspawn) |
266 | return NULL__null; |
267 | |
268 | brushesToMove = Mem_AllocTypeN(mapbrush_t *, numToMoveToWorldspawn)((mapbrush_t **)_Mem_Alloc(((sizeof(mapbrush_t *) * (numToMoveToWorldspawn ))),true,(com_genericPool),(0),"src/tools/ufo2map/check/checkentities.cpp" ,268)); |
269 | if (!brushesToMove) |
270 | Sys_Error("Check_ExtraBrushesForWorldspawn: out of memory"); |
271 | |
272 | /* 0 is the world - start at 1 */ |
273 | for (i = 1, j = 0; i < num_entities; i++) { |
274 | const entity_t *e = &entities[i]; |
275 | const char *name = ValueForKey(e, "classname"); |
276 | |
277 | if (e->numbrushes == 1 && Q_streq(name, "func_group")(strcmp(name, "func_group") == 0)) { |
278 | assert(j < numToMoveToWorldspawn)(__builtin_expect(!(j < numToMoveToWorldspawn), 0) ? __assert_rtn (__func__, "src/tools/ufo2map/check/checkentities.cpp", 278, "j < numToMoveToWorldspawn" ) : (void)0); |
279 | brushesToMove[j++] = &mapbrushes[e->firstbrush]; |
280 | } |
281 | } |
282 | |
283 | return brushesToMove; |
284 | } |