Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

be_aas_route.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 /*****************************************************************************
00024  * name:        be_aas_route.c
00025  *
00026  * desc:        AAS
00027  *
00028  * $Archive: /MissionPack/code/botlib/be_aas_route.c $
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 //travel time in hundreths of a second = distance * 100 / speed
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 //cache refresh time
00056 #define CACHE_REFRESHTIME       15.0f   //15 seconds refresh time
00057 
00058 //maximum number of routing updates each frame
00059 #define MAX_FRAMEROUTINGUPDATES     10
00060 
00061 
00062 /*
00063 
00064   area routing cache:
00065   stores the distances within one cluster to a specific goal area
00066   this goal area is in this same cluster and could be a cluster portal
00067   for every cluster there's a list with routing cache for every area
00068   in that cluster (including the portals of that cluster)
00069   area cache stores aasworld.clusters[?].numreachabilityareas travel times
00070 
00071   portal routing cache:
00072   stores the distances of all portals to a specific goal area
00073   this goal area could be in any cluster and could also be a cluster portal
00074   for every area (aasworld.numareas) the portal cache stores
00075   aasworld.numportals travel times
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 // Parameter:           -
00090 // Returns:             -
00091 // Changes Globals:     -
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 } //end of the function AAS_RoutingInfo
00100 #endif //ROUTING_DEBUG
00101 //===========================================================================
00102 // returns the number of the area in the cluster
00103 // assumes the given area is in the given cluster or a portal of the cluster
00104 //
00105 // Parameter:           -
00106 // Returns:             -
00107 // Changes Globals:     -
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 /*#ifdef ROUTING_DEBUG
00118         if (aasworld.portals[-areacluster].frontcluster != cluster &&
00119                 aasworld.portals[-areacluster].backcluster != cluster)
00120         {
00121             botimport.Print(PRT_ERROR, "portal %d: does not belong to cluster %d\n"
00122                                             , -areacluster, cluster);
00123         } //end if
00124 #endif //ROUTING_DEBUG*/
00125         side = aasworld.portals[-areacluster].frontcluster != cluster;
00126         return aasworld.portals[-areacluster].clusterareanum[side];
00127     } //end else
00128 } //end of the function AAS_ClusterAreaNum
00129 //===========================================================================
00130 //
00131 // Parameter:           -
00132 // Returns:             -
00133 // Changes Globals:     -
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     } //end for
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 } //end of the function AAS_InitTravelFlagFromType
00163 //===========================================================================
00164 //
00165 // Parameter:           -
00166 // Returns:             -
00167 // Changes Globals:     -
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 } //end of the function AAS_TravelFlagForType_inline
00184 //===========================================================================
00185 //
00186 // Parameter:           -
00187 // Returns:             -
00188 // Changes Globals:     -
00189 //===========================================================================
00190 int AAS_TravelFlagForType(int traveltype)
00191 {
00192     return AAS_TravelFlagForType_inline(traveltype);
00193 } //end of the function AAS_TravelFlagForType_inline
00194 //===========================================================================
00195 //
00196 // Parameter:           -
00197 // Returns:             -
00198 // Changes Globals:     -
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 } //end of the function AAS_UnlinkCache
00209 //===========================================================================
00210 //
00211 // Parameter:           -
00212 // Returns:             -
00213 // Changes Globals:     -
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     } //end if
00222     else
00223     {
00224         aasworld.oldestcache = cache;
00225         cache->time_prev = NULL;
00226     } //end else
00227     cache->time_next = NULL;
00228     aasworld.newestcache = cache;
00229 } //end of the function AAS_LinkCache
00230 //===========================================================================
00231 //
00232 // Parameter:           -
00233 // Returns:             -
00234 // Changes Globals:     -
00235 //===========================================================================
00236 void AAS_FreeRoutingCache(aas_routingcache_t *cache)
00237 {
00238     AAS_UnlinkCache(cache);
00239     routingcachesize -= cache->size;
00240     FreeMemory(cache);
00241 } //end of the function AAS_FreeRoutingCache
00242 //===========================================================================
00243 //
00244 // Parameter:           -
00245 // Returns:             -
00246 // Changes Globals:     -
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         } //end for
00264         aasworld.clusterareacache[clusternum][i] = NULL;
00265     } //end for
00266 } //end of the function AAS_RemoveRoutingCacheInCluster
00267 //===========================================================================
00268 //
00269 // Parameter:           -
00270 // Returns:             -
00271 // Changes Globals:     -
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         //remove all the cache in the cluster the area is in
00282         AAS_RemoveRoutingCacheInCluster( clusternum );
00283     } //end if
00284     else
00285     {
00286         // if this is a portal remove all cache in both the front and back cluster
00287         AAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].frontcluster );
00288         AAS_RemoveRoutingCacheInCluster( aasworld.portals[-clusternum].backcluster );
00289     } //end else
00290     // remove all portal cache
00291     for (i = 0; i < aasworld.numareas; i++)
00292     {
00293         //refresh portal cache
00294         for (cache = aasworld.portalcache[i]; cache; cache = nextcache)
00295         {
00296             nextcache = cache->next;
00297             AAS_FreeRoutingCache(cache);
00298         } //end for
00299         aasworld.portalcache[i] = NULL;
00300     } //end for
00301 } //end of the function AAS_RemoveRoutingCacheUsingArea
00302 //===========================================================================
00303 //
00304 // Parameter:           -
00305 // Returns:             -
00306 // Changes Globals:     -
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         } //end if
00318         return 0;
00319     } //end if
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     // if the status of the area changed
00329     if ( (flags & AREA_DISABLED) != (aasworld.areasettings[areanum].areaflags & AREA_DISABLED) )
00330     {
00331         //remove all routing cache involving this area
00332         AAS_RemoveRoutingCacheUsingArea( areanum );
00333     } //end if
00334     return !flags;
00335 } //end of the function AAS_EnableRoutingArea
00336 //===========================================================================
00337 //
00338 // Parameter:           -
00339 // Returns:             -
00340 // Changes Globals:     -
00341 //===========================================================================
00342 __inline float AAS_RoutingTime(void)
00343 {
00344     return AAS_Time();
00345 } //end of the function AAS_RoutingTime
00346 //===========================================================================
00347 //
00348 // Parameter:               -
00349 // Returns:                 -
00350 // Changes Globals:     -
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 } //end of the function AAS_GetAreaContentsTravelFlags
00376 //===========================================================================
00377 //
00378 // Parameter:           -
00379 // Returns:             -
00380 // Changes Globals:     -
00381 //===========================================================================
00382 __inline int AAS_AreaContentsTravelFlags_inline(int areanum)
00383 {
00384     return aasworld.areacontentstravelflags[areanum];
00385 } //end of the function AAS_AreaContentsTravelFlags
00386 //===========================================================================
00387 //
00388 // Parameter:           -
00389 // Returns:             -
00390 // Changes Globals:     -
00391 //===========================================================================
00392 int AAS_AreaContentsTravelFlags(int areanum)
00393 {
00394     return aasworld.areacontentstravelflags[areanum];
00395 } //end of the function AAS_AreaContentsTravelFlags
00396 //===========================================================================
00397 //
00398 // Parameter:           -
00399 // Returns:             -
00400 // Changes Globals:     -
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 } //end of the function AAS_InitAreaContentsTravelFlags
00413 //===========================================================================
00414 //
00415 // Parameter:           -
00416 // Returns:             -
00417 // Changes Globals:     -
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     //free reversed links that have already been created
00432     if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability);
00433     //allocate memory for the reversed reachability links
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     //pointer to the memory for the reversed links
00439     ptr += aasworld.numareas * sizeof(aas_reversedreachability_t);
00440     //check all reachabilities of all areas
00441     for (i = 1; i < aasworld.numareas; i++)
00442     {
00443         //settings of the area
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         //create reversed links for the reachabilities
00449         for (n = 0; n < settings->numreachableareas && n < 128; n++)
00450         {
00451             //reachability link
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         } //end for
00463     } //end for
00464 #ifdef DEBUG
00465     botimport.Print(PRT_MESSAGE, "reversed reachability %d msec\n", Sys_MilliSeconds() - starttime);
00466 #endif
00467 } //end of the function AAS_CreateReversedReachability
00468 //===========================================================================
00469 //
00470 // Parameter:           -
00471 // Returns:             -
00472 // Changes Globals:     -
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     //if crouch only area
00483     if (AAS_AreaCrouch(areanum)) dist *= DISTANCEFACTOR_CROUCH;
00484     //if swim area
00485     else if (AAS_AreaSwim(areanum)) dist *= DISTANCEFACTOR_SWIM;
00486     //normal walk area
00487     else dist *= DISTANCEFACTOR_WALK;
00488     //
00489     intdist = (int) dist;
00490     //make sure the distance isn't zero
00491     if (intdist <= 0) intdist = 1;
00492     return intdist;
00493 } //end of the function AAS_AreaTravelTime
00494 //===========================================================================
00495 //
00496 // Parameter:           -
00497 // Returns:             -
00498 // Changes Globals:     -
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     //if there are still area travel times, free the memory
00513     if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes);
00514     //get the total size of all the area travel times
00515     size = aasworld.numareas * sizeof(unsigned short **);
00516     for (i = 0; i < aasworld.numareas; i++)
00517     {
00518         revreach = &aasworld.reversedreachability[i];
00519         //settings of the area
00520         settings = &aasworld.areasettings[i];
00521         //
00522         size += settings->numreachableareas * sizeof(unsigned short *);
00523         //
00524         size += settings->numreachableareas * revreach->numlinks * sizeof(unsigned short);
00525     } //end for
00526     //allocate memory for the area travel times
00527     ptr = (char *) GetClearedMemory(size);
00528     aasworld.areatraveltimes = (unsigned short ***) ptr;
00529     ptr += aasworld.numareas * sizeof(unsigned short **);
00530     //calcluate the travel times for all the areas
00531     for (i = 0; i < aasworld.numareas; i++)
00532     {
00533         //reversed reachabilities of this area
00534         revreach = &aasworld.reversedreachability[i];
00535         //settings of the area
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             //reachability link
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             } //end for
00554         } //end for
00555     } //end for
00556 #ifdef DEBUG
00557     botimport.Print(PRT_MESSAGE, "area travel times %d msec\n", Sys_MilliSeconds() - starttime);
00558 #endif
00559 } //end of the function AAS_CalculateAreaTravelTimes
00560 //===========================================================================
00561 //
00562 // Parameter:           -
00563 // Returns:             -
00564 // Changes Globals:     -
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     //reversed reachabilities of this portal area
00576     revreach = &aasworld.reversedreachability[portal->areanum];
00577     //settings of the portal area
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             } //end if
00590         } //end for
00591     } //end for
00592     return maxt;
00593 } //end of the function AAS_PortalMaxTravelTime
00594 //===========================================================================
00595 //
00596 // Parameter:           -
00597 // Returns:             -
00598 // Changes Globals:     -
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         //botimport.Print(PRT_MESSAGE, "portal %d max tt = %d\n", i, aasworld.portalmaxtraveltimes[i]);
00612     } //end for
00613 } //end of the function AAS_InitPortalMaxTravelTimes
00614 //===========================================================================
00615 //
00616 // Parameter:           -
00617 // Returns:             -
00618 // Changes Globals:     -
00619 //===========================================================================
00620 /*
00621 int AAS_FreeOldestCache(void)
00622 {
00623     int i, j, bestcluster, bestarea, freed;
00624     float besttime;
00625     aas_routingcache_t *cache, *bestcache;
00626 
00627     freed = qfalse;
00628     besttime = 999999999;
00629     bestcache = NULL;
00630     bestcluster = 0;
00631     bestarea = 0;
00632     //refresh cluster cache
00633     for (i = 0; i < aasworld.numclusters; i++)
00634     {
00635         for (j = 0; j < aasworld.clusters[i].numareas; j++)
00636         {
00637             for (cache = aasworld.clusterareacache[i][j]; cache; cache = cache->next)
00638             {
00639                 //never remove cache leading towards a portal
00640                 if (aasworld.areasettings[cache->areanum].cluster < 0) continue;
00641                 //if this cache is older than the cache we found so far
00642                 if (cache->time < besttime)
00643                 {
00644                     bestcache = cache;
00645                     bestcluster = i;
00646                     bestarea = j;
00647                     besttime = cache->time;
00648                 } //end if
00649             } //end for
00650         } //end for
00651     } //end for
00652     if (bestcache)
00653     {
00654         cache = bestcache;
00655         if (cache->prev) cache->prev->next = cache->next;
00656         else aasworld.clusterareacache[bestcluster][bestarea] = cache->next;
00657         if (cache->next) cache->next->prev = cache->prev;
00658         AAS_FreeRoutingCache(cache);
00659         freed = qtrue;
00660     } //end if
00661     besttime = 999999999;
00662     bestcache = NULL;
00663     bestarea = 0;
00664     for (i = 0; i < aasworld.numareas; i++)
00665     {
00666         //refresh portal cache
00667         for (cache = aasworld.portalcache[i]; cache; cache = cache->next)
00668         {
00669             if (cache->time < besttime)
00670             {
00671                 bestcache = cache;
00672                 bestarea = i;
00673                 besttime = cache->time;
00674             } //end if
00675         } //end for
00676     } //end for
00677     if (bestcache)
00678     {
00679         cache = bestcache;
00680         if (cache->prev) cache->prev->next = cache->next;
00681         else aasworld.portalcache[bestarea] = cache->next;
00682         if (cache->next) cache->next->prev = cache->prev;
00683         AAS_FreeRoutingCache(cache);
00684         freed = qtrue;
00685     } //end if
00686     return freed;
00687 } //end of the function AAS_FreeOldestCache
00688 */
00689 //===========================================================================
00690 //
00691 // Parameter:           -
00692 // Returns:             -
00693 // Changes Globals:     -
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         // never free area cache leading towards a portal
00702         if (cache->type == CACHETYPE_AREA && aasworld.areasettings[cache->areanum].cluster < 0) {
00703             continue;
00704         }
00705         break;
00706     }
00707     if (cache) {
00708         // unlink the cache
00709         if (cache->type == CACHETYPE_AREA) {
00710             //number of the area in the cluster
00711             clusterareanum = AAS_ClusterAreaNum(cache->cluster, cache->areanum);
00712             // unlink from cluster area cache
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             // unlink from portal cache
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 } //end of the function AAS_FreeOldestCache
00728 //===========================================================================
00729 //
00730 // Parameter:           -
00731 // Returns:             -
00732 // Changes Globals:     -
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 } //end of the function AAS_AllocRoutingCache
00752 //===========================================================================
00753 //
00754 // Parameter:           -
00755 // Returns:             -
00756 // Changes Globals:     -
00757 //===========================================================================
00758 void AAS_FreeAllClusterAreaCache(void)
00759 {
00760     int i, j;
00761     aas_routingcache_t *cache, *nextcache;
00762     aas_cluster_t *cluster;
00763 
00764     //free all cluster cache if existing
00765     if (!aasworld.clusterareacache) return;
00766     //free caches
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             } //end for
00777             aasworld.clusterareacache[i][j] = NULL;
00778         } //end for
00779     } //end for
00780     //free the cluster cache array
00781     FreeMemory(aasworld.clusterareacache);
00782     aasworld.clusterareacache = NULL;
00783 } //end of the function AAS_FreeAllClusterAreaCache
00784 //===========================================================================
00785 //
00786 // Parameter:           -
00787 // Returns:             -
00788 // Changes Globals:     -
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     } //end for
00800     //two dimensional array with pointers for every cluster to routing cache
00801     //for every area in that cluster
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     } //end for
00812 } //end of the function AAS_InitClusterAreaCache
00813 //===========================================================================
00814 //
00815 // Parameter:           -
00816 // Returns:             -
00817 // Changes Globals:     -
00818 //===========================================================================
00819 void AAS_FreeAllPortalCache(void)
00820 {
00821     int i;
00822     aas_routingcache_t *cache, *nextcache;
00823 
00824     //free all portal cache if existing
00825     if (!aasworld.portalcache) return;
00826     //free portal caches
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         } //end for
00834         aasworld.portalcache[i] = NULL;
00835     } //end for
00836     FreeMemory(aasworld.portalcache);
00837     aasworld.portalcache = NULL;
00838 } //end of the function AAS_FreeAllPortalCache
00839 //===========================================================================
00840 //
00841 // Parameter:               -
00842 // Returns:                 -
00843 // Changes Globals:     -
00844 //===========================================================================
00845 void AAS_InitPortalCache(void)
00846 {
00847     //
00848     aasworld.portalcache = (aas_routingcache_t **) GetClearedMemory(
00849                                 aasworld.numareas * sizeof(aas_routingcache_t *));
00850 } //end of the function AAS_InitPortalCache
00851 //===========================================================================
00852 //
00853 // Parameter:               -
00854 // Returns:                 -
00855 // Changes Globals:     -
00856 //===========================================================================
00857 void AAS_InitRoutingUpdate(void)
00858 {
00859     int i, maxreachabilityareas;
00860 
00861     //free routing update fields if already existing
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         } //end if
00871     } //end for
00872     //allocate memory for the routing update fields
00873     aasworld.areaupdate = (aas_routingupdate_t *) GetClearedMemory(
00874                                     maxreachabilityareas * sizeof(aas_routingupdate_t));
00875     //
00876     if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate);
00877     //allocate memory for the portal update fields
00878     aasworld.portalupdate = (aas_routingupdate_t *) GetClearedMemory(
00879                                     (aasworld.numportals+1) * sizeof(aas_routingupdate_t));
00880 } //end of the function AAS_InitRoutingUpdate
00881 //===========================================================================
00882 //
00883 // Parameter:           -
00884 // Returns:             -
00885 // Changes Globals:     -
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             //Log_Write("traveltime from %d to %d is %d", i, j, t);
00902         } //end for
00903     } //end for
00904     aasworld.initialized = qfalse;
00905 } //end of the function AAS_CreateAllRoutingCache
00906 //===========================================================================
00907 //
00908 // Parameter:           -
00909 // Returns:             -
00910 // Changes Globals:     -
00911 //===========================================================================
00912 
00913 //the route cache header
00914 //this header is followed by numportalcache + numareacache aas_routingcache_t
00915 //structures that store routing cache
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 //void AAS_DecompressVis(byte *in, int numareas, byte *decompressed);
00932 //int AAS_CompressVis(byte *vis, int numareas, byte *dest);
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         } //end for
00950     } //end for
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             } //end for
00961         } //end for
00962     } //end for
00963     // open the file for writing
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     } //end if
00971     //create the header
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     //write the header
00981     botimport.FS_Write(&routecacheheader, sizeof(routecacheheader_t), fp);
00982     //
00983     totalsize = 0;
00984     //write all the cache
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         } //end for
00992     } //end for
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             } //end for
01003         } //end for
01004     } //end for
01005     // write the visareas
01006     /*
01007     for (i = 0; i < aasworld.numareas; i++)
01008     {
01009         if (!aasworld.areavisibility[i]) {
01010             size = 0;
01011             botimport.FS_Write(&size, sizeof(int), fp);
01012             continue;
01013         }
01014         AAS_DecompressVis( aasworld.areavisibility[i], aasworld.numareas, aasworld.decompressedvis );
01015         size = AAS_CompressVis( aasworld.decompressedvis, aasworld.numareas, aasworld.decompressedvis );
01016         botimport.FS_Write(&size, sizeof(int), fp);
01017         botimport.FS_Write(aasworld.decompressedvis, size, fp);
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 } //end of the function AAS_WriteRouteCache
01025 //===========================================================================
01026 //
01027 // Parameter:           -
01028 // Returns:             -
01029 // Changes Globals:     -
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 } //end of the function AAS_ReadCache
01044 //===========================================================================
01045 //
01046 // Parameter:           -
01047 // Returns:             -
01048 // Changes Globals:     -
01049 //===========================================================================
01050 int AAS_ReadRouteCache(void)
01051 {
01052     int i, clusterareanum;//, size;
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     } //end if
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     } //end if
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     } //end if
01075     if (routecacheheader.numareas != aasworld.numareas)
01076     {
01077         //AAS_Error("route cache dump has wrong number of areas\n");
01078         return qfalse;
01079     } //end if
01080     if (routecacheheader.numclusters != aasworld.numclusters)
01081     {
01082         //AAS_Error("route cache dump has wrong number of clusters\n");
01083         return qfalse;
01084     } //end if
01085     if (routecacheheader.areacrc !=
01086         CRC_ProcessString( (unsigned char *)aasworld.areas, sizeof(aas_area_t) * aasworld.numareas ))
01087     {
01088         //AAS_Error("route cache dump area CRC incorrect\n");
01089         return qfalse;
01090     } //end if
01091     if (routecacheheader.clustercrc !=
01092         CRC_ProcessString( (unsigned char *)aasworld.clusters, sizeof(aas_cluster_t) * aasworld.numclusters ))
01093     {
01094         //AAS_Error("route cache dump cluster CRC incorrect\n");
01095         return qfalse;
01096     } //end if
01097     //read all the portal cache
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     } //end for
01107     //read all the cluster area cache
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     } //end for
01118     // read the visareas
01119     /*
01120     aasworld.areavisibility = (byte **) GetClearedMemory(aasworld.numareas * sizeof(byte *));
01121     aasworld.decompressedvis = (byte *) GetClearedMemory(aasworld.numareas * sizeof(byte));
01122     for (i = 0; i < aasworld.numareas; i++)
01123     {
01124         botimport.FS_Read(&size, sizeof(size), fp );
01125         if (size) {
01126             aasworld.areavisibility[i] = (byte *) GetMemory(size);
01127             botimport.FS_Read(aasworld.areavisibility[i], size, fp );
01128         }
01129     }
01130     */
01131     //
01132     botimport.FS_FCloseFile(fp);
01133     return qtrue;
01134 } //end of the function AAS_ReadRouteCache
01135 //===========================================================================
01136 //
01137 // Parameter:           -
01138 // Returns:             -
01139 // Changes Globals:     -
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             //trace areas from start to end
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             //trace arch
01183             case TRAVEL_JUMP: break;
01184             case TRAVEL_ROCKETJUMP: break;
01185             case TRAVEL_BFGJUMP: break;
01186             case TRAVEL_JUMPPAD: break;
01187 
01188             //trace from reach->start to entity center, along entity movement
01189             //and from entity center to reach->end
01190             case TRAVEL_ELEVATOR: break;
01191             case TRAVEL_FUNCBOB: break;
01192 
01193             //no areas in between
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         } //end switch
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         } //end for
01207     } //end for
01208 } //end of the function AAS_InitReachabilityAreas
01209 //===========================================================================
01210 //
01211 // Parameter:           -
01212 // Returns:             -
01213 // Changes Globals:     -
01214 //===========================================================================
01215 void AAS_InitRouting(void)
01216 {
01217     AAS_InitTravelFlagFromType();
01218     //
01219     AAS_InitAreaContentsTravelFlags();
01220     //initialize the routing update fields
01221     AAS_InitRoutingUpdate();
01222     //create reversed reachability links used by the routing update algorithm
01223     AAS_CreateReversedReachability();
01224     //initialize the cluster cache
01225     AAS_InitClusterAreaCache();
01226     //initialize portal cache
01227     AAS_InitPortalCache();
01228     //initialize the area travel times
01229     AAS_CalculateAreaTravelTimes();
01230     //calculate the maximum travel times through portals
01231     AAS_InitPortalMaxTravelTimes();
01232     //get the areas reachabilities go through
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     // read any routing cache if available
01243     AAS_ReadRouteCache();
01244 } //end of the function AAS_InitRouting
01245 //===========================================================================
01246 //
01247 // Parameter:           -
01248 // Returns:             -
01249 // Changes Globals:     -
01250 //===========================================================================
01251 void AAS_FreeRoutingCaches(void)
01252 {
01253     // free all the existing cluster area cache
01254     AAS_FreeAllClusterAreaCache();
01255     // free all the existing portal cache
01256     AAS_FreeAllPortalCache();
01257     // free cached travel times within areas
01258     if (aasworld.areatraveltimes) FreeMemory(aasworld.areatraveltimes);
01259     aasworld.areatraveltimes = NULL;
01260     // free cached maximum travel time through cluster portals
01261     if (aasworld.portalmaxtraveltimes) FreeMemory(aasworld.portalmaxtraveltimes);
01262     aasworld.portalmaxtraveltimes = NULL;
01263     // free reversed reachability links
01264     if (aasworld.reversedreachability) FreeMemory(aasworld.reversedreachability);
01265     aasworld.reversedreachability = NULL;
01266     // free routing algorithm memory
01267     if (aasworld.areaupdate) FreeMemory(aasworld.areaupdate);
01268     aasworld.areaupdate = NULL;
01269     if (aasworld.portalupdate) FreeMemory(aasworld.portalupdate);
01270     aasworld.portalupdate = NULL;
01271     // free lists with areas the reachabilities go through
01272     if (aasworld.reachabilityareas) FreeMemory(aasworld.reachabilityareas);
01273     aasworld.reachabilityareas = NULL;
01274     // free the reachability area index
01275     if (aasworld.reachabilityareaindex) FreeMemory(aasworld.reachabilityareaindex);
01276     aasworld.reachabilityareaindex = NULL;
01277     // free area contents travel flags look up table
01278     if (aasworld.areacontentstravelflags) FreeMemory(aasworld.areacontentstravelflags);
01279     aasworld.areacontentstravelflags = NULL;
01280 } //end of the function AAS_FreeRoutingCaches
01281 //===========================================================================
01282 // update the given routing cache
01283 //
01284 // Parameter:           areacache       : routing cache to update
01285 // Returns:             -
01286 // Changes Globals:     -
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]; //NOTE: not more than 128 reachabilities per area allowed
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     //number of reachability areas within this cluster
01302     numreachabilityareas = aasworld.clusters[areacache->cluster].numreachabilityareas;
01303     //
01304     aasworld.frameroutingupdates++;
01305     //clear the routing update fields
01306 //  Com_Memset(aasworld.areaupdate, 0, aasworld.numareas * sizeof(aas_routingupdate_t));
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     //VectorCopy(areacache->origin, curupdate->start);
01318     curupdate->areatraveltimes = startareatraveltimes;
01319     curupdate->tmptraveltime = areacache->starttraveltime;
01320     //
01321     areacache->traveltimes[clusterareanum] = areacache->starttraveltime;
01322     //put the area to start with in the current read list
01323     curupdate->next = NULL;
01324     curupdate->prev = NULL;
01325     updateliststart = curupdate;
01326     updatelistend = curupdate;
01327     //while there are updates in the current list
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         //check all reversed reachability links
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             //if there is used an undesired travel type
01345             if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue;
01346             //if not allowed to enter the next area
01347             if (aasworld.areasettings[reach->areanum].areaflags & AREA_DISABLED) continue;
01348             //if the next area has a not allowed travel flag
01349             if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue;
01350             //number of the area the reversed reachability leads to
01351             nextareanum = revlink->areanum;
01352             //get the cluster number of the area
01353             cluster = aasworld.areasettings[nextareanum].cluster;
01354             //don't leave the cluster
01355             if (cluster > 0 && cluster != areacache->cluster) continue;
01356             //get the number of the area in the cluster
01357             clusterareanum = AAS_ClusterAreaNum(areacache->cluster, nextareanum);
01358             if (clusterareanum >= numreachabilityareas) continue;
01359             //time already travelled plus the traveltime through
01360             //the current area plus the travel time from the reachability
01361             t = curupdate->tmptraveltime +
01362                         //AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->end) +
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                 //VectorCopy(reach->start, nextupdate->start);
01375                 nextupdate->areatraveltimes = aasworld.areatraveltimes[nextareanum][linknum -
01376                                                     aasworld.areasettings[nextareanum].firstreachablearea];
01377                 if (!nextupdate->inlist)
01378                 {
01379                     // we add the update to the end of the list
01380                     // we could also use a B+ tree to have a real sorted list
01381                     // on travel time which makes for faster routing updates
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                 } //end if
01389             } //end if
01390         } //end for
01391     } //end while
01392 } //end of the function AAS_UpdateAreaRoutingCache
01393 //===========================================================================
01394 //
01395 // Parameter:           -
01396 // Returns:             -
01397 // Changes Globals:     -
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     //number of the area in the cluster
01405     clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
01406     //pointer to the cache for the area in the cluster
01407     clustercache = aasworld.clusterareacache[clusternum][clusterareanum];
01408     //find the cache without undesired travel flags
01409     for (cache = clustercache; cache; cache = cache->next)
01410     {
01411         //if there aren't used any undesired travel types for the cache
01412         if (cache->travelflags == travelflags) break;
01413     } //end for
01414     //if there was no cache
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     } //end if
01429     else
01430     {
01431         AAS_UnlinkCache(cache);
01432     } //end else
01433     //the cache has been accessed
01434     cache->time = AAS_RoutingTime();
01435     cache->type = CACHETYPE_AREA;
01436     AAS_LinkCache(cache);
01437     return cache;
01438 } //end of the function AAS_GetAreaRoutingCache
01439 //===========================================================================
01440 //
01441 // Parameter:           -
01442 // Returns:             -
01443 // Changes Globals:     -
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     //clear the routing update fields
01458 //  Com_Memset(aasworld.portalupdate, 0, (aasworld.numportals+1) * sizeof(aas_routingupdate_t));
01459     //
01460     curupdate = &aasworld.portalupdate[aasworld.numportals];
01461     curupdate->cluster = portalcache->cluster;
01462     curupdate->areanum = portalcache->areanum;
01463     curupdate->tmptraveltime = portalcache->starttraveltime;
01464     //if the start area is a cluster portal, store the travel time for that portal
01465     clusternum = aasworld.areasettings[portalcache->areanum].cluster;
01466     if (clusternum < 0)
01467     {
01468         portalcache->traveltimes[-clusternum] = portalcache->starttraveltime;
01469     } //end if
01470     //put the area to start with in the current read list
01471     curupdate->next = NULL;
01472     curupdate->prev = NULL;
01473     updateliststart = curupdate;
01474     updatelistend = curupdate;
01475     //while there are updates in the current list
01476     while (updateliststart)
01477     {
01478         curupdate = updateliststart;
01479         //remove the current update from the list
01480         if (curupdate->next) curupdate->next->prev = NULL;
01481         else updatelistend = NULL;
01482         updateliststart = curupdate->next;
01483         //current update is removed from the list
01484         curupdate->inlist = qfalse;
01485         //
01486         cluster = &aasworld.clusters[curupdate->cluster];
01487         //
01488         cache = AAS_GetAreaRoutingCache(curupdate->cluster,
01489                                 curupdate->areanum, portalcache->travelflags);
01490         //take all portals of the cluster
01491         for (i = 0; i < cluster->numportals; i++)
01492         {
01493             portalnum = aasworld.portalindex[cluster->firstportal + i];
01494             portal = &aasworld.portals[portalnum];
01495             //if this is the portal of the current update continue
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                 } //end if
01514                 else
01515                 {
01516                     nextupdate->cluster = portal->frontcluster;
01517                 } //end else
01518                 nextupdate->areanum = portal->areanum;
01519                 //add travel time through the actual portal area for the next update
01520                 nextupdate->tmptraveltime = t + aasworld.portalmaxtraveltimes[portalnum];
01521                 if (!nextupdate->inlist)
01522                 {
01523                     // we add the update to the end of the list
01524                     // we could also use a B+ tree to have a real sorted list
01525                     // on travel time which makes for faster routing updates
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                 } //end if
01533             } //end if
01534         } //end for
01535     } //end while
01536 } //end of the function AAS_UpdatePortalRoutingCache
01537 //===========================================================================
01538 //
01539 // Parameter:           -
01540 // Returns:             -
01541 // Changes Globals:     -
01542 //===========================================================================
01543 aas_routingcache_t *AAS_GetPortalRoutingCache(int clusternum, int areanum, int travelflags)
01544 {
01545     aas_routingcache_t *cache;
01546 
01547     //find the cached portal routing if existing
01548     for (cache = aasworld.portalcache[areanum]; cache; cache = cache->next)
01549     {
01550         if (cache->travelflags == travelflags) break;
01551     } //end for
01552     //if the portal routing isn't cached
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         //add the cache to the cache list
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         //update the cache
01567         AAS_UpdatePortalRoutingCache(cache);
01568     } //end if
01569     else
01570     {
01571         AAS_UnlinkCache(cache);
01572     } //end else
01573     //the cache has been accessed
01574     cache->time = AAS_RoutingTime();
01575     cache->type = CACHETYPE_PORTAL;
01576     AAS_LinkCache(cache);
01577     return cache;
01578 } //end of the function AAS_GetPortalRoutingCache
01579 //===========================================================================
01580 //
01581 // Parameter:           -
01582 // Returns:             -
01583 // Changes Globals:     -
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         } //end if
01609         return qfalse;
01610     } //end if
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         } //end if
01617         return qfalse;
01618     } //end if
01619     // make sure the routing cache doesn't grow to large
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     } //end if
01628     //NOTE: the number of routing updates is limited per frame
01629     /*
01630     if (aasworld.frameroutingupdates > MAX_FRAMEROUTINGUPDATES)
01631     {
01632 #ifdef DEBUG
01633         //Log_Write("WARNING: AAS_AreaTravelTimeToGoalArea: frame routing updates overflowed");
01634 #endif
01635         return 0;
01636     } //end if
01637     */
01638     //
01639     clusternum = aasworld.areasettings[areanum].cluster;
01640     goalclusternum = aasworld.areasettings[goalareanum].cluster;
01641     //check if the area is a portal of the goal area cluster
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         } //end if
01650     } //end if
01651     //check if the goalarea is a portal of the area cluster
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         } //end if
01660     } //end if
01661     //if both areas are in the same cluster
01662     //NOTE: there might be a shorter route via another cluster!!! but we don't care
01663     if (clusternum > 0 && goalclusternum > 0 && clusternum == goalclusternum)
01664     {
01665         //
01666         areacache = AAS_GetAreaRoutingCache(clusternum, goalareanum, travelflags);
01667         //the number of the area in the cluster
01668         clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
01669         //the cluster the area is in
01670         cluster = &aasworld.clusters[clusternum];
01671         //if the area is NOT a reachability area
01672         if (clusterareanum >= cluster->numreachabilityareas) return 0;
01673         //if it is possible to travel to the goal area through this cluster
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         } //end if
01688     } //end if
01689     //
01690     clusternum = aasworld.areasettings[areanum].cluster;
01691     goalclusternum = aasworld.areasettings[goalareanum].cluster;
01692     //if the goal area is a portal
01693     if (goalclusternum < 0)
01694     {
01695         //just assume the goal area is part of the front cluster
01696         portal = &aasworld.portals[-goalclusternum];
01697         goalclusternum = portal->frontcluster;
01698     } //end if
01699     //get the portal routing cache
01700     portalcache = AAS_GetPortalRoutingCache(goalclusternum, goalareanum, travelflags);
01701     //if the area is a cluster portal, read directly from the portal cache
01702     if (clusternum < 0)
01703     {
01704         *traveltime = portalcache->traveltimes[-clusternum];
01705         *reachnum = aasworld.areasettings[areanum].firstreachablearea +
01706                         portalcache->reachabilities[-clusternum];
01707         return qtrue;
01708     } //end if
01709     //
01710     besttime = 0;
01711     bestreachnum = -1;
01712     //the cluster the area is in
01713     cluster = &aasworld.clusters[clusternum];
01714     //find the portal of the area cluster leading towards the goal area
01715     for (i = 0; i < cluster->numportals; i++)
01716     {
01717         portalnum = aasworld.portalindex[cluster->firstportal + i];
01718         //if the goal area isn't reachable from the portal
01719         if (!portalcache->traveltimes[portalnum]) continue;
01720         //
01721         portal = &aasworld.portals[portalnum];
01722         //get the cache of the portal area
01723         areacache = AAS_GetAreaRoutingCache(clusternum, portal->areanum, travelflags);
01724         //current area inside the current cluster
01725         clusterareanum = AAS_ClusterAreaNum(clusternum, areanum);
01726         //if the area is NOT a reachability area
01727         if (clusterareanum >= cluster->numreachabilityareas) continue;
01728         //if the portal is NOT reachable from this area
01729         if (!areacache->traveltimes[clusterareanum]) continue;
01730         //total travel time is the travel time the portal area is from
01731         //the goal area plus the travel time towards the portal area
01732         t = portalcache->traveltimes[portalnum] + areacache->traveltimes[clusterareanum];
01733         //FIXME: add the exact travel time through the actual portal area
01734         //NOTE: for now we just add the largest travel time through the portal area
01735         //      because we can't directly calculate the exact travel time
01736         //      to be more specific we don't know which reachability was used to travel
01737         //      into the portal area
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         } //end if
01747         //if the time is better than the one already found
01748         if (!besttime || t < besttime)
01749         {
01750             bestreachnum = *reachnum;
01751             besttime = t;
01752         } //end if
01753     } //end for
01754     if (bestreachnum < 0) {
01755         return qfalse;
01756     }
01757     *reachnum = bestreachnum;
01758     *traveltime = besttime;
01759     return qtrue;
01760 } //end of the function AAS_AreaRouteToGoalArea
01761 //===========================================================================
01762 //
01763 // Parameter:           -
01764 // Returns:             -
01765 // Changes Globals:     -
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 } //end of the function AAS_AreaTravelTimeToGoalArea
01777 //===========================================================================
01778 //
01779 // Parameter:           -
01780 // Returns:             -
01781 // Changes Globals:     -
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 } //end of the function AAS_AreaReachabilityToGoalArea
01793 //===========================================================================
01794 // predict the route and stop on one of the stop events
01795 //
01796 // Parameter:           -
01797 // Returns:             -
01798 // Changes Globals:     -
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     //init output
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         } //end if
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             } //end if
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             } //end if
01852         } //end if
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                 } //end if
01872             } //end if
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                 } //end if
01883             } //end if
01884         } //end for
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     } //end while
01899     if (curareanum != goalareanum)
01900         return qfalse;
01901     return qtrue;
01902 } //end of the function AAS_PredictRoute
01903 //===========================================================================
01904 //
01905 // Parameter:           -
01906 // Returns:             -
01907 // Changes Globals:     -
01908 //===========================================================================
01909 int AAS_BridgeWalkable(int areanum)
01910 {
01911     return qfalse;
01912 } //end of the function AAS_BridgeWalkable
01913 //===========================================================================
01914 //
01915 // Parameter:           -
01916 // Returns:             -
01917 // Changes Globals:     -
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     } //end if
01926     if (num < 0 || num >= aasworld.reachabilitysize)
01927     {
01928         Com_Memset(reach, 0, sizeof(aas_reachability_t));
01929         return;
01930     } //end if
01931     Com_Memcpy(reach, &aasworld.reachability[num], sizeof(aas_reachability_t));;
01932 } //end of the function AAS_ReachabilityFromNum
01933 //===========================================================================
01934 //
01935 // Parameter:           -
01936 // Returns:             -
01937 // Changes Globals:     -
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     } //end if
01950 
01951     settings = &aasworld.areasettings[areanum];
01952     if (!reachnum)
01953     {
01954         return settings->firstreachablearea;
01955     } //end if
01956     if (reachnum < settings->firstreachablearea)
01957     {
01958         botimport.Print(PRT_FATAL, "AAS_NextAreaReachability: reachnum < settings->firstreachableara");
01959         return 0;
01960     } //end if
01961     reachnum++;
01962     if (reachnum >= settings->firstreachablearea + settings->numreachableareas)
01963     {
01964         return 0;
01965     } //end if
01966     return reachnum;
01967 } //end of the function AAS_NextAreaReachability
01968 //===========================================================================
01969 //
01970 // Parameter:           -
01971 // Returns:             -
01972 // Changes Globals:     -
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         } //end if
01988         else if ((aasworld.reachability[i].traveltype & TRAVELTYPE_MASK) == TRAVEL_FUNCBOB)
01989         {
01990             if ((aasworld.reachability[i].facenum & 0x0000FFFF) == modelnum) return i;
01991         } //end if
01992     } //end for
01993     return 0;
01994 } //end of the function AAS_NextModelReachability
01995 //===========================================================================
01996 //
01997 // Parameter:           -
01998 // Returns:             -
01999 // Changes Globals:     -
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     //if the area has no reachabilities
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             //if the goal is reachable
02019             if (t > 0)
02020             {
02021                 if (AAS_AreaSwim(n))
02022                 {
02023                     *goalareanum = n;
02024                     VectorCopy(aasworld.areas[n].center, goalorigin);
02025                     //botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum);
02026                     return qtrue;
02027                 } //end if
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                         //botimport.Print(PRT_MESSAGE, "found random goal area %d\n", *goalareanum);
02041                         return qtrue;
02042                     } //end if
02043                 } //end if
02044             } //end if
02045         } //end if
02046         n++;
02047     } //end for
02048     return qfalse;
02049 } //end of the function AAS_RandomGoalArea
02050 //===========================================================================
02051 //
02052 // Parameter:           -
02053 // Returns:             -
02054 // Changes Globals:     -
02055 //===========================================================================
02056 int AAS_AreaVisible(int srcarea, int destarea)
02057 {
02058     return qfalse;
02059 } //end of the function AAS_AreaVisible
02060 //===========================================================================
02061 //
02062 // Parameter:           -
02063 // Returns:             -
02064 // Changes Globals:     -
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 } //end of the function DistancePointToLine
02074 //===========================================================================
02075 //
02076 // Parameter:           -
02077 // Returns:             -
02078 // Changes Globals:     -
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     } //end if
02096     else
02097     {
02098         Com_Memset(hidetraveltimes, 0, aasworld.numareas * sizeof(unsigned short int));
02099     } //end else
02100     besttraveltime = 0;
02101     bestarea = 0;
02102     //assume visible
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     //put the area to start with in the current read list
02113     curupdate->next = NULL;
02114     curupdate->prev = NULL;
02115     updateliststart = curupdate;
02116     updatelistend = curupdate;
02117     //while there are updates in the list
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         //check all reversed reachability links
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             //if an undesired travel type is used
02134             if (AAS_TravelFlagForType_inline(reach->traveltype) & badtravelflags) continue;
02135             //
02136             if (AAS_AreaContentsTravelFlags_inline(reach->areanum) & badtravelflags) continue;
02137             //number of the area the reachability leads to
02138             nextareanum = reach->areanum;
02139             // if this moves us into the enemies area, skip it
02140             if (nextareanum == enemyareanum) continue;
02141             //time already travelled plus the traveltime through
02142             //the current area plus the travel time from the reachability
02143             t = curupdate->tmptraveltime +
02144                         AAS_AreaTravelTime(curupdate->areanum, curupdate->start, reach->start) +
02145                             reach->traveltime;
02146 
02147             //avoid going near the enemy
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             } //end if
02157             else
02158             {
02159                 VectorSubtract(enemyorigin, p, v2);
02160             } //end else
02161             dist2 = VectorLength(v2);
02162             //never go through the enemy
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             // if we weren't visible when starting, make sure we don't move into their view
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                 //if the nextarea is not visible from the enemy area
02183                 if (!AAS_AreaVisible(enemyareanum, nextareanum))
02184                 {
02185                     besttraveltime = t;
02186                     bestarea = nextareanum;
02187                 } //end if
02188                 hidetraveltimes[nextareanum] = t;
02189                 nextupdate = &aasworld.areaupdate[nextareanum];
02190                 nextupdate->areanum = nextareanum;
02191                 nextupdate->tmptraveltime = t;
02192                 //remember where we entered this area
02193                 VectorCopy(reach->end, nextupdate->start);
02194                 //if this update is not in the list yet
02195                 if (!nextupdate->inlist)
02196                 {
02197                     //add the new update to the end of the list
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                 } //end if
02205             } //end if
02206         } //end for
02207     } //end while
02208     return bestarea;
02209 } //end of the function AAS_NearestHideArea

Generated on Thu Aug 25 12:37:10 2005 for Quake III Arena by  doxygen 1.3.9.1