1 /*
2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
4 
5 This file is part of Quake 2 Tools source code.
6 
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 
23 #include "qe3.h"
24 
ValueForKey(entity_t * ent,char * key)25 char 	*ValueForKey (entity_t *ent, char *key)
26 {
27 	epair_t	*ep;
28 
29 	for (ep=ent->epairs ; ep ; ep=ep->next)
30 		if (!strcmp (ep->key, key) )
31 			return ep->value;
32 	return "";
33 }
34 
SetKeyValue(entity_t * ent,char * key,char * value)35 void 	SetKeyValue (entity_t *ent, char *key, char *value)
36 {
37 	epair_t	*ep;
38 
39 	if (ent == NULL)
40 		return;
41 
42 	if (!key || !key[0])
43 		return;
44 
45 	for (ep=ent->epairs ; ep ; ep=ep->next)
46 		if (!strcmp (ep->key, key) )
47 		{
48 			free (ep->value);
49 			ep->value = qmalloc(strlen(value)+1);
50 			strcpy (ep->value, value);
51 			return;
52 		}
53 	ep = qmalloc (sizeof(*ep));
54 	ep->next = ent->epairs;
55 	ent->epairs = ep;
56 	ep->key = qmalloc(strlen(key)+1);
57 	strcpy (ep->key, key);
58 	ep->value = qmalloc(strlen(value)+1);
59 	strcpy (ep->value, value);
60 }
61 
DeleteKey(entity_t * ent,char * key)62 void 	DeleteKey (entity_t *ent, char *key)
63 {
64 	epair_t	**ep, *next;
65 
66 	ep = &ent->epairs;
67 	while (*ep)
68 	{
69 		next = *ep;
70 		if ( !strcmp (next->key, key) )
71 		{
72 			*ep = next->next;
73 			free(next->key);
74 			free(next->value);
75 			free(next);
76 			return;
77 		}
78 		ep = &next->next;
79 	}
80 }
81 
FloatForKey(entity_t * ent,char * key)82 float	FloatForKey (entity_t *ent, char *key)
83 {
84 	char	*k;
85 
86 	k = ValueForKey (ent, key);
87 	return atof(k);
88 }
89 
IntForKey(entity_t * ent,char * key)90 int IntForKey (entity_t *ent, char *key)
91 {
92 	char	*k;
93 
94 	k = ValueForKey (ent, key);
95 	return atoi(k);
96 }
97 
GetVectorForKey(entity_t * ent,char * key,vec3_t vec)98 void 	GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
99 {
100 	char	*k;
101 
102 	k = ValueForKey (ent, key);
103 	sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]);
104 }
105 
106 
107 /*
108 ===============
109 Entity_Free
110 
111 Frees the entity and any brushes is has.
112 The entity is removed from the global entities list.
113 ===============
114 */
Entity_Free(entity_t * e)115 void Entity_Free (entity_t *e)
116 {
117 	epair_t	*ep, *next;
118 
119 	while (e->brushes.onext != &e->brushes)
120 		Brush_Free (e->brushes.onext);
121 
122 	if (e->next)
123 	{
124 		e->next->prev = e->prev;
125 		e->prev->next = e->next;
126 	}
127 
128 	for (ep = e->epairs ; ep ; ep=next)
129 	{
130 		next = ep->next;
131 		free (ep);
132 	}
133 	free (e);
134 }
135 
136 /*
137 =================
138 ParseEpair
139 =================
140 */
ParseEpair(void)141 epair_t *ParseEpair (void)
142 {
143 	epair_t	*e;
144 
145 	e = qmalloc (sizeof(*e));
146 
147 	e->key = qmalloc(strlen(token)+1);
148 	strcpy (e->key, token);
149 
150 	GetToken (false);
151 	e->value = qmalloc(strlen(token)+1);
152 	strcpy (e->value, token);
153 
154 	return e;
155 }
156 
157 /*
158 ================
159 Entity_Parse
160 
161 If onlypairs is set, the classname info will not
162 be looked up, and the entity will not be added
163 to the global list.  Used for parsing the project.
164 ================
165 */
Entity_Parse(qboolean onlypairs)166 entity_t	*Entity_Parse (qboolean onlypairs)
167 {
168 	entity_t	*ent;
169 	eclass_t	*e;
170 	brush_t		*b;
171 	vec3_t		mins, maxs;
172 	epair_t		*ep;
173 	qboolean	has_brushes;
174 
175 	if (!GetToken (true))
176 		return NULL;
177 
178 	if (strcmp (token, "{") )
179 		Error ("ParseEntity: { not found");
180 
181 	ent = qmalloc (sizeof(*ent));
182 	ent->brushes.onext = ent->brushes.oprev = &ent->brushes;
183 
184 	do
185 	{
186 		if (!GetToken (true))
187 			Error ("ParseEntity: EOF without closing brace");
188 		if (!strcmp (token, "}") )
189 			break;
190 		if (!strcmp (token, "{") )
191 		{
192 			b = Brush_Parse ();
193 			b->owner = ent;
194 
195 			// add to the end of the entity chain
196 			b->onext = &ent->brushes;
197 			b->oprev = ent->brushes.oprev;
198 			ent->brushes.oprev->onext = b;
199 			ent->brushes.oprev = b;
200 		}
201 		else
202 		{
203 			ep = ParseEpair ();
204 			ep->next = ent->epairs;
205 			ent->epairs = ep;
206 		}
207 	} while (1);
208 
209 	if (onlypairs)
210 		return ent;
211 
212 	if (ent->brushes.onext == &ent->brushes)
213 		has_brushes = false;
214 	else
215 		has_brushes = true;
216 
217 	GetVectorForKey (ent, "origin", ent->origin);
218 
219 	e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes);
220 	ent->eclass = e;
221 	if (e->fixedsize)
222 	{	// fixed size entity
223 		if (ent->brushes.onext != &ent->brushes)
224 		{
225 			printf ("Warning: Fixed size entity with brushes\n");
226 #if 0
227 			while (ent->brushes.onext != &ent->brushes)
228 			{	// FIXME: this will free the entity and crash!
229 				Brush_Free (b);
230 			}
231 #endif
232 ent->brushes.next = ent->brushes.prev = &ent->brushes;
233 		}
234 		// create a custom brush
235 		VectorAdd (e->mins, ent->origin, mins);
236 		VectorAdd (e->maxs, ent->origin, maxs);
237 		b = Brush_Create (mins, maxs, &e->texdef);
238 		b->owner = ent;
239 
240 		b->onext = ent->brushes.onext;
241 		b->oprev = &ent->brushes;
242 		ent->brushes.onext->oprev = b;
243 		ent->brushes.onext = b;
244 	}
245 	else
246 	{	// brush entity
247 		if (ent->brushes.next == &ent->brushes)
248 			printf ("Warning: Brush entity with no brushes\n");
249 	}
250 
251 	// add all the brushes to the main list
252 	for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext)
253 	{
254 		b->next = active_brushes.next;
255 		active_brushes.next->prev = b;
256 		b->prev = &active_brushes;
257 		active_brushes.next = b;
258 	}
259 
260 	return ent;
261 }
262 
263 /*
264 ============
265 Entity_Write
266 ============
267 */
Entity_Write(entity_t * e,FILE * f,qboolean use_region)268 void Entity_Write (entity_t *e, FILE *f, qboolean use_region)
269 {
270 	epair_t		*ep;
271 	brush_t		*b;
272 	vec3_t		origin;
273 	char		text[128];
274 	int			count;
275 
276 	// if none of the entities brushes are in the region,
277 	// don't write the entity at all
278 	if (use_region)
279 	{
280 		// in region mode, save the camera position as playerstart
281 		if ( !strcmp(ValueForKey (e, "classname"), "info_player_start") )
282 		{
283 			fprintf (f, "{\n");
284 			fprintf (f, "\"classname\" \"info_player_start\"\n");
285 			fprintf (f, "\"origin\" \"%i %i %i\"\n", (int)camera.origin[0],
286 				(int)camera.origin[1], (int)camera.origin[2]);
287 			fprintf (f, "\"angle\" \"%i\"\n", (int)camera.angles[YAW]);
288 			fprintf (f, "}\n");
289 			return;
290 		}
291 
292 		for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
293 			if (!Map_IsBrushFiltered(b))
294 				break;	// got one
295 
296 		if (b == &e->brushes)
297 			return;		// nothing visible
298 	}
299 
300 	// if fixedsize, calculate a new origin based on the current
301 	// brush position
302 	if (e->eclass->fixedsize)
303 	{
304 		VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin);
305 		sprintf (text, "%i %i %i", (int)origin[0],
306 			(int)origin[1], (int)origin[2]);
307 		SetKeyValue (e, "origin", text);
308 	}
309 
310 	fprintf (f, "{\n");
311 	for (ep = e->epairs ; ep ; ep=ep->next)
312 		fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value);
313 
314 	if (!e->eclass->fixedsize)
315 	{
316 		count = 0;
317 		for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
318 		{
319 			if (!use_region || !Map_IsBrushFiltered (b))
320 			{
321 				fprintf (f, "// brush %i\n", count);
322 				count++;
323 				Brush_Write (b, f);
324 			}
325 		}
326 	}
327 	fprintf (f, "}\n");
328 }
329 
330 
331 
332 /*
333 ============
334 Entity_Create
335 
336 Creates a new entity out of the selected_brushes list.
337 If the entity class is fixed size, the brushes are only
338 used to find a midpoint.  Otherwise, the brushes have
339 their ownershi[ transfered to the new entity.
340 ============
341 */
Entity_Create(eclass_t * c)342 entity_t	*Entity_Create (eclass_t *c)
343 {
344 	entity_t	*e;
345 	brush_t		*b;
346 	vec3_t		mins, maxs;
347 	int			i;
348 
349 	// check to make sure the brushes are ok
350 
351 	for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
352 		if (b->owner != world_entity)
353 		{
354 			Sys_Printf ("Entity NOT created, brushes not all from world\n");
355 			Sys_Beep ();
356 			return NULL;
357 		}
358 
359 	// create it
360 
361 	e = qmalloc(sizeof(*e));
362 	e->brushes.onext = e->brushes.oprev = &e->brushes;
363 	e->eclass = c;
364 	SetKeyValue (e, "classname", c->name);
365 
366 	// add the entity to the entity list
367 	e->next = entities.next;
368 	entities.next = e;
369 	e->next->prev = e;
370 	e->prev = &entities;
371 
372 	if (c->fixedsize)
373 	{
374 		//
375 		// just use the selection for positioning
376 		//
377 		b = selected_brushes.next;
378 		for (i=0 ; i<3 ; i++)
379 			e->origin[i] = b->mins[i] - c->mins[i];
380 
381 		// create a custom brush
382 		VectorAdd (c->mins, e->origin, mins);
383 		VectorAdd (c->maxs, e->origin, maxs);
384 		b = Brush_Create (mins, maxs, &c->texdef);
385 
386 		Entity_LinkBrush (e, b);
387 
388 		// delete the current selection
389 		Select_Delete ();
390 
391 		// select the new brush
392 		b->next = b->prev = &selected_brushes;
393 		selected_brushes.next = selected_brushes.prev = b;
394 
395 		Brush_Build( b );
396 	}
397 	else
398 	{
399 		//
400 		// change the selected brushes over to the new entity
401 		//
402 		for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
403 		{
404 			Entity_UnlinkBrush (b);
405 			Entity_LinkBrush (e, b);
406 			Brush_Build( b );	// so the key brush gets a name
407 		}
408 	}
409 
410 	Sys_UpdateWindows (W_ALL);
411 	return e;
412 }
413 
414 
415 /*
416 ===========
417 Entity_LinkBrush
418 ===========
419 */
Entity_LinkBrush(entity_t * e,brush_t * b)420 void Entity_LinkBrush (entity_t *e, brush_t *b)
421 {
422 	if (b->oprev || b->onext)
423 		Error ("Entity_LinkBrush: Allready linked");
424 	b->owner = e;
425 
426 	b->onext = e->brushes.onext;
427 	b->oprev = &e->brushes;
428 	e->brushes.onext->oprev = b;
429 	e->brushes.onext = b;
430 }
431 
432 /*
433 ===========
434 Entity_UnlinkBrush
435 ===========
436 */
Entity_UnlinkBrush(brush_t * b)437 void Entity_UnlinkBrush (brush_t *b)
438 {
439 	if (!b->owner || !b->onext || !b->oprev)
440 		Error ("Entity_UnlinkBrush: Not currently linked");
441 	b->onext->oprev = b->oprev;
442 	b->oprev->onext = b->onext;
443 	b->onext = b->oprev = NULL;
444 	b->owner = NULL;
445 }
446 
447 
448 
449 /*
450 ===========
451 Entity_Clone
452 ===========
453 */
Entity_Clone(entity_t * e)454 entity_t	*Entity_Clone (entity_t *e)
455 {
456 	entity_t	*n;
457 	epair_t		*ep, *np;
458 
459 	n = qmalloc(sizeof(*n));
460 	n->brushes.onext = n->brushes.oprev = &n->brushes;
461 	n->eclass = e->eclass;
462 
463 	// add the entity to the entity list
464 	n->next = entities.next;
465 	entities.next = n;
466 	n->next->prev = n;
467 	n->prev = &entities;
468 
469 	for (ep = e->epairs ; ep ; ep=ep->next)
470 	{
471 		np = qmalloc(sizeof(*np));
472 		np->key = copystring(ep->key);
473 		np->value = copystring(ep->value);
474 		np->next = n->epairs;
475 		n->epairs = np;
476 	}
477 	return n;
478 }
479 
GetUniqueTargetId(int iHint)480 int GetUniqueTargetId(int iHint)
481 {
482 	int iMin, iMax, i;
483 	BOOL fFound;
484 	entity_t *pe;
485 
486 	fFound = FALSE;
487 	pe = entities.next;
488 	iMin = 0;
489 	iMax = 0;
490 
491 	for (; pe != NULL && pe != &entities ; pe = pe->next)
492 	{
493 		i = IntForKey(pe, "target");
494 		if (i)
495 		{
496 			iMin = min(i, iMin);
497 			iMax = max(i, iMax);
498 			if (i == iHint)
499 				fFound = TRUE;
500 		}
501 	}
502 
503 	if (fFound)
504 		return iMax + 1;
505 	else
506 		return iHint;
507 }
508 
FindEntity(char * pszKey,char * pszValue)509 entity_t *FindEntity(char *pszKey, char *pszValue)
510 {
511 	entity_t *pe;
512 
513 	pe = entities.next;
514 
515 	for (; pe != NULL && pe != &entities ; pe = pe->next)
516 	{
517 		if (!strcmp(ValueForKey(pe, pszKey), pszValue))
518 			return pe;
519 	}
520 
521 	return NULL;
522 }
523 
FindEntityInt(char * pszKey,int iValue)524 entity_t *FindEntityInt(char *pszKey, int iValue)
525 {
526 	entity_t *pe;
527 
528 	pe = entities.next;
529 
530 	for (; pe != NULL && pe != &entities ; pe = pe->next)
531 	{
532 		if (IntForKey(pe, pszKey) == iValue)
533 			return pe;
534 	}
535 
536 	return NULL;
537 }
538 
539