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 #ifndef CLIENTONLY
23 #include "qwsvdef.h"
24 
25 /*
26 
27 entities never clip against themselves, or their owner
28 
29 line of sight checks trace->crosscontent, but bullets don't
30 
31 */
32 
33 
34 typedef struct
35 {
36 	vec3_t		boxmins, boxmaxs;// enclose the test object along entire move
37 	float		*mins, *maxs;	// size of the moving object
38 	vec3_t		mins2, maxs2;	// size when clipping against mosnters
39 	float		*start, *end;
40 	trace_t		trace;
41 	int			type;
42 	edict_t		*passedict;
43 } moveclip_t;
44 
45 
46 /*
47 ================
48 SV_HullForEntity
49 
50 Returns a hull that can be used for testing or clipping an object of mins/maxs
51 size.
52 Offset is filled in to contain the adjustment that must be added to the
53 testing object's origin to get a point to use with the returned hull.
54 ================
55 */
SV_HullForEntity(edict_t * ent,vec3_t mins,vec3_t maxs,vec3_t offset)56 hull_t *SV_HullForEntity (edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)
57 {
58 	vec3_t size, hullmins, hullmaxs;
59 	cmodel_t *model;
60 	hull_t *hull;
61 
62 
63 	// decide which clipping hull to use, based on the size
64 	if (ent->v.solid == SOLID_BSP)
65 	{	// explicit hulls in the BSP model
66 		if (ent->v.movetype != MOVETYPE_PUSH)
67 			SV_Error ("SOLID_BSP without MOVETYPE_PUSH");
68 
69 		if ((unsigned)ent->v.modelindex >= MAX_MODELS)
70 			SV_Error ("SV_HullForEntity: ent.modelindex >= MAX_MODELS");
71 
72 		model = sv.models[(int)ent->v.modelindex];
73 		if (!model)
74 			SV_Error ("SOLID_BSP with a non-bsp model");
75 
76 		VectorSubtract (maxs, mins, size);
77 		if (size[0] < 3)
78 			hull = &model->hulls[0];
79 		else if (size[0] <= 32)
80 			hull = &model->hulls[1];
81 		else
82 			hull = &model->hulls[2];
83 
84 		// calculate an offset value to center the origin
85 		VectorSubtract (hull->clip_mins, mins, offset);
86 		VectorAdd (offset, ent->v.origin, offset);
87 	}
88 	else
89 	{	// create a temp hull from bounding box sizes
90 
91 		VectorSubtract (ent->v.mins, maxs, hullmins);
92 		VectorSubtract (ent->v.maxs, mins, hullmaxs);
93 		hull = CM_HullForBox (hullmins, hullmaxs);
94 
95 		VectorCopy (ent->v.origin, offset);
96 	}
97 
98 
99 	return hull;
100 }
101 
102 /*
103 ===============================================================================
104 
105 ENTITY AREA CHECKING
106 
107 ===============================================================================
108 */
109 
110 // ClearLink is used for new headnodes
ClearLink(link_t * l)111 void ClearLink (link_t *l)
112 {
113 	l->prev = l->next = l;
114 }
115 
RemoveLink(link_t * l)116 void RemoveLink (link_t *l)
117 {
118 	l->next->prev = l->prev;
119 	l->prev->next = l->next;
120 }
121 
InsertLinkBefore(link_t * l,link_t * before)122 void InsertLinkBefore (link_t *l, link_t *before)
123 {
124 	l->next = before;
125 	l->prev = before->prev;
126 	l->prev->next = l;
127 	l->next->prev = l;
128 }
InsertLinkAfter(link_t * l,link_t * after)129 void InsertLinkAfter (link_t *l, link_t *after)
130 {
131 	l->next = after->next;
132 	l->prev = after;
133 	l->prev->next = l;
134 	l->next->prev = l;
135 }
136 
137 //============================================================================
138 
139 // well, here should be all things related to world but atm it antilag only
140 typedef struct world_s
141 {
142 // { sv_antilag related
143 	float lagentsfrac;
144 	laggedentinfo_t *lagents;
145 	unsigned int maxlagents;
146 // }
147 } world_t;
148 
149 static world_t w;
150 
151 areanode_t sv_areanodes[AREA_NODES];
152 int sv_numareanodes;
153 
154 /*
155 ===============
156 SV_CreateAreaNode
157 ===============
158 */
SV_CreateAreaNode(int depth,vec3_t mins,vec3_t maxs)159 areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
160 {
161 	areanode_t	*anode;
162 	vec3_t		size;
163 	vec3_t		mins1, maxs1, mins2, maxs2;
164 
165 	anode = &sv_areanodes[sv_numareanodes];
166 	sv_numareanodes++;
167 
168 	ClearLink (&anode->trigger_edicts);
169 	ClearLink (&anode->solid_edicts);
170 
171 	if (depth == AREA_DEPTH)
172 	{
173 		anode->axis = -1;
174 		anode->children[0] = anode->children[1] = NULL;
175 		return anode;
176 	}
177 
178 	VectorSubtract (maxs, mins, size);
179 	if (size[0] > size[1])
180 		anode->axis = 0;
181 	else
182 		anode->axis = 1;
183 
184 	anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
185 	VectorCopy (mins, mins1);
186 	VectorCopy (mins, mins2);
187 	VectorCopy (maxs, maxs1);
188 	VectorCopy (maxs, maxs2);
189 
190 	maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
191 
192 	anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
193 	anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
194 
195 	return anode;
196 }
197 
198 /*
199 ===============
200 SV_ClearWorld
201 ===============
202 */
SV_ClearWorld(void)203 void SV_ClearWorld (void)
204 {
205 	memset (sv_areanodes, 0, sizeof(sv_areanodes));
206 	sv_numareanodes = 0;
207 	SV_CreateAreaNode (0, sv.worldmodel->mins, sv.worldmodel->maxs);
208 }
209 
210 
211 /*
212 ===============
213 SV_UnlinkEdict
214 ===============
215 */
SV_UnlinkEdict(edict_t * ent)216 void SV_UnlinkEdict (edict_t *ent)
217 {
218 	if (!ent->e->area.prev)
219 		return;		// not linked in anywhere
220 	RemoveLink (&ent->e->area);
221 	ent->e->area.prev = ent->e->area.next = NULL;
222 }
223 
224 /*
225 ====================
226 SV_AreaEdicts
227 ====================
228 */
SV_AreaEdicts(vec3_t mins,vec3_t maxs,edict_t ** edicts,int max_edicts,int area)229 int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **edicts, int max_edicts, int area)
230 {
231 	link_t		*l, *start;
232 	edict_t		*touch;
233 	int			stackdepth = 0, count = 0;
234 	areanode_t	*localstack[AREA_NODES], *node = sv_areanodes;
235 
236 // touch linked edicts
237 	while (1)
238 	{
239 		if (area == AREA_SOLID)
240 			start = &node->solid_edicts;
241 		else
242 			start = &node->trigger_edicts;
243 
244 		for (l = start->next ; l != start ; l = l->next)
245 		{
246 			touch = EDICT_FROM_AREA(l);
247 			if (touch->v.solid == SOLID_NOT)
248 				continue;
249 
250 			if (mins[0] > touch->v.absmax[0]
251 						 || mins[1] > touch->v.absmax[1]
252 						 || mins[2] > touch->v.absmax[2]
253 						 || maxs[0] < touch->v.absmin[0]
254 						 || maxs[1] < touch->v.absmin[1]
255 						 || maxs[2] < touch->v.absmin[2])
256 				continue;
257 
258 			if (count == max_edicts)
259 				return count;
260 			edicts[count++] = touch;
261 		}
262 
263 		if (node->axis == -1)
264 			goto checkstack;		// terminal node
265 
266 		// recurse down both sides
267 		if (maxs[node->axis] > node->dist)
268 		{
269 			if (mins[node->axis] < node->dist)
270 			{
271 				localstack[stackdepth++] = node->children[0];
272 				node = node->children[1];
273 				continue;
274 			}
275 			node = node->children[0];
276 			continue;
277 		}
278 		if (mins[node->axis] < node->dist)
279 		{
280 			node = node->children[1];
281 			continue;
282 		}
283 
284 checkstack:
285 		if (!stackdepth)
286 		return count;
287 		node = localstack[--stackdepth];
288 	}
289 
290 	return count;
291 }
292 
293 /*
294 ====================
295 SV_TouchLinks
296 ====================
297 */
SV_TouchLinks(edict_t * ent,areanode_t * node)298 static void SV_TouchLinks ( edict_t *ent, areanode_t *node )
299 {
300 	int			i, numtouch;
301 	edict_t		*touchlist[MAX_EDICTS], *touch;
302 	int			old_self, old_other;
303 
304 	numtouch = SV_AreaEdicts (ent->v.absmin, ent->v.absmax, touchlist, sv.max_edicts, AREA_TRIGGERS);
305 
306 // touch linked edicts
307 	for (i = 0; i < numtouch; i++)
308 	{
309 		touch = touchlist[i];
310 		if (touch == ent)
311 			continue;
312 		if (!touch->v.touch || touch->v.solid != SOLID_TRIGGER)
313 			continue;
314 
315 		old_self = pr_global_struct->self;
316 		old_other = pr_global_struct->other;
317 
318 		pr_global_struct->self = EDICT_TO_PROG(touch);
319 		pr_global_struct->other = EDICT_TO_PROG(ent);
320 		pr_global_struct->time = sv.time;
321 		PR_EdictTouch (touch->v.touch);
322 
323 		pr_global_struct->self = old_self;
324 		pr_global_struct->other = old_other;
325 	}
326 }
327 
328 /*
329 ====================
330 SV_LinkToLeafs
331 ====================
332 */
SV_LinkToLeafs(edict_t * ent)333 void SV_LinkToLeafs (edict_t *ent)
334 {
335 	int	i, leafnums[MAX_ENT_LEAFS];
336 
337 	ent->e->num_leafs = CM_FindTouchedLeafs (ent->v.absmin, ent->v.absmax, leafnums,
338 					      MAX_ENT_LEAFS, 0, NULL);
339 	for (i = 0; i < ent->e->num_leafs; i++) {
340 		// ent->e->leafnums are real leafnum minus one (for pvs checks)
341 		ent->e->leafnums[i] = leafnums[i] - 1;
342 	}
343 }
344 
345 
346 /*
347 ===============
348 SV_LinkEdict
349 
350 ===============
351 */
SV_LinkEdict(edict_t * ent,qbool touch_triggers)352 void SV_LinkEdict (edict_t *ent, qbool touch_triggers)
353 {
354 	areanode_t	*node;
355 
356 	if (ent->e->area.prev)
357 		SV_UnlinkEdict (ent);	// unlink from old position
358 
359 	if (ent == sv.edicts)
360 		return;		// don't add the world
361 
362 	if (ent->e->free)
363 		return;
364 
365 // set the abs box
366 	VectorAdd (ent->v.origin, ent->v.mins, ent->v.absmin);
367 	VectorAdd (ent->v.origin, ent->v.maxs, ent->v.absmax);
368 
369 	//
370 // to make items easier to pick up and allow them to be grabbed off
371 // of shelves, the abs sizes are expanded
372 	//
373 	if ((int)ent->v.flags & FL_ITEM)
374 	{
375 		ent->v.absmin[0] -= 15;
376 		ent->v.absmin[1] -= 15;
377 		ent->v.absmax[0] += 15;
378 		ent->v.absmax[1] += 15;
379 	}
380 	else
381 	{	// because movement is clipped an epsilon away from an actual edge,
382 		// we must fully check even when bounding boxes don't quite touch
383 		ent->v.absmin[0] -= 1;
384 		ent->v.absmin[1] -= 1;
385 		ent->v.absmin[2] -= 1;
386 		ent->v.absmax[0] += 1;
387 		ent->v.absmax[1] += 1;
388 		ent->v.absmax[2] += 1;
389 	}
390 
391 // link to PVS leafs
392 	if (ent->v.modelindex)
393 		SV_LinkToLeafs (ent);
394 	else
395 		ent->e->num_leafs = 0;
396 
397 	if (ent->v.solid == SOLID_NOT)
398 		return;
399 
400 // find the first node that the ent's box crosses
401 	node = sv_areanodes;
402 	while (1)
403 	{
404 		if (node->axis == -1)
405 			break;
406 		if (ent->v.absmin[node->axis] > node->dist)
407 			node = node->children[0];
408 		else if (ent->v.absmax[node->axis] < node->dist)
409 			node = node->children[1];
410 		else
411 			break;		// crosses the node
412 	}
413 
414 // link it in
415 
416 	if (ent->v.solid == SOLID_TRIGGER)
417 		InsertLinkBefore (&ent->e->area, &node->trigger_edicts);
418 	else
419 		InsertLinkBefore (&ent->e->area, &node->solid_edicts);
420 
421 // if touch_triggers, touch all entities at this node and decend for more
422 	if (touch_triggers)
423 		SV_TouchLinks ( ent, sv_areanodes );
424 }
425 
426 
427 
428 /*
429 ===============================================================================
430 
431 POINT TESTING IN HULLS
432 
433 ===============================================================================
434 */
435 
436 /*
437 ==================
438 SV_PointContents
439 
440 ==================
441 */
SV_PointContents(vec3_t p)442 int SV_PointContents (vec3_t p)
443 {
444 	return CM_HullPointContents (&sv.worldmodel->hulls[0], sv.worldmodel->hulls[0].firstclipnode, p);
445 }
446 
447 //===========================================================================
448 
449 /*
450 ============
451 SV_TestEntityPosition
452 
453 A small wrapper around SV_BoxInSolidEntity that never clips against the
454 supplied entity.
455 ============
456 */
SV_TestEntityPosition(edict_t * ent)457 edict_t	*SV_TestEntityPosition (edict_t *ent)
458 {
459 	trace_t	trace;
460 
461 	if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
462 		// only clip against bmodels
463 		trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NOMONSTERS, ent);
464 	else
465 		trace = SV_Trace (ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent);
466 
467 	if (trace.startsolid)
468 		return sv.edicts;
469 
470 	return NULL;
471 }
472 
473 /*
474 ==================
475 SV_ClipMoveToEntity
476 
477 Handles selection or creation of a clipping hull, and offseting (and
478 eventually rotation) of the end points
479 ==================
480 */
SV_ClipMoveToEntity(edict_t * ent,vec3_t * eorg,vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end)481 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t *eorg, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
482 {
483 	trace_t		trace;
484 	vec3_t		offset;
485 	vec3_t		start_l, end_l;
486 	hull_t		*hull;
487 
488 	// get the clipping hull
489 	hull = SV_HullForEntity (ent, mins, maxs, offset);
490 
491 	// { well, its hack for sv_antilag
492 	if (eorg)
493 		VectorCopy((*eorg), offset);
494 	// }
495 
496 	VectorSubtract (start, offset, start_l);
497 	VectorSubtract (end, offset, end_l);
498 
499 	// trace a line through the apropriate clipping hull
500 	trace = CM_HullTrace (hull, start_l, end_l);
501 
502 	// fix trace up by the offset
503 	VectorAdd (trace.endpos, offset, trace.endpos);
504 
505 	// did we clip the move?
506 	if (trace.fraction < 1 || trace.startsolid)
507 		trace.e.ent = ent;
508 
509 	return trace;
510 }
511 
512 //===========================================================================
513 
514 /*
515 ====================
516 SV_ClipToLinks
517 
518 Mins and maxs enclose the entire area swept by the move
519 ====================
520 */
SV_ClipToLinks(areanode_t * node,moveclip_t * clip)521 void SV_ClipToLinks ( areanode_t *node, moveclip_t *clip )
522 {
523 	int			i, numtouch;
524 	edict_t		*touchlist[MAX_EDICTS], *touch;
525 	trace_t		trace;
526 
527 	numtouch = SV_AreaEdicts (clip->boxmins, clip->boxmaxs, touchlist, sv.max_edicts, AREA_SOLID);
528 
529 	// touch linked edicts
530 	for (i = 0; i < numtouch; i++)
531 	{
532 		// might intersect, so do an exact clip
533 		if (clip->trace.allsolid)
534 			return; // return!!!
535 
536 		touch = touchlist[i];
537 		if (touch == clip->passedict)
538 			continue;
539 		if (touch->v.solid == SOLID_TRIGGER)
540 			SV_Error ("Trigger in clipping list");
541 
542 		if ((clip->type & MOVE_NOMONSTERS) && touch->v.solid != SOLID_BSP)
543 			continue;
544 
545 		if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0])
546 			continue;	// points never interact
547 
548 		if (clip->type & MOVE_LAGGED)
549 		{
550 			//can't touch lagged ents - we do an explicit test for them later in SV_AntilagClipCheck.
551 			if (touch->e->entnum - 1 < w.maxlagents)
552 				if (w.lagents[touch->e->entnum - 1].present)
553 					continue;
554 		}
555 
556 		if (clip->passedict)
557 		{
558 			if (PROG_TO_EDICT(touch->v.owner) == clip->passedict)
559 				continue;	// don't clip against own missiles
560 			if (PROG_TO_EDICT(clip->passedict->v.owner) == touch)
561 				continue;	// don't clip against owner
562 		}
563 
564 		if ((int)touch->v.flags & FL_MONSTER)
565 			trace = SV_ClipMoveToEntity (touch, NULL, clip->start, clip->mins2, clip->maxs2, clip->end);
566 		else
567 			trace = SV_ClipMoveToEntity (touch, NULL, clip->start, clip->mins, clip->maxs, clip->end);
568 
569 		// qqshka: I have NO idea why we keep startsolid but let do it.
570 
571 		// make sure we keep a startsolid from a previous trace
572 		clip->trace.startsolid |= trace.startsolid;
573 
574 		if ( trace.allsolid || trace.fraction < clip->trace.fraction )
575 		{
576 			// set edict
577 			trace.e.ent = touch;
578 			// make sure we keep a startsolid from a previous trace
579 			trace.startsolid |= clip->trace.startsolid;
580 			// bit by bit copy trace struct
581 			clip->trace = trace;
582 		}
583 	}
584 }
585 
586 
587 /*
588 ==================
589 SV_MoveBounds
590 ==================
591 */
SV_MoveBounds(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,vec3_t boxmins,vec3_t boxmaxs)592 void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
593 {
594 #if 0
595 	// debug to test against everything
596 	boxmins[0] = boxmins[1] = boxmins[2] = -9999;
597 	boxmaxs[0] = boxmaxs[1] = boxmaxs[2] = 9999;
598 #else
599 	int		i;
600 
601 	for (i=0 ; i<3 ; i++)
602 	{
603 		if (end[i] > start[i])
604 		{
605 			boxmins[i] = start[i] + mins[i] - 1;
606 			boxmaxs[i] = end[i] + maxs[i] + 1;
607 		}
608 		else
609 		{
610 			boxmins[i] = end[i] + mins[i] - 1;
611 			boxmaxs[i] = start[i] + maxs[i] + 1;
612 		}
613 	}
614 #endif
615 }
616 
617 //=============================================
618 
SV_AntilagReset(edict_t * ent)619 void SV_AntilagReset (edict_t *ent)
620 {
621 	if (ent->e->entnum == 0 || ent->e->entnum > MAX_CLIENTS)
622 		return;
623 
624 	svs.clients[ent->e->entnum - 1].antilag_position_next = 0;
625 }
626 
SV_AntilagClipSetUp(areanode_t * node,moveclip_t * clip)627 void SV_AntilagClipSetUp ( areanode_t *node, moveclip_t *clip )
628 {
629 	edict_t *passedict = clip->passedict;
630 	int entnum = passedict->e->entnum;
631 
632 	clip->type &= ~MOVE_LAGGED;
633 
634 	if (entnum && entnum <= MAX_CLIENTS && !svs.clients[entnum - 1].isBot)
635 	{
636 		clip->type |= MOVE_LAGGED;
637 		w.lagents = svs.clients[entnum - 1].laggedents;
638 		w.maxlagents = svs.clients[entnum - 1].laggedents_count;
639 		w.lagentsfrac = svs.clients[entnum - 1].laggedents_frac;
640 	}
641 	else if (passedict->v.owner)
642 	{
643 		int owner = PROG_TO_EDICT(passedict->v.owner)->e->entnum;
644 
645 		if (owner && owner <= MAX_CLIENTS && !svs.clients[owner - 1].isBot)
646 		{
647 			clip->type |= MOVE_LAGGED;
648 			w.lagents = svs.clients[owner - 1].laggedents;
649 			w.maxlagents = svs.clients[owner - 1].laggedents_count;
650 			w.lagentsfrac = svs.clients[owner - 1].laggedents_frac;
651 		}
652 	}
653 }
654 
SV_AntilagClipCheck(areanode_t * node,moveclip_t * clip)655 void SV_AntilagClipCheck ( areanode_t *node, moveclip_t *clip )
656 {
657 	trace_t trace;
658 	edict_t *touch;
659 	vec3_t lp;
660 	int i;
661 
662 	for (i = 0; i < w.maxlagents; i++)
663 	{
664 		if (clip->trace.allsolid)
665 			return; // return!!!
666 
667 		if (!w.lagents[i].present)
668 			continue;
669 
670 		touch = EDICT_NUM(i + 1);
671 		if (touch->v.solid == SOLID_NOT)
672 			continue;
673 		if (touch == clip->passedict)
674 			continue;
675 		if (touch->v.solid == SOLID_TRIGGER)
676 			SV_Error ("Trigger (%s) in clipping list", PR_GetEntityString(touch->v.classname));
677 
678 		if ((clip->type & MOVE_NOMONSTERS) && touch->v.solid != SOLID_BSP)
679 			continue;
680 
681 		VectorInterpolate(touch->v.origin, w.lagentsfrac, w.lagents[i].laggedpos, lp);
682 
683 		if (   clip->boxmins[0] > lp[0]+touch->v.maxs[0]
684 			|| clip->boxmins[1] > lp[1]+touch->v.maxs[1]
685 			|| clip->boxmins[2] > lp[2]+touch->v.maxs[2]
686 			|| clip->boxmaxs[0] < lp[0]+touch->v.mins[0]
687 			|| clip->boxmaxs[1] < lp[1]+touch->v.mins[1]
688 			|| clip->boxmaxs[2] < lp[2]+touch->v.mins[2] )
689 			continue;
690 
691 		if (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0])
692 			continue;	// points never interact
693 
694 		if (clip->passedict)
695 		{
696 			if (PROG_TO_EDICT(touch->v.owner) == clip->passedict)
697 				continue;	// don't clip against own missiles
698 			if (PROG_TO_EDICT(clip->passedict->v.owner) == touch)
699 				continue;	// don't clip against owner
700 		}
701 
702 		if ((int)touch->v.flags & FL_MONSTER)
703 			trace = SV_ClipMoveToEntity (touch, &lp, clip->start, clip->mins2, clip->maxs2, clip->end);
704 		else
705 			trace = SV_ClipMoveToEntity (touch, &lp, clip->start, clip->mins, clip->maxs, clip->end);
706 
707 		// qqshka: I have NO idea why we keep startsolid but let do it.
708 
709 		// make sure we keep a startsolid from a previous trace
710 		clip->trace.startsolid |= trace.startsolid;
711 
712 		if ( trace.allsolid || trace.fraction < clip->trace.fraction )
713 		{
714 			// set edict
715 			trace.e.ent = touch;
716 			// make sure we keep a startsolid from a previous trace
717 			trace.startsolid |= clip->trace.startsolid;
718 			// bit by bit copy trace struct
719 			clip->trace = trace;
720 		}
721 	}
722 }
723 
724 /*
725 ==================
726 SV_Trace
727 ==================
728 */
SV_Trace(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,int type,edict_t * passedict)729 trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict)
730 {
731 	moveclip_t	clip;
732 	int			i;
733 
734 	memset ( &clip, 0, sizeof ( moveclip_t ) );
735 
736 	// clip to world
737 	clip.trace = SV_ClipMoveToEntity ( sv.edicts, NULL, start, mins, maxs, end );
738 
739 	clip.start = start;
740 	clip.end = end;
741 	clip.mins = mins;
742 	clip.maxs = maxs;
743 	clip.type = type;
744 	clip.passedict = passedict;
745 
746 	if (type & MOVE_MISSILE)
747 	{
748 		for (i=0 ; i<3 ; i++)
749 		{
750 			clip.mins2[i] = -15;
751 			clip.maxs2[i] = 15;
752 		}
753 	}
754 	else
755 	{
756 		VectorCopy (mins, clip.mins2);
757 		VectorCopy (maxs, clip.maxs2);
758 	}
759 
760 	// create the bounding box of the entire move
761 	SV_MoveBounds ( start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs );
762 
763 	// set up antilag
764 	if (clip.type & MOVE_LAGGED)
765 		SV_AntilagClipSetUp ( sv_areanodes, &clip );
766 
767 	// clip to entities
768 	SV_ClipToLinks ( sv_areanodes, &clip );
769 
770 	// additional antilag clip check
771 	if (clip.type & MOVE_LAGGED)
772 		SV_AntilagClipCheck ( sv_areanodes, &clip );
773 
774 	return clip.trace;
775 }
776 
777 #endif // !CLIENTONLY
778