1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer 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 multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP 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 MP 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 MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP 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 MP 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_sample.c
32  *
33  * desc:		AAS 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 AAS_SAMPLE_DEBUG
52 
53 #define BBOX_NORMAL_EPSILON     0.001
54 
55 #define ON_EPSILON                  0 //0.0005
56 
57 #define TRACEPLANE_EPSILON          0.125
58 
59 typedef struct aas_tracestack_s
60 {
61 	vec3_t start;       //start point of the piece of line to trace
62 	vec3_t end;         //end point of the piece of line to trace
63 	int planenum;       //last plane used as splitter
64 	int nodenum;        //node found after splitting with planenum
65 } aas_tracestack_t;
66 
67 //===========================================================================
68 //
69 // Parameter:				-
70 // Returns:					-
71 // Changes Globals:		-
72 //===========================================================================
AAS_PresenceTypeBoundingBox(int presencetype,vec3_t mins,vec3_t maxs)73 void AAS_PresenceTypeBoundingBox( int presencetype, vec3_t mins, vec3_t maxs ) {
74 	int index;
75 	//bounding box size for each presence type
76 	vec3_t boxmins[3] = {{0, 0, 0}, {-15, -15, -24}, {-15, -15, -24}};
77 	vec3_t boxmaxs[3] = {{0, 0, 0}, { 15,  15,  32}, { 15,  15,   8}};
78 
79 	if ( presencetype == PRESENCE_NORMAL ) {
80 		index = 1;
81 	} else if ( presencetype == PRESENCE_CROUCH ) {
82 		index = 2;
83 	} else
84 	{
85 		botimport.Print( PRT_FATAL, "AAS_PresenceTypeBoundingBox: unknown presence type\n" );
86 		index = 2;
87 	} //end if
88 	VectorCopy( boxmins[index], mins );
89 	VectorCopy( boxmaxs[index], maxs );
90 } //end of the function AAS_PresenceTypeBoundingBox
91 //===========================================================================
92 //
93 // Parameter:				-
94 // Returns:					-
95 // Changes Globals:		-
96 //===========================================================================
AAS_InitAASLinkHeap(void)97 void AAS_InitAASLinkHeap( void ) {
98 	int i, max_aaslinks;
99 
100 	max_aaslinks = ( *aasworld ).linkheapsize;
101 	//if there's no link heap present
102 	if ( !( *aasworld ).linkheap ) {
103 		max_aaslinks = (int) 4096; //LibVarValue("max_aaslinks", "4096");
104 		if ( max_aaslinks < 0 ) {
105 			max_aaslinks = 0;
106 		}
107 		( *aasworld ).linkheapsize = max_aaslinks;
108 		( *aasworld ).linkheap = (aas_link_t *) GetHunkMemory( max_aaslinks * sizeof( aas_link_t ) );
109 	} //end if
110 	  //link the links on the heap
111 	( *aasworld ).linkheap[0].prev_ent = NULL;
112 	( *aasworld ).linkheap[0].next_ent = &( *aasworld ).linkheap[1];
113 	for ( i = 1; i < max_aaslinks - 1; i++ )
114 	{
115 		( *aasworld ).linkheap[i].prev_ent = &( *aasworld ).linkheap[i - 1];
116 		( *aasworld ).linkheap[i].next_ent = &( *aasworld ).linkheap[i + 1];
117 	} //end for
118 	( *aasworld ).linkheap[max_aaslinks - 1].prev_ent = &( *aasworld ).linkheap[max_aaslinks - 2];
119 	( *aasworld ).linkheap[max_aaslinks - 1].next_ent = NULL;
120 	//pointer to the first free link
121 	( *aasworld ).freelinks = &( *aasworld ).linkheap[0];
122 } //end of the function AAS_InitAASLinkHeap
123 //===========================================================================
124 //
125 // Parameter:				-
126 // Returns:					-
127 // Changes Globals:		-
128 //===========================================================================
AAS_FreeAASLinkHeap(void)129 void AAS_FreeAASLinkHeap( void ) {
130 	if ( ( *aasworld ).linkheap ) {
131 		FreeMemory( ( *aasworld ).linkheap );
132 	}
133 	( *aasworld ).linkheap = NULL;
134 	( *aasworld ).linkheapsize = 0;
135 } //end of the function AAS_FreeAASLinkHeap
136 //===========================================================================
137 //
138 // Parameter:				-
139 // Returns:					-
140 // Changes Globals:		-
141 //===========================================================================
AAS_AllocAASLink(void)142 aas_link_t *AAS_AllocAASLink( void ) {
143 	aas_link_t *link;
144 
145 	link = ( *aasworld ).freelinks;
146 	if ( !link ) {
147 		botimport.Print( PRT_FATAL, "empty aas link heap\n" );
148 		return NULL;
149 	} //end if
150 	if ( ( *aasworld ).freelinks ) {
151 		( *aasworld ).freelinks = ( *aasworld ).freelinks->next_ent;
152 	}
153 	if ( ( *aasworld ).freelinks ) {
154 		( *aasworld ).freelinks->prev_ent = NULL;
155 	}
156 	return link;
157 } //end of the function AAS_AllocAASLink
158 //===========================================================================
159 //
160 // Parameter:				-
161 // Returns:					-
162 // Changes Globals:		-
163 //===========================================================================
AAS_DeAllocAASLink(aas_link_t * link)164 void AAS_DeAllocAASLink( aas_link_t *link ) {
165 	if ( ( *aasworld ).freelinks ) {
166 		( *aasworld ).freelinks->prev_ent = link;
167 	}
168 	link->prev_ent = NULL;
169 	link->next_ent = ( *aasworld ).freelinks;
170 	link->prev_area = NULL;
171 	link->next_area = NULL;
172 	( *aasworld ).freelinks = link;
173 } //end of the function AAS_DeAllocAASLink
174 //===========================================================================
175 //
176 // Parameter:				-
177 // Returns:					-
178 // Changes Globals:		-
179 //===========================================================================
AAS_InitAASLinkedEntities(void)180 void AAS_InitAASLinkedEntities( void ) {
181 	if ( !( *aasworld ).loaded ) {
182 		return;
183 	}
184 	if ( ( *aasworld ).arealinkedentities ) {
185 		FreeMemory( ( *aasworld ).arealinkedentities );
186 	}
187 	( *aasworld ).arealinkedentities = (aas_link_t **) GetClearedHunkMemory(
188 		( *aasworld ).numareas * sizeof( aas_link_t * ) );
189 } //end of the function AAS_InitAASLinkedEntities
190 //===========================================================================
191 //
192 // Parameter:				-
193 // Returns:					-
194 // Changes Globals:		-
195 //===========================================================================
AAS_FreeAASLinkedEntities(void)196 void AAS_FreeAASLinkedEntities( void ) {
197 	if ( ( *aasworld ).arealinkedentities ) {
198 		FreeMemory( ( *aasworld ).arealinkedentities );
199 	}
200 	( *aasworld ).arealinkedentities = NULL;
201 } //end of the function AAS_InitAASLinkedEntities
202 //===========================================================================
203 // returns the AAS area the point is in
204 //
205 // Parameter:				-
206 // Returns:					-
207 // Changes Globals:		-
208 //===========================================================================
AAS_PointAreaNum(vec3_t point)209 int AAS_PointAreaNum( vec3_t point ) {
210 	int nodenum;
211 	vec_t dist;
212 	aas_node_t *node;
213 	aas_plane_t *plane;
214 
215 	if ( !( *aasworld ).loaded ) {
216 		botimport.Print( PRT_ERROR, "AAS_PointAreaNum: aas not loaded\n" );
217 		return 0;
218 	} //end if
219 
220 	//start with node 1 because node zero is a dummy used for solid leafs
221 	nodenum = 1;
222 	while ( nodenum > 0 )
223 	{
224 //		botimport.Print(PRT_MESSAGE, "[%d]", nodenum);
225 #ifdef AAS_SAMPLE_DEBUG
226 		if ( nodenum >= ( *aasworld ).numnodes ) {
227 			botimport.Print( PRT_ERROR, "nodenum = %d >= (*aasworld).numnodes = %d\n", nodenum, ( *aasworld ).numnodes );
228 			return 0;
229 		} //end if
230 #endif //AAS_SAMPLE_DEBUG
231 		node = &( *aasworld ).nodes[nodenum];
232 #ifdef AAS_SAMPLE_DEBUG
233 		if ( node->planenum < 0 || node->planenum >= ( *aasworld ).numplanes ) {
234 			botimport.Print( PRT_ERROR, "node->planenum = %d >= (*aasworld).numplanes = %d\n", node->planenum, ( *aasworld ).numplanes );
235 			return 0;
236 		} //end if
237 #endif //AAS_SAMPLE_DEBUG
238 		plane = &( *aasworld ).planes[node->planenum];
239 		dist = DotProduct( point, plane->normal ) - plane->dist;
240 		if ( dist > 0 ) {
241 			nodenum = node->children[0];
242 		} else { nodenum = node->children[1];}
243 	} //end while
244 	if ( !nodenum ) {
245 #ifdef AAS_SAMPLE_DEBUG
246 		botimport.Print( PRT_MESSAGE, "in solid\n" );
247 #endif //AAS_SAMPLE_DEBUG
248 		return 0;
249 	} //end if
250 	return -nodenum;
251 } //end of the function AAS_PointAreaNum
252 //===========================================================================
253 //
254 // Parameter:				-
255 // Returns:					-
256 // Changes Globals:		-
257 //===========================================================================
AAS_AreaCluster(int areanum)258 int AAS_AreaCluster( int areanum ) {
259 	if ( areanum <= 0 || areanum >= ( *aasworld ).numareas ) {
260 		botimport.Print( PRT_ERROR, "AAS_AreaCluster: invalid area number\n" );
261 		return 0;
262 	} //end if
263 	return ( *aasworld ).areasettings[areanum].cluster;
264 } //end of the function AAS_AreaCluster
265 //===========================================================================
266 // returns the presence types of the given area
267 //
268 // Parameter:				-
269 // Returns:					-
270 // Changes Globals:		-
271 //===========================================================================
AAS_AreaPresenceType(int areanum)272 int AAS_AreaPresenceType( int areanum ) {
273 	if ( !( *aasworld ).loaded ) {
274 		return 0;
275 	}
276 	if ( areanum <= 0 || areanum >= ( *aasworld ).numareas ) {
277 		botimport.Print( PRT_ERROR, "AAS_AreaPresenceType: invalid area number\n" );
278 		return 0;
279 	} //end if
280 	return ( *aasworld ).areasettings[areanum].presencetype;
281 } //end of the function AAS_AreaPresenceType
282 //===========================================================================
283 // returns the presence type at the given point
284 //
285 // Parameter:				-
286 // Returns:					-
287 // Changes Globals:		-
288 //===========================================================================
AAS_PointPresenceType(vec3_t point)289 int AAS_PointPresenceType( vec3_t point ) {
290 	int areanum;
291 
292 	if ( !( *aasworld ).loaded ) {
293 		return 0;
294 	}
295 
296 	areanum = AAS_PointAreaNum( point );
297 	if ( !areanum ) {
298 		return PRESENCE_NONE;
299 	}
300 	return ( *aasworld ).areasettings[areanum].presencetype;
301 } //end of the function AAS_PointPresenceType
302 //===========================================================================
303 //
304 // Parameter:				-
305 // Returns:					-
306 // Changes Globals:		-
307 //===========================================================================
AAS_AreaEntityCollision(int areanum,vec3_t start,vec3_t end,int presencetype,int passent,aas_trace_t * trace)308 qboolean AAS_AreaEntityCollision( int areanum, vec3_t start, vec3_t end,
309 								  int presencetype, int passent, aas_trace_t *trace ) {
310 	int collision;
311 	vec3_t boxmins, boxmaxs;
312 	aas_link_t *link;
313 	bsp_trace_t bsptrace;
314 
315 	AAS_PresenceTypeBoundingBox( presencetype, boxmins, boxmaxs );
316 
317 	memset( &bsptrace, 0, sizeof( bsp_trace_t ) ); //make compiler happy
318 	//assume no collision
319 	bsptrace.fraction = 1;
320 	collision = qfalse;
321 	for ( link = ( *aasworld ).arealinkedentities[areanum]; link; link = link->next_ent )
322 	{
323 		//ignore the pass entity
324 		if ( link->entnum == passent ) {
325 			continue;
326 		}
327 		//
328 		if ( AAS_EntityCollision( link->entnum, start, boxmins, boxmaxs, end,
329 								  CONTENTS_SOLID | CONTENTS_PLAYERCLIP, &bsptrace ) ) {
330 			collision = qtrue;
331 		} //end if
332 	} //end for
333 	if ( collision ) {
334 		trace->startsolid = bsptrace.startsolid;
335 		trace->ent = bsptrace.ent;
336 		VectorCopy( bsptrace.endpos, trace->endpos );
337 		trace->area = 0;
338 		trace->planenum = 0;
339 		return qtrue;
340 	} //end if
341 	return qfalse;
342 } //end of the function AAS_AreaEntityCollision
343 //===========================================================================
344 // recursive subdivision of the line by the BSP tree.
345 //
346 // Parameter:				-
347 // Returns:					-
348 // Changes Globals:		-
349 //===========================================================================
AAS_TraceClientBBox(vec3_t start,vec3_t end,int presencetype,int passent)350 aas_trace_t AAS_TraceClientBBox( vec3_t start, vec3_t end, int presencetype,
351 								 int passent ) {
352 	int side, nodenum, tmpplanenum;
353 	float front, back, frac;
354 	vec3_t cur_start, cur_end, cur_mid, v1, v2;
355 	aas_tracestack_t tracestack[127];
356 	aas_tracestack_t *tstack_p;
357 	aas_node_t *aasnode;
358 	aas_plane_t *plane;
359 	aas_trace_t trace;
360 
361 	//clear the trace structure
362 	memset( &trace, 0, sizeof( aas_trace_t ) );
363 
364 	if ( !( *aasworld ).loaded ) {
365 		return trace;
366 	}
367 
368 	tstack_p = tracestack;
369 	//we start with the whole line on the stack
370 	VectorCopy( start, tstack_p->start );
371 	VectorCopy( end, tstack_p->end );
372 	tstack_p->planenum = 0;
373 	//start with node 1 because node zero is a dummy for a solid leaf
374 	tstack_p->nodenum = 1;      //starting at the root of the tree
375 	tstack_p++;
376 
377 	while ( 1 )
378 	{
379 		//pop up the stack
380 		tstack_p--;
381 		//if the trace stack is empty (ended up with a piece of the
382 		//line to be traced in an area)
383 		if ( tstack_p < tracestack ) {
384 			tstack_p++;
385 			//nothing was hit
386 			trace.startsolid = qfalse;
387 			trace.fraction = 1.0;
388 			//endpos is the end of the line
389 			VectorCopy( end, trace.endpos );
390 			//nothing hit
391 			trace.ent = 0;
392 			trace.area = 0;
393 			trace.planenum = 0;
394 			return trace;
395 		} //end if
396 		  //number of the current node to test the line against
397 		nodenum = tstack_p->nodenum;
398 		//if it is an area
399 		if ( nodenum < 0 ) {
400 #ifdef AAS_SAMPLE_DEBUG
401 			if ( -nodenum > ( *aasworld ).numareasettings ) {
402 				botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: -nodenum out of range\n" );
403 				return trace;
404 			} //end if
405 #endif //AAS_SAMPLE_DEBUG
406 			//botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start));
407 			//if can't enter the area because it hasn't got the right presence type
408 			if ( !( ( *aasworld ).areasettings[-nodenum].presencetype & presencetype ) ) {
409 				//if the start point is still the initial start point
410 				//NOTE: no need for epsilons because the points will be
411 				//exactly the same when they're both the start point
412 				if ( tstack_p->start[0] == start[0] &&
413 					 tstack_p->start[1] == start[1] &&
414 					 tstack_p->start[2] == start[2] )
415 				{
416 					trace.startsolid = qtrue;
417 					trace.fraction = 0.0;
418 					VectorClear(v1);
419 				} //end if
420 				else
421 				{
422 					trace.startsolid = qfalse;
423 					VectorSubtract( end, start, v1 );
424 					VectorSubtract( tstack_p->start, start, v2 );
425 					trace.fraction = VectorLength( v2 ) / VectorNormalize( v1 );
426 					VectorMA( tstack_p->start, -0.125, v1, tstack_p->start );
427 				} //end else
428 				VectorCopy( tstack_p->start, trace.endpos );
429 				trace.ent = 0;
430 				trace.area = -nodenum;
431 //				VectorSubtract(end, start, v1);
432 				trace.planenum = tstack_p->planenum;
433 				//always take the plane with normal facing towards the trace start
434 				plane = &( *aasworld ).planes[trace.planenum];
435 				if ( DotProduct( v1, plane->normal ) > 0 ) {
436 					trace.planenum ^= 1;
437 				}
438 				return trace;
439 			} //end if
440 			else
441 			{
442 				if ( passent >= 0 ) {
443 					if ( AAS_AreaEntityCollision( -nodenum, tstack_p->start,
444 												  tstack_p->end, presencetype, passent,
445 												  &trace ) ) {
446 						if ( !trace.startsolid ) {
447 							VectorSubtract( end, start, v1 );
448 							VectorSubtract( trace.endpos, start, v2 );
449 							trace.fraction = VectorLength( v2 ) / VectorLength( v1 );
450 						} //end if
451 						return trace;
452 					} //end if
453 				} //end if
454 			} //end else
455 			trace.lastarea = -nodenum;
456 			continue;
457 		} //end if
458 		  //if it is a solid leaf
459 		if ( !nodenum ) {
460 			//if the start point is still the initial start point
461 			//NOTE: no need for epsilons because the points will be
462 			//exactly the same when they're both the start point
463 			if ( tstack_p->start[0] == start[0] &&
464 				 tstack_p->start[1] == start[1] &&
465 				 tstack_p->start[2] == start[2] )
466 			{
467 				trace.startsolid = qtrue;
468 				trace.fraction = 0.0;
469 				VectorClear(v1);
470 			} //end if
471 			else
472 			{
473 				trace.startsolid = qfalse;
474 				VectorSubtract( end, start, v1 );
475 				VectorSubtract( tstack_p->start, start, v2 );
476 				trace.fraction = VectorLength( v2 ) / VectorNormalize( v1 );
477 				VectorMA( tstack_p->start, -0.125, v1, tstack_p->start );
478 			} //end else
479 			VectorCopy( tstack_p->start, trace.endpos );
480 			trace.ent = 0;
481 			trace.area = 0; //hit solid leaf
482 //			VectorSubtract(end, start, v1);
483 			trace.planenum = tstack_p->planenum;
484 			//always take the plane with normal facing towards the trace start
485 			plane = &( *aasworld ).planes[trace.planenum];
486 			if ( DotProduct( v1, plane->normal ) > 0 ) {
487 				trace.planenum ^= 1;
488 			}
489 			return trace;
490 		} //end if
491 #ifdef AAS_SAMPLE_DEBUG
492 		if ( nodenum > ( *aasworld ).numnodes ) {
493 			botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: nodenum out of range\n" );
494 			return trace;
495 		} //end if
496 #endif //AAS_SAMPLE_DEBUG
497 	   //the node to test against
498 		aasnode = &( *aasworld ).nodes[nodenum];
499 		//start point of current line to test against node
500 		VectorCopy( tstack_p->start, cur_start );
501 		//end point of the current line to test against node
502 		VectorCopy( tstack_p->end, cur_end );
503 		//the current node plane
504 		plane = &( *aasworld ).planes[aasnode->planenum];
505 
506 		switch ( plane->type )
507 		{/*FIXME: wtf doesn't this work? obviously the axial node planes aren't always facing positive!!!
508 			//check for axial planes
509 			case PLANE_X:
510 			{
511 				front = cur_start[0] - plane->dist;
512 				back = cur_end[0] - plane->dist;
513 				break;
514 			} //end case
515 			case PLANE_Y:
516 			{
517 				front = cur_start[1] - plane->dist;
518 				back = cur_end[1] - plane->dist;
519 				break;
520 			} //end case
521 			case PLANE_Z:
522 			{
523 				front = cur_start[2] - plane->dist;
524 				back = cur_end[2] - plane->dist;
525 				break;
526 			} //end case*/
527 		default:     //gee it's not an axial plane
528 		{
529 			front = DotProduct( cur_start, plane->normal ) - plane->dist;
530 			back = DotProduct( cur_end, plane->normal ) - plane->dist;
531 			break;
532 		}     //end default
533 		} //end switch
534 
535 		//calculate the hitpoint with the node (split point of the line)
536 		//put the crosspoint TRACEPLANE_EPSILON pixels on the near side
537 		if ( front < 0 ) {
538 			frac = ( front + TRACEPLANE_EPSILON ) / ( front - back );
539 		} else { frac = ( front - TRACEPLANE_EPSILON ) / ( front - back );}
540 		//if the whole to be traced line is totally at the front of this node
541 		//only go down the tree with the front child
542 		if ( ( front >= -ON_EPSILON && back >= -ON_EPSILON ) ) {
543 			//keep the current start and end point on the stack
544 			//and go down the tree with the front child
545 			tstack_p->nodenum = aasnode->children[0];
546 			tstack_p++;
547 			if ( tstack_p >= &tracestack[127] ) {
548 				botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n" );
549 				return trace;
550 			} //end if
551 		} //end if
552 		  //if the whole to be traced line is totally at the back of this node
553 		  //only go down the tree with the back child
554 		else if ( ( front < ON_EPSILON && back < ON_EPSILON ) ) {
555 			//keep the current start and end point on the stack
556 			//and go down the tree with the back child
557 			tstack_p->nodenum = aasnode->children[1];
558 			tstack_p++;
559 			if ( tstack_p >= &tracestack[127] ) {
560 				botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n" );
561 				return trace;
562 			} //end if
563 		} //end if
564 		  //go down the tree both at the front and back of the node
565 		else
566 		{
567 			tmpplanenum = tstack_p->planenum;
568 			//
569 			if ( frac < 0 ) {
570 				frac = 0.001; //0
571 			} else if ( frac > 1 )                         {
572 				frac = 0.999; //1
573 			}
574 			//frac = front / (front-back);
575 			//
576 			cur_mid[0] = cur_start[0] + ( cur_end[0] - cur_start[0] ) * frac;
577 			cur_mid[1] = cur_start[1] + ( cur_end[1] - cur_start[1] ) * frac;
578 			cur_mid[2] = cur_start[2] + ( cur_end[2] - cur_start[2] ) * frac;
579 
580 //			AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED);
581 			//side the front part of the line is on
582 			side = front < 0;
583 			//first put the end part of the line on the stack (back side)
584 			VectorCopy( cur_mid, tstack_p->start );
585 			//not necesary to store because still on stack
586 			//VectorCopy(cur_end, tstack_p->end);
587 			tstack_p->planenum = aasnode->planenum;
588 			tstack_p->nodenum = aasnode->children[!side];
589 			tstack_p++;
590 			if ( tstack_p >= &tracestack[127] ) {
591 				botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n" );
592 				return trace;
593 			} //end if
594 			  //now put the part near the start of the line on the stack so we will
595 			  //continue with thats part first. This way we'll find the first
596 			  //hit of the bbox
597 			VectorCopy( cur_start, tstack_p->start );
598 			VectorCopy( cur_mid, tstack_p->end );
599 			tstack_p->planenum = tmpplanenum;
600 			tstack_p->nodenum = aasnode->children[side];
601 			tstack_p++;
602 			if ( tstack_p >= &tracestack[127] ) {
603 				botimport.Print( PRT_ERROR, "AAS_TraceBoundingBox: stack overflow\n" );
604 				return trace;
605 			} //end if
606 		} //end else
607 	} //end while
608 //	return trace;
609 } //end of the function AAS_TraceClientBBox
610 //===========================================================================
611 // recursive subdivision of the line by the BSP tree.
612 //
613 // Parameter:				-
614 // Returns:					-
615 // Changes Globals:		-
616 //===========================================================================
AAS_TraceAreas(vec3_t start,vec3_t end,int * areas,vec3_t * points,int maxareas)617 int AAS_TraceAreas( vec3_t start, vec3_t end, int *areas, vec3_t *points, int maxareas ) {
618 	int side, nodenum, tmpplanenum;
619 	int numareas;
620 	float front, back, frac;
621 	vec3_t cur_start, cur_end, cur_mid;
622 	aas_tracestack_t tracestack[127];
623 	aas_tracestack_t *tstack_p;
624 	aas_node_t *aasnode;
625 	aas_plane_t *plane;
626 
627 	numareas = 0;
628 	areas[0] = 0;
629 	if ( !( *aasworld ).loaded ) {
630 		return numareas;
631 	}
632 
633 	tstack_p = tracestack;
634 	//we start with the whole line on the stack
635 	VectorCopy( start, tstack_p->start );
636 	VectorCopy( end, tstack_p->end );
637 	tstack_p->planenum = 0;
638 	//start with node 1 because node zero is a dummy for a solid leaf
639 	tstack_p->nodenum = 1;      //starting at the root of the tree
640 	tstack_p++;
641 
642 	while ( 1 )
643 	{
644 		//pop up the stack
645 		tstack_p--;
646 		//if the trace stack is empty (ended up with a piece of the
647 		//line to be traced in an area)
648 		if ( tstack_p < tracestack ) {
649 			return numareas;
650 		} //end if
651 		  //number of the current node to test the line against
652 		nodenum = tstack_p->nodenum;
653 		//if it is an area
654 		if ( nodenum < 0 ) {
655 #ifdef AAS_SAMPLE_DEBUG
656 			if ( -nodenum > ( *aasworld ).numareasettings ) {
657 				botimport.Print( PRT_ERROR, "AAS_TraceAreas: -nodenum = %d out of range\n", -nodenum );
658 				return numareas;
659 			} //end if
660 #endif //AAS_SAMPLE_DEBUG
661 			//botimport.Print(PRT_MESSAGE, "areanum = %d, must be %d\n", -nodenum, AAS_PointAreaNum(start));
662 			areas[numareas] = -nodenum;
663 			if ( points ) {
664 				VectorCopy( tstack_p->start, points[numareas] );
665 			}
666 			numareas++;
667 			if ( numareas >= maxareas ) {
668 				return numareas;
669 			}
670 			continue;
671 		} //end if
672 		  //if it is a solid leaf
673 		if ( !nodenum ) {
674 			continue;
675 		} //end if
676 #ifdef AAS_SAMPLE_DEBUG
677 		if ( nodenum > ( *aasworld ).numnodes ) {
678 			botimport.Print( PRT_ERROR, "AAS_TraceAreas: nodenum out of range\n" );
679 			return numareas;
680 		} //end if
681 #endif //AAS_SAMPLE_DEBUG
682 	   //the node to test against
683 		aasnode = &( *aasworld ).nodes[nodenum];
684 		//start point of current line to test against node
685 		VectorCopy( tstack_p->start, cur_start );
686 		//end point of the current line to test against node
687 		VectorCopy( tstack_p->end, cur_end );
688 		//the current node plane
689 		plane = &( *aasworld ).planes[aasnode->planenum];
690 
691 		switch ( plane->type )
692 		{/*FIXME: wtf doesn't this work? obviously the node planes aren't always facing positive!!!
693 			//check for axial planes
694 			case PLANE_X:
695 			{
696 				front = cur_start[0] - plane->dist;
697 				back = cur_end[0] - plane->dist;
698 				break;
699 			} //end case
700 			case PLANE_Y:
701 			{
702 				front = cur_start[1] - plane->dist;
703 				back = cur_end[1] - plane->dist;
704 				break;
705 			} //end case
706 			case PLANE_Z:
707 			{
708 				front = cur_start[2] - plane->dist;
709 				back = cur_end[2] - plane->dist;
710 				break;
711 			} //end case*/
712 		default:     //gee it's not an axial plane
713 		{
714 			front = DotProduct( cur_start, plane->normal ) - plane->dist;
715 			back = DotProduct( cur_end, plane->normal ) - plane->dist;
716 			break;
717 		}     //end default
718 		} //end switch
719 
720 		//if the whole to be traced line is totally at the front of this node
721 		//only go down the tree with the front child
722 		if ( front > 0 && back > 0 ) {
723 			//keep the current start and end point on the stack
724 			//and go down the tree with the front child
725 			tstack_p->nodenum = aasnode->children[0];
726 			tstack_p++;
727 			if ( tstack_p >= &tracestack[127] ) {
728 				botimport.Print( PRT_ERROR, "AAS_TraceAreas: stack overflow\n" );
729 				return numareas;
730 			} //end if
731 		} //end if
732 		  //if the whole to be traced line is totally at the back of this node
733 		  //only go down the tree with the back child
734 		else if ( front <= 0 && back <= 0 ) {
735 			//keep the current start and end point on the stack
736 			//and go down the tree with the back child
737 			tstack_p->nodenum = aasnode->children[1];
738 			tstack_p++;
739 			if ( tstack_p >= &tracestack[127] ) {
740 				botimport.Print( PRT_ERROR, "AAS_TraceAreas: stack overflow\n" );
741 				return numareas;
742 			} //end if
743 		} //end if
744 		  //go down the tree both at the front and back of the node
745 		else
746 		{
747 			tmpplanenum = tstack_p->planenum;
748 			//calculate the hitpoint with the node (split point of the line)
749 			//put the crosspoint TRACEPLANE_EPSILON pixels on the near side
750 			if ( front < 0 ) {
751 				frac = ( front ) / ( front - back );
752 			} else { frac = ( front ) / ( front - back );}
753 			if ( frac < 0 ) {
754 				frac = 0;
755 			} else if ( frac > 1 ) {
756 				frac = 1;
757 			}
758 			//frac = front / (front-back);
759 			//
760 			cur_mid[0] = cur_start[0] + ( cur_end[0] - cur_start[0] ) * frac;
761 			cur_mid[1] = cur_start[1] + ( cur_end[1] - cur_start[1] ) * frac;
762 			cur_mid[2] = cur_start[2] + ( cur_end[2] - cur_start[2] ) * frac;
763 
764 //			AAS_DrawPlaneCross(cur_mid, plane->normal, plane->dist, plane->type, LINECOLOR_RED);
765 			//side the front part of the line is on
766 			side = front < 0;
767 			//first put the end part of the line on the stack (back side)
768 			VectorCopy( cur_mid, tstack_p->start );
769 			//not necesary to store because still on stack
770 			//VectorCopy(cur_end, tstack_p->end);
771 			tstack_p->planenum = aasnode->planenum;
772 			tstack_p->nodenum = aasnode->children[!side];
773 			tstack_p++;
774 			if ( tstack_p >= &tracestack[127] ) {
775 				botimport.Print( PRT_ERROR, "AAS_TraceAreas: stack overflow\n" );
776 				return numareas;
777 			} //end if
778 			  //now put the part near the start of the line on the stack so we will
779 			  //continue with thats part first. This way we'll find the first
780 			  //hit of the bbox
781 			VectorCopy( cur_start, tstack_p->start );
782 			VectorCopy( cur_mid, tstack_p->end );
783 			tstack_p->planenum = tmpplanenum;
784 			tstack_p->nodenum = aasnode->children[side];
785 			tstack_p++;
786 			if ( tstack_p >= &tracestack[127] ) {
787 				botimport.Print( PRT_ERROR, "AAS_TraceAreas: stack overflow\n" );
788 				return numareas;
789 			} //end if
790 		} //end else
791 	} //end while
792 //	return numareas;
793 } //end of the function AAS_TraceAreas
794 //===========================================================================
795 // a simple cross product
796 //
797 // Parameter:				-
798 // Returns:					-
799 // Changes Globals:		-
800 //===========================================================================
801 // void AAS_OrthogonalToVectors(vec3_t v1, vec3_t v2, vec3_t res)
802 #define AAS_OrthogonalToVectors( v1, v2, res ) \
803 	( res )[0] = ( ( v1 )[1] * ( v2 )[2] ) - ( ( v1 )[2] * ( v2 )[1] );	\
804 	( res )[1] = ( ( v1 )[2] * ( v2 )[0] ) - ( ( v1 )[0] * ( v2 )[2] );	\
805 	( res )[2] = ( ( v1 )[0] * ( v2 )[1] ) - ( ( v1 )[1] * ( v2 )[0] );
806 //===========================================================================
807 // tests if the given point is within the face boundaries
808 //
809 // Parameter:				face		: face to test if the point is in it
810 //								pnormal	: normal of the plane to use for the face
811 //								point		: point to test if inside face boundaries
812 // Returns:					qtrue if the point is within the face boundaries
813 // Changes Globals:		-
814 //===========================================================================
AAS_InsideFace(aas_face_t * face,vec3_t pnormal,vec3_t point,float epsilon)815 qboolean AAS_InsideFace( aas_face_t *face, vec3_t pnormal, vec3_t point, float epsilon ) {
816 	int i, firstvertex, edgenum;
817 	vec3_t v0;
818 	vec3_t edgevec, pointvec, sepnormal;
819 	aas_edge_t *edge;
820 #ifdef AAS_SAMPLE_DEBUG
821 	int lastvertex = 0;
822 #endif //AAS_SAMPLE_DEBUG
823 
824 	if ( !( *aasworld ).loaded ) {
825 		return qfalse;
826 	}
827 
828 	for ( i = 0; i < face->numedges; i++ )
829 	{
830 		edgenum = ( *aasworld ).edgeindex[face->firstedge + i];
831 		edge = &( *aasworld ).edges[abs( edgenum )];
832 		//get the first vertex of the edge
833 		firstvertex = edgenum < 0;
834 		VectorCopy( ( *aasworld ).vertexes[edge->v[firstvertex]], v0 );
835 		//edge vector
836 		VectorSubtract( ( *aasworld ).vertexes[edge->v[!firstvertex]], v0, edgevec );
837 		//
838 #ifdef AAS_SAMPLE_DEBUG
839 		if ( lastvertex && lastvertex != edge->v[firstvertex] ) {
840 			botimport.Print( PRT_MESSAGE, "winding not counter clockwise\n" );
841 		} //end if
842 		lastvertex = edge->v[!firstvertex];
843 #endif //AAS_SAMPLE_DEBUG
844 	   //vector from first edge point to point possible in face
845 		VectorSubtract( point, v0, pointvec );
846 		//get a vector pointing inside the face orthogonal to both the
847 		//edge vector and the normal vector of the plane the face is in
848 		//this vector defines a plane through the origin (first vertex of
849 		//edge) and through both the edge vector and the normal vector
850 		//of the plane
851 		AAS_OrthogonalToVectors( edgevec, pnormal, sepnormal );
852 		//check on wich side of the above plane the point is
853 		//this is done by checking the sign of the dot product of the
854 		//vector orthogonal vector from above and the vector from the
855 		//origin (first vertex of edge) to the point
856 		//if the dotproduct is smaller than zero the point is outside the face
857 		if ( DotProduct( pointvec, sepnormal ) < -epsilon ) {
858 			return qfalse;
859 		}
860 	} //end for
861 	return qtrue;
862 } //end of the function AAS_InsideFace
863 //===========================================================================
864 //
865 // Parameter:				-
866 // Returns:					-
867 // Changes Globals:		-
868 //===========================================================================
AAS_PointInsideFace(int facenum,vec3_t point,float epsilon)869 qboolean AAS_PointInsideFace( int facenum, vec3_t point, float epsilon ) {
870 	int i, firstvertex, edgenum;
871 	vec_t *v1, *v2;
872 	vec3_t edgevec, pointvec, sepnormal;
873 	aas_edge_t *edge;
874 	aas_plane_t *plane;
875 	aas_face_t *face;
876 
877 	if ( !( *aasworld ).loaded ) {
878 		return qfalse;
879 	}
880 
881 	face = &( *aasworld ).faces[facenum];
882 	plane = &( *aasworld ).planes[face->planenum];
883 	//
884 	for ( i = 0; i < face->numedges; i++ )
885 	{
886 		edgenum = ( *aasworld ).edgeindex[face->firstedge + i];
887 		edge = &( *aasworld ).edges[abs( edgenum )];
888 		//get the first vertex of the edge
889 		firstvertex = edgenum < 0;
890 		v1 = ( *aasworld ).vertexes[edge->v[firstvertex]];
891 		v2 = ( *aasworld ).vertexes[edge->v[!firstvertex]];
892 		//edge vector
893 		VectorSubtract( v2, v1, edgevec );
894 		//vector from first edge point to point possible in face
895 		VectorSubtract( point, v1, pointvec );
896 		//
897 		CrossProduct( edgevec, plane->normal, sepnormal );
898 		//
899 		if ( DotProduct( pointvec, sepnormal ) < -epsilon ) {
900 			return qfalse;
901 		}
902 	} //end for
903 	return qtrue;
904 } //end of the function AAS_PointInsideFace
905 //===========================================================================
906 // returns the ground face the given point is above in the given area
907 //
908 // Parameter:				-
909 // Returns:					-
910 // Changes Globals:		-
911 //===========================================================================
AAS_AreaGroundFace(int areanum,vec3_t point)912 aas_face_t *AAS_AreaGroundFace( int areanum, vec3_t point ) {
913 	int i, facenum;
914 	vec3_t up = {0, 0, 1};
915 	vec3_t normal;
916 	aas_area_t *area;
917 	aas_face_t *face;
918 
919 	if ( !( *aasworld ).loaded ) {
920 		return NULL;
921 	}
922 
923 	area = &( *aasworld ).areas[areanum];
924 	for ( i = 0; i < area->numfaces; i++ )
925 	{
926 		facenum = ( *aasworld ).faceindex[area->firstface + i];
927 		face = &( *aasworld ).faces[abs( facenum )];
928 		//if this is a ground face
929 		if ( face->faceflags & FACE_GROUND ) {
930 			//get the up or down normal
931 			if ( ( *aasworld ).planes[face->planenum].normal[2] < 0 ) {
932 				VectorNegate( up, normal );
933 			} else { VectorCopy( up, normal );}
934 			//check if the point is in the face
935 			if ( AAS_InsideFace( face, normal, point, 0.01 ) ) {
936 				return face;
937 			}
938 		} //end if
939 	} //end for
940 	return NULL;
941 } //end of the function AAS_AreaGroundFace
942 //===========================================================================
943 // returns the face the trace end position is situated in
944 //
945 // Parameter:				-
946 // Returns:					-
947 // Changes Globals:		-
948 //===========================================================================
AAS_FacePlane(int facenum,vec3_t normal,float * dist)949 void AAS_FacePlane( int facenum, vec3_t normal, float *dist ) {
950 	aas_plane_t *plane;
951 
952 	plane = &( *aasworld ).planes[( *aasworld ).faces[facenum].planenum];
953 	VectorCopy( plane->normal, normal );
954 	*dist = plane->dist;
955 } //end of the function AAS_FacePlane
956 //===========================================================================
957 // returns the face the trace end position is situated in
958 //
959 // Parameter:				-
960 // Returns:					-
961 // Changes Globals:		-
962 //===========================================================================
AAS_TraceEndFace(aas_trace_t * trace)963 aas_face_t *AAS_TraceEndFace( aas_trace_t *trace ) {
964 	int i, facenum;
965 	aas_area_t *area;
966 	aas_face_t *face, *firstface = NULL;
967 
968 	if ( !( *aasworld ).loaded ) {
969 		return NULL;
970 	}
971 
972 	//if started in solid no face was hit
973 	if ( trace->startsolid ) {
974 		return NULL;
975 	}
976 	//trace->lastarea is the last area the trace was in
977 	area = &( *aasworld ).areas[trace->lastarea];
978 	//check which face the trace.endpos was in
979 	for ( i = 0; i < area->numfaces; i++ )
980 	{
981 		facenum = ( *aasworld ).faceindex[area->firstface + i];
982 		face = &( *aasworld ).faces[abs( facenum )];
983 		//if the face is in the same plane as the trace end point
984 		if ( ( face->planenum & ~1 ) == ( trace->planenum & ~1 ) ) {
985 			//firstface is used for optimization, if theres only one
986 			//face in the plane then it has to be the good one
987 			//if there are more faces in the same plane then always
988 			//check the one with the fewest edges first
989 /*			if (firstface)
990 			{
991 				if (firstface->numedges < face->numedges)
992 				{
993 					if (AAS_InsideFace(firstface,
994 						(*aasworld).planes[face->planenum].normal, trace->endpos))
995 					{
996 						return firstface;
997 					} //end if
998 					firstface = face;
999 				} //end if
1000 				else
1001 				{
1002 					if (AAS_InsideFace(face,
1003 						(*aasworld).planes[face->planenum].normal, trace->endpos))
1004 					{
1005 						return face;
1006 					} //end if
1007 				} //end else
1008 			} //end if
1009 			else
1010 			{
1011 				firstface = face;
1012 			} //end else*/
1013 			if ( AAS_InsideFace( face,
1014 								 ( *aasworld ).planes[face->planenum].normal, trace->endpos, 0.01 ) ) {
1015 				return face;
1016 			}
1017 		} //end if
1018 	} //end for
1019 	return firstface;
1020 } //end of the function AAS_TraceEndFace
1021 //===========================================================================
1022 //
1023 // Parameter:				-
1024 // Returns:					-
1025 // Changes Globals:		-
1026 //===========================================================================
AAS_BoxOnPlaneSide2(vec3_t absmins,vec3_t absmaxs,aas_plane_t * p)1027 int AAS_BoxOnPlaneSide2( vec3_t absmins, vec3_t absmaxs, aas_plane_t *p ) {
1028 	int i, sides;
1029 	float dist1, dist2;
1030 	vec3_t corners[2];
1031 
1032 	for ( i = 0; i < 3; i++ )
1033 	{
1034 		if ( p->normal[i] < 0 ) {
1035 			corners[0][i] = absmins[i];
1036 			corners[1][i] = absmaxs[i];
1037 		} //end if
1038 		else
1039 		{
1040 			corners[1][i] = absmins[i];
1041 			corners[0][i] = absmaxs[i];
1042 		} //end else
1043 	} //end for
1044 	dist1 = DotProduct( p->normal, corners[0] ) - p->dist;
1045 	dist2 = DotProduct( p->normal, corners[1] ) - p->dist;
1046 	sides = 0;
1047 	if ( dist1 >= 0 ) {
1048 		sides = 1;
1049 	}
1050 	if ( dist2 < 0 ) {
1051 		sides |= 2;
1052 	}
1053 
1054 	return sides;
1055 } //end of the function AAS_BoxOnPlaneSide2
1056 //===========================================================================
1057 //
1058 // Parameter:				-
1059 // Returns:					-
1060 // Changes Globals:		-
1061 //===========================================================================
1062 //int AAS_BoxOnPlaneSide(vec3_t absmins, vec3_t absmaxs, aas_plane_t *p)
1063 #define AAS_BoxOnPlaneSide( absmins, absmaxs, p ) (	\
1064 		( ( p )->type < 3 ) ? \
1065 		( \
1066 			( ( p )->dist <= ( absmins )[( p )->type] ) ? \
1067 			( \
1068 				1 \
1069 			) \
1070 			: \
1071 			( \
1072 				( ( p )->dist >= ( absmaxs )[( p )->type] ) ? \
1073 				( \
1074 					2 \
1075 				) \
1076 				: \
1077 				( \
1078 					3 \
1079 				) \
1080 			) \
1081 		) \
1082 		: \
1083 		( \
1084 			AAS_BoxOnPlaneSide2( ( absmins ), ( absmaxs ), ( p ) ) \
1085 		) \
1086 		) //end of the function AAS_BoxOnPlaneSide
1087 //===========================================================================
1088 // remove the links to this entity from all areas
1089 //
1090 // Parameter:				-
1091 // Returns:					-
1092 // Changes Globals:		-
1093 //===========================================================================
AAS_UnlinkFromAreas(aas_link_t * areas)1094 void AAS_UnlinkFromAreas( aas_link_t *areas ) {
1095 	aas_link_t *link, *nextlink;
1096 
1097 	for ( link = areas; link; link = nextlink )
1098 	{
1099 		//next area the entity is linked in
1100 		nextlink = link->next_area;
1101 		//remove the entity from the linked list of this area
1102 		if ( link->prev_ent ) {
1103 			link->prev_ent->next_ent = link->next_ent;
1104 		} else { ( *aasworld ).arealinkedentities[link->areanum] = link->next_ent;}
1105 		if ( link->next_ent ) {
1106 			link->next_ent->prev_ent = link->prev_ent;
1107 		}
1108 		//deallocate the link structure
1109 		AAS_DeAllocAASLink( link );
1110 	} //end for
1111 } //end of the function AAS_UnlinkFromAreas
1112 //===========================================================================
1113 // link the entity to the areas the bounding box is totally or partly
1114 // situated in. This is done with recursion down the tree using the
1115 // bounding box to test for plane sides
1116 //
1117 // Parameter:				-
1118 // Returns:					-
1119 // Changes Globals:		-
1120 //===========================================================================
1121 
1122 typedef struct
1123 {
1124 	int nodenum;        //node found after splitting
1125 } aas_linkstack_t;
1126 
AAS_AASLinkEntity(vec3_t absmins,vec3_t absmaxs,int entnum)1127 aas_link_t *AAS_AASLinkEntity( vec3_t absmins, vec3_t absmaxs, int entnum ) {
1128 	int side, nodenum;
1129 	aas_linkstack_t linkstack[128];
1130 	aas_linkstack_t *lstack_p;
1131 	aas_node_t *aasnode;
1132 	aas_plane_t *plane;
1133 	aas_link_t *link, *areas;
1134 
1135 	if ( !( *aasworld ).loaded ) {
1136 		botimport.Print( PRT_ERROR, "AAS_LinkEntity: aas not loaded\n" );
1137 		return NULL;
1138 	} //end if
1139 
1140 	areas = NULL;
1141 	//
1142 	lstack_p = linkstack;
1143 	//we start with the whole line on the stack
1144 	//start with node 1 because node zero is a dummy used for solid leafs
1145 	lstack_p->nodenum = 1;      //starting at the root of the tree
1146 	lstack_p++;
1147 
1148 	while ( 1 )
1149 	{
1150 		//pop up the stack
1151 		lstack_p--;
1152 		//if the trace stack is empty (ended up with a piece of the
1153 		//line to be traced in an area)
1154 		if ( lstack_p < linkstack ) {
1155 			break;
1156 		}
1157 		//number of the current node to test the line against
1158 		nodenum = lstack_p->nodenum;
1159 		//if it is an area
1160 		if ( nodenum < 0 ) {
1161 			//NOTE: the entity might have already been linked into this area
1162 			// because several node children can point to the same area
1163 			for ( link = ( *aasworld ).arealinkedentities[-nodenum]; link; link = link->next_ent )
1164 			{
1165 				if ( link->entnum == entnum ) {
1166 					break;
1167 				}
1168 			} //end for
1169 			if ( link ) {
1170 				continue;
1171 			}
1172 			//
1173 			link = AAS_AllocAASLink();
1174 			if ( !link ) {
1175 				return areas;
1176 			}
1177 			link->entnum = entnum;
1178 			link->areanum = -nodenum;
1179 			//put the link into the double linked area list of the entity
1180 			link->prev_area = NULL;
1181 			link->next_area = areas;
1182 			if ( areas ) {
1183 				areas->prev_area = link;
1184 			}
1185 			areas = link;
1186 			//put the link into the double linked entity list of the area
1187 			link->prev_ent = NULL;
1188 			link->next_ent = ( *aasworld ).arealinkedentities[-nodenum];
1189 			if ( ( *aasworld ).arealinkedentities[-nodenum] ) {
1190 				( *aasworld ).arealinkedentities[-nodenum]->prev_ent = link;
1191 			}
1192 			( *aasworld ).arealinkedentities[-nodenum] = link;
1193 			//
1194 			continue;
1195 		} //end if
1196 		  //if solid leaf
1197 		if ( !nodenum ) {
1198 			continue;
1199 		}
1200 		//the node to test against
1201 		aasnode = &( *aasworld ).nodes[nodenum];
1202 		//the current node plane
1203 		plane = &( *aasworld ).planes[aasnode->planenum];
1204 		//get the side(s) the box is situated relative to the plane
1205 		side = AAS_BoxOnPlaneSide2( absmins, absmaxs, plane );
1206 		//if on the front side of the node
1207 		if ( side & 1 ) {
1208 			lstack_p->nodenum = aasnode->children[0];
1209 			lstack_p++;
1210 		} //end if
1211 		if ( lstack_p >= &linkstack[127] ) {
1212 			botimport.Print( PRT_ERROR, "AAS_LinkEntity: stack overflow\n" );
1213 			break;
1214 		} //end if
1215 		  //if on the back side of the node
1216 		if ( side & 2 ) {
1217 			lstack_p->nodenum = aasnode->children[1];
1218 			lstack_p++;
1219 		} //end if
1220 		if ( lstack_p >= &linkstack[127] ) {
1221 			botimport.Print( PRT_ERROR, "AAS_LinkEntity: stack overflow\n" );
1222 			break;
1223 		} //end if
1224 	} //end while
1225 	return areas;
1226 } //end of the function AAS_AASLinkEntity
1227 //===========================================================================
1228 //
1229 // Parameter:				-
1230 // Returns:					-
1231 // Changes Globals:		-
1232 //===========================================================================
AAS_LinkEntityClientBBox(vec3_t absmins,vec3_t absmaxs,int entnum,int presencetype)1233 aas_link_t *AAS_LinkEntityClientBBox( vec3_t absmins, vec3_t absmaxs, int entnum, int presencetype ) {
1234 	vec3_t mins, maxs;
1235 	vec3_t newabsmins, newabsmaxs;
1236 
1237 	AAS_PresenceTypeBoundingBox( presencetype, mins, maxs );
1238 	VectorSubtract( absmins, maxs, newabsmins );
1239 	VectorSubtract( absmaxs, mins, newabsmaxs );
1240 	//relink the entity
1241 	return AAS_AASLinkEntity( newabsmins, newabsmaxs, entnum );
1242 } //end of the function AAS_LinkEntityClientBBox
1243 //===========================================================================
1244 //
1245 // Parameter:				-
1246 // Returns:					-
1247 // Changes Globals:		-
1248 //===========================================================================
AAS_PlaneFromNum(int planenum)1249 aas_plane_t *AAS_PlaneFromNum( int planenum ) {
1250 	if ( !( *aasworld ).loaded ) {
1251 		return NULL;
1252 	}
1253 
1254 	return &( *aasworld ).planes[planenum];
1255 } //end of the function AAS_PlaneFromNum
1256 
1257 /*
1258 =============
1259 AAS_BBoxAreas
1260 =============
1261 */
AAS_BBoxAreas(vec3_t absmins,vec3_t absmaxs,int * areas,int maxareas)1262 int AAS_BBoxAreas( vec3_t absmins, vec3_t absmaxs, int *areas, int maxareas ) {
1263 	aas_link_t *linkedareas, *link;
1264 	int num;
1265 
1266 	linkedareas = AAS_AASLinkEntity( absmins, absmaxs, -1 );
1267 	num = 0;
1268 	for ( link = linkedareas; link; link = link->next_area )
1269 	{
1270 		areas[num] = link->areanum;
1271 		num++;
1272 		if ( num >= maxareas ) {
1273 			break;
1274 		}
1275 	} //end for
1276 	AAS_UnlinkFromAreas( linkedareas );
1277 	return num;
1278 } //end of the function AAS_BBoxAreas
1279