]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - world.c
lights now have an orientation (this isn't editable yet, and is infact not really...
[xonotic/darkplaces.git] / world.c
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->inopen and trace->inwater, but bullets don't
29
30 */
31
32 cvar_t sv_useareanodes = {CVAR_NOTIFY, "sv_useareanodes", "1"};
33 cvar_t sv_polygoncollisions = {CVAR_NOTIFY, "sv_polygoncollisions", "0"};
34
35 void SV_World_Init(void)
36 {
37         Cvar_RegisterVariable(&sv_useareanodes);
38         Cvar_RegisterVariable(&sv_polygoncollisions);
39         Collision_Init();
40 }
41
42 typedef struct
43 {
44         // bounding box of entire move area
45         vec3_t boxmins, boxmaxs;
46
47         // size of the moving object
48         vec3_t mins, maxs;
49
50         // size when clipping against monsters
51         vec3_t mins2, maxs2;
52
53         // size when clipping against brush models
54         vec3_t hullmins, hullmaxs;
55
56         // start and end origin of move
57         vec3_t start, end;
58
59         // trace results
60         trace_t trace;
61
62         // type of move (like ignoring monsters, or similar)
63         int type;
64
65         // the edict that is moving (if any)
66         edict_t *passedict;
67 }
68 moveclip_t;
69
70 //#define EDICT_FROM_AREA(l) ((edict_t *)((qbyte *)l - (int)&(((edict_t *)0)->area)))
71 #define EDICT_FROM_AREA(l) ((edict_t *)l->entity)
72
73 //============================================================================
74
75 // ClearLink is used for new headnodes
76 void ClearLink (link_t *l)
77 {
78         l->entity = NULL;
79         l->prev = l->next = l;
80 }
81
82 void RemoveLink (link_t *l)
83 {
84         l->next->prev = l->prev;
85         l->prev->next = l->next;
86 }
87
88 void InsertLinkBefore (link_t *l, link_t *before, void *ent)
89 {
90         l->entity = ent;
91         l->next = before;
92         l->prev = before->prev;
93         l->prev->next = l;
94         l->next->prev = l;
95 }
96
97 void InsertLinkAfter (link_t *l, link_t *after)
98 {
99         l->next = after->next;
100         l->prev = after;
101         l->prev->next = l;
102         l->next->prev = l;
103 }
104
105
106 /*
107 ===============================================================================
108
109 ENTITY AREA CHECKING
110
111 ===============================================================================
112 */
113
114 typedef struct areanode_s
115 {
116         // -1 = leaf node
117         int axis;
118         float dist;
119         struct areanode_s *children[2];
120         link_t trigger_edicts;
121         link_t solid_edicts;
122 }
123 areanode_t;
124
125 #define AREA_DEPTH 1
126 #define AREA_NODES (1 << (AREA_DEPTH + 1))
127
128 static areanode_t sv_areanodes[AREA_NODES];
129 static int sv_numareanodes;
130
131 /*
132 ===============
133 SV_CreateAreaNode
134
135 ===============
136 */
137 areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs)
138 {
139         areanode_t *anode;
140         vec3_t size, mins1, maxs1, mins2, maxs2;
141
142         anode = &sv_areanodes[sv_numareanodes];
143         sv_numareanodes++;
144
145         ClearLink (&anode->trigger_edicts);
146         ClearLink (&anode->solid_edicts);
147
148         if (depth == AREA_DEPTH)
149         {
150                 anode->axis = -1;
151                 anode->children[0] = anode->children[1] = NULL;
152                 return anode;
153         }
154
155         VectorSubtract (maxs, mins, size);
156         if (size[0] > size[1])
157                 anode->axis = 0;
158         else
159                 anode->axis = 1;
160
161         anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
162         VectorCopy (mins, mins1);
163         VectorCopy (mins, mins2);
164         VectorCopy (maxs, maxs1);
165         VectorCopy (maxs, maxs2);
166
167         maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
168
169         anode->children[0] = SV_CreateAreaNode (depth+1, mins2, maxs2);
170         anode->children[1] = SV_CreateAreaNode (depth+1, mins1, maxs1);
171
172         return anode;
173 }
174
175 typedef struct areagrid_s
176 {
177         link_t trigger_edicts;
178         link_t solid_edicts;
179 }
180 areagrid_t;
181
182 #define AREA_GRID 16
183 #define AREA_GRIDNODES (AREA_GRID * AREA_GRID)
184
185 static areagrid_t sv_areagrid[AREA_GRIDNODES];
186 static vec3_t sv_areagridbias, sv_areagridscale;
187
188 void SV_CreateAreaGrid (vec3_t mins, vec3_t maxs)
189 {
190         int i;
191         VectorNegate(mins, sv_areagridbias);
192         sv_areagridscale[0] = AREA_GRID / (maxs[0] + sv_areagridbias[0]);
193         sv_areagridscale[1] = AREA_GRID / (maxs[1] + sv_areagridbias[1]);
194         sv_areagridscale[2] = AREA_GRID / (maxs[2] + sv_areagridbias[2]);
195         for (i = 0;i < AREA_GRIDNODES;i++)
196         {
197                 ClearLink (&sv_areagrid[i].trigger_edicts);
198                 ClearLink (&sv_areagrid[i].solid_edicts);
199         }
200 }
201
202 /*
203 ===============
204 SV_ClearWorld
205
206 ===============
207 */
208 void SV_ClearWorld (void)
209 {
210         memset(sv_areanodes, 0, sizeof(sv_areanodes));
211         sv_numareanodes = 0;
212         Mod_CheckLoaded(sv.worldmodel);
213         SV_CreateAreaNode(0, sv.worldmodel->normalmins, sv.worldmodel->normalmaxs);
214         SV_CreateAreaGrid(sv.worldmodel->normalmins, sv.worldmodel->normalmaxs);
215 }
216
217
218 /*
219 ===============
220 SV_UnlinkEdict
221
222 ===============
223 */
224 void SV_UnlinkEdict (edict_t *ent)
225 {
226         int i;
227         for (i = 0;i < ENTITYGRIDAREAS;i++)
228         {
229                 if (ent->areagrid[i].prev)
230                 {
231                         RemoveLink (&ent->areagrid[i]);
232                         ent->areagrid[i].prev = ent->areagrid[i].next = NULL;
233                 }
234         }
235         if (ent->area.prev)
236         {
237                 RemoveLink (&ent->area);
238                 ent->area.prev = ent->area.next = NULL;
239         }
240 }
241
242
243 /*
244 ====================
245 SV_TouchAreaNodes
246 ====================
247 */
248 void SV_TouchAreaNodes ( edict_t *ent, areanode_t *node )
249 {
250         link_t *l, *next;
251         edict_t *touch;
252         int old_self, old_other;
253
254 loc0:
255 // touch linked edicts
256         for (l = node->trigger_edicts.next ; l != &node->trigger_edicts ; l = next)
257         {
258                 next = l->next;
259                 touch = EDICT_FROM_AREA(l);
260                 if (touch == ent)
261                         continue;
262                 if (!touch->v->touch || touch->v->solid != SOLID_TRIGGER)
263                         continue;
264                 if (ent->v->absmin[0] > touch->v->absmax[0]
265                  || ent->v->absmin[1] > touch->v->absmax[1]
266                  || ent->v->absmin[2] > touch->v->absmax[2]
267                  || ent->v->absmax[0] < touch->v->absmin[0]
268                  || ent->v->absmax[1] < touch->v->absmin[1]
269                  || ent->v->absmax[2] < touch->v->absmin[2])
270                         continue;
271                 old_self = pr_global_struct->self;
272                 old_other = pr_global_struct->other;
273
274                 pr_global_struct->self = EDICT_TO_PROG(touch);
275                 pr_global_struct->other = EDICT_TO_PROG(ent);
276                 pr_global_struct->time = sv.time;
277                 PR_ExecuteProgram (touch->v->touch, "");
278
279                 pr_global_struct->self = old_self;
280                 pr_global_struct->other = old_other;
281         }
282
283 // recurse down both sides
284         if (node->axis == -1)
285                 return;
286
287         if (ent->v->absmax[node->axis] > node->dist)
288         {
289                 if (ent->v->absmin[node->axis] < node->dist)
290                         SV_TouchAreaNodes(ent, node->children[1]); // order reversed to reduce code
291                 node = node->children[0];
292                 goto loc0;
293         }
294         else
295         {
296                 if (ent->v->absmin[node->axis] < node->dist)
297                 {
298                         node = node->children[1];
299                         goto loc0;
300                 }
301         }
302 }
303
304 void SV_TouchAreaGrid(edict_t *ent, areanode_t *node)
305 {
306         link_t *l, *next;
307         edict_t *touch;
308         areagrid_t *grid;
309         int old_self, old_other, igrid[3], igridmins[3], igridmaxs[3];
310
311         igridmins[0] = (int) ((ent->v->absmin[0] + sv_areagridbias[0]) * sv_areagridscale[0]);
312         igridmins[1] = (int) ((ent->v->absmin[1] + sv_areagridbias[1]) * sv_areagridscale[1]);
313         //igridmins[2] = (int) ((ent->v->absmin[2] + sv_areagridbias[2]) * sv_areagridscale[2]);
314         igridmaxs[0] = (int) ((ent->v->absmax[0] + sv_areagridbias[0]) * sv_areagridscale[0]) + 1;
315         igridmaxs[1] = (int) ((ent->v->absmax[1] + sv_areagridbias[1]) * sv_areagridscale[1]) + 1;
316         //igridmaxs[2] = (int) ((ent->v->absmax[2] + sv_areagridbias[2]) * sv_areagridscale[2]) + 1;
317         igridmins[0] = max(0, igridmins[0]);
318         igridmins[1] = max(0, igridmins[1]);
319         //igridmins[2] = max(0, igridmins[2]);
320         igridmaxs[0] = min(AREA_GRID, igridmaxs[0]);
321         igridmaxs[1] = min(AREA_GRID, igridmaxs[1]);
322         //igridmaxs[2] = min(AREA_GRID, igridmaxs[2]);
323
324         for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++)
325         {
326                 grid = sv_areagrid + igrid[1] * AREA_GRID + igridmins[0];
327                 for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++)
328                 {
329                         for (l = grid->trigger_edicts.next;l != &grid->trigger_edicts;l = next)
330                         {
331                                 next = l->next;
332                                 touch = EDICT_FROM_AREA(l);
333                                 if (touch == ent)
334                                         continue;
335                                 if (!touch->v->touch || touch->v->solid != SOLID_TRIGGER)
336                                         continue;
337                                 if (ent->v->absmin[0] > touch->v->absmax[0]
338                                  || ent->v->absmin[1] > touch->v->absmax[1]
339                                  || ent->v->absmin[2] > touch->v->absmax[2]
340                                  || ent->v->absmax[0] < touch->v->absmin[0]
341                                  || ent->v->absmax[1] < touch->v->absmin[1]
342                                  || ent->v->absmax[2] < touch->v->absmin[2])
343                                         continue;
344                                 old_self = pr_global_struct->self;
345                                 old_other = pr_global_struct->other;
346
347                                 pr_global_struct->self = EDICT_TO_PROG(touch);
348                                 pr_global_struct->other = EDICT_TO_PROG(ent);
349                                 pr_global_struct->time = sv.time;
350                                 PR_ExecuteProgram (touch->v->touch, "");
351
352                                 pr_global_struct->self = old_self;
353                                 pr_global_struct->other = old_other;
354                         }
355                 }
356         }
357 }
358
359 void SV_LinkEdict_AreaNode(edict_t *ent)
360 {
361         areanode_t *node;
362         // find the first node that the ent's box crosses
363         node = sv_areanodes;
364         while (1)
365         {
366                 if (node->axis == -1)
367                         break;
368                 if (ent->v->absmin[node->axis] > node->dist)
369                         node = node->children[0];
370                 else if (ent->v->absmax[node->axis] < node->dist)
371                         node = node->children[1];
372                 else
373                         break;          // crosses the node
374         }
375
376         // link it in
377
378         if (ent->v->solid == SOLID_TRIGGER)
379                 InsertLinkBefore (&ent->area, &node->trigger_edicts, ent);
380         else
381                 InsertLinkBefore (&ent->area, &node->solid_edicts, ent);
382 }
383
384 int SV_LinkEdict_AreaGrid(edict_t *ent)
385 {
386         areagrid_t *grid;
387         int igrid[3], igridmins[3], igridmaxs[3], gridnum;
388
389         igridmins[0] = (int) ((ent->v->absmin[0] + sv_areagridbias[0]) * sv_areagridscale[0]);
390         igridmins[1] = (int) ((ent->v->absmin[1] + sv_areagridbias[1]) * sv_areagridscale[1]);
391         //igridmins[2] = (int) ((ent->v->absmin[2] + sv_areagridbias[2]) * sv_areagridscale[2]);
392         igridmaxs[0] = (int) ((ent->v->absmax[0] + sv_areagridbias[0]) * sv_areagridscale[0]) + 1;
393         igridmaxs[1] = (int) ((ent->v->absmax[1] + sv_areagridbias[1]) * sv_areagridscale[1]) + 1;
394         //igridmaxs[2] = (int) ((ent->v->absmax[2] + sv_areagridbias[2]) * sv_areagridscale[2]) + 1;
395         if (igridmins[0] < 0 || igridmaxs[0] > AREA_GRID || igridmins[1] < 0 || igridmaxs[1] > AREA_GRID || ((igridmaxs[0] - igridmins[0]) * (igridmaxs[1] - igridmins[1])) > ENTITYGRIDAREAS)
396                 return false;
397
398         gridnum = 0;
399         for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++)
400         {
401                 grid = sv_areagrid + igrid[1] * AREA_GRID + igridmins[0];
402                 for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++, gridnum++)
403                 {
404                         if (ent->v->solid == SOLID_TRIGGER)
405                                 InsertLinkBefore (&ent->areagrid[gridnum], &grid->trigger_edicts, ent);
406                         else
407                                 InsertLinkBefore (&ent->areagrid[gridnum], &grid->solid_edicts, ent);
408                 }
409         }
410         return true;
411 }
412
413 /*
414 ===============
415 SV_LinkEdict
416
417 ===============
418 */
419 void SV_LinkEdict (edict_t *ent, qboolean touch_triggers)
420 {
421         model_t *model;
422
423         if (ent->area.prev || ent->areagrid[0].prev)
424                 SV_UnlinkEdict (ent);   // unlink from old position
425
426         if (ent == sv.edicts)
427                 return;         // don't add the world
428
429         if (ent->free)
430                 return;
431
432 // set the abs box
433
434         if (ent->v->solid == SOLID_BSP)
435         {
436                 if (ent->v->modelindex < 0 || ent->v->modelindex > MAX_MODELS)
437                         Host_Error("SOLID_BSP with invalid modelindex!\n");
438                 model = sv.models[(int) ent->v->modelindex];
439                 if (model != NULL)
440                 {
441                         if (model->type != mod_brush)
442                                 Host_Error("SOLID_BSP with non-BSP model\n");
443
444                         if (ent->v->angles[0] || ent->v->angles[2] || ent->v->avelocity[0] || ent->v->avelocity[2])
445                         {
446                                 VectorAdd(ent->v->origin, model->rotatedmins, ent->v->absmin);
447                                 VectorAdd(ent->v->origin, model->rotatedmaxs, ent->v->absmax);
448                         }
449                         else if (ent->v->angles[1] || ent->v->avelocity[1])
450                         {
451                                 VectorAdd(ent->v->origin, model->yawmins, ent->v->absmin);
452                                 VectorAdd(ent->v->origin, model->yawmaxs, ent->v->absmax);
453                         }
454                         else
455                         {
456                                 VectorAdd(ent->v->origin, model->normalmins, ent->v->absmin);
457                                 VectorAdd(ent->v->origin, model->normalmaxs, ent->v->absmax);
458                         }
459                 }
460                 else
461                 {
462                         // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily
463                         VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmin);
464                         VectorAdd(ent->v->origin, ent->v->maxs, ent->v->absmax);
465                 }
466         }
467         else
468         {
469                 VectorAdd(ent->v->origin, ent->v->mins, ent->v->absmin);
470                 VectorAdd(ent->v->origin, ent->v->maxs, ent->v->absmax);
471         }
472
473 //
474 // to make items easier to pick up and allow them to be grabbed off
475 // of shelves, the abs sizes are expanded
476 //
477         if ((int)ent->v->flags & FL_ITEM)
478         {
479                 ent->v->absmin[0] -= 15;
480                 ent->v->absmin[1] -= 15;
481                 ent->v->absmin[2] -= 1;
482                 ent->v->absmax[0] += 15;
483                 ent->v->absmax[1] += 15;
484                 ent->v->absmax[2] += 1;
485         }
486         else
487         {
488                 // because movement is clipped an epsilon away from an actual edge,
489                 // we must fully check even when bounding boxes don't quite touch
490                 ent->v->absmin[0] -= 1;
491                 ent->v->absmin[1] -= 1;
492                 ent->v->absmin[2] -= 1;
493                 ent->v->absmax[0] += 1;
494                 ent->v->absmax[1] += 1;
495                 ent->v->absmax[2] += 1;
496         }
497
498         if (ent->v->solid == SOLID_NOT)
499                 return;
500
501         // try to link into areagrid, if that fails fall back on areanode
502         if (!SV_LinkEdict_AreaGrid(ent))
503                 SV_LinkEdict_AreaNode(ent);
504
505 // if touch_triggers, touch all entities at this node and descend for more
506         if (touch_triggers)
507         {
508                 SV_TouchAreaNodes(ent, sv_areanodes);
509                 SV_TouchAreaGrid(ent, sv_areanodes);
510         }
511 }
512
513
514
515 /*
516 ===============================================================================
517
518 POINT TESTING IN HULLS
519
520 ===============================================================================
521 */
522
523 /*
524 ============
525 SV_TestEntityPosition
526
527 This could be a lot more efficient...
528 ============
529 */
530 int SV_TestEntityPosition (edict_t *ent)
531 {
532         return SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, ent->v->origin, MOVE_NORMAL, ent).startsolid;
533 }
534
535
536 /*
537 ===============================================================================
538
539 LINE TESTING IN HULLS
540
541 ===============================================================================
542 */
543
544 /*
545 ==================
546 SV_ClipMoveToEntity
547
548 Handles selection or creation of a clipping hull, and offseting (and
549 eventually rotation) of the end points
550 ==================
551 */
552 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)
553 {
554         int i;
555         trace_t trace;
556         model_t *model;
557
558         i = ent->v->modelindex;
559         if ((unsigned int) i >= MAX_MODELS)
560                 Host_Error("SV_ClipMoveToEntity: invalid modelindex\n");
561         model = sv.models[i];
562         if (i != 0 && model == NULL)
563                 Host_Error("SV_ClipMoveToEntity: invalid modelindex\n");
564
565         if ((int) ent->v->solid == SOLID_BSP)
566         {
567                 Mod_CheckLoaded(model);
568                 if (model->type != mod_brush)
569                 {
570                         Con_Printf ("SV_ClipMoveToEntity: SOLID_BSP with a non bsp model, entity dump:\n");
571                         ED_Print (ent);
572                         Host_Error ("SV_ClipMoveToEntity: SOLID_BSP with a non bsp model\n");
573                 }
574                 if (ent->v->movetype != MOVETYPE_PUSH)
575                         Host_Error ("SV_ClipMoveToEntity: SOLID_BSP without MOVETYPE_PUSH");
576         }
577
578         if (sv_polygoncollisions.integer && (mins[0] != maxs[0] || mins[1] != maxs[1] || mins[2] != maxs[2]))
579                 Collision_PolygonClipTrace(&trace, ent, model, ent->v->origin, ent->v->angles, ent->v->mins, ent->v->maxs, start, mins, maxs, end);
580         else
581                 Collision_ClipTrace(&trace, ent, model, ent->v->origin, ent->v->angles, ent->v->mins, ent->v->maxs, start, mins, maxs, end);
582
583         return trace;
584 }
585
586 //===========================================================================
587
588 /*
589 ====================
590 SV_ClipToAreaNodes
591
592 Mins and maxs enclose the entire area swept by the move
593 ====================
594 */
595 void SV_ClipToAreaNodes ( areanode_t *node, moveclip_t *clip )
596 {
597         link_t *l, *next;
598         edict_t *touch;
599         trace_t trace;
600
601 loc0:
602         if (clip->trace.allsolid)
603                 return;
604 // touch linked edicts
605         for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
606         {
607                 next = l->next;
608                 touch = EDICT_FROM_AREA(l);
609                 if (touch->v->solid == SOLID_NOT)
610                         continue;
611                 if (touch == clip->passedict)
612                         continue;
613                 if (touch->v->solid == SOLID_TRIGGER)
614                 {
615                         ED_Print(touch);
616                         Host_Error ("Trigger in clipping list");
617                 }
618
619                 if (clip->type == MOVE_NOMONSTERS && touch->v->solid != SOLID_BSP)
620                         continue;
621
622                 if (clip->boxmins[0] > touch->v->absmax[0]
623                  || clip->boxmaxs[0] < touch->v->absmin[0]
624                  || clip->boxmins[1] > touch->v->absmax[1]
625                  || clip->boxmaxs[1] < touch->v->absmin[1]
626                  || clip->boxmins[2] > touch->v->absmax[2]
627                  || clip->boxmaxs[2] < touch->v->absmin[2])
628                         continue;
629
630                 if (clip->passedict)
631                 {
632                         if (clip->passedict->v->size[0] && !touch->v->size[0])
633                                 continue;       // points never interact
634                         if (PROG_TO_EDICT(touch->v->owner) == clip->passedict)
635                                 continue;       // don't clip against own missiles
636                         if (PROG_TO_EDICT(clip->passedict->v->owner) == touch)
637                                 continue;       // don't clip against owner
638                         // LordHavoc: corpse code
639                         if (clip->passedict->v->solid == SOLID_CORPSE && (touch->v->solid == SOLID_SLIDEBOX || touch->v->solid == SOLID_CORPSE))
640                                 continue;
641                         if (clip->passedict->v->solid == SOLID_SLIDEBOX && touch->v->solid == SOLID_CORPSE)
642                                 continue;
643                 }
644
645                 // might interact, so do an exact clip
646                 if (touch->v->solid == SOLID_BSP)
647                         trace = SV_ClipMoveToEntity (touch, clip->start, clip->hullmins, clip->hullmaxs, clip->end);
648                 else if ((int)touch->v->flags & FL_MONSTER)
649                         trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end);
650                 else
651                         trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end);
652                 // LordHavoc: take the 'best' answers from the new trace and combine with existing data
653                 if (trace.allsolid)
654                         clip->trace.allsolid = true;
655                 if (trace.startsolid)
656                 {
657                         clip->trace.startsolid = true;
658                         if (!clip->trace.ent)
659                                 clip->trace.ent = trace.ent;
660                 }
661                 if (trace.inopen)
662                         clip->trace.inopen = true;
663                 if (trace.inwater)
664                         clip->trace.inwater = true;
665                 if (trace.fraction < clip->trace.fraction)
666                 {
667                         clip->trace.fraction = trace.fraction;
668                         VectorCopy(trace.endpos, clip->trace.endpos);
669                         clip->trace.plane = trace.plane;
670                         clip->trace.endcontents = trace.endcontents;
671                         clip->trace.ent = trace.ent;
672                 }
673         }
674
675 // recurse down both sides
676         if (node->axis == -1)
677                 return;
678
679         if (clip->boxmaxs[node->axis] > node->dist)
680         {
681                 if (clip->boxmins[node->axis] < node->dist)
682                         SV_ClipToAreaNodes(node->children[1], clip);
683                 node = node->children[0];
684                 goto loc0;
685         }
686         else if (clip->boxmins[node->axis] < node->dist)
687         {
688                 node = node->children[1];
689                 goto loc0;
690         }
691 }
692
693 /*
694 ====================
695 SV_ClipToAreaGrid
696
697 Mins and maxs enclose the entire area swept by the move
698 ====================
699 */
700 void SV_ClipToAreaGrid(moveclip_t *clip)
701 {
702         link_t *l, *next;
703         edict_t *touch;
704         areagrid_t *grid;
705         int igrid[3], igridmins[3], igridmaxs[3];
706         trace_t trace;
707
708         if (clip->trace.allsolid)
709                 return;
710
711         igridmins[0] = (int) ((clip->boxmins[0] + sv_areagridbias[0]) * sv_areagridscale[0]);
712         igridmins[1] = (int) ((clip->boxmins[1] + sv_areagridbias[1]) * sv_areagridscale[1]);
713         //igridmins[2] = (int) ((clip->boxmins[2] + sv_areagridbias[2]) * sv_areagridscale[2]);
714         igridmaxs[0] = (int) ((clip->boxmaxs[0] + sv_areagridbias[0]) * sv_areagridscale[0]) + 1;
715         igridmaxs[1] = (int) ((clip->boxmaxs[1] + sv_areagridbias[1]) * sv_areagridscale[1]) + 1;
716         //igridmaxs[2] = (int) ((clip->boxmaxs[2] + sv_areagridbias[2]) * sv_areagridscale[2]) + 1;
717         igridmins[0] = max(0, igridmins[0]);
718         igridmins[1] = max(0, igridmins[1]);
719         //igridmins[2] = max(0, igridmins[2]);
720         igridmaxs[0] = min(AREA_GRID, igridmaxs[0]);
721         igridmaxs[1] = min(AREA_GRID, igridmaxs[1]);
722         //igridmaxs[2] = min(AREA_GRID, igridmaxs[2]);
723
724         for (igrid[1] = igridmins[1];igrid[1] < igridmaxs[1];igrid[1]++)
725         {
726                 grid = sv_areagrid + igrid[1] * AREA_GRID + igridmins[0];
727                 for (igrid[0] = igridmins[0];igrid[0] < igridmaxs[0];igrid[0]++, grid++)
728                 {
729                         for (l = grid->solid_edicts.next;l != &grid->solid_edicts;l = next)
730                         {
731                                 next = l->next;
732                                 touch = EDICT_FROM_AREA(l);
733                                 if (touch->v->solid == SOLID_NOT)
734                                         continue;
735                                 if (touch == clip->passedict)
736                                         continue;
737                                 if (touch->v->solid == SOLID_TRIGGER)
738                                 {
739                                         ED_Print(touch);
740                                         Host_Error ("Trigger in clipping list");
741                                 }
742
743                                 if (clip->type == MOVE_NOMONSTERS && touch->v->solid != SOLID_BSP)
744                                         continue;
745
746                                 if (clip->boxmins[0] > touch->v->absmax[0]
747                                  || clip->boxmaxs[0] < touch->v->absmin[0]
748                                  || clip->boxmins[1] > touch->v->absmax[1]
749                                  || clip->boxmaxs[1] < touch->v->absmin[1]
750                                  || clip->boxmins[2] > touch->v->absmax[2]
751                                  || clip->boxmaxs[2] < touch->v->absmin[2])
752                                         continue;
753
754                                 if (clip->passedict)
755                                 {
756                                         if (clip->passedict->v->size[0] && !touch->v->size[0])
757                                                 continue;       // points never interact
758                                         if (PROG_TO_EDICT(touch->v->owner) == clip->passedict)
759                                                 continue;       // don't clip against own missiles
760                                         if (PROG_TO_EDICT(clip->passedict->v->owner) == touch)
761                                                 continue;       // don't clip against owner
762                                         // LordHavoc: corpse code
763                                         if (clip->passedict->v->solid == SOLID_CORPSE && (touch->v->solid == SOLID_SLIDEBOX || touch->v->solid == SOLID_CORPSE))
764                                                 continue;
765                                         if (clip->passedict->v->solid == SOLID_SLIDEBOX && touch->v->solid == SOLID_CORPSE)
766                                                 continue;
767                                 }
768
769                                 // might interact, so do an exact clip
770                                 if (touch->v->solid == SOLID_BSP)
771                                         trace = SV_ClipMoveToEntity (touch, clip->start, clip->hullmins, clip->hullmaxs, clip->end);
772                                 else if ((int)touch->v->flags & FL_MONSTER)
773                                         trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins2, clip->maxs2, clip->end);
774                                 else
775                                         trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end);
776                                 // LordHavoc: take the 'best' answers from the new trace and combine with existing data
777                                 if (trace.allsolid)
778                                         clip->trace.allsolid = true;
779                                 if (trace.startsolid)
780                                 {
781                                         clip->trace.startsolid = true;
782                                         if (!clip->trace.ent)
783                                                 clip->trace.ent = trace.ent;
784                                 }
785                                 if (trace.inopen)
786                                         clip->trace.inopen = true;
787                                 if (trace.inwater)
788                                         clip->trace.inwater = true;
789                                 if (trace.fraction < clip->trace.fraction)
790                                 {
791                                         clip->trace.fraction = trace.fraction;
792                                         VectorCopy(trace.endpos, clip->trace.endpos);
793                                         clip->trace.plane = trace.plane;
794                                         clip->trace.endcontents = trace.endcontents;
795                                         clip->trace.ent = trace.ent;
796                                 }
797                                 if (clip->trace.allsolid)
798                                         return;
799                         }
800                 }
801         }
802 }
803
804
805 /*
806 ==================
807 SV_MoveBounds
808 ==================
809 */
810 void SV_MoveBounds (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)
811 {
812         if (sv_useareanodes.integer)
813         {
814                 int i;
815
816                 for (i=0 ; i<3 ; i++)
817                 {
818                         if (end[i] > start[i])
819                         {
820                                 boxmins[i] = start[i] + mins[i] - 1;
821                                 boxmaxs[i] = end[i] + maxs[i] + 1;
822                         }
823                         else
824                         {
825                                 boxmins[i] = end[i] + mins[i] - 1;
826                                 boxmaxs[i] = start[i] + maxs[i] + 1;
827                         }
828                 }
829         }
830         else
831         {
832                 // debug to test against everything
833                 boxmins[0] = boxmins[1] = boxmins[2] = -999999999;
834                 boxmaxs[0] = boxmaxs[1] = boxmaxs[2] =  999999999;
835         }
836 }
837
838 /*
839 ==================
840 SV_Move
841 ==================
842 */
843 trace_t SV_Move (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict)
844 {
845         moveclip_t      clip;
846         vec3_t          bigmins, bigmaxs;
847         int                     i;
848
849         memset ( &clip, 0, sizeof ( moveclip_t ) );
850
851         VectorCopy(start, clip.start);
852         VectorCopy(end, clip.end);
853         VectorCopy(mins, clip.mins);
854         VectorCopy(maxs, clip.maxs);
855         clip.type = type;
856         clip.passedict = passedict;
857
858         Collision_RoundUpToHullSize(sv.worldmodel, clip.mins, clip.maxs, clip.hullmins, clip.hullmaxs);
859
860         if (type == MOVE_MISSILE)
861         {
862                 // LordHavoc: modified this, was = -15, now = clip.mins[i] - 15
863                 for (i=0 ; i<3 ; i++)
864                 {
865                         clip.mins2[i] = clip.mins[i] - 15;
866                         clip.maxs2[i] = clip.maxs[i] + 15;
867                 }
868         }
869         else
870         {
871                 VectorCopy (clip.mins, clip.mins2);
872                 VectorCopy (clip.maxs, clip.maxs2);
873         }
874
875         bigmins[0] = min(clip.mins2[0], clip.hullmins[0]);
876         bigmaxs[0] = max(clip.maxs2[0], clip.hullmaxs[0]);
877         bigmins[1] = min(clip.mins2[1], clip.hullmins[1]);
878         bigmaxs[1] = max(clip.maxs2[1], clip.hullmaxs[1]);
879         bigmins[2] = min(clip.mins2[2], clip.hullmins[2]);
880         bigmaxs[2] = max(clip.maxs2[2], clip.hullmaxs[2]);
881
882         // clip to world
883         clip.trace = SV_ClipMoveToEntity (sv.edicts, start, mins, maxs, end);
884
885         // clip to entities
886         // create the bounding box of the entire move
887         SV_MoveBounds ( start, bigmins, bigmaxs, end, clip.boxmins, clip.boxmaxs );
888
889         SV_ClipToAreaNodes(sv_areanodes, &clip);
890         SV_ClipToAreaGrid(&clip);
891
892         return clip.trace;
893 }
894