1 /*
2 ===========================================================================
3
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (RTCW MP Source Code).
8
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29
30 /*****************************************************************************
31 * name: be_aas_route.c
32 *
33 * desc: AAS
34 *
35 *
36 *****************************************************************************/
37
38 #include "../qcommon/q_shared.h"
39 #include "l_utils.h"
40 #include "l_memory.h"
41 #include "l_log.h"
42 #include "l_crc.h"
43 #include "l_libvar.h"
44 #include "l_script.h"
45 #include "l_precomp.h"
46 #include "l_struct.h"
47 #include "aasfile.h"
48 #include "botlib.h"
49 #include "be_aas.h"
50 #include "be_aas_funcs.h"
51 #include "be_interface.h"
52 #include "be_aas_def.h"
53
54 #define LL(x) x=LittleLong(x)
55
56 #define ROUTING_DEBUG
57
58 //travel time in hundreths of a second = distance * 100 / speed
59 #define DISTANCEFACTOR_CROUCH 1.3 //crouch speed = 100
60 #define DISTANCEFACTOR_SWIM 1 //should be 0.66, swim speed = 150
61 #define DISTANCEFACTOR_WALK 0.33 //walk speed = 300
62
63 // Ridah, scale traveltimes with ground steepness of area
64 #define GROUNDSTEEPNESS_TIMESCALE 20 // this is the maximum scale, 1 being the usual for a flat ground
65
66 //cache refresh time
67 #define CACHE_REFRESHTIME 15.0 //15 seconds refresh time
68
69 //maximum number of routing updates each frame
70 #define MAX_FRAMEROUTINGUPDATES 100
71
72
73 /*
74
75 area routing cache:
76 stores the distances within one cluster to a specific goal area
77 this goal area is in this same cluster and could be a cluster portal
78 for every cluster there's a list with routing cache for every area
79 in that cluster (including the portals of that cluster)
80 area cache stores (*aasworld).clusters[?].numreachabilityareas travel times
81
82 portal routing cache:
83 stores the distances of all portals to a specific goal area
84 this goal area could be in any cluster and could also be a cluster portal
85 for every area ((*aasworld).numareas) the portal cache stores
86 (*aasworld).numportals travel times
87
88 */
89
90 #ifdef ROUTING_DEBUG
91 int numareacacheupdates;
92 int numportalcacheupdates;
93 #endif //ROUTING_DEBUG
94
95 int routingcachesize;
96 int max_routingcachesize;
97
98 // Ridah, routing memory calls go here, so we can change between Hunk/Zone easily
AAS_RoutingGetMemory(int size)99 void *AAS_RoutingGetMemory( int size ) {
100 return GetClearedMemory( size );
101 }
102
AAS_RoutingFreeMemory(void * ptr)103 void AAS_RoutingFreeMemory( void *ptr ) {
104 FreeMemory( ptr );
105 }
106 // done.
107
108 //===========================================================================
109 //
110 // Parameter: -
111 // Returns: -
112 // Changes Globals: -
113 //===========================================================================
114 #ifdef ROUTING_DEBUG
AAS_RoutingInfo(void)115 void AAS_RoutingInfo( void ) {
116 botimport.Print( PRT_MESSAGE, "%d area cache updates\n", numareacacheupdates );
117 botimport.Print( PRT_MESSAGE, "%d portal cache updates\n", numportalcacheupdates );
118 botimport.Print( PRT_MESSAGE, "%d bytes routing cache\n", routingcachesize );
119 } //end of the function AAS_RoutingInfo
120 #endif //ROUTING_DEBUG
121 //===========================================================================
122 // returns the number of the area in the cluster
123 // assumes the given area is in the given cluster or a portal of the cluster
124 //
125 // Parameter: -
126 // Returns: -
127 // Changes Globals: -
128 //===========================================================================
AAS_ClusterAreaNum(int cluster,int areanum)129 static ID_INLINE int AAS_ClusterAreaNum(int cluster, int areanum) {
130 int side, areacluster;
131
132 areacluster = ( *aasworld ).areasettings[areanum].cluster;
133 if ( areacluster > 0 ) {
134 return ( *aasworld ).areasettings[areanum].clusterareanum;
135 } else
136 {
137 /*#ifdef ROUTING_DEBUG
138 if ((*aasworld).portals[-areacluster].frontcluster != cluster &&
139 (*aasworld).portals[-areacluster].backcluster != cluster)
140 {
141 botimport.Print(PRT_ERROR, "portal %d: does not belong to cluster %d\n"
142 , -areacluster, cluster);
143 } //end if
144 #endif //ROUTING_DEBUG*/
145 side = ( *aasworld ).portals[-areacluster].frontcluster != cluster;
146 return ( *aasworld ).portals[-areacluster].clusterareanum[side];
147 } //end else
148 } //end of the function AAS_ClusterAreaNum
149 //===========================================================================
150 //
151 // Parameter: -
152 // Returns: -
153 // Changes Globals: -
154 //===========================================================================
AAS_InitTravelFlagFromType(void)155 void AAS_InitTravelFlagFromType( void ) {
156 int i;
157
158 for ( i = 0; i < MAX_TRAVELTYPES; i++ )
159 {
160 ( *aasworld ).travelflagfortype[i] = TFL_INVALID;
161 } //end for
162 ( *aasworld ).travelflagfortype[TRAVEL_INVALID] = TFL_INVALID;
163 ( *aasworld ).travelflagfortype[TRAVEL_WALK] = TFL_WALK;
164 ( *aasworld ).travelflagfortype[TRAVEL_CROUCH] = TFL_CROUCH;
165 ( *aasworld ).travelflagfortype[TRAVEL_BARRIERJUMP] = TFL_BARRIERJUMP;
166 ( *aasworld ).travelflagfortype[TRAVEL_JUMP] = TFL_JUMP;
167 ( *aasworld ).travelflagfortype[TRAVEL_LADDER] = TFL_LADDER;
168 ( *aasworld ).travelflagfortype[TRAVEL_WALKOFFLEDGE] = TFL_WALKOFFLEDGE;
169 ( *aasworld ).travelflagfortype[TRAVEL_SWIM] = TFL_SWIM;
170 ( *aasworld ).travelflagfortype[TRAVEL_WATERJUMP] = TFL_WATERJUMP;
171 ( *aasworld ).travelflagfortype[TRAVEL_TELEPORT] = TFL_TELEPORT;
172 ( *aasworld ).travelflagfortype[TRAVEL_ELEVATOR] = TFL_ELEVATOR;
173 ( *aasworld ).travelflagfortype[TRAVEL_ROCKETJUMP] = TFL_ROCKETJUMP;
174 ( *aasworld ).travelflagfortype[TRAVEL_BFGJUMP] = TFL_BFGJUMP;
175 ( *aasworld ).travelflagfortype[TRAVEL_GRAPPLEHOOK] = TFL_GRAPPLEHOOK;
176 ( *aasworld ).travelflagfortype[TRAVEL_DOUBLEJUMP] = TFL_DOUBLEJUMP;
177 ( *aasworld ).travelflagfortype[TRAVEL_RAMPJUMP] = TFL_RAMPJUMP;
178 ( *aasworld ).travelflagfortype[TRAVEL_STRAFEJUMP] = TFL_STRAFEJUMP;
179 ( *aasworld ).travelflagfortype[TRAVEL_JUMPPAD] = TFL_JUMPPAD;
180 ( *aasworld ).travelflagfortype[TRAVEL_FUNCBOB] = TFL_FUNCBOB;
181 } //end of the function AAS_InitTravelFlagFromType
182 //===========================================================================
183 //
184 // Parameter: -
185 // Returns: -
186 // Changes Globals: -
187 //===========================================================================
AAS_TravelFlagForType(int traveltype)188 int AAS_TravelFlagForType( int traveltype ) {
189 if ( traveltype < 0 || traveltype >= MAX_TRAVELTYPES ) {
190 return TFL_INVALID;
191 }
192 return ( *aasworld ).travelflagfortype[traveltype];
193 } //end of the function AAS_TravelFlagForType
194 //===========================================================================
195 //
196 // Parameter: -
197 // Returns: -
198 // Changes Globals: -
199 //===========================================================================
AAS_RoutingTime(void)200 static ID_INLINE float AAS_RoutingTime(void) {
201 return AAS_Time();
202 } //end of the function AAS_RoutingTime
203 //===========================================================================
204 //
205 // Parameter: -
206 // Returns: -
207 // Changes Globals: -
208 //===========================================================================
AAS_FreeRoutingCache(aas_routingcache_t * cache)209 void AAS_FreeRoutingCache( aas_routingcache_t *cache ) {
210 routingcachesize -= cache->size;
211 AAS_RoutingFreeMemory( cache );
212 } //end of the function AAS_FreeRoutingCache
213 //===========================================================================
214 //
215 // Parameter: -
216 // Returns: -
217 // Changes Globals: -
218 //===========================================================================
AAS_RemoveRoutingCacheInCluster(int clusternum)219 void AAS_RemoveRoutingCacheInCluster( int clusternum ) {
220 int i;
221 aas_routingcache_t *cache, *nextcache;
222 aas_cluster_t *cluster;
223
224 if ( !( *aasworld ).clusterareacache ) {
225 return;
226 }
227 cluster = &( *aasworld ).clusters[clusternum];
228 for ( i = 0; i < cluster->numareas; i++ )
229 {
230 for ( cache = ( *aasworld ).clusterareacache[clusternum][i]; cache; cache = nextcache )
231 {
232 nextcache = cache->next;
233 AAS_FreeRoutingCache( cache );
234 } //end for
235 ( *aasworld ).clusterareacache[clusternum][i] = NULL;
236 } //end for
237 } //end of the function AAS_RemoveRoutingCacheInCluster
238 //===========================================================================
239 //
240 // Parameter: -
241 // Returns: -
242 // Changes Globals: -
243 //===========================================================================
AAS_RemoveRoutingCacheUsingArea(int areanum)244 void AAS_RemoveRoutingCacheUsingArea( int areanum ) {
245 int i, clusternum;
246 aas_routingcache_t *cache, *nextcache;
247
248 clusternum = ( *aasworld ).areasettings[areanum].cluster;
249 if ( clusternum > 0 ) {
250 //remove all the cache in the cluster the area is in
251 AAS_RemoveRoutingCacheInCluster( clusternum );
252 } //end if
253 else
254 {
255 // if this is a portal remove all cache in both the front and back cluster
256 AAS_RemoveRoutingCacheInCluster( ( *aasworld ).portals[-clusternum].frontcluster );
257 AAS_RemoveRoutingCacheInCluster( ( *aasworld ).portals[-clusternum].backcluster );
258 } //end else
259 // remove all portal cache
260 if ( ( *aasworld ).portalcache ) {
261 for ( i = 0; i < ( *aasworld ).numareas; i++ )
262 {
263 //refresh portal cache
264 for ( cache = ( *aasworld ).portalcache[i]; cache; cache = nextcache )
265 {
266 nextcache = cache->next;
267 AAS_FreeRoutingCache( cache );
268 } //end for
269 ( *aasworld ).portalcache[i] = NULL;
270 } //end for
271 }
272 } //end of the function AAS_RemoveRoutingCacheUsingArea
273 //===========================================================================
274 //
275 // Parameter: -
276 // Returns: -
277 // Changes Globals: -
278 //===========================================================================
AAS_EnableRoutingArea(int areanum,int enable)279 int AAS_EnableRoutingArea( int areanum, int enable ) {
280 int flags;
281
282 if ( areanum <= 0 || areanum >= ( *aasworld ).numareas ) {
283 if ( botDeveloper ) {
284 botimport.Print( PRT_ERROR, "AAS_EnableRoutingArea: areanum %d out of range\n", areanum );
285 } //end if
286 return 0;
287 } //end if
288 flags = ( *aasworld ).areasettings[areanum].areaflags & AREA_DISABLED;
289 if ( enable < 0 ) {
290 return !flags;
291 }
292
293 if ( enable ) {
294 ( *aasworld ).areasettings[areanum].areaflags &= ~AREA_DISABLED;
295 } else {
296 ( *aasworld ).areasettings[areanum].areaflags |= AREA_DISABLED;
297 }
298 // if the status of the area changed
299 if ( ( flags & AREA_DISABLED ) != ( ( *aasworld ).areasettings[areanum].areaflags & AREA_DISABLED ) ) {
300 //remove all routing cache involving this area
301 AAS_RemoveRoutingCacheUsingArea( areanum );
302 } //end if
303 return !flags;
304 } //end of the function AAS_EnableRoutingArea
305 //===========================================================================
306 //
307 // Parameter: -
308 // Returns: -
309 // Changes Globals: -
310 //===========================================================================
AAS_CreateReversedReachability(void)311 void AAS_CreateReversedReachability( void ) {
312 int i, n;
313 aas_reversedlink_t *revlink;
314 aas_reachability_t *reach;
315 aas_areasettings_t *settings;
316 char *ptr;
317 #ifdef DEBUG
318 int starttime;
319
320 starttime = Sys_MilliSeconds();
321 #endif
322 //free reversed links that have already been created
323 if ( ( *aasworld ).reversedreachability ) {
324 AAS_RoutingFreeMemory( ( *aasworld ).reversedreachability );
325 }
326 //allocate memory for the reversed reachability links
327 ptr = (char *) AAS_RoutingGetMemory( ( *aasworld ).numareas * sizeof( aas_reversedreachability_t ) +
328 ( *aasworld ).reachabilitysize * sizeof( aas_reversedlink_t ) );
329 //
330 ( *aasworld ).reversedreachability = (aas_reversedreachability_t *) ptr;
331 //pointer to the memory for the reversed links
332 ptr += ( *aasworld ).numareas * sizeof( aas_reversedreachability_t );
333 //check all other areas for reachability links to the area
334 for ( i = 1; i < ( *aasworld ).numareas; i++ )
335 {
336 //settings of the area
337 settings = &( *aasworld ).areasettings[i];
338 //check the reachability links
339 for ( n = 0; n < settings->numreachableareas; n++ )
340 {
341 //reachability link
342 reach = &( *aasworld ).reachability[settings->firstreachablearea + n];
343 //
344 revlink = (aas_reversedlink_t *) ptr;
345 ptr += sizeof( aas_reversedlink_t );
346 //
347 revlink->areanum = i;
348 revlink->linknum = settings->firstreachablearea + n;
349 revlink->next = ( *aasworld ).reversedreachability[reach->areanum].first;
350 ( *aasworld ).reversedreachability[reach->areanum].first = revlink;
351 ( *aasworld ).reversedreachability[reach->areanum].numlinks++;
352 } //end for
353 } //end for
354 #ifdef DEBUG
355 botimport.Print( PRT_MESSAGE, "reversed reachability %d msec\n", Sys_MilliSeconds() - starttime );
356 #endif //DEBUG
357 } //end of the function AAS_CreateReversedReachability
358 //===========================================================================
359 //
360 // Parameter: -
361 // Returns: -
362 // Changes Globals: -
363 //===========================================================================
AAS_AreaGroundSteepnessScale(int areanum)364 float AAS_AreaGroundSteepnessScale( int areanum ) {
365 return ( 1.0 + ( *aasworld ).areasettings[areanum].groundsteepness * (float)( GROUNDSTEEPNESS_TIMESCALE - 1 ) );
366 }
367 //===========================================================================
368 //
369 // Parameter: -
370 // Returns: -
371 // Changes Globals: -
372 //===========================================================================
AAS_AreaTravelTime(int areanum,vec3_t start,vec3_t end)373 unsigned short int AAS_AreaTravelTime( int areanum, vec3_t start, vec3_t end ) {
374 int intdist;
375 float dist;
376 vec3_t dir;
377
378 VectorSubtract( start, end, dir );
379 dist = VectorLength( dir );
380 // Ridah, factor in the groundsteepness now
381 dist *= AAS_AreaGroundSteepnessScale( areanum );
382
383 //if crouch only area
384 if ( AAS_AreaCrouch( areanum ) ) {
385 dist *= DISTANCEFACTOR_CROUCH;
386 }
387 //if swim area
388 else if ( AAS_AreaSwim( areanum ) ) {
389 dist *= DISTANCEFACTOR_SWIM;
390 }
391 //normal walk area
392 else {dist *= DISTANCEFACTOR_WALK;}
393 //
394 intdist = (int) dist;
395 //make sure the distance isn't zero
396 if ( intdist <= 0 ) {
397 intdist = 1;
398 }
399 return intdist;
400 } //end of the function AAS_AreaTravelTime
401 //===========================================================================
402 //
403 // Parameter: -
404 // Returns: -
405 // Changes Globals: -
406 //===========================================================================
AAS_CalculateAreaTravelTimes(void)407 void AAS_CalculateAreaTravelTimes( void ) {
408 int i, l, n, size;
409 char *ptr;
410 vec3_t end;
411 aas_reversedreachability_t *revreach;
412 aas_reversedlink_t *revlink;
413 aas_reachability_t *reach;
414 aas_areasettings_t *settings;
415 #ifdef DEBUG
416 int starttime;
417
418 starttime = Sys_MilliSeconds();
419 #endif
420 //if there are still area travel times, free the memory
421 if ( ( *aasworld ).areatraveltimes ) {
422 AAS_RoutingFreeMemory( ( *aasworld ).areatraveltimes );
423 }
424 //get the total size of all the area travel times
425 size = ( *aasworld ).numareas * sizeof( unsigned short ** );
426 for ( i = 0; i < ( *aasworld ).numareas; i++ )
427 {
428 revreach = &( *aasworld ).reversedreachability[i];
429 //settings of the area
430 settings = &( *aasworld ).areasettings[i];
431 //
432 size += settings->numreachableareas * sizeof( unsigned short * );
433 //
434 size += settings->numreachableareas *
435 PAD(revreach->numlinks, sizeof(long)) * sizeof(unsigned short);
436 } //end for
437 //allocate memory for the area travel times
438 ptr = (char *) AAS_RoutingGetMemory( size );
439 ( *aasworld ).areatraveltimes = (unsigned short ***) ptr;
440 ptr += ( *aasworld ).numareas * sizeof( unsigned short ** );
441 //calcluate the travel times for all the areas
442 for ( i = 0; i < ( *aasworld ).numareas; i++ )
443 {
444 //reversed reachabilities of this area
445 revreach = &( *aasworld ).reversedreachability[i];
446 //settings of the area
447 settings = &( *aasworld ).areasettings[i];
448 //
449 ( *aasworld ).areatraveltimes[i] = (unsigned short **) ptr;
450 ptr += settings->numreachableareas * sizeof( unsigned short * );
451 //
452 reach = &( *aasworld ).reachability[settings->firstreachablearea];
453 for ( l = 0; l < settings->numreachableareas; l++, reach++ )
454 {
455 ( *aasworld ).areatraveltimes[i][l] = (unsigned short *) ptr;
456 ptr += PAD(revreach->numlinks, sizeof(long)) * sizeof(unsigned short);
457 //reachability link
458 //
459 for ( n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++ )
460 {
461 VectorCopy( ( *aasworld ).reachability[revlink->linknum].end, end );
462 //
463 ( *aasworld ).areatraveltimes[i][l][n] = AAS_AreaTravelTime( i, end, reach->start );
464 } //end for
465 } //end for
466 } //end for
467 #ifdef DEBUG
468 botimport.Print( PRT_MESSAGE, "area travel times %d msec\n", Sys_MilliSeconds() - starttime );
469 #endif //DEBUG
470 } //end of the function AAS_CalculateAreaTravelTimes
471 //===========================================================================
472 //
473 // Parameter: -
474 // Returns: -
475 // Changes Globals: -
476 //===========================================================================
AAS_PortalMaxTravelTime(int portalnum)477 int AAS_PortalMaxTravelTime( int portalnum ) {
478 int l, n, t, maxt;
479 aas_portal_t *portal;
480 aas_reversedreachability_t *revreach;
481 aas_reversedlink_t *revlink;
482 aas_areasettings_t *settings;
483
484 portal = &( *aasworld ).portals[portalnum];
485 //reversed reachabilities of this portal area
486 revreach = &( *aasworld ).reversedreachability[portal->areanum];
487 //settings of the portal area
488 settings = &( *aasworld ).areasettings[portal->areanum];
489 //
490 maxt = 0;
491 for ( l = 0; l < settings->numreachableareas; l++ )
492 {
493 for ( n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++ )
494 {
495 t = ( *aasworld ).areatraveltimes[portal->areanum][l][n];
496 if ( t > maxt ) {
497 maxt = t;
498 } //end if
499 } //end for
500 } //end for
501 return maxt;
502 } //end of the function AAS_PortalMaxTravelTime
503 //===========================================================================
504 //
505 // Parameter: -
506 // Returns: -
507 // Changes Globals: -
508 //===========================================================================
AAS_InitPortalMaxTravelTimes(void)509 void AAS_InitPortalMaxTravelTimes( void ) {
510 int i;
511
512 if ( ( *aasworld ).portalmaxtraveltimes ) {
513 AAS_RoutingFreeMemory( ( *aasworld ).portalmaxtraveltimes );
514 }
515
516 ( *aasworld ).portalmaxtraveltimes = (int *) AAS_RoutingGetMemory( ( *aasworld ).numportals * sizeof( int ) );
517
518 for ( i = 0; i < ( *aasworld ).numportals; i++ )
519 {
520 ( *aasworld ).portalmaxtraveltimes[i] = AAS_PortalMaxTravelTime( i );
521 //botimport.Print(PRT_MESSAGE, "portal %d max tt = %d\n", i, (*aasworld).portalmaxtraveltimes[i]);
522 } //end for
523 } //end of the function AAS_InitPortalMaxTravelTimes
524 /*
525 //===========================================================================
526 //
527 // Parameter: -
528 // Returns: -
529 // Changes Globals: -
530 //===========================================================================
531 void AAS_UnlinkCache(aas_routingcache_t *cache)
532 {
533 if (cache->time_next) cache->time_next->time_prev = cache->time_prev;
534 else newestcache = cache->time_prev;
535 if (cache->time_prev) cache->time_prev->time_next = cache->time_next;
536 else oldestcache = cache->time_next;
537 cache->time_next = NULL;
538 cache->time_prev = NULL;
539 } //end of the function AAS_UnlinkCache
540 //===========================================================================
541 //
542 // Parameter: -
543 // Returns: -
544 // Changes Globals: -
545 //===========================================================================
546 void AAS_LinkCache(aas_routingcache_t *cache)
547 {
548 if (newestcache)
549 {
550 newestcache->time_next = cache;
551 cache->time_prev = cache;
552 } //end if
553 else
554 {
555 oldestcache = cache;
556 cache->time_prev = NULL;
557 } //end else
558 cache->time_next = NULL;
559 newestcache = cache;
560 } //end of the function AAS_LinkCache*/
561 //===========================================================================
562 //
563 // Parameter: -
564 // Returns: -
565 // Changes Globals: -
566 //===========================================================================
AAS_FreeOldestCache(void)567 int AAS_FreeOldestCache( void ) {
568 int i, j, bestcluster, bestarea, freed;
569 float besttime;
570 aas_routingcache_t *cache, *bestcache;
571
572 freed = qfalse;
573 besttime = 999999999;
574 bestcache = NULL;
575 bestcluster = 0;
576 bestarea = 0;
577 //refresh cluster cache
578 for ( i = 0; i < ( *aasworld ).numclusters; i++ )
579 {
580 for ( j = 0; j < ( *aasworld ).clusters[i].numareas; j++ )
581 {
582 for ( cache = ( *aasworld ).clusterareacache[i][j]; cache; cache = cache->next )
583 {
584 //never remove cache leading towards a portal
585 if ( ( *aasworld ).areasettings[cache->areanum].cluster < 0 ) {
586 continue;
587 }
588 //if this cache is older than the cache we found so far
589 if ( cache->time < besttime ) {
590 bestcache = cache;
591 bestcluster = i;
592 bestarea = j;
593 besttime = cache->time;
594 } //end if
595 } //end for
596 } //end for
597 } //end for
598 if ( bestcache ) {
599 cache = bestcache;
600 if ( cache->prev ) {
601 cache->prev->next = cache->next;
602 } else { ( *aasworld ).clusterareacache[bestcluster][bestarea] = cache->next;}
603 if ( cache->next ) {
604 cache->next->prev = cache->prev;
605 }
606 AAS_FreeRoutingCache( cache );
607 freed = qtrue;
608 } //end if
609 besttime = 999999999;
610 bestcache = NULL;
611 bestarea = 0;
612 for ( i = 0; i < ( *aasworld ).numareas; i++ )
613 {
614 //refresh portal cache
615 for ( cache = ( *aasworld ).portalcache[i]; cache; cache = cache->next )
616 {
617 if ( cache->time < besttime ) {
618 bestcache = cache;
619 bestarea = i;
620 besttime = cache->time;
621 } //end if
622 } //end for
623 } //end for
624 if ( bestcache ) {
625 cache = bestcache;
626 if ( cache->prev ) {
627 cache->prev->next = cache->next;
628 } else { ( *aasworld ).portalcache[bestarea] = cache->next;}
629 if ( cache->next ) {
630 cache->next->prev = cache->prev;
631 }
632 AAS_FreeRoutingCache( cache );
633 freed = qtrue;
634 } //end if
635 return freed;
636 } //end of the function AAS_FreeOldestCache
637 //===========================================================================
638 //
639 // Parameter: -
640 // Returns: -
641 // Changes Globals: -
642 //===========================================================================
AAS_AllocRoutingCache(int numtraveltimes)643 aas_routingcache_t *AAS_AllocRoutingCache( int numtraveltimes ) {
644 aas_routingcache_t *cache;
645 int size;
646
647 //
648 size = sizeof( aas_routingcache_t )
649 + numtraveltimes * sizeof( unsigned short int )
650 + numtraveltimes * sizeof( unsigned char );
651 //
652 routingcachesize += size;
653 //
654 cache = (aas_routingcache_t *) AAS_RoutingGetMemory( size );
655 cache->reachabilities = (unsigned char *) cache + sizeof( aas_routingcache_t )
656 + numtraveltimes * sizeof( unsigned short int );
657 cache->size = size;
658 return cache;
659 } //end of the function AAS_AllocRoutingCache
660 //===========================================================================
661 //
662 // Parameter: -
663 // Returns: -
664 // Changes Globals: -
665 //===========================================================================
AAS_FreeAllClusterAreaCache(void)666 void AAS_FreeAllClusterAreaCache( void ) {
667 int i, j;
668 aas_routingcache_t *cache, *nextcache;
669 aas_cluster_t *cluster;
670
671 //free all cluster cache if existing
672 if ( !( *aasworld ).clusterareacache ) {
673 return;
674 }
675 //free caches
676 for ( i = 0; i < ( *aasworld ).numclusters; i++ )
677 {
678 cluster = &( *aasworld ).clusters[i];
679 for ( j = 0; j < cluster->numareas; j++ )
680 {
681 for ( cache = ( *aasworld ).clusterareacache[i][j]; cache; cache = nextcache )
682 {
683 nextcache = cache->next;
684 AAS_FreeRoutingCache( cache );
685 } //end for
686 ( *aasworld ).clusterareacache[i][j] = NULL;
687 } //end for
688 } //end for
689 //free the cluster cache array
690 AAS_RoutingFreeMemory( ( *aasworld ).clusterareacache );
691 ( *aasworld ).clusterareacache = NULL;
692 } //end of the function AAS_FreeAllClusterAreaCache
693 //===========================================================================
694 //
695 // Parameter: -
696 // Returns: -
697 // Changes Globals: -
698 //===========================================================================
AAS_InitClusterAreaCache(void)699 void AAS_InitClusterAreaCache( void ) {
700 int i, size;
701 char *ptr;
702
703 //
704 for ( size = 0, i = 0; i < ( *aasworld ).numclusters; i++ )
705 {
706 size += ( *aasworld ).clusters[i].numareas;
707 } //end for
708 //two dimensional array with pointers for every cluster to routing cache
709 //for every area in that cluster
710 ptr = (char *) AAS_RoutingGetMemory(
711 ( *aasworld ).numclusters * sizeof( aas_routingcache_t * * ) +
712 size * sizeof( aas_routingcache_t * ) );
713 ( *aasworld ).clusterareacache = (aas_routingcache_t ***) ptr;
714 ptr += ( *aasworld ).numclusters * sizeof( aas_routingcache_t * * );
715 for ( i = 0; i < ( *aasworld ).numclusters; i++ )
716 {
717 ( *aasworld ).clusterareacache[i] = (aas_routingcache_t **) ptr;
718 ptr += ( *aasworld ).clusters[i].numareas * sizeof( aas_routingcache_t * );
719 } //end for
720 } //end of the function AAS_InitClusterAreaCache
721 //===========================================================================
722 //
723 // Parameter: -
724 // Returns: -
725 // Changes Globals: -
726 //===========================================================================
AAS_FreeAllPortalCache(void)727 void AAS_FreeAllPortalCache( void ) {
728 int i;
729 aas_routingcache_t *cache, *nextcache;
730
731 //free all portal cache if existing
732 if ( !( *aasworld ).portalcache ) {
733 return;
734 }
735 //free portal caches
736 for ( i = 0; i < ( *aasworld ).numareas; i++ )
737 {
738 for ( cache = ( *aasworld ).portalcache[i]; cache; cache = nextcache )
739 {
740 nextcache = cache->next;
741 AAS_FreeRoutingCache( cache );
742 } //end for
743 ( *aasworld ).portalcache[i] = NULL;
744 } //end for
745 AAS_RoutingFreeMemory( ( *aasworld ).portalcache );
746 ( *aasworld ).portalcache = NULL;
747 } //end of the function AAS_FreeAllPortalCache
748 //===========================================================================
749 //
750 // Parameter: -
751 // Returns: -
752 // Changes Globals: -
753 //===========================================================================
AAS_InitPortalCache(void)754 void AAS_InitPortalCache( void ) {
755 //
756 ( *aasworld ).portalcache = (aas_routingcache_t **) AAS_RoutingGetMemory(
757 ( *aasworld ).numareas * sizeof( aas_routingcache_t * ) );
758 } //end of the function AAS_InitPortalCache
759 //
760 //===========================================================================
761 //
762 // Parameter: -
763 // Returns: -
764 // Changes Globals: -
765 //===========================================================================
AAS_FreeAreaVisibility(void)766 void AAS_FreeAreaVisibility( void ) {
767 int i;
768
769 if ( ( *aasworld ).areavisibility ) {
770 for ( i = 0; i < ( *aasworld ).numareas; i++ )
771 {
772 if ( ( *aasworld ).areavisibility[i] ) {
773 FreeMemory( ( *aasworld ).areavisibility[i] );
774 }
775 }
776 }
777 if ( ( *aasworld ).areavisibility ) {
778 FreeMemory( ( *aasworld ).areavisibility );
779 }
780 ( *aasworld ).areavisibility = NULL;
781 if ( ( *aasworld ).decompressedvis ) {
782 FreeMemory( ( *aasworld ).decompressedvis );
783 }
784 ( *aasworld ).decompressedvis = NULL;
785 }
786 //===========================================================================
787 //
788 // Parameter: -
789 // Returns: -
790 // Changes Globals: -
791 //===========================================================================
AAS_InitRoutingUpdate(void)792 void AAS_InitRoutingUpdate( void ) {
793 // int i, maxreachabilityareas;
794
795 //free routing update fields if already existing
796 if ( ( *aasworld ).areaupdate ) {
797 AAS_RoutingFreeMemory( ( *aasworld ).areaupdate );
798 }
799 //
800 // Ridah, had to change it to numareas for hidepos checking
801 /*
802 maxreachabilityareas = 0;
803 for (i = 0; i < (*aasworld).numclusters; i++)
804 {
805 if ((*aasworld).clusters[i].numreachabilityareas > maxreachabilityareas)
806 {
807 maxreachabilityareas = (*aasworld).clusters[i].numreachabilityareas;
808 } //end if
809 } //end for
810 //allocate memory for the routing update fields
811 (*aasworld).areaupdate = (aas_routingupdate_t *) AAS_RoutingGetMemory(
812 maxreachabilityareas * sizeof(aas_routingupdate_t));
813 */
814 ( *aasworld ).areaupdate = (aas_routingupdate_t *) AAS_RoutingGetMemory(
815 ( *aasworld ).numareas * sizeof( aas_routingupdate_t ) );
816 //
817 if ( ( *aasworld ).portalupdate ) {
818 AAS_RoutingFreeMemory( ( *aasworld ).portalupdate );
819 }
820 //allocate memory for the portal update fields
821 ( *aasworld ).portalupdate = (aas_routingupdate_t *) AAS_RoutingGetMemory(
822 ( ( *aasworld ).numportals + 1 ) * sizeof( aas_routingupdate_t ) );
823 } //end of the function AAS_InitRoutingUpdate
824 //===========================================================================
825 //
826 // Parameter: -
827 // Returns: -
828 // Changes Globals: -
829 //===========================================================================
830
AAS_CreateAllRoutingCache(void)831 void AAS_CreateAllRoutingCache( void ) {
832 int i, j, k, tfl, numroutingareas;
833 aas_areasettings_t *areasettings;
834 aas_reachability_t *reach;
835
836 numroutingareas = 0;
837 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
838 // tfl = TFL_DEFAULT & ~(TFL_JUMPPAD|TFL_ROCKETJUMP|TFL_BFGJUMP|TFL_GRAPPLEHOOK|TFL_DOUBLEJUMP|TFL_RAMPJUMP|TFL_STRAFEJUMP|TFL_SLIME|TFL_LAVA);
839 botimport.Print( PRT_MESSAGE, "AAS_CreateAllRoutingCache\n" );
840 //
841 for ( i = 1; i < ( *aasworld ).numareas; i++ )
842 {
843 if ( !AAS_AreaReachability( i ) ) {
844 continue;
845 }
846 areasettings = &( *aasworld ).areasettings[i];
847 for ( k = 0; k < areasettings->numreachableareas; k++ )
848 {
849 reach = &( *aasworld ).reachability[areasettings->firstreachablearea + k];
850 if ( ( *aasworld ).travelflagfortype[reach->traveltype] & tfl ) {
851 break;
852 }
853 }
854 if ( k >= areasettings->numreachableareas ) {
855 continue;
856 }
857 ( *aasworld ).areasettings[i].areaflags |= AREA_USEFORROUTING;
858 numroutingareas++;
859 }
860 for ( i = 1; i < ( *aasworld ).numareas; i++ )
861 {
862 if ( !( ( *aasworld ).areasettings[i].areaflags & AREA_USEFORROUTING ) ) {
863 continue;
864 }
865 for ( j = 1; j < ( *aasworld ).numareas; j++ )
866 {
867 if ( i == j ) {
868 continue;
869 }
870 if ( !( ( *aasworld ).areasettings[j].areaflags & AREA_USEFORROUTING ) ) {
871 continue;
872 }
873 AAS_AreaTravelTimeToGoalArea( j, ( *aasworld ).areawaypoints[j], i, tfl );
874 //( *aasworld ).frameroutingupdates = 0;
875 } //end for
876 } //end for
877 } //end of the function AAS_CreateAllRoutingCache
878 //===========================================================================
879 //
880 // Parameter: -
881 // Returns: -
882 // Changes Globals: -
883 //===========================================================================
AAS_WriteCache(fileHandle_t fp,aas_routingcache_t * nativecache)884 void AAS_WriteCache( fileHandle_t fp, aas_routingcache_t *nativecache ) {
885 int i, size, numtraveltimes;
886 aas_routingcache_32_t *cache;
887 unsigned char *cache_reachabilities;
888
889 size = nativecache->size + sizeof (aas_routingcache_32_t) - sizeof (aas_routingcache_t);
890
891 cache = GetClearedMemory( size );
892 cache->size = LittleLong( size );
893 cache->time = LittleFloat( nativecache->time );
894 cache->cluster = LittleLong( nativecache->cluster );
895 cache->areanum = LittleLong( nativecache->areanum );
896 cache->origin[0] = LittleFloat( nativecache->origin[0] );
897 cache->origin[1] = LittleFloat( nativecache->origin[1] );
898 cache->origin[2] = LittleFloat( nativecache->origin[2] );
899 cache->starttraveltime = LittleFloat( nativecache->starttraveltime );
900 cache->travelflags = LittleLong( nativecache->travelflags );
901
902 numtraveltimes = ( size - sizeof( aas_routingcache_32_t ) ) / 3;
903 for ( i = 0; i < numtraveltimes; i++ ) {
904 cache->traveltimes[i] = LittleShort( nativecache->traveltimes[i] );
905 }
906
907 cache_reachabilities = (unsigned char *) cache + sizeof( aas_routingcache_32_t ) + numtraveltimes * sizeof (cache->traveltimes[0]);
908 for ( i = 0; i < numtraveltimes; i++ ) {
909 cache_reachabilities[i] = nativecache->reachabilities[i];
910 }
911
912 botimport.FS_Write( cache, size, fp );
913 FreeMemory( cache );
914 } //end of the function AAS_WriteCache
915 //===========================================================================
916 //
917 // Parameter: -
918 // Returns: -
919 // Changes Globals: -
920 //===========================================================================
921 unsigned short CRC_ProcessString( unsigned char *data, int length );
922
923 //the route cache header
924 //this header is followed by numportalcache + numareacache aas_routingcache_t
925 //structures that store routing cache
926 typedef struct routecacheheader_s
927 {
928 int ident;
929 int version;
930 int numareas;
931 int numclusters;
932 int areacrc;
933 int clustercrc;
934 int reachcrc;
935 int numportalcache;
936 int numareacache;
937 } routecacheheader_t;
938
939 #define RCID ( ( 'C' << 24 ) + ( 'R' << 16 ) + ( 'E' << 8 ) + 'M' )
940 #define RCVERSION 12
941
942 void AAS_DecompressVis( byte *in, int numareas, byte *decompressed );
943 int AAS_CompressVis( byte *vis, int numareas, byte *dest );
944
AAS_WriteRouteCache(void)945 void AAS_WriteRouteCache( void ) {
946 int i, j, numportalcache, numareacache, size;
947 aas_routingcache_t *cache;
948 aas_cluster_t *cluster;
949 fileHandle_t fp;
950 char filename[MAX_QPATH];
951 routecacheheader_t routecacheheader;
952 byte *buf;
953 vec3_t waypoint;
954
955 buf = (byte *) GetClearedMemory( ( *aasworld ).numareas * 2 * sizeof( byte ) ); // in case it ends up bigger than the decompressedvis, which is rare but possible
956
957 numportalcache = 0;
958 for ( i = 0; i < ( *aasworld ).numareas; i++ )
959 {
960 for ( cache = ( *aasworld ).portalcache[i]; cache; cache = cache->next )
961 {
962 numportalcache++;
963 } //end for
964 } //end for
965 numareacache = 0;
966 for ( i = 0; i < ( *aasworld ).numclusters; i++ )
967 {
968 cluster = &( *aasworld ).clusters[i];
969 for ( j = 0; j < cluster->numareas; j++ )
970 {
971 for ( cache = ( *aasworld ).clusterareacache[i][j]; cache; cache = cache->next )
972 {
973 numareacache++;
974 } //end for
975 } //end for
976 } //end for
977 // open the file for writing
978 Com_sprintf( filename, MAX_QPATH, "maps/%s.rcd", ( *aasworld ).mapname );
979 botimport.FS_FOpenFile( filename, &fp, FS_WRITE );
980 if ( !fp ) {
981 AAS_Error( "Unable to open file: %s\n", filename );
982 return;
983 } //end if
984 //create the header
985 routecacheheader.ident = LittleLong( RCID );
986 routecacheheader.version = LittleLong( RCVERSION );
987 routecacheheader.numareas = LittleLong( ( *aasworld ).numareas );
988 routecacheheader.numclusters = LittleLong( ( *aasworld ).numclusters );
989 routecacheheader.areacrc = LittleLong( CRC_ProcessString( (unsigned char *)( *aasworld ).areas, sizeof( aas_area_t ) * ( *aasworld ).numareas ) );
990 routecacheheader.clustercrc = LittleLong( CRC_ProcessString( (unsigned char *)( *aasworld ).clusters, sizeof( aas_cluster_t ) * ( *aasworld ).numclusters ) );
991 routecacheheader.reachcrc = LittleLong( CRC_ProcessString( (unsigned char *)( *aasworld ).reachability, sizeof( aas_reachability_t ) * ( *aasworld ).reachabilitysize ) );
992 routecacheheader.numportalcache = LittleLong( numportalcache );
993 routecacheheader.numareacache = LittleLong( numareacache );
994 //write the header
995 botimport.FS_Write( &routecacheheader, sizeof( routecacheheader_t ), fp );
996 //write all the cache
997 for ( i = 0; i < ( *aasworld ).numareas; i++ )
998 {
999 for ( cache = ( *aasworld ).portalcache[i]; cache; cache = cache->next )
1000 {
1001 AAS_WriteCache( fp, cache );
1002 } //end for
1003 } //end for
1004 for ( i = 0; i < ( *aasworld ).numclusters; i++ )
1005 {
1006 cluster = &( *aasworld ).clusters[i];
1007 for ( j = 0; j < cluster->numareas; j++ )
1008 {
1009 for ( cache = ( *aasworld ).clusterareacache[i][j]; cache; cache = cache->next )
1010 {
1011 AAS_WriteCache( fp, cache );
1012 } //end for
1013 } //end for
1014 } //end for
1015 // write the visareas
1016 for ( i = 0; i < ( *aasworld ).numareas; i++ )
1017 {
1018 if ( !( *aasworld ).areavisibility[i] ) {
1019 size = LittleLong( 0 );
1020 botimport.FS_Write( &size, sizeof( int ), fp );
1021 continue;
1022 }
1023 AAS_DecompressVis( ( *aasworld ).areavisibility[i], ( *aasworld ).numareas, ( *aasworld ).decompressedvis );
1024 size = AAS_CompressVis( ( *aasworld ).decompressedvis, ( *aasworld ).numareas, buf );
1025 LL( size );
1026 botimport.FS_Write( &size, sizeof( int ), fp );
1027 LL( size ); // convert back to native endian
1028 botimport.FS_Write( buf, size, fp );
1029 }
1030 // write the waypoints
1031 for ( i = 0; i < ( *aasworld ).numareas; i++ ) {
1032 waypoint[0] = LittleFloat( ( *aasworld ).areawaypoints[i][0] );
1033 waypoint[1] = LittleFloat( ( *aasworld ).areawaypoints[i][1] );
1034 waypoint[2] = LittleFloat( ( *aasworld ).areawaypoints[i][2] );
1035 botimport.FS_Write( waypoint, sizeof( vec3_t ), fp );
1036 }
1037 //
1038 botimport.FS_FCloseFile( fp );
1039 botimport.Print( PRT_MESSAGE, "\nroute cache written to %s\n", filename );
1040 } //end of the function AAS_WriteRouteCache
1041 //===========================================================================
1042 //
1043 // Parameter: -
1044 // Returns: -
1045 // Changes Globals: -
1046 //===========================================================================
AAS_ReadCache(fileHandle_t fp)1047 aas_routingcache_t *AAS_ReadCache( fileHandle_t fp ) {
1048 int i, size, numtraveltimes;
1049 aas_routingcache_t *nativecache;
1050 aas_routingcache_32_t *cache;
1051 unsigned char *cache_reachabilities;
1052
1053 botimport.FS_Read( &size, sizeof( size ), fp );
1054 LL( size );
1055 cache = (aas_routingcache_32_t *) AAS_RoutingGetMemory( size );
1056 cache->size = size;
1057 botimport.FS_Read( (unsigned char *)cache + sizeof( size ), size - sizeof( size ), fp );
1058
1059 numtraveltimes = ( size - sizeof( aas_routingcache_32_t ) ) / 3;
1060
1061 if ( sizeof (intptr_t) == 4 ) {
1062 nativecache = (aas_routingcache_t *) cache;
1063 } else {
1064 int nativesize = size - sizeof (aas_routingcache_32_t) + sizeof (aas_routingcache_t);
1065 nativecache = (aas_routingcache_t *) AAS_RoutingGetMemory( nativesize );
1066 nativecache->size = nativesize;
1067 }
1068
1069 // copy to native structure and/or swap
1070 if ( sizeof (intptr_t) != 4 || 1 != LittleLong( 1 ) ) {
1071 nativecache->time = LittleFloat( cache->time );
1072 nativecache->cluster = LittleLong( cache->cluster );
1073 nativecache->areanum = LittleLong( cache->areanum );
1074 nativecache->origin[0] = LittleFloat( cache->origin[0] );
1075 nativecache->origin[1] = LittleFloat( cache->origin[1] );
1076 nativecache->origin[2] = LittleFloat( cache->origin[2] );
1077 nativecache->starttraveltime = LittleFloat( cache->starttraveltime );
1078 nativecache->travelflags = LittleLong( cache->travelflags );
1079
1080 //DAJ BUGFIX for missing byteswaps for traveltimes
1081 for ( i = 0; i < numtraveltimes; i++ ) {
1082 nativecache->traveltimes[i] = LittleShort( cache->traveltimes[i] );
1083 }
1084 }
1085
1086 nativecache->reachabilities = (unsigned char *) nativecache + sizeof( aas_routingcache_t ) + numtraveltimes * sizeof (nativecache->traveltimes[0]);
1087
1088 // copy reachabilities to native structure, free original cache
1089 if ( sizeof (intptr_t) != 4 ) {
1090 cache_reachabilities = (unsigned char *) cache + sizeof( aas_routingcache_32_t ) + numtraveltimes * sizeof (cache->traveltimes[0]);
1091
1092 for ( i = 0; i < numtraveltimes; i++ ) {
1093 nativecache->reachabilities[i] = cache_reachabilities[i];
1094 }
1095
1096 AAS_RoutingFreeMemory(cache);
1097 }
1098
1099 return nativecache;
1100 } //end of the function AAS_ReadCache
1101 //===========================================================================
1102 //
1103 // Parameter: -
1104 // Returns: -
1105 // Changes Globals: -
1106 //===========================================================================
AAS_ReadRouteCache(void)1107 int AAS_ReadRouteCache( void ) {
1108 int i, clusterareanum, size;
1109 fileHandle_t fp = 0;
1110 char filename[MAX_QPATH];
1111 routecacheheader_t routecacheheader;
1112 aas_routingcache_t *cache;
1113
1114 Com_sprintf( filename, MAX_QPATH, "maps/%s.rcd", ( *aasworld ).mapname );
1115 botimport.FS_FOpenFile( filename, &fp, FS_READ );
1116 if ( !fp ) {
1117 return qfalse;
1118 } //end if
1119 botimport.FS_Read( &routecacheheader, sizeof( routecacheheader_t ), fp );
1120 routecacheheader.areacrc = LittleLong( routecacheheader.areacrc );
1121 routecacheheader.clustercrc = LittleLong( routecacheheader.clustercrc );
1122 routecacheheader.ident = LittleLong( routecacheheader.ident );
1123 routecacheheader.numareacache = LittleLong( routecacheheader.numareacache );
1124 routecacheheader.numareas = LittleLong( routecacheheader.numareas );
1125 routecacheheader.numclusters = LittleLong( routecacheheader.numclusters );
1126 routecacheheader.numportalcache = LittleLong( routecacheheader.numportalcache );
1127 routecacheheader.reachcrc = LittleLong( routecacheheader.reachcrc );
1128 routecacheheader.version = LittleLong( routecacheheader.version );
1129
1130 if ( routecacheheader.ident != RCID ) {
1131 botimport.FS_FCloseFile( fp );
1132 Com_Printf( "%s is not a route cache dump\n", filename ); // not an aas_error because we want to continue
1133 return qfalse; // and remake them by returning false here
1134 } //end if
1135
1136 if ( routecacheheader.version != RCVERSION ) {
1137 botimport.FS_FCloseFile( fp );
1138 Com_Printf( "route cache dump has wrong version %d, should be %d\n", routecacheheader.version, RCVERSION );
1139 return qfalse;
1140 } //end if
1141 if ( routecacheheader.numareas != ( *aasworld ).numareas ) {
1142 botimport.FS_FCloseFile( fp );
1143 //AAS_Error("route cache dump has wrong number of areas\n");
1144 return qfalse;
1145 } //end if
1146 if ( routecacheheader.numclusters != ( *aasworld ).numclusters ) {
1147 botimport.FS_FCloseFile( fp );
1148 //AAS_Error("route cache dump has wrong number of clusters\n");
1149 return qfalse;
1150 } //end if
1151 // crc code is only good on little endian machines
1152 if ( 1 == LittleLong( 1 ) ) {
1153 if ( routecacheheader.areacrc !=
1154 CRC_ProcessString( (unsigned char *)( *aasworld ).areas, sizeof( aas_area_t ) * ( *aasworld ).numareas ) ) {
1155 botimport.FS_FCloseFile( fp );
1156 //AAS_Error("route cache dump area CRC incorrect\n");
1157 return qfalse;
1158 } //end if
1159 if ( routecacheheader.clustercrc !=
1160 CRC_ProcessString( (unsigned char *)( *aasworld ).clusters, sizeof( aas_cluster_t ) * ( *aasworld ).numclusters ) ) {
1161 botimport.FS_FCloseFile( fp );
1162 //AAS_Error("route cache dump cluster CRC incorrect\n");
1163 return qfalse;
1164 } //end if
1165 if ( routecacheheader.reachcrc !=
1166 CRC_ProcessString( (unsigned char *)( *aasworld ).reachability, sizeof( aas_reachability_t ) * ( *aasworld ).reachabilitysize ) ) {
1167 botimport.FS_FCloseFile( fp );
1168 //AAS_Error("route cache dump reachability CRC incorrect\n");
1169 return qfalse;
1170 } //end if
1171 } //end if
1172 //read all the portal cache
1173 for ( i = 0; i < routecacheheader.numportalcache; i++ )
1174 {
1175 cache = AAS_ReadCache( fp );
1176 cache->next = ( *aasworld ).portalcache[cache->areanum];
1177 cache->prev = NULL;
1178 if ( ( *aasworld ).portalcache[cache->areanum] ) {
1179 ( *aasworld ).portalcache[cache->areanum]->prev = cache;
1180 }
1181 ( *aasworld ).portalcache[cache->areanum] = cache;
1182 } //end for
1183 //read all the cluster area cache
1184 for ( i = 0; i < routecacheheader.numareacache; i++ )
1185 {
1186 cache = AAS_ReadCache( fp );
1187 clusterareanum = AAS_ClusterAreaNum( cache->cluster, cache->areanum );
1188 cache->next = ( *aasworld ).clusterareacache[cache->cluster][clusterareanum];
1189 cache->prev = NULL;
1190 if ( ( *aasworld ).clusterareacache[cache->cluster][clusterareanum] ) {
1191 ( *aasworld ).clusterareacache[cache->cluster][clusterareanum]->prev = cache;
1192 }
1193 ( *aasworld ).clusterareacache[cache->cluster][clusterareanum] = cache;
1194 } //end for
1195 // read the visareas
1196 ( *aasworld ).areavisibility = (byte **) GetClearedMemory( ( *aasworld ).numareas * sizeof( byte * ) );
1197 ( *aasworld ).decompressedvis = (byte *) GetClearedMemory( ( *aasworld ).numareas * sizeof( byte ) );
1198 for ( i = 0; i < ( *aasworld ).numareas; i++ )
1199 {
1200 botimport.FS_Read( &size, sizeof( size ), fp );
1201 LL( size );
1202 if ( size ) {
1203 ( *aasworld ).areavisibility[i] = (byte *) GetMemory( size );
1204 botimport.FS_Read( ( *aasworld ).areavisibility[i], size, fp );
1205 }
1206 }
1207 // read the area waypoints
1208 ( *aasworld ).areawaypoints = (vec3_t *) GetClearedMemory( ( *aasworld ).numareas * sizeof( vec3_t ) );
1209 botimport.FS_Read( ( *aasworld ).areawaypoints, ( *aasworld ).numareas * sizeof( vec3_t ), fp );
1210 if ( 1 != LittleLong( 1 ) ) {
1211 for ( i = 0; i < ( *aasworld ).numareas; i++ ) {
1212 ( *aasworld ).areawaypoints[i][0] = LittleFloat( ( *aasworld ).areawaypoints[i][0] );
1213 ( *aasworld ).areawaypoints[i][1] = LittleFloat( ( *aasworld ).areawaypoints[i][1] );
1214 ( *aasworld ).areawaypoints[i][2] = LittleFloat( ( *aasworld ).areawaypoints[i][2] );
1215 }
1216 }
1217 //
1218 botimport.FS_FCloseFile( fp );
1219 return qtrue;
1220 } //end of the function AAS_ReadRouteCache
1221 //===========================================================================
1222 //
1223 // Parameter: -
1224 // Returns: -
1225 // Changes Globals: -
1226 //===========================================================================
1227 void AAS_CreateVisibility( void );
AAS_InitRouting(void)1228 void AAS_InitRouting( void ) {
1229 AAS_InitTravelFlagFromType();
1230 //initialize the routing update fields
1231 AAS_InitRoutingUpdate();
1232 //create reversed reachability links used by the routing update algorithm
1233 AAS_CreateReversedReachability();
1234 //initialize the cluster cache
1235 AAS_InitClusterAreaCache();
1236 //initialize portal cache
1237 AAS_InitPortalCache();
1238 //initialize the area travel times
1239 AAS_CalculateAreaTravelTimes();
1240 //calculate the maximum travel times through portals
1241 AAS_InitPortalMaxTravelTimes();
1242 //
1243 #ifdef ROUTING_DEBUG
1244 numareacacheupdates = 0;
1245 numportalcacheupdates = 0;
1246 #endif //ROUTING_DEBUG
1247 //
1248 routingcachesize = 0;
1249 max_routingcachesize = 1024 * (int) LibVarValue( "max_routingcache", "4096" );
1250 //
1251 // Ridah, load or create the routing cache
1252 if ( !AAS_ReadRouteCache() ) {
1253 ( *aasworld ).initialized = qtrue; // Hack, so routing can compute traveltimes
1254 AAS_CreateVisibility();
1255 AAS_CreateAllRoutingCache();
1256 ( *aasworld ).initialized = qfalse;
1257
1258 AAS_WriteRouteCache(); // save it so we don't have to create it again
1259 }
1260 // done.
1261 } //end of the function AAS_InitRouting
1262 //===========================================================================
1263 //
1264 // Parameter: -
1265 // Returns: -
1266 // Changes Globals: -
1267 //===========================================================================
AAS_FreeRoutingCaches(void)1268 void AAS_FreeRoutingCaches( void ) {
1269 // free all the existing cluster area cache
1270 AAS_FreeAllClusterAreaCache();
1271 // free all the existing portal cache
1272 AAS_FreeAllPortalCache();
1273 // free all the existing area visibility data
1274 AAS_FreeAreaVisibility();
1275 // free cached travel times within areas
1276 if ( ( *aasworld ).areatraveltimes ) {
1277 AAS_RoutingFreeMemory( ( *aasworld ).areatraveltimes );
1278 }
1279 ( *aasworld ).areatraveltimes = NULL;
1280 // free cached maximum travel time through cluster portals
1281 if ( ( *aasworld ).portalmaxtraveltimes ) {
1282 AAS_RoutingFreeMemory( ( *aasworld ).portalmaxtraveltimes );
1283 }
1284 ( *aasworld ).portalmaxtraveltimes = NULL;
1285 // free reversed reachability links
1286 if ( ( *aasworld ).reversedreachability ) {
1287 AAS_RoutingFreeMemory( ( *aasworld ).reversedreachability );
1288 }
1289 ( *aasworld ).reversedreachability = NULL;
1290 // free routing algorithm memory
1291 if ( ( *aasworld ).areaupdate ) {
1292 AAS_RoutingFreeMemory( ( *aasworld ).areaupdate );
1293 }
1294 ( *aasworld ).areaupdate = NULL;
1295 if ( ( *aasworld ).portalupdate ) {
1296 AAS_RoutingFreeMemory( ( *aasworld ).portalupdate );
1297 }
1298 ( *aasworld ).portalupdate = NULL;
1299 // free area waypoints
1300 if ( ( *aasworld ).areawaypoints ) {
1301 FreeMemory( ( *aasworld ).areawaypoints );
1302 }
1303 ( *aasworld ).areawaypoints = NULL;
1304 } //end of the function AAS_FreeRoutingCaches
1305 //===========================================================================
1306 //
1307 // Parameter: -
1308 // Returns: -
1309 // Changes Globals: -
1310 //===========================================================================
AAS_AreaContentsTravelFlag(int areanum)1311 int AAS_AreaContentsTravelFlag( int areanum ) {
1312 int contents, tfl;
1313
1314 contents = ( *aasworld ).areasettings[areanum].contents;
1315 tfl = 0;
1316 if ( contents & AREACONTENTS_WATER ) {
1317 return tfl |= TFL_WATER;
1318 } else if ( contents & AREACONTENTS_SLIME ) {
1319 return tfl |= TFL_SLIME;
1320 } else if ( contents & AREACONTENTS_LAVA ) {
1321 return tfl |= TFL_LAVA;
1322 } else { tfl |= TFL_AIR;}
1323 if ( contents & AREACONTENTS_DONOTENTER_LARGE ) {
1324 tfl |= TFL_DONOTENTER_LARGE;
1325 }
1326 if ( contents & AREACONTENTS_DONOTENTER ) {
1327 return tfl |= TFL_DONOTENTER;
1328 }
1329 return tfl;
1330 } //end of the function AAS_AreaContentsTravelFlag
1331 //===========================================================================
1332 // update the given routing cache
1333 //
1334 // Parameter: areacache : routing cache to update
1335 // Returns: -
1336 // Changes Globals: -
1337 //===========================================================================
AAS_UpdateAreaRoutingCache(aas_routingcache_t * areacache)1338 void AAS_UpdateAreaRoutingCache( aas_routingcache_t *areacache ) {
1339 int i, nextareanum, cluster, badtravelflags, clusterareanum, linknum;
1340 int numreachabilityareas;
1341 unsigned short int t, startareatraveltimes[128];
1342 aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
1343 aas_reachability_t *reach;
1344 aas_reversedreachability_t *revreach;
1345 aas_reversedlink_t *revlink;
1346
1347 #ifdef ROUTING_DEBUG
1348 numareacacheupdates++;
1349 #endif //ROUTING_DEBUG
1350 //number of reachability areas within this cluster
1351 numreachabilityareas = ( *aasworld ).clusters[areacache->cluster].numreachabilityareas;
1352 //
1353 //clear the routing update fields
1354 // memset((*aasworld).areaupdate, 0, (*aasworld).numareas * sizeof(aas_routingupdate_t));
1355 //
1356 badtravelflags = ~areacache->travelflags;
1357 //
1358 clusterareanum = AAS_ClusterAreaNum( areacache->cluster, areacache->areanum );
1359 if ( clusterareanum >= numreachabilityareas ) {
1360 return;
1361 }
1362 //
1363 memset( startareatraveltimes, 0, sizeof( startareatraveltimes ) );
1364 //
1365 curupdate = &( *aasworld ).areaupdate[clusterareanum];
1366 curupdate->areanum = areacache->areanum;
1367 //VectorCopy(areacache->origin, curupdate->start);
1368 curupdate->areatraveltimes = ( *aasworld ).areatraveltimes[areacache->areanum][0];
1369 curupdate->tmptraveltime = areacache->starttraveltime;
1370 //
1371 areacache->traveltimes[clusterareanum] = areacache->starttraveltime;
1372 //put the area to start with in the current read list
1373 curupdate->next = NULL;
1374 curupdate->prev = NULL;
1375 updateliststart = curupdate;
1376 updatelistend = curupdate;
1377 //while there are updates in the current list, flip the lists
1378 while ( updateliststart )
1379 {
1380 curupdate = updateliststart;
1381 //
1382 if ( curupdate->next ) {
1383 curupdate->next->prev = NULL;
1384 } else { updatelistend = NULL;}
1385 updateliststart = curupdate->next;
1386 //
1387 curupdate->inlist = qfalse;
1388 //check all reversed reachability links
1389 revreach = &( *aasworld ).reversedreachability[curupdate->areanum];
1390 //
1391 for ( i = 0, revlink = revreach->first; revlink; revlink = revlink->next, i++ )
1392 {
1393 linknum = revlink->linknum;
1394 reach = &( *aasworld ).reachability[linknum];
1395 //if there is used an undesired travel type
1396 if ( ( *aasworld ).travelflagfortype[reach->traveltype] & badtravelflags ) {
1397 continue;
1398 }
1399 //if not allowed to enter the next area
1400 if ( ( *aasworld ).areasettings[reach->areanum].areaflags & AREA_DISABLED ) {
1401 continue;
1402 }
1403 //if the next area has a not allowed travel flag
1404 if ( AAS_AreaContentsTravelFlag( reach->areanum ) & badtravelflags ) {
1405 continue;
1406 }
1407 //number of the area the reversed reachability leads to
1408 nextareanum = revlink->areanum;
1409 //get the cluster number of the area
1410 cluster = ( *aasworld ).areasettings[nextareanum].cluster;
1411 //don't leave the cluster
1412 if ( cluster > 0 && cluster != areacache->cluster ) {
1413 continue;
1414 }
1415 //get the number of the area in the cluster
1416 clusterareanum = AAS_ClusterAreaNum( areacache->cluster, nextareanum );
1417 if ( clusterareanum >= numreachabilityareas ) {
1418 continue;
1419 }
1420 //time already travelled plus the traveltime through
1421 //the current area plus the travel time from the reachability
1422 t = curupdate->tmptraveltime +
1423 //AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->end) +
1424 curupdate->areatraveltimes[i] +
1425 reach->traveltime;
1426 //
1427 ( *aasworld ).frameroutingupdates++;
1428 //
1429 if ( !areacache->traveltimes[clusterareanum] ||
1430 areacache->traveltimes[clusterareanum] > t ) {
1431 areacache->traveltimes[clusterareanum] = t;
1432 areacache->reachabilities[clusterareanum] = linknum - ( *aasworld ).areasettings[nextareanum].firstreachablearea;
1433 nextupdate = &( *aasworld ).areaupdate[clusterareanum];
1434 nextupdate->areanum = nextareanum;
1435 nextupdate->tmptraveltime = t;
1436 //VectorCopy(reach->start, nextupdate->start);
1437 nextupdate->areatraveltimes = ( *aasworld ).areatraveltimes[nextareanum][linknum -
1438 ( *aasworld ).areasettings[nextareanum].firstreachablearea];
1439 if ( !nextupdate->inlist ) {
1440 nextupdate->next = NULL;
1441 nextupdate->prev = updatelistend;
1442 if ( updatelistend ) {
1443 updatelistend->next = nextupdate;
1444 } else { updateliststart = nextupdate;}
1445 updatelistend = nextupdate;
1446 nextupdate->inlist = qtrue;
1447 } //end if
1448 } //end if
1449 } //end for
1450 } //end while
1451 } //end of the function AAS_UpdateAreaRoutingCache
1452 //===========================================================================
1453 //
1454 // Parameter: -
1455 // Returns: -
1456 // Changes Globals: -
1457 //===========================================================================
AAS_GetAreaRoutingCache(int clusternum,int areanum,int travelflags,qboolean forceUpdate)1458 aas_routingcache_t *AAS_GetAreaRoutingCache( int clusternum, int areanum, int travelflags, qboolean forceUpdate ) {
1459 int clusterareanum;
1460 aas_routingcache_t *cache, *clustercache;
1461
1462 //number of the area in the cluster
1463 clusterareanum = AAS_ClusterAreaNum( clusternum, areanum );
1464 //pointer to the cache for the area in the cluster
1465 clustercache = ( *aasworld ).clusterareacache[clusternum][clusterareanum];
1466 //find the cache without undesired travel flags
1467 for ( cache = clustercache; cache; cache = cache->next )
1468 {
1469 //if there aren't used any undesired travel types for the cache
1470 if ( cache->travelflags == travelflags ) {
1471 break;
1472 }
1473 } //end for
1474 //if there was no cache
1475 if ( !cache ) {
1476 //NOTE: the number of routing updates is limited per frame
1477 if ( !forceUpdate && ( ( *aasworld ).frameroutingupdates > MAX_FRAMEROUTINGUPDATES ) ) {
1478 return NULL;
1479 } //end if
1480
1481 cache = AAS_AllocRoutingCache( ( *aasworld ).clusters[clusternum].numreachabilityareas );
1482 cache->cluster = clusternum;
1483 cache->areanum = areanum;
1484 VectorCopy( ( *aasworld ).areas[areanum].center, cache->origin );
1485 cache->starttraveltime = 1;
1486 cache->travelflags = travelflags;
1487 cache->prev = NULL;
1488 cache->next = clustercache;
1489 if ( clustercache ) {
1490 clustercache->prev = cache;
1491 }
1492 ( *aasworld ).clusterareacache[clusternum][clusterareanum] = cache;
1493 AAS_UpdateAreaRoutingCache( cache );
1494 } //end if
1495 //the cache has been accessed
1496 cache->time = AAS_RoutingTime();
1497 return cache;
1498 } //end of the function AAS_GetAreaRoutingCache
1499 //===========================================================================
1500 //
1501 // Parameter: -
1502 // Returns: -
1503 // Changes Globals: -
1504 //===========================================================================
AAS_UpdatePortalRoutingCache(aas_routingcache_t * portalcache)1505 void AAS_UpdatePortalRoutingCache( aas_routingcache_t *portalcache ) {
1506 int i, portalnum, clusterareanum, clusternum;
1507 unsigned short int t;
1508 aas_portal_t *portal;
1509 aas_cluster_t *cluster;
1510 aas_routingcache_t *cache;
1511 aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
1512
1513 #ifdef ROUTING_DEBUG
1514 numportalcacheupdates++;
1515 #endif //ROUTING_DEBUG
1516 //clear the routing update fields
1517 // memset((*aasworld).portalupdate, 0, ((*aasworld).numportals+1) * sizeof(aas_routingupdate_t));
1518 //
1519 curupdate = &( *aasworld ).portalupdate[( *aasworld ).numportals];
1520 curupdate->cluster = portalcache->cluster;
1521 curupdate->areanum = portalcache->areanum;
1522 curupdate->tmptraveltime = portalcache->starttraveltime;
1523 //if the start area is a cluster portal, store the travel time for that portal
1524 clusternum = ( *aasworld ).areasettings[portalcache->areanum].cluster;
1525 if ( clusternum < 0 ) {
1526 portalcache->traveltimes[-clusternum] = portalcache->starttraveltime;
1527 } //end if
1528 //put the area to start with in the current read list
1529 curupdate->next = NULL;
1530 curupdate->prev = NULL;
1531 updateliststart = curupdate;
1532 updatelistend = curupdate;
1533 //while there are updates in the current list, flip the lists
1534 while ( updateliststart )
1535 {
1536 curupdate = updateliststart;
1537 //remove the current update from the list
1538 if ( curupdate->next ) {
1539 curupdate->next->prev = NULL;
1540 } else { updatelistend = NULL;}
1541 updateliststart = curupdate->next;
1542 //current update is removed from the list
1543 curupdate->inlist = qfalse;
1544 //
1545 cluster = &( *aasworld ).clusters[curupdate->cluster];
1546 //
1547 cache = AAS_GetAreaRoutingCache( curupdate->cluster,
1548 curupdate->areanum, portalcache->travelflags, qtrue );
1549 //take all portals of the cluster
1550 for ( i = 0; i < cluster->numportals; i++ )
1551 {
1552 portalnum = ( *aasworld ).portalindex[cluster->firstportal + i];
1553 portal = &( *aasworld ).portals[portalnum];
1554 //if this is the portal of the current update continue
1555 if ( portal->areanum == curupdate->areanum ) {
1556 continue;
1557 }
1558 //
1559 clusterareanum = AAS_ClusterAreaNum( curupdate->cluster, portal->areanum );
1560 if ( clusterareanum >= cluster->numreachabilityareas ) {
1561 continue;
1562 }
1563 //
1564 t = cache->traveltimes[clusterareanum];
1565 if ( !t ) {
1566 continue;
1567 }
1568 t += curupdate->tmptraveltime;
1569 //
1570 if ( !portalcache->traveltimes[portalnum] ||
1571 portalcache->traveltimes[portalnum] > t ) {
1572 portalcache->traveltimes[portalnum] = t;
1573 portalcache->reachabilities[portalnum] = cache->reachabilities[clusterareanum];
1574 nextupdate = &( *aasworld ).portalupdate[portalnum];
1575 if ( portal->frontcluster == curupdate->cluster ) {
1576 nextupdate->cluster = portal->backcluster;
1577 } //end if
1578 else
1579 {
1580 nextupdate->cluster = portal->frontcluster;
1581 } //end else
1582 nextupdate->areanum = portal->areanum;
1583 //add travel time through actual portal area for the next update
1584 nextupdate->tmptraveltime = t + ( *aasworld ).portalmaxtraveltimes[portalnum];
1585 if ( !nextupdate->inlist ) {
1586 nextupdate->next = NULL;
1587 nextupdate->prev = updatelistend;
1588 if ( updatelistend ) {
1589 updatelistend->next = nextupdate;
1590 } else { updateliststart = nextupdate;}
1591 updatelistend = nextupdate;
1592 nextupdate->inlist = qtrue;
1593 } //end if
1594 } //end if
1595 } //end for
1596 } //end while
1597 } //end of the function AAS_UpdatePortalRoutingCache
1598 //===========================================================================
1599 //
1600 // Parameter: -
1601 // Returns: -
1602 // Changes Globals: -
1603 //===========================================================================
AAS_GetPortalRoutingCache(int clusternum,int areanum,int travelflags)1604 aas_routingcache_t *AAS_GetPortalRoutingCache( int clusternum, int areanum, int travelflags ) {
1605 aas_routingcache_t *cache;
1606
1607 //find the cached portal routing if existing
1608 for ( cache = ( *aasworld ).portalcache[areanum]; cache; cache = cache->next )
1609 {
1610 if ( cache->travelflags == travelflags ) {
1611 break;
1612 }
1613 } //end for
1614 //if the portal routing isn't cached
1615 if ( !cache ) {
1616 cache = AAS_AllocRoutingCache( ( *aasworld ).numportals );
1617 cache->cluster = clusternum;
1618 cache->areanum = areanum;
1619 VectorCopy( ( *aasworld ).areas[areanum].center, cache->origin );
1620 cache->starttraveltime = 1;
1621 cache->travelflags = travelflags;
1622 //add the cache to the cache list
1623 cache->prev = NULL;
1624 cache->next = ( *aasworld ).portalcache[areanum];
1625 if ( ( *aasworld ).portalcache[areanum] ) {
1626 ( *aasworld ).portalcache[areanum]->prev = cache;
1627 }
1628 ( *aasworld ).portalcache[areanum] = cache;
1629 //update the cache
1630 AAS_UpdatePortalRoutingCache( cache );
1631 } //end if
1632 //the cache has been accessed
1633 cache->time = AAS_RoutingTime();
1634 return cache;
1635 } //end of the function AAS_GetPortalRoutingCache
1636 //===========================================================================
1637 //
1638 // Parameter: -
1639 // Returns: -
1640 // Changes Globals: -
1641 //===========================================================================
AAS_AreaRouteToGoalArea(int areanum,vec3_t origin,int goalareanum,int travelflags,int * traveltime,int * reachnum)1642 int AAS_AreaRouteToGoalArea( int areanum, vec3_t origin, int goalareanum, int travelflags, int *traveltime, int *reachnum ) {
1643 int clusternum, goalclusternum, portalnum, i, clusterareanum, bestreachnum;
1644 unsigned short int t, besttime;
1645 aas_portal_t *portal;
1646 aas_cluster_t *cluster;
1647 aas_routingcache_t *areacache, *portalcache;
1648 aas_reachability_t *reach;
1649 aas_portalindex_t *pPortalnum;
1650
1651 if ( !( *aasworld ).initialized ) {
1652 return qfalse;
1653 }
1654
1655 if ( areanum == goalareanum ) {
1656 *traveltime = 1;
1657 *reachnum = 0;
1658 return qtrue;
1659 } //end if
1660 //check !AAS_AreaReachability(areanum) with custom developer-only debug message
1661 if ( areanum <= 0 || areanum >= ( *aasworld ).numareas ) {
1662 if ( botDeveloper ) {
1663 botimport.Print( PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: areanum %d out of range\n", areanum );
1664 } //end if
1665 return qfalse;
1666 } //end if
1667 if ( goalareanum <= 0 || goalareanum >= ( *aasworld ).numareas ) {
1668 if ( botDeveloper ) {
1669 botimport.Print( PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: goalareanum %d out of range\n", goalareanum );
1670 } //end if
1671 return qfalse;
1672 } //end if
1673 if ( !( *aasworld ).areasettings[areanum].numreachableareas || !( *aasworld ).areasettings[goalareanum].numreachableareas )
1674 {
1675 return qfalse;
1676 } //end if
1677 //make sure the routing cache doesn't grow to large
1678 while ( routingcachesize > max_routingcachesize ) {
1679 if ( !AAS_FreeOldestCache() ) {
1680 break;
1681 }
1682 }
1683 //
1684 if ( AAS_AreaDoNotEnter( areanum ) || AAS_AreaDoNotEnter( goalareanum ) ) {
1685 travelflags |= TFL_DONOTENTER;
1686 } //end if
1687 if ( AAS_AreaDoNotEnterLarge( areanum ) || AAS_AreaDoNotEnterLarge( goalareanum ) ) {
1688 travelflags |= TFL_DONOTENTER_LARGE;
1689 } //end if
1690 //NOTE: the number of routing updates is limited per frame
1691 /*
1692 if ((*aasworld).frameroutingupdates > MAX_FRAMEROUTINGUPDATES)
1693 {
1694 #ifdef DEBUG
1695 //Log_Write("WARNING: AAS_AreaTravelTimeToGoalArea: frame routing updates overflowed");
1696 #endif
1697 return 0;
1698 } //end if
1699 */
1700 //
1701 clusternum = ( *aasworld ).areasettings[areanum].cluster;
1702 goalclusternum = ( *aasworld ).areasettings[goalareanum].cluster;
1703 //check if the area is a portal of the goal area cluster
1704 if ( clusternum < 0 && goalclusternum > 0 ) {
1705 portal = &( *aasworld ).portals[-clusternum];
1706 if ( portal->frontcluster == goalclusternum ||
1707 portal->backcluster == goalclusternum ) {
1708 clusternum = goalclusternum;
1709 } //end if
1710 } //end if
1711 //check if the goalarea is a portal of the area cluster
1712 else if ( clusternum > 0 && goalclusternum < 0 ) {
1713 portal = &( *aasworld ).portals[-goalclusternum];
1714 if ( portal->frontcluster == clusternum ||
1715 portal->backcluster == clusternum ) {
1716 goalclusternum = clusternum;
1717 } //end if
1718 } //end if
1719 //if both areas are in the same cluster
1720 //NOTE: there might be a shorter route via another cluster!!! but we don't care
1721 if ( clusternum > 0 && goalclusternum > 0 && clusternum == goalclusternum ) {
1722 //
1723 areacache = AAS_GetAreaRoutingCache( clusternum, goalareanum, travelflags, qfalse );
1724 // RF, note that the routing cache might be NULL now since we are restricting
1725 // the updates per frame, hopefully rejected cache's will be requested again
1726 // when things have settled down
1727 if ( !areacache ) {
1728 return qfalse;
1729 }
1730 //the number of the area in the cluster
1731 clusterareanum = AAS_ClusterAreaNum( clusternum, areanum );
1732 //the cluster the area is in
1733 cluster = &( *aasworld ).clusters[clusternum];
1734 //if the area is NOT a reachability area
1735 if ( clusterareanum >= cluster->numreachabilityareas ) {
1736 return qfalse;
1737 }
1738 //if it is possible to travel to the goal area through this cluster
1739 if ( areacache->traveltimes[clusterareanum] != 0 ) {
1740 *reachnum = ( *aasworld ).areasettings[areanum].firstreachablearea +
1741 areacache->reachabilities[clusterareanum];
1742 //
1743 if ( !origin ) {
1744 *traveltime = areacache->traveltimes[clusterareanum];
1745 return qtrue;
1746 }
1747 //
1748 reach = &( *aasworld ).reachability[*reachnum];
1749 *traveltime = areacache->traveltimes[clusterareanum] +
1750 AAS_AreaTravelTime( areanum, origin, reach->start );
1751 return qtrue;
1752 } //end if
1753 } //end if
1754 //
1755 clusternum = ( *aasworld ).areasettings[areanum].cluster;
1756 goalclusternum = ( *aasworld ).areasettings[goalareanum].cluster;
1757 //if the goal area is a portal
1758 if ( goalclusternum < 0 ) {
1759 //just assume the goal area is part of the front cluster
1760 portal = &( *aasworld ).portals[-goalclusternum];
1761 goalclusternum = portal->frontcluster;
1762 } //end if
1763 //get the portal routing cache
1764 portalcache = AAS_GetPortalRoutingCache( goalclusternum, goalareanum, travelflags );
1765 //if the area is a cluster portal, read directly from the portal cache
1766 if ( clusternum < 0 ) {
1767 *traveltime = portalcache->traveltimes[-clusternum];
1768 *reachnum = ( *aasworld ).areasettings[areanum].firstreachablearea +
1769 portalcache->reachabilities[-clusternum];
1770 return qtrue;
1771 }
1772 //
1773 besttime = 0;
1774 bestreachnum = -1;
1775 //the cluster the area is in
1776 cluster = &( *aasworld ).clusters[clusternum];
1777 //current area inside the current cluster
1778 clusterareanum = AAS_ClusterAreaNum( clusternum, areanum );
1779 //if the area is NOT a reachability area
1780 if ( clusterareanum >= cluster->numreachabilityareas ) {
1781 return qfalse;
1782 }
1783 //
1784 pPortalnum = ( *aasworld ).portalindex + cluster->firstportal;
1785 //find the portal of the area cluster leading towards the goal area
1786 for ( i = 0; i < cluster->numportals; i++, pPortalnum++ )
1787 {
1788 portalnum = *pPortalnum;
1789 //if the goal area isn't reachable from the portal
1790 if ( !portalcache->traveltimes[portalnum] ) {
1791 continue;
1792 }
1793 //
1794 portal = ( *aasworld ).portals + portalnum;
1795 // if the area in disabled
1796 if ( ( *aasworld ).areasettings[portal->areanum].areaflags & AREA_DISABLED ) {
1797 continue;
1798 }
1799 //get the cache of the portal area
1800 areacache = AAS_GetAreaRoutingCache( clusternum, portal->areanum, travelflags, qfalse );
1801 // RF, this may be NULL if we were unable to calculate the cache this frame
1802 if ( !areacache ) {
1803 return qfalse;
1804 }
1805 //if the portal is NOT reachable from this area
1806 if ( !areacache->traveltimes[clusterareanum] ) {
1807 continue;
1808 }
1809 //total travel time is the travel time the portal area is from
1810 //the goal area plus the travel time towards the portal area
1811 t = portalcache->traveltimes[portalnum] + areacache->traveltimes[clusterareanum];
1812 //FIXME: add the exact travel time through the actual portal area
1813 //NOTE: for now we just add the largest travel time through the area portal
1814 // because we can't directly calculate the exact travel time
1815 // to be more specific we don't know which reachability is used to travel
1816 // into the portal area when coming from the current area
1817 t += ( *aasworld ).portalmaxtraveltimes[portalnum];
1818 //
1819 // Ridah, needs to be up here
1820 *reachnum = ( *aasworld ).areasettings[areanum].firstreachablearea +
1821 areacache->reachabilities[clusterareanum];
1822
1823 //botimport.Print(PRT_MESSAGE, "portal reachability: %i\n", (int)areacache->reachabilities[clusterareanum] );
1824
1825 if ( origin ) {
1826 reach = ( *aasworld ).reachability + *reachnum;
1827 t += AAS_AreaTravelTime( areanum, origin, reach->start );
1828 } //end if
1829 //if the time is better than the one already found
1830 if ( !besttime || t < besttime ) {
1831 bestreachnum = *reachnum;
1832 besttime = t;
1833 } //end if
1834 } //end for
1835 // Ridah, check a route was found
1836 if ( bestreachnum < 0 ) {
1837 return qfalse;
1838 }
1839 *reachnum = bestreachnum;
1840 *traveltime = besttime;
1841 return qtrue;
1842 } //end of the function AAS_AreaRouteToGoalArea
1843 //===========================================================================
1844 //
1845 // Parameter: -
1846 // Returns: -
1847 // Changes Globals: -
1848 //===========================================================================
AAS_AreaTravelTimeToGoalArea(int areanum,vec3_t origin,int goalareanum,int travelflags)1849 int AAS_AreaTravelTimeToGoalArea( int areanum, vec3_t origin, int goalareanum, int travelflags ) {
1850 int traveltime, reachnum = 0;
1851
1852 if ( AAS_AreaRouteToGoalArea( areanum, origin, goalareanum, travelflags, &traveltime, &reachnum ) ) {
1853 return traveltime;
1854 }
1855 return 0;
1856 } //end of the function AAS_AreaTravelTimeToGoalArea
1857 //===========================================================================
1858 //
1859 // Parameter: -
1860 // Returns: -
1861 // Changes Globals: -
1862 //===========================================================================
AAS_AreaReachabilityToGoalArea(int areanum,vec3_t origin,int goalareanum,int travelflags)1863 int AAS_AreaReachabilityToGoalArea( int areanum, vec3_t origin, int goalareanum, int travelflags ) {
1864 int traveltime, reachnum = 0;
1865
1866 if ( AAS_AreaRouteToGoalArea( areanum, origin, goalareanum, travelflags, &traveltime, &reachnum ) ) {
1867 return reachnum;
1868 }
1869 return 0;
1870 } //end of the function AAS_AreaReachabilityToGoalArea
1871 //===========================================================================
1872 //
1873 // Parameter: -
1874 // Returns: -
1875 // Changes Globals: -
1876 //===========================================================================
AAS_ReachabilityFromNum(int num,struct aas_reachability_s * reach)1877 void AAS_ReachabilityFromNum( int num, struct aas_reachability_s *reach ) {
1878 if ( !( *aasworld ).initialized ) {
1879 memset( reach, 0, sizeof( aas_reachability_t ) );
1880 return;
1881 } //end if
1882 if ( num < 0 || num >= ( *aasworld ).reachabilitysize ) {
1883 memset( reach, 0, sizeof( aas_reachability_t ) );
1884 return;
1885 } //end if
1886 memcpy( reach, &( *aasworld ).reachability[num], sizeof( aas_reachability_t ) );;
1887 } //end of the function AAS_ReachabilityFromNum
1888 //===========================================================================
1889 //
1890 // Parameter: -
1891 // Returns: -
1892 // Changes Globals: -
1893 //===========================================================================
AAS_NextAreaReachability(int areanum,int reachnum)1894 int AAS_NextAreaReachability( int areanum, int reachnum ) {
1895 aas_areasettings_t *settings;
1896
1897 if ( !( *aasworld ).initialized ) {
1898 return 0;
1899 }
1900
1901 if ( areanum <= 0 || areanum >= ( *aasworld ).numareas ) {
1902 botimport.Print( PRT_ERROR, "AAS_NextAreaReachability: areanum %d out of range\n", areanum );
1903 return 0;
1904 } //end if
1905
1906 settings = &( *aasworld ).areasettings[areanum];
1907 if ( !reachnum ) {
1908 return settings->firstreachablearea;
1909 } //end if
1910 if ( reachnum < settings->firstreachablearea ) {
1911 botimport.Print( PRT_FATAL, "AAS_NextAreaReachability: reachnum < settings->firstreachableara" );
1912 return 0;
1913 } //end if
1914 reachnum++;
1915 if ( reachnum >= settings->firstreachablearea + settings->numreachableareas ) {
1916 return 0;
1917 } //end if
1918 return reachnum;
1919 } //end of the function AAS_NextAreaReachability
1920 //===========================================================================
1921 //
1922 // Parameter: -
1923 // Returns: -
1924 // Changes Globals: -
1925 //===========================================================================
AAS_NextModelReachability(int num,int modelnum)1926 int AAS_NextModelReachability( int num, int modelnum ) {
1927 int i;
1928
1929 if ( num <= 0 ) {
1930 num = 1;
1931 } else if ( num >= ( *aasworld ).reachabilitysize ) {
1932 return 0;
1933 } else { num++;}
1934 //
1935 for ( i = num; i < ( *aasworld ).reachabilitysize; i++ )
1936 {
1937 if ( ( *aasworld ).reachability[i].traveltype == TRAVEL_ELEVATOR ) {
1938 if ( ( *aasworld ).reachability[i].facenum == modelnum ) {
1939 return i;
1940 }
1941 } //end if
1942 else if ( ( *aasworld ).reachability[i].traveltype == TRAVEL_FUNCBOB ) {
1943 if ( ( ( *aasworld ).reachability[i].facenum & 0x0000FFFF ) == modelnum ) {
1944 return i;
1945 }
1946 } //end if
1947 } //end for
1948 return 0;
1949 } //end of the function AAS_NextModelReachability
1950 //===========================================================================
1951 //
1952 // Parameter: -
1953 // Returns: -
1954 // Changes Globals: -
1955 //===========================================================================
AAS_RandomGoalArea(int areanum,int travelflags,int * goalareanum,vec3_t goalorigin)1956 int AAS_RandomGoalArea( int areanum, int travelflags, int *goalareanum, vec3_t goalorigin ) {
1957 int i, n, t;
1958 vec3_t start, end;
1959 aas_trace_t trace;
1960
1961 //if the area has no reachabilities
1962 if ( !AAS_AreaReachability( areanum ) ) {
1963 return qfalse;
1964 }
1965 //
1966 n = ( *aasworld ).numareas * random();
1967 for ( i = 0; i < ( *aasworld ).numareas; i++ )
1968 {
1969 if ( n <= 0 ) {
1970 n = 1;
1971 }
1972 if ( n >= ( *aasworld ).numareas ) {
1973 n = 1;
1974 }
1975 if ( AAS_AreaReachability( n ) ) {
1976 t = AAS_AreaTravelTimeToGoalArea( areanum, ( *aasworld ).areas[areanum].center, n, travelflags );
1977 //if the goal is reachable
1978 if ( t > 0 ) {
1979 if ( AAS_AreaSwim( n ) ) {
1980 *goalareanum = n;
1981 VectorCopy( ( *aasworld ).areas[n].center, goalorigin );
1982 //botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum);
1983 return qtrue;
1984 } //end if
1985 VectorCopy( ( *aasworld ).areas[n].center, start );
1986 if ( !AAS_PointAreaNum( start ) ) {
1987 Log_Write( "area %d center %f %f %f in solid?", n,
1988 start[0], start[1], start[2] );
1989 }
1990 VectorCopy( start, end );
1991 end[2] -= 300;
1992 trace = AAS_TraceClientBBox( start, end, PRESENCE_CROUCH, -1 );
1993 if ( !trace.startsolid && AAS_PointAreaNum( trace.endpos ) == n ) {
1994 if ( AAS_AreaGroundFaceArea( n ) > 300 ) {
1995 *goalareanum = n;
1996 VectorCopy( trace.endpos, goalorigin );
1997 //botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum);
1998 return qtrue;
1999 } //end if
2000 } //end if
2001 } //end if
2002 } //end if
2003 n++;
2004 } //end for
2005 return qfalse;
2006 } //end of the function AAS_RandomGoalArea
2007 //===========================================================================
2008 // run-length compression on zeros
2009 //
2010 // Parameter: -
2011 // Returns: -
2012 // Changes Globals: -
2013 //===========================================================================
AAS_CompressVis(byte * vis,int numareas,byte * dest)2014 int AAS_CompressVis( byte *vis, int numareas, byte *dest ) {
2015 int j;
2016 int rep;
2017 //int visrow;
2018 byte *dest_p;
2019 byte check;
2020
2021 //
2022 dest_p = dest;
2023 //visrow = (numareas + 7)>>3;
2024
2025 for ( j = 0 ; j < numareas /*visrow*/ ; j++ )
2026 {
2027 *dest_p++ = vis[j];
2028 check = vis[j];
2029 //if (vis[j])
2030 // continue;
2031
2032 rep = 1;
2033 for ( j++; j < numareas /*visrow*/ ; j++ )
2034 if ( vis[j] != check || rep == 255 ) {
2035 break;
2036 } else {
2037 rep++;
2038 }
2039 *dest_p++ = rep;
2040 j--;
2041 }
2042 return dest_p - dest;
2043 } //end of the function AAS_CompressVis
2044 //===========================================================================
2045 //
2046 // Parameter: -
2047 // Returns: -
2048 // Changes Globals: -
2049 //===========================================================================
AAS_DecompressVis(byte * in,int numareas,byte * decompressed)2050 void AAS_DecompressVis( byte *in, int numareas, byte *decompressed ) {
2051 byte c;
2052 byte *out;
2053 byte *end;
2054
2055 // initialize the vis data, only set those that are visible
2056 memset( decompressed, 0, numareas );
2057
2058 out = decompressed;
2059 end = ( byte * )( decompressed + numareas );
2060
2061 do
2062 {
2063 c = in[1];
2064 if ( !c ) {
2065 AAS_Error( "DecompressVis: 0 repeat" );
2066 }
2067 if ( *in ) { // we need to set these bits
2068 memset( out, 1, c );
2069 }
2070 in += 2;
2071 out += c;
2072 } while ( out < end );
2073 } //end of the function AAS_DecompressVis
2074 //===========================================================================
2075 //
2076 // Parameter: -
2077 // Returns: -
2078 // Changes Globals: -
2079 //===========================================================================
AAS_AreaVisible(int srcarea,int destarea)2080 int AAS_AreaVisible( int srcarea, int destarea ) {
2081 if ( srcarea != ( *aasworld ).decompressedvisarea ) {
2082 if ( !( *aasworld ).areavisibility[srcarea] ) {
2083 return qfalse;
2084 }
2085 AAS_DecompressVis( ( *aasworld ).areavisibility[srcarea],
2086 ( *aasworld ).numareas, ( *aasworld ).decompressedvis );
2087 ( *aasworld ).decompressedvisarea = srcarea;
2088 }
2089 return ( *aasworld ).decompressedvis[destarea];
2090 } //end of the function AAS_AreaVisible
2091 //===========================================================================
2092 // just center to center visibility checking...
2093 // FIXME: implement a correct full vis
2094 //
2095 // Parameter: -
2096 // Returns: -
2097 // Changes Globals: -
2098 //===========================================================================
AAS_CreateVisibility(void)2099 void AAS_CreateVisibility( void ) {
2100 int i, j, size, totalsize;
2101 vec3_t endpos, mins, maxs;
2102 bsp_trace_t trace;
2103 byte *buf;
2104 byte *validareas;
2105 int numvalid = 0;
2106
2107 buf = (byte *) GetClearedMemory( ( *aasworld ).numareas * 2 * sizeof( byte ) ); // in case it ends up bigger than the decompressedvis, which is rare but possible
2108 validareas = (byte *) GetClearedMemory( ( *aasworld ).numareas * sizeof( byte ) );
2109
2110 ( *aasworld ).areavisibility = (byte **) GetClearedMemory( ( *aasworld ).numareas * sizeof( byte * ) );
2111 ( *aasworld ).decompressedvis = (byte *) GetClearedMemory( ( *aasworld ).numareas * sizeof( byte ) );
2112 ( *aasworld ).areawaypoints = (vec3_t *) GetClearedMemory( ( *aasworld ).numareas * sizeof( vec3_t ) );
2113 totalsize = ( *aasworld ).numareas * sizeof( byte * );
2114 for ( i = 1; i < ( *aasworld ).numareas; i++ )
2115 {
2116 if ( !AAS_AreaReachability( i ) ) {
2117 continue;
2118 }
2119
2120 // find the waypoint
2121 VectorCopy( ( *aasworld ).areas[i].center, endpos );
2122 endpos[2] -= 256;
2123 AAS_PresenceTypeBoundingBox( PRESENCE_NORMAL, mins, maxs );
2124 // maxs[2] = 0;
2125 trace = AAS_Trace( ( *aasworld ).areas[i].center, mins, maxs, endpos, -1, CONTENTS_SOLID );
2126 if ( !trace.startsolid && trace.fraction < 1 && AAS_PointAreaNum( trace.endpos ) == i ) {
2127 VectorCopy( trace.endpos, ( *aasworld ).areawaypoints[i] );
2128 validareas[i] = 1;
2129 numvalid++;
2130 } else {
2131 continue;
2132 }
2133 }
2134
2135 for ( i = 1; i < ( *aasworld ).numareas; i++ )
2136 {
2137 if ( !validareas[i] ) {
2138 continue;
2139 }
2140
2141 if ( !AAS_AreaReachability( i ) ) {
2142 continue;
2143 }
2144
2145 for ( j = 1; j < ( *aasworld ).numareas; j++ )
2146 {
2147 if ( i == j ) {
2148 ( *aasworld ).decompressedvis[j] = 1;
2149 continue;
2150 }
2151 if ( !validareas[j] || !AAS_AreaReachability( j ) ) {
2152 ( *aasworld ).decompressedvis[j] = 0;
2153 continue;
2154 } //end if
2155
2156 // Ridah, this always returns false?!
2157 //if (AAS_inPVS( (*aasworld).areawaypoints[i], (*aasworld).areawaypoints[j] ))
2158 trace = AAS_Trace( ( *aasworld ).areawaypoints[i], NULL, NULL, ( *aasworld ).areawaypoints[j], -1, CONTENTS_SOLID );
2159 if ( trace.fraction >= 1 ) {
2160 //if (botimport.inPVS( (*aasworld).areawaypoints[i], (*aasworld).areawaypoints[j] ))
2161 ( *aasworld ).decompressedvis[j] = 1;
2162 } //end if
2163 else
2164 {
2165 ( *aasworld ).decompressedvis[j] = 0;
2166 } //end else
2167 } //end for
2168 size = AAS_CompressVis( ( *aasworld ).decompressedvis, ( *aasworld ).numareas, buf );
2169 ( *aasworld ).areavisibility[i] = (byte *) GetMemory( size );
2170 memcpy( ( *aasworld ).areavisibility[i], buf, size );
2171 totalsize += size;
2172 } //end for
2173 botimport.Print( PRT_MESSAGE, "AAS_CreateVisibility: compressed vis size = %i\n", totalsize );
2174 } //end of the function AAS_CreateVisibility
2175 //===========================================================================
2176 //
2177 // Parameter: -
2178 // Returns: -
2179 // Changes Globals: -
2180 //===========================================================================
2181 float VectorDistance( vec3_t v1, vec3_t v2 );
2182 extern void ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj ) ;
AAS_NearestHideArea(int srcnum,vec3_t origin,int areanum,int enemynum,vec3_t enemyorigin,int enemyareanum,int travelflags)2183 int AAS_NearestHideArea( int srcnum, vec3_t origin, int areanum, int enemynum, vec3_t enemyorigin, int enemyareanum, int travelflags ) {
2184 int i, j, nextareanum, badtravelflags, numreach, bestarea;
2185 unsigned short int t, besttraveltime;
2186 aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
2187 aas_reachability_t *reach;
2188 float dist1, dist2;
2189 float enemytraveldist;
2190 vec3_t enemyVec;
2191 qboolean startVisible;
2192 vec3_t v1, v2, p;
2193 #define MAX_HIDEAREA_LOOPS 4000
2194 static float lastTime;
2195 int count = 0;
2196 //
2197 // don't run this more than once per frame
2198 if ( lastTime == AAS_Time() ) {
2199 return 0;
2200 }
2201 lastTime = AAS_Time();
2202 //
2203 if ( !( *aasworld ).hidetraveltimes ) {
2204 ( *aasworld ).hidetraveltimes = (unsigned short int *) GetClearedMemory( ( *aasworld ).numareas * sizeof( unsigned short int ) );
2205 } else {
2206 memset( ( *aasworld ).hidetraveltimes, 0, ( *aasworld ).numareas * sizeof( unsigned short int ) );
2207 } //end else
2208 //
2209 if ( !( *aasworld ).visCache ) {
2210 ( *aasworld ).visCache = (byte *) GetClearedMemory( ( *aasworld ).numareas * sizeof( byte ) );
2211 } else {
2212 memset( ( *aasworld ).visCache, 0, ( *aasworld ).numareas * sizeof( byte ) );
2213 } //end else
2214 besttraveltime = 0;
2215 bestarea = 0;
2216 if ( enemyareanum ) {
2217 AAS_AreaTravelTimeToGoalArea( areanum, origin, enemyareanum, travelflags );
2218 }
2219 VectorSubtract( enemyorigin, origin, enemyVec );
2220 enemytraveldist = VectorNormalize( enemyVec );
2221 startVisible = botimport.AICast_VisibleFromPos( enemyorigin, enemynum, origin, srcnum, qfalse );
2222 //
2223 badtravelflags = ~travelflags;
2224 //
2225 curupdate = &( *aasworld ).areaupdate[areanum];
2226 curupdate->areanum = areanum;
2227 VectorCopy( origin, curupdate->start );
2228 curupdate->areatraveltimes = ( *aasworld ).areatraveltimes[areanum][0];
2229 curupdate->tmptraveltime = 0;
2230 //put the area to start with in the current read list
2231 curupdate->next = NULL;
2232 curupdate->prev = NULL;
2233 updateliststart = curupdate;
2234 updatelistend = curupdate;
2235 //while there are updates in the current list, flip the lists
2236 while ( updateliststart )
2237 {
2238 curupdate = updateliststart;
2239 //
2240 if ( curupdate->next ) {
2241 curupdate->next->prev = NULL;
2242 } else { updatelistend = NULL;}
2243 updateliststart = curupdate->next;
2244 //
2245 curupdate->inlist = qfalse;
2246 //check all reversed reachability links
2247 numreach = ( *aasworld ).areasettings[curupdate->areanum].numreachableareas;
2248 reach = &( *aasworld ).reachability[( *aasworld ).areasettings[curupdate->areanum].firstreachablearea];
2249 //
2250 for ( i = 0; i < numreach; i++, reach++ )
2251 {
2252 //if an undesired travel type is used
2253 if ( ( *aasworld ).travelflagfortype[reach->traveltype] & badtravelflags ) {
2254 continue;
2255 }
2256 //
2257 if ( AAS_AreaContentsTravelFlag( reach->areanum ) & badtravelflags ) {
2258 continue;
2259 }
2260 //
2261 if ( ( *aasworld ).areasettings[reach->areanum].areaflags & AREA_DISABLED ) {
2262 continue;
2263 }
2264 //number of the area the reachability leads to
2265 nextareanum = reach->areanum;
2266 // if this moves us into the enemies area, skip it
2267 if ( nextareanum == enemyareanum ) {
2268 continue;
2269 }
2270 //time already travelled plus the traveltime through
2271 //the current area plus the travel time from the reachability
2272 t = curupdate->tmptraveltime +
2273 AAS_AreaTravelTime( curupdate->areanum, curupdate->start, reach->start ) +
2274 reach->traveltime;
2275 // if this isn't the fastest route to this area, ignore
2276 if ( ( *aasworld ).hidetraveltimes[nextareanum] && ( *aasworld ).hidetraveltimes[nextareanum] < t ) {
2277 continue;
2278 }
2279 ( *aasworld ).hidetraveltimes[nextareanum] = t;
2280 // if the bestarea is this area, then it must be a longer route, so ignore it
2281 if ( bestarea == nextareanum ) {
2282 bestarea = 0;
2283 besttraveltime = 0;
2284 }
2285 // do this test now, so we can reject the route if it starts out too long
2286 if ( besttraveltime && t >= besttraveltime ) {
2287 continue;
2288 }
2289 //
2290 //avoid going near the enemy
2291 ProjectPointOntoVector( enemyorigin, curupdate->start, reach->end, p );
2292 for ( j = 0; j < 3; j++ ) {
2293 if ( ( p[j] > curupdate->start[j] + 0.1 && p[j] > reach->end[j] + 0.1 ) ||
2294 ( p[j] < curupdate->start[j] - 0.1 && p[j] < reach->end[j] - 0.1 ) ) {
2295 break;
2296 }
2297 }
2298 if ( j < 3 ) {
2299 VectorSubtract( enemyorigin, reach->end, v2 );
2300 } //end if
2301 else
2302 {
2303 VectorSubtract( enemyorigin, p, v2 );
2304 } //end else
2305 dist2 = VectorLength( v2 );
2306 //never go through the enemy
2307 if ( enemytraveldist > 32 && dist2 < enemytraveldist && dist2 < 256 ) {
2308 continue;
2309 }
2310 //
2311 VectorSubtract( reach->end, origin, v2 );
2312 if ( enemytraveldist > 32 && DotProduct( v2, enemyVec ) > enemytraveldist / 2 ) {
2313 continue;
2314 }
2315 //
2316 VectorSubtract( enemyorigin, curupdate->start, v1 );
2317 dist1 = VectorLength( v1 );
2318 //
2319 if ( enemytraveldist > 32 && dist2 < dist1 ) {
2320 t += ( dist1 - dist2 ) * 10;
2321 // test it again after modifying it
2322 if ( besttraveltime && t >= besttraveltime ) {
2323 continue;
2324 }
2325 }
2326 // make sure the hide area doesn't have anyone else in it
2327 if ( AAS_IsEntityInArea( srcnum, -1, nextareanum ) ) {
2328 t += 1000; // avoid this path/area
2329 //continue;
2330 }
2331 //
2332 // if we weren't visible when starting, make sure we don't move into their view
2333 if ( enemyareanum && !startVisible && AAS_AreaVisible( enemyareanum, nextareanum ) ) {
2334 continue;
2335 //t += 1000;
2336 }
2337 //
2338 if ( !besttraveltime || besttraveltime > t ) {
2339 //
2340 // if this area doesn't have a vis list, ignore it
2341 if ( ( *aasworld ).areavisibility[nextareanum] ) {
2342 //if the nextarea is not visible from the enemy area
2343 if ( !AAS_AreaVisible( enemyareanum, nextareanum ) ) { // now last of all, check that this area is a safe hiding spot
2344 if ( ( ( *aasworld ).visCache[nextareanum] == 2 ) ||
2345 ( !( *aasworld ).visCache[nextareanum] && !botimport.AICast_VisibleFromPos( enemyorigin, enemynum, ( *aasworld ).areawaypoints[nextareanum], srcnum, qfalse ) ) ) {
2346 ( *aasworld ).visCache[nextareanum] = 2;
2347 besttraveltime = t;
2348 bestarea = nextareanum;
2349 } else {
2350 ( *aasworld ).visCache[nextareanum] = 1;
2351 }
2352 } //end if
2353 }
2354 //
2355 // getting down to here is bad for cpu usage
2356 if ( count++ > MAX_HIDEAREA_LOOPS ) {
2357 //botimport.Print(PRT_MESSAGE, "AAS_NearestHideArea: exceeded max loops, aborting\n" );
2358 continue;
2359 }
2360 //
2361 // otherwise, add this to the list so we check is reachables
2362 // disabled, this should only store the raw traveltime, not the adjusted time
2363 //(*aasworld).hidetraveltimes[nextareanum] = t;
2364 nextupdate = &( *aasworld ).areaupdate[nextareanum];
2365 nextupdate->areanum = nextareanum;
2366 nextupdate->tmptraveltime = t;
2367 //remember where we entered this area
2368 VectorCopy( reach->end, nextupdate->start );
2369 //if this update is not in the list yet
2370 if ( !nextupdate->inlist ) {
2371 //add the new update to the end of the list
2372 nextupdate->next = NULL;
2373 nextupdate->prev = updatelistend;
2374 if ( updatelistend ) {
2375 updatelistend->next = nextupdate;
2376 } else { updateliststart = nextupdate;}
2377 updatelistend = nextupdate;
2378 nextupdate->inlist = qtrue;
2379 } //end if
2380 } //end if
2381 } //end for
2382 } //end while
2383 //botimport.Print(PRT_MESSAGE, "AAS_NearestHideArea: hidearea: %i, %i loops\n", bestarea, count );
2384 return bestarea;
2385 } //end of the function AAS_NearestHideArea
2386
2387 //===========================================================================
2388 //
2389 // Parameter: -
2390 // Returns: -
2391 // Changes Globals: -
2392 //===========================================================================
AAS_FindAttackSpotWithinRange(int srcnum,int rangenum,int enemynum,float rangedist,int travelflags,float * outpos)2393 int AAS_FindAttackSpotWithinRange( int srcnum, int rangenum, int enemynum, float rangedist, int travelflags, float *outpos ) {
2394 int i, nextareanum, badtravelflags, numreach, bestarea;
2395 unsigned short int t, besttraveltime;
2396 aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
2397 aas_reachability_t *reach;
2398 vec3_t srcorg, rangeorg, enemyorg;
2399 int srcarea, rangearea, enemyarea;
2400 unsigned short int srctraveltime;
2401 int count = 0;
2402 #define MAX_ATTACKAREA_LOOPS 200
2403 static float lastTime;
2404 //
2405 // RF, currently doesn't work with multiple AAS worlds, so only enable for the default world
2406 //if (aasworld != aasworlds) return 0;
2407 //
2408 // don't run this more than once per frame
2409 if ( lastTime == AAS_Time() ) {
2410 return 0;
2411 }
2412 lastTime = AAS_Time();
2413 //
2414 if ( !( *aasworld ).hidetraveltimes ) {
2415 ( *aasworld ).hidetraveltimes = (unsigned short int *) GetClearedMemory( ( *aasworld ).numareas * sizeof( unsigned short int ) );
2416 } else {
2417 memset( ( *aasworld ).hidetraveltimes, 0, ( *aasworld ).numareas * sizeof( unsigned short int ) );
2418 } //end else
2419 //
2420 if ( !( *aasworld ).visCache ) {
2421 ( *aasworld ).visCache = (byte *) GetClearedMemory( ( *aasworld ).numareas * sizeof( byte ) );
2422 } else {
2423 memset( ( *aasworld ).visCache, 0, ( *aasworld ).numareas * sizeof( byte ) );
2424 } //end else
2425 //
2426 srcarea = AAS_BestReachableEntityArea( srcnum );
2427 rangearea = AAS_BestReachableEntityArea( rangenum );
2428 enemyarea = AAS_BestReachableEntityArea( enemynum );
2429 //
2430 AAS_EntityOrigin( srcnum, srcorg );
2431 AAS_EntityOrigin( rangenum, rangeorg );
2432 AAS_EntityOrigin( enemynum, enemyorg );
2433 //
2434 besttraveltime = 0;
2435 bestarea = 0;
2436 AAS_AreaTravelTimeToGoalArea( srcarea, srcorg, enemyarea, travelflags );
2437 //
2438 badtravelflags = ~travelflags;
2439 //
2440 curupdate = &( *aasworld ).areaupdate[rangearea];
2441 curupdate->areanum = rangearea;
2442 VectorCopy( rangeorg, curupdate->start );
2443 curupdate->areatraveltimes = ( *aasworld ).areatraveltimes[srcarea][0];
2444 curupdate->tmptraveltime = 0;
2445 //put the area to start with in the current read list
2446 curupdate->next = NULL;
2447 curupdate->prev = NULL;
2448 updateliststart = curupdate;
2449 updatelistend = curupdate;
2450 //while there are updates in the current list, flip the lists
2451 while ( updateliststart )
2452 {
2453 curupdate = updateliststart;
2454 //
2455 if ( curupdate->next ) {
2456 curupdate->next->prev = NULL;
2457 } else { updatelistend = NULL;}
2458 updateliststart = curupdate->next;
2459 //
2460 curupdate->inlist = qfalse;
2461 //check all reversed reachability links
2462 numreach = ( *aasworld ).areasettings[curupdate->areanum].numreachableareas;
2463 reach = &( *aasworld ).reachability[( *aasworld ).areasettings[curupdate->areanum].firstreachablearea];
2464 //
2465 for ( i = 0; i < numreach; i++, reach++ )
2466 {
2467 //if an undesired travel type is used
2468 if ( ( *aasworld ).travelflagfortype[reach->traveltype] & badtravelflags ) {
2469 continue;
2470 }
2471 //
2472 if ( AAS_AreaContentsTravelFlag( reach->areanum ) & badtravelflags ) {
2473 continue;
2474 }
2475 //
2476 if ( ( *aasworld ).areasettings[reach->areanum].areaflags & AREA_DISABLED ) {
2477 continue;
2478 }
2479 //number of the area the reachability leads to
2480 nextareanum = reach->areanum;
2481 // if this moves us into the enemies area, skip it
2482 if ( nextareanum == enemyarea ) {
2483 continue;
2484 }
2485 // if we've already been to this area
2486 if ( ( *aasworld ).hidetraveltimes[nextareanum] ) {
2487 continue;
2488 }
2489 //time already travelled plus the traveltime through
2490 //the current area plus the travel time from the reachability
2491 if ( count++ > MAX_ATTACKAREA_LOOPS ) {
2492 //botimport.Print(PRT_MESSAGE, "AAS_FindAttackSpotWithinRange: exceeded max loops, aborting\n" );
2493 if ( bestarea ) {
2494 VectorCopy( ( *aasworld ).areawaypoints[bestarea], outpos );
2495 }
2496 return bestarea;
2497 }
2498 t = curupdate->tmptraveltime +
2499 AAS_AreaTravelTime( curupdate->areanum, curupdate->start, reach->start ) +
2500 reach->traveltime;
2501 //
2502 // if it's too far from rangenum, ignore
2503 if ( Distance( rangeorg, ( *aasworld ).areawaypoints[nextareanum] ) > rangedist ) {
2504 continue;
2505 }
2506 //
2507 // find the traveltime from srcnum
2508 srctraveltime = AAS_AreaTravelTimeToGoalArea( srcarea, srcorg, nextareanum, travelflags );
2509 // do this test now, so we can reject the route if it starts out too long
2510 if ( besttraveltime && srctraveltime >= besttraveltime ) {
2511 continue;
2512 }
2513 //
2514 // if this area doesn't have a vis list, ignore it
2515 if ( ( *aasworld ).areavisibility[nextareanum] ) {
2516 //if the nextarea can see the enemy area
2517 if ( AAS_AreaVisible( enemyarea, nextareanum ) ) { // now last of all, check that this area is a good attacking spot
2518 if ( ( ( *aasworld ).visCache[nextareanum] == 2 ) ||
2519 ( !( *aasworld ).visCache[nextareanum] &&
2520 ( count += 10 ) && // we are about to use lots of CPU time
2521 botimport.AICast_CheckAttackAtPos( srcnum, enemynum, ( *aasworld ).areawaypoints[nextareanum], qfalse, qfalse ) ) ) {
2522 ( *aasworld ).visCache[nextareanum] = 2;
2523 besttraveltime = srctraveltime;
2524 bestarea = nextareanum;
2525 } else {
2526 ( *aasworld ).visCache[nextareanum] = 1;
2527 }
2528 } //end if
2529 }
2530 ( *aasworld ).hidetraveltimes[nextareanum] = t;
2531 nextupdate = &( *aasworld ).areaupdate[nextareanum];
2532 nextupdate->areanum = nextareanum;
2533 nextupdate->tmptraveltime = t;
2534 //remember where we entered this area
2535 VectorCopy( reach->end, nextupdate->start );
2536 //if this update is not in the list yet
2537 if ( !nextupdate->inlist ) {
2538 //add the new update to the end of the list
2539 nextupdate->next = NULL;
2540 nextupdate->prev = updatelistend;
2541 if ( updatelistend ) {
2542 updatelistend->next = nextupdate;
2543 } else { updateliststart = nextupdate;}
2544 updatelistend = nextupdate;
2545 nextupdate->inlist = qtrue;
2546 } //end if
2547 } //end for
2548 } //end while
2549 //botimport.Print(PRT_MESSAGE, "AAS_NearestHideArea: hidearea: %i, %i loops\n", bestarea, count );
2550 if ( bestarea ) {
2551 VectorCopy( ( *aasworld ).areawaypoints[bestarea], outpos );
2552 }
2553 return bestarea;
2554 } //end of the function AAS_NearestHideArea
2555