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