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_main.c
25  *
26  * desc:		AAS
27  *
28  * $Archive: /MissionPack/code/botlib/be_aas_main.c $
29  *
30  *****************************************************************************/
31 
32 #include "../qcommon/q_shared.h"
33 #include "l_memory.h"
34 #include "l_libvar.h"
35 #include "l_utils.h"
36 #include "l_script.h"
37 #include "l_precomp.h"
38 #include "l_struct.h"
39 #include "l_log.h"
40 #include "aasfile.h"
41 #include "botlib.h"
42 #include "be_aas.h"
43 #include "be_aas_funcs.h"
44 #include "be_interface.h"
45 #include "be_aas_def.h"
46 
47 aas_t aasworld;
48 
49 libvar_t *saveroutingcache;
50 int showroute_ent = 0;	// cyr
51 int showroute_entarea = 0;	// cyr
52 
53 //===========================================================================
54 //
55 // Parameter:				-
56 // Returns:					-
57 // Changes Globals:		-
58 //===========================================================================
AAS_Error(char * fmt,...)59 void QDECL AAS_Error(char *fmt, ...)
60 {
61 	char str[1024];
62 	va_list arglist;
63 
64 	va_start(arglist, fmt);
65 	Q_vsnprintf(str, sizeof(str), fmt, arglist);
66 	va_end(arglist);
67 	botimport.Print(PRT_FATAL, "%s", str);
68 } //end of the function AAS_Error
69 //===========================================================================
70 //
71 // Parameter:				-
72 // Returns:					-
73 // Changes Globals:		-
74 //===========================================================================
AAS_StringFromIndex(char * indexname,char * stringindex[],int numindexes,int index)75 char *AAS_StringFromIndex(char *indexname, char *stringindex[], int numindexes, int index)
76 {
77 	if (!aasworld.indexessetup)
78 	{
79 		botimport.Print(PRT_ERROR, "%s: index %d not setup\n", indexname, index);
80 		return "";
81 	} //end if
82 	if (index < 0 || index >= numindexes)
83 	{
84 		botimport.Print(PRT_ERROR, "%s: index %d out of range\n", indexname, index);
85 		return "";
86 	} //end if
87 	if (!stringindex[index])
88 	{
89 		if (index)
90 		{
91 			botimport.Print(PRT_ERROR, "%s: reference to unused index %d\n", indexname, index);
92 		} //end if
93 		return "";
94 	} //end if
95 	return stringindex[index];
96 } //end of the function AAS_StringFromIndex
97 //===========================================================================
98 //
99 // Parameter:				-
100 // Returns:					-
101 // Changes Globals:		-
102 //===========================================================================
AAS_IndexFromString(char * indexname,char * stringindex[],int numindexes,char * string)103 int AAS_IndexFromString(char *indexname, char *stringindex[], int numindexes, char *string)
104 {
105 	int i;
106 	if (!aasworld.indexessetup)
107 	{
108 		botimport.Print(PRT_ERROR, "%s: index not setup \"%s\"\n", indexname, string);
109 		return 0;
110 	} //end if
111 	for (i = 0; i < numindexes; i++)
112 	{
113 		if (!stringindex[i]) continue;
114 		if (!Q_stricmp(stringindex[i], string)) return i;
115 	} //end for
116 	return 0;
117 } //end of the function AAS_IndexFromString
118 //===========================================================================
119 //
120 // Parameter:				-
121 // Returns:					-
122 // Changes Globals:		-
123 //===========================================================================
AAS_ModelFromIndex(int index)124 char *AAS_ModelFromIndex(int index)
125 {
126 	return AAS_StringFromIndex("ModelFromIndex", &aasworld.configstrings[CS_MODELS], MAX_MODELS, index);
127 } //end of the function AAS_ModelFromIndex
128 //===========================================================================
129 //
130 // Parameter:				-
131 // Returns:					-
132 // Changes Globals:		-
133 //===========================================================================
AAS_IndexFromModel(char * modelname)134 int AAS_IndexFromModel(char *modelname)
135 {
136 	return AAS_IndexFromString("IndexFromModel", &aasworld.configstrings[CS_MODELS], MAX_MODELS, modelname);
137 } //end of the function AAS_IndexFromModel
138 //===========================================================================
139 //
140 // Parameter:				-
141 // Returns:					-
142 // Changes Globals:		-
143 //===========================================================================
AAS_UpdateStringIndexes(int numconfigstrings,char * configstrings[])144 void AAS_UpdateStringIndexes(int numconfigstrings, char *configstrings[])
145 {
146 	int i;
147 	//set string pointers and copy the strings
148 	for (i = 0; i < numconfigstrings; i++)
149 	{
150 		if (configstrings[i])
151 		{
152 			//if (aasworld.configstrings[i]) FreeMemory(aasworld.configstrings[i]);
153 			aasworld.configstrings[i] = (char *) GetMemory(strlen(configstrings[i]) + 1);
154 			strcpy(aasworld.configstrings[i], configstrings[i]);
155 		} //end if
156 	} //end for
157 	aasworld.indexessetup = qtrue;
158 } //end of the function AAS_UpdateStringIndexes
159 //===========================================================================
160 //
161 // Parameter:				-
162 // Returns:					-
163 // Changes Globals:		-
164 //===========================================================================
AAS_Loaded(void)165 int AAS_Loaded(void)
166 {
167 	return aasworld.loaded;
168 } //end of the function AAS_Loaded
169 //===========================================================================
170 //
171 // Parameter:				-
172 // Returns:					-
173 // Changes Globals:		-
174 //===========================================================================
AAS_Initialized(void)175 int AAS_Initialized(void)
176 {
177 	return aasworld.initialized;
178 } //end of the function AAS_Initialized
179 //===========================================================================
180 //
181 // Parameter:				-
182 // Returns:					-
183 // Changes Globals:		-
184 //===========================================================================
AAS_SetInitialized(void)185 void AAS_SetInitialized(void)
186 {
187 	aasworld.initialized = qtrue;
188 	botimport.Print(PRT_MESSAGE, "AAS initialized.\n");
189 #ifdef DEBUG
190 	//create all the routing cache
191 	//AAS_CreateAllRoutingCache();
192 	//
193 	//AAS_RoutingInfo();
194 #endif
195 } //end of the function AAS_SetInitialized
196 //===========================================================================
197 //
198 // Parameter:				-
199 // Returns:					-
200 // Changes Globals:		-
201 //===========================================================================
AAS_ContinueInit(float time)202 void AAS_ContinueInit(float time)
203 {
204 	//if no AAS file loaded
205 	if (!aasworld.loaded) return;
206 	//if AAS is already initialized
207 	if (aasworld.initialized) return;
208 	//calculate reachability, if not finished return
209 	if (AAS_ContinueInitReachability(time)) return;
210 	//initialize clustering for the new map
211 	AAS_InitClustering();
212 	//if reachability has been calculated and an AAS file should be written
213 	//or there is a forced data optimization
214 	if (aasworld.savefile || ((int)LibVarGetValue("forcewrite")))
215 	{
216 		//optimize the AAS data
217 		if ((int)LibVarValue("aasoptimize", "0")) AAS_Optimize();
218 		//save the AAS file
219 		if (AAS_WriteAASFile(aasworld.filename))
220 		{
221 			botimport.Print(PRT_MESSAGE, "%s written succesfully\n", aasworld.filename);
222 		} //end if
223 		else
224 		{
225 			botimport.Print(PRT_ERROR, "couldn't write %s\n", aasworld.filename);
226 		} //end else
227 	} //end if
228 	//initialize the routing
229 	AAS_InitRouting();
230 	//at this point AAS is initialized
231 	AAS_SetInitialized();
232 } //end of the function AAS_ContinueInit
233 
234 //cyr
ShowReachesFrom(void)235 void ShowReachesFrom(void){
236 	int reachnum, areanum;
237 	aas_reachability_t reach;
238 	vec3_t origin;
239 	aas_entityinfo_t entinfo;
240 
241 	// client0 position
242 	AAS_EntityInfo(0, &entinfo);
243 	areanum = AAS_PointAreaNum(entinfo.origin);
244 
245 	VectorCopy(entinfo.origin, origin);
246 	origin[2] -= 20;	// player height... how much is it?
247 
248 	if(!areanum) return;
249 	for (reachnum = AAS_NextAreaReachability(areanum, 0); reachnum;
250 		reachnum = AAS_NextAreaReachability(areanum, reachnum)){
251 
252 		AAS_ReachabilityFromNum(reachnum, &reach);
253 
254 		//AAS_DrawArrow(entinfo.origin, reach.start, LINECOLOR_BLUE, LINECOLOR_YELLOW);
255 		AAS_DebugLine(origin, reach.start, LINECOLOR_YELLOW);
256 		AAS_ShowReachability(&reach);
257 		AAS_ShowArea(reach.areanum, qtrue);
258 
259 		//botimport.Print(PRT_MESSAGE, " towards area %d \n", reach.areanum);
260 	}
261 }
262 
ShowReachesTo(void)263 void ShowReachesTo(void){
264 	int areanum;
265 	aas_reachability_t* reach;
266 //	vec3_t origin;
267 	aas_entityinfo_t entinfo;
268 	int linknum;
269 	aas_reversedreachability_t *revreach;
270     aas_reversedlink_t *revlink;
271 
272 	// client0 position
273 	AAS_EntityInfo(0, &entinfo);
274 	areanum = AAS_PointAreaNum(entinfo.origin);
275 
276 	if(!areanum) return;
277 	// iterate over all
278 	revreach = &aasworld.reversedreachability[areanum];
279         //
280         for (revlink = revreach->first; revlink; revlink = revlink->next){
281         	linknum = revlink->linknum;
282             reach = &aasworld.reachability[linknum];
283 
284 			//AAS_DrawArrow(entinfo.origin, reach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW);
285 			AAS_DebugLine(entinfo.origin, reach->end, LINECOLOR_BLUE);
286 			AAS_ShowReachability(reach);
287 			AAS_ShowArea(revlink->areanum, qtrue);
288 
289 			//botimport.Print(PRT_MESSAGE, " from area %d \n", revlink->areanum);
290         }
291 }
292 
293 //===========================================================================
294 // called at the start of every frame
295 //
296 // Parameter:				-
297 // Returns:					-
298 // Changes Globals:		-
299 //===========================================================================
AAS_StartFrame(float time)300 int AAS_StartFrame(float time)
301 {
302 	aasworld.time = time;
303 	//unlink all entities that were not updated last frame
304 	AAS_UnlinkInvalidEntities();
305 	//invalidate the entities
306 	AAS_InvalidateEntities();
307 	//initialize AAS
308 	AAS_ContinueInit(time);
309 	//
310 	aasworld.frameroutingupdates = 0;
311 
312 	AAS_ClearShownPolygons();
313 	AAS_ClearShownDebugLines();
314 
315 	//
316 	if (bot_developer)
317 	{
318 		if (LibVarGetValue("showcacheupdates"))
319 		{
320 			AAS_RoutingInfo();
321 			LibVarSet("showcacheupdates", "0");
322 		} //end if
323 		if (LibVarGetValue("showmemoryusage"))
324 		{
325 			PrintUsedMemorySize();
326 			LibVarSet("showmemoryusage", "0");
327 		} //end if
328 		if (LibVarGetValue("memorydump"))
329 		{
330 			PrintMemoryLabels();
331 			LibVarSet("memorydump", "0");
332 		} //end if
333 	} //end if
334 	//
335 	if (saveroutingcache->value)
336 	{
337 		AAS_WriteRouteCache();
338 		LibVarSet("saveroutingcache", "0");
339 	} //end if
340 // cyr{
341 	if ( LibVarGetValue("shownextitem") ){
342 		/*
343 		GetNextItemNumber(&showroute_ent, &showroute_entarea);
344 		botimport.Print(PRT_MESSAGE, "avl %f next item: %d \n", LibVarGetValue("shownextitem"), showroute_ent);
345 		PrintCurItemInfo();
346 		ShowRoute(0, showroute_ent, showroute_entarea, qtrue);
347 		*/
348 		LibVarSet("shownextitem", "0");
349 	}
350 	if ( LibVarGetValue("shownoitem") ){
351 		/*
352 		showroute_ent = 0;
353 		botimport.Print(PRT_MESSAGE, " %f dont show item route \n", LibVarGetValue("shownoitem") );
354 		AAS_ClearShownPolygons();
355 		AAS_ClearShownDebugLines();
356 		*/
357 		LibVarSet("shownoitem", "0");
358 	}
359 
360 
361 	if(showroute_ent != 0){
362 		AAS_ClearShownPolygons();
363 		AAS_ClearShownDebugLines();
364 		ShowRoute(0, showroute_ent, showroute_entarea, qfalse);
365 	}
366 
367 	if ( LibVarGetValue("showreachesfrom") ){
368 		//botimport.Print(PRT_MESSAGE, " from \n");
369 		AAS_ClearShownPolygons();
370 		AAS_ClearShownDebugLines();
371 		ShowReachesFrom();
372 	}
373 
374 	if ( LibVarGetValue("showreachesto") ){
375 		AAS_ClearShownPolygons();
376 		AAS_ClearShownDebugLines();
377 		ShowReachesTo();
378 	}
379 
380 // cyr}
381 	//
382 	aasworld.numframes++;
383 	return BLERR_NOERROR;
384 } //end of the function AAS_StartFrame
385 //===========================================================================
386 //
387 // Parameter:				-
388 // Returns:					-
389 // Changes Globals:		-
390 //===========================================================================
AAS_Time(void)391 float AAS_Time(void)
392 {
393 	return aasworld.time;
394 } //end of the function AAS_Time
395 //===========================================================================
396 //
397 // Parameter:			-
398 // Returns:				-
399 // Changes Globals:		-
400 //===========================================================================
AAS_ProjectPointOntoVector(vec3_t point,vec3_t vStart,vec3_t vEnd,vec3_t vProj)401 void AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj )
402 {
403 	vec3_t pVec, vec;
404 
405 	VectorSubtract( point, vStart, pVec );
406 	VectorSubtract( vEnd, vStart, vec );
407 	VectorNormalize( vec );
408 	// project onto the directional vector for this segment
409 	VectorMA( vStart, DotProduct( pVec, vec ), vec, vProj );
410 } //end of the function AAS_ProjectPointOntoVector
411 //===========================================================================
412 //
413 // Parameter:				-
414 // Returns:					-
415 // Changes Globals:		-
416 //===========================================================================
AAS_LoadFiles(const char * mapname)417 int AAS_LoadFiles(const char *mapname)
418 {
419 	int errnum;
420 	char aasfile[MAX_PATH];
421 //	char bspfile[MAX_PATH];
422 
423 	strcpy(aasworld.mapname, mapname);
424 	//NOTE: first reset the entity links into the AAS areas and BSP leaves
425 	// the AAS link heap and BSP link heap are reset after respectively the
426 	// AAS file and BSP file are loaded
427 	AAS_ResetEntityLinks();
428 	// load bsp info
429 	AAS_LoadBSPFile();
430 
431 	//load the aas file
432 	Com_sprintf(aasfile, MAX_PATH, "maps/%s.aas", mapname);
433 	errnum = AAS_LoadAASFile(aasfile);
434 	if (errnum != BLERR_NOERROR)
435 		return errnum;
436 
437 	botimport.Print(PRT_MESSAGE, "loaded %s\n", aasfile);
438 	strncpy(aasworld.filename, aasfile, MAX_PATH);
439 	return BLERR_NOERROR;
440 } //end of the function AAS_LoadFiles
441 //===========================================================================
442 // called everytime a map changes
443 //
444 // Parameter:				-
445 // Returns:					-
446 // Changes Globals:		-
447 //===========================================================================
AAS_LoadMap(const char * mapname)448 int AAS_LoadMap(const char *mapname)
449 {
450 	int	errnum;
451 
452 	//if no mapname is provided then the string indexes are updated
453 	if (!mapname)
454 	{
455 		return 0;
456 	} //end if
457 	//
458 	aasworld.initialized = qfalse;
459 	//NOTE: free the routing caches before loading a new map because
460 	// to free the caches the old number of areas, number of clusters
461 	// and number of areas in a clusters must be available
462 	AAS_FreeRoutingCaches();
463 	//load the map
464 	errnum = AAS_LoadFiles(mapname);
465 	if (errnum != BLERR_NOERROR)
466 	{
467 		aasworld.loaded = qfalse;
468 		return errnum;
469 	} //end if
470 	//
471 	AAS_InitSettings();
472 	//initialize the AAS link heap for the new map
473 	AAS_InitAASLinkHeap();
474 	//initialize the AAS linked entities for the new map
475 	AAS_InitAASLinkedEntities();
476 	//initialize reachability for the new map
477 	AAS_InitReachability();
478 	//initialize the alternative routing
479 	AAS_InitAlternativeRouting();
480 	//everything went ok
481 	return 0;
482 } //end of the function AAS_LoadMap
483 //===========================================================================
484 // called when the library is first loaded
485 //
486 // Parameter:				-
487 // Returns:					-
488 // Changes Globals:		-
489 //===========================================================================
AAS_Setup(void)490 int AAS_Setup(void)
491 {
492 	aasworld.maxclients = (int) LibVarValue("maxclients", "128");
493 	aasworld.maxentities = (int) LibVarValue("maxentities", "1024");
494 	// as soon as it's set to 1 the routing cache will be saved
495 	saveroutingcache = LibVar("saveroutingcache", "0");
496 	//allocate memory for the entities
497 	if (aasworld.entities) FreeMemory(aasworld.entities);
498 	aasworld.entities = (aas_entity_t *) GetClearedHunkMemory(aasworld.maxentities * sizeof(aas_entity_t));
499 	//invalidate all the entities
500 	AAS_InvalidateEntities();
501 	//force some recalculations
502 	//LibVarSet("forceclustering", "1");			//force clustering calculation
503 	//LibVarSet("forcereachability", "1");		//force reachability calculation
504 	aasworld.numframes = 0;
505 	return BLERR_NOERROR;
506 } //end of the function AAS_Setup
507 //===========================================================================
508 //
509 // Parameter:				-
510 // Returns:					-
511 // Changes Globals:		-
512 //===========================================================================
AAS_Shutdown(void)513 void AAS_Shutdown(void)
514 {
515 	AAS_ShutdownAlternativeRouting();
516 	//
517 	AAS_DumpBSPData();
518 	//free routing caches
519 	AAS_FreeRoutingCaches();
520 	//free aas link heap
521 	AAS_FreeAASLinkHeap();
522 	//free aas linked entities
523 	AAS_FreeAASLinkedEntities();
524 	//free the aas data
525 	AAS_DumpAASData();
526 	//free the entities
527 	if (aasworld.entities) FreeMemory(aasworld.entities);
528 	//clear the aasworld structure
529 	Com_Memset(&aasworld, 0, sizeof(aas_t));
530 	//aas has not been initialized
531 	aasworld.initialized = qfalse;
532 	//NOTE: as soon as a new .bsp file is loaded the .bsp file memory is
533 	// freed an reallocated, so there's no need to free that memory here
534 	//print shutdown
535 	botimport.Print(PRT_MESSAGE, "AAS shutdown.\n");
536 } //end of the function AAS_Shutdown
537