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