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_entity.c
25  *
26  * desc:		AAS entities
27  *
28  * $Archive: /MissionPack/code/botlib/be_aas_entity.c $
29  *
30  *****************************************************************************/
31 
32 #include "../qcommon/q_shared.h"
33 #include "l_memory.h"
34 #include "l_script.h"
35 #include "l_precomp.h"
36 #include "l_struct.h"
37 #include "l_utils.h"
38 #include "l_log.h"
39 #include "aasfile.h"
40 #include "botlib.h"
41 #include "be_aas.h"
42 #include "be_aas_funcs.h"
43 #include "be_interface.h"
44 #include "be_aas_def.h"
45 
46 #define MASK_SOLID		CONTENTS_PLAYERCLIP
47 
48 //FIXME: these might change
49 enum {
50 	ET_GENERAL,
51 	ET_PLAYER,
52 	ET_ITEM,
53 	ET_MISSILE,
54 	ET_MOVER
55 };
56 
57 //===========================================================================
58 //
59 // Parameter:				-
60 // Returns:					-
61 // Changes Globals:		-
62 //===========================================================================
AAS_UpdateEntity(int entnum,bot_entitystate_t * state)63 int AAS_UpdateEntity(int entnum, bot_entitystate_t *state)
64 {
65 	int relink;
66 	aas_entity_t *ent;
67 	vec3_t absmins, absmaxs;
68 
69 	if (!aasworld.loaded)
70 	{
71 		botimport.Print(PRT_MESSAGE, "AAS_UpdateEntity: not loaded\n");
72 		return BLERR_NOAASFILE;
73 	} //end if
74 
75 	ent = &aasworld.entities[entnum];
76 
77 	if (!state) {
78 		//unlink the entity
79 		AAS_UnlinkFromAreas(ent->areas);
80 		//unlink the entity from the BSP leaves
81 		AAS_UnlinkFromBSPLeaves(ent->leaves);
82 		//
83 		ent->areas = NULL;
84 		//
85 		ent->leaves = NULL;
86 		return BLERR_NOERROR;
87 	}
88 
89 	ent->i.update_time = AAS_Time() - ent->i.ltime;
90 	ent->i.type = state->type;
91 	ent->i.flags = state->flags;
92 	ent->i.ltime = AAS_Time();
93 	VectorCopy(ent->i.origin, ent->i.lastvisorigin);
94 	VectorCopy(state->old_origin, ent->i.old_origin);
95 	ent->i.solid = state->solid;
96 	ent->i.groundent = state->groundent;
97 	ent->i.modelindex = state->modelindex;
98 	ent->i.modelindex2 = state->modelindex2;
99 	ent->i.frame = state->frame;
100 	ent->i.event = state->event;
101 	ent->i.eventParm = state->eventParm;
102 	ent->i.powerups = state->powerups;
103 	ent->i.weapon = state->weapon;
104 	ent->i.legsAnim = state->legsAnim;
105 	ent->i.torsoAnim = state->torsoAnim;
106 	//number of the entity
107 	ent->i.number = entnum;
108 	//updated so set valid flag
109 	ent->i.valid = qtrue;
110 	//link everything the first frame
111 	if (aasworld.numframes == 1) relink = qtrue;
112 	else relink = qfalse;
113 	//
114 	if (ent->i.solid == SOLID_BSP)
115 	{
116 		//if the angles of the model changed
117 		if (!VectorCompare(state->angles, ent->i.angles))
118 		{
119 			VectorCopy(state->angles, ent->i.angles);
120 			relink = qtrue;
121 		} //end if
122 		//get the mins and maxs of the model
123 		//FIXME: rotate mins and maxs
124 		AAS_BSPModelMinsMaxsOrigin(ent->i.modelindex, ent->i.angles, ent->i.mins, ent->i.maxs, NULL);
125 	} //end if
126 	else if (ent->i.solid == SOLID_BBOX)
127 	{
128 		//if the bounding box size changed
129 		if (!VectorCompare(state->mins, ent->i.mins) ||
130 				!VectorCompare(state->maxs, ent->i.maxs))
131 		{
132 			VectorCopy(state->mins, ent->i.mins);
133 			VectorCopy(state->maxs, ent->i.maxs);
134 			relink = qtrue;
135 		} //end if
136 		VectorCopy(state->angles, ent->i.angles);
137 	} //end if
138 	//if the origin changed
139 	if (!VectorCompare(state->origin, ent->i.origin))
140 	{
141 		VectorCopy(state->origin, ent->i.origin);
142 		relink = qtrue;
143 	} //end if
144 	//if the entity should be relinked
145 	if (relink)
146 	{
147 		//don't link the world model
148 		if (entnum != ENTITYNUM_WORLD)
149 		{
150 			//absolute mins and maxs
151 			VectorAdd(ent->i.mins, ent->i.origin, absmins);
152 			VectorAdd(ent->i.maxs, ent->i.origin, absmaxs);
153 			//unlink the entity
154 			AAS_UnlinkFromAreas(ent->areas);
155 			//relink the entity to the AAS areas (use the larges bbox)
156 			ent->areas = AAS_LinkEntityClientBBox(absmins, absmaxs, entnum, PRESENCE_NORMAL);
157 			//unlink the entity from the BSP leaves
158 			AAS_UnlinkFromBSPLeaves(ent->leaves);
159 			//link the entity to the world BSP tree
160 			ent->leaves = AAS_BSPLinkEntity(absmins, absmaxs, entnum, 0);
161 		} //end if
162 	} //end if
163 	return BLERR_NOERROR;
164 } //end of the function AAS_UpdateEntity
165 //===========================================================================
166 //
167 // Parameter:			-
168 // Returns:				-
169 // Changes Globals:		-
170 //===========================================================================
AAS_EntityInfo(int entnum,aas_entityinfo_t * info)171 void AAS_EntityInfo(int entnum, aas_entityinfo_t *info)
172 {
173 	if (!aasworld.initialized)
174 	{
175 		botimport.Print(PRT_FATAL, "AAS_EntityInfo: aasworld not initialized\n");
176 		Com_Memset(info, 0, sizeof(aas_entityinfo_t));
177 		return;
178 	} //end if
179 
180 	if (entnum < 0 || entnum >= aasworld.maxentities)
181 	{
182 		botimport.Print(PRT_FATAL, "AAS_EntityInfo: entnum %d out of range\n", entnum);
183 		Com_Memset(info, 0, sizeof(aas_entityinfo_t));
184 		return;
185 	} //end if
186 
187 	Com_Memcpy(info, &aasworld.entities[entnum].i, sizeof(aas_entityinfo_t));
188 } //end of the function AAS_EntityInfo
189 //===========================================================================
190 //
191 // Parameter:				-
192 // Returns:					-
193 // Changes Globals:		-
194 //===========================================================================
AAS_EntityOrigin(int entnum,vec3_t origin)195 void AAS_EntityOrigin(int entnum, vec3_t origin)
196 {
197 	if (entnum < 0 || entnum >= aasworld.maxentities)
198 	{
199 		botimport.Print(PRT_FATAL, "AAS_EntityOrigin: entnum %d out of range\n", entnum);
200 		VectorClear(origin);
201 		return;
202 	} //end if
203 
204 	VectorCopy(aasworld.entities[entnum].i.origin, origin);
205 } //end of the function AAS_EntityOrigin
206 //===========================================================================
207 //
208 // Parameter:				-
209 // Returns:					-
210 // Changes Globals:		-
211 //===========================================================================
AAS_EntityModelindex(int entnum)212 int AAS_EntityModelindex(int entnum)
213 {
214 	if (entnum < 0 || entnum >= aasworld.maxentities)
215 	{
216 		botimport.Print(PRT_FATAL, "AAS_EntityModelindex: entnum %d out of range\n", entnum);
217 		return 0;
218 	} //end if
219 	return aasworld.entities[entnum].i.modelindex;
220 } //end of the function AAS_EntityModelindex
221 //===========================================================================
222 //
223 // Parameter:				-
224 // Returns:					-
225 // Changes Globals:		-
226 //===========================================================================
AAS_EntityType(int entnum)227 int AAS_EntityType(int entnum)
228 {
229 	if (!aasworld.initialized) return 0;
230 
231 	if (entnum < 0 || entnum >= aasworld.maxentities)
232 	{
233 		botimport.Print(PRT_FATAL, "AAS_EntityType: entnum %d out of range\n", entnum);
234 		return 0;
235 	} //end if
236 	return aasworld.entities[entnum].i.type;
237 } //end of the AAS_EntityType
238 //===========================================================================
239 //
240 // Parameter:				-
241 // Returns:					-
242 // Changes Globals:		-
243 //===========================================================================
AAS_EntityModelNum(int entnum)244 int AAS_EntityModelNum(int entnum)
245 {
246 	if (!aasworld.initialized) return 0;
247 
248 	if (entnum < 0 || entnum >= aasworld.maxentities)
249 	{
250 		botimport.Print(PRT_FATAL, "AAS_EntityModelNum: entnum %d out of range\n", entnum);
251 		return 0;
252 	} //end if
253 	return aasworld.entities[entnum].i.modelindex;
254 } //end of the function AAS_EntityModelNum
255 //===========================================================================
256 //
257 // Parameter:				-
258 // Returns:					-
259 // Changes Globals:		-
260 //===========================================================================
AAS_OriginOfMoverWithModelNum(int modelnum,vec3_t origin)261 int AAS_OriginOfMoverWithModelNum(int modelnum, vec3_t origin)
262 {
263 	int i;
264 	aas_entity_t *ent;
265 
266 	for (i = 0; i < aasworld.maxentities; i++)
267 	{
268 		ent = &aasworld.entities[i];
269 		if (ent->i.type == ET_MOVER)
270 		{
271 			if (ent->i.modelindex == modelnum)
272 			{
273 				VectorCopy(ent->i.origin, origin);
274 				return qtrue;
275 			} //end if
276 		} //end if
277 	} //end for
278 	return qfalse;
279 } //end of the function AAS_OriginOfMoverWithModelNum
280 //===========================================================================
281 //
282 // Parameter:				-
283 // Returns:					-
284 // Changes Globals:		-
285 //===========================================================================
AAS_EntitySize(int entnum,vec3_t mins,vec3_t maxs)286 void AAS_EntitySize(int entnum, vec3_t mins, vec3_t maxs)
287 {
288 	aas_entity_t *ent;
289 
290 	if (!aasworld.initialized) return;
291 
292 	if (entnum < 0 || entnum >= aasworld.maxentities)
293 	{
294 		botimport.Print(PRT_FATAL, "AAS_EntitySize: entnum %d out of range\n", entnum);
295 		return;
296 	} //end if
297 
298 	ent = &aasworld.entities[entnum];
299 	VectorCopy(ent->i.mins, mins);
300 	VectorCopy(ent->i.maxs, maxs);
301 } //end of the function AAS_EntitySize
302 //===========================================================================
303 //
304 // Parameter:				-
305 // Returns:					-
306 // Changes Globals:		-
307 //===========================================================================
AAS_EntityBSPData(int entnum,bsp_entdata_t * entdata)308 void AAS_EntityBSPData(int entnum, bsp_entdata_t *entdata)
309 {
310 	aas_entity_t *ent;
311 
312 	ent = &aasworld.entities[entnum];
313 	VectorCopy(ent->i.origin, entdata->origin);
314 	VectorCopy(ent->i.angles, entdata->angles);
315 	VectorAdd(ent->i.origin, ent->i.mins, entdata->absmins);
316 	VectorAdd(ent->i.origin, ent->i.maxs, entdata->absmaxs);
317 	entdata->solid = ent->i.solid;
318 	entdata->modelnum = ent->i.modelindex - 1;
319 } //end of the function AAS_EntityBSPData
320 //===========================================================================
321 //
322 // Parameter:				-
323 // Returns:					-
324 // Changes Globals:		-
325 //===========================================================================
AAS_ResetEntityLinks(void)326 void AAS_ResetEntityLinks(void)
327 {
328 	int i;
329 	for (i = 0; i < aasworld.maxentities; i++)
330 	{
331 		aasworld.entities[i].areas = NULL;
332 		aasworld.entities[i].leaves = NULL;
333 	} //end for
334 } //end of the function AAS_ResetEntityLinks
335 //===========================================================================
336 //
337 // Parameter:				-
338 // Returns:					-
339 // Changes Globals:		-
340 //===========================================================================
AAS_InvalidateEntities(void)341 void AAS_InvalidateEntities(void)
342 {
343 	int i;
344 	for (i = 0; i < aasworld.maxentities; i++)
345 	{
346 		aasworld.entities[i].i.valid = qfalse;
347 		aasworld.entities[i].i.number = i;
348 	} //end for
349 } //end of the function AAS_InvalidateEntities
350 //===========================================================================
351 //
352 // Parameter:				-
353 // Returns:					-
354 // Changes Globals:		-
355 //===========================================================================
AAS_UnlinkInvalidEntities(void)356 void AAS_UnlinkInvalidEntities(void)
357 {
358 	int i;
359 	aas_entity_t *ent;
360 
361 	for (i = 0; i < aasworld.maxentities; i++)
362 	{
363 		ent = &aasworld.entities[i];
364 		if (!ent->i.valid)
365 		{
366 			AAS_UnlinkFromAreas( ent->areas );
367 			ent->areas = NULL;
368 			AAS_UnlinkFromBSPLeaves( ent->leaves );
369 			ent->leaves = NULL;
370 		} //end for
371 	} //end for
372 } //end of the function AAS_UnlinkInvalidEntities
373 //===========================================================================
374 //
375 // Parameter:				-
376 // Returns:					-
377 // Changes Globals:		-
378 //===========================================================================
AAS_NearestEntity(vec3_t origin,int modelindex)379 int AAS_NearestEntity(vec3_t origin, int modelindex)
380 {
381 	int i, bestentnum;
382 	float dist, bestdist;
383 	aas_entity_t *ent;
384 	vec3_t dir;
385 
386 	bestentnum = 0;
387 	bestdist = 99999;
388 	for (i = 0; i < aasworld.maxentities; i++)
389 	{
390 		ent = &aasworld.entities[i];
391 		if (ent->i.modelindex != modelindex) continue;
392 		VectorSubtract(ent->i.origin, origin, dir);
393 		if (abs(dir[0]) < 40)
394 		{
395 			if (abs(dir[1]) < 40)
396 			{
397 				dist = VectorLength(dir);
398 				if (dist < bestdist)
399 				{
400 					bestdist = dist;
401 					bestentnum = i;
402 				} //end if
403 			} //end if
404 		} //end if
405 	} //end for
406 	return bestentnum;
407 } //end of the function AAS_NearestEntity
408 //===========================================================================
409 //
410 // Parameter:				-
411 // Returns:					-
412 // Changes Globals:		-
413 //===========================================================================
AAS_BestReachableEntityArea(int entnum)414 int AAS_BestReachableEntityArea(int entnum)
415 {
416 	aas_entity_t *ent;
417 
418 	ent = &aasworld.entities[entnum];
419 	return AAS_BestReachableLinkArea(ent->areas);
420 } //end of the function AAS_BestReachableEntityArea
421 //===========================================================================
422 //
423 // Parameter:			-
424 // Returns:				-
425 // Changes Globals:		-
426 //===========================================================================
AAS_NextEntity(int entnum)427 int AAS_NextEntity(int entnum)
428 {
429 	if (!aasworld.loaded) return 0;
430 
431 	if (entnum < 0) entnum = -1;
432 	while(++entnum < aasworld.maxentities)
433 	{
434 		if (aasworld.entities[entnum].i.valid) return entnum;
435 	} //end while
436 	return 0;
437 } //end of the function AAS_NextEntity
438