• 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 "quakedef.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->u.v.solid == SOLID_BSP)
138 	{	// explicit hulls in the BSP model
139 		if (ent->u.v.movetype != MOVETYPE_PUSH)
140 			Sys_Error ("SOLID_BSP without MOVETYPE_PUSH");
141 
142 		model = sv.models[ (int)ent->u.v.modelindex ];
143 
144 		if (!model || model->type != mod_brush)
145 			Sys_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->u.v.origin, offset);
158 	}
159 	else
160 	{	// create a temp hull from bounding box sizes
161 
162 		VectorSubtract (ent->u.v.mins, maxs, hullmins);
163 		VectorSubtract (ent->u.v.maxs, mins, hullmaxs);
164 		hull = SV_HullForBox (hullmins, hullmaxs);
165 
166 		VectorCopy (ent->u.v.origin, offset);
167 	}
168 
169 
170 	return hull;
171 }
172 
173 /*
174 ===============================================================================
175 
176 ENTITY AREA CHECKING
177 
178 ===============================================================================
179 */
180 
181 typedef struct areanode_s
182 {
183 	int		axis;		// -1 = leaf node
184 	float	dist;
185 	struct areanode_s	*children[2];
186 	link_t	trigger_edicts;
187 	link_t	solid_edicts;
188 } areanode_t;
189 
190 #define	AREA_DEPTH	4
191 #define	AREA_NODES	32
192 
193 static	areanode_t	sv_areanodes[AREA_NODES];
194 static	int			sv_numareanodes;
195 
196 /*
197 ===============
198 SV_CreateAreaNode
199 
200 ===============
201 */
SV_CreateAreaNode(int depth,vec3_t mins,vec3_t maxs)202 areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
203 {
204 	areanode_t	*anode;
205 	vec3_t		size;
206 	vec3_t		mins1, maxs1, mins2, maxs2;
207 
208 	anode = &sv_areanodes[sv_numareanodes];
209 	sv_numareanodes++;
210 
211 	ClearLink (&anode->trigger_edicts);
212 	ClearLink (&anode->solid_edicts);
213 
214 	if (depth == AREA_DEPTH)
215 	{
216 		anode->axis = -1;
217 		anode->children[0] = anode->children[1] = NULL;
218 		return anode;
219 	}
220 
221 	VectorSubtract (maxs, mins, size);
222 	if (size[0] > size[1])
223 		anode->axis = 0;
224 	else
225 		anode->axis = 1;
226 
227 	anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
228 	VectorCopy (mins, mins1);
229 	VectorCopy (mins, mins2);
230 	VectorCopy (maxs, maxs1);
231 	VectorCopy (maxs, maxs2);
232 
233 	maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
234 
235 	anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
236 	anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
237 
238 	return anode;
239 }
240 
241 /*
242 ===============
243 SV_ClearWorld
244 
245 ===============
246 */
SV_ClearWorld(void)247 void SV_ClearWorld (void)
248 {
249 	SV_InitBoxHull ();
250 
251 	memset (sv_areanodes, 0, sizeof(sv_areanodes));
252 	sv_numareanodes = 0;
253 	SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs);
254 }
255 
256 
257 /*
258 ===============
259 SV_UnlinkEdict
260 
261 ===============
262 */
SV_UnlinkEdict(edict_t * ent)263 void SV_UnlinkEdict (edict_t *ent)
264 {
265 	if (!ent->area.prev)
266 		return;		// not linked in anywhere
267 	RemoveLink (&ent->area);
268 	ent->area.prev = ent->area.next = NULL;
269 }
270 
271 
272 /*
273 ====================
274 SV_TouchLinks
275 ====================
276 */
SV_TouchLinks(edict_t * ent,areanode_t * node)277 void SV_TouchLinks ( edict_t *ent, areanode_t *node )
278 {
279 	link_t		*l, *next;
280 	edict_t		*touch;
281 	int			old_self, old_other;
282 
283 // touch linked edicts
284 	for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next)
285 	{
286 		next = l->next;
287 		touch = EDICT_FROM_AREA(l);
288 		if (touch == ent)
289 			continue;
290 		if (!touch->u.v.touch || touch->u.v.solid != SOLID_TRIGGER)
291 			continue;
292 		if (ent->u.v.absmin[0] > touch->u.v.absmax[0]
293 		|| ent->u.v.absmin[1] > touch->u.v.absmax[1]
294 		|| ent->u.v.absmin[2] > touch->u.v.absmax[2]
295 		|| ent->u.v.absmax[0] < touch->u.v.absmin[0]
296 		|| ent->u.v.absmax[1] < touch->u.v.absmin[1]
297 		|| ent->u.v.absmax[2] < touch->u.v.absmin[2] )
298 			continue;
299 		old_self = pr_global_struct->self;
300 		old_other = pr_global_struct->other;
301 
302 		pr_global_struct->self = EDICT_TO_PROG(touch);
303 		pr_global_struct->other = EDICT_TO_PROG(ent);
304 		pr_global_struct->time = sv.time;
305 		PR_ExecuteProgram (touch->u.v.touch);
306 
307 		pr_global_struct->self = old_self;
308 		pr_global_struct->other = old_other;
309 	}
310 
311 // recurse down both sides
312 	if (node->axis == -1)
313 		return;
314 
315 	if ( ent->u.v.absmax[node->axis] > node->dist )
316 		SV_TouchLinks ( ent, node->children[0] );
317 	if ( ent->u.v.absmin[node->axis] < node->dist )
318 		SV_TouchLinks ( ent, node->children[1] );
319 }
320 
321 
322 /*
323 ===============
324 SV_FindTouchedLeafs
325 
326 ===============
327 */
SV_FindTouchedLeafs(edict_t * ent,mnode_t * node)328 void SV_FindTouchedLeafs (edict_t *ent, mnode_t *node)
329 {
330 	mplane_t	*splitplane;
331 	mleaf_t		*leaf;
332 	int			sides;
333 	int			leafnum;
334 
335 	if (node->contents == CONTENTS_SOLID)
336 		return;
337 
338 // add an efrag if the node is a leaf
339 
340 	if ( node->contents < 0)
341 	{
342 		if (ent->num_leafs == MAX_ENT_LEAFS)
343 			return;
344 
345 		leaf = (mleaf_t *)node;
346 		leafnum = leaf - sv.worldmodel->leafs - 1;
347 
348 		ent->leafnums[ent->num_leafs] = leafnum;
349 		ent->num_leafs++;
350 		return;
351 	}
352 
353 // NODE_MIXED
354 
355 	splitplane = node->plane;
356 	sides = BOX_ON_PLANE_SIDE(ent->u.v.absmin, ent->u.v.absmax, splitplane);
357 
358 // recurse down the contacted sides
359 	if (sides & 1)
360 		SV_FindTouchedLeafs (ent, node->children[0]);
361 
362 	if (sides & 2)
363 		SV_FindTouchedLeafs (ent, node->children[1]);
364 }
365 
366 /*
367 ===============
368 SV_LinkEdict
369 
370 ===============
371 */
SV_LinkEdict(edict_t * ent,qboolean touch_triggers)372 void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
373 {
374 	areanode_t	*node;
375 
376 	if (ent->area.prev)
377 		SV_UnlinkEdict (ent);	// unlink from old position
378 
379 	if (ent == sv.edicts)
380 		return;		// don't add the world
381 
382 	if (ent->free)
383 		return;
384 
385 // set the abs box
386 
387 #ifdef QUAKE2
388 	if (ent->u.v.solid == SOLID_BSP &&
389 	(ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) )
390 	{	// expand for rotation
391 		float		max, v;
392 		int			i;
393 
394 		max = 0;
395 		for (i=0 ; i<3 ; i++)
396 		{
397 			v =fabs( ent->u.v.mins[i]);
398 			if (v > max)
399 				max = v;
400 			v =fabs( ent->u.v.maxs[i]);
401 			if (v > max)
402 				max = v;
403 		}
404 		for (i=0 ; i<3 ; i++)
405 		{
406 			ent->u.v.absmin[i] = ent->u.v.origin[i] - max;
407 			ent->u.v.absmax[i] = ent->u.v.origin[i] + max;
408 		}
409 	}
410 	else
411 #endif
412 	{
413 		VectorAdd (ent->u.v.origin, ent->u.v.mins, ent->u.v.absmin);
414 		VectorAdd (ent->u.v.origin, ent->u.v.maxs, ent->u.v.absmax);
415 	}
416 
417 //
418 // to make items easier to pick up and allow them to be grabbed off
419 // of shelves, the abs sizes are expanded
420 //
421 	if ((int)ent->u.v.flags & FL_ITEM)
422 	{
423 		ent->u.v.absmin[0] -= 15;
424 		ent->u.v.absmin[1] -= 15;
425 		ent->u.v.absmax[0] += 15;
426 		ent->u.v.absmax[1] += 15;
427 	}
428 	else
429 	{	// because movement is clipped an epsilon away from an actual edge,
430 		// we must fully check even when bounding boxes don't quite touch
431 		ent->u.v.absmin[0] -= 1;
432 		ent->u.v.absmin[1] -= 1;
433 		ent->u.v.absmin[2] -= 1;
434 		ent->u.v.absmax[0] += 1;
435 		ent->u.v.absmax[1] += 1;
436 		ent->u.v.absmax[2] += 1;
437 	}
438 
439 // link to PVS leafs
440 	ent->num_leafs = 0;
441 	if (ent->u.v.modelindex)
442 		SV_FindTouchedLeafs (ent, sv.worldmodel->nodes);
443 
444 	if (ent->u.v.solid == SOLID_NOT)
445 		return;
446 
447 // find the first node that the ent's box crosses
448 	node = sv_areanodes;
449 	while (1)
450 	{
451 		if (node->axis == -1)
452 			break;
453 		if (ent->u.v.absmin[node->axis] > node->dist)
454 			node = node->children[0];
455 		else if (ent->u.v.absmax[node->axis] < node->dist)
456 			node = node->children[1];
457 		else
458 			break;		// crosses the node
459 	}
460 
461 // link it in
462 
463 	if (ent->u.v.solid == SOLID_TRIGGER)
464 		InsertLinkBefore (&ent->area, &node->trigger_edicts);
465 	else
466 		InsertLinkBefore (&ent->area, &node->solid_edicts);
467 
468 // if touch_triggers, touch all entities at this node and decend for more
469 	if (touch_triggers)
470 		SV_TouchLinks ( ent, sv_areanodes );
471 }
472 
473 
474 
475 /*
476 ===============================================================================
477 
478 POINT TESTING IN HULLS
479 
480 ===============================================================================
481 */
482 
483 #if	!id386
484 
485 /*
486 ==================
487 SV_HullPointContents
488 
489 ==================
490 */
SV_HullPointContents(hull_t * hull,int num,vec3_t p)491 int SV_HullPointContents (hull_t *hull, int num, vec3_t p)
492 {
493 	float		d;
494 	dclipnode_t	*node;
495 	mplane_t	*plane;
496 
497 	while (num >= 0)
498 	{
499 		if (num < hull->firstclipnode || num > hull->lastclipnode)
500 			Sys_Error ("SV_HullPointContents: bad node number");
501 
502 		node = hull->clipnodes + num;
503 		plane = hull->planes + node->planenum;
504 
505 		if (plane->type < 3)
506 			d = p[plane->type] - plane->dist;
507 		else
508 			d = DotProduct (plane->normal, p) - plane->dist;
509 		if (d < 0)
510 			num = node->children[1];
511 		else
512 			num = node->children[0];
513 	}
514 
515 	return num;
516 }
517 
518 #endif	// !id386
519 
520 
521 /*
522 ==================
523 SV_PointContents
524 
525 ==================
526 */
SV_PointContents(vec3_t p)527 int SV_PointContents (vec3_t p)
528 {
529 	int		cont;
530 
531 	cont = SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
532 	if (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)
533 		cont = CONTENTS_WATER;
534 	return cont;
535 }
536 
SV_TruePointContents(vec3_t p)537 int SV_TruePointContents (vec3_t p)
538 {
539 	return SV_HullPointContents (&sv.worldmodel->hulls[0], 0, p);
540 }
541 
542 //===========================================================================
543 
544 /*
545 ============
546 SV_TestEntityPosition
547 
548 This could be a lot more efficient...
549 ============
550 */
SV_TestEntityPosition(edict_t * ent)551 edict_t	*SV_TestEntityPosition (edict_t *ent)
552 {
553 	trace_t	trace;
554 
555 	trace = SV_Move (ent->u.v.origin, ent->u.v.mins, ent->u.v.maxs, ent->u.v.origin, 0, ent);
556 
557 	if (trace.startsolid)
558 		return sv.edicts;
559 
560 	return NULL;
561 }
562 
563 
564 /*
565 ===============================================================================
566 
567 LINE TESTING IN HULLS
568 
569 ===============================================================================
570 */
571 
572 // 1/32 epsilon to keep floating point happy
573 #define	DIST_EPSILON	(0.03125)
574 
575 /*
576 ==================
577 SV_RecursiveHullCheck
578 
579 ==================
580 */
SV_RecursiveHullCheck(hull_t * hull,int num,float p1f,float p2f,vec3_t p1,vec3_t p2,trace_t * trace)581 qboolean SV_RecursiveHullCheck (hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)
582 {
583 	dclipnode_t	*node;
584 	mplane_t	*plane;
585 	float		t1, t2;
586 	float		frac;
587 	int			i;
588 	vec3_t		mid;
589 	int			side;
590 	float		midf;
591 
592 // check for empty
593 	if (num < 0)
594 	{
595 		if (num != CONTENTS_SOLID)
596 		{
597 			trace->allsolid = false;
598 			if (num == CONTENTS_EMPTY)
599 				trace->inopen = true;
600 			else
601 				trace->inwater = true;
602 		}
603 		else
604 			trace->startsolid = true;
605 		return true;		// empty
606 	}
607 
608 	if (num < hull->firstclipnode || num > hull->lastclipnode)
609 		Sys_Error ("SV_RecursiveHullCheck: bad node number");
610 
611 //
612 // find the point distances
613 //
614 	node = hull->clipnodes + num;
615 	plane = hull->planes + node->planenum;
616 
617 	if (plane->type < 3)
618 	{
619 		t1 = p1[plane->type] - plane->dist;
620 		t2 = p2[plane->type] - plane->dist;
621 	}
622 	else
623 	{
624 		t1 = DotProduct (plane->normal, p1) - plane->dist;
625 		t2 = DotProduct (plane->normal, p2) - plane->dist;
626 	}
627 
628 #if 1
629 	if (t1 >= 0 && t2 >= 0)
630 		return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
631 	if (t1 < 0 && t2 < 0)
632 		return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
633 #else
634 	if ( (t1 >= DIST_EPSILON && t2 >= DIST_EPSILON) || (t2 > t1 && t1 >= 0) )
635 		return SV_RecursiveHullCheck (hull, node->children[0], p1f, p2f, p1, p2, trace);
636 	if ( (t1 <= -DIST_EPSILON && t2 <= -DIST_EPSILON) || (t2 < t1 && t1 <= 0) )
637 		return SV_RecursiveHullCheck (hull, node->children[1], p1f, p2f, p1, p2, trace);
638 #endif
639 
640 // put the crosspoint DIST_EPSILON pixels on the near side
641 	if (t1 < 0)
642 		frac = (t1 + DIST_EPSILON)/(t1-t2);
643 	else
644 		frac = (t1 - DIST_EPSILON)/(t1-t2);
645 	if (frac < 0)
646 		frac = 0;
647 	if (frac > 1)
648 		frac = 1;
649 
650 	midf = p1f + (p2f - p1f)*frac;
651 	for (i=0 ; i<3 ; i++)
652 		mid[i] = p1[i] + frac*(p2[i] - p1[i]);
653 
654 	side = (t1 < 0);
655 
656 // move up to the node
657 	if (!SV_RecursiveHullCheck (hull, node->children[side], p1f, midf, p1, mid, trace) )
658 		return false;
659 
660 #ifdef PARANOID
661 	if (SV_HullPointContents (sv_hullmodel, mid, node->children[side])
662 	== CONTENTS_SOLID)
663 	{
664 		Con_Printf ("mid PointInHullSolid\n");
665 		return false;
666 	}
667 #endif
668 
669 	if (SV_HullPointContents (hull, node->children[side^1], mid)
670 	!= CONTENTS_SOLID)
671 // go past the node
672 		return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace);
673 
674 	if (trace->allsolid)
675 		return false;		// never got out of the solid area
676 
677 //==================
678 // the other side of the node is solid, this is the impact point
679 //==================
680 	if (!side)
681 	{
682 		VectorCopy (plane->normal, trace->plane.normal);
683 		trace->plane.dist = plane->dist;
684 	}
685 	else
686 	{
687 		VectorSubtract (vec3_origin, plane->normal, trace->plane.normal);
688 		trace->plane.dist = -plane->dist;
689 	}
690 
691 	while (SV_HullPointContents (hull, hull->firstclipnode, mid)
692 	== CONTENTS_SOLID)
693 	{ // shouldn't really happen, but does occasionally
694 		frac -= 0.1;
695 		if (frac < 0)
696 		{
697 			trace->fraction = midf;
698 			VectorCopy (mid, trace->endpos);
699 			Con_DPrintf ("backup past 0\n");
700 			return false;
701 		}
702 		midf = p1f + (p2f - p1f)*frac;
703 		for (i=0 ; i<3 ; i++)
704 			mid[i] = p1[i] + frac*(p2[i] - p1[i]);
705 	}
706 
707 	trace->fraction = midf;
708 	VectorCopy (mid, trace->endpos);
709 
710 	return false;
711 }
712 
713 
714 /*
715 ==================
716 SV_ClipMoveToEntity
717 
718 Handles selection or creation of a clipping hull, and offseting (and
719 eventually rotation) of the end points
720 ==================
721 */
SV_ClipMoveToEntity(edict_t * ent,vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end)722 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
723 {
724 	trace_t		trace;
725 	vec3_t		offset;
726 	vec3_t		start_l, end_l;
727 	hull_t		*hull;
728 
729 // fill in a default trace
730 	memset (&trace, 0, sizeof(trace_t));
731 	trace.fraction = 1;
732 	trace.allsolid = true;
733 	VectorCopy (end, trace.endpos);
734 
735 // get the clipping hull
736 	hull = SV_HullForEntity (ent, mins, maxs, offset);
737 
738 	VectorSubtract (start, offset, start_l);
739 	VectorSubtract (end, offset, end_l);
740 
741 #ifdef QUAKE2
742 	// rotate start and end into the models frame of reference
743 	if (ent->u.v.solid == SOLID_BSP &&
744 	(ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) )
745 	{
746 		vec3_t	a;
747 		vec3_t	forward, right, up;
748 		vec3_t	temp;
749 
750 		AngleVectors (ent->u.v.angles, forward, right, up);
751 
752 		VectorCopy (start_l, temp);
753 		start_l[0] = DotProduct (temp, forward);
754 		start_l[1] = -DotProduct (temp, right);
755 		start_l[2] = DotProduct (temp, up);
756 
757 		VectorCopy (end_l, temp);
758 		end_l[0] = DotProduct (temp, forward);
759 		end_l[1] = -DotProduct (temp, right);
760 		end_l[2] = DotProduct (temp, up);
761 	}
762 #endif
763 
764 // trace a line through the apropriate clipping hull
765 	SV_RecursiveHullCheck (hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace);
766 
767 #ifdef QUAKE2
768 	// rotate endpos back to world frame of reference
769 	if (ent->u.v.solid == SOLID_BSP &&
770 	(ent->u.v.angles[0] || ent->u.v.angles[1] || ent->u.v.angles[2]) )
771 	{
772 		vec3_t	a;
773 		vec3_t	forward, right, up;
774 		vec3_t	temp;
775 
776 		if (trace.fraction != 1)
777 		{
778 			VectorSubtract (vec3_origin, ent->u.v.angles, a);
779 			AngleVectors (a, forward, right, up);
780 
781 			VectorCopy (trace.endpos, temp);
782 			trace.endpos[0] = DotProduct (temp, forward);
783 			trace.endpos[1] = -DotProduct (temp, right);
784 			trace.endpos[2] = DotProduct (temp, up);
785 
786 			VectorCopy (trace.plane.normal, temp);
787 			trace.plane.normal[0] = DotProduct (temp, forward);
788 			trace.plane.normal[1] = -DotProduct (temp, right);
789 			trace.plane.normal[2] = DotProduct (temp, up);
790 		}
791 	}
792 #endif
793 
794 // fix trace up by the offset
795 	if (trace.fraction != 1)
796 		VectorAdd (trace.endpos, offset, trace.endpos);
797 
798 // did we clip the move?
799 	if (trace.fraction < 1 || trace.startsolid  )
800 		trace.ent = ent;
801 
802 	return trace;
803 }
804 
805 //===========================================================================
806 
807 /*
808 ====================
809 SV_ClipToLinks
810 
811 Mins and maxs enclose the entire area swept by the move
812 ====================
813 */
SV_ClipToLinks(areanode_t * node,moveclip_t * clip)814 void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip )
815 {
816 	link_t		*l, *next;
817 	edict_t		*touch;
818 	trace_t		trace;
819 
820 // touch linked edicts
821 	for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
822 	{
823 		next = l->next;
824 		touch = EDICT_FROM_AREA(l);
825 		if (touch->u.v.solid == SOLID_NOT)
826 			continue;
827 		if (touch == clip->passedict)
828 			continue;
829 		if (touch->u.v.solid == SOLID_TRIGGER)
830 			Sys_Error ("Trigger in clipping list");
831 
832 		if (clip->type == MOVE_NOMONSTERS && touch->u.v.solid != SOLID_BSP)
833 			continue;
834 
835 		if (clip->boxmins[0] > touch->u.v.absmax[0]
836 		|| clip->boxmins[1] > touch->u.v.absmax[1]
837 		|| clip->boxmins[2] > touch->u.v.absmax[2]
838 		|| clip->boxmaxs[0] < touch->u.v.absmin[0]
839 		|| clip->boxmaxs[1] < touch->u.v.absmin[1]
840 		|| clip->boxmaxs[2] < touch->u.v.absmin[2] )
841 			continue;
842 
843 		if (clip->passedict && clip->passedict->u.v.size[0] && !touch->u.v.size[0])
844 			continue;	// points never interact
845 
846 	// might intersect, so do an exact clip
847 		if (clip->trace.allsolid)
848 			return;
849 		if (clip->passedict)
850 		{
851 		 	if (PROG_TO_EDICT(touch->u.v.owner) == clip->passedict)
852 				continue;	// don't clip against own missiles
853 			if (PROG_TO_EDICT(clip->passedict->u.v.owner) == touch)
854 				continue;	// don't clip against owner
855 		}
856 
857 		if ((int)touch->u.v.flags & FL_MONSTER)
858 			trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end);
859 		else
860 			trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end);
861 		if (trace.allsolid || trace.startsolid ||
862 		trace.fraction < clip->trace.fraction)
863 		{
864 			trace.ent = touch;
865 		 	if (clip->trace.startsolid)
866 			{
867 				clip->trace = trace;
868 				clip->trace.startsolid = true;
869 			}
870 			else
871 				clip->trace = trace;
872 		}
873 		else if (trace.startsolid)
874 			clip->trace.startsolid = true;
875 	}
876 
877 // recurse down both sides
878 	if (node->axis == -1)
879 		return;
880 
881 	if ( clip->boxmaxs[node->axis] > node->dist )
882 		SV_ClipToLinks ( node->children[0], clip );
883 	if ( clip->boxmins[node->axis] < node->dist )
884 		SV_ClipToLinks ( node->children[1], clip );
885 }
886 
887 
888 /*
889 ==================
890 SV_MoveBounds
891 ==================
892 */
SV_MoveBounds(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,vec3_t boxmins,vec3_t boxmaxs)893 void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
894 {
895 #if 0
896 // debug to test against everything
897 boxmins[0] = boxmins[1] = boxmins[2] = -9999;
898 boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
899 #else
900 	int		i;
901 
902 	for (i=0 ; i<3 ; i++)
903 	{
904 		if (end[i] > start[i])
905 		{
906 			boxmins[i] = start[i] + mins[i] - 1;
907 			boxmaxs[i] = end[i] + maxs[i] + 1;
908 		}
909 		else
910 		{
911 			boxmins[i] = end[i] + mins[i] - 1;
912 			boxmaxs[i] = start[i] + maxs[i] + 1;
913 		}
914 	}
915 #endif
916 }
917 
918 /*
919 ==================
920 SV_Move
921 ==================
922 */
SV_Move(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,int type,edict_t * passedict)923 trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict)
924 {
925 	moveclip_t	clip;
926 	int			i;
927 
928 	memset ( &clip, 0, sizeof ( moveclip_t ) );
929 
930 // clip to world
931 	clip.trace = SV_ClipMoveToEntity ( sv.edicts, start, mins, maxs, end );
932 
933 	clip.start = start;
934 	clip.end = end;
935 	clip.mins = mins;
936 	clip.maxs = maxs;
937 	clip.type = type;
938 	clip.passedict = passedict;
939 
940 	if (type == MOVE_MISSILE)
941 	{
942 		for (i=0 ; i<3 ; i++)
943 		{
944 			clip.mins2[i] = -15;
945 			clip.maxs2[i] = 15;
946 		}
947 	}
948 	else
949 	{
950 		VectorCopy (mins, clip.mins2);
951 		VectorCopy (maxs, clip.maxs2);
952 	}
953 
954 // create the bounding box of the entire move
955 	SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
956 
957 // clip to entities
958 	SV_ClipToLinks ( sv_areanodes, &clip );
959 
960 	return clip.trace;
961 }
962 
963