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