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