1 /* -------------------------------------------------------------------------------
2 
3 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 
6 This file is part of GtkRadiant.
7 
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12 
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 
22 ----------------------------------------------------------------------------------
23 
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
26 
27 ------------------------------------------------------------------------------- */
28 
29 
30 
31 /* marker */
32 #define BSPFILE_ABSTRACT_C
33 
34 
35 
36 /* dependencies */
37 #include "q3map2.h"
38 
39 
40 
41 
42 /* -------------------------------------------------------------------------------
43 
44 this file was copied out of the common directory in order to not break
45 compatibility with the q3map 1.x tree. it was moved out in order to support
46 the raven bsp format (RBSP) used in soldier of fortune 2 and jedi knight 2.
47 
48 since each game has its own set of particular features, the data structures
49 below no longer directly correspond to the binary format of a particular game.
50 
51 the translation will be done at bsp load/save time to keep any sort of
52 special-case code messiness out of the rest of the program.
53 
54 ------------------------------------------------------------------------------- */
55 
56 
57 
58 /* FIXME: remove the functions below that handle memory management of bsp file chunks */
59 
60 int numBSPDrawVertsBuffer = 0;
IncDrawVerts()61 void IncDrawVerts()
62 {
63 	numBSPDrawVerts++;
64 
65 	if(bspDrawVerts == 0)
66 	{
67 		numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS / 37;
68 
69 		bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");
70 
71 	}
72 	else if(numBSPDrawVerts > numBSPDrawVertsBuffer)
73 	{
74 		numBSPDrawVertsBuffer *= 3; // multiply by 1.5
75 		numBSPDrawVertsBuffer /= 2;
76 
77 		if(numBSPDrawVertsBuffer > MAX_MAP_DRAW_VERTS)
78 			numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS;
79 
80 		bspDrawVerts = realloc(bspDrawVerts, sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer);
81 
82 		if(!bspDrawVerts)
83 			Error( "realloc() failed (IncDrawVerts)");
84 	}
85 
86 	memset(bspDrawVerts + (numBSPDrawVerts - 1), 0, sizeof(bspDrawVert_t));
87 }
88 
SetDrawVerts(int n)89 void SetDrawVerts(int n)
90 {
91 	if(bspDrawVerts != 0)
92 		free(bspDrawVerts);
93 
94 	numBSPDrawVerts = n;
95 	numBSPDrawVertsBuffer = numBSPDrawVerts;
96 
97 	bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");
98 
99 	memset(bspDrawVerts, 0, n * sizeof(bspDrawVert_t));
100 }
101 
102 int numBSPDrawSurfacesBuffer = 0;
SetDrawSurfacesBuffer()103 void SetDrawSurfacesBuffer()
104 {
105 	if(bspDrawSurfaces != 0)
106 		free(bspDrawSurfaces);
107 
108 	numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
109 
110 	bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");
111 
112 	memset(bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof(bspDrawVert_t));
113 }
114 
SetDrawSurfaces(int n)115 void SetDrawSurfaces(int n)
116 {
117 	if(bspDrawSurfaces != 0)
118 		free(bspDrawSurfaces);
119 
120 	numBSPDrawSurfaces = n;
121 	numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
122 
123 	bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");
124 
125 	memset(bspDrawSurfaces, 0, n * sizeof(bspDrawVert_t));
126 }
127 
BSPFilesCleanup()128 void BSPFilesCleanup()
129 {
130 	if(bspDrawVerts != 0)
131 		free(bspDrawVerts);
132 	if(bspDrawSurfaces != 0)
133 		free(bspDrawSurfaces);
134 	if(bspLightBytes != 0)
135 		free(bspLightBytes);
136 	if(bspGridPoints != 0)
137 		free(bspGridPoints);
138 }
139 
140 
141 
142 
143 
144 
145 /*
146 SwapBlock()
147 if all values are 32 bits, this can be used to swap everything
148 */
149 
SwapBlock(int * block,int size)150 void SwapBlock( int *block, int size )
151 {
152 	int		i;
153 
154 
155 	/* dummy check */
156 	if( block == NULL )
157 		return;
158 
159 	/* swap */
160 	size >>= 2;
161 	for( i = 0; i < size; i++ )
162 		block[ i ] = LittleLong( block[ i ] );
163 }
164 
165 
166 
167 /*
168 SwapBSPFile()
169 byte swaps all data in the abstract bsp
170 */
171 
SwapBSPFile(void)172 void SwapBSPFile( void )
173 {
174 	int		i, j;
175 
176 
177 	/* models */
178 	SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) );
179 
180 	/* shaders (don't swap the name) */
181 	for( i = 0; i < numBSPShaders ; i++ )
182 	{
183 		bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
184 		bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
185 	}
186 
187 	/* planes */
188 	SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
189 
190 	/* nodes */
191 	SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
192 
193 	/* leafs */
194 	SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
195 
196 	/* leaffaces */
197 	SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
198 
199 	/* leafbrushes */
200 	SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
201 
202 	// brushes
203 	SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
204 
205 	// brushsides
206 	SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
207 
208 	// vis
209 	((int*) &bspVisBytes)[ 0 ] = LittleLong( ((int*) &bspVisBytes)[ 0 ] );
210 	((int*) &bspVisBytes)[ 1 ] = LittleLong( ((int*) &bspVisBytes)[ 1 ] );
211 
212 	/* drawverts (don't swap colors) */
213 	for( i = 0; i < numBSPDrawVerts; i++ )
214 	{
215 		bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
216 		bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
217 		bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
218 		bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
219 		bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
220 		bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
221 		bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
222 		bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
223 		for( j = 0; j < MAX_LIGHTMAPS; j++ )
224 		{
225 			bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
226 			bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
227 		}
228 	}
229 
230 	/* drawindexes */
231 	SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
232 
233 	/* drawsurfs */
234 	/* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
235 	SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
236 
237 	/* fogs */
238 	for( i = 0; i < numBSPFogs; i++ )
239 	{
240 		bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
241 		bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
242 	}
243 }
244 
245 
246 
247 /*
248 GetLumpElements()
249 gets the number of elements in a bsp lump
250 */
251 
GetLumpElements(bspHeader_t * header,int lump,int size)252 int GetLumpElements( bspHeader_t *header, int lump, int size )
253 {
254 	/* check for odd size */
255 	if( header->lumps[ lump ].length % size )
256 	{
257 		if( force )
258 		{
259 			Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
260 			return 0;
261 		}
262 		else
263 			Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
264 	}
265 
266 	/* return element count */
267 	return header->lumps[ lump ].length / size;
268 }
269 
270 
271 
272 /*
273 GetLump()
274 returns a pointer to the specified lump
275 */
276 
GetLump(bspHeader_t * header,int lump)277 void *GetLump( bspHeader_t *header, int lump )
278 {
279 	return (void*)( (byte*) header + header->lumps[ lump ].offset);
280 }
281 
282 
283 
284 /*
285 CopyLump()
286 copies a bsp file lump into a destination buffer
287 */
288 
CopyLump(bspHeader_t * header,int lump,void * dest,int size)289 int CopyLump( bspHeader_t *header, int lump, void *dest, int size )
290 {
291 	int		length, offset;
292 
293 
294 	/* get lump length and offset */
295 	length = header->lumps[ lump ].length;
296 	offset = header->lumps[ lump ].offset;
297 
298 	/* handle erroneous cases */
299 	if( length == 0 )
300 		return 0;
301 	if( length % size )
302 	{
303 		if( force )
304 		{
305 			Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
306 			return 0;
307 		}
308 		else
309 			Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
310 	}
311 
312 	/* copy block of memory and return */
313 	memcpy( dest, (byte*) header + offset, length );
314 	return length / size;
315 }
316 
317 
318 
319 /*
320 AddLump()
321 adds a lump to an outgoing bsp file
322 */
323 
AddLump(FILE * file,bspHeader_t * header,int lumpNum,const void * data,int length)324 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length )
325 {
326 	bspLump_t	*lump;
327 
328 
329 	/* add lump to bsp file header */
330 	lump = &header->lumps[ lumpNum ];
331 	lump->offset = LittleLong( ftell( file ) );
332 	lump->length = LittleLong( length );
333 
334 	/* write lump to file */
335 	SafeWrite( file, data, (length + 3) & ~3 );
336 }
337 
338 
339 
340 /*
341 LoadBSPFile()
342 loads a bsp file into memory
343 */
344 
LoadBSPFile(const char * filename)345 void LoadBSPFile( const char *filename )
346 {
347 	/* dummy check */
348 	if( game == NULL || game->load == NULL )
349 		Error( "LoadBSPFile: unsupported BSP file format" );
350 
351 	/* load it, then byte swap the in-memory version */
352 	game->load( filename );
353 	SwapBSPFile();
354 }
355 
356 
357 
358 /*
359 WriteBSPFile()
360 writes a bsp file
361 */
362 
WriteBSPFile(const char * filename)363 void WriteBSPFile( const char *filename )
364 {
365 	char	tempname[ 1024 ];
366 	time_t	tm;
367 
368 
369 	/* dummy check */
370 	if( game == NULL || game->write == NULL )
371 		Error( "WriteBSPFile: unsupported BSP file format" );
372 
373 	/* make fake temp name so existing bsp file isn't damaged in case write process fails */
374 	time( &tm );
375 	sprintf( tempname, "%s.%08X", filename, (int) tm );
376 
377 	/* byteswap, write the bsp, then swap back so it can be manipulated further */
378 	SwapBSPFile();
379 	game->write( tempname );
380 	SwapBSPFile();
381 
382 	/* replace existing bsp file */
383 	remove( filename );
384 	rename( tempname, filename );
385 }
386 
387 
388 
389 /*
390 PrintBSPFileSizes()
391 dumps info about current file
392 */
393 
PrintBSPFileSizes(void)394 void PrintBSPFileSizes( void )
395 {
396 	/* parse entities first */
397 	if( numEntities <= 0 )
398 		ParseEntities();
399 
400 	/* note that this is abstracted */
401 	Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
402 
403 	/* print various and sundry bits */
404 	Sys_Printf( "%9d models        %9d\n",
405 		numBSPModels, (int) (numBSPModels * sizeof( bspModel_t )) );
406 	Sys_Printf( "%9d shaders       %9d\n",
407 		numBSPShaders, (int) (numBSPShaders * sizeof( bspShader_t )) );
408 	Sys_Printf( "%9d brushes       %9d\n",
409 		numBSPBrushes, (int) (numBSPBrushes * sizeof( bspBrush_t )) );
410 	Sys_Printf( "%9d brushsides    %9d *\n",
411 		numBSPBrushSides, (int) (numBSPBrushSides * sizeof( bspBrushSide_t )) );
412 	Sys_Printf( "%9d fogs          %9d\n",
413 		numBSPFogs, (int) (numBSPFogs * sizeof( bspFog_t ) ) );
414 	Sys_Printf( "%9d planes        %9d\n",
415 		numBSPPlanes, (int) (numBSPPlanes * sizeof( bspPlane_t )) );
416 	Sys_Printf( "%9d entdata       %9d\n",
417 		numEntities, bspEntDataSize );
418 	Sys_Printf( "\n");
419 
420 	Sys_Printf( "%9d nodes         %9d\n",
421 		numBSPNodes, (int) (numBSPNodes * sizeof( bspNode_t)) );
422 	Sys_Printf( "%9d leafs         %9d\n",
423 		numBSPLeafs, (int) (numBSPLeafs * sizeof( bspLeaf_t )) );
424 	Sys_Printf( "%9d leafsurfaces  %9d\n",
425 		numBSPLeafSurfaces, (int) (numBSPLeafSurfaces * sizeof( *bspLeafSurfaces )) );
426 	Sys_Printf( "%9d leafbrushes   %9d\n",
427 		numBSPLeafBrushes, (int) (numBSPLeafBrushes * sizeof( *bspLeafBrushes )) );
428 	Sys_Printf( "\n");
429 
430 	Sys_Printf( "%9d drawsurfaces  %9d *\n",
431 		numBSPDrawSurfaces, (int) (numBSPDrawSurfaces * sizeof( *bspDrawSurfaces )) );
432 	Sys_Printf( "%9d drawverts     %9d *\n",
433 		numBSPDrawVerts, (int) (numBSPDrawVerts * sizeof( *bspDrawVerts )) );
434 	Sys_Printf( "%9d drawindexes   %9d\n",
435 		numBSPDrawIndexes, (int) (numBSPDrawIndexes * sizeof( *bspDrawIndexes )) );
436 	Sys_Printf( "\n");
437 
438 	Sys_Printf( "%9d lightmaps     %9d\n",
439 		numBSPLightBytes / (game->lightmapSize * game->lightmapSize * 3), numBSPLightBytes );
440 	Sys_Printf( "%9d lightgrid     %9d *\n",
441 		numBSPGridPoints, (int) (numBSPGridPoints * sizeof( *bspGridPoints )) );
442 	Sys_Printf( "          visibility    %9d\n",
443 		numBSPVisBytes );
444 }
445 
446 
447 
448 /* -------------------------------------------------------------------------------
449 
450 entity data handling
451 
452 ------------------------------------------------------------------------------- */
453 
454 
455 /*
456 StripTrailing()
457 strips low byte chars off the end of a string
458 */
459 
StripTrailing(char * e)460 void StripTrailing( char *e )
461 {
462 	char	*s;
463 
464 
465 	s = e + strlen( e ) - 1;
466 	while( s >= e && *s <= 32 )
467 	{
468 		*s = 0;
469 		s--;
470 	}
471 }
472 
473 
474 
475 /*
476 ParseEpair()
477 parses a single quoted "key" "value" pair into an epair struct
478 */
479 
ParseEPair(void)480 epair_t *ParseEPair( void )
481 {
482 	epair_t		*e;
483 
484 
485 	/* allocate and clear new epair */
486 	e = safe_malloc( sizeof( epair_t ) );
487 	memset( e, 0, sizeof( epair_t ) );
488 
489 	/* handle key */
490 	if( strlen( token ) >= (MAX_KEY - 1) )
491 		Error( "ParseEPair: token too long" );
492 
493 	e->key = copystring( token );
494 	GetToken( qfalse );
495 
496 	/* handle value */
497 	if( strlen( token ) >= MAX_VALUE - 1 )
498 		Error( "ParseEpar: token too long" );
499 	e->value = copystring( token );
500 
501 	/* strip trailing spaces that sometimes get accidentally added in the editor */
502 	StripTrailing( e->key );
503 	StripTrailing( e->value );
504 
505 	/* return it */
506 	return e;
507 }
508 
509 
510 
511 /*
512 ParseEntity()
513 parses an entity's epairs
514 */
515 
ParseEntity(void)516 qboolean ParseEntity( void )
517 {
518 	epair_t		*e;
519 
520 
521 	/* dummy check */
522 	if( !GetToken( qtrue ) )
523 		return qfalse;
524 	if( strcmp( token, "{" ) )
525 		Error( "ParseEntity: { not found" );
526 	if( numEntities == MAX_MAP_ENTITIES )
527 		Error( "numEntities == MAX_MAP_ENTITIES" );
528 
529 	/* create new entity */
530 	mapEnt = &entities[ numEntities ];
531 	numEntities++;
532 
533 	/* parse */
534 	while( 1 )
535 	{
536 		if( !GetToken( qtrue ) )
537 			Error( "ParseEntity: EOF without closing brace" );
538 		if( !EPAIR_STRCMP( token, "}" ) )
539 			break;
540 		e = ParseEPair();
541 		e->next = mapEnt->epairs;
542 		mapEnt->epairs = e;
543 	}
544 
545 	/* return to sender */
546 	return qtrue;
547 }
548 
549 
550 
551 /*
552 ParseEntities()
553 parses the bsp entity data string into entities
554 */
555 
ParseEntities(void)556 void ParseEntities( void )
557 {
558 	numEntities = 0;
559 	ParseFromMemory( bspEntData, bspEntDataSize );
560 	while( ParseEntity() );
561 
562 	/* ydnar: set number of bsp entities in case a map is loaded on top */
563 	numBSPEntities = numEntities;
564 }
565 
566 
567 
568 /*
569 UnparseEntities()
570 generates the dentdata string from all the entities.
571 this allows the utilities to add or remove key/value
572 pairs to the data created by the map editor
573 */
574 
UnparseEntities(void)575 void UnparseEntities( void )
576 {
577 	int			i;
578 	char		*buf, *end;
579 	epair_t		*ep;
580 	char		line[ 2048 ];
581 	char		key[ 1024 ], value[ 1024 ];
582 	const char	*value2;
583 
584 
585 	/* setup */
586 	buf = bspEntData;
587 	end = buf;
588 	*end = 0;
589 
590 	/* run through entity list */
591 	for( i = 0; i < numBSPEntities && i < numEntities; i++ )
592 	{
593 		/* get epair */
594 		ep = entities[ i ].epairs;
595 		if( ep == NULL )
596 			continue;	/* ent got removed */
597 
598 		/* ydnar: certain entities get stripped from bsp file */
599 		value2 = ValueForKey( &entities[ i ], "classname" );
600 		if( !Q_stricmp( value2, "misc_model" ) ||
601 			!Q_stricmp( value2, "_decal" ) ||
602 			!Q_stricmp( value2, "_skybox" ) )
603 			continue;
604 
605 		/* add beginning brace */
606 		strcat( end, "{\n" );
607 		end += 2;
608 
609 		/* walk epair list */
610 		for( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
611 		{
612 			/* copy and clean */
613 			strcpy( key, ep->key );
614 			StripTrailing( key );
615 			strcpy( value, ep->value );
616 			StripTrailing( value );
617 
618 			/* add to buffer */
619 			sprintf( line, "\"%s\" \"%s\"\n", key, value );
620 			strcat( end, line );
621 			end += strlen( line );
622 		}
623 
624 		/* add trailing brace */
625 		strcat( end,"}\n" );
626 		end += 2;
627 
628 		/* check for overflow */
629 		if( end > buf + MAX_MAP_ENTSTRING )
630 			Error( "Entity text too long" );
631 	}
632 
633 	/* set size */
634 	bspEntDataSize = end - buf + 1;
635 }
636 
637 
638 
639 /*
640 PrintEntity()
641 prints an entity's epairs to the console
642 */
643 
PrintEntity(const entity_t * ent)644 void PrintEntity( const entity_t *ent )
645 {
646 	epair_t	*ep;
647 
648 
649 	Sys_Printf( "------- entity %p -------\n", ent );
650 	for( ep = ent->epairs; ep != NULL; ep = ep->next )
651 		Sys_Printf( "%s = %s\n", ep->key, ep->value );
652 
653 }
654 
655 
656 
657 /*
658 SetKeyValue()
659 sets an epair in an entity
660 */
661 
SetKeyValue(entity_t * ent,const char * key,const char * value)662 void SetKeyValue( entity_t *ent, const char *key, const char *value )
663 {
664 	epair_t	*ep;
665 
666 
667 	/* check for existing epair */
668 	for( ep = ent->epairs; ep != NULL; ep = ep->next )
669 	{
670 		if( !EPAIR_STRCMP( ep->key, key ) )
671 		{
672 			free( ep->value );
673 			ep->value = copystring( value );
674 			return;
675 		}
676 	}
677 
678 	/* create new epair */
679 	ep = safe_malloc( sizeof( *ep ) );
680 	ep->next = ent->epairs;
681 	ent->epairs = ep;
682 	ep->key = copystring( key );
683 	ep->value = copystring( value );
684 }
685 
686 
687 
688 /*
689 ValueForKey()
690 gets the value for an entity key
691 */
692 
ValueForKey(const entity_t * ent,const char * key)693 const char *ValueForKey( const entity_t *ent, const char *key )
694 {
695 	epair_t	*ep;
696 
697 
698 	/* dummy check */
699 	if( ent == NULL )
700 		return "";
701 
702 	/* walk epair list */
703 	for( ep = ent->epairs; ep != NULL; ep = ep->next )
704 	{
705 		if( !EPAIR_STRCMP( ep->key, key ) )
706 			return ep->value;
707 	}
708 
709 	/* if no match, return empty string */
710 	return "";
711 }
712 
713 
714 
715 /*
716 IntForKey()
717 gets the integer point value for an entity key
718 */
719 
IntForKey(const entity_t * ent,const char * key)720 int IntForKey( const entity_t *ent, const char *key )
721 {
722 	const char	*k;
723 
724 
725 	k = ValueForKey( ent, key );
726 	return atoi( k );
727 }
728 
729 
730 
731 /*
732 FloatForKey()
733 gets the floating point value for an entity key
734 */
735 
FloatForKey(const entity_t * ent,const char * key)736 vec_t FloatForKey( const entity_t *ent, const char *key )
737 {
738 	const char	*k;
739 
740 
741 	k = ValueForKey( ent, key );
742 	return atof( k );
743 }
744 
745 
746 
747 /*
748 GetVectorForKey()
749 gets a 3-element vector value for an entity key
750 */
751 
GetVectorForKey(const entity_t * ent,const char * key,vec3_t vec)752 void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec )
753 {
754 	const char	*k;
755 	double		v1, v2, v3;
756 
757 
758 	/* get value */
759 	k = ValueForKey( ent, key );
760 
761 	/* scanf into doubles, then assign, so it is vec_t size independent */
762 	v1 = v2 = v3 = 0.0;
763 	sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
764 	vec[ 0 ] = v1;
765 	vec[ 1 ] = v2;
766 	vec[ 2 ] = v3;
767 }
768 
769 
770 
771 /*
772 FindTargetEntity()
773 finds an entity target
774 */
775 
FindTargetEntity(const char * target)776 entity_t *FindTargetEntity( const char *target )
777 {
778 	int			i;
779 	const char	*n;
780 
781 
782 	/* walk entity list */
783 	for( i = 0; i < numEntities; i++ )
784 	{
785 		n = ValueForKey( &entities[ i ], "targetname" );
786 		if ( !strcmp( n, target ) )
787 			return &entities[ i ];
788 	}
789 
790 	/* nada */
791 	return NULL;
792 }
793 
794 
795 
796 /*
797 GetEntityShadowFlags() - ydnar
798 gets an entity's shadow flags
799 note: does not set them to defaults if the keys are not found!
800 */
801 
GetEntityShadowFlags(const entity_t * ent,const entity_t * ent2,int * castShadows,int * recvShadows)802 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows )
803 {
804 	const char	*value;
805 
806 
807 	/* get cast shadows */
808 	if( castShadows != NULL )
809 	{
810 		value = ValueForKey( ent, "_castShadows" );
811 		if( value[ 0 ] == '\0' )
812 			value = ValueForKey( ent, "_cs" );
813 		if( value[ 0 ] == '\0' )
814 			value = ValueForKey( ent2, "_castShadows" );
815 		if( value[ 0 ] == '\0' )
816 			value = ValueForKey( ent2, "_cs" );
817 		if( value[ 0 ] != '\0' )
818 			*castShadows = atoi( value );
819 	}
820 
821 	/* receive */
822 	if( recvShadows != NULL )
823 	{
824 		value = ValueForKey( ent, "_receiveShadows" );
825 		if( value[ 0 ] == '\0' )
826 			value = ValueForKey( ent, "_rs" );
827 		if( value[ 0 ] == '\0' )
828 			value = ValueForKey( ent2, "_receiveShadows" );
829 		if( value[ 0 ] == '\0' )
830 			value = ValueForKey( ent2, "_rs" );
831 		if( value[ 0 ] != '\0' )
832 			*recvShadows = atoi( value );
833 	}
834 }
835 
836