1 /*
2 * entities.c
3 * $Id: entities.c,v 1.19 2007-12-14 16:41:23 sezero Exp $
4 *
5 * Copyright (C) 1996-1997 Id Software, Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 *
16 * See the GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include "q_stdinc.h"
24 #include "compiler.h"
25 #include "arch_def.h"
26 #include "cmdlib.h"
27 #include "mathlib.h"
28 #include "bspfile.h"
29 #include "entities.h"
30 #include "tyrlite.h"
31
32
33 entity_t entities[MAX_MAP_ENTITIES];
34 int num_entities;
35 int num_lights;
36 int num_clights;
37
38
39 /*
40 ==============================================================================
41
42 ENTITY FILE PARSING
43
44 If a light has a targetname, generate a unique style in the 32-63 range
45 ==============================================================================
46 */
47
48 static int numlighttargets;
49 static char lighttargets[32][64];
50
LightStyleForTargetname(char * targetname,qboolean alloc)51 static int LightStyleForTargetname (char *targetname, qboolean alloc)
52 {
53 int i;
54
55 for (i = 0 ; i < numlighttargets ; i++)
56 if (!strcmp (lighttargets[i], targetname))
57 return 32 + i;
58 if (!alloc)
59 return -1;
60 strcpy (lighttargets[i], targetname);
61 numlighttargets++;
62 return numlighttargets-1 + 32;
63 }
64
65
66 /*
67 ==================
68 MatchTargets
69 ==================
70 */
MatchTargets(void)71 static void MatchTargets (void)
72 {
73 int i, j;
74
75 for (i = 0 ; i < num_entities ; i++)
76 {
77 if (!entities[i].target[0])
78 continue;
79
80 for (j = 0 ; j < num_entities ; j++)
81 if (!strcmp(entities[j].targetname, entities[i].target))
82 {
83 entities[i].targetent = &entities[j];
84 break;
85 }
86 if (j == num_entities)
87 {
88 printf ("WARNING: entity at (%i,%i,%i) (%s) has unmatched target\n",
89 (int)entities[i].origin[0], (int)entities[i].origin[1],
90 (int)entities[i].origin[2], entities[i].classname);
91 continue;
92 }
93
94 // set the style on the source ent for switchable lights
95 if (entities[j].style)
96 {
97 char s[16];
98
99 entities[i].style = entities[j].style;
100 sprintf (s,"%i", entities[i].style);
101 SetKeyValue (&entities[i], "style", s);
102 }
103 }
104 }
105
106
107 /*
108 ==================
109 LoadEntities
110 ==================
111 */
LoadEntities(void)112 void LoadEntities (void)
113 {
114 const char *data;
115 entity_t *entity;
116 char key[64];
117 epair_t *epair;
118 vec_t v[3];
119 int i;
120
121 data = dentdata;
122 //
123 // start parsing
124 //
125 num_entities = 0;
126 num_lights = 0;
127
128 // go through all the entities
129 while (1)
130 {
131 // parse the opening brace
132 data = COM_Parse (data);
133 if (!data)
134 break;
135 if (com_token[0] != '{')
136 COM_Error ("%s: found %s when expecting {", __thisfunc__, com_token);
137
138 if (num_entities == MAX_MAP_ENTITIES)
139 COM_Error ("%s: MAX_MAP_ENTITIES", __thisfunc__);
140 entity = &entities[num_entities];
141 num_entities++;
142 entity->use_mangle = false;
143
144 // go through all the keys in this entity
145 while (1)
146 {
147 int c;
148
149 // parse key
150 data = COM_Parse (data);
151 if (!data)
152 COM_Error ("%s: EOF without closing brace", __thisfunc__);
153 if (!strcmp(com_token,"}"))
154 break;
155 strcpy (key, com_token);
156
157 // parse value
158 data = COM_Parse (data);
159 if (!data)
160 COM_Error ("%s: EOF without closing brace", __thisfunc__);
161 c = com_token[0];
162 if (c == '}')
163 COM_Error ("%s: closing brace without data", __thisfunc__);
164
165 epair = (epair_t *) SafeMalloc (sizeof(epair_t));
166 strcpy (epair->key, key);
167 strcpy (epair->value, com_token);
168 epair->next = entity->epairs;
169 entity->epairs = epair;
170
171 if (!strcmp(key, "classname"))
172 strcpy (entity->classname, com_token);
173 else if (!strcmp (key, "message"))
174 strcpy (entity->message, com_token);
175 else if (!strcmp (key, "netname"))
176 strcpy (entity->netname, com_token);
177 else if (!strcmp(key, "target"))
178 strcpy (entity->target, com_token);
179 else if (!strcmp(key, "targetname"))
180 strcpy (entity->targetname, com_token);
181 else if (!strcmp(key, "origin"))
182 {
183 if (sscanf(com_token, "%lf %lf %lf",
184 &entity->origin[0],
185 &entity->origin[1],
186 &entity->origin[2]) != 3)
187 COM_Error ("%s: not 3 values for origin", __thisfunc__);
188 }
189 else if (!strncmp(key, "light", 5))
190 {
191 entity->light = atof(com_token);
192 }
193 else if (!strncmp (key, "_light", 6))
194 {
195 entity->light = atof(com_token);
196 }
197 else if (!strcmp(key, "style"))
198 {
199 entity->style = atoi(com_token);
200 if ((unsigned int)entity->style > 254)
201 COM_Error ("Bad light style %i (must be 0-254)", entity->style);
202 }
203 else if (!strcmp(key, "angle"))
204 entity->angle = atof(com_token);
205 else if (!strcmp(key, "wait"))
206 entity->atten = atof(com_token);
207 else if (!strcmp(key, "delay"))
208 entity->formula = atoi(com_token);
209 else if (!strcmp(key, "mangle"))
210 {
211 if (sscanf(com_token, "%lf %lf %lf", &v[0], &v[1], &v[2]) != 3)
212 COM_Error ("%s: not 3 values for mangle", __thisfunc__);
213
214 /* Precalculate the direction vector */
215 entity->use_mangle = true;
216 entity->mangle[0] = cos(v[0]*Q_PI/180)*cos(v[1]*Q_PI/180);
217 entity->mangle[1] = sin(v[0]*Q_PI/180)*cos(v[1]*Q_PI/180);
218 entity->mangle[2] = sin(v[1]*Q_PI/180);
219 }
220 else if (!strcmp(key, "_color")/* don't work with hipnotic particle fields || !strcmp(key, "color")*/)
221 {
222 if (sscanf(com_token, "%lf %lf %lf", &v[0], &v[1], &v[2]) != 3)
223 COM_Error ("%s: not 3 values for color", __thisfunc__);
224 for (i = 0 ; i < 3 ; i++)
225 entity->lightcolor[i] = v[i];
226 }
227 else if (!strcmp(key, "_sunlight"))
228 sunlight = atof(com_token);
229 else if (!strcmp(key, "_sun_mangle"))
230 {
231 if (sscanf(com_token, "%lf %lf %lf", &v[0], &v[1], &v[2]) != 3)
232 COM_Error ("%s: not 3 values for _sun_mangle", __thisfunc__);
233
234 /* Precalculate sun vector and */
235 /* make it too large to fit into the map */
236 sunmangle[0] = cos(v[0]*Q_PI/180)*cos(v[1]*Q_PI/180);
237 sunmangle[1] = sin(v[0]*Q_PI/180)*cos(v[1]*Q_PI/180);
238 sunmangle[2] = sin(v[1]*Q_PI/180);
239 VectorNormalize(sunmangle);
240 VectorScale(sunmangle, -16384, sunmangle);
241 }
242 else if (!strcmp(key, "_sunlight_color"))
243 {
244 if (sscanf(com_token, "%lf %lf %lf",
245 &sunlight_color[0],
246 &sunlight_color[1],
247 &sunlight_color[2]) != 3)
248 COM_Error ("%s: not 3 values for _sunlight_color", __thisfunc__);
249 }
250 else if (!strcmp(key, "_minlight_color"))
251 {
252 if (sscanf(com_token, "%lf %lf %lf",
253 &minlight_color[0],
254 &minlight_color[1],
255 &minlight_color[2]) != 3)
256 COM_Error ("%s: not 3 values for _minlight_color", __thisfunc__);
257 }
258 }
259
260 // all fields have been parsed
261
262 if (!strncmp (entity->classname, "light", 5))
263 {
264 num_lights++;
265
266 if (!entity->light)
267 entity->light = DEFAULTLIGHTLEVEL;
268 if (entity->atten <= 0.0)
269 entity->atten = 1.0;
270 if (entity->formula < 0 || entity->formula > 3)
271 entity->formula = 0;
272
273 // set some colors based on hexen2 entity classname
274 if (!q_strncasecmp(entity->classname, "light_flame", 11) || /* _large_yellow, _small_yellow */
275 !q_strncasecmp(entity->classname, "light_torch", 11) || /* _castle, _rome, _meso, _egypt, _walltorch */
276 !q_strcasecmp (entity->classname, "light_gem"))
277 {
278 // make it orange
279 entity->lightcolor[0] = 255;
280 entity->lightcolor[1] = 128;
281 entity->lightcolor[2] = 64;
282 num_clights++;
283 }
284 else
285 {
286 // we don't need any color info to begin with
287 entity->lightcolor[0] = 0;
288 entity->lightcolor[1] = 0;
289 entity->lightcolor[2] = 0;
290 }
291
292 if (entity->targetname[0] && !entity->style)
293 {
294 char s[16];
295
296 entity->style = LightStyleForTargetname (entity->targetname, true);
297 sprintf (s,"%i", entity->style);
298 SetKeyValue (entity, "style", s);
299 }
300 }
301
302 // check for light value in worldspawn
303 if (!strcmp (entity->classname, "worldspawn"))
304 {
305 // mapname according to the message field requires line
306 // number entity->message to be read from strings.txt
307 if (strlen(entity->netname))
308 printf ("Map name : \"%s\"\n\n", entity->netname);
309 else if (strlen(entity->message) && atoi(entity->message) > 0)
310 printf ("Map name : at line %d in strings.txt\n\n", atoi(entity->message));
311 else
312 printf ("Map name : -- unknown --\n\n");
313
314 if (entity->light > 0 && !worldminlight)
315 {
316 worldminlight = entity->light;
317 printf("using minlight value %i from worldspawn.\n", worldminlight);
318 }
319 else if (worldminlight)
320 {
321 printf("Using minlight value %i from command line.\n", worldminlight);
322 }
323 }
324 }
325
326 printf ("%d entities read, %d are lights.\n", num_entities, num_lights);
327
328 MatchTargets ();
329 }
330
331
ValueForKey(entity_t * ent,const char * key)332 const char *ValueForKey (entity_t *ent, const char *key)
333 {
334 epair_t *ep;
335
336 for (ep = ent->epairs ; ep ; ep = ep->next)
337 {
338 if (!strcmp (ep->key, key) )
339 return ep->value;
340 }
341
342 return "";
343 }
344
SetKeyValue(entity_t * ent,const char * key,const char * value)345 void SetKeyValue (entity_t *ent, const char *key, const char *value)
346 {
347 epair_t *ep;
348
349 for (ep = ent->epairs ; ep ; ep = ep->next)
350 {
351 if (!strcmp (ep->key, key) )
352 {
353 strcpy (ep->value, value);
354 return;
355 }
356 }
357
358 ep = (epair_t *) SafeMalloc (sizeof(*ep));
359 ep->next = ent->epairs;
360 ent->epairs = ep;
361 strcpy (ep->key, key);
362 strcpy (ep->value, value);
363 }
364
FloatForKey(entity_t * ent,const char * key)365 float FloatForKey (entity_t *ent, const char *key)
366 {
367 const char *k;
368
369 k = ValueForKey (ent, key);
370 return (float)atof(k);
371 }
372
GetVectorForKey(entity_t * ent,const char * key,vec3_t vec)373 void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec)
374 {
375 const char *k;
376
377 k = ValueForKey (ent, key);
378 sscanf (k, "%lf %lf %lf", &vec[0], &vec[1], &vec[2]);
379 }
380
FindEntityWithKeyPair(const char * key,const char * value)381 entity_t *FindEntityWithKeyPair (const char *key, const char *value)
382 {
383 epair_t *ep;
384 entity_t *ent;
385 int i;
386
387 for (i = 0 ; i < num_entities ; i++)
388 {
389 ent = &entities[i];
390 for (ep = ent->epairs ; ep ; ep = ep->next)
391 {
392 if (!strcmp (ep->key, key))
393 {
394 if (!strcmp (ep->value, value))
395 return ent;
396 break;
397 }
398 }
399 }
400 return NULL;
401 }
402
403