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
51 //===========================================================================
52 //
53 // Parameter: -
54 // Returns: -
55 // Changes Globals: -
56 //===========================================================================
AAS_Error(char * fmt,...)57 void QDECL AAS_Error(char *fmt, ...)
58 {
59 char str[1024];
60 va_list arglist;
61
62 va_start(arglist, fmt);
63 Q_vsnprintf(str, sizeof(str), fmt, arglist);
64 va_end(arglist);
65 botimport.Print(PRT_FATAL, "%s", str);
66 } //end of the function AAS_Error
67 //===========================================================================
68 //
69 // Parameter: -
70 // Returns: -
71 // Changes Globals: -
72 //===========================================================================
AAS_StringFromIndex(char * indexname,char * stringindex[],int numindexes,int index)73 char *AAS_StringFromIndex(char *indexname, char *stringindex[], int numindexes, int index)
74 {
75 if (!aasworld.indexessetup)
76 {
77 botimport.Print(PRT_ERROR, "%s: index %d not setup\n", indexname, index);
78 return "";
79 } //end if
80 if (index < 0 || index >= numindexes)
81 {
82 botimport.Print(PRT_ERROR, "%s: index %d out of range\n", indexname, index);
83 return "";
84 } //end if
85 if (!stringindex[index])
86 {
87 if (index)
88 {
89 botimport.Print(PRT_ERROR, "%s: reference to unused index %d\n", indexname, index);
90 } //end if
91 return "";
92 } //end if
93 return stringindex[index];
94 } //end of the function AAS_StringFromIndex
95 //===========================================================================
96 //
97 // Parameter: -
98 // Returns: -
99 // Changes Globals: -
100 //===========================================================================
AAS_IndexFromString(char * indexname,char * stringindex[],int numindexes,char * string)101 int AAS_IndexFromString(char *indexname, char *stringindex[], int numindexes, char *string)
102 {
103 int i;
104 if (!aasworld.indexessetup)
105 {
106 botimport.Print(PRT_ERROR, "%s: index not setup \"%s\"\n", indexname, string);
107 return 0;
108 } //end if
109 for (i = 0; i < numindexes; i++)
110 {
111 if (!stringindex[i]) continue;
112 if (!Q_stricmp(stringindex[i], string)) return i;
113 } //end for
114 return 0;
115 } //end of the function AAS_IndexFromString
116 //===========================================================================
117 //
118 // Parameter: -
119 // Returns: -
120 // Changes Globals: -
121 //===========================================================================
AAS_ModelFromIndex(int index)122 char *AAS_ModelFromIndex(int index)
123 {
124 return AAS_StringFromIndex("ModelFromIndex", &aasworld.configstrings[CS_MODELS], MAX_MODELS, index);
125 } //end of the function AAS_ModelFromIndex
126 //===========================================================================
127 //
128 // Parameter: -
129 // Returns: -
130 // Changes Globals: -
131 //===========================================================================
AAS_IndexFromModel(char * modelname)132 int AAS_IndexFromModel(char *modelname)
133 {
134 return AAS_IndexFromString("IndexFromModel", &aasworld.configstrings[CS_MODELS], MAX_MODELS, modelname);
135 } //end of the function AAS_IndexFromModel
136 //===========================================================================
137 //
138 // Parameter: -
139 // Returns: -
140 // Changes Globals: -
141 //===========================================================================
AAS_UpdateStringIndexes(int numconfigstrings,char * configstrings[])142 void AAS_UpdateStringIndexes(int numconfigstrings, char *configstrings[])
143 {
144 int i;
145 //set string pointers and copy the strings
146 for (i = 0; i < numconfigstrings; i++)
147 {
148 if (configstrings[i])
149 {
150 //if (aasworld.configstrings[i]) FreeMemory(aasworld.configstrings[i]);
151 aasworld.configstrings[i] = (char *) GetMemory(strlen(configstrings[i]) + 1);
152 strcpy(aasworld.configstrings[i], configstrings[i]);
153 } //end if
154 } //end for
155 aasworld.indexessetup = qtrue;
156 } //end of the function AAS_UpdateStringIndexes
157 //===========================================================================
158 //
159 // Parameter: -
160 // Returns: -
161 // Changes Globals: -
162 //===========================================================================
AAS_Loaded(void)163 int AAS_Loaded(void)
164 {
165 return aasworld.loaded;
166 } //end of the function AAS_Loaded
167 //===========================================================================
168 //
169 // Parameter: -
170 // Returns: -
171 // Changes Globals: -
172 //===========================================================================
AAS_Initialized(void)173 int AAS_Initialized(void)
174 {
175 return aasworld.initialized;
176 } //end of the function AAS_Initialized
177 //===========================================================================
178 //
179 // Parameter: -
180 // Returns: -
181 // Changes Globals: -
182 //===========================================================================
AAS_SetInitialized(void)183 void AAS_SetInitialized(void)
184 {
185 aasworld.initialized = qtrue;
186 botimport.Print(PRT_MESSAGE, "AAS initialized.\n");
187 #ifdef DEBUG
188 //create all the routing cache
189 //AAS_CreateAllRoutingCache();
190 //
191 //AAS_RoutingInfo();
192 #endif
193 } //end of the function AAS_SetInitialized
194 //===========================================================================
195 //
196 // Parameter: -
197 // Returns: -
198 // Changes Globals: -
199 //===========================================================================
AAS_ContinueInit(float time)200 void AAS_ContinueInit(float time)
201 {
202 //if no AAS file loaded
203 if (!aasworld.loaded) return;
204 //if AAS is already initialized
205 if (aasworld.initialized) return;
206 //calculate reachability, if not finished return
207 if (AAS_ContinueInitReachability(time)) return;
208 //initialize clustering for the new map
209 AAS_InitClustering();
210 //if reachability has been calculated and an AAS file should be written
211 //or there is a forced data optimization
212 if (aasworld.savefile || ((int)LibVarGetValue("forcewrite")))
213 {
214 //optimize the AAS data
215 if ((int)LibVarValue("aasoptimize", "0")) AAS_Optimize();
216 //save the AAS file
217 if (AAS_WriteAASFile(aasworld.filename))
218 {
219 botimport.Print(PRT_MESSAGE, "%s written succesfully\n", aasworld.filename);
220 } //end if
221 else
222 {
223 botimport.Print(PRT_ERROR, "couldn't write %s\n", aasworld.filename);
224 } //end else
225 } //end if
226 //initialize the routing
227 AAS_InitRouting();
228 //at this point AAS is initialized
229 AAS_SetInitialized();
230 } //end of the function AAS_ContinueInit
231 //===========================================================================
232 // called at the start of every frame
233 //
234 // Parameter: -
235 // Returns: -
236 // Changes Globals: -
237 //===========================================================================
AAS_StartFrame(float time)238 int AAS_StartFrame(float time)
239 {
240 aasworld.time = time;
241 //unlink all entities that were not updated last frame
242 AAS_UnlinkInvalidEntities();
243 //invalidate the entities
244 AAS_InvalidateEntities();
245 //initialize AAS
246 AAS_ContinueInit(time);
247 //
248 aasworld.frameroutingupdates = 0;
249 //
250 if (bot_developer)
251 {
252 if (LibVarGetValue("showcacheupdates"))
253 {
254 AAS_RoutingInfo();
255 LibVarSet("showcacheupdates", "0");
256 } //end if
257 if (LibVarGetValue("showmemoryusage"))
258 {
259 PrintUsedMemorySize();
260 LibVarSet("showmemoryusage", "0");
261 } //end if
262 if (LibVarGetValue("memorydump"))
263 {
264 PrintMemoryLabels();
265 LibVarSet("memorydump", "0");
266 } //end if
267 } //end if
268 //
269 if (saveroutingcache->value)
270 {
271 AAS_WriteRouteCache();
272 LibVarSet("saveroutingcache", "0");
273 } //end if
274 //
275 aasworld.numframes++;
276 return BLERR_NOERROR;
277 } //end of the function AAS_StartFrame
278 //===========================================================================
279 //
280 // Parameter: -
281 // Returns: -
282 // Changes Globals: -
283 //===========================================================================
AAS_Time(void)284 float AAS_Time(void)
285 {
286 return aasworld.time;
287 } //end of the function AAS_Time
288 //===========================================================================
289 //
290 // Parameter: -
291 // Returns: -
292 // Changes Globals: -
293 //===========================================================================
AAS_ProjectPointOntoVector(vec3_t point,vec3_t vStart,vec3_t vEnd,vec3_t vProj)294 void AAS_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vEnd, vec3_t vProj )
295 {
296 vec3_t pVec, vec;
297
298 VectorSubtract( point, vStart, pVec );
299 VectorSubtract( vEnd, vStart, vec );
300 VectorNormalize( vec );
301 // project onto the directional vector for this segment
302 VectorMA( vStart, DotProduct( pVec, vec ), vec, vProj );
303 } //end of the function AAS_ProjectPointOntoVector
304 //===========================================================================
305 //
306 // Parameter: -
307 // Returns: -
308 // Changes Globals: -
309 //===========================================================================
AAS_LoadFiles(const char * mapname)310 int AAS_LoadFiles(const char *mapname)
311 {
312 int errnum;
313 char aasfile[MAX_PATH];
314 // char bspfile[MAX_PATH];
315
316 strcpy(aasworld.mapname, mapname);
317 //NOTE: first reset the entity links into the AAS areas and BSP leaves
318 // the AAS link heap and BSP link heap are reset after respectively the
319 // AAS file and BSP file are loaded
320 AAS_ResetEntityLinks();
321 // load bsp info
322 AAS_LoadBSPFile();
323
324 //load the aas file
325 Com_sprintf(aasfile, MAX_PATH, "maps/%s.aas", mapname);
326 errnum = AAS_LoadAASFile(aasfile);
327 if (errnum != BLERR_NOERROR)
328 return errnum;
329
330 botimport.Print(PRT_MESSAGE, "loaded %s\n", aasfile);
331 strncpy(aasworld.filename, aasfile, MAX_PATH);
332 return BLERR_NOERROR;
333 } //end of the function AAS_LoadFiles
334 //===========================================================================
335 // called everytime a map changes
336 //
337 // Parameter: -
338 // Returns: -
339 // Changes Globals: -
340 //===========================================================================
AAS_LoadMap(const char * mapname)341 int AAS_LoadMap(const char *mapname)
342 {
343 int errnum;
344
345 //if no mapname is provided then the string indexes are updated
346 if (!mapname)
347 {
348 return 0;
349 } //end if
350 //
351 aasworld.initialized = qfalse;
352 //NOTE: free the routing caches before loading a new map because
353 // to free the caches the old number of areas, number of clusters
354 // and number of areas in a clusters must be available
355 AAS_FreeRoutingCaches();
356 //load the map
357 errnum = AAS_LoadFiles(mapname);
358 if (errnum != BLERR_NOERROR)
359 {
360 aasworld.loaded = qfalse;
361 return errnum;
362 } //end if
363 //
364 AAS_InitSettings();
365 //initialize the AAS link heap for the new map
366 AAS_InitAASLinkHeap();
367 //initialize the AAS linked entities for the new map
368 AAS_InitAASLinkedEntities();
369 //initialize reachability for the new map
370 AAS_InitReachability();
371 //initialize the alternative routing
372 AAS_InitAlternativeRouting();
373 //everything went ok
374 return 0;
375 } //end of the function AAS_LoadMap
376 //===========================================================================
377 // called when the library is first loaded
378 //
379 // Parameter: -
380 // Returns: -
381 // Changes Globals: -
382 //===========================================================================
AAS_Setup(void)383 int AAS_Setup(void)
384 {
385 aasworld.maxclients = (int) LibVarValue("maxclients", "128");
386 aasworld.maxentities = (int) LibVarValue("maxentities", "1024");
387 // as soon as it's set to 1 the routing cache will be saved
388 saveroutingcache = LibVar("saveroutingcache", "0");
389 //allocate memory for the entities
390 if (aasworld.entities) FreeMemory(aasworld.entities);
391 aasworld.entities = (aas_entity_t *) GetClearedHunkMemory(aasworld.maxentities * sizeof(aas_entity_t));
392 //invalidate all the entities
393 AAS_InvalidateEntities();
394 //force some recalculations
395 //LibVarSet("forceclustering", "1"); //force clustering calculation
396 //LibVarSet("forcereachability", "1"); //force reachability calculation
397 aasworld.numframes = 0;
398 return BLERR_NOERROR;
399 } //end of the function AAS_Setup
400 //===========================================================================
401 //
402 // Parameter: -
403 // Returns: -
404 // Changes Globals: -
405 //===========================================================================
AAS_Shutdown(void)406 void AAS_Shutdown(void)
407 {
408 AAS_ShutdownAlternativeRouting();
409 //
410 AAS_DumpBSPData();
411 //free routing caches
412 AAS_FreeRoutingCaches();
413 //free aas link heap
414 AAS_FreeAASLinkHeap();
415 //free aas linked entities
416 AAS_FreeAASLinkedEntities();
417 //free the aas data
418 AAS_DumpAASData();
419 //free the entities
420 if (aasworld.entities) FreeMemory(aasworld.entities);
421 //clear the aasworld structure
422 Com_Memset(&aasworld, 0, sizeof(aas_t));
423 //aas has not been initialized
424 aasworld.initialized = qfalse;
425 //NOTE: as soon as a new .bsp file is loaded the .bsp file memory is
426 // freed an reallocated, so there's no need to free that memory here
427 //print shutdown
428 botimport.Print(PRT_MESSAGE, "AAS shutdown.\n");
429 } //end of the function AAS_Shutdown
430