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_routetable.c
32 // Function:		Area Awareness System, Route-table defines
33 // Programmer:		Ridah
34 // Tab Size:		3
35 //===========================================================================
36 
37 #include "../qcommon/q_shared.h"
38 #include "l_memory.h"
39 #include "l_script.h"
40 #include "l_precomp.h"
41 #include "l_struct.h"
42 #include "l_libvar.h"
43 #include "l_utils.h"
44 #include "aasfile.h"
45 #include "botlib.h"
46 #include "be_aas.h"
47 #include "be_interface.h"
48 #include "be_aas_def.h"
49 
50 #define	LL(x) x=LittleLong(x)
51 #define	LS(x) x=LittleShort(x)
52 
53 // ugly hack to turn off route-tables, can't find a way to check cvar's
54 int disable_routetable = 0;
55 
56 // this must be enabled for the route-tables to work, but it's not fully operational yet
57 #define CHECK_TRAVEL_TIMES
58 //#define DEBUG_ROUTETABLE
59 #define FILTERAREAS
60 
61 // enable this to use the built-in route-cache system to find the routes
62 #define USE_ROUTECACHE
63 
64 // enable this to disable Rocket/BFG Jumping, Grapple Hook
65 #define FILTER_TRAVEL
66 
67 // hmm, is there a cleaner way of finding out memory usage?
68 extern int totalmemorysize;
69 static int memorycount, cachememory;
70 
71 // globals to reduce function parameters
72 static unsigned short int *filtered_areas, childcount, num_parents;
73 static unsigned short int *rev_filtered_areas;
74 
75 // misc defines
76 unsigned short CRC_ProcessString( unsigned char *data, int length );
77 
78 
79 //===========================================================================
80 // Memory debugging/optimization
81 
AAS_RT_GetClearedMemory(unsigned long size)82 void *AAS_RT_GetClearedMemory( unsigned long size ) {
83 	void *ptr;
84 
85 	memorycount += size;
86 
87 	// ptr = GetClearedMemory(size);
88 	//ptr = GetClearedHunkMemory(size);
89 	// Ryan - 01102k, need to use this, since the routetable calculations use up a lot of memory
90 	// this will be a non-issue once we transfer the remnants of the routetable over to the aasworld
91 	ptr = malloc( size );
92 	memset( ptr, 0, size );
93 
94 	return ptr;
95 }
96 
AAS_RT_FreeMemory(void * ptr)97 void AAS_RT_FreeMemory( void *ptr ) {
98 	int before;
99 
100 	before = totalmemorysize;
101 
102 	// FreeMemory( ptr );
103 	// Ryan - 01102k
104 	free( ptr );
105 
106 	memorycount -= before - totalmemorysize;
107 }
108 
AAS_RT_PrintMemoryUsage(void)109 void AAS_RT_PrintMemoryUsage( void ) {
110 #ifdef  AAS_RT_MEMORY_USAGE
111 
112 	botimport.Print( PRT_MESSAGE, "\n" );
113 
114 	// TODO: print the usage from each of the aas_rt_t lumps
115 
116 #endif
117 }
118 //===========================================================================
119 
120 
121 //===========================================================================
122 // return the number of unassigned areas that are in the given area's visible list
123 //
124 // Parameter:				-
125 // Returns:					-
126 // Changes Globals:		-
127 //===========================================================================
AAS_RT_GetValidVisibleAreasCount(aas_area_buildlocalinfo_t * localinfo,aas_area_childlocaldata_t ** childlocaldata)128 int AAS_RT_GetValidVisibleAreasCount( aas_area_buildlocalinfo_t *localinfo, aas_area_childlocaldata_t **childlocaldata ) {
129 	int i, cnt;
130 
131 	cnt = 1;        // assume it can reach itself
132 
133 	for ( i = 0; i < localinfo->numvisible; i++ )
134 	{
135 		if ( childlocaldata[localinfo->visible[i]] ) {
136 			continue;
137 		}
138 
139 		cnt++;
140 	}
141 
142 	return cnt;
143 }
144 //===========================================================================
145 //
146 // Parameter:				-
147 // Returns:					-
148 // Changes Globals:		-
149 //===========================================================================
150 static aas_rt_route_t   **routetable;
151 
152 int AAS_AreaRouteToGoalArea( int areanum, vec3_t origin, int goalareanum, int travelflags, int *traveltime, int *reachnum );
153 
154 //===========================================================================
155 //
156 // Parameter:				-
157 // Returns:					-
158 // Changes Globals:		-
159 //===========================================================================
160 
AAS_RT_CalcTravelTimesToGoalArea(int goalarea)161 void AAS_RT_CalcTravelTimesToGoalArea( int goalarea ) {
162 	int i;
163 	// TTimo: unused
164 //	static int tfl = TFL_DEFAULT & ~(TFL_JUMPPAD|TFL_ROCKETJUMP|TFL_BFGJUMP|TFL_GRAPPLEHOOK|TFL_DOUBLEJUMP|TFL_RAMPJUMP|TFL_STRAFEJUMP|TFL_LAVA);	//----(SA)	modified since slime is no longer deadly
165 //	static int tfl = TFL_DEFAULT & ~(TFL_JUMPPAD|TFL_ROCKETJUMP|TFL_BFGJUMP|TFL_GRAPPLEHOOK|TFL_DOUBLEJUMP|TFL_RAMPJUMP|TFL_STRAFEJUMP|TFL_SLIME|TFL_LAVA);
166 	aas_rt_route_t  *rt;
167 	int reach, travel;
168 
169 	for ( i = 0; i < childcount; i++ ) {
170 		rt = &routetable[i][-1 + rev_filtered_areas[goalarea]];
171 		if ( AAS_AreaRouteToGoalArea( filtered_areas[i], ( *aasworld ).areas[filtered_areas[i]].center, goalarea, ~RTB_BADTRAVELFLAGS, &travel, &reach ) ) {
172 			rt->reachable_index = reach;
173 			rt->travel_time = travel;
174 		} else {
175 			rt->reachable_index = -1;
176 			rt->travel_time = 0;
177 		}
178 	}
179 }
180 //===========================================================================
181 // calculate the initial route-table for each filtered area to all other areas
182 //
183 // FIXME: this isn't fully operational yet, for some reason not all routes are found
184 //
185 // Parameter:				-
186 // Returns:					-
187 // Changes Globals:		-
188 //===========================================================================
AAS_RT_CalculateRouteTable(aas_rt_route_t ** parmroutetable)189 void AAS_RT_CalculateRouteTable( aas_rt_route_t **parmroutetable ) {
190 	int i;
191 
192 	routetable = parmroutetable;
193 
194 	for ( i = 0; i < childcount; i++ )
195 	{
196 		AAS_RT_CalcTravelTimesToGoalArea( filtered_areas[i] );
197 	}
198 }
199 
200 //===========================================================================
201 //
202 // Parameter:				-
203 // Returns:					-
204 // Changes Globals:		-
205 //===========================================================================
AAS_RT_AddParentLink(aas_area_childlocaldata_t * child,int parentindex,int childindex)206 void AAS_RT_AddParentLink( aas_area_childlocaldata_t *child, int parentindex, int childindex ) {
207 	aas_parent_link_t       *oldparentlink;
208 
209 	oldparentlink = child->parentlink;
210 
211 	child->parentlink = (aas_parent_link_t *) AAS_RT_GetClearedMemory( sizeof( aas_parent_link_t ) );
212 
213 	child->parentlink->childindex = (unsigned short int)childindex;
214 	child->parentlink->parent = (unsigned short int)parentindex;
215 	child->parentlink->next = oldparentlink;
216 }
217 
218 //===========================================================================
219 //
220 // Parameter:				-
221 // Returns:					-
222 // Changes Globals:		-
223 //===========================================================================
AAS_RT_WriteShort(unsigned short int si,fileHandle_t fp)224 void AAS_RT_WriteShort( unsigned short int si, fileHandle_t fp ) {
225 	unsigned short int lsi;
226 
227 	lsi = LittleShort( si );
228 	botimport.FS_Write( &lsi, sizeof( lsi ), fp );
229 }
230 
231 //===========================================================================
232 //
233 // Parameter:				-
234 // Returns:					-
235 // Changes Globals:		-
236 //===========================================================================
AAS_RT_WriteByte(int si,fileHandle_t fp)237 void AAS_RT_WriteByte( int si, fileHandle_t fp ) {
238 	unsigned char uc;
239 
240 	uc = si;
241 	botimport.FS_Write( &uc, sizeof( uc ), fp );
242 }
243 
244 //===========================================================================
245 //	writes the current route-table data to a .rtb file in tne maps folder
246 //
247 // Parameter:				-
248 // Returns:					-
249 // Changes Globals:		-
250 //===========================================================================
AAS_RT_WriteRouteTable(void)251 void AAS_RT_WriteRouteTable( void ) {
252 	int ident, version;
253 	unsigned short crc_aas;
254 	fileHandle_t fp;
255 	char filename[MAX_QPATH];
256 
257 	// open the file for writing
258 	Com_sprintf( filename, MAX_QPATH, "maps/%s.rtb", ( *aasworld ).mapname );
259 	botimport.Print( PRT_MESSAGE, "\nsaving route-table to %s\n", filename );
260 	botimport.FS_FOpenFile( filename, &fp, FS_WRITE );
261 	if ( !fp ) {
262 		AAS_Error( "Unable to open file: %s\n", filename );
263 		return;
264 	}
265 
266 	// ident
267 	ident = LittleLong( RTBID );
268 	botimport.FS_Write( &ident, sizeof( ident ), fp );
269 
270 	// version
271 	version = LittleLong( RTBVERSION );
272 	botimport.FS_Write( &version, sizeof( version ), fp );
273 
274 	// crc
275 	crc_aas = CRC_ProcessString( (unsigned char *)( *aasworld ).areas, sizeof( aas_area_t ) * ( *aasworld ).numareas );
276 	botimport.FS_Write( &crc_aas, sizeof( crc_aas ), fp );
277 
278 	// save the table data
279 
280 	// children
281 	botimport.FS_Write( &( *aasworld ).routetable->numChildren, sizeof( int ), fp );
282 	botimport.FS_Write( ( *aasworld ).routetable->children, ( *aasworld ).routetable->numChildren * sizeof( aas_rt_child_t ), fp );
283 
284 	// parents
285 	botimport.FS_Write( &( *aasworld ).routetable->numParents, sizeof( int ), fp );
286 	botimport.FS_Write( ( *aasworld ).routetable->parents, ( *aasworld ).routetable->numParents * sizeof( aas_rt_parent_t ), fp );
287 
288 	// parentChildren
289 	botimport.FS_Write( &( *aasworld ).routetable->numParentChildren, sizeof( int ), fp );
290 	botimport.FS_Write( ( *aasworld ).routetable->parentChildren, ( *aasworld ).routetable->numParentChildren * sizeof( unsigned short int ), fp );
291 
292 	// visibleParents
293 	botimport.FS_Write( &( *aasworld ).routetable->numVisibleParents, sizeof( int ), fp );
294 	botimport.FS_Write( ( *aasworld ).routetable->visibleParents, ( *aasworld ).routetable->numVisibleParents * sizeof( unsigned short int ), fp );
295 
296 	// parentLinks
297 	botimport.FS_Write( &( *aasworld ).routetable->numParentLinks, sizeof( int ), fp );
298 	botimport.FS_Write( ( *aasworld ).routetable->parentLinks, ( *aasworld ).routetable->numParentLinks * sizeof( aas_rt_parent_link_t ), fp );
299 
300 	botimport.FS_FCloseFile( fp );
301 	return;
302 }
303 
304 //===========================================================================
305 //
306 // Parameter:				-
307 // Returns:					-
308 // Changes Globals:		-
309 //===========================================================================
AAS_RT_DBG_Read(void * buf,int size,int fp)310 void AAS_RT_DBG_Read( void *buf, int size, int fp ) {
311 	botimport.FS_Read( buf, size, fp );
312 }
313 
314 //===========================================================================
315 //	reads the given file, and creates the structures required for the route-table system
316 //
317 // Parameter:				-
318 // Returns:					qtrue if succesful, qfalse if not
319 // Changes Globals:		-
320 //===========================================================================
321 #define DEBUG_READING_TIME
AAS_RT_ReadRouteTable(fileHandle_t fp)322 qboolean AAS_RT_ReadRouteTable( fileHandle_t fp ) {
323 	int ident, version, i;
324 	unsigned short int crc, crc_aas;
325 	aas_rt_t    *routetable;
326 	aas_rt_child_t  *child;
327 	aas_rt_parent_t *parent;
328 	aas_rt_parent_link_t *plink;
329 	unsigned short int  *psi;
330 
331 	qboolean doswap;
332 
333 #ifdef DEBUG_READING_TIME
334 	int pretime;
335 
336 	pretime = Sys_MilliSeconds();
337 #endif
338 
339 	routetable = ( *aasworld ).routetable;
340 
341 	doswap = ( LittleLong( 1 ) != 1 );
342 
343 	// check ident
344 	AAS_RT_DBG_Read( &ident, sizeof( ident ), fp );
345 	LL( ident );
346 
347 	if ( ident != RTBID ) {
348 		AAS_Error( "File is not an RTB file\n" );
349 		botimport.FS_FCloseFile( fp );
350 		return qfalse;
351 	}
352 
353 	// check version
354 	AAS_RT_DBG_Read( &version, sizeof( version ), fp );
355 	LL( version );
356 
357 	if ( version != RTBVERSION ) {
358 		AAS_Error( "File is version %i not %i\n", version, RTBVERSION );
359 		botimport.FS_FCloseFile( fp );
360 		return qfalse;
361 	}
362 
363 	// read the CRC check on the AAS data
364 	AAS_RT_DBG_Read( &crc, sizeof( crc ), fp );
365 	LS( crc );
366 
367 	// calculate a CRC on the AAS areas
368 	crc_aas = CRC_ProcessString( (unsigned char *)( *aasworld ).areas, sizeof( aas_area_t ) * ( *aasworld ).numareas );
369 
370 	if ( crc != crc_aas ) {
371 		AAS_Error( "Route-table is from different AAS file, ignoring.\n" );
372 		botimport.FS_FCloseFile( fp );
373 		return qfalse;
374 	}
375 
376 	// read the route-table
377 
378 	// children
379 	botimport.FS_Read( &routetable->numChildren, sizeof( int ), fp );
380 	routetable->numChildren = LittleLong( routetable->numChildren );
381 	routetable->children = (aas_rt_child_t *) AAS_RT_GetClearedMemory( routetable->numChildren * sizeof( aas_rt_child_t ) );
382 	botimport.FS_Read( routetable->children, routetable->numChildren * sizeof( aas_rt_child_t ), fp );
383 	child = &routetable->children[0];
384 	if ( doswap ) {
385 		for ( i = 0; i < routetable->numChildren; i++, child++ ) {
386 			child->areanum = LittleShort( child->areanum );
387 			child->numParentLinks = LittleLong( child->numParentLinks );
388 			child->startParentLinks = LittleLong( child->startParentLinks );
389 		}
390 	}
391 
392 	// parents
393 	botimport.FS_Read( &routetable->numParents, sizeof( int ), fp );
394 	routetable->numParents = LittleLong( routetable->numParents );
395 	routetable->parents = (aas_rt_parent_t *) AAS_RT_GetClearedMemory( routetable->numParents * sizeof( aas_rt_parent_t ) );
396 	botimport.FS_Read( routetable->parents, routetable->numParents * sizeof( aas_rt_parent_t ), fp );
397 	parent = &routetable->parents[0];
398 	if ( doswap ) {
399 		for ( i = 0; i < routetable->numParents; i++, parent++ ) {
400 			parent->areanum = LittleShort( parent->areanum );
401 			parent->numParentChildren = LittleLong( parent->numParentChildren );
402 			parent->startParentChildren = LittleLong( parent->startParentChildren );
403 			parent->numVisibleParents = LittleLong( parent->numVisibleParents );
404 			parent->startVisibleParents = LittleLong( parent->startVisibleParents );
405 		}
406 	}
407 
408 	// parentChildren
409 	botimport.FS_Read( &routetable->numParentChildren, sizeof( int ), fp );
410 	routetable->numParentChildren = LittleLong( routetable->numParentChildren );
411 	routetable->parentChildren = (unsigned short int *) AAS_RT_GetClearedMemory( routetable->numParentChildren * sizeof( unsigned short int ) );
412 	botimport.FS_Read( routetable->parentChildren, routetable->numParentChildren * sizeof( unsigned short int ), fp );
413 	psi = &routetable->parentChildren[0];
414 	if ( doswap ) {
415 		for ( i = 0; i < routetable->numParentChildren; i++, psi++ ) {
416 			*psi = LittleShort( *psi );
417 		}
418 	}
419 
420 	// visibleParents
421 	botimport.FS_Read( &routetable->numVisibleParents, sizeof( int ), fp );
422 	routetable->numVisibleParents = LittleLong( routetable->numVisibleParents );
423 	routetable->visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory( routetable->numVisibleParents * sizeof( unsigned short int ) );
424 	botimport.FS_Read( routetable->visibleParents, routetable->numVisibleParents * sizeof( unsigned short int ), fp );
425 	psi = &routetable->visibleParents[0];
426 	if ( doswap ) {
427 		for ( i = 0; i < routetable->numVisibleParents; i++, psi++ ) {
428 			*psi = LittleShort( *psi );
429 		}
430 	}
431 
432 	// parentLinks
433 	botimport.FS_Read( &routetable->numParentLinks, sizeof( int ), fp );
434 	routetable->numParentLinks = LittleLong( routetable->numParentLinks );
435 	routetable->parentLinks = (aas_rt_parent_link_t *) AAS_RT_GetClearedMemory( routetable->numParentLinks * sizeof( aas_rt_parent_link_t ) );
436 	botimport.FS_Read( routetable->parentLinks, routetable->numParentLinks * sizeof( aas_parent_link_t ), fp );
437 	plink = &routetable->parentLinks[0];
438 	if ( doswap ) {
439 		for ( i = 0; i < routetable->numParentLinks; i++, plink++ ) {
440 			plink->childIndex = LittleShort( plink->childIndex );
441 			plink->parent = LittleShort( plink->parent );
442 		}
443 	}
444 
445 	// build the areaChildIndexes
446 	routetable->areaChildIndexes = (unsigned short int *) AAS_RT_GetClearedMemory( ( *aasworld ).numareas * sizeof( unsigned short int ) );
447 	child = routetable->children;
448 	for ( i = 0; i < routetable->numChildren; i++, child++ ) {
449 		routetable->areaChildIndexes[child->areanum] = i + 1;
450 	}
451 
452 	botimport.Print( PRT_MESSAGE, "Total Parents: %d\n", routetable->numParents );
453 	botimport.Print( PRT_MESSAGE, "Total Children: %d\n", routetable->numChildren );
454 	botimport.Print( PRT_MESSAGE, "Total Memory Used: %d\n", memorycount );
455 
456 #ifdef DEBUG_READING_TIME
457 	botimport.Print( PRT_MESSAGE, "Route-Table read time: %i\n", Sys_MilliSeconds() - pretime );
458 #endif
459 
460 	botimport.FS_FCloseFile( fp );
461 	return qtrue;
462 }
463 
AAS_RT_NumParentLinks(aas_area_childlocaldata_t * child)464 int AAS_RT_NumParentLinks( aas_area_childlocaldata_t *child ) {
465 	aas_parent_link_t *plink;
466 	int i;
467 
468 	i = 0;
469 	plink = child->parentlink;
470 	while ( plink )
471 	{
472 		i++;
473 		plink = plink->next;
474 	}
475 
476 	return i;
477 }
478 
479 //===========================================================================
480 //	main routine to build the route-table
481 //
482 // Parameter:				-
483 // Returns:					-
484 // Changes Globals:		-
485 //===========================================================================
486 void AAS_CreateAllRoutingCache( void );
487 
AAS_RT_BuildRouteTable(void)488 void AAS_RT_BuildRouteTable( void ) {
489 	int i,j,k;
490 	aas_areasettings_t  *srcsettings;
491 	unsigned int totalcount;
492 	unsigned int noroutecount;
493 
494 	aas_area_buildlocalinfo_t   **area_localinfos;
495 	aas_area_buildlocalinfo_t   *localinfo;
496 
497 	aas_area_childlocaldata_t   **area_childlocaldata;
498 	aas_area_childlocaldata_t   *child;
499 
500 	aas_area_parent_t               *area_parents[MAX_PARENTS];
501 	aas_area_parent_t               *thisparent;
502 
503 	int bestchild, bestcount, bestparent, cnt;
504 
505 	int memoryend;
506 
507 	unsigned short int      *visibleParents;
508 
509 #ifdef CHECK_TRAVEL_TIMES
510 	aas_rt_route_t      **filteredroutetable;
511 	unsigned short int traveltime;
512 #endif
513 
514 	fileHandle_t fp;
515 	char filename[MAX_QPATH];
516 
517 // not used anymore
518 	return;
519 
520 	// create the routetable in this aasworld
521 	aasworld->routetable = (aas_rt_t *) AAS_RT_GetClearedMemory( sizeof( aas_rt_t ) );
522 
523 	// Try to load in a prepared route-table
524 	Com_sprintf( filename, MAX_QPATH, "maps/%s.rtb", ( *aasworld ).mapname );
525 	botimport.Print( PRT_MESSAGE, "\n---------------------------------\n" );
526 	botimport.Print( PRT_MESSAGE, "\ntrying to load %s\n", filename );
527 	botimport.FS_FOpenFile( filename, &fp, FS_READ );
528 	if ( fp ) {
529 		// read in the table..
530 		if ( AAS_RT_ReadRouteTable( fp ) ) {
531 			AAS_RT_PrintMemoryUsage();
532 
533 			botimport.Print( PRT_MESSAGE, "\nAAS Route-Table loaded.\n" );
534 			botimport.Print( PRT_MESSAGE, "---------------------------------\n\n" );
535 			return;
536 		} else
537 		{
538 			botimport.Print( PRT_MESSAGE, "\nUnable to load %s, building route-table..\n", filename );
539 		}
540 	} else
541 	{
542 		botimport.Print( PRT_MESSAGE, "file not found, building route-table\n\n" );
543 	}
544 
545 
546 	botimport.Print( PRT_MESSAGE, "\n-------------------------------------\nRoute-table memory usage figures..\n\n" );
547 
548 	totalcount = 0;
549 	childcount = 0;
550 	noroutecount = 0;
551 	childcount = 0;
552 	num_parents = 0;
553 
554 	memorycount = 0;
555 	cachememory = 0;
556 
557 	filtered_areas = (unsigned short int *) AAS_RT_GetClearedMemory( ( *aasworld ).numareas * sizeof( unsigned short int ) );
558 	rev_filtered_areas = (unsigned short int *) AAS_RT_GetClearedMemory( ( *aasworld ).numareas * sizeof( unsigned short int ) );
559 
560 	// to speed things up, build a list of FILTERED areas first
561 	// do this so we can check for filtered areas
562 	AAS_CreateAllRoutingCache();
563 	for ( i = 0; i < ( *aasworld ).numareas; i++ )
564 	{
565 		srcsettings = &( *aasworld ).areasettings[i];
566 
567 #ifdef FILTERAREAS
568 		if ( !( srcsettings->areaflags & ( AREA_USEFORROUTING ) ) ) {
569 			continue;
570 		}
571 		if ( !( srcsettings->areaflags & ( AREA_GROUNDED | AREA_LIQUID | AREA_LADDER ) ) ) {
572 			continue;
573 		}
574 #endif
575 
576 		rev_filtered_areas[i] = childcount + 1;
577 		filtered_areas[childcount++] = (unsigned short int)i;
578 	}
579 
580 #ifdef CHECK_TRAVEL_TIMES
581 	// allocate and calculate the travel times
582 	filteredroutetable = (aas_rt_route_t **) AAS_RT_GetClearedMemory( childcount * sizeof( aas_rt_route_t * ) );
583 	for ( i = 0; i < childcount; i++ )
584 		filteredroutetable[i] = (aas_rt_route_t *) AAS_RT_GetClearedMemory( childcount * sizeof( aas_rt_route_t ) );
585 
586 	AAS_RT_CalculateRouteTable( filteredroutetable );
587 
588 #endif  // CHECK_TRAVEL_TIMES
589 
590 	// allocate for the temporary build local data
591 	area_localinfos = (aas_area_buildlocalinfo_t **) AAS_RT_GetClearedMemory( childcount * sizeof( aas_area_buildlocalinfo_t * ) );
592 
593 	for ( i = 0; i < childcount; i++ )
594 	{
595 		srcsettings = &( *aasworld ).areasettings[filtered_areas[i]];
596 
597 		// allocate memory for this area
598 		area_localinfos[i] = (aas_area_buildlocalinfo_t *) AAS_RT_GetClearedMemory( sizeof( aas_area_buildlocalinfo_t ) );
599 		localinfo = area_localinfos[i];
600 
601 		for ( j = 0; j < childcount; j++ )
602 		{
603 			if ( i == j ) {
604 				continue;
605 			}
606 
607 #ifdef CHECK_TRAVEL_TIMES
608 
609 			// make sure travel time is reasonable
610 			// Get the travel time from i to j
611 			traveltime = (int)filteredroutetable[i][j].travel_time;
612 
613 			if ( !traveltime ) {
614 				noroutecount++;
615 				continue;
616 			}
617 			if ( traveltime > MAX_LOCALTRAVELTIME ) {
618 				continue;
619 			}
620 
621 #endif  // CHECK_TRAVEL_TIMES
622 
623 			// Add it to the list
624 			localinfo->visible[localinfo->numvisible++] = j;
625 			totalcount++;
626 
627 			if ( localinfo->numvisible >= MAX_VISIBLE_AREAS ) {
628 				botimport.Print( PRT_MESSAGE, "MAX_VISIBLE_AREAS exceeded, lower MAX_VISIBLE_RANGE\n" );
629 				break;
630 			}
631 		}
632 	}
633 
634 	// now calculate the best list of locale's
635 
636 	// allocate for the long-term child data
637 	area_childlocaldata = (aas_area_childlocaldata_t **) AAS_RT_GetClearedMemory( childcount * sizeof( aas_area_childlocaldata_t * ) );
638 
639 	for ( i = 0; i < childcount; i++ )
640 	{
641 		area_childlocaldata[i] = (aas_area_childlocaldata_t *) AAS_RT_GetClearedMemory( sizeof( aas_area_childlocaldata_t ) );
642 		area_childlocaldata[i]->areanum = filtered_areas[i];
643 	}
644 
645 	while ( 1 )
646 	{
647 		bestchild = -1;
648 		bestcount = 99999;
649 
650 		// find the area with the least number of visible areas
651 		for ( i = 0; i < childcount; i++ )
652 		{
653 			if ( area_childlocaldata[i]->parentlink ) {
654 				continue;   // already has been allocated to a parent
655 
656 			}
657 			cnt = AAS_RT_GetValidVisibleAreasCount( area_localinfos[i], area_childlocaldata );
658 
659 			if ( cnt < bestcount ) {
660 				bestcount = area_localinfos[i]->numvisible;
661 				bestchild = i;
662 			}
663 		}
664 
665 		if ( bestchild < 0 ) {
666 			break;      // our job is done
667 
668 
669 		}
670 		localinfo = area_localinfos[bestchild];
671 
672 
673 		// look through this area's list of visible areas, and pick the one with the most VALID visible areas
674 		bestparent = bestchild;
675 
676 		for ( i = 0; i < localinfo->numvisible; i++ )
677 		{
678 			if ( area_childlocaldata[localinfo->visible[i]]->parentlink ) {
679 				continue;   // already has been allocated to a parent
680 
681 			}
682 			// calculate how many of children are valid
683 			cnt = AAS_RT_GetValidVisibleAreasCount( area_localinfos[localinfo->visible[i]], area_childlocaldata );
684 
685 			if ( cnt > bestcount ) {
686 				bestcount = cnt;
687 				bestparent = localinfo->visible[i];
688 			}
689 		}
690 
691 		// now setup this parent, and assign all it's children
692 		localinfo = area_localinfos[bestparent];
693 
694 		// we use all children now, not just valid ones
695 		bestcount = localinfo->numvisible;
696 
697 		area_parents[num_parents] = (aas_area_parent_t *) AAS_RT_GetClearedMemory( sizeof( aas_area_parent_t ) );
698 		thisparent = area_parents[num_parents];
699 
700 		thisparent->areanum = filtered_areas[bestparent];
701 		thisparent->children = (unsigned short int *) AAS_RT_GetClearedMemory( ( localinfo->numvisible + 1 ) * sizeof( unsigned short int ) );
702 
703 		// first, add itself to the list (yes, a parent is a child of itself)
704 		child = area_childlocaldata[bestparent];
705 		AAS_RT_AddParentLink( child, num_parents, thisparent->numchildren );
706 		thisparent->children[thisparent->numchildren++] = filtered_areas[bestparent];
707 
708 		// loop around all the parent's visible list, and make them children if they're aren't already assigned to a parent
709 		for ( i = 0; i < localinfo->numvisible; i++ )
710 		{
711 			// create the childlocaldata
712 			child = area_childlocaldata[localinfo->visible[i]];
713 
714 			// Ridah, only one parent per child in the new system
715 			if ( child->parentlink ) {
716 				continue;   // already has been allocated to a parent
717 
718 			}
719 			if ( child->areanum != thisparent->areanum ) {
720 				AAS_RT_AddParentLink( child, num_parents, thisparent->numchildren );
721 				thisparent->children[thisparent->numchildren++] = filtered_areas[localinfo->visible[i]];
722 			}
723 		}
724 
725 		// now setup the list of children and the route-tables
726 		for ( i = 0; i < thisparent->numchildren; i++ )
727 		{
728 			child = area_childlocaldata[-1 + rev_filtered_areas[thisparent->children[i]]];
729 			localinfo = area_localinfos[-1 + rev_filtered_areas[thisparent->children[i]]];
730 
731 			child->parentlink->routeindexes = (unsigned short int *) AAS_RT_GetClearedMemory( thisparent->numchildren * sizeof( unsigned short int ) );
732 
733 			// now setup the indexes
734 			for ( j = 0; j < thisparent->numchildren; j++ )
735 			{
736 				// find this child in our list of visibles
737 				if ( j == child->parentlink->childindex ) {
738 					continue;
739 				}
740 
741 				for ( k = 0; k < localinfo->numvisible; k++ )
742 				{
743 					if ( thisparent->children[j] == filtered_areas[localinfo->visible[k]] ) { // found a match
744 						child->parentlink->routeindexes[j] = (unsigned short int)k;
745 						break;
746 					}
747 				}
748 
749 				if ( k == localinfo->numvisible ) { // didn't find it, so add it to our list
750 					if ( localinfo->numvisible >= MAX_VISIBLE_AREAS ) {
751 						botimport.Print( PRT_MESSAGE, "MAX_VISIBLE_AREAS exceeded, lower MAX_VISIBLE_RANGE\n" );
752 					} else
753 					{
754 						localinfo->visible[localinfo->numvisible] = -1 + rev_filtered_areas[thisparent->children[j]];
755 						child->parentlink->routeindexes[j] = (unsigned short int)localinfo->numvisible;
756 						localinfo->numvisible++;
757 					}
758 				}
759 			}
760 		}
761 
762 		num_parents++;
763 	}
764 
765 	// place all the visible areas from each child, into their childlocaldata route-table
766 	for ( i = 0; i < childcount; i++ )
767 	{
768 		localinfo = area_localinfos[i];
769 		child = area_childlocaldata[i];
770 
771 		child->numlocal = localinfo->numvisible;
772 		child->localroutes = (aas_rt_route_t *) AAS_RT_GetClearedMemory( localinfo->numvisible * sizeof( aas_rt_route_t ) );
773 
774 		for ( j = 0; j < localinfo->numvisible; j++ )
775 		{
776 			child->localroutes[j] = filteredroutetable[i][localinfo->visible[j]];
777 		}
778 
779 		child->parentroutes = (aas_rt_route_t *) AAS_RT_GetClearedMemory( num_parents * sizeof( aas_rt_route_t ) );
780 
781 		for ( j = 0; j < num_parents; j++ )
782 		{
783 			child->parentroutes[j] = filteredroutetable[i][-1 + rev_filtered_areas[area_parents[j]->areanum]];
784 		}
785 	}
786 
787 	// build the visibleParents lists
788 	visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory( num_parents * sizeof( unsigned short int ) );
789 	for ( i = 0; i < num_parents; i++ )
790 	{
791 		area_parents[i]->numVisibleParents = 0;
792 
793 		for ( j = 0; j < num_parents; j++ )
794 		{
795 			if ( i == j ) {
796 				continue;
797 			}
798 
799 			if ( !AAS_inPVS( ( *aasworld ).areas[area_parents[i]->areanum].center, ( *aasworld ).areas[area_parents[j]->areanum].center ) ) {
800 				continue;
801 			}
802 
803 			visibleParents[area_parents[i]->numVisibleParents] = j;
804 			area_parents[i]->numVisibleParents++;
805 		}
806 
807 		// now copy the list over to the current src area
808 		area_parents[i]->visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory( area_parents[i]->numVisibleParents * sizeof( unsigned short int ) );
809 		memcpy( area_parents[i]->visibleParents, visibleParents, area_parents[i]->numVisibleParents * sizeof( unsigned short int ) );
810 
811 	}
812 	AAS_RT_FreeMemory( visibleParents );
813 
814 	// before we free the main childlocaldata, go through and assign the aas_area's to their appropriate childlocaldata
815 	//	this would require modification of the aas_area_t structure, so for now, we'll just place them in a global array, for external reference
816 
817 //	aasworld->routetable->area_childlocaldata_list = (aas_area_childlocaldata_t **) AAS_RT_GetClearedMemory( (*aasworld).numareas * sizeof(aas_area_childlocaldata_t *) );
818 //	for (i=0; i<childcount; i++)
819 //	{
820 //		aasworld->routetable->area_childlocaldata_list[filtered_areas[i]] = area_childlocaldata[i];
821 //	}
822 
823 	// copy the list of parents to a global structure for now (should eventually go into the (*aasworld) structure
824 //	aasworld->routetable->area_parents_global = (aas_area_parent_t **) AAS_RT_GetClearedMemory( num_parents * sizeof(aas_area_parent_t *) );
825 //	memcpy( aasworld->routetable->area_parents_global, area_parents, num_parents * sizeof(aas_area_parent_t *) );
826 
827 	// ................................................
828 	// Convert the data into the correct format
829 	{
830 		aas_rt_t    *rt;
831 		aas_rt_child_t  *child;
832 		aas_rt_parent_t *parent;
833 		aas_rt_parent_link_t *plink;
834 		unsigned short int  *psi;
835 
836 		aas_area_childlocaldata_t   *chloc;
837 		aas_area_parent_t           *apar;
838 		aas_parent_link_t           *oplink;
839 
840 		int parentChildrenCount, visibleParentsCount, parentLinkCount;
841 
842 		rt = ( *aasworld ).routetable;
843 		parentChildrenCount = 0;
844 		visibleParentsCount = 0;
845 		parentLinkCount = 0;
846 
847 		// areaChildIndexes
848 		rt->areaChildIndexes = (unsigned short int *) AAS_RT_GetClearedMemory( ( *aasworld ).numareas * sizeof( unsigned short int ) );
849 		for ( i = 0; i < childcount; i++ )
850 		{
851 			rt->areaChildIndexes[filtered_areas[i]] = i + 1;
852 		}
853 
854 		// children
855 		rt->numChildren = childcount;
856 		rt->children = (aas_rt_child_t *) AAS_RT_GetClearedMemory( rt->numChildren * sizeof( aas_rt_child_t ) );
857 		child = rt->children;
858 		for ( i = 0; i < childcount; i++, child++ )
859 		{
860 			chloc = area_childlocaldata[i];
861 
862 			child->areanum = chloc->areanum;
863 			child->numParentLinks = AAS_RT_NumParentLinks( chloc );
864 
865 			child->startParentLinks = parentLinkCount;
866 
867 			parentLinkCount += child->numParentLinks;
868 		}
869 
870 		// parents
871 		rt->numParents = num_parents;
872 		rt->parents = (aas_rt_parent_t *) AAS_RT_GetClearedMemory( rt->numParents * sizeof( aas_rt_parent_t ) );
873 		parent = rt->parents;
874 		for ( i = 0; i < num_parents; i++, parent++ )
875 		{
876 			apar = area_parents[i];
877 
878 			parent->areanum = apar->areanum;
879 			parent->numParentChildren = apar->numchildren;
880 			parent->numVisibleParents = apar->numVisibleParents;
881 
882 			parent->startParentChildren = parentChildrenCount;
883 			parent->startVisibleParents = visibleParentsCount;
884 
885 			parentChildrenCount += parent->numParentChildren;
886 			visibleParentsCount += parent->numVisibleParents;
887 		}
888 
889 		// parentChildren
890 		rt->numParentChildren = parentChildrenCount;
891 		rt->parentChildren = (unsigned short int *) AAS_RT_GetClearedMemory( parentChildrenCount * sizeof( unsigned short int ) );
892 		psi = rt->parentChildren;
893 		for ( i = 0; i < num_parents; i++ )
894 		{
895 			apar = area_parents[i];
896 			for ( j = 0; j < apar->numchildren; j++, psi++ )
897 			{
898 				*psi = apar->children[j];
899 			}
900 		}
901 
902 		// visibleParents
903 		rt->numVisibleParents = visibleParentsCount;
904 		rt->visibleParents = (unsigned short int *) AAS_RT_GetClearedMemory( rt->numVisibleParents * sizeof( unsigned short int ) );
905 		psi = rt->visibleParents;
906 		for ( i = 0; i < num_parents; i++ )
907 		{
908 			apar = area_parents[i];
909 			for ( j = 0; j < apar->numVisibleParents; j++, psi++ )
910 			{
911 				*psi = apar->visibleParents[j];
912 			}
913 		}
914 
915 		// parentLinks
916 		rt->numParentLinks = parentLinkCount;
917 		rt->parentLinks = (aas_rt_parent_link_t *) AAS_RT_GetClearedMemory( parentLinkCount * sizeof( aas_rt_parent_link_t ) );
918 		plink = rt->parentLinks;
919 		for ( i = 0; i < childcount; i++ )
920 		{
921 			chloc = area_childlocaldata[i];
922 			for ( oplink = chloc->parentlink; oplink; plink++, oplink = oplink->next )
923 			{
924 				plink->childIndex = oplink->childindex;
925 				plink->parent = oplink->parent;
926 			}
927 		}
928 
929 	}
930 	// ................................................
931 
932 	// write the newly created table
933 	AAS_RT_WriteRouteTable();
934 
935 
936 	botimport.Print( PRT_MESSAGE, "Child Areas: %i\nTotal Parents: %i\nAverage VisAreas: %i\n", (int)childcount, num_parents, (int)( childcount / num_parents ) );
937 	botimport.Print( PRT_MESSAGE, "NoRoute Ratio: %i%%\n", (int)( ( 100.0 * noroutecount ) / ( 1.0 * childcount * childcount ) ) );
938 
939 	memoryend = memorycount;
940 
941 	// clear allocated memory
942 
943 // causes crashes in route-caching
944 //#ifdef USE_ROUTECACHE
945 //	AAS_FreeRoutingCaches();
946 //#endif
947 
948 	for ( i = 0; i < childcount; i++ )
949 	{
950 		AAS_RT_FreeMemory( area_localinfos[i] );
951 #ifdef CHECK_TRAVEL_TIMES
952 		AAS_RT_FreeMemory( filteredroutetable[i] );
953 #endif
954 	}
955 
956 	{
957 		aas_parent_link_t *next, *trav;
958 
959 		// kill the client areas
960 		for ( i = 0; i < childcount; i++ )
961 		{
962 			// kill the parent links
963 			next = area_childlocaldata[i]->parentlink;
964 			// TTimo gcc: suggests () around assignment used as truth value
965 			while ( ( trav = next ) )
966 			{
967 				next = next->next;
968 
969 				AAS_RT_FreeMemory( trav->routeindexes );
970 				AAS_RT_FreeMemory( trav );
971 			}
972 
973 			AAS_RT_FreeMemory( area_childlocaldata[i]->localroutes );
974 			AAS_RT_FreeMemory( area_childlocaldata[i]->parentroutes );
975 			AAS_RT_FreeMemory( area_childlocaldata[i] );
976 		}
977 
978 		// kill the parents
979 		for ( i = 0; i < num_parents; i++ )
980 		{
981 			AAS_RT_FreeMemory( area_parents[i]->children );
982 			AAS_RT_FreeMemory( area_parents[i]->visibleParents );
983 			AAS_RT_FreeMemory( area_parents[i] );
984 		}
985 	}
986 
987 	AAS_RT_FreeMemory( area_localinfos );
988 	AAS_RT_FreeMemory( area_childlocaldata );
989 	AAS_RT_FreeMemory( filtered_areas );
990 	AAS_RT_FreeMemory( rev_filtered_areas );
991 #ifdef CHECK_TRAVEL_TIMES
992 	AAS_RT_FreeMemory( filteredroutetable );
993 #endif
994 
995 	// check how much memory we've used, and intend to keep
996 	AAS_RT_PrintMemoryUsage();
997 
998 	botimport.Print( PRT_MESSAGE, "Route-Table Permanent Memory Usage: %i\n", memorycount );
999 	botimport.Print( PRT_MESSAGE, "Route-Table Calculation Usage: %i\n", memoryend + cachememory );
1000 	botimport.Print( PRT_MESSAGE, "---------------------------------\n" );
1001 }
1002 
1003 //===========================================================================
1004 //	free permanent memory used by route-table system
1005 //
1006 // Parameter:				-
1007 // Returns:					-
1008 // Changes Globals:		-
1009 //===========================================================================
AAS_RT_ShutdownRouteTable(void)1010 void AAS_RT_ShutdownRouteTable( void ) {
1011 	if ( !aasworld->routetable ) {
1012 		return;
1013 	}
1014 
1015 	// free the dynamic lists
1016 	AAS_RT_FreeMemory( aasworld->routetable->areaChildIndexes );
1017 	AAS_RT_FreeMemory( aasworld->routetable->children );
1018 	AAS_RT_FreeMemory( aasworld->routetable->parents );
1019 	AAS_RT_FreeMemory( aasworld->routetable->parentChildren );
1020 	AAS_RT_FreeMemory( aasworld->routetable->visibleParents );
1021 //	AAS_RT_FreeMemory( aasworld->routetable->localRoutes );
1022 //	AAS_RT_FreeMemory( aasworld->routetable->parentRoutes );
1023 	AAS_RT_FreeMemory( aasworld->routetable->parentLinks );
1024 //	AAS_RT_FreeMemory( aasworld->routetable->routeIndexes );
1025 //	AAS_RT_FreeMemory( aasworld->routetable->parentTravelTimes );
1026 
1027 	// kill the table
1028 	AAS_RT_FreeMemory( aasworld->routetable );
1029 	aasworld->routetable = NULL;
1030 }
1031 
1032 //===========================================================================
1033 //
1034 // Parameter:				-
1035 // Returns:					-
1036 // Changes Globals:		-
1037 //===========================================================================
AAS_RT_GetFirstParentLink(aas_rt_child_t * child)1038 aas_rt_parent_link_t *AAS_RT_GetFirstParentLink( aas_rt_child_t *child ) {
1039 	return &aasworld->routetable->parentLinks[child->startParentLinks];
1040 }
1041 
1042 //===========================================================================
1043 //
1044 // Parameter:				-
1045 // Returns:					-
1046 // Changes Globals:		-
1047 //===========================================================================
AAS_RT_GetChild(int areanum)1048 aas_rt_child_t *AAS_RT_GetChild( int areanum ) {
1049 	int i;
1050 
1051 	i = (int)aasworld->routetable->areaChildIndexes[areanum] - 1;
1052 
1053 	if ( i >= 0 ) {
1054 		return &aasworld->routetable->children[i];
1055 	} else {
1056 		return NULL;
1057 	}
1058 }
1059 
1060 //===========================================================================
1061 //	returns a route between the areas
1062 //
1063 // Parameter:				-
1064 // Returns:					-
1065 // Changes Globals:		-
1066 //===========================================================================
1067 int AAS_AreaRouteToGoalArea( int areanum, vec3_t origin, int goalareanum, int travelflags, int *traveltime, int *reachnum );
AAS_RT_GetRoute(int srcnum,vec3_t origin,int destnum)1068 aas_rt_route_t *AAS_RT_GetRoute( int srcnum, vec3_t origin, int destnum ) {
1069 	#define GETROUTE_NUMROUTES  64
1070 	static aas_rt_route_t routes[GETROUTE_NUMROUTES];   // cycle through these, so we don't overlap
1071 	static int routeIndex = 0;
1072 	aas_rt_route_t  *thisroute;
1073 	int reach, traveltime;
1074 	aas_rt_t *rt;
1075 	static int tfl = TFL_DEFAULT & ~( TFL_JUMPPAD | TFL_ROCKETJUMP | TFL_BFGJUMP | TFL_GRAPPLEHOOK | TFL_DOUBLEJUMP | TFL_RAMPJUMP | TFL_STRAFEJUMP | TFL_LAVA );   //----(SA)	modified since slime is no longer deadly
1076 //	static int tfl = TFL_DEFAULT & ~(TFL_JUMPPAD|TFL_ROCKETJUMP|TFL_BFGJUMP|TFL_GRAPPLEHOOK|TFL_DOUBLEJUMP|TFL_RAMPJUMP|TFL_STRAFEJUMP|TFL_SLIME|TFL_LAVA);
1077 
1078 	if ( !( rt = aasworld->routetable ) ) { // no route table present
1079 		return NULL;
1080 	}
1081 
1082 	if ( disable_routetable ) {
1083 		return NULL;
1084 	}
1085 
1086 	if ( ++routeIndex >= GETROUTE_NUMROUTES ) {
1087 		routeIndex = 0;
1088 	}
1089 
1090 	thisroute = &routes[routeIndex];
1091 
1092 	if ( AAS_AreaRouteToGoalArea( srcnum, origin, destnum, tfl, &traveltime, &reach ) ) {
1093 		thisroute->reachable_index = reach;
1094 		thisroute->travel_time = traveltime;
1095 		return thisroute;
1096 	} else {
1097 		return NULL;
1098 	}
1099 }
1100 
1101 //===========================================================================
1102 //	draws the route-table from src to dest
1103 //
1104 // Parameter:				-
1105 // Returns:					-
1106 // Changes Globals:		-
1107 //===========================================================================
1108 #include "be_ai_goal.h"
1109 int BotGetReachabilityToGoal( vec3_t origin, int areanum, int entnum,
1110 							  int lastgoalareanum, int lastareanum,
1111 							  int *avoidreach, float *avoidreachtimes, int *avoidreachtries,
1112 							  bot_goal_t *goal, int travelflags, int movetravelflags );
1113 
AAS_RT_ShowRoute(vec3_t srcpos,int srcnum,int destnum)1114 void AAS_RT_ShowRoute( vec3_t srcpos, int srcnum, int destnum ) {
1115 #ifdef DEBUG
1116 #define MAX_RT_AVOID_REACH 1
1117 	AAS_ClearShownPolygons();
1118 	AAS_ClearShownDebugLines();
1119 	AAS_ShowAreaPolygons( srcnum, 1, qtrue );
1120 	AAS_ShowAreaPolygons( destnum, 4, qtrue );
1121 	{
1122 		static int lastgoalareanum, lastareanum;
1123 		static int avoidreach[MAX_RT_AVOID_REACH];
1124 		static float avoidreachtimes[MAX_RT_AVOID_REACH];
1125 		static int avoidreachtries[MAX_RT_AVOID_REACH];
1126 		int reachnum;
1127 		bot_goal_t goal;
1128 		aas_reachability_t reach;
1129 
1130 		goal.areanum = destnum;
1131 		VectorCopy( botlibglobals.goalorigin, goal.origin );
1132 		reachnum = BotGetReachabilityToGoal( srcpos, srcnum, -1,
1133 											 lastgoalareanum, lastareanum,
1134 											 avoidreach, avoidreachtimes, avoidreachtries,
1135 											 &goal, TFL_DEFAULT | TFL_FUNCBOB, TFL_DEFAULT | TFL_FUNCBOB );
1136 		AAS_ReachabilityFromNum( reachnum, &reach );
1137 		AAS_ShowReachability( &reach );
1138 	}
1139 #endif
1140 }
1141 
1142 /*
1143 =================
1144 AAS_RT_GetHidePos
1145 
1146   "src" is hiding ent, "dest" is the enemy
1147 =================
1148 */
1149 int AAS_NearestHideArea( int srcnum, vec3_t origin, int areanum, int enemynum, vec3_t enemyorigin, int enemyareanum, int travelflags );
AAS_RT_GetHidePos(vec3_t srcpos,int srcnum,int srcarea,vec3_t destpos,int destnum,int destarea,vec3_t returnPos)1150 qboolean AAS_RT_GetHidePos( vec3_t srcpos, int srcnum, int srcarea, vec3_t destpos, int destnum, int destarea, vec3_t returnPos ) {
1151 	static int tfl = TFL_DEFAULT & ~( TFL_JUMPPAD | TFL_ROCKETJUMP | TFL_BFGJUMP | TFL_GRAPPLEHOOK | TFL_DOUBLEJUMP | TFL_RAMPJUMP | TFL_STRAFEJUMP | TFL_LAVA );   //----(SA)	modified since slime is no longer deadly
1152 //	static int tfl = TFL_DEFAULT & ~(TFL_JUMPPAD|TFL_ROCKETJUMP|TFL_BFGJUMP|TFL_GRAPPLEHOOK|TFL_DOUBLEJUMP|TFL_RAMPJUMP|TFL_STRAFEJUMP|TFL_SLIME|TFL_LAVA);
1153 
1154 #if 1
1155 	// use MrE's breadth first method
1156 	int hideareanum;
1157 //	int pretime;
1158 
1159 	// disabled this so grenade hiding works
1160 	//if (!srcarea || !destarea)
1161 	//	return qfalse;
1162 
1163 //	pretime = -Sys_MilliSeconds();
1164 
1165 	hideareanum = AAS_NearestHideArea( srcnum, srcpos, srcarea, destnum, destpos, destarea, tfl );
1166 	if ( !hideareanum ) {
1167 //		botimport.Print(PRT_MESSAGE, "Breadth First HidePos FAILED: %i ms\n", pretime + Sys_MilliSeconds());
1168 		return qfalse;
1169 	}
1170 	// we found a valid hiding area
1171 	VectorCopy( ( *aasworld ).areawaypoints[hideareanum], returnPos );
1172 
1173 //	botimport.Print(PRT_MESSAGE, "Breadth First HidePos: %i ms\n", pretime + Sys_MilliSeconds());
1174 
1175 	return qtrue;
1176 
1177 #else
1178 	// look around at random parent areas, if any of them have a center point
1179 	// that isn't visible from "destpos", then return it's position in returnPos
1180 
1181 	int i, j, pathArea, dir;
1182 	unsigned short int destTravelTime;
1183 	aas_rt_parent_t *srcParent, *travParent, *destParent;
1184 	aas_rt_child_t  *srcChild, *destChild, *travChild;
1185 	aas_rt_route_t  *route;
1186 	vec3_t destVec;
1187 	float destTravelDist;
1188 	static float lastTime;
1189 	static int frameCount, maxPerFrame = 2;
1190 	int firstreach;
1191 	aas_reachability_t  *reachability, *reach;
1192 	qboolean startVisible;
1193 	unsigned short int bestTravelTime, thisTravelTime, elapsedTravelTime;
1194 	#define MAX_HIDE_TRAVELTIME     1000    // 10 seconds is a very long way away
1195 	unsigned char destVisLookup[MAX_PARENTS];
1196 	unsigned short int *destVisTrav;
1197 
1198 	aas_rt_t    *rt;
1199 
1200 	const int MAX_CHECK_VISPARENTS    = 100;
1201 	int visparents_count, total_parents_checked;
1202 	int thisParentIndex;
1203 	int pretime;
1204 
1205 	if ( !( rt = aasworld->routetable ) ) { // no route table present
1206 		return qfalse;
1207 	}
1208 /*
1209 	if (lastTime > (AAS_Time() - 0.1)) {
1210 		if (frameCount++ > maxPerFrame) {
1211 			return qfalse;
1212 		}
1213 	} else {
1214 		frameCount = 0;
1215 		lastTime = AAS_Time();
1216 	}
1217 */
1218 	pretime = -Sys_MilliSeconds();
1219 
1220 	// is the src area grounded?
1221 	if ( !( srcChild = AAS_RT_GetChild( srcarea ) ) ) {
1222 		return qfalse;
1223 	}
1224 	// does it have a parent?
1225 // all valid areas have a parent
1226 //	if (!srcChild->numParentLinks) {
1227 //		return qfalse;
1228 //	}
1229 	// get the dest (enemy) area
1230 	if ( !( destChild = AAS_RT_GetChild( destarea ) ) ) {
1231 		return qfalse;
1232 	}
1233 	destParent = &rt->parents[ rt->parentLinks[destChild->startParentLinks].parent ];
1234 	//
1235 	// populate the destVisAreas
1236 	memset( destVisLookup, 0, sizeof( destVisLookup ) );
1237 	destVisTrav = rt->visibleParents + destParent->startVisibleParents;
1238 	for ( i = 0; i < destParent->numVisibleParents; i++, destVisTrav++ ) {
1239 		destVisLookup[*destVisTrav] = 1;
1240 	}
1241 	//
1242 	// use the first parent to source the vis areas from
1243 	srcParent = &rt->parents[ rt->parentLinks[srcChild->startParentLinks].parent ];
1244 	//
1245 	// set the destTravelTime
1246 	if ( route = AAS_RT_GetRoute( srcarea, srcpos, destarea ) ) {
1247 		destTravelTime = route->travel_time;
1248 	} else {
1249 		destTravelTime = 0;
1250 	}
1251 	bestTravelTime = MAX_HIDE_TRAVELTIME;   // ignore any routes longer than 10 seconds away
1252 	// set the destVec
1253 	VectorSubtract( destpos, srcpos, destVec );
1254 	destTravelDist = VectorNormalize( destVec );
1255 	//
1256 	// randomize the direction we traverse the list, so the hiding spot isn't always the same
1257 	if ( rand() % 2 ) {
1258 		dir = 1;    // forward
1259 	} else {
1260 		dir = -1;   // reverse
1261 	}
1262 	// randomize the starting area
1263 	if ( srcParent->numVisibleParents ) {
1264 		i = rand() % srcParent->numVisibleParents;
1265 	} else {    // prevent divide by zero
1266 		i = 0;
1267 	}
1268 	//
1269 	// setup misc stuff
1270 	reachability = ( *aasworld ).reachability;
1271 	startVisible = botimport.AICast_VisibleFromPos( destpos, destnum, srcpos, srcnum, qfalse );
1272 	//
1273 	// set the firstreach to prevent having to do an array and pointer lookup for each destination
1274 	firstreach = ( *aasworld ).areasettings[srcarea].firstreachablearea;
1275 	//
1276 	// just check random parent areas, traversing the route until we find an area that can't be seen from the dest area
1277 	for ( visparents_count = 0, total_parents_checked = 0; visparents_count < MAX_CHECK_VISPARENTS && total_parents_checked < rt->numParents; total_parents_checked++ ) {
1278 		thisParentIndex = rand() % rt->numParents;
1279 		travParent = &rt->parents[ thisParentIndex ];
1280 		//
1281 		// never go to the enemy's areas
1282 		if ( travParent->areanum == destarea ) {
1283 			continue;
1284 		}
1285 		//
1286 		// if it's visible from dest, ignore it
1287 		if ( destVisLookup[thisParentIndex] ) {
1288 			continue;
1289 		}
1290 		//
1291 		visparents_count++;
1292 		// they might be visible, check to see if the path to the area, takes us towards the
1293 		// enemy we are trying to hide from
1294 		{
1295 			qboolean invalidRoute;
1296 			vec3_t curPos, lastVec;
1297 			#define     GETHIDE_MAX_CHECK_PATHS     15
1298 			//
1299 			invalidRoute = qfalse;
1300 			// initialize the pathArea
1301 			pathArea = srcarea;
1302 			VectorCopy( srcpos, curPos );
1303 			// now evaluate the path
1304 			for ( j = 0; j < GETHIDE_MAX_CHECK_PATHS; j++ ) {
1305 				// get the reachability to the travParent
1306 				if ( !( route = AAS_RT_GetRoute( pathArea, curPos, travParent->areanum ) ) ) {
1307 					// we can't get to the travParent, so don't bother checking it
1308 					invalidRoute = qtrue;
1309 					break;
1310 				}
1311 				// set the pathArea
1312 				reach = &reachability[route->reachable_index];
1313 				// how far have we travelled so far?
1314 				elapsedTravelTime = AAS_AreaTravelTimeToGoalArea( pathArea, curPos, reach->areanum, tfl );
1315 				// add the travel to the center of the area
1316 				elapsedTravelTime += AAS_AreaTravelTime( reach->areanum, reach->end, ( *aasworld ).areas[reach->areanum].center );
1317 				// have we gone too far already?
1318 				if ( elapsedTravelTime > bestTravelTime ) {
1319 					invalidRoute = qtrue;
1320 					break;
1321 				} else {
1322 					thisTravelTime = route->travel_time;
1323 				}
1324 				//
1325 				// if this travel would have us do something wierd
1326 				if ( ( reach->traveltype == TRAVEL_WALKOFFLEDGE ) && ( reach->traveltime > 500 ) ) {
1327 					invalidRoute = qtrue;
1328 					break;
1329 				}
1330 				//
1331 				pathArea = reach->areanum;
1332 				VectorCopy( reach->end, curPos );
1333 				//
1334 				// if this moves us into the enemies area, skip it
1335 				if ( pathArea == destarea ) {
1336 					invalidRoute = qtrue;
1337 					break;
1338 				}
1339 				// if we are very close, don't get any closer under any circumstances
1340 				{
1341 					vec3_t vec;
1342 					float dist;
1343 					//
1344 					VectorSubtract( destpos, reachability[firstreach + route->reachable_index].end, vec );
1345 					dist = VectorNormalize( vec );
1346 					//
1347 					if ( destTravelTime < 400 ) {
1348 						if ( dist < destTravelDist ) {
1349 							invalidRoute = qtrue;
1350 							break;
1351 						}
1352 						if ( DotProduct( destVec, vec ) < 0.2 ) {
1353 							invalidRoute = qtrue;
1354 							break;
1355 						}
1356 					} else {
1357 						if ( dist < destTravelDist * 0.7 ) {
1358 							invalidRoute = qtrue;
1359 							break;
1360 						}
1361 					}
1362 					//
1363 					// check the directions to make sure we're not trying to run through them
1364 					if ( j > 0 ) {
1365 						if ( DotProduct( vec, lastVec ) < 0.2 ) {
1366 							invalidRoute = qtrue;
1367 							break;
1368 						}
1369 					} else if ( DotProduct( destVec, vec ) < 0.2 ) {
1370 						invalidRoute = qtrue;
1371 						break;
1372 					}
1373 					//
1374 					VectorCopy( vec, lastVec );
1375 				}
1376 				//
1377 				// if this area isn't in the visible list for the enemy's area, it's a good hiding spot
1378 				if ( !( travChild = AAS_RT_GetChild( pathArea ) ) ) {
1379 					invalidRoute = qtrue;
1380 					break;
1381 				}
1382 				if ( !destVisLookup[rt->parentLinks[travChild->startParentLinks].parent] ) {
1383 					// success ?
1384 					if ( !botimport.AICast_VisibleFromPos( destpos, destnum, ( *aasworld ).areas[pathArea].center, srcnum, qfalse ) ) {
1385 						// SUCCESS !!
1386 						travParent = &rt->parents[rt->parentLinks[travChild->startParentLinks].parent];
1387 						break;
1388 					}
1389 				} else {
1390 					// if we weren't visible when starting, make sure we don't move into their view
1391 					if ( !startVisible ) { //botimport.AICast_VisibleFromPos( destpos, destnum, reachability[firstreach + route->reachable_index].end, srcnum, qfalse )) {
1392 						invalidRoute = qtrue;
1393 						break;
1394 					}
1395 				}
1396 				//
1397 				// if this is the travParent, then stop checking
1398 				if ( pathArea == travParent->areanum ) {
1399 					invalidRoute = qtrue;   // we didn't find a hiding spot
1400 					break;
1401 				}
1402 			}   // end for areas in route
1403 			//
1404 			// if the route is invalid, skip this travParent
1405 			if ( invalidRoute ) {
1406 				continue;
1407 			}
1408 		}
1409 		//
1410 		// now last of all, check that this area is a safe hiding spot
1411 //		if (botimport.AICast_VisibleFromPos( destpos, destnum, (*aasworld).areas[travParent->areanum].center, srcnum, qfalse )) {
1412 //			continue;
1413 //		}
1414 		//
1415 		// we've found a good hiding spot, so use it
1416 		VectorCopy( ( *aasworld ).areas[travParent->areanum].center, returnPos );
1417 		bestTravelTime = elapsedTravelTime;
1418 		//
1419 		if ( thisTravelTime < 300 ) {
1420 			botimport.Print( PRT_MESSAGE, "Fuzzy RT HidePos: %i ms\n", pretime + Sys_MilliSeconds() );
1421 			return qtrue;
1422 		}
1423 	}
1424 	//
1425 	// did we find something?
1426 	if ( bestTravelTime < MAX_HIDE_TRAVELTIME ) {
1427 		botimport.Print( PRT_MESSAGE, "Fuzzy RT HidePos: %i ms\n", pretime + Sys_MilliSeconds() );
1428 		return qtrue;
1429 	}
1430 	//
1431 	// couldn't find anything
1432 	botimport.Print( PRT_MESSAGE, "Fuzzy RT HidePos FAILED: %i ms\n", pretime + Sys_MilliSeconds() );
1433 	return qfalse;
1434 #endif
1435 }
1436 
1437 /*
1438 =================
1439 AAS_RT_GetReachabilityIndex
1440 =================
1441 */
AAS_RT_GetReachabilityIndex(int areanum,int reachIndex)1442 int AAS_RT_GetReachabilityIndex( int areanum, int reachIndex ) {
1443 //	return (*aasworld).areasettings[areanum].firstreachablearea + reachIndex;
1444 	return reachIndex;
1445 }
1446