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