1 /*
2 	world.c
3 
4 	world query functions
5 
6 	Copyright (C) 1996-1997  Id Software, Inc.
7 
8 	This program is free software; you can redistribute it and/or
9 	modify it under the terms of the GNU General Public License
10 	as published by the Free Software Foundation; either version 2
11 	of the License, or (at your option) any later version.
12 
13 	This program is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 	See the 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, write to:
21 
22 		Free Software Foundation, Inc.
23 		59 Temple Place - Suite 330
24 		Boston, MA  02111-1307, USA
25 
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #endif
34 #ifdef HAVE_STRINGS_H
35 # include <strings.h>
36 #endif
37 
38 #include <stdio.h>
39 
40 #include "QF/clip_hull.h"
41 #include "QF/console.h"
42 #include "QF/crc.h"
43 #include "QF/sys.h"
44 
45 #include "compat.h"
46 #include "server.h"
47 #include "sv_progs.h"
48 #include "world.h"
49 
50 #define always_inline inline __attribute__((__always_inline__))
51 
52 #define EDICT_LEAFS 32
53 typedef struct edict_leaf_bucket_s {
54 	struct edict_leaf_bucket_s *next;
55 	edict_leaf_t edict_leafs[EDICT_LEAFS];
56 } edict_leaf_bucket_t;
57 
58 static edict_leaf_bucket_t *edict_leaf_buckets;
59 static edict_leaf_bucket_t **edict_leaf_bucket_tail = &edict_leaf_buckets;
60 static edict_leaf_t *free_edict_leaf_list;
61 
62 static edict_leaf_t *
alloc_edict_leaf(void)63 alloc_edict_leaf (void)
64 {
65 	edict_leaf_bucket_t *bucket;
66 	edict_leaf_t *el;
67 	int         i;
68 
69 	if ((el = free_edict_leaf_list)) {
70 		free_edict_leaf_list = el->next;
71 		el->next = 0;
72 		return el;
73 	}
74 
75 	bucket = malloc (sizeof (edict_leaf_bucket_t));
76 	bucket->next = 0;
77 	*edict_leaf_bucket_tail = bucket;
78 	edict_leaf_bucket_tail = &bucket->next;
79 
80 	for (el = bucket->edict_leafs, i = 0; i < EDICT_LEAFS - 1; i++, el++)
81 		el->next = el + 1;
82 	el->next = 0;
83 	free_edict_leaf_list = bucket->edict_leafs;
84 
85 	return alloc_edict_leaf ();
86 }
87 
88 static void
free_edict_leafs(edict_leaf_t ** edict_leafs)89 free_edict_leafs (edict_leaf_t **edict_leafs)
90 {
91 	edict_leaf_t **el;
92 
93 	for (el = edict_leafs; *el; el = &(*el)->next)
94 		;
95 	*el = free_edict_leaf_list;
96 	free_edict_leaf_list = *edict_leafs;
97 	*edict_leafs = 0;
98 }
99 
100 void
SV_FreeAllEdictLeafs(void)101 SV_FreeAllEdictLeafs (void)
102 {
103 	edict_leaf_bucket_t *bucket;
104 	edict_leaf_t *el;
105 	int         i;
106 
107 	for (bucket = edict_leaf_buckets; bucket; bucket = bucket->next) {
108 		for (el = bucket->edict_leafs, i = 0; i < EDICT_LEAFS - 1; i++, el++)
109 			el->next = el + 1;
110 		el->next = bucket->next ? bucket->next->edict_leafs : 0;
111 	}
112 	free_edict_leaf_list = 0;
113 	if (edict_leaf_buckets)
114 		free_edict_leaf_list = edict_leaf_buckets->edict_leafs;
115 }
116 
117 /*
118 	entities never clip against themselves, or their owner
119 	line of sight checks trace->crosscontent, but bullets don't
120 */
121 
122 typedef struct {
123 	vec3_t       boxmins, boxmaxs;		// enclose the test object along
124 										// entire move
125 	const float *mins, *maxs;			// size of the moving object
126 	vec3_t       mins2, maxs2;			// size when clipping against
127 										// monsters
128 	const float *start, *end;
129 	trace_t      trace;
130 	int          type;
131 	edict_t     *passedict;
132 } moveclip_t;
133 
134 /* HULL BOXES */
135 
136 static hull_t box_hull;
137 static mclipnode_t box_clipnodes[6];
138 static plane_t box_planes[6];
139 
140 
141 /*
142 	SV_InitHull SV_InitBoxHull
143 
144 	Set up the planes and clipnodes so that the six floats of a bounding box
145 	can just be stored out and get a proper hull_t structure.
146 */
147 void
SV_InitHull(hull_t * hull,mclipnode_t * clipnodes,plane_t * planes)148 SV_InitHull (hull_t *hull, mclipnode_t *clipnodes, plane_t *planes)
149 {
150 	int			side, i;
151 
152 	hull->clipnodes = clipnodes;
153 	hull->planes = planes;
154 	hull->firstclipnode = 0;
155 	hull->lastclipnode = 5;
156 	hull->depth = 6;
157 
158 	for (i = 0; i < 6; i++) {
159 		hull->clipnodes[i].planenum = i;
160 
161 		side = i & 1;
162 
163 		hull->clipnodes[i].children[side] = CONTENTS_EMPTY;
164 		if (i != 5)
165 			hull->clipnodes[i].children[side ^ 1] = i + 1;
166 		else
167 			hull->clipnodes[i].children[side ^ 1] = CONTENTS_SOLID;
168 
169 		hull->planes[i].type = i >> 1;
170 		hull->planes[i].normal[i >> 1] = 1;
171 	}
172 }
173 
174 static inline void
SV_InitBoxHull(void)175 SV_InitBoxHull (void)
176 {
177 	SV_InitHull (&box_hull, box_clipnodes, box_planes);
178 }
179 
180 /*
181 	SV_HullForBox
182 
183 	To keep everything totally uniform, bounding boxes are turned into small
184 	BSP trees instead of being compared directly.
185 */
186 static inline hull_t *
SV_HullForBox(const vec3_t mins,const vec3_t maxs)187 SV_HullForBox (const vec3_t mins, const vec3_t maxs)
188 {
189 	box_planes[0].dist = maxs[0];
190 	box_planes[1].dist = mins[0];
191 	box_planes[2].dist = maxs[1];
192 	box_planes[3].dist = mins[1];
193 	box_planes[4].dist = maxs[2];
194 	box_planes[5].dist = mins[2];
195 
196 	return &box_hull;
197 }
198 
199 /*
200 	SV_HullForEntity
201 
202 	Returns a hull that can be used for testing or clipping an object of
203 	mins/maxs size.  Offset is filled in to contain the adjustment that
204 	must be added to the testing object's origin to get a point to use with
205 	the returned hull.
206 */
207 hull_t *
SV_HullForEntity(edict_t * ent,const vec3_t mins,const vec3_t maxs,vec3_t extents,vec3_t offset)208 SV_HullForEntity (edict_t *ent, const vec3_t mins, const vec3_t maxs,
209 				  vec3_t extents, vec3_t offset)
210 {
211 	int         hull_index = 0;
212 	hull_t     *hull = 0, **hull_list = 0;
213 	model_t    *model;
214 	vec3_t      hullmins, hullmaxs, size;
215 
216 	if ((sv_fields.rotated_bbox != -1
217 		 && SVinteger (ent, rotated_bbox))
218 		|| SVfloat (ent, solid) == SOLID_BSP) {
219 		VectorSubtract (maxs, mins, size);
220 		if (size[0] < 3)
221 			hull_index = 0;
222 		else if (size[0] <= 32)
223 			hull_index = 1;
224 		else
225 			hull_index = 2;
226 	}
227 	if (sv_fields.rotated_bbox != -1
228 		&& SVinteger (ent, rotated_bbox)) {
229 		int h = SVinteger (ent, rotated_bbox) - 1;
230 		hull_list = pf_hull_list[h]->hulls;
231 	} if (SVfloat (ent, solid) == SOLID_BSP) {
232 		// explicit hulls in the BSP model
233 		if (SVfloat (ent, movetype) != MOVETYPE_PUSH)
234 			Sys_Error ("SOLID_BSP without MOVETYPE_PUSH: %d %s",
235 					   NUM_FOR_EDICT (&sv_pr_state, ent),
236 					   PR_GetString (&sv_pr_state,
237 						   			 SVstring (ent, classname)));
238 
239 		model = sv.models[(int) SVfloat (ent, modelindex)];
240 
241 		if (!model || model->type != mod_brush)
242 			Sys_Error ("SOLID_BSP with a non bsp model: %d %s",
243 					   NUM_FOR_EDICT (&sv_pr_state, ent),
244 					   PR_GetString (&sv_pr_state,
245 						   			 SVstring (ent, classname)));
246 
247 		hull_list = model->hull_list;
248 	}
249 	if (hull_list) {
250 		// decide which clipping hull to use, based on the size
251 		VectorSubtract (maxs, mins, size);
252 		if (extents) {
253 			VectorScale (size, 0.5, extents);
254 		} else {
255 			if (size[0] < 3)
256 				hull_index = 0;
257 			else if (size[0] <= 32)
258 				hull_index = 1;
259 			else
260 				hull_index = 2;
261 		}
262 		hull = hull_list[hull_index];
263 	}
264 
265 	if (hull) {
266 		// calculate an offset value to center the origin
267 		if (extents) {
268 			VectorAdd (extents, mins, offset);
269 			VectorSubtract (SVvector (ent, origin), offset, offset);
270 		} else {
271 			VectorSubtract (hull->clip_mins, mins, offset);
272 			VectorAdd (offset, SVvector (ent, origin), offset);
273 		}
274 	} else {
275 		// create a temp hull from bounding box sizes
276 		if (extents) {
277 			VectorCopy (SVvector (ent, mins), hullmins);
278 			VectorCopy (SVvector (ent, maxs), hullmaxs);
279 
280 			//FIXME broken for map models (ie, origin always 0, 0, 0)
281 			VectorAdd (extents, mins, offset);
282 			VectorSubtract (SVvector (ent, origin), offset, offset);
283 		} else {
284 			VectorSubtract (SVvector (ent, mins), maxs, hullmins);
285 			VectorSubtract (SVvector (ent, maxs), mins, hullmaxs);
286 
287 			VectorCopy (SVvector (ent, origin), offset);
288 		}
289 		hull = SV_HullForBox (hullmins, hullmaxs);
290 	}
291 
292 	return hull;
293 }
294 
295 /* ENTITY AREA CHECKING */
296 
297 areanode_t  sv_areanodes[AREA_NODES];
298 int         sv_numareanodes;
299 
300 static areanode_t *
SV_CreateAreaNode(int depth,const vec3_t mins,const vec3_t maxs)301 SV_CreateAreaNode (int depth, const vec3_t mins, const vec3_t maxs)
302 {
303 	areanode_t *anode;
304 	vec3_t      mins1, maxs1, mins2, maxs2, size;
305 
306 	anode = &sv_areanodes[sv_numareanodes];
307 	sv_numareanodes++;
308 
309 	ClearLink (&anode->trigger_edicts);
310 	ClearLink (&anode->solid_edicts);
311 
312 	if (depth == AREA_DEPTH) {
313 		anode->axis = -1;
314 		anode->children[0] = anode->children[1] = NULL;
315 		return anode;
316 	}
317 
318 	VectorSubtract (maxs, mins, size);
319 	if (size[0] > size[1])
320 		anode->axis = 0;
321 	else
322 		anode->axis = 1;
323 
324 	anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
325 	VectorCopy (mins, mins1);
326 	VectorCopy (mins, mins2);
327 	VectorCopy (maxs, maxs1);
328 	VectorCopy (maxs, maxs2);
329 
330 	maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
331 
332 	anode->children[0] = SV_CreateAreaNode (depth + 1, mins2, maxs2);
333 	anode->children[1] = SV_CreateAreaNode (depth + 1, mins1, maxs1);
334 
335 	return anode;
336 }
337 
338 void
SV_ClearWorld(void)339 SV_ClearWorld (void)
340 {
341 	SV_InitBoxHull ();
342 
343 	memset (sv_areanodes, 0, sizeof (sv_areanodes));
344 	sv_numareanodes = 0;
345 	SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs);
346 }
347 
348 link_t        **sv_link_next;
349 link_t        **sv_link_prev;
350 
351 void
SV_UnlinkEdict(edict_t * ent)352 SV_UnlinkEdict (edict_t *ent)
353 {
354 	free_edict_leafs (&SVdata (ent)->leafs);
355 	if (!SVdata (ent)->area.prev)
356 		return;							// not linked in anywhere
357 	RemoveLink (&SVdata (ent)->area);
358 	if (sv_link_next && *sv_link_next == &SVdata (ent)->area)
359 		*sv_link_next = SVdata (ent)->area.next;
360 	if (sv_link_prev && *sv_link_prev == &SVdata (ent)->area)
361 		*sv_link_prev = SVdata (ent)->area.prev;
362 	SVdata (ent)->area.prev = SVdata (ent)->area.next = NULL;
363 }
364 
365 static void
SV_TouchLinks(edict_t * ent,areanode_t * node)366 SV_TouchLinks (edict_t *ent, areanode_t *node)
367 {
368 	int         old_self, old_other;
369 	edict_t    *touch;
370 	link_t     *l, *next;
371 
372 	// touch linked edicts
373 	sv_link_next = &next;
374 	for (l = node->trigger_edicts.next; l != &node->trigger_edicts; l = next) {
375 		next = l->next;
376 		touch = EDICT_FROM_AREA (l);
377 		if (touch == ent)
378 			continue;
379 		if (!SVfunc (touch, touch)
380 			|| SVfloat (touch, solid) != SOLID_TRIGGER)
381 			continue;
382 		if (SVvector (ent, absmin)[0] > SVvector (touch, absmax)[0]
383 			|| SVvector (ent, absmin)[1] > SVvector (touch, absmax)[1]
384 			|| SVvector (ent, absmin)[2] > SVvector (touch, absmax)[2]
385 			|| SVvector (ent, absmax)[0] < SVvector (touch, absmin)[0]
386 			|| SVvector (ent, absmax)[1] < SVvector (touch, absmin)[1]
387 			|| SVvector (ent, absmax)[2] < SVvector (touch, absmin)[2])
388 			continue;
389 
390 		old_self = *sv_globals.self;
391 		old_other = *sv_globals.other;
392 
393 		*sv_globals.time = sv.time;
394 		sv_pr_touch (touch, ent);
395 
396 		*sv_globals.self = old_self;
397 		*sv_globals.other = old_other;
398 	}
399 	sv_link_next = 0;
400 
401 	// recurse down both sides
402 	if (node->axis == -1)
403 		return;
404 
405 	if (SVvector (ent, absmax)[node->axis] > node->dist)
406 		SV_TouchLinks (ent, node->children[0]);
407 	if (SVvector (ent, absmin)[node->axis] < node->dist)
408 		SV_TouchLinks (ent, node->children[1]);
409 }
410 
411 static void
SV_FindTouchedLeafs(edict_t * ent,mnode_t * node)412 SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)
413 {
414 	int			sides;
415 	mleaf_t    *leaf;
416 	plane_t    *splitplane;
417 	edict_leaf_t *edict_leaf;
418 
419 	if (node->contents == CONTENTS_SOLID)
420 		return;
421 
422 	// add an efrag if the node is a leaf
423 	if (node->contents < 0) {
424 		leaf = (mleaf_t *) node;
425 
426 		edict_leaf = alloc_edict_leaf ();
427 		edict_leaf->leafnum = leaf - sv.worldmodel->leafs - 1;
428 		edict_leaf->next = SVdata (ent)->leafs;
429 		SVdata (ent)->leafs = edict_leaf;
430 		return;
431 	}
432 
433 	// NODE_MIXED
434 	splitplane = node->plane;
435 	sides = BOX_ON_PLANE_SIDE (SVvector (ent, absmin),
436 							   SVvector (ent, absmax), splitplane);
437 
438 	// recurse down the contacted sides
439 	if (sides & 1)
440 		SV_FindTouchedLeafs (ent, node->children[0]);
441 
442 	if (sides & 2)
443 		SV_FindTouchedLeafs (ent, node->children[1]);
444 }
445 
446 void
SV_LinkEdict(edict_t * ent,qboolean touch_triggers)447 SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
448 {
449 	areanode_t *node;
450 
451 	if (SVdata (ent)->area.prev)
452 		SV_UnlinkEdict (ent);			// unlink from old position
453 
454 	if (ent == sv.edicts)
455 		return;							// don't add the world
456 	if (ent->free)
457 		return;
458 
459 	if (SVfloat (ent, solid) == SOLID_BSP
460 		&& !VectorIsZero (SVvector (ent, angles)) && ent != sv.edicts) {
461 		float       m, v;
462 		vec3_t      r;
463 		m = DotProduct (SVvector (ent, mins), SVvector (ent, mins));
464 		v = DotProduct (SVvector (ent, maxs), SVvector (ent, maxs));
465 		if (m < v)
466 			m = v;
467 		m = sqrt (m);
468 		VectorSet (m, m, m, r);
469 		VectorSubtract (SVvector (ent, origin), r, SVvector (ent, absmin));
470 		VectorAdd (SVvector (ent, origin), r, SVvector (ent, absmax));
471 	} else {
472 		// set the abs box
473 		VectorAdd (SVvector (ent, origin), SVvector (ent, mins),
474 				   SVvector (ent, absmin));
475 		VectorAdd (SVvector (ent, origin), SVvector (ent, maxs),
476 				   SVvector (ent, absmax));
477 	}
478 
479 	// to make items easier to pick up and allow them to be grabbed off
480 	// of shelves, the abs sizes are expanded
481 	if ((int) SVfloat (ent, flags) & FL_ITEM) {
482 		SVvector (ent, absmin)[0] -= 15;
483 		SVvector (ent, absmin)[1] -= 15;
484 		SVvector (ent, absmax)[0] += 15;
485 		SVvector (ent, absmax)[1] += 15;
486 	} else {	// movement is clipped an epsilon away from actual edge, so we
487 				// must fully check even when bounding boxes don't quite touch
488 		SVvector (ent, absmin)[0] -= 1;
489 		SVvector (ent, absmin)[1] -= 1;
490 		SVvector (ent, absmin)[2] -= 1;
491 		SVvector (ent, absmax)[0] += 1;
492 		SVvector (ent, absmax)[1] += 1;
493 		SVvector (ent, absmax)[2] += 1;
494 	}
495 
496 	// link to PVS leafs
497 	free_edict_leafs (&SVdata (ent)->leafs);
498 	if (SVfloat (ent, modelindex))
499 		SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);
500 
501 	if (SVfloat (ent, solid) == SOLID_NOT)
502 		return;
503 
504 	// find the first node that the ent's box crosses
505 	node = sv_areanodes;
506 	while (1) {
507 		if (node->axis == -1)
508 			break;
509 		if (SVvector (ent, absmin)[node->axis] > node->dist)
510 			node = node->children[0];
511 		else if (SVvector (ent, absmax)[node->axis] < node->dist)
512 			node = node->children[1];
513 		else
514 			break;						// crosses the node
515 	}
516 
517 	// link it in
518 	if (SVfloat (ent, solid) == SOLID_TRIGGER)
519 		InsertLinkBefore (&SVdata (ent)->area, &node->trigger_edicts);
520 	else
521 		InsertLinkBefore (&SVdata (ent)->area, &node->solid_edicts);
522 
523 	// if touch_triggers, touch all entities at this node and descend for more
524 	if (touch_triggers)
525 		SV_TouchLinks (ent, sv_areanodes);
526 }
527 
528 /* POINT TESTING IN HULLS */
529 
530 int
SV_HullPointContents(hull_t * hull,int num,const vec3_t p)531 SV_HullPointContents (hull_t *hull, int num, const vec3_t p)
532 {
533 	float        d;
534 	mclipnode_t *node;
535 	plane_t     *plane;
536 
537 	while (num >= 0) {
538 		//if (num < hull->firstclipnode || num > hull->lastclipnode)
539 		//	Sys_Error ("SV_HullPointContents: bad node number");
540 
541 		node = hull->clipnodes + num;
542 		plane = hull->planes + node->planenum;
543 
544 		if (plane->type < 3)
545 			d = p[plane->type] - plane->dist;
546 		else
547 			d = DotProduct (plane->normal, p) - plane->dist;
548 		if (d < 0)
549 			num = node->children[1];
550 		else
551 			num = node->children[0];
552 	}
553 
554 	return num;
555 }
556 
557 int
SV_PointContents(const vec3_t p)558 SV_PointContents (const vec3_t p)
559 {
560 	int         cont;
561 
562 	cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
563 	if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)
564 		cont = CONTENTS_WATER;
565 	return cont;
566 }
567 
568 int
SV_TruePointContents(const vec3_t p)569 SV_TruePointContents (const vec3_t p)
570 {
571 	return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
572 }
573 
574 /*
575 	SV_TestEntityPosition
576 
577 	This could be a lot more efficient...
578 	A small wrapper around SV_BoxInSolidEntity that never clips against the
579 	supplied entity.
580 */
581 edict_t *
SV_TestEntityPosition(edict_t * ent)582 SV_TestEntityPosition (edict_t *ent)
583 {
584 	trace_t		trace;
585 
586 	trace =	SV_Move (SVvector (ent, origin),
587 					 SVvector (ent, mins),
588 					 SVvector (ent, maxs),
589 					 SVvector (ent, origin), 0, ent);
590 
591 	if (trace.startsolid)
592 		return sv.edicts;
593 	return NULL;
594 }
595 
596 /*
597 	SV_ClipMoveToEntity
598 
599 	Handles selection or creation of a clipping hull, and offseting (and
600 	eventually rotation) of the end points
601 */
602 static trace_t
SV_ClipMoveToEntity(edict_t * touched,const vec3_t start,const vec3_t mins,const vec3_t maxs,const vec3_t end)603 SV_ClipMoveToEntity (edict_t *touched, const vec3_t start,
604 					 const vec3_t mins, const vec3_t maxs, const vec3_t end)
605 {
606 	hull_t     *hull;
607 	trace_t     trace;
608 	vec3_t      offset, start_l, end_l;
609 	vec3_t      forward, right, up;
610 	int         rot = 0;
611 	vec3_t      temp;
612 
613 	// fill in a default trace
614 	memset (&trace, 0, sizeof (trace_t));
615 
616 	trace.fraction = 1;
617 	trace.allsolid = true;
618 	trace.type = tr_point;
619 	VectorCopy (end, trace.endpos);
620 
621 	// get the clipping hull
622 	hull = SV_HullForEntity (touched, mins, maxs,
623 							 trace.type != tr_point ? trace.extents : 0,
624 							 offset);
625 
626 	VectorSubtract (start, offset, start_l);
627 	VectorSubtract (end, offset, end_l);
628 
629 	if (SVfloat (touched, solid) == SOLID_BSP
630 		&& !VectorIsZero (SVvector (touched, angles))
631 		&& touched != sv.edicts) {
632 		rot = 1;
633 		AngleVectors (SVvector (touched, angles), forward, right, up);
634 		VectorNegate (right, right);	// convert lhs to rhs
635 
636 		VectorCopy (start_l, temp);
637 		start_l[0] = DotProduct (temp, forward);
638 		start_l[1] = DotProduct (temp, right);
639 		start_l[2] = DotProduct (temp, up);
640 
641 		VectorCopy (end_l, temp);
642 		end_l[0] = DotProduct (temp, forward);
643 		end_l[1] = DotProduct (temp, right);
644 		end_l[2] = DotProduct (temp, up);
645 	}
646 
647 	// trace a line through the apropriate clipping hull
648 	MOD_TraceLine (hull, hull->firstclipnode, start_l, end_l, &trace);
649 
650 	// fix up trace by the rotation and offset
651 	if (trace.fraction != 1) {
652 		if (rot) {
653 			vec_t       t;
654 
655 			// transpose the rotation matrix to get its inverse
656 			t = forward[1]; forward[1] = right[0]; right[0] = t;
657 			t = forward[2]; forward[2] = up[0]; up[0] = t;
658 			t = right[2]; right[2] = up[1]; up[1] = t;
659 
660 			VectorCopy (trace.endpos, temp);
661 			trace.endpos[0] = DotProduct (temp, forward);
662 			trace.endpos[1] = DotProduct (temp, right);
663 			trace.endpos[2] = DotProduct (temp, up);
664 
665 			VectorCopy (trace.plane.normal, temp);
666 			trace.plane.normal[0] = DotProduct (temp, forward);
667 			trace.plane.normal[1] = DotProduct (temp, right);
668 			trace.plane.normal[2] = DotProduct (temp, up);
669 		}
670 		VectorAdd (trace.endpos, offset, trace.endpos);
671 	}
672 
673 	// did we clip the move?
674 	if (trace.fraction < 1 || trace.startsolid)
675 		trace.ent = touched;
676 
677 	return trace;
678 }
679 
680 static always_inline int
ctl_pretest_everything(edict_t * touch,moveclip_t * clip)681 ctl_pretest_everything (edict_t *touch, moveclip_t *clip)
682 {
683 	if (touch->free)
684 		return 0;
685 	if (!((int) SVfloat (touch, flags) & FL_FINDABLE_NONSOLID)) {
686 		if (SVfloat (touch, solid) == SOLID_NOT)
687 			return 0;
688 		if (SVfloat (touch, solid) == SOLID_TRIGGER)
689 			return 0;
690 	}
691 	if (touch == clip->passedict)
692 		return 0;
693 	return 1;
694 }
695 
696 static always_inline int
ctl_pretest_triggers(edict_t * touch,moveclip_t * clip)697 ctl_pretest_triggers (edict_t *touch, moveclip_t *clip)
698 {
699 	if (SVfloat (touch, solid) != SOLID_TRIGGER)
700 		return 0;
701 	if (!((int) SVfloat (touch, flags) & FL_FINDABLE_NONSOLID))
702 		return 0;
703 	if (touch == clip->passedict)
704 		return 0;
705 	return 1;
706 }
707 
708 static always_inline int
ctl_pretest_other(edict_t * touch,moveclip_t * clip)709 ctl_pretest_other (edict_t *touch, moveclip_t *clip)
710 {
711 	if (SVfloat (touch, solid) == SOLID_NOT)
712 		return 0;
713 	if (touch == clip->passedict)
714 		return 0;
715 	if (SVfloat (touch, solid) == SOLID_TRIGGER)
716 		Sys_Error ("Trigger in clipping list");
717 
718 	if (clip->type == MOVE_NOMONSTERS && SVfloat (touch, solid) != SOLID_BSP)
719 		return 0;
720 	return 1;
721 }
722 
723 static always_inline int
ctl_pretest_lagged(edict_t * touch,moveclip_t * clip)724 ctl_pretest_lagged (edict_t *touch, moveclip_t *clip)
725 {
726 	if (clip->type & MOVE_LAGGED)
727 		if ((unsigned) (touch->entnum - 1) < sv.maxlagents)
728 			if (sv.lagents[touch->entnum - 1].present)
729 				return 0;
730 	return 1;
731 }
732 
733 static always_inline int
ctl_touch_common(edict_t * touch,moveclip_t * clip)734 ctl_touch_common (edict_t *touch, moveclip_t *clip)
735 {
736 	if (clip->passedict && SVvector (clip->passedict, size)[0]
737 		&& !SVvector (touch, size)[0])
738 		return 0;						// points never interact
739 
740 	// might intersect, so do an exact clip
741 	if (clip->passedict) {
742 		if (PROG_TO_EDICT (&sv_pr_state, SVentity (touch, owner))
743 			== clip->passedict)
744 			return 0;					// don't clip against own missiles
745 		if (PROG_TO_EDICT (&sv_pr_state,
746 						   SVentity (clip->passedict, owner)) == touch)
747 			return 0;					// don't clip against owner
748 	}
749 	return 1;
750 }
751 
752 static always_inline int
ctl_touch_test(edict_t * touch,moveclip_t * clip)753 ctl_touch_test (edict_t *touch, moveclip_t *clip)
754 {
755 	if (clip->boxmins[0] > SVvector (touch, absmax)[0]
756 		|| clip->boxmins[1] > SVvector (touch, absmax)[1]
757 		|| clip->boxmins[2] > SVvector (touch, absmax)[2]
758 		|| clip->boxmaxs[0] < SVvector (touch, absmin)[0]
759 		|| clip->boxmaxs[1] < SVvector (touch, absmin)[1]
760 		|| clip->boxmaxs[2] < SVvector (touch, absmin)[2])
761 		return 0;
762 
763 	return ctl_touch_common (touch, clip);
764 }
765 
766 static always_inline int
ctl_touch_test_origin(edict_t * touch,const vec3_t origin,moveclip_t * clip)767 ctl_touch_test_origin (edict_t *touch, const vec3_t origin, moveclip_t *clip)
768 {
769 	if (clip->boxmins[0] > origin[0] + SVvector (touch, maxs)[0]
770 		|| clip->boxmins[1] > origin[1] + SVvector (touch, maxs)[1]
771 		|| clip->boxmins[2] > origin[2] + SVvector (touch, maxs)[2]
772 		|| clip->boxmaxs[0] < origin[0] + SVvector (touch, mins)[0]
773 		|| clip->boxmaxs[1] < origin[1] + SVvector (touch, mins)[1]
774 		|| clip->boxmaxs[2] < origin[2] + SVvector (touch, mins)[2])
775 		return 0;
776 
777 	return ctl_touch_common (touch, clip);
778 }
779 
780 static void
ctl_do_clip(edict_t * touch,moveclip_t * clip,trace_t * trace)781 ctl_do_clip (edict_t *touch, moveclip_t *clip, trace_t *trace)
782 {
783 	if ((int) SVfloat (touch, flags) & FL_MONSTER)
784 		*trace = SV_ClipMoveToEntity (touch, clip->start,
785 									  clip->mins2, clip->maxs2, clip->end);
786 	else
787 		*trace = SV_ClipMoveToEntity (touch, clip->start,
788 									  clip->mins, clip->maxs, clip->end);
789 	if (trace->allsolid || trace->startsolid
790 		|| trace->fraction < clip->trace.fraction) {
791 		trace->ent = touch;
792 		if (clip->type & MOVE_ENTCHAIN) {
793 			SVentity (touch, chain) = EDICT_TO_PROG (&sv_pr_state,
794 													 clip->trace.ent
795 														? clip->trace.ent
796 														: sv.edicts);
797 			clip->trace.ent = touch;
798 		} else {
799 			if (clip->trace.startsolid) {
800 				clip->trace = *trace;
801 				clip->trace.startsolid = true;
802 			} else {
803 				clip->trace = *trace;
804 			}
805 		}
806 	}
807 }
808 
809 /*
810 	SV_ClipToLinks
811 
812 	Mins and maxs enclose the entire area swept by the move
813 */
814 static void
SV_ClipToLinks(areanode_t * node,moveclip_t * clip)815 SV_ClipToLinks (areanode_t *node, moveclip_t *clip)
816 {
817 	edict_t    *touch;
818 	link_t     *l, *next;
819 	trace_t		trace;
820 	int         i;
821 
822 	if (clip->type & MOVE_EVERYTHING) {
823 		touch = NEXT_EDICT (&sv_pr_state, sv.edicts);
824 		for (i = 1; i < sv.num_edicts; i++,
825 			 touch = NEXT_EDICT (&sv_pr_state, touch)) {
826 			if (clip->trace.allsolid)
827 				return;
828 			if (!ctl_pretest_everything (touch, clip))
829 				continue;
830 			if (!ctl_pretest_lagged (touch, clip))
831 				continue;
832 			if (!ctl_touch_test (touch, clip))
833 				continue;
834 			ctl_do_clip (touch, clip, &trace);
835 		}
836 	} else if (clip->type & MOVE_TRIGGERS) {
837 		for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) {
838 			next = l->next;
839 			touch = EDICT_FROM_AREA (l);
840 
841 			if (clip->trace.allsolid)
842 				return;
843 			if (!ctl_pretest_triggers (touch, clip))
844 				continue;
845 			if (!ctl_pretest_lagged (touch, clip))
846 				continue;
847 			if (!ctl_touch_test (touch, clip))
848 				continue;
849 			ctl_do_clip (touch, clip, &trace);
850 		}
851 	} else {
852 		// touch linked edicts
853 		for (l = node->solid_edicts.next; l != &node->solid_edicts; l = next) {
854 			next = l->next;
855 			touch = EDICT_FROM_AREA (l);
856 
857 			if (clip->trace.allsolid)
858 				return;
859 			if (!ctl_pretest_other (touch, clip))
860 				continue;
861 			if (!ctl_pretest_lagged (touch, clip))
862 				continue;
863 			if (!ctl_touch_test (touch, clip))
864 				continue;
865 			ctl_do_clip (touch, clip, &trace);
866 		}
867 	}
868 
869 	// recurse down both sides
870 	if (node->axis == -1)
871 		return;
872 
873 	if (clip->boxmaxs[node->axis] > node->dist)
874 		SV_ClipToLinks (node->children[0], clip);
875 	if (clip->boxmins[node->axis] < node->dist)
876 		SV_ClipToLinks (node->children[1], clip);
877 }
878 
879 static inline void
SV_MoveBounds(const vec3_t start,const vec3_t mins,const vec3_t maxs,const vec3_t end,vec3_t boxmins,vec3_t boxmaxs)880 SV_MoveBounds (const vec3_t start, const vec3_t mins, const vec3_t maxs,
881 			   const vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
882 {
883 #if 0
884 	// debug to test against everything
885 	boxmins[0] = boxmins[1] = boxmins[2] = -9999;
886 	boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
887 #else
888 	int			i;
889 
890 	for (i = 0; i < 3; i++) {
891 		if (end[i] > start[i]) {
892 			boxmins[i] = start[i] + mins[i] - 1;
893 			boxmaxs[i] = end[i] + maxs[i] + 1;
894 		} else {
895 			boxmins[i] = end[i] + mins[i] - 1;
896 			boxmaxs[i] = start[i] + maxs[i] + 1;
897 		}
898 	}
899 #endif
900 }
901 
902 trace_t
SV_Move(const vec3_t start,const vec3_t mins,const vec3_t maxs,const vec3_t end,int type,edict_t * passedict)903 SV_Move (const vec3_t start, const vec3_t mins, const vec3_t maxs,
904 		 const vec3_t end, int type, edict_t *passedict)
905 {
906 	int			i;
907 	moveclip_t  clip;
908 
909 	memset (&clip, 0, sizeof (moveclip_t));
910 
911 	// clip to world
912 	clip.trace = SV_ClipMoveToEntity (sv.edicts, start, mins, maxs, end);
913 	clip.start = start;
914 	clip.end = end;
915 	clip.mins = mins;
916 	clip.maxs = maxs;
917 	clip.type = type;
918 	clip.passedict = passedict;
919 
920 	if (type == MOVE_MISSILE) {
921 		for (i = 0; i < 3; i++) {
922 			clip.mins2[i] = -15;
923 			clip.maxs2[i] = 15;
924 		}
925 	} else {
926 		VectorCopy (mins, clip.mins2);
927 		VectorCopy (maxs, clip.maxs2);
928 	}
929 
930 	// create the bounding box of the entire move
931 	SV_MoveBounds (start, clip.mins2, clip.maxs2, end, clip.boxmins,
932 				   clip.boxmaxs);
933 
934 	// clip to entities
935 	if (clip.type & MOVE_LAGGED) {
936 		clip.type &= ~MOVE_LAGGED;
937 		if (passedict->entnum && passedict->entnum <= MAX_CLIENTS) {
938 			client_t   *cl = &svs.clients[passedict->entnum - 1];
939 			clip.type |= MOVE_LAGGED;
940 			sv.lagents = cl->laggedents;
941 			sv.maxlagents = cl->laggedents_count;
942 			sv.lagentsfrac = cl->laggedents_frac;
943 		} else if (PROG_TO_EDICT (&sv_pr_state, SVentity (passedict, owner))) {
944 			edict_t    *owner;
945 			owner = PROG_TO_EDICT (&sv_pr_state, SVentity (passedict, owner));
946 			if (owner->entnum && owner->entnum <= MAX_CLIENTS) {
947 				client_t   *cl = &svs.clients[owner->entnum - 1];
948 				clip.type |= MOVE_LAGGED;
949 				sv.lagents = cl->laggedents;
950 				sv.maxlagents = cl->laggedents_count;
951 				sv.lagentsfrac = cl->laggedents_frac;
952 			}
953 		}
954 	}
955 	if (clip.type & MOVE_LAGGED) {
956 		trace_t     trace;
957 		edict_t    *touch;
958 		vec3_t      lp;
959 		unsigned    li;
960 
961 		SV_ClipToLinks (sv_areanodes, &clip);
962 		for (li = 0; li < sv.maxlagents; li++) {
963 			if (!sv.lagents[li].present)
964 				continue;
965 			if (clip.trace.allsolid)
966 				break;
967 
968 			touch = EDICT_NUM (&sv_pr_state, li + 1);
969 			if (!ctl_pretest_other (touch, &clip))
970 				continue;
971 			VectorBlend (SVvector(touch, origin), sv.lagents[li].laggedpos,
972 						 sv.lagentsfrac, lp);
973 			if (!ctl_touch_test_origin (touch, lp, &clip))
974 				continue;
975 			ctl_do_clip (touch, &clip, &trace);
976 		}
977 	} else {
978 		SV_ClipToLinks (sv_areanodes, &clip);
979 	}
980 
981 	return clip.trace;
982 }
983 
984 edict_t *
SV_TestPlayerPosition(edict_t * ent,const vec3_t origin)985 SV_TestPlayerPosition (edict_t *ent, const vec3_t origin)
986 {
987 	int         e;
988 	edict_t    *check;
989 	hull_t     *hull;
990 	vec3_t      boxmins, boxmaxs, offset;
991 
992 	// check world first
993 	hull = &sv.worldmodel->hulls[1];
994 	if (SV_HullPointContents (hull, hull->firstclipnode, origin) !=
995 		CONTENTS_EMPTY) return sv.edicts;
996 
997 	// check all entities
998 	VectorAdd (origin, SVvector (ent, mins), boxmins);
999 	VectorAdd (origin, SVvector (ent, maxs), boxmaxs);
1000 
1001 	check = NEXT_EDICT (&sv_pr_state, sv.edicts);
1002 	for (e = 1; e < sv.num_edicts; e++, check = NEXT_EDICT (&sv_pr_state,
1003 															check)) {
1004 		if (check->free)
1005 			continue;
1006 		if (check == ent)
1007 			continue;
1008 
1009 		if (SVfloat (check, solid) != SOLID_BSP
1010 			&& SVfloat (check, solid) != SOLID_BBOX
1011 			&& SVfloat (check, solid) != SOLID_SLIDEBOX)
1012 			continue;
1013 
1014 		if (boxmins[0] > SVvector (check, absmax)[0]
1015 			|| boxmins[1] > SVvector (check, absmax)[1]
1016 			|| boxmins[2] > SVvector (check, absmax)[2]
1017 			|| boxmaxs[0] < SVvector (check, absmin)[0]
1018 			|| boxmaxs[1] < SVvector (check, absmin)[1]
1019 			|| boxmaxs[2] < SVvector (check, absmin)[2])
1020 			continue;
1021 
1022 		// get the clipping hull
1023 		hull = SV_HullForEntity (check, SVvector (ent, mins),
1024 								 SVvector (ent, maxs), 0, offset);
1025 
1026 		VectorSubtract (origin, offset, offset);
1027 
1028 		// test the point
1029 		if (SV_HullPointContents (hull, hull->firstclipnode, offset) !=
1030 			CONTENTS_EMPTY)
1031 			return check;
1032 	}
1033 
1034 	return NULL;
1035 }
1036