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