~ubuntu-branches/ubuntu/precise/openarena/precise

« back to all changes in this revision

Viewing changes to code/botlib/be_aas_route.c

  • Committer: Bazaar Package Importer
  • Author(s): Bruno "Fuddl" Kleinert
  • Date: 2007-01-20 12:28:09 UTC
  • Revision ID: james.westby@ubuntu.com-20070120122809-2yza5ojt7nqiyiam
Tags: upstream-0.6.0
ImportĀ upstreamĀ versionĀ 0.6.0

Show diffs side-by-side

added added

removed removed

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