2
===========================================================================
3
Copyright (C) 1999-2005 Id Software, Inc.
5
This file is part of Quake III Arena source code.
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.
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.
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
===========================================================================
23
/*****************************************************************************
24
* name: be_aas_route.c
28
* $Archive: /MissionPack/code/botlib/be_aas_route.c $
30
*****************************************************************************/
32
#include "../qcommon/q_shared.h"
39
#include "l_precomp.h"
44
#include "be_aas_funcs.h"
45
#include "be_interface.h"
46
#include "be_aas_def.h"
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
56
#define CACHE_REFRESHTIME 15.0f //15 seconds refresh time
58
//maximum number of routing updates each frame
59
#define MAX_FRAMEROUTINGUPDATES 10
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
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
80
int numareacacheupdates;
81
int numportalcacheupdates;
82
#endif //ROUTING_DEBUG
85
int max_routingcachesize;
87
//===========================================================================
92
//===========================================================================
94
void AAS_RoutingInfo(void)
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
107
// Changes Globals: -
108
//===========================================================================
109
ID_INLINE int AAS_ClusterAreaNum(int cluster, int areanum)
111
int side, areacluster;
113
areacluster = aasworld.areasettings[areanum].cluster;
114
if (areacluster > 0) return aasworld.areasettings[areanum].clusterareanum;
117
/*#ifdef ROUTING_DEBUG
118
if (aasworld.portals[-areacluster].frontcluster != cluster &&
119
aasworld.portals[-areacluster].backcluster != cluster)
121
botimport.Print(PRT_ERROR, "portal %d: does not belong to cluster %d\n"
122
, -areacluster, cluster);
124
#endif //ROUTING_DEBUG*/
125
side = aasworld.portals[-areacluster].frontcluster != cluster;
126
return aasworld.portals[-areacluster].clusterareanum[side];
128
} //end of the function AAS_ClusterAreaNum
129
//===========================================================================
133
// Changes Globals: -
134
//===========================================================================
135
void AAS_InitTravelFlagFromType(void)
139
for (i = 0; i < MAX_TRAVELTYPES; i++)
141
aasworld.travelflagfortype[i] = TFL_INVALID;
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
//===========================================================================
167
// Changes Globals: -
168
//===========================================================================
169
ID_INLINE int AAS_TravelFlagForType_inline(int traveltype)
174
if (tfl & TRAVELFLAG_NOTTEAM1)
176
if (tfl & TRAVELFLAG_NOTTEAM2)
178
traveltype &= TRAVELTYPE_MASK;
179
if (traveltype < 0 || traveltype >= MAX_TRAVELTYPES)
181
tfl |= aasworld.travelflagfortype[traveltype];
183
} //end of the function AAS_TravelFlagForType_inline
184
//===========================================================================
188
// Changes Globals: -
189
//===========================================================================
190
int AAS_TravelFlagForType(int traveltype)
192
return AAS_TravelFlagForType_inline(traveltype);
193
} //end of the function AAS_TravelFlagForType_inline
194
//===========================================================================
198
// Changes Globals: -
199
//===========================================================================
200
void AAS_UnlinkCache(aas_routingcache_t *cache)
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
//===========================================================================
213
// Changes Globals: -
214
//===========================================================================
215
void AAS_LinkCache(aas_routingcache_t *cache)
217
if (aasworld.newestcache)
219
aasworld.newestcache->time_next = cache;
220
cache->time_prev = aasworld.newestcache;
224
aasworld.oldestcache = cache;
225
cache->time_prev = NULL;
227
cache->time_next = NULL;
228
aasworld.newestcache = cache;
229
} //end of the function AAS_LinkCache
230
//===========================================================================
234
// Changes Globals: -
235
//===========================================================================
236
void AAS_FreeRoutingCache(aas_routingcache_t *cache)
238
AAS_UnlinkCache(cache);
239
routingcachesize -= cache->size;
241
} //end of the function AAS_FreeRoutingCache
242
//===========================================================================
246
// Changes Globals: -
247
//===========================================================================
248
void AAS_RemoveRoutingCacheInCluster( int clusternum )
251
aas_routingcache_t *cache, *nextcache;
252
aas_cluster_t *cluster;
254
if (!aasworld.clusterareacache)
256
cluster = &aasworld.clusters[clusternum];
257
for (i = 0; i < cluster->numareas; i++)
259
for (cache = aasworld.clusterareacache[clusternum][i]; cache; cache = nextcache)
261
nextcache = cache->next;
262
AAS_FreeRoutingCache(cache);
264
aasworld.clusterareacache[clusternum][i] = NULL;
266
} //end of the function AAS_RemoveRoutingCacheInCluster
267
//===========================================================================
271
// Changes Globals: -
272
//===========================================================================
273
void AAS_RemoveRoutingCacheUsingArea( int areanum )
276
aas_routingcache_t *cache, *nextcache;
278
clusternum = aasworld.areasettings[areanum].cluster;
281
//remove all the cache in the cluster the area is in
282
AAS_RemoveRoutingCacheInCluster( clusternum );
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 );
290
// remove all portal cache
291
for (i = 0; i < aasworld.numareas; i++)
293
//refresh portal cache
294
for (cache = aasworld.portalcache[i]; cache; cache = nextcache)
296
nextcache = cache->next;
297
AAS_FreeRoutingCache(cache);
299
aasworld.portalcache[i] = NULL;
301
} //end of the function AAS_RemoveRoutingCacheUsingArea
302
//===========================================================================
306
// Changes Globals: -
307
//===========================================================================
308
int AAS_EnableRoutingArea(int areanum, int enable)
312
if (areanum <= 0 || areanum >= aasworld.numareas)
316
botimport.Print(PRT_ERROR, "AAS_EnableRoutingArea: areanum %d out of range\n", areanum);
320
flags = aasworld.areasettings[areanum].areaflags & AREA_DISABLED;
325
aasworld.areasettings[areanum].areaflags &= ~AREA_DISABLED;
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) )
331
//remove all routing cache involving this area
332
AAS_RemoveRoutingCacheUsingArea( areanum );
335
} //end of the function AAS_EnableRoutingArea
336
//===========================================================================
340
// Changes Globals: -
341
//===========================================================================
342
ID_INLINE float AAS_RoutingTime(void)
345
} //end of the function AAS_RoutingTime
346
//===========================================================================
350
// Changes Globals: -
351
//===========================================================================
352
int AAS_GetAreaContentsTravelFlags(int areanum)
356
contents = aasworld.areasettings[areanum].contents;
358
if (contents & AREACONTENTS_WATER)
360
else if (contents & AREACONTENTS_SLIME)
362
else if (contents & AREACONTENTS_LAVA)
366
if (contents & AREACONTENTS_DONOTENTER)
367
tfl |= TFL_DONOTENTER;
368
if (contents & AREACONTENTS_NOTTEAM1)
370
if (contents & AREACONTENTS_NOTTEAM2)
372
if (aasworld.areasettings[areanum].areaflags & AREA_BRIDGE)
375
} //end of the function AAS_GetAreaContentsTravelFlags
376
//===========================================================================
380
// Changes Globals: -
381
//===========================================================================
382
ID_INLINE int AAS_AreaContentsTravelFlags_inline(int areanum)
384
return aasworld.areacontentstravelflags[areanum];
385
} //end of the function AAS_AreaContentsTravelFlags
386
//===========================================================================
390
// Changes Globals: -
391
//===========================================================================
392
int AAS_AreaContentsTravelFlags(int areanum)
394
return aasworld.areacontentstravelflags[areanum];
395
} //end of the function AAS_AreaContentsTravelFlags
396
//===========================================================================
400
// Changes Globals: -
401
//===========================================================================
402
void AAS_InitAreaContentsTravelFlags(void)
406
if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags);
407
aasworld.areacontentstravelflags = (int *) GetClearedMemory(aasworld.numareas * sizeof(int));
409
for (i = 0; i < aasworld.numareas; i++) {
410
aasworld.areacontentstravelflags[i] = AAS_GetAreaContentsTravelFlags(i);
412
} //end of the function AAS_InitAreaContentsTravelFlags
413
//===========================================================================
417
// Changes Globals: -
418
//===========================================================================
419
void AAS_CreateReversedReachability(void)
422
aas_reversedlink_t *revlink;
423
aas_reachability_t *reach;
424
aas_areasettings_t *settings;
429
starttime = Sys_MilliSeconds();
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));
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++)
443
//settings of the area
444
settings = &aasworld.areasettings[i];
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++)
452
reach = &aasworld.reachability[settings->firstreachablearea + n];
454
revlink = (aas_reversedlink_t *) ptr;
455
ptr += sizeof(aas_reversedlink_t);
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++;
465
botimport.Print(PRT_MESSAGE, "reversed reachability %d msec\n", Sys_MilliSeconds() - starttime);
467
} //end of the function AAS_CreateReversedReachability
468
//===========================================================================
472
// Changes Globals: -
473
//===========================================================================
474
unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end)
480
VectorSubtract(start, end, dir);
481
dist = VectorLength(dir);
482
//if crouch only area
483
if (AAS_AreaCrouch(areanum)) dist *= DISTANCEFACTOR_CROUCH;
485
else if (AAS_AreaSwim(areanum)) dist *= DISTANCEFACTOR_SWIM;
487
else dist *= DISTANCEFACTOR_WALK;
489
intdist = (int) dist;
490
//make sure the distance isn't zero
491
if (intdist <= 0) intdist = 1;
493
} //end of the function AAS_AreaTravelTime
494
//===========================================================================
498
// Changes Globals: -
499
//===========================================================================
500
void AAS_CalculateAreaTravelTimes(void)
505
aas_reversedreachability_t *revreach;
506
aas_reversedlink_t *revlink;
507
aas_reachability_t *reach;
508
aas_areasettings_t *settings;
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++)
518
revreach = &aasworld.reversedreachability[i];
519
//settings of the area
520
settings = &aasworld.areasettings[i];
522
size += settings->numreachableareas * sizeof(unsigned short *);
524
size += settings->numreachableareas *
525
PAD(revreach->numlinks, sizeof(long)) * sizeof(unsigned short);
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++)
534
//reversed reachabilities of this area
535
revreach = &aasworld.reversedreachability[i];
536
//settings of the area
537
settings = &aasworld.areasettings[i];
539
aasworld.areatraveltimes[i] = (unsigned short **) ptr;
540
ptr += settings->numreachableareas * sizeof(unsigned short *);
542
for (l = 0; l < settings->numreachableareas; l++)
544
aasworld.areatraveltimes[i][l] = (unsigned short *) ptr;
545
ptr += PAD(revreach->numlinks, sizeof(long)) * sizeof(unsigned short);
547
reach = &aasworld.reachability[settings->firstreachablearea + l];
549
for (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++)
551
VectorCopy(aasworld.reachability[revlink->linknum].end, end);
553
aasworld.areatraveltimes[i][l][n] = AAS_AreaTravelTime(i, end, reach->start);
558
botimport.Print(PRT_MESSAGE, "area travel times %d msec\n", Sys_MilliSeconds() - starttime);
560
} //end of the function AAS_CalculateAreaTravelTimes
561
//===========================================================================
565
// Changes Globals: -
566
//===========================================================================
567
int AAS_PortalMaxTravelTime(int portalnum)
570
aas_portal_t *portal;
571
aas_reversedreachability_t *revreach;
572
aas_reversedlink_t *revlink;
573
aas_areasettings_t *settings;
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];
582
for (l = 0; l < settings->numreachableareas; l++)
584
for (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++)
586
t = aasworld.areatraveltimes[portal->areanum][l][n];
594
} //end of the function AAS_PortalMaxTravelTime
595
//===========================================================================
599
// Changes Globals: -
600
//===========================================================================
601
void AAS_InitPortalMaxTravelTimes(void)
605
if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes);
607
aasworld.portalmaxtraveltimes = (int *) GetClearedMemory(aasworld.numportals * sizeof(int));
609
for (i = 0; i < aasworld.numportals; i++)
611
aasworld.portalmaxtraveltimes[i] = AAS_PortalMaxTravelTime(i);
612
//botimport.Print(PRT_MESSAGE, "portal %d max tt = %d\n", i, aasworld.portalmaxtraveltimes[i]);
614
} //end of the function AAS_InitPortalMaxTravelTimes
615
//===========================================================================
619
// Changes Globals: -
620
//===========================================================================
622
int AAS_FreeOldestCache(void)
624
int i, j, bestcluster, bestarea, freed;
626
aas_routingcache_t *cache, *bestcache;
629
besttime = 999999999;
633
//refresh cluster cache
634
for (i = 0; i < aasworld.numclusters; i++)
636
for (j = 0; j < aasworld.clusters[i].numareas; j++)
638
for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)
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)
648
besttime = cache->time;
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);
662
besttime = 999999999;
665
for (i = 0; i < aasworld.numareas; i++)
667
//refresh portal cache
668
for (cache = aasworld.portalcache[i]; cache; cache = cache->next)
670
if (cache->time < besttime)
674
besttime = cache->time;
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);
688
} //end of the function AAS_FreeOldestCache
690
//===========================================================================
694
// Changes Globals: -
695
//===========================================================================
696
int AAS_FreeOldestCache(void)
699
aas_routingcache_t *cache;
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) {
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;
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;
724
AAS_FreeRoutingCache(cache);
728
} //end of the function AAS_FreeOldestCache
729
//===========================================================================
733
// Changes Globals: -
734
//===========================================================================
735
aas_routingcache_t *AAS_AllocRoutingCache(int numtraveltimes)
737
aas_routingcache_t *cache;
741
size = sizeof(aas_routingcache_t)
742
+ numtraveltimes * sizeof(unsigned short int)
743
+ numtraveltimes * sizeof(unsigned char);
745
routingcachesize += size;
747
cache = (aas_routingcache_t *) GetClearedMemory(size);
748
cache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t)
749
+ numtraveltimes * sizeof(unsigned short int);
752
} //end of the function AAS_AllocRoutingCache
753
//===========================================================================
757
// Changes Globals: -
758
//===========================================================================
759
void AAS_FreeAllClusterAreaCache(void)
762
aas_routingcache_t *cache, *nextcache;
763
aas_cluster_t *cluster;
765
//free all cluster cache if existing
766
if (!aasworld.clusterareacache) return;
768
for (i = 0; i < aasworld.numclusters; i++)
770
cluster = &aasworld.clusters[i];
771
for (j = 0; j < cluster->numareas; j++)
773
for (cache = aasworld.clusterareacache[i][j]; cache; cache = nextcache)
775
nextcache = cache->next;
776
AAS_FreeRoutingCache(cache);
778
aasworld.clusterareacache[i][j] = NULL;
781
//free the cluster cache array
782
FreeMemory(aasworld.clusterareacache);
783
aasworld.clusterareacache = NULL;
784
} //end of the function AAS_FreeAllClusterAreaCache
785
//===========================================================================
789
// Changes Globals: -
790
//===========================================================================
791
void AAS_InitClusterAreaCache(void)
797
for (size = 0, i = 0; i < aasworld.numclusters; i++)
799
size += aasworld.clusters[i].numareas;
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++)
810
aasworld.clusterareacache[i] = (aas_routingcache_t **) ptr;
811
ptr += aasworld.clusters[i].numareas * sizeof(aas_routingcache_t *);
813
} //end of the function AAS_InitClusterAreaCache
814
//===========================================================================
818
// Changes Globals: -
819
//===========================================================================
820
void AAS_FreeAllPortalCache(void)
823
aas_routingcache_t *cache, *nextcache;
825
//free all portal cache if existing
826
if (!aasworld.portalcache) return;
828
for (i = 0; i < aasworld.numareas; i++)
830
for (cache = aasworld.portalcache[i]; cache; cache = nextcache)
832
nextcache = cache->next;
833
AAS_FreeRoutingCache(cache);
835
aasworld.portalcache[i] = NULL;
837
FreeMemory(aasworld.portalcache);
838
aasworld.portalcache = NULL;
839
} //end of the function AAS_FreeAllPortalCache
840
//===========================================================================
844
// Changes Globals: -
845
//===========================================================================
846
void AAS_InitPortalCache(void)
849
aasworld.portalcache = (aas_routingcache_t **) GetClearedMemory(
850
aasworld.numareas * sizeof(aas_routingcache_t *));
851
} //end of the function AAS_InitPortalCache
852
//===========================================================================
856
// Changes Globals: -
857
//===========================================================================
858
void AAS_InitRoutingUpdate(void)
860
int i, maxreachabilityareas;
862
//free routing update fields if already existing
863
if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate);
865
maxreachabilityareas = 0;
866
for (i = 0; i < aasworld.numclusters; i++)
868
if (aasworld.clusters[i].numreachabilityareas > maxreachabilityareas)
870
maxreachabilityareas = aasworld.clusters[i].numreachabilityareas;
873
//allocate memory for the routing update fields
874
aasworld.areaupdate = (aas_routingupdate_t *) GetClearedMemory(
875
maxreachabilityareas * sizeof(aas_routingupdate_t));
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
} //end of the function AAS_InitRoutingUpdate
882
//===========================================================================
886
// Changes Globals: -
887
//===========================================================================
888
void AAS_CreateAllRoutingCache(void)
892
aasworld.initialized = qtrue;
893
botimport.Print(PRT_MESSAGE, "AAS_CreateAllRoutingCache\n");
894
for (i = 1; i < aasworld.numareas; i++)
896
if (!AAS_AreaReachability(i)) continue;
897
for (j = 1; j < aasworld.numareas; j++)
899
if (i == j) continue;
900
if (!AAS_AreaReachability(j)) continue;
901
t = AAS_AreaTravelTimeToGoalArea(i, aasworld.areas[i].center, j, TFL_DEFAULT);
902
//Log_Write("traveltime from %d to %d is %d", i, j, t);
905
aasworld.initialized = qfalse;
906
} //end of the function AAS_CreateAllRoutingCache
907
//===========================================================================
911
// Changes Globals: -
912
//===========================================================================
914
//the route cache header
915
//this header is followed by numportalcache + numareacache aas_routingcache_t
916
//structures that store routing cache
917
typedef struct routecacheheader_s
927
} routecacheheader_t;
929
#define RCID (('C'<<24)+('R'<<16)+('E'<<8)+'M')
932
//void AAS_DecompressVis(byte *in, int numareas, byte *decompressed);
933
//int AAS_CompressVis(byte *vis, int numareas, byte *dest);
935
void AAS_WriteRouteCache(void)
937
int i, j, numportalcache, numareacache, totalsize;
938
aas_routingcache_t *cache;
939
aas_cluster_t *cluster;
941
char filename[MAX_QPATH];
942
routecacheheader_t routecacheheader;
945
for (i = 0; i < aasworld.numareas; i++)
947
for (cache = aasworld.portalcache[i]; cache; cache = cache->next)
953
for (i = 0; i < aasworld.numclusters; i++)
955
cluster = &aasworld.clusters[i];
956
for (j = 0; j < cluster->numareas; j++)
958
for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)
964
// open the file for writing
965
Com_sprintf(filename, MAX_QPATH, "maps/%s.rcd", aasworld.mapname);
966
botimport.FS_FOpenFile( filename, &fp, FS_WRITE );
969
AAS_Error("Unable to open file: %s\n", filename);
973
routecacheheader.ident = RCID;
974
routecacheheader.version = RCVERSION;
975
routecacheheader.numareas = aasworld.numareas;
976
routecacheheader.numclusters = aasworld.numclusters;
977
routecacheheader.areacrc = CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas );
978
routecacheheader.clustercrc = CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters );
979
routecacheheader.numportalcache = numportalcache;
980
routecacheheader.numareacache = numareacache;
982
botimport.FS_Write(&routecacheheader, sizeof(routecacheheader_t), fp);
985
//write all the cache
986
for (i = 0; i < aasworld.numareas; i++)
988
for (cache = aasworld.portalcache[i]; cache; cache = cache->next)
990
botimport.FS_Write(cache, cache->size, fp);
991
totalsize += cache->size;
994
for (i = 0; i < aasworld.numclusters; i++)
996
cluster = &aasworld.clusters[i];
997
for (j = 0; j < cluster->numareas; j++)
999
for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)
1001
botimport.FS_Write(cache, cache->size, fp);
1002
totalsize += cache->size;
1006
// write the visareas
1008
for (i = 0; i < aasworld.numareas; i++)
1010
if (!aasworld.areavisibility[i]) {
1012
botimport.FS_Write(&size, sizeof(int), fp);
1015
AAS_DecompressVis( aasworld.areavisibility[i], aasworld.numareas, aasworld.decompressedvis );
1016
size = AAS_CompressVis( aasworld.decompressedvis, aasworld.numareas, aasworld.decompressedvis );
1017
botimport.FS_Write(&size, sizeof(int), fp);
1018
botimport.FS_Write(aasworld.decompressedvis, size, fp);
1022
botimport.FS_FCloseFile(fp);
1023
botimport.Print(PRT_MESSAGE, "\nroute cache written to %s\n", filename);
1024
botimport.Print(PRT_MESSAGE, "written %d bytes of routing cache\n", totalsize);
1025
} //end of the function AAS_WriteRouteCache
1026
//===========================================================================
1030
// Changes Globals: -
1031
//===========================================================================
1032
aas_routingcache_t *AAS_ReadCache(fileHandle_t fp)
1035
aas_routingcache_t *cache;
1037
botimport.FS_Read(&size, sizeof(size), fp);
1038
cache = (aas_routingcache_t *) GetMemory(size);
1040
botimport.FS_Read((unsigned char *)cache + sizeof(size), size - sizeof(size), fp);
1041
cache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t) - sizeof(unsigned short) +
1042
(size - sizeof(aas_routingcache_t) + sizeof(unsigned short)) / 3 * 2;
1044
} //end of the function AAS_ReadCache
1045
//===========================================================================
1049
// Changes Globals: -
1050
//===========================================================================
1051
int AAS_ReadRouteCache(void)
1053
int i, clusterareanum;//, size;
1055
char filename[MAX_QPATH];
1056
routecacheheader_t routecacheheader;
1057
aas_routingcache_t *cache;
1059
Com_sprintf(filename, MAX_QPATH, "maps/%s.rcd", aasworld.mapname);
1060
botimport.FS_FOpenFile( filename, &fp, FS_READ );
1065
botimport.FS_Read(&routecacheheader, sizeof(routecacheheader_t), fp );
1066
if (routecacheheader.ident != RCID)
1068
AAS_Error("%s is not a route cache dump\n");
1071
if (routecacheheader.version != RCVERSION)
1073
AAS_Error("route cache dump has wrong version %d, should be %d", routecacheheader.version, RCVERSION);
1076
if (routecacheheader.numareas != aasworld.numareas)
1078
//AAS_Error("route cache dump has wrong number of areas\n");
1081
if (routecacheheader.numclusters != aasworld.numclusters)
1083
//AAS_Error("route cache dump has wrong number of clusters\n");
1086
if (routecacheheader.areacrc !=
1087
CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas ))
1089
//AAS_Error("route cache dump area CRC incorrect\n");
1092
if (routecacheheader.clustercrc !=
1093
CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters ))
1095
//AAS_Error("route cache dump cluster CRC incorrect\n");
1098
//read all the portal cache
1099
for (i = 0; i < routecacheheader.numportalcache; i++)
1101
cache = AAS_ReadCache(fp);
1102
cache->next = aasworld.portalcache[cache->areanum];
1104
if (aasworld.portalcache[cache->areanum])
1105
aasworld.portalcache[cache->areanum]->prev = cache;
1106
aasworld.portalcache[cache->areanum] = cache;
1108
//read all the cluster area cache
1109
for (i = 0; i < routecacheheader.numareacache; i++)
1111
cache = AAS_ReadCache(fp);
1112
clusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum);
1113
cache->next = aasworld.clusterareacache[cache->cluster][clusterareanum];
1115
if (aasworld.clusterareacache[cache->cluster][clusterareanum])
1116
aasworld.clusterareacache[cache->cluster][clusterareanum]->prev = cache;
1117
aasworld.clusterareacache[cache->cluster][clusterareanum] = cache;
1119
// read the visareas
1121
aasworld.areavisibility = (byte **) GetClearedMemory(aasworld.numareas * sizeof(byte *));
1122
aasworld.decompressedvis = (byte *) GetClearedMemory(aasworld.numareas * sizeof(byte));
1123
for (i = 0; i < aasworld.numareas; i++)
1125
botimport.FS_Read(&size, sizeof(size), fp );
1127
aasworld.areavisibility[i] = (byte *) GetMemory(size);
1128
botimport.FS_Read(aasworld.areavisibility[i], size, fp );
1133
botimport.FS_FCloseFile(fp);
1135
} //end of the function AAS_ReadRouteCache
1136
//===========================================================================
1140
// Changes Globals: -
1141
//===========================================================================
1142
#define MAX_REACHABILITYPASSAREAS 32
1144
void AAS_InitReachabilityAreas(void)
1146
int i, j, numareas, areas[MAX_REACHABILITYPASSAREAS];
1148
aas_reachability_t *reach;
1151
if (aasworld.reachabilityareas)
1152
FreeMemory(aasworld.reachabilityareas);
1153
if (aasworld.reachabilityareaindex)
1154
FreeMemory(aasworld.reachabilityareaindex);
1156
aasworld.reachabilityareas = (aas_reachabilityareas_t *)
1157
GetClearedMemory(aasworld.reachabilitysize * sizeof(aas_reachabilityareas_t));
1158
aasworld.reachabilityareaindex = (int *)
1159
GetClearedMemory(aasworld.reachabilitysize * MAX_REACHABILITYPASSAREAS * sizeof(int));
1161
for (i = 0; i < aasworld.reachabilitysize; i++)
1163
reach = &aasworld.reachability[i];
1165
switch(reach->traveltype & TRAVELTYPE_MASK)
1167
//trace areas from start to end
1168
case TRAVEL_BARRIERJUMP:
1169
case TRAVEL_WATERJUMP:
1170
VectorCopy(reach->start, end);
1171
end[2] = reach->end[2];
1172
numareas = AAS_TraceAreas(reach->start, end, areas, NULL, MAX_REACHABILITYPASSAREAS);
1174
case TRAVEL_WALKOFFLEDGE:
1175
VectorCopy(reach->end, start);
1176
start[2] = reach->start[2];
1177
numareas = AAS_TraceAreas(start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS);
1179
case TRAVEL_GRAPPLEHOOK:
1180
numareas = AAS_TraceAreas(reach->start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS);
1184
case TRAVEL_JUMP: break;
1185
case TRAVEL_ROCKETJUMP: break;
1186
case TRAVEL_BFGJUMP: break;
1187
case TRAVEL_JUMPPAD: break;
1189
//trace from reach->start to entity center, along entity movement
1190
//and from entity center to reach->end
1191
case TRAVEL_ELEVATOR: break;
1192
case TRAVEL_FUNCBOB: break;
1194
//no areas in between
1195
case TRAVEL_WALK: break;
1196
case TRAVEL_CROUCH: break;
1197
case TRAVEL_LADDER: break;
1198
case TRAVEL_SWIM: break;
1199
case TRAVEL_TELEPORT: break;
1202
aasworld.reachabilityareas[i].firstarea = numreachareas;
1203
aasworld.reachabilityareas[i].numareas = numareas;
1204
for (j = 0; j < numareas; j++)
1206
aasworld.reachabilityareaindex[numreachareas++] = areas[j];
1209
} //end of the function AAS_InitReachabilityAreas
1210
//===========================================================================
1214
// Changes Globals: -
1215
//===========================================================================
1216
void AAS_InitRouting(void)
1218
AAS_InitTravelFlagFromType();
1220
AAS_InitAreaContentsTravelFlags();
1221
//initialize the routing update fields
1222
AAS_InitRoutingUpdate();
1223
//create reversed reachability links used by the routing update algorithm
1224
AAS_CreateReversedReachability();
1225
//initialize the cluster cache
1226
AAS_InitClusterAreaCache();
1227
//initialize portal cache
1228
AAS_InitPortalCache();
1229
//initialize the area travel times
1230
AAS_CalculateAreaTravelTimes();
1231
//calculate the maximum travel times through portals
1232
AAS_InitPortalMaxTravelTimes();
1233
//get the areas reachabilities go through
1234
AAS_InitReachabilityAreas();
1236
#ifdef ROUTING_DEBUG
1237
numareacacheupdates = 0;
1238
numportalcacheupdates = 0;
1239
#endif //ROUTING_DEBUG
1241
routingcachesize = 0;
1242
max_routingcachesize = 1024 * (int) LibVarValue("max_routingcache", "4096");
1243
// read any routing cache if available
1244
AAS_ReadRouteCache();
1245
} //end of the function AAS_InitRouting
1246
//===========================================================================
1250
// Changes Globals: -
1251
//===========================================================================
1252
void AAS_FreeRoutingCaches(void)
1254
// free all the existing cluster area cache
1255
AAS_FreeAllClusterAreaCache();
1256
// free all the existing portal cache
1257
AAS_FreeAllPortalCache();
1258
// free cached travel times within areas
1259
if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes);
1260
aasworld.areatraveltimes = NULL;
1261
// free cached maximum travel time through cluster portals
1262
if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes);
1263
aasworld.portalmaxtraveltimes = NULL;
1264
// free reversed reachability links
1265
if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability);
1266
aasworld.reversedreachability = NULL;
1267
// free routing algorithm memory
1268
if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate);
1269
aasworld.areaupdate = NULL;
1270
if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate);
1271
aasworld.portalupdate = NULL;
1272
// free lists with areas the reachabilities go through
1273
if (aasworld.reachabilityareas) FreeMemory(aasworld.reachabilityareas);
1274
aasworld.reachabilityareas = NULL;
1275
// free the reachability area index
1276
if (aasworld.reachabilityareaindex) FreeMemory(aasworld.reachabilityareaindex);
1277
aasworld.reachabilityareaindex = NULL;
1278
// free area contents travel flags look up table
1279
if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags);
1280
aasworld.areacontentstravelflags = NULL;
1281
} //end of the function AAS_FreeRoutingCaches
1282
//===========================================================================
1283
// update the given routing cache
1285
// Parameter: areacache : routing cache to update
1287
// Changes Globals: -
1288
//===========================================================================
1289
void AAS_UpdateAreaRoutingCache(aas_routingcache_t *areacache)
1291
int i, nextareanum, cluster, badtravelflags, clusterareanum, linknum;
1292
int numreachabilityareas;
1293
unsigned short int t, startareatraveltimes[128]; //NOTE: not more than 128 reachabilities per area allowed
1294
aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
1295
aas_reachability_t *reach;
1296
aas_reversedreachability_t *revreach;
1297
aas_reversedlink_t *revlink;
1299
#ifdef ROUTING_DEBUG
1300
numareacacheupdates++;
1301
#endif //ROUTING_DEBUG
1302
//number of reachability areas within this cluster
1303
numreachabilityareas = aasworld.clusters[areacache->cluster].numreachabilityareas;
1305
aasworld.frameroutingupdates++;
1306
//clear the routing update fields
1307
// Com_Memset(aasworld.areaupdate, 0, aasworld.numareas * sizeof(aas_routingupdate_t));
1309
badtravelflags = ~areacache->travelflags;
1311
clusterareanum = AAS_ClusterAreaNum(areacache->cluster, areacache->areanum);
1312
if (clusterareanum >= numreachabilityareas) return;
1314
Com_Memset(startareatraveltimes, 0, sizeof(startareatraveltimes));
1316
curupdate = &aasworld.areaupdate[clusterareanum];
1317
curupdate->areanum = areacache->areanum;
1318
//VectorCopy(areacache->origin, curupdate->start);
1319
curupdate->areatraveltimes = startareatraveltimes;
1320
curupdate->tmptraveltime = areacache->starttraveltime;
1322
areacache->traveltimes[clusterareanum] = areacache->starttraveltime;
1323
//put the area to start with in the current read list
1324
curupdate->next = NULL;
1325
curupdate->prev = NULL;
1326
updateliststart = curupdate;
1327
updatelistend = curupdate;
1328
//while there are updates in the current list
1329
while (updateliststart)
1331
curupdate = updateliststart;
1333
if (curupdate->next) curupdate->next->prev = NULL;
1334
else updatelistend = NULL;
1335
updateliststart = curupdate->next;
1337
curupdate->inlist = qfalse;
1338
//check all reversed reachability links
1339
revreach = &aasworld.reversedreachability[curupdate->areanum];
1341
for (i = 0, revlink = revreach->first; revlink; revlink = revlink->next, i++)
1343
linknum = revlink->linknum;
1344
reach = &aasworld.reachability[linknum];
1345
//if there is used an undesired travel type
1346
if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue;
1347
//if not allowed to enter the next area
1348
if (aasworld.areasettings[reach->areanum].areaflags & AREA_DISABLED) continue;
1349
//if the next area has a not allowed travel flag
1350
if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue;
1351
//number of the area the reversed reachability leads to
1352
nextareanum = revlink->areanum;
1353
//get the cluster number of the area
1354
cluster = aasworld.areasettings[nextareanum].cluster;
1355
//don't leave the cluster
1356
if (cluster > 0 && cluster != areacache->cluster) continue;
1357
//get the number of the area in the cluster
1358
clusterareanum = AAS_ClusterAreaNum(areacache->cluster, nextareanum);
1359
if (clusterareanum >= numreachabilityareas) continue;
1360
//time already travelled plus the traveltime through
1361
//the current area plus the travel time from the reachability
1362
t = curupdate->tmptraveltime +
1363
//AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->end) +
1364
curupdate->areatraveltimes[i] +
1367
if (!areacache->traveltimes[clusterareanum] ||
1368
areacache->traveltimes[clusterareanum] > t)
1370
areacache->traveltimes[clusterareanum] = t;
1371
areacache->reachabilities[clusterareanum] = linknum - aasworld.areasettings[nextareanum].firstreachablearea;
1372
nextupdate = &aasworld.areaupdate[clusterareanum];
1373
nextupdate->areanum = nextareanum;
1374
nextupdate->tmptraveltime = t;
1375
//VectorCopy(reach->start, nextupdate->start);
1376
nextupdate->areatraveltimes = aasworld.areatraveltimes[nextareanum][linknum -
1377
aasworld.areasettings[nextareanum].firstreachablearea];
1378
if (!nextupdate->inlist)
1380
// we add the update to the end of the list
1381
// we could also use a B+ tree to have a real sorted list
1382
// on travel time which makes for faster routing updates
1383
nextupdate->next = NULL;
1384
nextupdate->prev = updatelistend;
1385
if (updatelistend) updatelistend->next = nextupdate;
1386
else updateliststart = nextupdate;
1387
updatelistend = nextupdate;
1388
nextupdate->inlist = qtrue;
1393
} //end of the function AAS_UpdateAreaRoutingCache
1394
//===========================================================================
1398
// Changes Globals: -
1399
//===========================================================================
1400
aas_routingcache_t *AAS_GetAreaRoutingCache(int clusternum, int areanum, int travelflags)
1403
aas_routingcache_t *cache, *clustercache;
1405
//number of the area in the cluster
1406
clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
1407
//pointer to the cache for the area in the cluster
1408
clustercache = aasworld.clusterareacache[clusternum][clusterareanum];
1409
//find the cache without undesired travel flags
1410
for (cache = clustercache; cache; cache = cache->next)
1412
//if there aren't used any undesired travel types for the cache
1413
if (cache->travelflags == travelflags) break;
1415
//if there was no cache
1418
cache = AAS_AllocRoutingCache(aasworld.clusters[clusternum].numreachabilityareas);
1419
cache->cluster = clusternum;
1420
cache->areanum = areanum;
1421
VectorCopy(aasworld.areas[areanum].center, cache->origin);
1422
cache->starttraveltime = 1;
1423
cache->travelflags = travelflags;
1425
cache->next = clustercache;
1426
if (clustercache) clustercache->prev = cache;
1427
aasworld.clusterareacache[clusternum][clusterareanum] = cache;
1428
AAS_UpdateAreaRoutingCache(cache);
1432
AAS_UnlinkCache(cache);
1434
//the cache has been accessed
1435
cache->time = AAS_RoutingTime();
1436
cache->type = CACHETYPE_AREA;
1437
AAS_LinkCache(cache);
1439
} //end of the function AAS_GetAreaRoutingCache
1440
//===========================================================================
1444
// Changes Globals: -
1445
//===========================================================================
1446
void AAS_UpdatePortalRoutingCache(aas_routingcache_t *portalcache)
1448
int i, portalnum, clusterareanum, clusternum;
1449
unsigned short int t;
1450
aas_portal_t *portal;
1451
aas_cluster_t *cluster;
1452
aas_routingcache_t *cache;
1453
aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
1455
#ifdef ROUTING_DEBUG
1456
numportalcacheupdates++;
1457
#endif //ROUTING_DEBUG
1458
//clear the routing update fields
1459
// Com_Memset(aasworld.portalupdate, 0, (aasworld.numportals+1) * sizeof(aas_routingupdate_t));
1461
curupdate = &aasworld.portalupdate[aasworld.numportals];
1462
curupdate->cluster = portalcache->cluster;
1463
curupdate->areanum = portalcache->areanum;
1464
curupdate->tmptraveltime = portalcache->starttraveltime;
1465
//if the start area is a cluster portal, store the travel time for that portal
1466
clusternum = aasworld.areasettings[portalcache->areanum].cluster;
1469
portalcache->traveltimes[-clusternum] = portalcache->starttraveltime;
1471
//put the area to start with in the current read list
1472
curupdate->next = NULL;
1473
curupdate->prev = NULL;
1474
updateliststart = curupdate;
1475
updatelistend = curupdate;
1476
//while there are updates in the current list
1477
while (updateliststart)
1479
curupdate = updateliststart;
1480
//remove the current update from the list
1481
if (curupdate->next) curupdate->next->prev = NULL;
1482
else updatelistend = NULL;
1483
updateliststart = curupdate->next;
1484
//current update is removed from the list
1485
curupdate->inlist = qfalse;
1487
cluster = &aasworld.clusters[curupdate->cluster];
1489
cache = AAS_GetAreaRoutingCache(curupdate->cluster,
1490
curupdate->areanum, portalcache->travelflags);
1491
//take all portals of the cluster
1492
for (i = 0; i < cluster->numportals; i++)
1494
portalnum = aasworld.portalindex[cluster->firstportal + i];
1495
portal = &aasworld.portals[portalnum];
1496
//if this is the portal of the current update continue
1497
if (portal->areanum == curupdate->areanum) continue;
1499
clusterareanum = AAS_ClusterAreaNum(curupdate->cluster, portal->areanum);
1500
if (clusterareanum >= cluster->numreachabilityareas) continue;
1502
t = cache->traveltimes[clusterareanum];
1504
t += curupdate->tmptraveltime;
1506
if (!portalcache->traveltimes[portalnum] ||
1507
portalcache->traveltimes[portalnum] > t)
1509
portalcache->traveltimes[portalnum] = t;
1510
nextupdate = &aasworld.portalupdate[portalnum];
1511
if (portal->frontcluster == curupdate->cluster)
1513
nextupdate->cluster = portal->backcluster;
1517
nextupdate->cluster = portal->frontcluster;
1519
nextupdate->areanum = portal->areanum;
1520
//add travel time through the actual portal area for the next update
1521
nextupdate->tmptraveltime = t + aasworld.portalmaxtraveltimes[portalnum];
1522
if (!nextupdate->inlist)
1524
// we add the update to the end of the list
1525
// we could also use a B+ tree to have a real sorted list
1526
// on travel time which makes for faster routing updates
1527
nextupdate->next = NULL;
1528
nextupdate->prev = updatelistend;
1529
if (updatelistend) updatelistend->next = nextupdate;
1530
else updateliststart = nextupdate;
1531
updatelistend = nextupdate;
1532
nextupdate->inlist = qtrue;
1537
} //end of the function AAS_UpdatePortalRoutingCache
1538
//===========================================================================
1542
// Changes Globals: -
1543
//===========================================================================
1544
aas_routingcache_t *AAS_GetPortalRoutingCache(int clusternum, int areanum, int travelflags)
1546
aas_routingcache_t *cache;
1548
//find the cached portal routing if existing
1549
for (cache = aasworld.portalcache[areanum]; cache; cache = cache->next)
1551
if (cache->travelflags == travelflags) break;
1553
//if the portal routing isn't cached
1556
cache = AAS_AllocRoutingCache(aasworld.numportals);
1557
cache->cluster = clusternum;
1558
cache->areanum = areanum;
1559
VectorCopy(aasworld.areas[areanum].center, cache->origin);
1560
cache->starttraveltime = 1;
1561
cache->travelflags = travelflags;
1562
//add the cache to the cache list
1564
cache->next = aasworld.portalcache[areanum];
1565
if (aasworld.portalcache[areanum]) aasworld.portalcache[areanum]->prev = cache;
1566
aasworld.portalcache[areanum] = cache;
1568
AAS_UpdatePortalRoutingCache(cache);
1572
AAS_UnlinkCache(cache);
1574
//the cache has been accessed
1575
cache->time = AAS_RoutingTime();
1576
cache->type = CACHETYPE_PORTAL;
1577
AAS_LinkCache(cache);
1579
} //end of the function AAS_GetPortalRoutingCache
1580
//===========================================================================
1584
// Changes Globals: -
1585
//===========================================================================
1586
int AAS_AreaRouteToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags, int *traveltime, int *reachnum)
1588
int clusternum, goalclusternum, portalnum, i, clusterareanum, bestreachnum;
1589
unsigned short int t, besttime;
1590
aas_portal_t *portal;
1591
aas_cluster_t *cluster;
1592
aas_routingcache_t *areacache, *portalcache;
1593
aas_reachability_t *reach;
1595
if (!aasworld.initialized) return qfalse;
1597
if (areanum == goalareanum)
1604
if (areanum <= 0 || areanum >= aasworld.numareas)
1608
botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: areanum %d out of range\n", areanum);
1612
if (goalareanum <= 0 || goalareanum >= aasworld.numareas)
1616
botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: goalareanum %d out of range\n", goalareanum);
1620
// make sure the routing cache doesn't grow to large
1621
while(AvailableMemory() < 1 * 1024 * 1024) {
1622
if (!AAS_FreeOldestCache()) break;
1625
if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goalareanum))
1627
travelflags |= TFL_DONOTENTER;
1629
//NOTE: the number of routing updates is limited per frame
1631
if (aasworld.frameroutingupdates > MAX_FRAMEROUTINGUPDATES)
1634
//Log_Write("WARNING: AAS_AreaTravelTimeToGoalArea: frame routing updates overflowed");
1640
clusternum = aasworld.areasettings[areanum].cluster;
1641
goalclusternum = aasworld.areasettings[goalareanum].cluster;
1642
//check if the area is a portal of the goal area cluster
1643
if (clusternum < 0 && goalclusternum > 0)
1645
portal = &aasworld.portals[-clusternum];
1646
if (portal->frontcluster == goalclusternum ||
1647
portal->backcluster == goalclusternum)
1649
clusternum = goalclusternum;
1652
//check if the goalarea is a portal of the area cluster
1653
else if (clusternum > 0 && goalclusternum < 0)
1655
portal = &aasworld.portals[-goalclusternum];
1656
if (portal->frontcluster == clusternum ||
1657
portal->backcluster == clusternum)
1659
goalclusternum = clusternum;
1662
//if both areas are in the same cluster
1663
//NOTE: there might be a shorter route via another cluster!!! but we don't care
1664
if (clusternum > 0 && goalclusternum > 0 && clusternum == goalclusternum)
1667
areacache = AAS_GetAreaRoutingCache(clusternum, goalareanum, travelflags);
1668
//the number of the area in the cluster
1669
clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
1670
//the cluster the area is in
1671
cluster = &aasworld.clusters[clusternum];
1672
//if the area is NOT a reachability area
1673
if (clusterareanum >= cluster->numreachabilityareas) return 0;
1674
//if it is possible to travel to the goal area through this cluster
1675
if (areacache->traveltimes[clusterareanum] != 0)
1677
*reachnum = aasworld.areasettings[areanum].firstreachablearea +
1678
areacache->reachabilities[clusterareanum];
1680
*traveltime = areacache->traveltimes[clusterareanum];
1683
reach = &aasworld.reachability[*reachnum];
1684
*traveltime = areacache->traveltimes[clusterareanum] +
1685
AAS_AreaTravelTime(areanum, origin, reach->start);
1691
clusternum = aasworld.areasettings[areanum].cluster;
1692
goalclusternum = aasworld.areasettings[goalareanum].cluster;
1693
//if the goal area is a portal
1694
if (goalclusternum < 0)
1696
//just assume the goal area is part of the front cluster
1697
portal = &aasworld.portals[-goalclusternum];
1698
goalclusternum = portal->frontcluster;
1700
//get the portal routing cache
1701
portalcache = AAS_GetPortalRoutingCache(goalclusternum, goalareanum, travelflags);
1702
//if the area is a cluster portal, read directly from the portal cache
1705
*traveltime = portalcache->traveltimes[-clusternum];
1706
*reachnum = aasworld.areasettings[areanum].firstreachablearea +
1707
portalcache->reachabilities[-clusternum];
1713
//the cluster the area is in
1714
cluster = &aasworld.clusters[clusternum];
1715
//find the portal of the area cluster leading towards the goal area
1716
for (i = 0; i < cluster->numportals; i++)
1718
portalnum = aasworld.portalindex[cluster->firstportal + i];
1719
//if the goal area isn't reachable from the portal
1720
if (!portalcache->traveltimes[portalnum]) continue;
1722
portal = &aasworld.portals[portalnum];
1723
//get the cache of the portal area
1724
areacache = AAS_GetAreaRoutingCache(clusternum, portal->areanum, travelflags);
1725
//current area inside the current cluster
1726
clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
1727
//if the area is NOT a reachability area
1728
if (clusterareanum >= cluster->numreachabilityareas) continue;
1729
//if the portal is NOT reachable from this area
1730
if (!areacache->traveltimes[clusterareanum]) continue;
1731
//total travel time is the travel time the portal area is from
1732
//the goal area plus the travel time towards the portal area
1733
t = portalcache->traveltimes[portalnum] + areacache->traveltimes[clusterareanum];
1734
//FIXME: add the exact travel time through the actual portal area
1735
//NOTE: for now we just add the largest travel time through the portal area
1736
// because we can't directly calculate the exact travel time
1737
// to be more specific we don't know which reachability was used to travel
1738
// into the portal area
1739
t += aasworld.portalmaxtraveltimes[portalnum];
1743
*reachnum = aasworld.areasettings[areanum].firstreachablearea +
1744
areacache->reachabilities[clusterareanum];
1745
reach = aasworld.reachability + *reachnum;
1746
t += AAS_AreaTravelTime(areanum, origin, reach->start);
1748
//if the time is better than the one already found
1749
if (!besttime || t < besttime)
1751
bestreachnum = *reachnum;
1755
if (bestreachnum < 0) {
1758
*reachnum = bestreachnum;
1759
*traveltime = besttime;
1761
} //end of the function AAS_AreaRouteToGoalArea
1762
//===========================================================================
1766
// Changes Globals: -
1767
//===========================================================================
1768
int AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags)
1770
int traveltime, reachnum;
1772
if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum))
1777
} //end of the function AAS_AreaTravelTimeToGoalArea
1778
//===========================================================================
1782
// Changes Globals: -
1783
//===========================================================================
1784
int AAS_AreaReachabilityToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags)
1786
int traveltime, reachnum;
1788
if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum))
1793
} //end of the function AAS_AreaReachabilityToGoalArea
1794
//===========================================================================
1795
// predict the route and stop on one of the stop events
1799
// Changes Globals: -
1800
//===========================================================================
1801
int AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin,
1802
int goalareanum, int travelflags, int maxareas, int maxtime,
1803
int stopevent, int stopcontents, int stoptfl, int stopareanum)
1805
int curareanum, reachnum, i, j, testareanum;
1807
aas_reachability_t *reach;
1808
aas_reachabilityareas_t *reachareas;
1811
route->stopevent = RSE_NONE;
1812
route->endarea = goalareanum;
1813
route->endcontents = 0;
1814
route->endtravelflags = 0;
1815
VectorCopy(origin, route->endpos);
1818
curareanum = areanum;
1819
VectorCopy(origin, curorigin);
1821
for (i = 0; curareanum != goalareanum && (!maxareas || i < maxareas) && i < aasworld.numareas; i++)
1823
reachnum = AAS_AreaReachabilityToGoalArea(curareanum, curorigin, goalareanum, travelflags);
1826
route->stopevent = RSE_NOROUTE;
1829
reach = &aasworld.reachability[reachnum];
1831
if (stopevent & RSE_USETRAVELTYPE)
1833
if (AAS_TravelFlagForType_inline(reach->traveltype) & stoptfl)
1835
route->stopevent = RSE_USETRAVELTYPE;
1836
route->endarea = curareanum;
1837
route->endcontents = aasworld.areasettings[curareanum].contents;
1838
route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype);
1839
VectorCopy(reach->start, route->endpos);
1842
if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & stoptfl)
1844
route->stopevent = RSE_USETRAVELTYPE;
1845
route->endarea = reach->areanum;
1846
route->endcontents = aasworld.areasettings[reach->areanum].contents;
1847
route->endtravelflags = AAS_AreaContentsTravelFlags_inline(reach->areanum);
1848
VectorCopy(reach->end, route->endpos);
1849
route->time += AAS_AreaTravelTime(areanum, origin, reach->start);
1850
route->time += reach->traveltime;
1854
reachareas = &aasworld.reachabilityareas[reachnum];
1855
for (j = 0; j < reachareas->numareas + 1; j++)
1857
if (j >= reachareas->numareas)
1858
testareanum = reach->areanum;
1860
testareanum = aasworld.reachabilityareaindex[reachareas->firstarea + j];
1861
if (stopevent & RSE_ENTERCONTENTS)
1863
if (aasworld.areasettings[testareanum].contents & stopcontents)
1865
route->stopevent = RSE_ENTERCONTENTS;
1866
route->endarea = testareanum;
1867
route->endcontents = aasworld.areasettings[testareanum].contents;
1868
VectorCopy(reach->end, route->endpos);
1869
route->time += AAS_AreaTravelTime(areanum, origin, reach->start);
1870
route->time += reach->traveltime;
1874
if (stopevent & RSE_ENTERAREA)
1876
if (testareanum == stopareanum)
1878
route->stopevent = RSE_ENTERAREA;
1879
route->endarea = testareanum;
1880
route->endcontents = aasworld.areasettings[testareanum].contents;
1881
VectorCopy(reach->start, route->endpos);
1887
route->time += AAS_AreaTravelTime(areanum, origin, reach->start);
1888
route->time += reach->traveltime;
1889
route->endarea = reach->areanum;
1890
route->endcontents = aasworld.areasettings[reach->areanum].contents;
1891
route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype);
1892
VectorCopy(reach->end, route->endpos);
1894
curareanum = reach->areanum;
1895
VectorCopy(reach->end, curorigin);
1897
if (maxtime && route->time > maxtime)
1900
if (curareanum != goalareanum)
1903
} //end of the function AAS_PredictRoute
1904
//===========================================================================
1908
// Changes Globals: -
1909
//===========================================================================
1910
int AAS_BridgeWalkable(int areanum)
1913
} //end of the function AAS_BridgeWalkable
1914
//===========================================================================
1918
// Changes Globals: -
1919
//===========================================================================
1920
void AAS_ReachabilityFromNum(int num, struct aas_reachability_s *reach)
1922
if (!aasworld.initialized)
1924
Com_Memset(reach, 0, sizeof(aas_reachability_t));
1927
if (num < 0 || num >= aasworld.reachabilitysize)
1929
Com_Memset(reach, 0, sizeof(aas_reachability_t));
1932
Com_Memcpy(reach, &aasworld.reachability[num], sizeof(aas_reachability_t));;
1933
} //end of the function AAS_ReachabilityFromNum
1934
//===========================================================================
1938
// Changes Globals: -
1939
//===========================================================================
1940
int AAS_NextAreaReachability(int areanum, int reachnum)
1942
aas_areasettings_t *settings;
1944
if (!aasworld.initialized) return 0;
1946
if (areanum <= 0 || areanum >= aasworld.numareas)
1948
botimport.Print(PRT_ERROR, "AAS_NextAreaReachability: areanum %d out of range\n", areanum);
1952
settings = &aasworld.areasettings[areanum];
1955
return settings->firstreachablearea;
1957
if (reachnum < settings->firstreachablearea)
1959
botimport.Print(PRT_FATAL, "AAS_NextAreaReachability: reachnum < settings->firstreachableara");
1963
if (reachnum >= settings->firstreachablearea + settings->numreachableareas)
1968
} //end of the function AAS_NextAreaReachability
1969
//===========================================================================
1973
// Changes Globals: -
1974
//===========================================================================
1975
int AAS_NextModelReachability(int num, int modelnum)
1979
if (num <= 0) num = 1;
1980
else if (num >= aasworld.reachabilitysize) return 0;
1983
for (i = num; i < aasworld.reachabilitysize; i++)
1985
if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR)
1987
if (aasworld.reachability[i].facenum == modelnum) return i;
1989
else if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)
1991
if ((aasworld.reachability[i].facenum & 0x0000FFFF) == modelnum) return i;
1995
} //end of the function AAS_NextModelReachability
1996
//===========================================================================
2000
// Changes Globals: -
2001
//===========================================================================
2002
int AAS_RandomGoalArea(int areanum, int travelflags, int *goalareanum, vec3_t goalorigin)
2008
//if the area has no reachabilities
2009
if (!AAS_AreaReachability(areanum)) return qfalse;
2011
n = aasworld.numareas * random();
2012
for (i = 0; i < aasworld.numareas; i++)
2015
if (n >= aasworld.numareas) n = 1;
2016
if (AAS_AreaReachability(n))
2018
t = AAS_AreaTravelTimeToGoalArea(areanum, aasworld.areas[areanum].center, n, travelflags);
2019
//if the goal is reachable
2022
if (AAS_AreaSwim(n))
2025
VectorCopy(aasworld.areas[n].center, goalorigin);
2026
//botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum);
2029
VectorCopy(aasworld.areas[n].center, start);
2030
if (!AAS_PointAreaNum(start))
2031
Log_Write("area %d center %f %f %f in solid?", n, start[0], start[1], start[2]);
2032
VectorCopy(start, end);
2034
trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
2035
if (!trace.startsolid && trace.fraction < 1 && AAS_PointAreaNum(trace.endpos) == n)
2037
if (AAS_AreaGroundFaceArea(n) > 300)
2040
VectorCopy(trace.endpos, goalorigin);
2041
//botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum);
2050
} //end of the function AAS_RandomGoalArea
2051
//===========================================================================
2055
// Changes Globals: -
2056
//===========================================================================
2057
int AAS_AreaVisible(int srcarea, int destarea)
2060
} //end of the function AAS_AreaVisible
2061
//===========================================================================
2065
// Changes Globals: -
2066
//===========================================================================
2067
float DistancePointToLine(vec3_t v1, vec3_t v2, vec3_t point)
2071
AAS_ProjectPointOntoVector(point, v1, v2, p2);
2072
VectorSubtract(point, p2, vec);
2073
return VectorLength(vec);
2074
} //end of the function DistancePointToLine
2075
//===========================================================================
2079
// Changes Globals: -
2080
//===========================================================================
2081
int AAS_NearestHideArea(int srcnum, vec3_t origin, int areanum, int enemynum, vec3_t enemyorigin, int enemyareanum, int travelflags)
2083
int i, j, nextareanum, badtravelflags, numreach, bestarea;
2084
unsigned short int t, besttraveltime;
2085
static unsigned short int *hidetraveltimes;
2086
aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
2087
aas_reachability_t *reach;
2090
qboolean startVisible;
2093
if (!hidetraveltimes)
2095
hidetraveltimes = (unsigned short int *) GetClearedMemory(aasworld.numareas * sizeof(unsigned short int));
2099
Com_Memset(hidetraveltimes, 0, aasworld.numareas * sizeof(unsigned short int));
2104
startVisible = qtrue;
2106
badtravelflags = ~travelflags;
2108
curupdate = &aasworld.areaupdate[areanum];
2109
curupdate->areanum = areanum;
2110
VectorCopy(origin, curupdate->start);
2111
curupdate->areatraveltimes = aasworld.areatraveltimes[areanum][0];
2112
curupdate->tmptraveltime = 0;
2113
//put the area to start with in the current read list
2114
curupdate->next = NULL;
2115
curupdate->prev = NULL;
2116
updateliststart = curupdate;
2117
updatelistend = curupdate;
2118
//while there are updates in the list
2119
while (updateliststart)
2121
curupdate = updateliststart;
2123
if (curupdate->next) curupdate->next->prev = NULL;
2124
else updatelistend = NULL;
2125
updateliststart = curupdate->next;
2127
curupdate->inlist = qfalse;
2128
//check all reversed reachability links
2129
numreach = aasworld.areasettings[curupdate->areanum].numreachableareas;
2130
reach = &aasworld.reachability[aasworld.areasettings[curupdate->areanum].firstreachablearea];
2132
for (i = 0; i < numreach; i++, reach++)
2134
//if an undesired travel type is used
2135
if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue;
2137
if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue;
2138
//number of the area the reachability leads to
2139
nextareanum = reach->areanum;
2140
// if this moves us into the enemies area, skip it
2141
if (nextareanum == enemyareanum) continue;
2142
//time already travelled plus the traveltime through
2143
//the current area plus the travel time from the reachability
2144
t = curupdate->tmptraveltime +
2145
AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->start) +
2148
//avoid going near the enemy
2149
AAS_ProjectPointOntoVector(enemyorigin, curupdate->start, reach->end, p);
2150
for (j = 0; j < 3; j++)
2151
if ((p[j] > curupdate->start[j] && p[j] > reach->end[j]) ||
2152
(p[j] < curupdate->start[j] && p[j] < reach->end[j]))
2156
VectorSubtract(enemyorigin, reach->end, v2);
2160
VectorSubtract(enemyorigin, p, v2);
2162
dist2 = VectorLength(v2);
2163
//never go through the enemy
2164
if (dist2 < 40) continue;
2166
VectorSubtract(enemyorigin, curupdate->start, v1);
2167
dist1 = VectorLength(v1);
2171
t += (dist1 - dist2) * 10;
2173
// if we weren't visible when starting, make sure we don't move into their view
2174
if (!startVisible && AAS_AreaVisible(enemyareanum, nextareanum)) {
2178
if (besttraveltime && t >= besttraveltime) continue;
2180
if (!hidetraveltimes[nextareanum] ||
2181
hidetraveltimes[nextareanum] > t)
2183
//if the nextarea is not visible from the enemy area
2184
if (!AAS_AreaVisible(enemyareanum, nextareanum))
2187
bestarea = nextareanum;
2189
hidetraveltimes[nextareanum] = t;
2190
nextupdate = &aasworld.areaupdate[nextareanum];
2191
nextupdate->areanum = nextareanum;
2192
nextupdate->tmptraveltime = t;
2193
//remember where we entered this area
2194
VectorCopy(reach->end, nextupdate->start);
2195
//if this update is not in the list yet
2196
if (!nextupdate->inlist)
2198
//add the new update to the end of the list
2199
nextupdate->next = NULL;
2200
nextupdate->prev = updatelistend;
2201
if (updatelistend) updatelistend->next = nextupdate;
2202
else updateliststart = nextupdate;
2203
updatelistend = nextupdate;
2204
nextupdate->inlist = qtrue;
2210
} //end of the function AAS_NearestHideArea