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