]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/bspfile_abstract.c
uncrustify! now the code is only ugly on the *inside*
[xonotic/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         numBSPDrawVerts++;
63
64         if ( bspDrawVerts == 0 ) {
65                 numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS / 37;
66
67                 bspDrawVerts = safe_malloc_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
68
69         }
70         else if ( numBSPDrawVerts > numBSPDrawVertsBuffer ) {
71                 numBSPDrawVertsBuffer *= 3; // multiply by 1.5
72                 numBSPDrawVertsBuffer /= 2;
73
74                 if ( numBSPDrawVertsBuffer > MAX_MAP_DRAW_VERTS ) {
75                         numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS;
76                 }
77
78                 bspDrawVerts = realloc( bspDrawVerts, sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer );
79
80                 if ( !bspDrawVerts ) {
81                         Error( "realloc() failed (IncDrawVerts)" );
82                 }
83         }
84
85         memset( bspDrawVerts + ( numBSPDrawVerts - 1 ), 0, sizeof( bspDrawVert_t ) );
86 }
87
88 void SetDrawVerts( int n ){
89         if ( bspDrawVerts != 0 ) {
90                 free( bspDrawVerts );
91         }
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         if ( bspDrawSurfaces != 0 ) {
104                 free( bspDrawSurfaces );
105         }
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         if ( bspDrawSurfaces != 0 ) {
116                 free( bspDrawSurfaces );
117         }
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         if ( bspDrawVerts != 0 ) {
129                 free( bspDrawVerts );
130         }
131         if ( bspDrawSurfaces != 0 ) {
132                 free( bspDrawSurfaces );
133         }
134         if ( bspLightBytes != 0 ) {
135                 free( bspLightBytes );
136         }
137         if ( bspGridPoints != 0 ) {
138                 free( bspGridPoints );
139         }
140 }
141
142
143
144
145
146
147 /*
148    SwapBlock()
149    if all values are 32 bits, this can be used to swap everything
150  */
151
152 void SwapBlock( int *block, int size ){
153         int i;
154
155
156         /* dummy check */
157         if ( block == NULL ) {
158                 return;
159         }
160
161         /* swap */
162         size >>= 2;
163         for ( i = 0; i < size; i++ )
164                 block[ i ] = LittleLong( block[ i ] );
165 }
166
167
168
169 /*
170    SwapBSPFile()
171    byte swaps all data in the abstract bsp
172  */
173
174 void SwapBSPFile( void ){
175         int i, j;
176
177
178         /* models */
179         SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) );
180
181         /* shaders (don't swap the name) */
182         for ( i = 0; i < numBSPShaders ; i++ )
183         {
184                 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
185                 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
186         }
187
188         /* planes */
189         SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
190
191         /* nodes */
192         SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
193
194         /* leafs */
195         SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
196
197         /* leaffaces */
198         SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
199
200         /* leafbrushes */
201         SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
202
203         // brushes
204         SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
205
206         // brushsides
207         SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
208
209         // vis
210         ( (int*) &bspVisBytes )[ 0 ] = LittleLong( ( (int*) &bspVisBytes )[ 0 ] );
211         ( (int*) &bspVisBytes )[ 1 ] = LittleLong( ( (int*) &bspVisBytes )[ 1 ] );
212
213         /* drawverts (don't swap colors) */
214         for ( i = 0; i < numBSPDrawVerts; i++ )
215         {
216                 bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
217                 bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
218                 bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
219                 bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
220                 bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
221                 bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
222                 bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
223                 bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
224                 for ( j = 0; j < MAX_LIGHTMAPS; j++ )
225                 {
226                         bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
227                         bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
228                 }
229         }
230
231         /* drawindexes */
232         SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
233
234         /* drawsurfs */
235         /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
236         SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
237
238         /* fogs */
239         for ( i = 0; i < numBSPFogs; i++ )
240         {
241                 bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
242                 bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
243         }
244
245         /* advertisements */
246         for ( i = 0; i < numBSPAds; i++ )
247         {
248                 bspAds[ i ].cellId = LittleLong( bspAds[ i ].cellId );
249                 bspAds[ i ].normal[ 0 ] = LittleFloat( bspAds[ i ].normal[ 0 ] );
250                 bspAds[ i ].normal[ 1 ] = LittleFloat( bspAds[ i ].normal[ 1 ] );
251                 bspAds[ i ].normal[ 2 ] = LittleFloat( bspAds[ i ].normal[ 2 ] );
252
253                 for ( j = 0; j < 4; j++ )
254                 {
255                         bspAds[ i ].rect[j][ 0 ] = LittleFloat( bspAds[ i ].rect[j][ 0 ] );
256                         bspAds[ i ].rect[j][ 1 ] = LittleFloat( bspAds[ i ].rect[j][ 1 ] );
257                         bspAds[ i ].rect[j][ 2 ] = LittleFloat( bspAds[ i ].rect[j][ 2 ] );
258                 }
259
260                 //bspAds[ i ].model[ MAX_QPATH ];
261         }
262 }
263
264
265
266 /*
267    GetLumpElements()
268    gets the number of elements in a bsp lump
269  */
270
271 int GetLumpElements( bspHeader_t *header, int lump, int size ){
272         /* check for odd size */
273         if ( header->lumps[ lump ].length % size ) {
274                 if ( force ) {
275                         Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
276                         return 0;
277                 }
278                 else{
279                         Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
280                 }
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         return (void*)( (byte*) header + header->lumps[ lump ].offset );
296 }
297
298
299
300 /*
301    CopyLump()
302    copies a bsp file lump into a destination buffer
303  */
304
305 int CopyLump( bspHeader_t *header, int lump, void *dest, int size ){
306         int length, offset;
307
308
309         /* get lump length and offset */
310         length = header->lumps[ lump ].length;
311         offset = header->lumps[ lump ].offset;
312
313         /* handle erroneous cases */
314         if ( length == 0 ) {
315                 return 0;
316         }
317         if ( length % size ) {
318                 if ( force ) {
319                         Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
320                         return 0;
321                 }
322                 else{
323                         Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
324                 }
325         }
326
327         /* copy block of memory and return */
328         memcpy( dest, (byte*) header + offset, length );
329         return length / size;
330 }
331
332
333
334 /*
335    AddLump()
336    adds a lump to an outgoing bsp file
337  */
338
339 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
340         bspLump_t   *lump;
341
342
343         /* add lump to bsp file header */
344         lump = &header->lumps[ lumpNum ];
345         lump->offset = LittleLong( ftell( file ) );
346         lump->length = LittleLong( length );
347
348         /* write lump to file */
349         SafeWrite( file, data, ( length + 3 ) & ~3 );
350 }
351
352
353
354 /*
355    LoadBSPFile()
356    loads a bsp file into memory
357  */
358
359 void LoadBSPFile( const char *filename ){
360         /* dummy check */
361         if ( game == NULL || game->load == NULL ) {
362                 Error( "LoadBSPFile: unsupported BSP file format" );
363         }
364
365         /* load it, then byte swap the in-memory version */
366         game->load( filename );
367         SwapBSPFile();
368 }
369
370
371
372 /*
373    WriteBSPFile()
374    writes a bsp file
375  */
376
377 void WriteBSPFile( const char *filename ){
378         char tempname[ 1024 ];
379         time_t tm;
380
381
382         /* dummy check */
383         if ( game == NULL || game->write == NULL ) {
384                 Error( "WriteBSPFile: unsupported BSP file format" );
385         }
386
387         /* make fake temp name so existing bsp file isn't damaged in case write process fails */
388         time( &tm );
389         sprintf( tempname, "%s.%08X", filename, (int) tm );
390
391         /* byteswap, write the bsp, then swap back so it can be manipulated further */
392         SwapBSPFile();
393         game->write( tempname );
394         SwapBSPFile();
395
396         /* replace existing bsp file */
397         remove( filename );
398         rename( tempname, filename );
399 }
400
401
402
403 /*
404    PrintBSPFileSizes()
405    dumps info about current file
406  */
407
408 void PrintBSPFileSizes( void ){
409         /* parse entities first */
410         if ( numEntities <= 0 ) {
411                 ParseEntities();
412         }
413
414         /* note that this is abstracted */
415         Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
416
417         /* print various and sundry bits */
418         Sys_Printf( "%9d models        %9d\n",
419                                 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
420         Sys_Printf( "%9d shaders       %9d\n",
421                                 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
422         Sys_Printf( "%9d brushes       %9d\n",
423                                 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
424         Sys_Printf( "%9d brushsides    %9d *\n",
425                                 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
426         Sys_Printf( "%9d fogs          %9d\n",
427                                 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
428         Sys_Printf( "%9d planes        %9d\n",
429                                 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
430         Sys_Printf( "%9d entdata       %9d\n",
431                                 numEntities, bspEntDataSize );
432         Sys_Printf( "\n" );
433
434         Sys_Printf( "%9d nodes         %9d\n",
435                                 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
436         Sys_Printf( "%9d leafs         %9d\n",
437                                 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
438         Sys_Printf( "%9d leafsurfaces  %9d\n",
439                                 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
440         Sys_Printf( "%9d leafbrushes   %9d\n",
441                                 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
442         Sys_Printf( "\n" );
443
444         Sys_Printf( "%9d drawsurfaces  %9d *\n",
445                                 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
446         Sys_Printf( "%9d drawverts     %9d *\n",
447                                 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
448         Sys_Printf( "%9d drawindexes   %9d\n",
449                                 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
450         Sys_Printf( "\n" );
451
452         Sys_Printf( "%9d lightmaps     %9d\n",
453                                 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
454         Sys_Printf( "%9d lightgrid     %9d *\n",
455                                 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
456         Sys_Printf( "          visibility    %9d\n",
457                                 numBSPVisBytes );
458 }
459
460
461
462 /* -------------------------------------------------------------------------------
463
464    entity data handling
465
466    ------------------------------------------------------------------------------- */
467
468
469 /*
470    StripTrailing()
471    strips low byte chars off the end of a string
472  */
473
474 void StripTrailing( char *e ){
475         char    *s;
476
477
478         s = e + strlen( e ) - 1;
479         while ( s >= e && *s <= 32 )
480         {
481                 *s = 0;
482                 s--;
483         }
484 }
485
486
487
488 /*
489    ParseEpair()
490    parses a single quoted "key" "value" pair into an epair struct
491  */
492
493 epair_t *ParseEPair( void ){
494         epair_t     *e;
495
496
497         /* allocate and clear new epair */
498         e = safe_malloc( sizeof( epair_t ) );
499         memset( e, 0, sizeof( epair_t ) );
500
501         /* handle key */
502         if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
503                 Error( "ParseEPair: token too long" );
504         }
505
506         e->key = copystring( token );
507         GetToken( qfalse );
508
509         /* handle value */
510         if ( strlen( token ) >= MAX_VALUE - 1 ) {
511                 Error( "ParseEpar: token too long" );
512         }
513         e->value = copystring( token );
514
515         /* strip trailing spaces that sometimes get accidentally added in the editor */
516         StripTrailing( e->key );
517         StripTrailing( e->value );
518
519         /* return it */
520         return e;
521 }
522
523
524
525 /*
526    ParseEntity()
527    parses an entity's epairs
528  */
529
530 qboolean ParseEntity( void ){
531         epair_t     *e;
532
533
534         /* dummy check */
535         if ( !GetToken( qtrue ) ) {
536                 return qfalse;
537         }
538         if ( strcmp( token, "{" ) ) {
539                 Error( "ParseEntity: { not found" );
540         }
541         if ( numEntities == MAX_MAP_ENTITIES ) {
542                 Error( "numEntities == MAX_MAP_ENTITIES" );
543         }
544
545         /* create new entity */
546         mapEnt = &entities[ numEntities ];
547         numEntities++;
548
549         /* parse */
550         while ( 1 )
551         {
552                 if ( !GetToken( qtrue ) ) {
553                         Error( "ParseEntity: EOF without closing brace" );
554                 }
555                 if ( !EPAIR_STRCMP( token, "}" ) ) {
556                         break;
557                 }
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         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         int i;
594         char        *buf, *end;
595         epair_t     *ep;
596         char line[ 2048 ];
597         char key[ 1024 ], value[ 1024 ];
598         const char  *value2;
599
600
601         /* setup */
602         buf = bspEntData;
603         end = buf;
604         *end = 0;
605
606         /* run through entity list */
607         for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
608         {
609                 /* get epair */
610                 ep = entities[ i ].epairs;
611                 if ( ep == NULL ) {
612                         continue;   /* ent got removed */
613
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
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
652         /* set size */
653         bspEntDataSize = end - buf + 1;
654 }
655
656
657
658 /*
659    PrintEntity()
660    prints an entity's epairs to the console
661  */
662
663 void PrintEntity( const entity_t *ent ){
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         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                         free( ep->value );
689                         ep->value = copystring( value );
690                         return;
691                 }
692         }
693
694         /* create new epair */
695         ep = safe_malloc( sizeof( *ep ) );
696         ep->next = ent->epairs;
697         ent->epairs = ep;
698         ep->key = copystring( key );
699         ep->value = copystring( value );
700 }
701
702
703
704 /*
705    ValueForKey()
706    gets the value for an entity key
707  */
708
709 const char *ValueForKey( const entity_t *ent, const char *key ){
710         epair_t *ep;
711
712
713         /* dummy check */
714         if ( ent == NULL ) {
715                 return "";
716         }
717
718         /* walk epair list */
719         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
720         {
721                 if ( !EPAIR_STRCMP( ep->key, key ) ) {
722                         return ep->value;
723                 }
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         const char  *k;
739
740
741         k = ValueForKey( ent, key );
742         return atoi( k );
743 }
744
745
746
747 /*
748    FloatForKey()
749    gets the floating point value for an entity key
750  */
751
752 vec_t FloatForKey( const entity_t *ent, const char *key ){
753         const char  *k;
754
755
756         k = ValueForKey( ent, key );
757         return atof( k );
758 }
759
760
761
762 /*
763    GetVectorForKey()
764    gets a 3-element vector value for an entity key
765  */
766
767 void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
768         const char  *k;
769         double v1, v2, v3;
770
771
772         /* get value */
773         k = ValueForKey( ent, key );
774
775         /* scanf into doubles, then assign, so it is vec_t size independent */
776         v1 = v2 = v3 = 0.0;
777         sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
778         vec[ 0 ] = v1;
779         vec[ 1 ] = v2;
780         vec[ 2 ] = v3;
781 }
782
783
784
785 /*
786    FindTargetEntity()
787    finds an entity target
788  */
789
790 entity_t *FindTargetEntity( const char *target ){
791         int i;
792         const char  *n;
793
794
795         /* walk entity list */
796         for ( i = 0; i < numEntities; i++ )
797         {
798                 n = ValueForKey( &entities[ i ], "targetname" );
799                 if ( !strcmp( n, target ) ) {
800                         return &entities[ i ];
801                 }
802         }
803
804         /* nada */
805         return NULL;
806 }
807
808
809
810 /*
811    GetEntityShadowFlags() - ydnar
812    gets an entity's shadow flags
813    note: does not set them to defaults if the keys are not found!
814  */
815
816 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
817         const char  *value;
818
819
820         /* get cast shadows */
821         if ( castShadows != NULL ) {
822                 value = ValueForKey( ent, "_castShadows" );
823                 if ( value[ 0 ] == '\0' ) {
824                         value = ValueForKey( ent, "_cs" );
825                 }
826                 if ( value[ 0 ] == '\0' ) {
827                         value = ValueForKey( ent2, "_castShadows" );
828                 }
829                 if ( value[ 0 ] == '\0' ) {
830                         value = ValueForKey( ent2, "_cs" );
831                 }
832                 if ( value[ 0 ] != '\0' ) {
833                         *castShadows = atoi( value );
834                 }
835         }
836
837         /* receive */
838         if ( recvShadows != NULL ) {
839                 value = ValueForKey( ent, "_receiveShadows" );
840                 if ( value[ 0 ] == '\0' ) {
841                         value = ValueForKey( ent, "_rs" );
842                 }
843                 if ( value[ 0 ] == '\0' ) {
844                         value = ValueForKey( ent2, "_receiveShadows" );
845                 }
846                 if ( value[ 0 ] == '\0' ) {
847                         value = ValueForKey( ent2, "_rs" );
848                 }
849                 if ( value[ 0 ] != '\0' ) {
850                         *recvShadows = atoi( value );
851                 }
852         }
853 }