00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "../game/q_shared.h"
00033 #include "l_utils.h"
00034 #include "l_memory.h"
00035 #include "l_log.h"
00036 #include "l_crc.h"
00037 #include "l_libvar.h"
00038 #include "l_script.h"
00039 #include "l_precomp.h"
00040 #include "l_struct.h"
00041 #include "aasfile.h"
00042 #include "../game/botlib.h"
00043 #include "../game/be_aas.h"
00044 #include "be_aas_funcs.h"
00045 #include "be_interface.h"
00046 #include "be_aas_def.h"
00047
00048 #define ROUTING_DEBUG
00049
00050
00051 #define DISTANCEFACTOR_CROUCH 1.3f //crouch speed = 100
00052 #define DISTANCEFACTOR_SWIM 1 //should be 0.66, swim speed = 150
00053 #define DISTANCEFACTOR_WALK 0.33f //walk speed = 300
00054
00055
00056 #define CACHE_REFRESHTIME 15.0f //15 seconds refresh time
00057
00058
00059 #define MAX_FRAMEROUTINGUPDATES 10
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 #ifdef ROUTING_DEBUG
00080 int numareacacheupdates;
00081 int numportalcacheupdates;
00082 #endif //ROUTING_DEBUG
00083
00084 int routingcachesize;
00085 int max_routingcachesize;
00086
00087
00088
00089
00090
00091
00092
00093 #ifdef ROUTING_DEBUG
00094 void AAS_RoutingInfo(void)
00095 {
00096 botimport.Print(PRT_MESSAGE, "%d area cache updates\n", numareacacheupdates);
00097 botimport.Print(PRT_MESSAGE, "%d portal cache updates\n", numportalcacheupdates);
00098 botimport.Print(PRT_MESSAGE, "%d bytes routing cache\n", routingcachesize);
00099 }
00100 #endif //ROUTING_DEBUG
00101
00102
00103
00104
00105
00106
00107
00108
00109 __inline int AAS_ClusterAreaNum(int cluster, int areanum)
00110 {
00111 int side, areacluster;
00112
00113 areacluster = aasworld.areasettings[areanum].cluster;
00114 if (areacluster > 0) return aasworld.areasettings[areanum].clusterareanum;
00115 else
00116 {
00117
00118
00119
00120
00121
00122
00123
00124
00125 side = aasworld.portals[-areacluster].frontcluster != cluster;
00126 return aasworld.portals[-areacluster].clusterareanum[side];
00127 }
00128 }
00129
00130
00131
00132
00133
00134
00135 void AAS_InitTravelFlagFromType(void)
00136 {
00137 int i;
00138
00139 for (i = 0; i < MAX_TRAVELTYPES; i++)
00140 {
00141 aasworld.travelflagfortype[i] = TFL_INVALID;
00142 }
00143 aasworld.travelflagfortype[TRAVEL_INVALID] = TFL_INVALID;
00144 aasworld.travelflagfortype[TRAVEL_WALK] = TFL_WALK;
00145 aasworld.travelflagfortype[TRAVEL_CROUCH] = TFL_CROUCH;
00146 aasworld.travelflagfortype[TRAVEL_BARRIERJUMP] = TFL_BARRIERJUMP;
00147 aasworld.travelflagfortype[TRAVEL_JUMP] = TFL_JUMP;
00148 aasworld.travelflagfortype[TRAVEL_LADDER] = TFL_LADDER;
00149 aasworld.travelflagfortype[TRAVEL_WALKOFFLEDGE] = TFL_WALKOFFLEDGE;
00150 aasworld.travelflagfortype[TRAVEL_SWIM] = TFL_SWIM;
00151 aasworld.travelflagfortype[TRAVEL_WATERJUMP] = TFL_WATERJUMP;
00152 aasworld.travelflagfortype[TRAVEL_TELEPORT] = TFL_TELEPORT;
00153 aasworld.travelflagfortype[TRAVEL_ELEVATOR] = TFL_ELEVATOR;
00154 aasworld.travelflagfortype[TRAVEL_ROCKETJUMP] = TFL_ROCKETJUMP;
00155 aasworld.travelflagfortype[TRAVEL_BFGJUMP] = TFL_BFGJUMP;
00156 aasworld.travelflagfortype[TRAVEL_GRAPPLEHOOK] = TFL_GRAPPLEHOOK;
00157 aasworld.travelflagfortype[TRAVEL_DOUBLEJUMP] = TFL_DOUBLEJUMP;
00158 aasworld.travelflagfortype[TRAVEL_RAMPJUMP] = TFL_RAMPJUMP;
00159 aasworld.travelflagfortype[TRAVEL_STRAFEJUMP] = TFL_STRAFEJUMP;
00160 aasworld.travelflagfortype[TRAVEL_JUMPPAD] = TFL_JUMPPAD;
00161 aasworld.travelflagfortype[TRAVEL_FUNCBOB] = TFL_FUNCBOB;
00162 }
00163
00164
00165
00166
00167
00168
00169 __inline int AAS_TravelFlagForType_inline(int traveltype)
00170 {
00171 int tfl;
00172
00173 tfl = 0;
00174 if (tfl & TRAVELFLAG_NOTTEAM1)
00175 tfl |= TFL_NOTTEAM1;
00176 if (tfl & TRAVELFLAG_NOTTEAM2)
00177 tfl |= TFL_NOTTEAM2;
00178 traveltype &= TRAVELTYPE_MASK;
00179 if (traveltype < 0 || traveltype >= MAX_TRAVELTYPES)
00180 return TFL_INVALID;
00181 tfl |= aasworld.travelflagfortype[traveltype];
00182 return tfl;
00183 }
00184
00185
00186
00187
00188
00189
00190 int AAS_TravelFlagForType(int traveltype)
00191 {
00192 return AAS_TravelFlagForType_inline(traveltype);
00193 }
00194
00195
00196
00197
00198
00199
00200 void AAS_UnlinkCache(aas_routingcache_t *cache)
00201 {
00202 if (cache->time_next) cache->time_next->time_prev = cache->time_prev;
00203 else aasworld.newestcache = cache->time_prev;
00204 if (cache->time_prev) cache->time_prev->time_next = cache->time_next;
00205 else aasworld.oldestcache = cache->time_next;
00206 cache->time_next = NULL;
00207 cache->time_prev = NULL;
00208 }
00209
00210
00211
00212
00213
00214
00215 void AAS_LinkCache(aas_routingcache_t *cache)
00216 {
00217 if (aasworld.newestcache)
00218 {
00219 aasworld.newestcache->time_next = cache;
00220 cache->time_prev = aasworld.newestcache;
00221 }
00222 else
00223 {
00224 aasworld.oldestcache = cache;
00225 cache->time_prev = NULL;
00226 }
00227 cache->time_next = NULL;
00228 aasworld.newestcache = cache;
00229 }
00230
00231
00232
00233
00234
00235
00236 void AAS_FreeRoutingCache(aas_routingcache_t *cache)
00237 {
00238 AAS_UnlinkCache(cache);
00239 routingcachesize -= cache->size;
00240 FreeMemory(cache);
00241 }
00242
00243
00244
00245
00246
00247
00248 void AAS_RemoveRoutingCacheInCluster( int clusternum )
00249 {
00250 int i;
00251 aas_routingcache_t *cache, *nextcache;
00252 aas_cluster_t *cluster;
00253
00254 if (!aasworld.clusterareacache)
00255 return;
00256 cluster = &aasworld.clusters[clusternum];
00257 for (i = 0; i < cluster->numareas; i++)
00258 {
00259 for (cache = aasworld.clusterareacache[clusternum][i]; cache; cache = nextcache)
00260 {
00261 nextcache = cache->next;
00262 AAS_FreeRoutingCache(cache);
00263 }
00264 aasworld.clusterareacache[clusternum][i] = NULL;
00265 }
00266 }
00267
00268
00269
00270
00271
00272
00273 void AAS_RemoveRoutingCacheUsingArea( int areanum )
00274 {
00275 int i, clusternum;
00276 aas_routingcache_t *cache, *nextcache;
00277
00278 clusternum = aasworld.areasettings[areanum].cluster;
00279 if (clusternum > 0)
00280 {
00281
00282 AAS_RemoveRoutingCacheInCluster( clusternum );
00283 }
00284 else
00285 {
00286
00287 AAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].frontcluster );
00288 AAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].backcluster );
00289 }
00290
00291 for (i = 0; i < aasworld.numareas; i++)
00292 {
00293
00294 for (cache = aasworld.portalcache[i]; cache; cache = nextcache)
00295 {
00296 nextcache = cache->next;
00297 AAS_FreeRoutingCache(cache);
00298 }
00299 aasworld.portalcache[i] = NULL;
00300 }
00301 }
00302
00303
00304
00305
00306
00307
00308 int AAS_EnableRoutingArea(int areanum, int enable)
00309 {
00310 int flags;
00311
00312 if (areanum <= 0 || areanum >= aasworld.numareas)
00313 {
00314 if (bot_developer)
00315 {
00316 botimport.Print(PRT_ERROR, "AAS_EnableRoutingArea: areanum %d out of range\n", areanum);
00317 }
00318 return 0;
00319 }
00320 flags = aasworld.areasettings[areanum].areaflags & AREA_DISABLED;
00321 if (enable < 0)
00322 return !flags;
00323
00324 if (enable)
00325 aasworld.areasettings[areanum].areaflags &= ~AREA_DISABLED;
00326 else
00327 aasworld.areasettings[areanum].areaflags |= AREA_DISABLED;
00328
00329 if ( (flags & AREA_DISABLED) != (aasworld.areasettings[areanum].areaflags & AREA_DISABLED) )
00330 {
00331
00332 AAS_RemoveRoutingCacheUsingArea( areanum );
00333 }
00334 return !flags;
00335 }
00336
00337
00338
00339
00340
00341
00342 __inline float AAS_RoutingTime(void)
00343 {
00344 return AAS_Time();
00345 }
00346
00347
00348
00349
00350
00351
00352 int AAS_GetAreaContentsTravelFlags(int areanum)
00353 {
00354 int contents, tfl;
00355
00356 contents = aasworld.areasettings[areanum].contents;
00357 tfl = 0;
00358 if (contents & AREACONTENTS_WATER)
00359 tfl |= TFL_WATER;
00360 else if (contents & AREACONTENTS_SLIME)
00361 tfl |= TFL_SLIME;
00362 else if (contents & AREACONTENTS_LAVA)
00363 tfl |= TFL_LAVA;
00364 else
00365 tfl |= TFL_AIR;
00366 if (contents & AREACONTENTS_DONOTENTER)
00367 tfl |= TFL_DONOTENTER;
00368 if (contents & AREACONTENTS_NOTTEAM1)
00369 tfl |= TFL_NOTTEAM1;
00370 if (contents & AREACONTENTS_NOTTEAM2)
00371 tfl |= TFL_NOTTEAM2;
00372 if (aasworld.areasettings[areanum].areaflags & AREA_BRIDGE)
00373 tfl |= TFL_BRIDGE;
00374 return tfl;
00375 }
00376
00377
00378
00379
00380
00381
00382 __inline int AAS_AreaContentsTravelFlags_inline(int areanum)
00383 {
00384 return aasworld.areacontentstravelflags[areanum];
00385 }
00386
00387
00388
00389
00390
00391
00392 int AAS_AreaContentsTravelFlags(int areanum)
00393 {
00394 return aasworld.areacontentstravelflags[areanum];
00395 }
00396
00397
00398
00399
00400
00401
00402 void AAS_InitAreaContentsTravelFlags(void)
00403 {
00404 int i;
00405
00406 if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags);
00407 aasworld.areacontentstravelflags = (int *) GetClearedMemory(aasworld.numareas * sizeof(int));
00408
00409 for (i = 0; i < aasworld.numareas; i++) {
00410 aasworld.areacontentstravelflags[i] = AAS_GetAreaContentsTravelFlags(i);
00411 }
00412 }
00413
00414
00415
00416
00417
00418
00419 void AAS_CreateReversedReachability(void)
00420 {
00421 int i, n;
00422 aas_reversedlink_t *revlink;
00423 aas_reachability_t *reach;
00424 aas_areasettings_t *settings;
00425 char *ptr;
00426 #ifdef DEBUG
00427 int starttime;
00428
00429 starttime = Sys_MilliSeconds();
00430 #endif
00431
00432 if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability);
00433
00434 ptr = (char *) GetClearedMemory(aasworld.numareas * sizeof(aas_reversedreachability_t) +
00435 aasworld.reachabilitysize * sizeof(aas_reversedlink_t));
00436
00437 aasworld.reversedreachability = (aas_reversedreachability_t *) ptr;
00438
00439 ptr += aasworld.numareas * sizeof(aas_reversedreachability_t);
00440
00441 for (i = 1; i < aasworld.numareas; i++)
00442 {
00443
00444 settings = &aasworld.areasettings[i];
00445
00446 if (settings->numreachableareas >= 128)
00447 botimport.Print(PRT_WARNING, "area %d has more than 128 reachabilities\n", i);
00448
00449 for (n = 0; n < settings->numreachableareas && n < 128; n++)
00450 {
00451
00452 reach = &aasworld.reachability[settings->firstreachablearea + n];
00453
00454 revlink = (aas_reversedlink_t *) ptr;
00455 ptr += sizeof(aas_reversedlink_t);
00456
00457 revlink->areanum = i;
00458 revlink->linknum = settings->firstreachablearea + n;
00459 revlink->next = aasworld.reversedreachability[reach->areanum].first;
00460 aasworld.reversedreachability[reach->areanum].first = revlink;
00461 aasworld.reversedreachability[reach->areanum].numlinks++;
00462 }
00463 }
00464 #ifdef DEBUG
00465 botimport.Print(PRT_MESSAGE, "reversed reachability %d msec\n", Sys_MilliSeconds() - starttime);
00466 #endif
00467 }
00468
00469
00470
00471
00472
00473
00474 unsigned short int AAS_AreaTravelTime(int areanum, vec3_t start, vec3_t end)
00475 {
00476 int intdist;
00477 float dist;
00478 vec3_t dir;
00479
00480 VectorSubtract(start, end, dir);
00481 dist = VectorLength(dir);
00482
00483 if (AAS_AreaCrouch(areanum)) dist *= DISTANCEFACTOR_CROUCH;
00484
00485 else if (AAS_AreaSwim(areanum)) dist *= DISTANCEFACTOR_SWIM;
00486
00487 else dist *= DISTANCEFACTOR_WALK;
00488
00489 intdist = (int) dist;
00490
00491 if (intdist <= 0) intdist = 1;
00492 return intdist;
00493 }
00494
00495
00496
00497
00498
00499
00500 void AAS_CalculateAreaTravelTimes(void)
00501 {
00502 int i, l, n, size;
00503 char *ptr;
00504 vec3_t end;
00505 aas_reversedreachability_t *revreach;
00506 aas_reversedlink_t *revlink;
00507 aas_reachability_t *reach;
00508 aas_areasettings_t *settings;
00509 int starttime;
00510
00511 starttime = Sys_MilliSeconds();
00512
00513 if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes);
00514
00515 size = aasworld.numareas * sizeof(unsigned short **);
00516 for (i = 0; i < aasworld.numareas; i++)
00517 {
00518 revreach = &aasworld.reversedreachability[i];
00519
00520 settings = &aasworld.areasettings[i];
00521
00522 size += settings->numreachableareas * sizeof(unsigned short *);
00523
00524 size += settings->numreachableareas * revreach->numlinks * sizeof(unsigned short);
00525 }
00526
00527 ptr = (char *) GetClearedMemory(size);
00528 aasworld.areatraveltimes = (unsigned short ***) ptr;
00529 ptr += aasworld.numareas * sizeof(unsigned short **);
00530
00531 for (i = 0; i < aasworld.numareas; i++)
00532 {
00533
00534 revreach = &aasworld.reversedreachability[i];
00535
00536 settings = &aasworld.areasettings[i];
00537
00538 aasworld.areatraveltimes[i] = (unsigned short **) ptr;
00539 ptr += settings->numreachableareas * sizeof(unsigned short *);
00540
00541 for (l = 0; l < settings->numreachableareas; l++)
00542 {
00543 aasworld.areatraveltimes[i][l] = (unsigned short *) ptr;
00544 ptr += revreach->numlinks * sizeof(unsigned short);
00545
00546 reach = &aasworld.reachability[settings->firstreachablearea + l];
00547
00548 for (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++)
00549 {
00550 VectorCopy(aasworld.reachability[revlink->linknum].end, end);
00551
00552 aasworld.areatraveltimes[i][l][n] = AAS_AreaTravelTime(i, end, reach->start);
00553 }
00554 }
00555 }
00556 #ifdef DEBUG
00557 botimport.Print(PRT_MESSAGE, "area travel times %d msec\n", Sys_MilliSeconds() - starttime);
00558 #endif
00559 }
00560
00561
00562
00563
00564
00565
00566 int AAS_PortalMaxTravelTime(int portalnum)
00567 {
00568 int l, n, t, maxt;
00569 aas_portal_t *portal;
00570 aas_reversedreachability_t *revreach;
00571 aas_reversedlink_t *revlink;
00572 aas_areasettings_t *settings;
00573
00574 portal = &aasworld.portals[portalnum];
00575
00576 revreach = &aasworld.reversedreachability[portal->areanum];
00577
00578 settings = &aasworld.areasettings[portal->areanum];
00579
00580 maxt = 0;
00581 for (l = 0; l < settings->numreachableareas; l++)
00582 {
00583 for (n = 0, revlink = revreach->first; revlink; revlink = revlink->next, n++)
00584 {
00585 t = aasworld.areatraveltimes[portal->areanum][l][n];
00586 if (t > maxt)
00587 {
00588 maxt = t;
00589 }
00590 }
00591 }
00592 return maxt;
00593 }
00594
00595
00596
00597
00598
00599
00600 void AAS_InitPortalMaxTravelTimes(void)
00601 {
00602 int i;
00603
00604 if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes);
00605
00606 aasworld.portalmaxtraveltimes = (int *) GetClearedMemory(aasworld.numportals * sizeof(int));
00607
00608 for (i = 0; i < aasworld.numportals; i++)
00609 {
00610 aasworld.portalmaxtraveltimes[i] = AAS_PortalMaxTravelTime(i);
00611
00612 }
00613 }
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695 int AAS_FreeOldestCache(void)
00696 {
00697 int clusterareanum;
00698 aas_routingcache_t *cache;
00699
00700 for (cache = aasworld.oldestcache; cache; cache = cache->time_next) {
00701
00702 if (cache->type == CACHETYPE_AREA && aasworld.areasettings[cache->areanum].cluster < 0) {
00703 continue;
00704 }
00705 break;
00706 }
00707 if (cache) {
00708
00709 if (cache->type == CACHETYPE_AREA) {
00710
00711 clusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum);
00712
00713 if (cache->prev) cache->prev->next = cache->next;
00714 else aasworld.clusterareacache[cache->cluster][clusterareanum] = cache->next;
00715 if (cache->next) cache->next->prev = cache->prev;
00716 }
00717 else {
00718
00719 if (cache->prev) cache->prev->next = cache->next;
00720 else aasworld.portalcache[cache->areanum] = cache->next;
00721 if (cache->next) cache->next->prev = cache->prev;
00722 }
00723 AAS_FreeRoutingCache(cache);
00724 return qtrue;
00725 }
00726 return qfalse;
00727 }
00728
00729
00730
00731
00732
00733
00734 aas_routingcache_t *AAS_AllocRoutingCache(int numtraveltimes)
00735 {
00736 aas_routingcache_t *cache;
00737 int size;
00738
00739
00740 size = sizeof(aas_routingcache_t)
00741 + numtraveltimes * sizeof(unsigned short int)
00742 + numtraveltimes * sizeof(unsigned char);
00743
00744 routingcachesize += size;
00745
00746 cache = (aas_routingcache_t *) GetClearedMemory(size);
00747 cache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t)
00748 + numtraveltimes * sizeof(unsigned short int);
00749 cache->size = size;
00750 return cache;
00751 }
00752
00753
00754
00755
00756
00757
00758 void AAS_FreeAllClusterAreaCache(void)
00759 {
00760 int i, j;
00761 aas_routingcache_t *cache, *nextcache;
00762 aas_cluster_t *cluster;
00763
00764
00765 if (!aasworld.clusterareacache) return;
00766
00767 for (i = 0; i < aasworld.numclusters; i++)
00768 {
00769 cluster = &aasworld.clusters[i];
00770 for (j = 0; j < cluster->numareas; j++)
00771 {
00772 for (cache = aasworld.clusterareacache[i][j]; cache; cache = nextcache)
00773 {
00774 nextcache = cache->next;
00775 AAS_FreeRoutingCache(cache);
00776 }
00777 aasworld.clusterareacache[i][j] = NULL;
00778 }
00779 }
00780
00781 FreeMemory(aasworld.clusterareacache);
00782 aasworld.clusterareacache = NULL;
00783 }
00784
00785
00786
00787
00788
00789
00790 void AAS_InitClusterAreaCache(void)
00791 {
00792 int i, size;
00793 char *ptr;
00794
00795
00796 for (size = 0, i = 0; i < aasworld.numclusters; i++)
00797 {
00798 size += aasworld.clusters[i].numareas;
00799 }
00800
00801
00802 ptr = (char *) GetClearedMemory(
00803 aasworld.numclusters * sizeof(aas_routingcache_t **) +
00804 size * sizeof(aas_routingcache_t *));
00805 aasworld.clusterareacache = (aas_routingcache_t ***) ptr;
00806 ptr += aasworld.numclusters * sizeof(aas_routingcache_t **);
00807 for (i = 0; i < aasworld.numclusters; i++)
00808 {
00809 aasworld.clusterareacache[i] = (aas_routingcache_t **) ptr;
00810 ptr += aasworld.clusters[i].numareas * sizeof(aas_routingcache_t *);
00811 }
00812 }
00813
00814
00815
00816
00817
00818
00819 void AAS_FreeAllPortalCache(void)
00820 {
00821 int i;
00822 aas_routingcache_t *cache, *nextcache;
00823
00824
00825 if (!aasworld.portalcache) return;
00826
00827 for (i = 0; i < aasworld.numareas; i++)
00828 {
00829 for (cache = aasworld.portalcache[i]; cache; cache = nextcache)
00830 {
00831 nextcache = cache->next;
00832 AAS_FreeRoutingCache(cache);
00833 }
00834 aasworld.portalcache[i] = NULL;
00835 }
00836 FreeMemory(aasworld.portalcache);
00837 aasworld.portalcache = NULL;
00838 }
00839
00840
00841
00842
00843
00844
00845 void AAS_InitPortalCache(void)
00846 {
00847
00848 aasworld.portalcache = (aas_routingcache_t **) GetClearedMemory(
00849 aasworld.numareas * sizeof(aas_routingcache_t *));
00850 }
00851
00852
00853
00854
00855
00856
00857 void AAS_InitRoutingUpdate(void)
00858 {
00859 int i, maxreachabilityareas;
00860
00861
00862 if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate);
00863
00864 maxreachabilityareas = 0;
00865 for (i = 0; i < aasworld.numclusters; i++)
00866 {
00867 if (aasworld.clusters[i].numreachabilityareas > maxreachabilityareas)
00868 {
00869 maxreachabilityareas = aasworld.clusters[i].numreachabilityareas;
00870 }
00871 }
00872
00873 aasworld.areaupdate = (aas_routingupdate_t *) GetClearedMemory(
00874 maxreachabilityareas * sizeof(aas_routingupdate_t));
00875
00876 if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate);
00877
00878 aasworld.portalupdate = (aas_routingupdate_t *) GetClearedMemory(
00879 (aasworld.numportals+1) * sizeof(aas_routingupdate_t));
00880 }
00881
00882
00883
00884
00885
00886
00887 void AAS_CreateAllRoutingCache(void)
00888 {
00889 int i, j, t;
00890
00891 aasworld.initialized = qtrue;
00892 botimport.Print(PRT_MESSAGE, "AAS_CreateAllRoutingCache\n");
00893 for (i = 1; i < aasworld.numareas; i++)
00894 {
00895 if (!AAS_AreaReachability(i)) continue;
00896 for (j = 1; j < aasworld.numareas; j++)
00897 {
00898 if (i == j) continue;
00899 if (!AAS_AreaReachability(j)) continue;
00900 t = AAS_AreaTravelTimeToGoalArea(i, aasworld.areas[i].center, j, TFL_DEFAULT);
00901
00902 }
00903 }
00904 aasworld.initialized = qfalse;
00905 }
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916 typedef struct routecacheheader_s
00917 {
00918 int ident;
00919 int version;
00920 int numareas;
00921 int numclusters;
00922 int areacrc;
00923 int clustercrc;
00924 int numportalcache;
00925 int numareacache;
00926 } routecacheheader_t;
00927
00928 #define RCID (('C'<<24)+('R'<<16)+('E'<<8)+'M')
00929 #define RCVERSION 2
00930
00931
00932
00933
00934 void AAS_WriteRouteCache(void)
00935 {
00936 int i, j, numportalcache, numareacache, totalsize;
00937 aas_routingcache_t *cache;
00938 aas_cluster_t *cluster;
00939 fileHandle_t fp;
00940 char filename[MAX_QPATH];
00941 routecacheheader_t routecacheheader;
00942
00943 numportalcache = 0;
00944 for (i = 0; i < aasworld.numareas; i++)
00945 {
00946 for (cache = aasworld.portalcache[i]; cache; cache = cache->next)
00947 {
00948 numportalcache++;
00949 }
00950 }
00951 numareacache = 0;
00952 for (i = 0; i < aasworld.numclusters; i++)
00953 {
00954 cluster = &aasworld.clusters[i];
00955 for (j = 0; j < cluster->numareas; j++)
00956 {
00957 for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)
00958 {
00959 numareacache++;
00960 }
00961 }
00962 }
00963
00964 Com_sprintf(filename, MAX_QPATH, "maps/%s.rcd", aasworld.mapname);
00965 botimport.FS_FOpenFile( filename, &fp, FS_WRITE );
00966 if (!fp)
00967 {
00968 AAS_Error("Unable to open file: %s\n", filename);
00969 return;
00970 }
00971
00972 routecacheheader.ident = RCID;
00973 routecacheheader.version = RCVERSION;
00974 routecacheheader.numareas = aasworld.numareas;
00975 routecacheheader.numclusters = aasworld.numclusters;
00976 routecacheheader.areacrc = CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas );
00977 routecacheheader.clustercrc = CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters );
00978 routecacheheader.numportalcache = numportalcache;
00979 routecacheheader.numareacache = numareacache;
00980
00981 botimport.FS_Write(&routecacheheader, sizeof(routecacheheader_t), fp);
00982
00983 totalsize = 0;
00984
00985 for (i = 0; i < aasworld.numareas; i++)
00986 {
00987 for (cache = aasworld.portalcache[i]; cache; cache = cache->next)
00988 {
00989 botimport.FS_Write(cache, cache->size, fp);
00990 totalsize += cache->size;
00991 }
00992 }
00993 for (i = 0; i < aasworld.numclusters; i++)
00994 {
00995 cluster = &aasworld.clusters[i];
00996 for (j = 0; j < cluster->numareas; j++)
00997 {
00998 for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)
00999 {
01000 botimport.FS_Write(cache, cache->size, fp);
01001 totalsize += cache->size;
01002 }
01003 }
01004 }
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021 botimport.FS_FCloseFile(fp);
01022 botimport.Print(PRT_MESSAGE, "\nroute cache written to %s\n", filename);
01023 botimport.Print(PRT_MESSAGE, "written %d bytes of routing cache\n", totalsize);
01024 }
01025
01026
01027
01028
01029
01030
01031 aas_routingcache_t *AAS_ReadCache(fileHandle_t fp)
01032 {
01033 int size;
01034 aas_routingcache_t *cache;
01035
01036 botimport.FS_Read(&size, sizeof(size), fp);
01037 cache = (aas_routingcache_t *) GetMemory(size);
01038 cache->size = size;
01039 botimport.FS_Read((unsigned char *)cache + sizeof(size), size - sizeof(size), fp);
01040 cache->reachabilities = (unsigned char *) cache + sizeof(aas_routingcache_t) - sizeof(unsigned short) +
01041 (size - sizeof(aas_routingcache_t) + sizeof(unsigned short)) / 3 * 2;
01042 return cache;
01043 }
01044
01045
01046
01047
01048
01049
01050 int AAS_ReadRouteCache(void)
01051 {
01052 int i, clusterareanum;
01053 fileHandle_t fp;
01054 char filename[MAX_QPATH];
01055 routecacheheader_t routecacheheader;
01056 aas_routingcache_t *cache;
01057
01058 Com_sprintf(filename, MAX_QPATH, "maps/%s.rcd", aasworld.mapname);
01059 botimport.FS_FOpenFile( filename, &fp, FS_READ );
01060 if (!fp)
01061 {
01062 return qfalse;
01063 }
01064 botimport.FS_Read(&routecacheheader, sizeof(routecacheheader_t), fp );
01065 if (routecacheheader.ident != RCID)
01066 {
01067 AAS_Error("%s is not a route cache dump\n");
01068 return qfalse;
01069 }
01070 if (routecacheheader.version != RCVERSION)
01071 {
01072 AAS_Error("route cache dump has wrong version %d, should be %d", routecacheheader.version, RCVERSION);
01073 return qfalse;
01074 }
01075 if (routecacheheader.numareas != aasworld.numareas)
01076 {
01077
01078 return qfalse;
01079 }
01080 if (routecacheheader.numclusters != aasworld.numclusters)
01081 {
01082
01083 return qfalse;
01084 }
01085 if (routecacheheader.areacrc !=
01086 CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas ))
01087 {
01088
01089 return qfalse;
01090 }
01091 if (routecacheheader.clustercrc !=
01092 CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters ))
01093 {
01094
01095 return qfalse;
01096 }
01097
01098 for (i = 0; i < routecacheheader.numportalcache; i++)
01099 {
01100 cache = AAS_ReadCache(fp);
01101 cache->next = aasworld.portalcache[cache->areanum];
01102 cache->prev = NULL;
01103 if (aasworld.portalcache[cache->areanum])
01104 aasworld.portalcache[cache->areanum]->prev = cache;
01105 aasworld.portalcache[cache->areanum] = cache;
01106 }
01107
01108 for (i = 0; i < routecacheheader.numareacache; i++)
01109 {
01110 cache = AAS_ReadCache(fp);
01111 clusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum);
01112 cache->next = aasworld.clusterareacache[cache->cluster][clusterareanum];
01113 cache->prev = NULL;
01114 if (aasworld.clusterareacache[cache->cluster][clusterareanum])
01115 aasworld.clusterareacache[cache->cluster][clusterareanum]->prev = cache;
01116 aasworld.clusterareacache[cache->cluster][clusterareanum] = cache;
01117 }
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132 botimport.FS_FCloseFile(fp);
01133 return qtrue;
01134 }
01135
01136
01137
01138
01139
01140
01141 #define MAX_REACHABILITYPASSAREAS 32
01142
01143 void AAS_InitReachabilityAreas(void)
01144 {
01145 int i, j, numareas, areas[MAX_REACHABILITYPASSAREAS];
01146 int numreachareas;
01147 aas_reachability_t *reach;
01148 vec3_t start, end;
01149
01150 if (aasworld.reachabilityareas)
01151 FreeMemory(aasworld.reachabilityareas);
01152 if (aasworld.reachabilityareaindex)
01153 FreeMemory(aasworld.reachabilityareaindex);
01154
01155 aasworld.reachabilityareas = (aas_reachabilityareas_t *)
01156 GetClearedMemory(aasworld.reachabilitysize * sizeof(aas_reachabilityareas_t));
01157 aasworld.reachabilityareaindex = (int *)
01158 GetClearedMemory(aasworld.reachabilitysize * MAX_REACHABILITYPASSAREAS * sizeof(int));
01159 numreachareas = 0;
01160 for (i = 0; i < aasworld.reachabilitysize; i++)
01161 {
01162 reach = &aasworld.reachability[i];
01163 numareas = 0;
01164 switch(reach->traveltype & TRAVELTYPE_MASK)
01165 {
01166
01167 case TRAVEL_BARRIERJUMP:
01168 case TRAVEL_WATERJUMP:
01169 VectorCopy(reach->start, end);
01170 end[2] = reach->end[2];
01171 numareas = AAS_TraceAreas(reach->start, end, areas, NULL, MAX_REACHABILITYPASSAREAS);
01172 break;
01173 case TRAVEL_WALKOFFLEDGE:
01174 VectorCopy(reach->end, start);
01175 start[2] = reach->start[2];
01176 numareas = AAS_TraceAreas(start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS);
01177 break;
01178 case TRAVEL_GRAPPLEHOOK:
01179 numareas = AAS_TraceAreas(reach->start, reach->end, areas, NULL, MAX_REACHABILITYPASSAREAS);
01180 break;
01181
01182
01183 case TRAVEL_JUMP: break;
01184 case TRAVEL_ROCKETJUMP: break;
01185 case TRAVEL_BFGJUMP: break;
01186 case TRAVEL_JUMPPAD: break;
01187
01188
01189
01190 case TRAVEL_ELEVATOR: break;
01191 case TRAVEL_FUNCBOB: break;
01192
01193
01194 case TRAVEL_WALK: break;
01195 case TRAVEL_CROUCH: break;
01196 case TRAVEL_LADDER: break;
01197 case TRAVEL_SWIM: break;
01198 case TRAVEL_TELEPORT: break;
01199 default: break;
01200 }
01201 aasworld.reachabilityareas[i].firstarea = numreachareas;
01202 aasworld.reachabilityareas[i].numareas = numareas;
01203 for (j = 0; j < numareas; j++)
01204 {
01205 aasworld.reachabilityareaindex[numreachareas++] = areas[j];
01206 }
01207 }
01208 }
01209
01210
01211
01212
01213
01214
01215 void AAS_InitRouting(void)
01216 {
01217 AAS_InitTravelFlagFromType();
01218
01219 AAS_InitAreaContentsTravelFlags();
01220
01221 AAS_InitRoutingUpdate();
01222
01223 AAS_CreateReversedReachability();
01224
01225 AAS_InitClusterAreaCache();
01226
01227 AAS_InitPortalCache();
01228
01229 AAS_CalculateAreaTravelTimes();
01230
01231 AAS_InitPortalMaxTravelTimes();
01232
01233 AAS_InitReachabilityAreas();
01234
01235 #ifdef ROUTING_DEBUG
01236 numareacacheupdates = 0;
01237 numportalcacheupdates = 0;
01238 #endif //ROUTING_DEBUG
01239
01240 routingcachesize = 0;
01241 max_routingcachesize = 1024 * (int) LibVarValue("max_routingcache", "4096");
01242
01243 AAS_ReadRouteCache();
01244 }
01245
01246
01247
01248
01249
01250
01251 void AAS_FreeRoutingCaches(void)
01252 {
01253
01254 AAS_FreeAllClusterAreaCache();
01255
01256 AAS_FreeAllPortalCache();
01257
01258 if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes);
01259 aasworld.areatraveltimes = NULL;
01260
01261 if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes);
01262 aasworld.portalmaxtraveltimes = NULL;
01263
01264 if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability);
01265 aasworld.reversedreachability = NULL;
01266
01267 if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate);
01268 aasworld.areaupdate = NULL;
01269 if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate);
01270 aasworld.portalupdate = NULL;
01271
01272 if (aasworld.reachabilityareas) FreeMemory(aasworld.reachabilityareas);
01273 aasworld.reachabilityareas = NULL;
01274
01275 if (aasworld.reachabilityareaindex) FreeMemory(aasworld.reachabilityareaindex);
01276 aasworld.reachabilityareaindex = NULL;
01277
01278 if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags);
01279 aasworld.areacontentstravelflags = NULL;
01280 }
01281
01282
01283
01284
01285
01286
01287
01288 void AAS_UpdateAreaRoutingCache(aas_routingcache_t *areacache)
01289 {
01290 int i, nextareanum, cluster, badtravelflags, clusterareanum, linknum;
01291 int numreachabilityareas;
01292 unsigned short int t, startareatraveltimes[128];
01293 aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
01294 aas_reachability_t *reach;
01295 aas_reversedreachability_t *revreach;
01296 aas_reversedlink_t *revlink;
01297
01298 #ifdef ROUTING_DEBUG
01299 numareacacheupdates++;
01300 #endif //ROUTING_DEBUG
01301
01302 numreachabilityareas = aasworld.clusters[areacache->cluster].numreachabilityareas;
01303
01304 aasworld.frameroutingupdates++;
01305
01306
01307
01308 badtravelflags = ~areacache->travelflags;
01309
01310 clusterareanum = AAS_ClusterAreaNum(areacache->cluster, areacache->areanum);
01311 if (clusterareanum >= numreachabilityareas) return;
01312
01313 Com_Memset(startareatraveltimes, 0, sizeof(startareatraveltimes));
01314
01315 curupdate = &aasworld.areaupdate[clusterareanum];
01316 curupdate->areanum = areacache->areanum;
01317
01318 curupdate->areatraveltimes = startareatraveltimes;
01319 curupdate->tmptraveltime = areacache->starttraveltime;
01320
01321 areacache->traveltimes[clusterareanum] = areacache->starttraveltime;
01322
01323 curupdate->next = NULL;
01324 curupdate->prev = NULL;
01325 updateliststart = curupdate;
01326 updatelistend = curupdate;
01327
01328 while (updateliststart)
01329 {
01330 curupdate = updateliststart;
01331
01332 if (curupdate->next) curupdate->next->prev = NULL;
01333 else updatelistend = NULL;
01334 updateliststart = curupdate->next;
01335
01336 curupdate->inlist = qfalse;
01337
01338 revreach = &aasworld.reversedreachability[curupdate->areanum];
01339
01340 for (i = 0, revlink = revreach->first; revlink; revlink = revlink->next, i++)
01341 {
01342 linknum = revlink->linknum;
01343 reach = &aasworld.reachability[linknum];
01344
01345 if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue;
01346
01347 if (aasworld.areasettings[reach->areanum].areaflags & AREA_DISABLED) continue;
01348
01349 if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue;
01350
01351 nextareanum = revlink->areanum;
01352
01353 cluster = aasworld.areasettings[nextareanum].cluster;
01354
01355 if (cluster > 0 && cluster != areacache->cluster) continue;
01356
01357 clusterareanum = AAS_ClusterAreaNum(areacache->cluster, nextareanum);
01358 if (clusterareanum >= numreachabilityareas) continue;
01359
01360
01361 t = curupdate->tmptraveltime +
01362
01363 curupdate->areatraveltimes[i] +
01364 reach->traveltime;
01365
01366 if (!areacache->traveltimes[clusterareanum] ||
01367 areacache->traveltimes[clusterareanum] > t)
01368 {
01369 areacache->traveltimes[clusterareanum] = t;
01370 areacache->reachabilities[clusterareanum] = linknum - aasworld.areasettings[nextareanum].firstreachablearea;
01371 nextupdate = &aasworld.areaupdate[clusterareanum];
01372 nextupdate->areanum = nextareanum;
01373 nextupdate->tmptraveltime = t;
01374
01375 nextupdate->areatraveltimes = aasworld.areatraveltimes[nextareanum][linknum -
01376 aasworld.areasettings[nextareanum].firstreachablearea];
01377 if (!nextupdate->inlist)
01378 {
01379
01380
01381
01382 nextupdate->next = NULL;
01383 nextupdate->prev = updatelistend;
01384 if (updatelistend) updatelistend->next = nextupdate;
01385 else updateliststart = nextupdate;
01386 updatelistend = nextupdate;
01387 nextupdate->inlist = qtrue;
01388 }
01389 }
01390 }
01391 }
01392 }
01393
01394
01395
01396
01397
01398
01399 aas_routingcache_t *AAS_GetAreaRoutingCache(int clusternum, int areanum, int travelflags)
01400 {
01401 int clusterareanum;
01402 aas_routingcache_t *cache, *clustercache;
01403
01404
01405 clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
01406
01407 clustercache = aasworld.clusterareacache[clusternum][clusterareanum];
01408
01409 for (cache = clustercache; cache; cache = cache->next)
01410 {
01411
01412 if (cache->travelflags == travelflags) break;
01413 }
01414
01415 if (!cache)
01416 {
01417 cache = AAS_AllocRoutingCache(aasworld.clusters[clusternum].numreachabilityareas);
01418 cache->cluster = clusternum;
01419 cache->areanum = areanum;
01420 VectorCopy(aasworld.areas[areanum].center, cache->origin);
01421 cache->starttraveltime = 1;
01422 cache->travelflags = travelflags;
01423 cache->prev = NULL;
01424 cache->next = clustercache;
01425 if (clustercache) clustercache->prev = cache;
01426 aasworld.clusterareacache[clusternum][clusterareanum] = cache;
01427 AAS_UpdateAreaRoutingCache(cache);
01428 }
01429 else
01430 {
01431 AAS_UnlinkCache(cache);
01432 }
01433
01434 cache->time = AAS_RoutingTime();
01435 cache->type = CACHETYPE_AREA;
01436 AAS_LinkCache(cache);
01437 return cache;
01438 }
01439
01440
01441
01442
01443
01444
01445 void AAS_UpdatePortalRoutingCache(aas_routingcache_t *portalcache)
01446 {
01447 int i, portalnum, clusterareanum, clusternum;
01448 unsigned short int t;
01449 aas_portal_t *portal;
01450 aas_cluster_t *cluster;
01451 aas_routingcache_t *cache;
01452 aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
01453
01454 #ifdef ROUTING_DEBUG
01455 numportalcacheupdates++;
01456 #endif //ROUTING_DEBUG
01457
01458
01459
01460 curupdate = &aasworld.portalupdate[aasworld.numportals];
01461 curupdate->cluster = portalcache->cluster;
01462 curupdate->areanum = portalcache->areanum;
01463 curupdate->tmptraveltime = portalcache->starttraveltime;
01464
01465 clusternum = aasworld.areasettings[portalcache->areanum].cluster;
01466 if (clusternum < 0)
01467 {
01468 portalcache->traveltimes[-clusternum] = portalcache->starttraveltime;
01469 }
01470
01471 curupdate->next = NULL;
01472 curupdate->prev = NULL;
01473 updateliststart = curupdate;
01474 updatelistend = curupdate;
01475
01476 while (updateliststart)
01477 {
01478 curupdate = updateliststart;
01479
01480 if (curupdate->next) curupdate->next->prev = NULL;
01481 else updatelistend = NULL;
01482 updateliststart = curupdate->next;
01483
01484 curupdate->inlist = qfalse;
01485
01486 cluster = &aasworld.clusters[curupdate->cluster];
01487
01488 cache = AAS_GetAreaRoutingCache(curupdate->cluster,
01489 curupdate->areanum, portalcache->travelflags);
01490
01491 for (i = 0; i < cluster->numportals; i++)
01492 {
01493 portalnum = aasworld.portalindex[cluster->firstportal + i];
01494 portal = &aasworld.portals[portalnum];
01495
01496 if (portal->areanum == curupdate->areanum) continue;
01497
01498 clusterareanum = AAS_ClusterAreaNum(curupdate->cluster, portal->areanum);
01499 if (clusterareanum >= cluster->numreachabilityareas) continue;
01500
01501 t = cache->traveltimes[clusterareanum];
01502 if (!t) continue;
01503 t += curupdate->tmptraveltime;
01504
01505 if (!portalcache->traveltimes[portalnum] ||
01506 portalcache->traveltimes[portalnum] > t)
01507 {
01508 portalcache->traveltimes[portalnum] = t;
01509 nextupdate = &aasworld.portalupdate[portalnum];
01510 if (portal->frontcluster == curupdate->cluster)
01511 {
01512 nextupdate->cluster = portal->backcluster;
01513 }
01514 else
01515 {
01516 nextupdate->cluster = portal->frontcluster;
01517 }
01518 nextupdate->areanum = portal->areanum;
01519
01520 nextupdate->tmptraveltime = t + aasworld.portalmaxtraveltimes[portalnum];
01521 if (!nextupdate->inlist)
01522 {
01523
01524
01525
01526 nextupdate->next = NULL;
01527 nextupdate->prev = updatelistend;
01528 if (updatelistend) updatelistend->next = nextupdate;
01529 else updateliststart = nextupdate;
01530 updatelistend = nextupdate;
01531 nextupdate->inlist = qtrue;
01532 }
01533 }
01534 }
01535 }
01536 }
01537
01538
01539
01540
01541
01542
01543 aas_routingcache_t *AAS_GetPortalRoutingCache(int clusternum, int areanum, int travelflags)
01544 {
01545 aas_routingcache_t *cache;
01546
01547
01548 for (cache = aasworld.portalcache[areanum]; cache; cache = cache->next)
01549 {
01550 if (cache->travelflags == travelflags) break;
01551 }
01552
01553 if (!cache)
01554 {
01555 cache = AAS_AllocRoutingCache(aasworld.numportals);
01556 cache->cluster = clusternum;
01557 cache->areanum = areanum;
01558 VectorCopy(aasworld.areas[areanum].center, cache->origin);
01559 cache->starttraveltime = 1;
01560 cache->travelflags = travelflags;
01561
01562 cache->prev = NULL;
01563 cache->next = aasworld.portalcache[areanum];
01564 if (aasworld.portalcache[areanum]) aasworld.portalcache[areanum]->prev = cache;
01565 aasworld.portalcache[areanum] = cache;
01566
01567 AAS_UpdatePortalRoutingCache(cache);
01568 }
01569 else
01570 {
01571 AAS_UnlinkCache(cache);
01572 }
01573
01574 cache->time = AAS_RoutingTime();
01575 cache->type = CACHETYPE_PORTAL;
01576 AAS_LinkCache(cache);
01577 return cache;
01578 }
01579
01580
01581
01582
01583
01584
01585 int AAS_AreaRouteToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags, int *traveltime, int *reachnum)
01586 {
01587 int clusternum, goalclusternum, portalnum, i, clusterareanum, bestreachnum;
01588 unsigned short int t, besttime;
01589 aas_portal_t *portal;
01590 aas_cluster_t *cluster;
01591 aas_routingcache_t *areacache, *portalcache;
01592 aas_reachability_t *reach;
01593
01594 if (!aasworld.initialized) return qfalse;
01595
01596 if (areanum == goalareanum)
01597 {
01598 *traveltime = 1;
01599 *reachnum = 0;
01600 return qtrue;
01601 }
01602
01603 if (areanum <= 0 || areanum >= aasworld.numareas)
01604 {
01605 if (bot_developer)
01606 {
01607 botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: areanum %d out of range\n", areanum);
01608 }
01609 return qfalse;
01610 }
01611 if (goalareanum <= 0 || goalareanum >= aasworld.numareas)
01612 {
01613 if (bot_developer)
01614 {
01615 botimport.Print(PRT_ERROR, "AAS_AreaTravelTimeToGoalArea: goalareanum %d out of range\n", goalareanum);
01616 }
01617 return qfalse;
01618 }
01619
01620 while(AvailableMemory() < 1 * 1024 * 1024) {
01621 if (!AAS_FreeOldestCache()) break;
01622 }
01623
01624 if (AAS_AreaDoNotEnter(areanum) || AAS_AreaDoNotEnter(goalareanum))
01625 {
01626 travelflags |= TFL_DONOTENTER;
01627 }
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639 clusternum = aasworld.areasettings[areanum].cluster;
01640 goalclusternum = aasworld.areasettings[goalareanum].cluster;
01641
01642 if (clusternum < 0 && goalclusternum > 0)
01643 {
01644 portal = &aasworld.portals[-clusternum];
01645 if (portal->frontcluster == goalclusternum ||
01646 portal->backcluster == goalclusternum)
01647 {
01648 clusternum = goalclusternum;
01649 }
01650 }
01651
01652 else if (clusternum > 0 && goalclusternum < 0)
01653 {
01654 portal = &aasworld.portals[-goalclusternum];
01655 if (portal->frontcluster == clusternum ||
01656 portal->backcluster == clusternum)
01657 {
01658 goalclusternum = clusternum;
01659 }
01660 }
01661
01662
01663 if (clusternum > 0 && goalclusternum > 0 && clusternum == goalclusternum)
01664 {
01665
01666 areacache = AAS_GetAreaRoutingCache(clusternum, goalareanum, travelflags);
01667
01668 clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
01669
01670 cluster = &aasworld.clusters[clusternum];
01671
01672 if (clusterareanum >= cluster->numreachabilityareas) return 0;
01673
01674 if (areacache->traveltimes[clusterareanum] != 0)
01675 {
01676 *reachnum = aasworld.areasettings[areanum].firstreachablearea +
01677 areacache->reachabilities[clusterareanum];
01678 if (!origin) {
01679 *traveltime = areacache->traveltimes[clusterareanum];
01680 return qtrue;
01681 }
01682 reach = &aasworld.reachability[*reachnum];
01683 *traveltime = areacache->traveltimes[clusterareanum] +
01684 AAS_AreaTravelTime(areanum, origin, reach->start);
01685
01686 return qtrue;
01687 }
01688 }
01689
01690 clusternum = aasworld.areasettings[areanum].cluster;
01691 goalclusternum = aasworld.areasettings[goalareanum].cluster;
01692
01693 if (goalclusternum < 0)
01694 {
01695
01696 portal = &aasworld.portals[-goalclusternum];
01697 goalclusternum = portal->frontcluster;
01698 }
01699
01700 portalcache = AAS_GetPortalRoutingCache(goalclusternum, goalareanum, travelflags);
01701
01702 if (clusternum < 0)
01703 {
01704 *traveltime = portalcache->traveltimes[-clusternum];
01705 *reachnum = aasworld.areasettings[areanum].firstreachablearea +
01706 portalcache->reachabilities[-clusternum];
01707 return qtrue;
01708 }
01709
01710 besttime = 0;
01711 bestreachnum = -1;
01712
01713 cluster = &aasworld.clusters[clusternum];
01714
01715 for (i = 0; i < cluster->numportals; i++)
01716 {
01717 portalnum = aasworld.portalindex[cluster->firstportal + i];
01718
01719 if (!portalcache->traveltimes[portalnum]) continue;
01720
01721 portal = &aasworld.portals[portalnum];
01722
01723 areacache = AAS_GetAreaRoutingCache(clusternum, portal->areanum, travelflags);
01724
01725 clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
01726
01727 if (clusterareanum >= cluster->numreachabilityareas) continue;
01728
01729 if (!areacache->traveltimes[clusterareanum]) continue;
01730
01731
01732 t = portalcache->traveltimes[portalnum] + areacache->traveltimes[clusterareanum];
01733
01734
01735
01736
01737
01738 t += aasworld.portalmaxtraveltimes[portalnum];
01739
01740 if (origin)
01741 {
01742 *reachnum = aasworld.areasettings[areanum].firstreachablearea +
01743 areacache->reachabilities[clusterareanum];
01744 reach = aasworld.reachability + *reachnum;
01745 t += AAS_AreaTravelTime(areanum, origin, reach->start);
01746 }
01747
01748 if (!besttime || t < besttime)
01749 {
01750 bestreachnum = *reachnum;
01751 besttime = t;
01752 }
01753 }
01754 if (bestreachnum < 0) {
01755 return qfalse;
01756 }
01757 *reachnum = bestreachnum;
01758 *traveltime = besttime;
01759 return qtrue;
01760 }
01761
01762
01763
01764
01765
01766
01767 int AAS_AreaTravelTimeToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags)
01768 {
01769 int traveltime, reachnum;
01770
01771 if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum))
01772 {
01773 return traveltime;
01774 }
01775 return 0;
01776 }
01777
01778
01779
01780
01781
01782
01783 int AAS_AreaReachabilityToGoalArea(int areanum, vec3_t origin, int goalareanum, int travelflags)
01784 {
01785 int traveltime, reachnum;
01786
01787 if (AAS_AreaRouteToGoalArea(areanum, origin, goalareanum, travelflags, &traveltime, &reachnum))
01788 {
01789 return reachnum;
01790 }
01791 return 0;
01792 }
01793
01794
01795
01796
01797
01798
01799
01800 int AAS_PredictRoute(struct aas_predictroute_s *route, int areanum, vec3_t origin,
01801 int goalareanum, int travelflags, int maxareas, int maxtime,
01802 int stopevent, int stopcontents, int stoptfl, int stopareanum)
01803 {
01804 int curareanum, reachnum, i, j, testareanum;
01805 vec3_t curorigin;
01806 aas_reachability_t *reach;
01807 aas_reachabilityareas_t *reachareas;
01808
01809
01810 route->stopevent = RSE_NONE;
01811 route->endarea = goalareanum;
01812 route->endcontents = 0;
01813 route->endtravelflags = 0;
01814 VectorCopy(origin, route->endpos);
01815 route->time = 0;
01816
01817 curareanum = areanum;
01818 VectorCopy(origin, curorigin);
01819
01820 for (i = 0; curareanum != goalareanum && (!maxareas || i < maxareas) && i < aasworld.numareas; i++)
01821 {
01822 reachnum = AAS_AreaReachabilityToGoalArea(curareanum, curorigin, goalareanum, travelflags);
01823 if (!reachnum)
01824 {
01825 route->stopevent = RSE_NOROUTE;
01826 return qfalse;
01827 }
01828 reach = &aasworld.reachability[reachnum];
01829
01830 if (stopevent & RSE_USETRAVELTYPE)
01831 {
01832 if (AAS_TravelFlagForType_inline(reach->traveltype) & stoptfl)
01833 {
01834 route->stopevent = RSE_USETRAVELTYPE;
01835 route->endarea = curareanum;
01836 route->endcontents = aasworld.areasettings[curareanum].contents;
01837 route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype);
01838 VectorCopy(reach->start, route->endpos);
01839 return qtrue;
01840 }
01841 if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & stoptfl)
01842 {
01843 route->stopevent = RSE_USETRAVELTYPE;
01844 route->endarea = reach->areanum;
01845 route->endcontents = aasworld.areasettings[reach->areanum].contents;
01846 route->endtravelflags = AAS_AreaContentsTravelFlags_inline(reach->areanum);
01847 VectorCopy(reach->end, route->endpos);
01848 route->time += AAS_AreaTravelTime(areanum, origin, reach->start);
01849 route->time += reach->traveltime;
01850 return qtrue;
01851 }
01852 }
01853 reachareas = &aasworld.reachabilityareas[reachnum];
01854 for (j = 0; j < reachareas->numareas + 1; j++)
01855 {
01856 if (j >= reachareas->numareas)
01857 testareanum = reach->areanum;
01858 else
01859 testareanum = aasworld.reachabilityareaindex[reachareas->firstarea + j];
01860 if (stopevent & RSE_ENTERCONTENTS)
01861 {
01862 if (aasworld.areasettings[testareanum].contents & stopcontents)
01863 {
01864 route->stopevent = RSE_ENTERCONTENTS;
01865 route->endarea = testareanum;
01866 route->endcontents = aasworld.areasettings[testareanum].contents;
01867 VectorCopy(reach->end, route->endpos);
01868 route->time += AAS_AreaTravelTime(areanum, origin, reach->start);
01869 route->time += reach->traveltime;
01870 return qtrue;
01871 }
01872 }
01873 if (stopevent & RSE_ENTERAREA)
01874 {
01875 if (testareanum == stopareanum)
01876 {
01877 route->stopevent = RSE_ENTERAREA;
01878 route->endarea = testareanum;
01879 route->endcontents = aasworld.areasettings[testareanum].contents;
01880 VectorCopy(reach->start, route->endpos);
01881 return qtrue;
01882 }
01883 }
01884 }
01885
01886 route->time += AAS_AreaTravelTime(areanum, origin, reach->start);
01887 route->time += reach->traveltime;
01888 route->endarea = reach->areanum;
01889 route->endcontents = aasworld.areasettings[reach->areanum].contents;
01890 route->endtravelflags = AAS_TravelFlagForType_inline(reach->traveltype);
01891 VectorCopy(reach->end, route->endpos);
01892
01893 curareanum = reach->areanum;
01894 VectorCopy(reach->end, curorigin);
01895
01896 if (maxtime && route->time > maxtime)
01897 break;
01898 }
01899 if (curareanum != goalareanum)
01900 return qfalse;
01901 return qtrue;
01902 }
01903
01904
01905
01906
01907
01908
01909 int AAS_BridgeWalkable(int areanum)
01910 {
01911 return qfalse;
01912 }
01913
01914
01915
01916
01917
01918
01919 void AAS_ReachabilityFromNum(int num, struct aas_reachability_s *reach)
01920 {
01921 if (!aasworld.initialized)
01922 {
01923 Com_Memset(reach, 0, sizeof(aas_reachability_t));
01924 return;
01925 }
01926 if (num < 0 || num >= aasworld.reachabilitysize)
01927 {
01928 Com_Memset(reach, 0, sizeof(aas_reachability_t));
01929 return;
01930 }
01931 Com_Memcpy(reach, &aasworld.reachability[num], sizeof(aas_reachability_t));;
01932 }
01933
01934
01935
01936
01937
01938
01939 int AAS_NextAreaReachability(int areanum, int reachnum)
01940 {
01941 aas_areasettings_t *settings;
01942
01943 if (!aasworld.initialized) return 0;
01944
01945 if (areanum <= 0 || areanum >= aasworld.numareas)
01946 {
01947 botimport.Print(PRT_ERROR, "AAS_NextAreaReachability: areanum %d out of range\n", areanum);
01948 return 0;
01949 }
01950
01951 settings = &aasworld.areasettings[areanum];
01952 if (!reachnum)
01953 {
01954 return settings->firstreachablearea;
01955 }
01956 if (reachnum < settings->firstreachablearea)
01957 {
01958 botimport.Print(PRT_FATAL, "AAS_NextAreaReachability: reachnum < settings->firstreachableara");
01959 return 0;
01960 }
01961 reachnum++;
01962 if (reachnum >= settings->firstreachablearea + settings->numreachableareas)
01963 {
01964 return 0;
01965 }
01966 return reachnum;
01967 }
01968
01969
01970
01971
01972
01973
01974 int AAS_NextModelReachability(int num, int modelnum)
01975 {
01976 int i;
01977
01978 if (num <= 0) num = 1;
01979 else if (num >= aasworld.reachabilitysize) return 0;
01980 else num++;
01981
01982 for (i = num; i < aasworld.reachabilitysize; i++)
01983 {
01984 if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_ELEVATOR)
01985 {
01986 if (aasworld.reachability[i].facenum == modelnum) return i;
01987 }
01988 else if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)
01989 {
01990 if ((aasworld.reachability[i].facenum & 0x0000FFFF) == modelnum) return i;
01991 }
01992 }
01993 return 0;
01994 }
01995
01996
01997
01998
01999
02000
02001 int AAS_RandomGoalArea(int areanum, int travelflags, int *goalareanum, vec3_t goalorigin)
02002 {
02003 int i, n, t;
02004 vec3_t start, end;
02005 aas_trace_t trace;
02006
02007
02008 if (!AAS_AreaReachability(areanum)) return qfalse;
02009
02010 n = aasworld.numareas * random();
02011 for (i = 0; i < aasworld.numareas; i++)
02012 {
02013 if (n <= 0) n = 1;
02014 if (n >= aasworld.numareas) n = 1;
02015 if (AAS_AreaReachability(n))
02016 {
02017 t = AAS_AreaTravelTimeToGoalArea(areanum, aasworld.areas[areanum].center, n, travelflags);
02018
02019 if (t > 0)
02020 {
02021 if (AAS_AreaSwim(n))
02022 {
02023 *goalareanum = n;
02024 VectorCopy(aasworld.areas[n].center, goalorigin);
02025
02026 return qtrue;
02027 }
02028 VectorCopy(aasworld.areas[n].center, start);
02029 if (!AAS_PointAreaNum(start))
02030 Log_Write("area %d center %f %f %f in solid?", n, start[0], start[1], start[2]);
02031 VectorCopy(start, end);
02032 end[2] -= 300;
02033 trace = AAS_TraceClientBBox(start, end, PRESENCE_CROUCH, -1);
02034 if (!trace.startsolid && trace.fraction < 1 && AAS_PointAreaNum(trace.endpos) == n)
02035 {
02036 if (AAS_AreaGroundFaceArea(n) > 300)
02037 {
02038 *goalareanum = n;
02039 VectorCopy(trace.endpos, goalorigin);
02040
02041 return qtrue;
02042 }
02043 }
02044 }
02045 }
02046 n++;
02047 }
02048 return qfalse;
02049 }
02050
02051
02052
02053
02054
02055
02056 int AAS_AreaVisible(int srcarea, int destarea)
02057 {
02058 return qfalse;
02059 }
02060
02061
02062
02063
02064
02065
02066 float DistancePointToLine(vec3_t v1, vec3_t v2, vec3_t point)
02067 {
02068 vec3_t vec, p2;
02069
02070 AAS_ProjectPointOntoVector(point, v1, v2, p2);
02071 VectorSubtract(point, p2, vec);
02072 return VectorLength(vec);
02073 }
02074
02075
02076
02077
02078
02079
02080 int AAS_NearestHideArea(int srcnum, vec3_t origin, int areanum, int enemynum, vec3_t enemyorigin, int enemyareanum, int travelflags)
02081 {
02082 int i, j, nextareanum, badtravelflags, numreach, bestarea;
02083 unsigned short int t, besttraveltime;
02084 static unsigned short int *hidetraveltimes;
02085 aas_routingupdate_t *updateliststart, *updatelistend, *curupdate, *nextupdate;
02086 aas_reachability_t *reach;
02087 float dist1, dist2;
02088 vec3_t v1, v2, p;
02089 qboolean startVisible;
02090
02091
02092 if (!hidetraveltimes)
02093 {
02094 hidetraveltimes = (unsigned short int *) GetClearedMemory(aasworld.numareas * sizeof(unsigned short int));
02095 }
02096 else
02097 {
02098 Com_Memset(hidetraveltimes, 0, aasworld.numareas * sizeof(unsigned short int));
02099 }
02100 besttraveltime = 0;
02101 bestarea = 0;
02102
02103 startVisible = qtrue;
02104
02105 badtravelflags = ~travelflags;
02106
02107 curupdate = &aasworld.areaupdate[areanum];
02108 curupdate->areanum = areanum;
02109 VectorCopy(origin, curupdate->start);
02110 curupdate->areatraveltimes = aasworld.areatraveltimes[areanum][0];
02111 curupdate->tmptraveltime = 0;
02112
02113 curupdate->next = NULL;
02114 curupdate->prev = NULL;
02115 updateliststart = curupdate;
02116 updatelistend = curupdate;
02117
02118 while (updateliststart)
02119 {
02120 curupdate = updateliststart;
02121
02122 if (curupdate->next) curupdate->next->prev = NULL;
02123 else updatelistend = NULL;
02124 updateliststart = curupdate->next;
02125
02126 curupdate->inlist = qfalse;
02127
02128 numreach = aasworld.areasettings[curupdate->areanum].numreachableareas;
02129 reach = &aasworld.reachability[aasworld.areasettings[curupdate->areanum].firstreachablearea];
02130
02131 for (i = 0; i < numreach; i++, reach++)
02132 {
02133
02134 if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue;
02135
02136 if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue;
02137
02138 nextareanum = reach->areanum;
02139
02140 if (nextareanum == enemyareanum) continue;
02141
02142
02143 t = curupdate->tmptraveltime +
02144 AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->start) +
02145 reach->traveltime;
02146
02147
02148 AAS_ProjectPointOntoVector(enemyorigin, curupdate->start, reach->end, p);
02149 for (j = 0; j < 3; j++)
02150 if ((p[j] > curupdate->start[j] && p[j] > reach->end[j]) ||
02151 (p[j] < curupdate->start[j] && p[j] < reach->end[j]))
02152 break;
02153 if (j < 3)
02154 {
02155 VectorSubtract(enemyorigin, reach->end, v2);
02156 }
02157 else
02158 {
02159 VectorSubtract(enemyorigin, p, v2);
02160 }
02161 dist2 = VectorLength(v2);
02162
02163 if (dist2 < 40) continue;
02164
02165 VectorSubtract(enemyorigin, curupdate->start, v1);
02166 dist1 = VectorLength(v1);
02167
02168 if (dist2 < dist1)
02169 {
02170 t += (dist1 - dist2) * 10;
02171 }
02172
02173 if (!startVisible && AAS_AreaVisible(enemyareanum, nextareanum)) {
02174 continue;
02175 }
02176
02177 if (besttraveltime && t >= besttraveltime) continue;
02178
02179 if (!hidetraveltimes[nextareanum] ||
02180 hidetraveltimes[nextareanum] > t)
02181 {
02182
02183 if (!AAS_AreaVisible(enemyareanum, nextareanum))
02184 {
02185 besttraveltime = t;
02186 bestarea = nextareanum;
02187 }
02188 hidetraveltimes[nextareanum] = t;
02189 nextupdate = &aasworld.areaupdate[nextareanum];
02190 nextupdate->areanum = nextareanum;
02191 nextupdate->tmptraveltime = t;
02192
02193 VectorCopy(reach->end, nextupdate->start);
02194
02195 if (!nextupdate->inlist)
02196 {
02197
02198 nextupdate->next = NULL;
02199 nextupdate->prev = updatelistend;
02200 if (updatelistend) updatelistend->next = nextupdate;
02201 else updateliststart = nextupdate;
02202 updatelistend = nextupdate;
02203 nextupdate->inlist = qtrue;
02204 }
02205 }
02206 }
02207 }
02208 return bestarea;
02209 }