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