]> icculus.org git repositories - divverent/netradiant.git/blob - tools/quake3/q3map2/bspfile_abstract.c
add the branch-manager for q3map2 too
[divverent/netradiant.git] / tools / quake3 / q3map2 / bspfile_abstract.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 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;
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
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;
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
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
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
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
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         /* advertisements */
245         for( i = 0; i < numBSPAds; i++ )
246         {
247                 bspAds[ i ].cellId = LittleLong( bspAds[ i ].cellId );
248                 bspAds[ i ].normal[ 0 ] = LittleFloat( bspAds[ i ].normal[ 0 ] );
249                 bspAds[ i ].normal[ 1 ] = LittleFloat( bspAds[ i ].normal[ 1 ] );
250                 bspAds[ i ].normal[ 2 ] = LittleFloat( bspAds[ i ].normal[ 2 ] );
251
252                 for( j = 0; j < 4; j++ ) 
253                 {
254                         bspAds[ i ].rect[j][ 0 ] = LittleFloat( bspAds[ i ].rect[j][ 0 ] );
255                         bspAds[ i ].rect[j][ 1 ] = LittleFloat( bspAds[ i ].rect[j][ 1 ] );
256                         bspAds[ i ].rect[j][ 2 ] = LittleFloat( bspAds[ i ].rect[j][ 2 ] );
257                 }
258
259                 //bspAds[ i ].model[ MAX_QPATH ];
260         }
261 }
262
263
264
265 /*
266 GetLumpElements()
267 gets the number of elements in a bsp lump
268 */
269
270 int GetLumpElements( bspHeader_t *header, int lump, int size )
271 {
272         /* check for odd size */
273         if( header->lumps[ lump ].length % size )
274         {
275                 if( force )
276                 {
277                         Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
278                         return 0;
279                 }
280                 else
281                         Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
282         }
283         
284         /* return element count */
285         return header->lumps[ lump ].length / size;
286 }
287
288
289
290 /*
291 GetLump()
292 returns a pointer to the specified lump
293 */
294
295 void *GetLump( bspHeader_t *header, int lump )
296 {
297         return (void*)( (byte*) header + header->lumps[ lump ].offset);
298 }
299
300
301
302 /*
303 CopyLump()
304 copies a bsp file lump into a destination buffer
305 */
306
307 int CopyLump( bspHeader_t *header, int lump, void *dest, int size )
308 {
309         int             length, offset;
310         
311         
312         /* get lump length and offset */
313         length = header->lumps[ lump ].length;
314         offset = header->lumps[ lump ].offset;
315         
316         /* handle erroneous cases */
317         if( length == 0 )
318                 return 0;
319         if( length % size )
320         {
321                 if( force )
322                 {
323                         Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
324                         return 0;
325                 }
326                 else
327                         Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
328         }
329         
330         /* copy block of memory and return */
331         memcpy( dest, (byte*) header + offset, length );
332         return length / size;
333 }
334
335
336
337 /*
338 AddLump()
339 adds a lump to an outgoing bsp file
340 */
341
342 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length )
343 {
344         bspLump_t       *lump;
345         
346         
347         /* add lump to bsp file header */
348         lump = &header->lumps[ lumpNum ];
349         lump->offset = LittleLong( ftell( file ) );
350         lump->length = LittleLong( length );
351         
352         /* write lump to file */
353         SafeWrite( file, data, (length + 3) & ~3 );
354 }
355
356
357
358 /*
359 LoadBSPFile()
360 loads a bsp file into memory
361 */
362
363 void LoadBSPFile( const char *filename )
364 {
365         /* dummy check */
366         if( game == NULL || game->load == NULL )
367                 Error( "LoadBSPFile: unsupported BSP file format" );
368         
369         /* load it, then byte swap the in-memory version */
370         game->load( filename );
371         SwapBSPFile();
372 }
373
374
375
376 /*
377 WriteBSPFile()
378 writes a bsp file
379 */
380
381 void WriteBSPFile( const char *filename )
382 {
383         char    tempname[ 1024 ];
384         time_t  tm;
385         
386         
387         /* dummy check */
388         if( game == NULL || game->write == NULL )
389                 Error( "WriteBSPFile: unsupported BSP file format" );
390         
391         /* make fake temp name so existing bsp file isn't damaged in case write process fails */
392         time( &tm );
393         sprintf( tempname, "%s.%08X", filename, (int) tm );
394         
395         /* byteswap, write the bsp, then swap back so it can be manipulated further */
396         SwapBSPFile();
397         game->write( tempname );
398         SwapBSPFile();
399         
400         /* replace existing bsp file */
401         remove( filename );
402         rename( tempname, filename );
403 }
404
405
406
407 /*
408 PrintBSPFileSizes()
409 dumps info about current file
410 */
411
412 void PrintBSPFileSizes( void )
413 {
414         /* parse entities first */
415         if( numEntities <= 0 )
416                 ParseEntities();
417         
418         /* note that this is abstracted */
419         Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
420         
421         /* print various and sundry bits */
422         Sys_Printf( "%9d models        %9d\n",
423                 numBSPModels, (int) (numBSPModels * sizeof( bspModel_t )) );
424         Sys_Printf( "%9d shaders       %9d\n",
425                 numBSPShaders, (int) (numBSPShaders * sizeof( bspShader_t )) );
426         Sys_Printf( "%9d brushes       %9d\n",
427                 numBSPBrushes, (int) (numBSPBrushes * sizeof( bspBrush_t )) );
428         Sys_Printf( "%9d brushsides    %9d *\n",
429                 numBSPBrushSides, (int) (numBSPBrushSides * sizeof( bspBrushSide_t )) );
430         Sys_Printf( "%9d fogs          %9d\n",
431                 numBSPFogs, (int) (numBSPFogs * sizeof( bspFog_t ) ) );
432         Sys_Printf( "%9d planes        %9d\n",
433                 numBSPPlanes, (int) (numBSPPlanes * sizeof( bspPlane_t )) );
434         Sys_Printf( "%9d entdata       %9d\n",
435                 numEntities, bspEntDataSize );
436         Sys_Printf( "\n");
437         
438         Sys_Printf( "%9d nodes         %9d\n",
439                 numBSPNodes, (int) (numBSPNodes * sizeof( bspNode_t)) );
440         Sys_Printf( "%9d leafs         %9d\n",
441                 numBSPLeafs, (int) (numBSPLeafs * sizeof( bspLeaf_t )) );
442         Sys_Printf( "%9d leafsurfaces  %9d\n",
443                 numBSPLeafSurfaces, (int) (numBSPLeafSurfaces * sizeof( *bspLeafSurfaces )) );
444         Sys_Printf( "%9d leafbrushes   %9d\n",
445                 numBSPLeafBrushes, (int) (numBSPLeafBrushes * sizeof( *bspLeafBrushes )) );
446         Sys_Printf( "\n");
447         
448         Sys_Printf( "%9d drawsurfaces  %9d *\n",
449                 numBSPDrawSurfaces, (int) (numBSPDrawSurfaces * sizeof( *bspDrawSurfaces )) );
450         Sys_Printf( "%9d drawverts     %9d *\n",
451                 numBSPDrawVerts, (int) (numBSPDrawVerts * sizeof( *bspDrawVerts )) );
452         Sys_Printf( "%9d drawindexes   %9d\n",
453                 numBSPDrawIndexes, (int) (numBSPDrawIndexes * sizeof( *bspDrawIndexes )) );
454         Sys_Printf( "\n");
455         
456         Sys_Printf( "%9d lightmaps     %9d\n",
457                 numBSPLightBytes / (game->lightmapSize * game->lightmapSize * 3), numBSPLightBytes );
458         Sys_Printf( "%9d lightgrid     %9d *\n",
459                 numBSPGridPoints, (int) (numBSPGridPoints * sizeof( *bspGridPoints )) );
460         Sys_Printf( "          visibility    %9d\n",
461                 numBSPVisBytes );
462 }
463
464
465
466 /* -------------------------------------------------------------------------------
467
468 entity data handling
469
470 ------------------------------------------------------------------------------- */
471
472
473 /*
474 StripTrailing()
475 strips low byte chars off the end of a string
476 */
477
478 void StripTrailing( char *e )
479 {
480         char    *s;
481         
482         
483         s = e + strlen( e ) - 1;
484         while( s >= e && *s <= 32 )
485         {
486                 *s = 0;
487                 s--;
488         }
489 }
490
491
492
493 /*
494 ParseEpair()
495 parses a single quoted "key" "value" pair into an epair struct
496 */
497
498 epair_t *ParseEPair( void )
499 {
500         epair_t         *e;
501         
502         
503         /* allocate and clear new epair */
504         e = safe_malloc( sizeof( epair_t ) );
505         memset( e, 0, sizeof( epair_t ) );
506         
507         /* handle key */
508         if( strlen( token ) >= (MAX_KEY - 1) )
509                 Error( "ParseEPair: token too long" );
510         
511         e->key = copystring( token );
512         GetToken( qfalse );
513         
514         /* handle value */
515         if( strlen( token ) >= MAX_VALUE - 1 )
516                 Error( "ParseEpar: token too long" );
517         e->value = copystring( token );
518         
519         /* strip trailing spaces that sometimes get accidentally added in the editor */
520         StripTrailing( e->key );
521         StripTrailing( e->value );
522         
523         /* return it */
524         return e;
525 }
526
527
528
529 /*
530 ParseEntity()
531 parses an entity's epairs
532 */
533
534 qboolean ParseEntity( void )
535 {
536         epair_t         *e;
537         
538         
539         /* dummy check */
540         if( !GetToken( qtrue ) )
541                 return qfalse;
542         if( strcmp( token, "{" ) )
543                 Error( "ParseEntity: { not found" );
544         if( numEntities == MAX_MAP_ENTITIES )
545                 Error( "numEntities == MAX_MAP_ENTITIES" );
546         
547         /* create new entity */
548         mapEnt = &entities[ numEntities ];
549         numEntities++;
550         
551         /* parse */
552         while( 1 )
553         {
554                 if( !GetToken( qtrue ) )
555                         Error( "ParseEntity: EOF without closing brace" );
556                 if( !EPAIR_STRCMP( token, "}" ) )
557                         break;
558                 e = ParseEPair();
559                 e->next = mapEnt->epairs;
560                 mapEnt->epairs = e;
561         }
562         
563         /* return to sender */
564         return qtrue;
565 }
566
567
568
569 /*
570 ParseEntities()
571 parses the bsp entity data string into entities
572 */
573
574 void ParseEntities( void )
575 {
576         numEntities = 0;
577         ParseFromMemory( bspEntData, bspEntDataSize );
578         while( ParseEntity() );
579         
580         /* ydnar: set number of bsp entities in case a map is loaded on top */
581         numBSPEntities = numEntities;
582 }
583
584
585
586 /*
587 UnparseEntities()
588 generates the dentdata string from all the entities.
589 this allows the utilities to add or remove key/value
590 pairs to the data created by the map editor
591 */
592
593 void UnparseEntities( void )
594 {
595         int                     i;
596         char            *buf, *end;
597         epair_t         *ep;
598         char            line[ 2048 ];
599         char            key[ 1024 ], value[ 1024 ];
600         const char      *value2;
601         
602         
603         /* setup */
604         buf = bspEntData;
605         end = buf;
606         *end = 0;
607         
608         /* run through entity list */
609         for( i = 0; i < numBSPEntities && i < numEntities; i++ )
610         {
611                 /* get epair */
612                 ep = entities[ i ].epairs;
613                 if( ep == NULL )
614                         continue;       /* ent got removed */
615                 
616                 /* ydnar: certain entities get stripped from bsp file */
617                 value2 = ValueForKey( &entities[ i ], "classname" );
618                 if( !Q_stricmp( value2, "misc_model" ) ||
619                         !Q_stricmp( value2, "_decal" ) ||
620                         !Q_stricmp( value2, "_skybox" ) )
621                         continue;
622                 
623                 /* add beginning brace */
624                 strcat( end, "{\n" );
625                 end += 2;
626                 
627                 /* walk epair list */
628                 for( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
629                 {
630                         /* copy and clean */
631                         strcpy( key, ep->key );
632                         StripTrailing( key );
633                         strcpy( value, ep->value );
634                         StripTrailing( value );
635                         
636                         /* add to buffer */
637                         sprintf( line, "\"%s\" \"%s\"\n", key, value );
638                         strcat( end, line );
639                         end += strlen( line );
640                 }
641                 
642                 /* add trailing brace */
643                 strcat( end,"}\n" );
644                 end += 2;
645                 
646                 /* check for overflow */
647                 if( end > buf + MAX_MAP_ENTSTRING )
648                         Error( "Entity text too long" );
649         }
650         
651         /* set size */
652         bspEntDataSize = end - buf + 1;
653 }
654
655
656
657 /*
658 PrintEntity()
659 prints an entity's epairs to the console
660 */
661
662 void PrintEntity( const entity_t *ent )
663 {
664         epair_t *ep;
665         
666
667         Sys_Printf( "------- entity %p -------\n", ent );
668         for( ep = ent->epairs; ep != NULL; ep = ep->next )
669                 Sys_Printf( "%s = %s\n", ep->key, ep->value );
670
671 }
672
673
674
675 /*
676 SetKeyValue()
677 sets an epair in an entity
678 */
679
680 void SetKeyValue( entity_t *ent, const char *key, const char *value )
681 {
682         epair_t *ep;
683         
684         
685         /* check for existing epair */
686         for( ep = ent->epairs; ep != NULL; ep = ep->next )
687         {
688                 if( !EPAIR_STRCMP( ep->key, key ) )
689                 {
690                         free( ep->value );
691                         ep->value = copystring( value );
692                         return;
693                 }
694         }
695         
696         /* create new epair */
697         ep = safe_malloc( sizeof( *ep ) );
698         ep->next = ent->epairs;
699         ent->epairs = ep;
700         ep->key = copystring( key );
701         ep->value = copystring( value );
702 }
703
704
705
706 /*
707 ValueForKey()
708 gets the value for an entity key
709 */
710
711 const char *ValueForKey( const entity_t *ent, const char *key )
712 {
713         epair_t *ep;
714         
715         
716         /* dummy check */
717         if( ent == NULL )
718                 return "";
719         
720         /* walk epair list */
721         for( ep = ent->epairs; ep != NULL; ep = ep->next )
722         {
723                 if( !EPAIR_STRCMP( ep->key, key ) )
724                         return ep->value;
725         }
726         
727         /* if no match, return empty string */
728         return "";
729 }
730
731
732
733 /*
734 IntForKey()
735 gets the integer point value for an entity key
736 */
737
738 int IntForKey( const entity_t *ent, const char *key )
739 {
740         const char      *k;
741         
742         
743         k = ValueForKey( ent, key );
744         return atoi( k );
745 }
746
747
748
749 /*
750 FloatForKey()
751 gets the floating point value for an entity key
752 */
753
754 vec_t FloatForKey( const entity_t *ent, const char *key )
755 {
756         const char      *k;
757         
758         
759         k = ValueForKey( ent, key );
760         return atof( k );
761 }
762
763
764
765 /*
766 GetVectorForKey()
767 gets a 3-element vector value for an entity key
768 */
769
770 void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec )
771 {
772         const char      *k;
773         double          v1, v2, v3;
774         
775
776         /* get value */
777         k = ValueForKey( ent, key );
778         
779         /* scanf into doubles, then assign, so it is vec_t size independent */
780         v1 = v2 = v3 = 0.0;
781         sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
782         vec[ 0 ] = v1;
783         vec[ 1 ] = v2;
784         vec[ 2 ] = v3;
785 }
786
787
788
789 /*
790 FindTargetEntity()
791 finds an entity target
792 */
793
794 entity_t *FindTargetEntity( const char *target )
795 {
796         int                     i;
797         const char      *n;
798
799         
800         /* walk entity list */
801         for( i = 0; i < numEntities; i++ )
802         {
803                 n = ValueForKey( &entities[ i ], "targetname" );
804                 if ( !strcmp( n, target ) )
805                         return &entities[ i ];
806         }
807         
808         /* nada */
809         return NULL;
810 }
811
812
813
814 /*
815 GetEntityShadowFlags() - ydnar
816 gets an entity's shadow flags
817 note: does not set them to defaults if the keys are not found!
818 */
819
820 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows )
821 {
822         const char      *value;
823         
824         
825         /* get cast shadows */
826         if( castShadows != NULL )
827         {
828                 value = ValueForKey( ent, "_castShadows" );
829                 if( value[ 0 ] == '\0' )
830                         value = ValueForKey( ent, "_cs" );
831                 if( value[ 0 ] == '\0' )
832                         value = ValueForKey( ent2, "_castShadows" );
833                 if( value[ 0 ] == '\0' )
834                         value = ValueForKey( ent2, "_cs" );
835                 if( value[ 0 ] != '\0' )
836                         *castShadows = atoi( value );
837         }
838         
839         /* receive */
840         if( recvShadows != NULL )
841         {
842                 value = ValueForKey( ent, "_receiveShadows" );
843                 if( value[ 0 ] == '\0' )
844                         value = ValueForKey( ent, "_rs" );
845                 if( value[ 0 ] == '\0' )
846                         value = ValueForKey( ent2, "_receiveShadows" );
847                 if( value[ 0 ] == '\0' )
848                         value = ValueForKey( ent2, "_rs" );
849                 if( value[ 0 ] != '\0' )
850                         *recvShadows = atoi( value );
851         }
852 }
853