1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein single player GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein single player GPL Source Code (“RTCW SP Source Code”).
8 
9 RTCW SP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW SP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW SP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 
30 /*****************************************************************************
31  * name:		be_aas_bspq3.c
32  *
33  * desc:		BSP, Environment Sampling
34  *
35  *
36  *****************************************************************************/
37 
38 #include "../qcommon/q_shared.h"
39 #include "l_memory.h"
40 #include "l_script.h"
41 #include "l_precomp.h"
42 #include "l_struct.h"
43 #include "aasfile.h"
44 #include "botlib.h"
45 #include "be_aas.h"
46 #include "be_aas_funcs.h"
47 #include "be_aas_def.h"
48 
49 extern botlib_import_t botimport;
50 
51 //#define TRACE_DEBUG
52 
53 #define ON_EPSILON      0.005
54 //#define DEG2RAD( a ) (( a * M_PI ) / 180.0F)
55 
56 #define MAX_BSPENTITIES     2048
57 
58 typedef struct rgb_s
59 {
60 	int red;
61 	int green;
62 	int blue;
63 } rgb_t;
64 
65 //bsp entity epair
66 typedef struct bsp_epair_s
67 {
68 	char *key;
69 	char *value;
70 	struct bsp_epair_s *next;
71 } bsp_epair_t;
72 
73 //bsp data entity
74 typedef struct bsp_entity_s
75 {
76 	bsp_epair_t *epairs;
77 } bsp_entity_t;
78 
79 //id Sofware BSP data
80 typedef struct bsp_s
81 {
82 	//true when bsp file is loaded
83 	int loaded;
84 	//entity data
85 	int entdatasize;
86 	char *dentdata;
87 	//bsp entities
88 	int numentities;
89 	bsp_entity_t entities[MAX_BSPENTITIES];
90 	//memory used for strings and epairs
91 	byte *ebuffer;
92 } bsp_t;
93 
94 //global bsp
95 bsp_t bspworld;
96 
97 
98 #ifdef BSP_DEBUG
99 typedef struct cname_s
100 {
101 	int value;
102 	char *name;
103 } cname_t;
104 
105 cname_t contentnames[] =
106 {
107 	{CONTENTS_SOLID,"CONTENTS_SOLID"},
108 	{CONTENTS_WINDOW,"CONTENTS_WINDOW"},
109 	{CONTENTS_AUX,"CONTENTS_AUX"},
110 	{CONTENTS_LAVA,"CONTENTS_LAVA"},
111 	{CONTENTS_SLIME,"CONTENTS_SLIME"},
112 	{CONTENTS_WATER,"CONTENTS_WATER"},
113 	{CONTENTS_MIST,"CONTENTS_MIST"},
114 	{LAST_VISIBLE_CONTENTS,"LAST_VISIBLE_CONTENTS"},
115 
116 	{CONTENTS_AREAPORTAL,"CONTENTS_AREAPORTAL"},
117 	{CONTENTS_PLAYERCLIP,"CONTENTS_PLAYERCLIP"},
118 	{CONTENTS_MONSTERCLIP,"CONTENTS_MONSTERCLIP"},
119 	{CONTENTS_CURRENT_0,"CONTENTS_CURRENT_0"},
120 	{CONTENTS_CURRENT_90,"CONTENTS_CURRENT_90"},
121 	{CONTENTS_CURRENT_180,"CONTENTS_CURRENT_180"},
122 	{CONTENTS_CURRENT_270,"CONTENTS_CURRENT_270"},
123 	{CONTENTS_CURRENT_UP,"CONTENTS_CURRENT_UP"},
124 	{CONTENTS_CURRENT_DOWN,"CONTENTS_CURRENT_DOWN"},
125 	{CONTENTS_ORIGIN,"CONTENTS_ORIGIN"},
126 	{CONTENTS_MONSTER,"CONTENTS_MONSTER"},
127 	{CONTENTS_DEADMONSTER,"CONTENTS_DEADMONSTER"},
128 	{CONTENTS_DETAIL,"CONTENTS_DETAIL"},
129 	{CONTENTS_TRANSLUCENT,"CONTENTS_TRANSLUCENT"},
130 	{CONTENTS_LADDER,"CONTENTS_LADDER"},
131 	{0, 0}
132 };
133 
PrintContents(int contents)134 void PrintContents( int contents ) {
135 	int i;
136 
137 	for ( i = 0; contentnames[i].value; i++ )
138 	{
139 		if ( contents & contentnames[i].value ) {
140 			botimport.Print( PRT_MESSAGE, "%s\n", contentnames[i].name );
141 		} //end if
142 	} //end for
143 } //end of the function PrintContents
144 
145 #endif //BSP_DEBUG
146 //===========================================================================
147 // traces axial boxes of any size through the world
148 //
149 // Parameter:				-
150 // Returns:					-
151 // Changes Globals:		-
152 //===========================================================================
AAS_Trace(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,int passent,int contentmask)153 bsp_trace_t AAS_Trace( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int passent, int contentmask ) {
154 	bsp_trace_t bsptrace;
155 	botimport.Trace( &bsptrace, start, mins, maxs, end, passent, contentmask );
156 	return bsptrace;
157 } //end of the function AAS_Trace
158 //===========================================================================
159 // returns the contents at the given point
160 //
161 // Parameter:				-
162 // Returns:					-
163 // Changes Globals:		-
164 //===========================================================================
AAS_PointContents(vec3_t point)165 int AAS_PointContents( vec3_t point ) {
166 	return botimport.PointContents( point );
167 } //end of the function AAS_PointContents
168 //===========================================================================
169 //
170 // Parameter:				-
171 // Returns:					-
172 // Changes Globals:		-
173 //===========================================================================
AAS_EntityCollision(int entnum,vec3_t start,vec3_t boxmins,vec3_t boxmaxs,vec3_t end,int contentmask,bsp_trace_t * trace)174 qboolean AAS_EntityCollision( int entnum,
175 							  vec3_t start, vec3_t boxmins, vec3_t boxmaxs, vec3_t end,
176 							  int contentmask, bsp_trace_t *trace ) {
177 	bsp_trace_t enttrace;
178 
179 	botimport.EntityTrace( &enttrace, start, boxmins, boxmaxs, end, entnum, contentmask );
180 	if ( enttrace.fraction < trace->fraction ) {
181 		memcpy( trace, &enttrace, sizeof( bsp_trace_t ) );
182 		return qtrue;
183 	} //end if
184 	return qfalse;
185 } //end of the function AAS_EntityCollision
186 //===========================================================================
187 // returns true if in Potentially Hearable Set
188 //
189 // Parameter:				-
190 // Returns:					-
191 // Changes Globals:		-
192 //===========================================================================
AAS_inPVS(vec3_t p1,vec3_t p2)193 qboolean AAS_inPVS( vec3_t p1, vec3_t p2 ) {
194 	return botimport.inPVS( p1, p2 );
195 } //end of the function AAS_InPVS
196 //===========================================================================
197 // returns true if in Potentially Visible Set
198 //
199 // Parameter:				-
200 // Returns:					-
201 // Changes Globals:		-
202 //===========================================================================
AAS_inPHS(vec3_t p1,vec3_t p2)203 qboolean AAS_inPHS( vec3_t p1, vec3_t p2 ) {
204 	return qtrue;
205 } //end of the function AAS_inPHS
206 //===========================================================================
207 //
208 // Parameter:				-
209 // Returns:					-
210 // Changes Globals:		-
211 //===========================================================================
AAS_BSPModelMinsMaxsOrigin(int modelnum,vec3_t angles,vec3_t mins,vec3_t maxs,vec3_t origin)212 void AAS_BSPModelMinsMaxsOrigin( int modelnum, vec3_t angles, vec3_t mins, vec3_t maxs, vec3_t origin ) {
213 	botimport.BSPModelMinsMaxsOrigin( modelnum, angles, mins, maxs, origin );
214 } //end of the function AAS_BSPModelMinsMaxs
215 //===========================================================================
216 // unlinks the entity from all leaves
217 //
218 // Parameter:				-
219 // Returns:					-
220 // Changes Globals:		-
221 //===========================================================================
AAS_UnlinkFromBSPLeaves(bsp_link_t * leaves)222 void AAS_UnlinkFromBSPLeaves( bsp_link_t *leaves ) {
223 } //end of the function AAS_UnlinkFromBSPLeaves
224 //===========================================================================
225 //
226 // Parameter:				-
227 // Returns:					-
228 // Changes Globals:		-
229 //===========================================================================
AAS_BSPLinkEntity(vec3_t absmins,vec3_t absmaxs,int entnum,int modelnum)230 bsp_link_t *AAS_BSPLinkEntity( vec3_t absmins, vec3_t absmaxs, int entnum, int modelnum ) {
231 	return NULL;
232 } //end of the function AAS_BSPLinkEntity
233 //===========================================================================
234 //
235 // Parameter:				-
236 // Returns:					-
237 // Changes Globals:		-
238 //===========================================================================
AAS_BoxEntities(vec3_t absmins,vec3_t absmaxs,int * list,int maxcount)239 int AAS_BoxEntities( vec3_t absmins, vec3_t absmaxs, int *list, int maxcount ) {
240 	return 0;
241 } //end of the function AAS_BoxEntities
242 //===========================================================================
243 //
244 // Parameter:			-
245 // Returns:				-
246 // Changes Globals:		-
247 //===========================================================================
AAS_NextBSPEntity(int ent)248 int AAS_NextBSPEntity( int ent ) {
249 	ent++;
250 	if ( ent >= 1 && ent < bspworld.numentities ) {
251 		return ent;
252 	}
253 	return 0;
254 } //end of the function AAS_NextBSPEntity
255 //===========================================================================
256 //
257 // Parameter:			-
258 // Returns:				-
259 // Changes Globals:		-
260 //===========================================================================
AAS_BSPEntityInRange(int ent)261 int AAS_BSPEntityInRange( int ent ) {
262 	if ( ent <= 0 || ent >= bspworld.numentities ) {
263 		botimport.Print( PRT_MESSAGE, "bsp entity out of range\n" );
264 		return qfalse;
265 	} //end if
266 	return qtrue;
267 } //end of the function AAS_BSPEntityInRange
268 //===========================================================================
269 //
270 // Parameter:			-
271 // Returns:				-
272 // Changes Globals:		-
273 //===========================================================================
AAS_ValueForBSPEpairKey(int ent,char * key,char * value,int size)274 int AAS_ValueForBSPEpairKey( int ent, char *key, char *value, int size ) {
275 	bsp_epair_t *epair;
276 
277 	value[0] = '\0';
278 	if ( !AAS_BSPEntityInRange( ent ) ) {
279 		return qfalse;
280 	}
281 	for ( epair = bspworld.entities[ent].epairs; epair; epair = epair->next )
282 	{
283 		if ( !strcmp( epair->key, key ) ) {
284 			strncpy( value, epair->value, size - 1 );
285 			value[size - 1] = '\0';
286 			return qtrue;
287 		} //end if
288 	} //end for
289 	return qfalse;
290 } //end of the function AAS_FindBSPEpair
291 //===========================================================================
292 //
293 // Parameter:				-
294 // Returns:					-
295 // Changes Globals:		-
296 //===========================================================================
AAS_VectorForBSPEpairKey(int ent,char * key,vec3_t v)297 int AAS_VectorForBSPEpairKey( int ent, char *key, vec3_t v ) {
298 	char buf[MAX_EPAIRKEY];
299 	double v1, v2, v3;
300 
301 	VectorClear( v );
302 	if ( !AAS_ValueForBSPEpairKey( ent, key, buf, MAX_EPAIRKEY ) ) {
303 		return qfalse;
304 	}
305 	//scanf into doubles, then assign, so it is vec_t size independent
306 	v1 = v2 = v3 = 0;
307 	sscanf( buf, "%lf %lf %lf", &v1, &v2, &v3 );
308 	v[0] = v1;
309 	v[1] = v2;
310 	v[2] = v3;
311 	return qtrue;
312 } //end of the function AAS_VectorForBSPEpairKey
313 //===========================================================================
314 //
315 // Parameter:				-
316 // Returns:					-
317 // Changes Globals:		-
318 //===========================================================================
AAS_FloatForBSPEpairKey(int ent,char * key,float * value)319 int AAS_FloatForBSPEpairKey( int ent, char *key, float *value ) {
320 	char buf[MAX_EPAIRKEY];
321 
322 	*value = 0;
323 	if ( !AAS_ValueForBSPEpairKey( ent, key, buf, MAX_EPAIRKEY ) ) {
324 		return qfalse;
325 	}
326 	*value = atof( buf );
327 	return qtrue;
328 } //end of the function AAS_FloatForBSPEpairKey
329 //===========================================================================
330 //
331 // Parameter:				-
332 // Returns:					-
333 // Changes Globals:		-
334 //===========================================================================
AAS_IntForBSPEpairKey(int ent,char * key,int * value)335 int AAS_IntForBSPEpairKey( int ent, char *key, int *value ) {
336 	char buf[MAX_EPAIRKEY];
337 
338 	*value = 0;
339 	if ( !AAS_ValueForBSPEpairKey( ent, key, buf, MAX_EPAIRKEY ) ) {
340 		return qfalse;
341 	}
342 	*value = atoi( buf );
343 	return qtrue;
344 } //end of the function AAS_IntForBSPEpairKey
345 //===========================================================================
346 //
347 // Parameter:			-
348 // Returns:				-
349 // Changes Globals:		-
350 //===========================================================================
AAS_FreeBSPEntities(void)351 void AAS_FreeBSPEntities( void ) {
352 // RF, optimized memory allocation
353 /*
354 	int i;
355 	bsp_entity_t *ent;
356 	bsp_epair_t *epair, *nextepair;
357 
358 	for (i = 1; i < bspworld.numentities; i++)
359 	{
360 		ent = &bspworld.entities[i];
361 		for (epair = ent->epairs; epair; epair = nextepair)
362 		{
363 			nextepair = epair->next;
364 			//
365 			if (epair->key) FreeMemory(epair->key);
366 			if (epair->value) FreeMemory(epair->value);
367 			FreeMemory(epair);
368 		} //end for
369 	} //end for
370 */
371 	if ( bspworld.ebuffer ) {
372 		FreeMemory( bspworld.ebuffer );
373 	}
374 	bspworld.numentities = 0;
375 } //end of the function AAS_FreeBSPEntities
376 //===========================================================================
377 //
378 // Parameter:			-
379 // Returns:				-
380 // Changes Globals:		-
381 //===========================================================================
AAS_ParseBSPEntities(void)382 void AAS_ParseBSPEntities( void ) {
383 	script_t *script;
384 	token_t token;
385 	bsp_entity_t *ent;
386 	bsp_epair_t *epair;
387 	byte *buffer, *buftrav;
388 	int bufsize;
389 
390 	// RF, modified this, so that it first gathers up memory requirements, then allocates a single chunk,
391 	// and places the strings all in there
392 
393 	bspworld.ebuffer = NULL;
394 
395 	script = LoadScriptMemory( bspworld.dentdata, bspworld.entdatasize, "entdata" );
396 	SetScriptFlags( script, SCFL_NOSTRINGWHITESPACES | SCFL_NOSTRINGESCAPECHARS ); //SCFL_PRIMITIVE);
397 
398 	bufsize = 0;
399 
400 	while ( PS_ReadToken( script, &token ) )
401 	{
402 		if ( strcmp( token.string, "{" ) ) {
403 			ScriptError( script, "invalid %s", token.string );
404 			AAS_FreeBSPEntities();
405 			FreeScript( script );
406 			return;
407 		} //end if
408 		if ( bspworld.numentities >= MAX_BSPENTITIES ) {
409 			botimport.Print( PRT_MESSAGE, "too many entities in BSP file\n" );
410 			break;
411 		} //end if
412 		while ( PS_ReadToken( script, &token ) )
413 		{
414 			if ( !strcmp( token.string, "}" ) ) {
415 				break;
416 			}
417 			bufsize += sizeof( bsp_epair_t );
418 			if ( token.type != TT_STRING ) {
419 				ScriptError( script, "invalid %s", token.string );
420 				AAS_FreeBSPEntities();
421 				FreeScript( script );
422 				return;
423 			} //end if
424 			StripDoubleQuotes( token.string );
425 			bufsize += strlen( token.string ) + 1;
426 			if ( !PS_ExpectTokenType( script, TT_STRING, 0, &token ) ) {
427 				AAS_FreeBSPEntities();
428 				FreeScript( script );
429 				return;
430 			} //end if
431 			StripDoubleQuotes( token.string );
432 			bufsize += strlen( token.string ) + 1;
433 		} //end while
434 		if ( strcmp( token.string, "}" ) ) {
435 			ScriptError( script, "missing }" );
436 			AAS_FreeBSPEntities();
437 			FreeScript( script );
438 			return;
439 		} //end if
440 	} //end while
441 	FreeScript( script );
442 
443 	buffer = (byte *)GetClearedHunkMemory( bufsize );
444 	buftrav = buffer;
445 	bspworld.ebuffer = buffer;
446 
447 	// RF, now parse the entities into memory
448 	// RF, NOTE: removed error checks for speed, no need to do them twice
449 
450 	script = LoadScriptMemory( bspworld.dentdata, bspworld.entdatasize, "entdata" );
451 	SetScriptFlags( script, SCFL_NOSTRINGWHITESPACES | SCFL_NOSTRINGESCAPECHARS ); //SCFL_PRIMITIVE);
452 
453 	bspworld.numentities = 1;
454 
455 	while ( PS_ReadToken( script, &token ) )
456 	{
457 		ent = &bspworld.entities[bspworld.numentities];
458 		bspworld.numentities++;
459 		ent->epairs = NULL;
460 		while ( PS_ReadToken( script, &token ) )
461 		{
462 			if ( !strcmp( token.string, "}" ) ) {
463 				break;
464 			}
465 			epair = (bsp_epair_t *) buftrav; buftrav += sizeof( bsp_epair_t );
466 			epair->next = ent->epairs;
467 			ent->epairs = epair;
468 			StripDoubleQuotes( token.string );
469 			epair->key = (char *) buftrav; buftrav += ( strlen( token.string ) + 1 );
470 			strcpy( epair->key, token.string );
471 			if ( !PS_ExpectTokenType( script, TT_STRING, 0, &token ) ) {
472 				AAS_FreeBSPEntities();
473 				FreeScript( script );
474 				return;
475 			} //end if
476 			StripDoubleQuotes( token.string );
477 			epair->value = (char *) buftrav; buftrav += ( strlen( token.string ) + 1 );
478 			strcpy( epair->value, token.string );
479 		} //end while
480 	} //end while
481 	FreeScript( script );
482 } //end of the function AAS_ParseBSPEntities
483 //===========================================================================
484 //
485 // Parameter:				-
486 // Returns:					-
487 // Changes Globals:		-
488 //===========================================================================
AAS_BSPTraceLight(vec3_t start,vec3_t end,vec3_t endpos,int * red,int * green,int * blue)489 int AAS_BSPTraceLight( vec3_t start, vec3_t end, vec3_t endpos, int *red, int *green, int *blue ) {
490 	return 0;
491 } //end of the function AAS_BSPTraceLight
492 //===========================================================================
493 //
494 // Parameter:				-
495 // Returns:					-
496 // Changes Globals:		-
497 //===========================================================================
AAS_DumpBSPData(void)498 void AAS_DumpBSPData( void ) {
499 	AAS_FreeBSPEntities();
500 
501 	if ( bspworld.dentdata ) {
502 		FreeMemory( bspworld.dentdata );
503 	}
504 	bspworld.dentdata = NULL;
505 	bspworld.entdatasize = 0;
506 	//
507 	bspworld.loaded = qfalse;
508 	memset( &bspworld, 0, sizeof( bspworld ) );
509 } //end of the function AAS_DumpBSPData
510 //===========================================================================
511 // load an bsp file
512 //
513 // Parameter:				-
514 // Returns:					-
515 // Changes Globals:		-
516 //===========================================================================
AAS_LoadBSPFile(void)517 int AAS_LoadBSPFile( void ) {
518 	AAS_DumpBSPData();
519 	bspworld.entdatasize = strlen( botimport.BSPEntityData() ) + 1;
520 	bspworld.dentdata = (char *) GetClearedHunkMemory( bspworld.entdatasize );
521 	memcpy( bspworld.dentdata, botimport.BSPEntityData(), bspworld.entdatasize );
522 	AAS_ParseBSPEntities();
523 	bspworld.loaded = qtrue;
524 	return BLERR_NOERROR;
525 } //end of the function AAS_LoadBSPFile
526