world.c revision 9fd67c44777b350dc56f3e70c88963b0d966ffc7
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, 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
26entities never clip against themselves, or their owner
27
28line of sight checks trace->crosscontent, but bullets don't
29
30*/
31
32
33typedef 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
45int SV_HullPointContents (hull_t *hull, int num, vec3_t p);
46
47/*
48===============================================================================
49
50HULL BOXES
51
52===============================================================================
53*/
54
55
56static	hull_t		box_hull;
57static	dclipnode_t	box_clipnodes[6];
58static	mplane_t	box_planes[6];
59
60/*
61===================
62SV_InitBoxHull
63
64Set up the planes and clipnodes so that the six floats of a bounding box
65can just be stored out and get a proper hull_t structure.
66===================
67*/
68void 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===================
99SV_HullForBox
100
101To keep everything totally uniform, bounding boxes are turned into small
102BSP trees instead of being compared directly.
103===================
104*/
105hull_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================
121SV_HullForEntity
122
123Returns a hull that can be used for testing or clipping an object of mins/maxs
124size.
125Offset is filled in to contain the adjustment that must be added to the
126testing object's origin to get a point to use with the returned hull.
127================
128*/
129hull_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
176ENTITY AREA CHECKING
177
178===============================================================================
179*/
180
181
182areanode_t	sv_areanodes[AREA_NODES];
183int			sv_numareanodes;
184
185/*
186===============
187SV_CreateAreaNode
188
189===============
190*/
191areanode_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===============
232SV_ClearWorld
233
234===============
235*/
236void 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===============
248SV_UnlinkEdict
249
250===============
251*/
252void 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====================
263SV_TouchLinks
264====================
265*/
266void 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===============
314SV_FindTouchedLeafs
315
316===============
317*/
318void 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===============
358SV_LinkEdict
359
360===============
361*/
362void 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
440POINT TESTING IN HULLS
441
442===============================================================================
443*/
444
445#if	!id386
446
447/*
448==================
449SV_HullPointContents
450
451==================
452*/
453int 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==================
485SV_PointContents
486
487==================
488*/
489int SV_PointContents (vec3_t p)
490{
491	return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
492}
493
494//===========================================================================
495
496/*
497============
498SV_TestEntityPosition
499
500A small wrapper around SV_BoxInSolidEntity that never clips against the
501supplied entity.
502============
503*/
504edict_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
519LINE 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==================
529SV_RecursiveHullCheck
530
531==================
532*/
533qboolean 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==================
668SV_ClipMoveToEntity
669
670Handles selection or creation of a clipping hull, and offseting (and
671eventually rotation) of the end points
672==================
673*/
674trace_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====================
711SV_ClipToLinks
712
713Mins and maxs enclose the entire area swept by the move
714====================
715*/
716void 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==================
792SV_MoveBounds
793==================
794*/
795void 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
799boxmins[0] = boxmins[1] = boxmins[2] = -9999;
800boxmaxs[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==================
822SV_Move
823==================
824*/
825trace_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============
869SV_TestPlayerPosition
870
871============
872*/
873edict_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