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