]> git.xonotic.org Git - xonotic/darkplaces.git/blob - sv_phys.c
SV_PushMove: no longer assume that just rotating the origin is correct
[xonotic/darkplaces.git] / sv_phys.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 // sv_phys.c
21
22 #include "quakedef.h"
23
24 /*
25
26
27 pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
28
29 onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects
30
31 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
32 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
33 corpses are SOLID_NOT and MOVETYPE_TOSS
34 crates are SOLID_BBOX and MOVETYPE_TOSS
35 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
36 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
37
38 solid_edge items only clip against bsp models.
39
40 */
41
42 #define MOVE_EPSILON    0.01
43
44 void SV_Physics_Toss (prvm_edict_t *ent);
45
46 int SV_GetPitchSign(prvm_edict_t *ent)
47 {
48         dp_model_t *model;
49         if (
50                         (model = SV_GetModelFromEdict(ent))
51                         ?
52                         model->type == mod_alias
53                         :
54                         (
55                          (((unsigned char)PRVM_serveredictfloat(ent, pflags)) & PFLAGS_FULLDYNAMIC)
56                          ||
57                          ((gamemode == GAME_TENEBRAE) && ((unsigned int)PRVM_serveredictfloat(ent, effects) & (16 | 32)))
58                         )
59            )
60                 return -1;
61         return 1;
62 }
63
64 /*
65 ===============================================================================
66
67 LINE TESTING IN HULLS
68
69 ===============================================================================
70 */
71
72 int SV_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
73 {
74         if (passedict)
75         {
76                 int dphitcontentsmask = (int)PRVM_serveredictfloat(passedict, dphitcontentsmask);
77                 if (dphitcontentsmask)
78                         return dphitcontentsmask;
79                 else if (PRVM_serveredictfloat(passedict, solid) == SOLID_SLIDEBOX)
80                 {
81                         if ((int)PRVM_serveredictfloat(passedict, flags) & FL_MONSTER)
82                                 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_MONSTERCLIP;
83                         else
84                                 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP;
85                 }
86                 else if (PRVM_serveredictfloat(passedict, solid) == SOLID_CORPSE)
87                         return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;
88                 else if (PRVM_serveredictfloat(passedict, solid) == SOLID_TRIGGER)
89                         return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY;
90                 else
91                         return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE;
92         }
93         else
94                 return SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_CORPSE;
95 }
96
97 /*
98 ==================
99 SV_TracePoint
100 ==================
101 */
102 trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
103 {
104         int i, bodysupercontents;
105         int passedictprog;
106         float pitchsign = 1;
107         prvm_edict_t *traceowner, *touch;
108         trace_t trace;
109         // bounding box of entire move area
110         vec3_t clipboxmins, clipboxmaxs;
111         // size when clipping against monsters
112         vec3_t clipmins2, clipmaxs2;
113         // start and end origin of move
114         vec3_t clipstart;
115         // trace results
116         trace_t cliptrace;
117         // matrices to transform into/out of other entity's space
118         matrix4x4_t matrix, imatrix;
119         // model of other entity
120         dp_model_t *model;
121         // list of entities to test for collisions
122         int numtouchedicts;
123         static prvm_edict_t *touchedicts[MAX_EDICTS];
124
125         //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask);
126
127         VectorCopy(start, clipstart);
128         VectorClear(clipmins2);
129         VectorClear(clipmaxs2);
130 #if COLLISIONPARANOID >= 3
131         Con_Printf("move(%f %f %f)", clipstart[0], clipstart[1], clipstart[2]);
132 #endif
133
134         // clip to world
135         Collision_ClipPointToWorld(&cliptrace, sv.worldmodel, clipstart, hitsupercontentsmask);
136         cliptrace.bmodelstartsolid = cliptrace.startsolid;
137         if (cliptrace.startsolid || cliptrace.fraction < 1)
138                 cliptrace.ent = prog->edicts;
139         if (type == MOVE_WORLDONLY)
140                 goto finished;
141
142         if (type == MOVE_MISSILE)
143         {
144                 // LordHavoc: modified this, was = -15, now -= 15
145                 for (i = 0;i < 3;i++)
146                 {
147                         clipmins2[i] -= 15;
148                         clipmaxs2[i] += 15;
149                 }
150         }
151
152         // create the bounding box of the entire move
153         for (i = 0;i < 3;i++)
154         {
155                 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1;
156                 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1;
157         }
158
159         // debug override to test against everything
160         if (sv_debugmove.integer)
161         {
162                 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
163                 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] =  999999999;
164         }
165
166         // if the passedict is world, make it NULL (to avoid two checks each time)
167         if (passedict == prog->edicts)
168                 passedict = NULL;
169         // precalculate prog value for passedict for comparisons
170         passedictprog = PRVM_EDICT_TO_PROG(passedict);
171         // precalculate passedict's owner edict pointer for comparisons
172         traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
173
174         // clip to entities
175         // because this uses World_EntitiestoBox, we know all entity boxes overlap
176         // the clip region, so we can skip culling checks in the loop below
177         numtouchedicts = World_EntitiesInBox(&sv.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
178         if (numtouchedicts > MAX_EDICTS)
179         {
180                 // this never happens
181                 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
182                 numtouchedicts = MAX_EDICTS;
183         }
184         for (i = 0;i < numtouchedicts;i++)
185         {
186                 touch = touchedicts[i];
187
188                 if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
189                         continue;
190                 if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
191                         continue;
192
193                 if (passedict)
194                 {
195                         // don't clip against self
196                         if (passedict == touch)
197                                 continue;
198                         // don't clip owned entities against owner
199                         if (traceowner == touch)
200                                 continue;
201                         // don't clip owner against owned entities
202                         if (passedictprog == PRVM_serveredictedict(touch, owner))
203                                 continue;
204                         // don't clip points against points (they can't collide)
205                         if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
206                                 continue;
207                 }
208
209                 bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
210
211                 // might interact, so do an exact clip
212                 model = NULL;
213                 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
214                 {
215                         model = SV_GetModelFromEdict(touch);
216                         pitchsign = SV_GetPitchSign(touch);
217                 }
218                 if (model)
219                         Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
220                 else
221                         Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
222                 Matrix4x4_Invert_Simple(&imatrix, &matrix);
223                 VM_GenerateFrameGroupBlend(touch->priv.server->framegroupblend, touch);
224                 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
225                 VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
226                 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
227                         Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask);
228                 else
229                         Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
230
231                 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
232         }
233
234 finished:
235         return cliptrace;
236 }
237
238 /*
239 ==================
240 SV_TraceLine
241 ==================
242 */
243 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
244 trace_t SV_TraceLine(const vec3_t start, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
245 #else
246 trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
247 #endif
248 {
249         int i, bodysupercontents;
250         int passedictprog;
251         float pitchsign = 1;
252         prvm_edict_t *traceowner, *touch;
253         trace_t trace;
254         // bounding box of entire move area
255         vec3_t clipboxmins, clipboxmaxs;
256         // size when clipping against monsters
257         vec3_t clipmins2, clipmaxs2;
258         // start and end origin of move
259         vec3_t clipstart, clipend;
260         // trace results
261         trace_t cliptrace;
262         // matrices to transform into/out of other entity's space
263         matrix4x4_t matrix, imatrix;
264         // model of other entity
265         dp_model_t *model;
266         // list of entities to test for collisions
267         int numtouchedicts;
268         static prvm_edict_t *touchedicts[MAX_EDICTS];
269 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
270         vec3_t end;
271         vec_t len = 0;
272
273         if (VectorCompare(start, pEnd))
274                 return SV_TracePoint(start, type, passedict, hitsupercontentsmask);
275
276         if(collision_endposnudge.value > 0)
277         {
278                 // TRICK: make the trace 1 qu longer!
279                 VectorSubtract(pEnd, start, end);
280                 len = VectorNormalizeLength(end);
281                 VectorMA(pEnd, collision_endposnudge.value, end, end);
282         }
283         else
284                 VectorCopy(pEnd, end);
285 #else
286         if (VectorCompare(start, end))
287                 return SV_TracePoint(start, type, passedict, hitsupercontentsmask);
288 #endif
289
290         //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask);
291
292         VectorCopy(start, clipstart);
293         VectorCopy(end, clipend);
294         VectorClear(clipmins2);
295         VectorClear(clipmaxs2);
296 #if COLLISIONPARANOID >= 3
297         Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]);
298 #endif
299
300         // clip to world
301         Collision_ClipLineToWorld(&cliptrace, sv.worldmodel, clipstart, clipend, hitsupercontentsmask, false);
302         cliptrace.bmodelstartsolid = cliptrace.startsolid;
303         if (cliptrace.startsolid || cliptrace.fraction < 1)
304                 cliptrace.ent = prog->edicts;
305         if (type == MOVE_WORLDONLY)
306                 goto finished;
307
308         if (type == MOVE_MISSILE)
309         {
310                 // LordHavoc: modified this, was = -15, now -= 15
311                 for (i = 0;i < 3;i++)
312                 {
313                         clipmins2[i] -= 15;
314                         clipmaxs2[i] += 15;
315                 }
316         }
317
318         // create the bounding box of the entire move
319         for (i = 0;i < 3;i++)
320         {
321                 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + clipmins2[i] - 1;
322                 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + clipmaxs2[i] + 1;
323         }
324
325         // debug override to test against everything
326         if (sv_debugmove.integer)
327         {
328                 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
329                 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] =  999999999;
330         }
331
332         // if the passedict is world, make it NULL (to avoid two checks each time)
333         if (passedict == prog->edicts)
334                 passedict = NULL;
335         // precalculate prog value for passedict for comparisons
336         passedictprog = PRVM_EDICT_TO_PROG(passedict);
337         // precalculate passedict's owner edict pointer for comparisons
338         traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
339
340         // clip to entities
341         // because this uses World_EntitiestoBox, we know all entity boxes overlap
342         // the clip region, so we can skip culling checks in the loop below
343         numtouchedicts = World_EntitiesInBox(&sv.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
344         if (numtouchedicts > MAX_EDICTS)
345         {
346                 // this never happens
347                 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
348                 numtouchedicts = MAX_EDICTS;
349         }
350         for (i = 0;i < numtouchedicts;i++)
351         {
352                 touch = touchedicts[i];
353
354                 if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
355                         continue;
356                 if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
357                         continue;
358
359                 if (passedict)
360                 {
361                         // don't clip against self
362                         if (passedict == touch)
363                                 continue;
364                         // don't clip owned entities against owner
365                         if (traceowner == touch)
366                                 continue;
367                         // don't clip owner against owned entities
368                         if (passedictprog == PRVM_serveredictedict(touch, owner))
369                                 continue;
370                         // don't clip points against points (they can't collide)
371                         if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
372                                 continue;
373                 }
374
375                 bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
376
377                 // might interact, so do an exact clip
378                 model = NULL;
379                 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
380                 {
381                         model = SV_GetModelFromEdict(touch);
382                         pitchsign = SV_GetPitchSign(touch);
383                 }
384                 if (model)
385                         Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
386                 else
387                         Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
388                 Matrix4x4_Invert_Simple(&imatrix, &matrix);
389                 VM_GenerateFrameGroupBlend(touch->priv.server->framegroupblend, touch);
390                 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
391                 VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
392                 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
393                         Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
394                 else
395                         Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, false);
396
397                 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
398         }
399
400 finished:
401 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
402         if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
403                 Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
404 #endif
405         return cliptrace;
406 }
407
408 /*
409 ==================
410 SV_Move
411 ==================
412 */
413 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
414 #if COLLISIONPARANOID >= 1
415 trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
416 #else
417 trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
418 #endif
419 #else
420 #if COLLISIONPARANOID >= 1
421 trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
422 #else
423 trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
424 #endif
425 #endif
426 {
427         vec3_t hullmins, hullmaxs;
428         int i, bodysupercontents;
429         int passedictprog;
430         float pitchsign = 1;
431         qboolean pointtrace;
432         prvm_edict_t *traceowner, *touch;
433         trace_t trace;
434         // bounding box of entire move area
435         vec3_t clipboxmins, clipboxmaxs;
436         // size of the moving object
437         vec3_t clipmins, clipmaxs;
438         // size when clipping against monsters
439         vec3_t clipmins2, clipmaxs2;
440         // start and end origin of move
441         vec3_t clipstart, clipend;
442         // trace results
443         trace_t cliptrace;
444         // matrices to transform into/out of other entity's space
445         matrix4x4_t matrix, imatrix;
446         // model of other entity
447         dp_model_t *model;
448         // list of entities to test for collisions
449         int numtouchedicts;
450         static prvm_edict_t *touchedicts[MAX_EDICTS];
451 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
452         vec3_t end;
453         vec_t len = 0;
454
455         if (VectorCompare(mins, maxs))
456         {
457                 vec3_t shiftstart, shiftend;
458                 VectorAdd(start, mins, shiftstart);
459                 VectorAdd(pEnd, mins, shiftend);
460                 if (VectorCompare(start, pEnd))
461                         trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask);
462                 else
463                         trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask);
464                 VectorSubtract(trace.endpos, mins, trace.endpos);
465                 return trace;
466         }
467
468         if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
469         {
470                 // TRICK: make the trace 1 qu longer!
471                 VectorSubtract(pEnd, start, end);
472                 len = VectorNormalizeLength(end);
473                 VectorMA(pEnd, collision_endposnudge.value, end, end);
474         }
475         else
476                 VectorCopy(pEnd, end);
477 #else
478         if (VectorCompare(mins, maxs))
479         {
480                 vec3_t shiftstart, shiftend;
481                 VectorAdd(start, mins, shiftstart);
482                 VectorAdd(end, mins, shiftend);
483                 if (VectorCompare(start, end))
484                         trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask);
485                 else
486                         trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask);
487                 VectorSubtract(trace.endpos, mins, trace.endpos);
488                 return trace;
489         }
490 #endif
491
492         VectorCopy(start, clipstart);
493         VectorCopy(end, clipend);
494         VectorCopy(mins, clipmins);
495         VectorCopy(maxs, clipmaxs);
496         VectorCopy(mins, clipmins2);
497         VectorCopy(maxs, clipmaxs2);
498 #if COLLISIONPARANOID >= 3
499         Con_Printf("move(%f %f %f,%f %f %f)", clipstart[0], clipstart[1], clipstart[2], clipend[0], clipend[1], clipend[2]);
500 #endif
501
502         // clip to world
503         Collision_ClipToWorld(&cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
504         cliptrace.bmodelstartsolid = cliptrace.startsolid;
505         if (cliptrace.startsolid || cliptrace.fraction < 1)
506                 cliptrace.ent = prog->edicts;
507         if (type == MOVE_WORLDONLY)
508                 goto finished;
509
510         if (type == MOVE_MISSILE)
511         {
512                 // LordHavoc: modified this, was = -15, now -= 15
513                 for (i = 0;i < 3;i++)
514                 {
515                         clipmins2[i] -= 15;
516                         clipmaxs2[i] += 15;
517                 }
518         }
519
520         // get adjusted box for bmodel collisions if the world is q1bsp or hlbsp
521         if (sv.worldmodel && sv.worldmodel->brush.RoundUpToHullSize)
522                 sv.worldmodel->brush.RoundUpToHullSize(sv.worldmodel, clipmins, clipmaxs, hullmins, hullmaxs);
523         else
524         {
525                 VectorCopy(clipmins, hullmins);
526                 VectorCopy(clipmaxs, hullmaxs);
527         }
528
529         // create the bounding box of the entire move
530         for (i = 0;i < 3;i++)
531         {
532                 clipboxmins[i] = min(clipstart[i], cliptrace.endpos[i]) + min(hullmins[i], clipmins2[i]) - 1;
533                 clipboxmaxs[i] = max(clipstart[i], cliptrace.endpos[i]) + max(hullmaxs[i], clipmaxs2[i]) + 1;
534         }
535
536         // debug override to test against everything
537         if (sv_debugmove.integer)
538         {
539                 clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
540                 clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] =  999999999;
541         }
542
543         // if the passedict is world, make it NULL (to avoid two checks each time)
544         if (passedict == prog->edicts)
545                 passedict = NULL;
546         // precalculate prog value for passedict for comparisons
547         passedictprog = PRVM_EDICT_TO_PROG(passedict);
548         // figure out whether this is a point trace for comparisons
549         pointtrace = VectorCompare(clipmins, clipmaxs);
550         // precalculate passedict's owner edict pointer for comparisons
551         traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
552
553         // clip to entities
554         // because this uses World_EntitiestoBox, we know all entity boxes overlap
555         // the clip region, so we can skip culling checks in the loop below
556         numtouchedicts = World_EntitiesInBox(&sv.world, clipboxmins, clipboxmaxs, MAX_EDICTS, touchedicts);
557         if (numtouchedicts > MAX_EDICTS)
558         {
559                 // this never happens
560                 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
561                 numtouchedicts = MAX_EDICTS;
562         }
563         for (i = 0;i < numtouchedicts;i++)
564         {
565                 touch = touchedicts[i];
566
567                 if (PRVM_serveredictfloat(touch, solid) < SOLID_BBOX)
568                         continue;
569                 if (type == MOVE_NOMONSTERS && PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
570                         continue;
571
572                 if (passedict)
573                 {
574                         // don't clip against self
575                         if (passedict == touch)
576                                 continue;
577                         // don't clip owned entities against owner
578                         if (traceowner == touch)
579                                 continue;
580                         // don't clip owner against owned entities
581                         if (passedictprog == PRVM_serveredictedict(touch, owner))
582                                 continue;
583                         // don't clip points against points (they can't collide)
584                         if (pointtrace && VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
585                                 continue;
586                 }
587
588                 bodysupercontents = PRVM_serveredictfloat(touch, solid) == SOLID_CORPSE ? SUPERCONTENTS_CORPSE : SUPERCONTENTS_BODY;
589
590                 // might interact, so do an exact clip
591                 model = NULL;
592                 if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
593                 {
594                         model = SV_GetModelFromEdict(touch);
595                         pitchsign = SV_GetPitchSign(touch);
596                 }
597                 if (model)
598                         Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
599                 else
600                         Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
601                 Matrix4x4_Invert_Simple(&imatrix, &matrix);
602                 VM_GenerateFrameGroupBlend(touch->priv.server->framegroupblend, touch);
603                 VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
604                 VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
605                 if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
606                         Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
607                 else
608                         Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
609
610                 Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
611         }
612
613 finished:
614 #ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
615         if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
616                 Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
617 #endif
618         return cliptrace;
619 }
620
621 #if COLLISIONPARANOID >= 1
622 trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
623 {
624         int endstuck;
625         trace_t trace;
626         vec3_t temp;
627         trace = SV_TraceBox_(start, mins, maxs, end, type, passedict, hitsupercontentsmask);
628         if (passedict)
629         {
630                 VectorCopy(trace.endpos, temp);
631                 endstuck = SV_TraceBox_(temp, mins, maxs, temp, type, passedict, hitsupercontentsmask).startsolid;
632 #if COLLISIONPARANOID < 3
633                 if (trace.startsolid || endstuck)
634 #endif
635                         Con_Printf("%s{e%i:%f %f %f:%f %f %f:%f:%f %f %f%s%s}\n", (trace.startsolid || endstuck) ? "^3" : "", passedict ? (int)(passedict - prog->edicts) : -1, PRVM_serveredictvector(passedict, origin)[0], PRVM_serveredictvector(passedict, origin)[1], PRVM_serveredictvector(passedict, origin)[2], end[0] - PRVM_serveredictvector(passedict, origin)[0], end[1] - PRVM_serveredictvector(passedict, origin)[1], end[2] - PRVM_serveredictvector(passedict, origin)[2], trace.fraction, trace.endpos[0] - PRVM_serveredictvector(passedict, origin)[0], trace.endpos[1] - PRVM_serveredictvector(passedict, origin)[1], trace.endpos[2] - PRVM_serveredictvector(passedict, origin)[2], trace.startsolid ? " startstuck" : "", endstuck ? " endstuck" : "");
636         }
637         return trace;
638 }
639 #endif
640
641 int SV_PointSuperContents(const vec3_t point)
642 {
643         int supercontents = 0;
644         int i;
645         prvm_edict_t *touch;
646         vec3_t transformed;
647         // matrices to transform into/out of other entity's space
648         matrix4x4_t matrix, imatrix;
649         // model of other entity
650         dp_model_t *model;
651         int frame;
652         // list of entities to test for collisions
653         int numtouchedicts;
654         static prvm_edict_t *touchedicts[MAX_EDICTS];
655
656         // get world supercontents at this point
657         if (sv.worldmodel && sv.worldmodel->PointSuperContents)
658                 supercontents = sv.worldmodel->PointSuperContents(sv.worldmodel, 0, point);
659
660         // if sv_gameplayfix_swiminbmodels is off we're done
661         if (!sv_gameplayfix_swiminbmodels.integer)
662                 return supercontents;
663
664         // get list of entities at this point
665         numtouchedicts = World_EntitiesInBox(&sv.world, point, point, MAX_EDICTS, touchedicts);
666         if (numtouchedicts > MAX_EDICTS)
667         {
668                 // this never happens
669                 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
670                 numtouchedicts = MAX_EDICTS;
671         }
672         for (i = 0;i < numtouchedicts;i++)
673         {
674                 touch = touchedicts[i];
675
676                 // we only care about SOLID_BSP for pointcontents
677                 if (PRVM_serveredictfloat(touch, solid) != SOLID_BSP)
678                         continue;
679
680                 // might interact, so do an exact clip
681                 model = SV_GetModelFromEdict(touch);
682                 if (!model || !model->PointSuperContents)
683                         continue;
684                 Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
685                 Matrix4x4_Invert_Simple(&imatrix, &matrix);
686                 Matrix4x4_Transform(&imatrix, point, transformed);
687                 frame = (int)PRVM_serveredictfloat(touch, frame);
688                 supercontents |= model->PointSuperContents(model, bound(0, frame, (model->numframes - 1)), transformed);
689         }
690
691         return supercontents;
692 }
693
694 /*
695 ===============================================================================
696
697 Linking entities into the world culling system
698
699 ===============================================================================
700 */
701
702 void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent)
703 {
704         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(touch);
705         PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(ent);
706         PRVM_serverglobalfloat(time) = sv.time;
707         PRVM_serverglobalfloat(trace_allsolid) = false;
708         PRVM_serverglobalfloat(trace_startsolid) = false;
709         PRVM_serverglobalfloat(trace_fraction) = 1;
710         PRVM_serverglobalfloat(trace_inwater) = false;
711         PRVM_serverglobalfloat(trace_inopen) = true;
712         VectorCopy (PRVM_serveredictvector(touch, origin), PRVM_serverglobalvector(trace_endpos));
713         VectorSet (PRVM_serverglobalvector(trace_plane_normal), 0, 0, 1);
714         PRVM_serverglobalfloat(trace_plane_dist) = 0;
715         PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(ent);
716         PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
717         PRVM_serverglobalfloat(trace_dphitcontents) = 0;
718         PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
719         PRVM_serverglobalstring(trace_dphittexturename) = 0;
720         PRVM_ExecuteProgram (PRVM_serveredictfunction(touch, touch), "QC function self.touch is missing");
721 }
722
723 void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
724 {
725         int i, numtouchedicts, old_self, old_other;
726         prvm_edict_t *touch;
727         static prvm_edict_t *touchedicts[MAX_EDICTS];
728
729         if (ent == prog->edicts)
730                 return;         // don't add the world
731
732         if (ent->priv.server->free)
733                 return;
734
735         if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
736                 return;
737
738         // build a list of edicts to touch, because the link loop can be corrupted
739         // by IncreaseEdicts called during touch functions
740         numtouchedicts = World_EntitiesInBox(&sv.world, ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts);
741         if (numtouchedicts > MAX_EDICTS)
742         {
743                 // this never happens
744                 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
745                 numtouchedicts = MAX_EDICTS;
746         }
747
748         old_self = PRVM_serverglobaledict(self);
749         old_other = PRVM_serverglobaledict(other);
750         for (i = 0;i < numtouchedicts;i++)
751         {
752                 touch = touchedicts[i];
753                 if (touch != ent && (int)PRVM_serveredictfloat(touch, solid) == SOLID_TRIGGER && PRVM_serveredictfunction(touch, touch))
754                 {
755                         SV_LinkEdict_TouchAreaGrid_Call(touch, ent);
756                 }
757         }
758         PRVM_serverglobaledict(self) = old_self;
759         PRVM_serverglobaledict(other) = old_other;
760 }
761
762 static void RotateBBox(const vec3_t mins, const vec3_t maxs, const vec3_t angles, vec3_t rotatedmins, vec3_t rotatedmaxs)
763 {
764         vec3_t v, u;
765         matrix4x4_t m;
766         Matrix4x4_CreateFromQuakeEntity(&m, 0, 0, 0, angles[PITCH], angles[YAW], angles[ROLL], 1.0);
767
768         v[0] = mins[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
769                 VectorCopy(u, rotatedmins); VectorCopy(u, rotatedmaxs);
770         v[0] = maxs[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
771                 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
772                 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
773         v[0] = mins[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
774                 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
775                 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
776         v[0] = maxs[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
777                 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
778                 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
779         v[0] = mins[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
780                 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
781                 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
782         v[0] = maxs[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
783                 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
784                 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
785         v[0] = mins[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
786                 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
787                 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
788         v[0] = maxs[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
789                 if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
790                 if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
791 }
792
793 /*
794 ===============
795 SV_LinkEdict
796
797 ===============
798 */
799 void SV_LinkEdict (prvm_edict_t *ent)
800 {
801         dp_model_t *model;
802         vec3_t mins, maxs;
803         int modelindex;
804
805         if (ent == prog->edicts)
806                 return;         // don't add the world
807
808         if (ent->priv.server->free)
809                 return;
810
811         modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
812         if (modelindex < 0 || modelindex >= MAX_MODELS)
813         {
814                 Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent));
815                 modelindex = 0;
816         }
817         model = SV_GetModelByIndex(modelindex);
818
819         VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
820         VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
821         VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
822
823 // set the abs box
824
825         if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_PHYSICS)
826         {
827                 // TODO maybe should do this for rotating SOLID_BSP too? Would behave better with rotating doors
828                 // TODO special handling for spheres?
829                 RotateBBox(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, angles), mins, maxs);
830                 VectorAdd(PRVM_serveredictvector(ent, origin), mins, mins);
831                 VectorAdd(PRVM_serveredictvector(ent, origin), maxs, maxs);
832         }
833         else if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
834         {
835                 if (model != NULL)
836                 {
837                         if (!model->TraceBox)
838                                 Con_DPrintf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent));
839
840                         if (PRVM_serveredictvector(ent, angles)[0] || PRVM_serveredictvector(ent, angles)[2] || PRVM_serveredictvector(ent, avelocity)[0] || PRVM_serveredictvector(ent, avelocity)[2])
841                         {
842                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmins, mins);
843                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmaxs, maxs);
844                         }
845                         else if (PRVM_serveredictvector(ent, angles)[1] || PRVM_serveredictvector(ent, avelocity)[1])
846                         {
847                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmins, mins);
848                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmaxs, maxs);
849                         }
850                         else
851                         {
852                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmins, mins);
853                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmaxs, maxs);
854                         }
855                 }
856                 else
857                 {
858                         // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily
859                         VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
860                         VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
861                 }
862         }
863         else
864         {
865                 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
866                 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
867         }
868
869 //
870 // to make items easier to pick up and allow them to be grabbed off
871 // of shelves, the abs sizes are expanded
872 //
873         if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
874         {
875                 mins[0] -= 15;
876                 mins[1] -= 15;
877                 mins[2] -= 1;
878                 maxs[0] += 15;
879                 maxs[1] += 15;
880                 maxs[2] += 1;
881         }
882         else
883         {
884                 // because movement is clipped an epsilon away from an actual edge,
885                 // we must fully check even when bounding boxes don't quite touch
886                 mins[0] -= 1;
887                 mins[1] -= 1;
888                 mins[2] -= 1;
889                 maxs[0] += 1;
890                 maxs[1] += 1;
891                 maxs[2] += 1;
892         }
893
894         VectorCopy(mins, PRVM_serveredictvector(ent, absmin));
895         VectorCopy(maxs, PRVM_serveredictvector(ent, absmax));
896
897         World_LinkEdict(&sv.world, ent, mins, maxs);
898 }
899
900 /*
901 ===============================================================================
902
903 Utility functions
904
905 ===============================================================================
906 */
907
908 /*
909 ============
910 SV_TestEntityPosition
911
912 returns true if the entity is in solid currently
913 ============
914 */
915 static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
916 {
917         int contents;
918         vec3_t org;
919         trace_t trace;
920         contents = SV_GenericHitSuperContentsMask(ent);
921         VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
922         trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), MOVE_NOMONSTERS, ent, contents);
923         if (trace.startsupercontents & contents)
924                 return true;
925         else
926         {
927                 if (sv.worldmodel->brushq1.numclipnodes && !VectorCompare(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs)))
928                 {
929                         // q1bsp/hlbsp use hulls and if the entity does not exactly match
930                         // a hull size it is incorrectly tested, so this code tries to
931                         // 'fix' it slightly...
932                         // FIXME: this breaks entities larger than the hull size
933                         int i;
934                         vec3_t v, m1, m2, s;
935                         VectorAdd(org, PRVM_serveredictvector(ent, mins), m1);
936                         VectorAdd(org, PRVM_serveredictvector(ent, maxs), m2);
937                         VectorSubtract(m2, m1, s);
938 #define EPSILON (1.0f / 32.0f)
939                         if (s[0] >= EPSILON*2) {m1[0] += EPSILON;m2[0] -= EPSILON;}
940                         if (s[1] >= EPSILON*2) {m1[1] += EPSILON;m2[1] -= EPSILON;}
941                         if (s[2] >= EPSILON*2) {m1[2] += EPSILON;m2[2] -= EPSILON;}
942                         for (i = 0;i < 8;i++)
943                         {
944                                 v[0] = (i & 1) ? m2[0] : m1[0];
945                                 v[1] = (i & 2) ? m2[1] : m1[1];
946                                 v[2] = (i & 4) ? m2[2] : m1[2];
947                                 if (SV_PointSuperContents(v) & contents)
948                                         return true;
949                         }
950                 }
951         }
952         // if the trace found a better position for the entity, move it there
953         if (VectorDistance2(trace.endpos, PRVM_serveredictvector(ent, origin)) >= 0.0001)
954         {
955 #if 0
956                 // please switch back to this code when trace.endpos sometimes being in solid bug is fixed
957                 VectorCopy(trace.endpos, PRVM_serveredictvector(ent, origin));
958 #else
959                 // verify if the endpos is REALLY outside solid
960                 VectorCopy(trace.endpos, org);
961                 trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), org, MOVE_NOMONSTERS, ent, contents);
962                 if(trace.startsolid)
963                         Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
964                 else
965                         VectorCopy(org, PRVM_serveredictvector(ent, origin));
966 #endif
967         }
968         return false;
969 }
970
971 /*
972 ================
973 SV_CheckAllEnts
974 ================
975 */
976 void SV_CheckAllEnts (void)
977 {
978         int e;
979         prvm_edict_t *check;
980
981         // see if any solid entities are inside the final position
982         check = PRVM_NEXT_EDICT(prog->edicts);
983         for (e = 1;e < prog->num_edicts;e++, check = PRVM_NEXT_EDICT(check))
984         {
985                 if (check->priv.server->free)
986                         continue;
987                 if (PRVM_serveredictfloat(check, movetype) == MOVETYPE_PUSH
988                  || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NONE
989                  || PRVM_serveredictfloat(check, movetype) == MOVETYPE_FOLLOW
990                  || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NOCLIP)
991                         continue;
992
993                 if (SV_TestEntityPosition (check, vec3_origin))
994                         Con_Print("entity in invalid position\n");
995         }
996 }
997
998 // DRESK - Support for Entity Contents Transition Event
999 /*
1000 ================
1001 SV_CheckContentsTransition
1002
1003 returns true if entity had a valid contentstransition function call
1004 ================
1005 */
1006 int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
1007 {
1008         int bValidFunctionCall;
1009
1010         // Default Valid Function Call to False
1011         bValidFunctionCall = false;
1012
1013         if(PRVM_serveredictfloat(ent, watertype) != nContents)
1014         { // Changed Contents
1015                 // Acquire Contents Transition Function from QC
1016                 if(PRVM_serveredictfunction(ent, contentstransition))
1017                 { // Valid Function; Execute
1018                         // Assign Valid Function
1019                         bValidFunctionCall = true;
1020                         // Prepare Parameters (Original Contents, New Contents)
1021                                 // Original Contents
1022                                 PRVM_G_FLOAT(OFS_PARM0) = PRVM_serveredictfloat(ent, watertype);
1023                                 // New Contents
1024                                 PRVM_G_FLOAT(OFS_PARM1) = nContents;
1025                                 // Assign Self
1026                                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1027                         // Execute VM Function
1028                         PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
1029                 }
1030         }
1031
1032         // Return if Function Call was Valid
1033         return bValidFunctionCall;
1034 }
1035
1036
1037 /*
1038 ================
1039 SV_CheckVelocity
1040 ================
1041 */
1042 void SV_CheckVelocity (prvm_edict_t *ent)
1043 {
1044         int i;
1045         float wishspeed;
1046
1047 //
1048 // bound velocity
1049 //
1050         for (i=0 ; i<3 ; i++)
1051         {
1052                 if (IS_NAN(PRVM_serveredictvector(ent, velocity)[i]))
1053                 {
1054                         Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
1055                         PRVM_serveredictvector(ent, velocity)[i] = 0;
1056                 }
1057                 if (IS_NAN(PRVM_serveredictvector(ent, origin)[i]))
1058                 {
1059                         Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
1060                         PRVM_serveredictvector(ent, origin)[i] = 0;
1061                 }
1062         }
1063
1064         // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
1065         // player_run/player_stand1 does not horribly malfunction if the
1066         // velocity becomes a denormalized float
1067         if (VectorLength2(PRVM_serveredictvector(ent, velocity)) < 0.0001)
1068                 VectorClear(PRVM_serveredictvector(ent, velocity));
1069
1070         // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
1071         wishspeed = DotProduct(PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, velocity));
1072         if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
1073         {
1074                 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
1075                 PRVM_serveredictvector(ent, velocity)[0] *= wishspeed;
1076                 PRVM_serveredictvector(ent, velocity)[1] *= wishspeed;
1077                 PRVM_serveredictvector(ent, velocity)[2] *= wishspeed;
1078         }
1079 }
1080
1081 /*
1082 =============
1083 SV_RunThink
1084
1085 Runs thinking code if time.  There is some play in the exact time the think
1086 function will be called, because it is called before any movement is done
1087 in a frame.  Not used for pushmove objects, because they must be exact.
1088 Returns false if the entity removed itself.
1089 =============
1090 */
1091 qboolean SV_RunThink (prvm_edict_t *ent)
1092 {
1093         int iterations;
1094
1095         // don't let things stay in the past.
1096         // it is possible to start that way by a trigger with a local time.
1097         if (PRVM_serveredictfloat(ent, nextthink) <= 0 || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime)
1098                 return true;
1099
1100         for (iterations = 0;iterations < 128  && !ent->priv.server->free;iterations++)
1101         {
1102                 PRVM_serverglobalfloat(time) = max(sv.time, PRVM_serveredictfloat(ent, nextthink));
1103                 PRVM_serveredictfloat(ent, nextthink) = 0;
1104                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1105                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
1106                 PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1107                 // mods often set nextthink to time to cause a think every frame,
1108                 // we don't want to loop in that case, so exit if the new nextthink is
1109                 // <= the time the qc was told, also exit if it is past the end of the
1110                 // frame
1111                 if (PRVM_serveredictfloat(ent, nextthink) <= PRVM_serverglobalfloat(time) || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer)
1112                         break;
1113         }
1114         return !ent->priv.server->free;
1115 }
1116
1117 /*
1118 ==================
1119 SV_Impact
1120
1121 Two entities have touched, so run their touch functions
1122 ==================
1123 */
1124 extern void VM_SetTraceGlobals(const trace_t *trace);
1125 extern sizebuf_t vm_tempstringsbuf;
1126 void SV_Impact (prvm_edict_t *e1, trace_t *trace)
1127 {
1128         int restorevm_tempstringsbuf_cursize;
1129         int old_self, old_other;
1130         prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
1131
1132         old_self = PRVM_serverglobaledict(self);
1133         old_other = PRVM_serverglobaledict(other);
1134         restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1135
1136         VM_SetTraceGlobals(trace);
1137
1138         PRVM_serverglobalfloat(time) = sv.time;
1139         if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e1, touch) && PRVM_serveredictfloat(e1, solid) != SOLID_NOT)
1140         {
1141                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e1);
1142                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e2);
1143                 PRVM_ExecuteProgram (PRVM_serveredictfunction(e1, touch), "QC function self.touch is missing");
1144         }
1145
1146         if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e2, touch) && PRVM_serveredictfloat(e2, solid) != SOLID_NOT)
1147         {
1148                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e2);
1149                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e1);
1150                 VectorCopy(PRVM_serveredictvector(e2, origin), PRVM_serverglobalvector(trace_endpos));
1151                 VectorNegate(trace->plane.normal, PRVM_serverglobalvector(trace_plane_normal));
1152                 PRVM_serverglobalfloat(trace_plane_dist) = -trace->plane.dist;
1153                 PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(e1);
1154                 PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
1155                 PRVM_serverglobalfloat(trace_dphitcontents) = 0;
1156                 PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
1157                 PRVM_serverglobalstring(trace_dphittexturename) = 0;
1158                 PRVM_ExecuteProgram (PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
1159         }
1160
1161         PRVM_serverglobaledict(self) = old_self;
1162         PRVM_serverglobaledict(other) = old_other;
1163         vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1164 }
1165
1166
1167 /*
1168 ==================
1169 ClipVelocity
1170
1171 Slide off of the impacting object
1172 returns the blocked flags (1 = floor, 2 = step / wall)
1173 ==================
1174 */
1175 #define STOP_EPSILON 0.1
1176 void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
1177 {
1178         int i;
1179         float backoff;
1180
1181         backoff = -DotProduct (in, normal) * overbounce;
1182         VectorMA(in, backoff, normal, out);
1183
1184         for (i = 0;i < 3;i++)
1185                 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
1186                         out[i] = 0;
1187 }
1188
1189
1190 /*
1191 ============
1192 SV_FlyMove
1193
1194 The basic solid body movement clip that slides along multiple planes
1195 Returns the clipflags if the velocity was modified (hit something solid)
1196 1 = floor
1197 2 = wall / step
1198 4 = dead stop
1199 8 = teleported by touch method
1200 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
1201 ============
1202 */
1203 static float SV_Gravity (prvm_edict_t *ent);
1204 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink);
1205 #define MAX_CLIP_PLANES 5
1206 static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask, float stepheight)
1207 {
1208         int blocked, bumpcount;
1209         int i, j, numplanes;
1210         float d, time_left, gravity;
1211         vec3_t dir, push, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
1212 #if 0
1213         vec3_t end;
1214 #endif
1215         trace_t trace;
1216         if (time <= 0)
1217                 return 0;
1218         gravity = 0;
1219
1220         if(sv_gameplayfix_nogravityonground.integer)
1221                 if((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
1222                         applygravity = false;
1223
1224         if (applygravity)
1225         {
1226                 if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
1227                 {
1228                         gravity = SV_Gravity(ent) * 0.5f;
1229                         PRVM_serveredictvector(ent, velocity)[2] -= gravity;
1230                 }
1231                 else
1232                 {
1233                         applygravity = false;
1234                         PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
1235                 }
1236         }
1237         blocked = 0;
1238         VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1239         VectorCopy(PRVM_serveredictvector(ent, velocity), primal_velocity);
1240         numplanes = 0;
1241         time_left = time;
1242         for (bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
1243         {
1244                 if (!PRVM_serveredictvector(ent, velocity)[0] && !PRVM_serveredictvector(ent, velocity)[1] && !PRVM_serveredictvector(ent, velocity)[2])
1245                         break;
1246
1247                 VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
1248                 if(!SV_PushEntity(&trace, ent, push, false, false))
1249                 {
1250                         // we got teleported by a touch function
1251                         // let's abort the move
1252                         blocked |= 8;
1253                         break;
1254                 }
1255
1256                 if (trace.fraction == 1)
1257                         break;
1258                 if (trace.plane.normal[2])
1259                 {
1260                         if (trace.plane.normal[2] > 0.7)
1261                         {
1262                                 // floor
1263                                 blocked |= 1;
1264
1265                                 if (!trace.ent)
1266                                 {
1267                                         Con_Printf ("SV_FlyMove: !trace.ent");
1268                                         trace.ent = prog->edicts;
1269                                 }
1270
1271                                 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1272                                 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1273                         }
1274                 }
1275                 else if (stepheight)
1276                 {
1277                         // step - handle it immediately
1278                         vec3_t org;
1279                         vec3_t steppush;
1280                         trace_t steptrace;
1281                         trace_t steptrace2;
1282                         trace_t steptrace3;
1283                         //Con_Printf("step %f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1284                         VectorSet(steppush, 0, 0, stepheight);
1285                         VectorCopy(PRVM_serveredictvector(ent, origin), org);
1286                         if(!SV_PushEntity(&steptrace, ent, steppush, false, false))
1287                         {
1288                                 blocked |= 8;
1289                                 break;
1290                         }
1291                         //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1292                         if(!SV_PushEntity(&steptrace2, ent, push, false, false))
1293                         {
1294                                 blocked |= 8;
1295                                 break;
1296                         }
1297                         //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1298                         VectorSet(steppush, 0, 0, org[2] - PRVM_serveredictvector(ent, origin)[2]);
1299                         if(!SV_PushEntity(&steptrace3, ent, steppush, false, false))
1300                         {
1301                                 blocked |= 8;
1302                                 break;
1303                         }
1304                         //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1305                         // accept the new position if it made some progress...
1306                         if (fabs(PRVM_serveredictvector(ent, origin)[0] - org[0]) >= 0.03125 || fabs(PRVM_serveredictvector(ent, origin)[1] - org[1]) >= 0.03125)
1307                         {
1308                                 //Con_Printf("accepted (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
1309                                 trace = steptrace2;
1310                                 VectorCopy(PRVM_serveredictvector(ent, origin), trace.endpos);
1311                                 time_left *= 1 - trace.fraction;
1312                                 numplanes = 0;
1313                                 continue;
1314                         }
1315                         else
1316                         {
1317                                 //Con_Printf("REJECTED (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
1318                                 VectorCopy(org, PRVM_serveredictvector(ent, origin));
1319                         }
1320                 }
1321                 else
1322                 {
1323                         // step - return it to caller
1324                         blocked |= 2;
1325                         // save the trace for player extrafriction
1326                         if (stepnormal)
1327                                 VectorCopy(trace.plane.normal, stepnormal);
1328                 }
1329                 if (trace.fraction >= 0.001)
1330                 {
1331                         // actually covered some distance
1332                         VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1333                         numplanes = 0;
1334                 }
1335
1336                 time_left *= 1 - trace.fraction;
1337
1338                 // clipped to another plane
1339                 if (numplanes >= MAX_CLIP_PLANES)
1340                 {
1341                         // this shouldn't really happen
1342                         VectorClear(PRVM_serveredictvector(ent, velocity));
1343                         blocked = 3;
1344                         break;
1345                 }
1346
1347                 /*
1348                 for (i = 0;i < numplanes;i++)
1349                         if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
1350                                 break;
1351                 if (i < numplanes)
1352                 {
1353                         VectorAdd(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity));
1354                         continue;
1355                 }
1356                 */
1357
1358                 VectorCopy(trace.plane.normal, planes[numplanes]);
1359                 numplanes++;
1360
1361                 // modify original_velocity so it parallels all of the clip planes
1362                 for (i = 0;i < numplanes;i++)
1363                 {
1364                         ClipVelocity(original_velocity, planes[i], new_velocity, 1);
1365                         for (j = 0;j < numplanes;j++)
1366                         {
1367                                 if (j != i)
1368                                 {
1369                                         // not ok
1370                                         if (DotProduct(new_velocity, planes[j]) < 0)
1371                                                 break;
1372                                 }
1373                         }
1374                         if (j == numplanes)
1375                                 break;
1376                 }
1377
1378                 if (i != numplanes)
1379                 {
1380                         // go along this plane
1381                         VectorCopy(new_velocity, PRVM_serveredictvector(ent, velocity));
1382                 }
1383                 else
1384                 {
1385                         // go along the crease
1386                         if (numplanes != 2)
1387                         {
1388                                 VectorClear(PRVM_serveredictvector(ent, velocity));
1389                                 blocked = 7;
1390                                 break;
1391                         }
1392                         CrossProduct(planes[0], planes[1], dir);
1393                         // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
1394                         VectorNormalize(dir);
1395                         d = DotProduct(dir, PRVM_serveredictvector(ent, velocity));
1396                         VectorScale(dir, d, PRVM_serveredictvector(ent, velocity));
1397                 }
1398
1399                 // if current velocity is against the original velocity,
1400                 // stop dead to avoid tiny occilations in sloping corners
1401                 if (DotProduct(PRVM_serveredictvector(ent, velocity), primal_velocity) <= 0)
1402                 {
1403                         VectorClear(PRVM_serveredictvector(ent, velocity));
1404                         break;
1405                 }
1406         }
1407
1408         //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - prog->edicts, blocked, PRVM_serveredictvector(ent, velocity)[0], PRVM_serveredictvector(ent, velocity)[1], PRVM_serveredictvector(ent, velocity)[2]);
1409
1410         /*
1411         if ((blocked & 1) == 0 && bumpcount > 1)
1412         {
1413                 // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
1414                 // flag ONGROUND if there's ground under it
1415                 trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, hitsupercontentsmask);
1416         }
1417         */
1418
1419         // LordHavoc: this came from QW and allows you to get out of water more easily
1420         if (sv_gameplayfix_easierwaterjump.integer && ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) && !(blocked & 8))
1421                 VectorCopy(primal_velocity, PRVM_serveredictvector(ent, velocity));
1422         if (applygravity && !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
1423                 PRVM_serveredictvector(ent, velocity)[2] -= gravity;
1424         return blocked;
1425 }
1426
1427 /*
1428 ============
1429 SV_Gravity
1430
1431 ============
1432 */
1433 static float SV_Gravity (prvm_edict_t *ent)
1434 {
1435         float ent_gravity;
1436
1437         ent_gravity = PRVM_serveredictfloat(ent, gravity);
1438         if (!ent_gravity)
1439                 ent_gravity = 1.0f;
1440         return ent_gravity * sv_gravity.value * sv.frametime;
1441 }
1442
1443
1444 /*
1445 ===============================================================================
1446
1447 PUSHMOVE
1448
1449 ===============================================================================
1450 */
1451
1452 static qboolean SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot)
1453 {
1454         int bump;
1455         trace_t stucktrace;
1456         vec3_t stuckorigin;
1457         vec3_t stuckmins, stuckmaxs;
1458         vec3_t goodmins, goodmaxs;
1459         vec3_t testorigin;
1460         vec_t nudge;
1461         vec3_t move;
1462         VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1463         VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1464         VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1465         VectorCopy(pivot, goodmins);
1466         VectorCopy(pivot, goodmaxs);
1467         for (bump = 0;bump < 6;bump++)
1468         {
1469                 int coord = 2-(bump >> 1);
1470                 //int coord = (bump >> 1);
1471                 int dir = (bump & 1);
1472                 int subbump;
1473
1474                 for(subbump = 0; ; ++subbump)
1475                 {
1476                         VectorCopy(stuckorigin, testorigin);
1477                         if(dir)
1478                         {
1479                                 // pushing maxs
1480                                 testorigin[coord] += stuckmaxs[coord] - goodmaxs[coord];
1481                         }
1482                         else
1483                         {
1484                                 // pushing mins
1485                                 testorigin[coord] += stuckmins[coord] - goodmins[coord];
1486                         }
1487
1488                         stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1489                         if (stucktrace.bmodelstartsolid)
1490                         {
1491                                 // BAD BAD, can't fix that
1492                                 return false;
1493                         }
1494
1495                         if (stucktrace.fraction >= 1)
1496                                 break; // it WORKS!
1497
1498                         if(subbump >= 10)
1499                         {
1500                                 // BAD BAD, can't fix that
1501                                 return false;
1502                         }
1503
1504                         // we hit something... let's move out of it
1505                         VectorSubtract(stucktrace.endpos, testorigin, move);
1506                         nudge = DotProduct(stucktrace.plane.normal, move) + 0.03125f; // FIXME cvar this constant
1507                         VectorMA(stuckorigin, nudge, stucktrace.plane.normal, stuckorigin);
1508                 }
1509                 /*
1510                 if(subbump > 0)
1511                         Con_Printf("subbump: %d\n", subbump);
1512                 */
1513
1514                 if(dir)
1515                 {
1516                         // pushing maxs
1517                         goodmaxs[coord] = stuckmaxs[coord];
1518                 }
1519                 else
1520                 {
1521                         // pushing mins
1522                         goodmins[coord] = stuckmins[coord];
1523                 }
1524         }
1525
1526         // WE WIN
1527         VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1528
1529         return true;
1530 }
1531
1532 static qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent)
1533 {
1534         int bump;
1535         trace_t stucktrace;
1536         vec3_t stuckorigin;
1537         vec3_t stuckmins, stuckmaxs;
1538         vec_t nudge;
1539         vec_t separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
1540         if (sv.worldmodel && sv.worldmodel->brushq1.numclipnodes)
1541                 separation = 0.0f; // when using hulls, it can not be enlarged
1542         VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1543         VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1544         VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1545         stuckmins[0] -= separation;
1546         stuckmins[1] -= separation;
1547         stuckmins[2] -= separation;
1548         stuckmaxs[0] += separation;
1549         stuckmaxs[1] += separation;
1550         stuckmaxs[2] += separation;
1551         for (bump = 0;bump < 10;bump++)
1552         {
1553                 stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1554                 if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
1555                 {
1556                         // found a good location, use it
1557                         VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1558                         return true;
1559                 }
1560                 nudge = -stucktrace.startdepth;
1561                 VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
1562         }
1563         return false;
1564 }
1565
1566 /*
1567 ============
1568 SV_PushEntity
1569
1570 Does not change the entities velocity at all
1571 The trace struct is filled with the trace that has been done.
1572 Returns true if the push did not result in the entity being teleported by QC code.
1573 ============
1574 */
1575 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
1576 {
1577         int solid;
1578         int movetype;
1579         int type;
1580         vec3_t mins, maxs;
1581         vec3_t original, original_velocity;
1582         vec3_t start;
1583         vec3_t end;
1584
1585         solid = (int)PRVM_serveredictfloat(ent, solid);
1586         movetype = (int)PRVM_serveredictfloat(ent, movetype);
1587         VectorCopy(PRVM_serveredictvector(ent, mins), mins);
1588         VectorCopy(PRVM_serveredictvector(ent, maxs), maxs);
1589
1590         // move start position out of solids
1591         if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
1592         {
1593                 SV_NudgeOutOfSolid(ent);
1594         }
1595
1596         VectorCopy(PRVM_serveredictvector(ent, origin), start);
1597         VectorAdd(start, push, end);
1598
1599         if (movetype == MOVETYPE_FLYMISSILE)
1600                 type = MOVE_MISSILE;
1601         else if (solid == SOLID_TRIGGER || solid == SOLID_NOT)
1602                 type = MOVE_NOMONSTERS; // only clip against bmodels
1603         else
1604                 type = MOVE_NORMAL;
1605
1606         *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
1607         if (trace->bmodelstartsolid && failonbmodelstartsolid)
1608                 return true;
1609
1610         VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
1611
1612         VectorCopy(PRVM_serveredictvector(ent, origin), original);
1613         VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1614
1615         SV_LinkEdict(ent);
1616
1617 #if 0
1618         if(!trace->startsolid)
1619         if(SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), type, ent, SV_GenericHitSuperContentsMask(ent)).startsolid)
1620         {
1621                 Con_Printf("something eeeeevil happened\n");
1622         }
1623 #endif
1624
1625         if (dolink)
1626                 SV_LinkEdict_TouchAreaGrid(ent);
1627
1628         if((PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace->ent && (!((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) || PRVM_serveredictedict(ent, groundentity) != PRVM_EDICT_TO_PROG(trace->ent))))
1629                 SV_Impact (ent, trace);
1630
1631         return VectorCompare(PRVM_serveredictvector(ent, origin), original) && VectorCompare(PRVM_serveredictvector(ent, velocity), original_velocity);
1632 }
1633
1634
1635 /*
1636 ============
1637 SV_PushMove
1638
1639 ============
1640 */
1641 void SV_PushMove (prvm_edict_t *pusher, float movetime)
1642 {
1643         int i, e, index;
1644         int pusherowner, pusherprog;
1645         int checkcontents;
1646         qboolean rotated;
1647         float savesolid, movetime2, pushltime;
1648         vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org;
1649         int num_moved;
1650         int numcheckentities;
1651         static prvm_edict_t *checkentities[MAX_EDICTS];
1652         dp_model_t *pushermodel;
1653         trace_t trace, trace2;
1654         matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
1655         static unsigned short moved_edicts[MAX_EDICTS];
1656         vec3_t pivot;
1657
1658         if (!PRVM_serveredictvector(pusher, velocity)[0] && !PRVM_serveredictvector(pusher, velocity)[1] && !PRVM_serveredictvector(pusher, velocity)[2] && !PRVM_serveredictvector(pusher, avelocity)[0] && !PRVM_serveredictvector(pusher, avelocity)[1] && !PRVM_serveredictvector(pusher, avelocity)[2])
1659         {
1660                 PRVM_serveredictfloat(pusher, ltime) += movetime;
1661                 return;
1662         }
1663
1664         switch ((int) PRVM_serveredictfloat(pusher, solid))
1665         {
1666         // LordHavoc: valid pusher types
1667         case SOLID_BSP:
1668         case SOLID_BBOX:
1669         case SOLID_SLIDEBOX:
1670         case SOLID_CORPSE: // LordHavoc: this would be weird...
1671                 break;
1672         // LordHavoc: no collisions
1673         case SOLID_NOT:
1674         case SOLID_TRIGGER:
1675                 VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1676                 VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1677                 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1678                 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1679                 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1680                 PRVM_serveredictfloat(pusher, ltime) += movetime;
1681                 SV_LinkEdict(pusher);
1682                 return;
1683         default:
1684                 Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, solid));
1685                 return;
1686         }
1687         index = (int) PRVM_serveredictfloat(pusher, modelindex);
1688         if (index < 1 || index >= MAX_MODELS)
1689         {
1690                 Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, modelindex));
1691                 return;
1692         }
1693         pushermodel = SV_GetModelByIndex(index);
1694         pusherowner = PRVM_serveredictedict(pusher, owner);
1695         pusherprog = PRVM_EDICT_TO_PROG(pusher);
1696
1697         rotated = VectorLength2(PRVM_serveredictvector(pusher, angles)) + VectorLength2(PRVM_serveredictvector(pusher, avelocity)) > 0;
1698
1699         movetime2 = movetime;
1700         VectorScale(PRVM_serveredictvector(pusher, velocity), movetime2, move1);
1701         VectorScale(PRVM_serveredictvector(pusher, avelocity), movetime2, moveangle);
1702         if (moveangle[0] || moveangle[2])
1703         {
1704                 for (i = 0;i < 3;i++)
1705                 {
1706                         if (move1[i] > 0)
1707                         {
1708                                 mins[i] = pushermodel->rotatedmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1709                                 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1710                         }
1711                         else
1712                         {
1713                                 mins[i] = pushermodel->rotatedmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1714                                 maxs[i] = pushermodel->rotatedmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1715                         }
1716                 }
1717         }
1718         else if (moveangle[1])
1719         {
1720                 for (i = 0;i < 3;i++)
1721                 {
1722                         if (move1[i] > 0)
1723                         {
1724                                 mins[i] = pushermodel->yawmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1725                                 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1726                         }
1727                         else
1728                         {
1729                                 mins[i] = pushermodel->yawmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1730                                 maxs[i] = pushermodel->yawmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1731                         }
1732                 }
1733         }
1734         else
1735         {
1736                 for (i = 0;i < 3;i++)
1737                 {
1738                         if (move1[i] > 0)
1739                         {
1740                                 mins[i] = pushermodel->normalmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1741                                 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1742                         }
1743                         else
1744                         {
1745                                 mins[i] = pushermodel->normalmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1746                                 maxs[i] = pushermodel->normalmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1747                         }
1748                 }
1749         }
1750
1751         VectorNegate (moveangle, a);
1752         AngleVectorsFLU (a, forward, left, up);
1753
1754         VectorCopy (PRVM_serveredictvector(pusher, origin), pushorig);
1755         VectorCopy (PRVM_serveredictvector(pusher, angles), pushang);
1756         pushltime = PRVM_serveredictfloat(pusher, ltime);
1757
1758 // move the pusher to its final position
1759
1760         VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1761         VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1762         PRVM_serveredictfloat(pusher, ltime) += movetime;
1763         SV_LinkEdict(pusher);
1764
1765         pushermodel = SV_GetModelFromEdict(pusher);
1766         Matrix4x4_CreateFromQuakeEntity(&pusherfinalmatrix, PRVM_serveredictvector(pusher, origin)[0], PRVM_serveredictvector(pusher, origin)[1], PRVM_serveredictvector(pusher, origin)[2], PRVM_serveredictvector(pusher, angles)[0], PRVM_serveredictvector(pusher, angles)[1], PRVM_serveredictvector(pusher, angles)[2], 1);
1767         Matrix4x4_Invert_Simple(&pusherfinalimatrix, &pusherfinalmatrix);
1768
1769         savesolid = PRVM_serveredictfloat(pusher, solid);
1770
1771 // see if any solid entities are inside the final position
1772         num_moved = 0;
1773
1774         numcheckentities = World_EntitiesInBox(&sv.world, mins, maxs, MAX_EDICTS, checkentities);
1775         for (e = 0;e < numcheckentities;e++)
1776         {
1777                 prvm_edict_t *check = checkentities[e];
1778                 int movetype = (int)PRVM_serveredictfloat(check, movetype);
1779                 switch(movetype)
1780                 {
1781                 case MOVETYPE_NONE:
1782                 case MOVETYPE_PUSH:
1783                 case MOVETYPE_FOLLOW:
1784                 case MOVETYPE_NOCLIP:
1785                 case MOVETYPE_FAKEPUSH:
1786                         continue;
1787                 default:
1788                         break;
1789                 }
1790
1791                 if (PRVM_serveredictedict(check, owner) == pusherprog)
1792                         continue;
1793
1794                 if (pusherowner == PRVM_EDICT_TO_PROG(check))
1795                         continue;
1796
1797                 //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname)));
1798
1799                 // tell any MOVETYPE_STEP entity that it may need to check for water transitions
1800                 check->priv.server->waterposition_forceupdate = true;
1801
1802                 checkcontents = SV_GenericHitSuperContentsMask(check);
1803
1804                 // if the entity is standing on the pusher, it will definitely be moved
1805                 // if the entity is not standing on the pusher, but is in the pusher's
1806                 // final position, move it
1807                 if (!((int)PRVM_serveredictfloat(check, flags) & FL_ONGROUND) || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher)
1808                 {
1809                         Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, PRVM_serveredictvector(pusher, mins), PRVM_serveredictvector(pusher, maxs), SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), checkcontents);
1810                         //trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
1811                         if (!trace.startsolid)
1812                         {
1813                                 //Con_Printf("- not in solid\n");
1814                                 continue;
1815                         }
1816                 }
1817
1818                 VectorLerp(PRVM_serveredictvector(check, mins), 0.5f, PRVM_serveredictvector(check, maxs), pivot);
1819                 //VectorClear(pivot);
1820
1821                 if (rotated)
1822                 {
1823                         vec3_t org2;
1824                         VectorSubtract (PRVM_serveredictvector(check, origin), PRVM_serveredictvector(pusher, origin), org);
1825                         VectorAdd (org, pivot, org);
1826                         org2[0] = DotProduct (org, forward);
1827                         org2[1] = DotProduct (org, left);
1828                         org2[2] = DotProduct (org, up);
1829                         VectorSubtract (org2, org, move);
1830                         VectorAdd (move, move1, move);
1831                 }
1832                 else
1833                         VectorCopy (move1, move);
1834
1835                 //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]);
1836
1837                 VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from);
1838                 VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles);
1839                 moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
1840
1841                 // physics objects need better collisions than this code can do
1842                 if (movetype == MOVETYPE_PHYSICS)
1843                 {
1844                         VectorAdd(PRVM_serveredictvector(check, origin), move, PRVM_serveredictvector(check, origin));
1845                         SV_LinkEdict(check);
1846                         SV_LinkEdict_TouchAreaGrid(check);
1847                         continue;
1848                 }
1849
1850                 // try moving the contacted entity
1851                 PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
1852                 if(!SV_PushEntity (&trace, check, move, true, true))
1853                 {
1854                         // entity "check" got teleported
1855                         PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1856                         PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1857                         continue; // pushed enough
1858                 }
1859                 // FIXME: turn players specially
1860                 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1861                 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1862                 //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
1863
1864                 // this trace.fraction < 1 check causes items to fall off of pushers
1865                 // if they pass under or through a wall
1866                 // the groundentity check causes items to fall off of ledges
1867                 if (PRVM_serveredictfloat(check, movetype) != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher))
1868                         PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND;
1869
1870                 // if it is still inside the pusher, block
1871                 Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, PRVM_serveredictvector(pusher, mins), PRVM_serveredictvector(pusher, maxs), SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), checkcontents);
1872                 if (trace.startsolid)
1873                 {
1874                         vec3_t move2;
1875                         if(SV_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
1876                         {
1877                                 // hack to invoke all necessary movement triggers
1878                                 VectorClear(move2);
1879                                 if(!SV_PushEntity(&trace2, check, move2, true, true))
1880                                 {
1881                                         // entity "check" got teleported
1882                                         continue;
1883                                 }
1884                                 // we could fix it
1885                                 continue;
1886                         }
1887
1888                         // still inside pusher, so it's really blocked
1889
1890                         // fail the move
1891                         if (PRVM_serveredictvector(check, mins)[0] == PRVM_serveredictvector(check, maxs)[0])
1892                                 continue;
1893                         if (PRVM_serveredictfloat(check, solid) == SOLID_NOT || PRVM_serveredictfloat(check, solid) == SOLID_TRIGGER)
1894                         {
1895                                 // corpse
1896                                 PRVM_serveredictvector(check, mins)[0] = PRVM_serveredictvector(check, mins)[1] = 0;
1897                                 VectorCopy (PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs));
1898                                 continue;
1899                         }
1900
1901                         VectorCopy (pushorig, PRVM_serveredictvector(pusher, origin));
1902                         VectorCopy (pushang, PRVM_serveredictvector(pusher, angles));
1903                         PRVM_serveredictfloat(pusher, ltime) = pushltime;
1904                         SV_LinkEdict(pusher);
1905
1906                         // move back any entities we already moved
1907                         for (i = 0;i < num_moved;i++)
1908                         {
1909                                 prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]);
1910                                 VectorCopy (ed->priv.server->moved_from, PRVM_serveredictvector(ed, origin));
1911                                 VectorCopy (ed->priv.server->moved_fromangles, PRVM_serveredictvector(ed, angles));
1912                                 SV_LinkEdict(ed);
1913                         }
1914
1915                         // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
1916                         if (PRVM_serveredictfunction(pusher, blocked))
1917                         {
1918                                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(pusher);
1919                                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(check);
1920                                 PRVM_ExecuteProgram (PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
1921                         }
1922                         break;
1923                 }
1924         }
1925         PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1926         PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1927         PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1928 }
1929
1930 /*
1931 ================
1932 SV_Physics_Pusher
1933
1934 ================
1935 */
1936 void SV_Physics_Pusher (prvm_edict_t *ent)
1937 {
1938         float thinktime, oldltime, movetime;
1939
1940         oldltime = PRVM_serveredictfloat(ent, ltime);
1941
1942         thinktime = PRVM_serveredictfloat(ent, nextthink);
1943         if (thinktime < PRVM_serveredictfloat(ent, ltime) + sv.frametime)
1944         {
1945                 movetime = thinktime - PRVM_serveredictfloat(ent, ltime);
1946                 if (movetime < 0)
1947                         movetime = 0;
1948         }
1949         else
1950                 movetime = sv.frametime;
1951
1952         if (movetime)
1953                 // advances PRVM_serveredictfloat(ent, ltime) if not blocked
1954                 SV_PushMove (ent, movetime);
1955
1956         if (thinktime > oldltime && thinktime <= PRVM_serveredictfloat(ent, ltime))
1957         {
1958                 PRVM_serveredictfloat(ent, nextthink) = 0;
1959                 PRVM_serverglobalfloat(time) = sv.time;
1960                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1961                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
1962                 PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1963         }
1964 }
1965
1966
1967 /*
1968 ===============================================================================
1969
1970 CLIENT MOVEMENT
1971
1972 ===============================================================================
1973 */
1974
1975 static float unstickoffsets[] =
1976 {
1977         // poutting -/+z changes first as they are least weird
1978          0,  0,  -1,
1979          0,  0,  1,
1980          // x or y changes
1981         -1,  0,  0,
1982          1,  0,  0,
1983          0, -1,  0,
1984          0,  1,  0,
1985          // x and y changes
1986         -1, -1,  0,
1987          1, -1,  0,
1988         -1,  1,  0,
1989          1,  1,  0,
1990 };
1991
1992 typedef enum unstickresult_e
1993 {
1994         UNSTICK_STUCK = 0,
1995         UNSTICK_GOOD = 1,
1996         UNSTICK_UNSTUCK = 2
1997 }
1998 unstickresult_t;
1999
2000 unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
2001 {
2002         int i, maxunstick;
2003
2004         // if not stuck in a bmodel, just return
2005         if (!SV_TestEntityPosition(ent, vec3_origin))
2006                 return UNSTICK_GOOD;
2007
2008         for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
2009         {
2010                 if (!SV_TestEntityPosition(ent, unstickoffsets + i))
2011                 {
2012                         VectorCopy(unstickoffsets + i, offset);
2013                         SV_LinkEdict(ent);
2014                         //SV_LinkEdict_TouchAreaGrid(ent);
2015                         return UNSTICK_UNSTUCK;
2016                 }
2017         }
2018
2019         maxunstick = (int) ((PRVM_serveredictvector(ent, maxs)[2] - PRVM_serveredictvector(ent, mins)[2]) * 0.36);
2020         // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox
2021
2022         for(i = 2; i <= maxunstick; ++i)
2023         {
2024                 VectorClear(offset);
2025                 offset[2] = -i;
2026                 if (!SV_TestEntityPosition(ent, offset))
2027                 {
2028                         SV_LinkEdict(ent);
2029                         //SV_LinkEdict_TouchAreaGrid(ent);
2030                         return UNSTICK_UNSTUCK;
2031                 }
2032                 offset[2] = i;
2033                 if (!SV_TestEntityPosition(ent, offset))
2034                 {
2035                         SV_LinkEdict(ent);
2036                         //SV_LinkEdict_TouchAreaGrid(ent);
2037                         return UNSTICK_UNSTUCK;
2038                 }
2039         }
2040
2041         return UNSTICK_STUCK;
2042 }
2043
2044 qboolean SV_UnstickEntity (prvm_edict_t *ent)
2045 {
2046         vec3_t offset;
2047         switch(SV_UnstickEntityReturnOffset(ent, offset))
2048         {
2049                 case UNSTICK_GOOD:
2050                         return true;
2051                 case UNSTICK_UNSTUCK:
2052                         Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
2053                         return true;
2054                 case UNSTICK_STUCK:
2055                         if (developer_extra.integer)
2056                                 Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2057                         return false;
2058                 default:
2059                         Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2060                         return false;
2061         }
2062 }
2063
2064 /*
2065 =============
2066 SV_CheckStuck
2067
2068 This is a big hack to try and fix the rare case of getting stuck in the world
2069 clipping hull.
2070 =============
2071 */
2072 void SV_CheckStuck (prvm_edict_t *ent)
2073 {
2074         vec3_t offset;
2075
2076         switch(SV_UnstickEntityReturnOffset(ent, offset))
2077         {
2078                 case UNSTICK_GOOD:
2079                         VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin));
2080                         break;
2081                 case UNSTICK_UNSTUCK:
2082                         Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
2083                         break;
2084                 case UNSTICK_STUCK:
2085                         VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset);
2086                         if (!SV_TestEntityPosition(ent, offset))
2087                         {
2088                                 Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2089                                 SV_LinkEdict(ent);
2090                                 //SV_LinkEdict_TouchAreaGrid(ent);
2091                         }
2092                         else
2093                                 Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2094                         break;
2095                 default:
2096                         Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2097         }
2098 }
2099
2100
2101 /*
2102 =============
2103 SV_CheckWater
2104 =============
2105 */
2106 qboolean SV_CheckWater (prvm_edict_t *ent)
2107 {
2108         int cont;
2109         int nNativeContents;
2110         vec3_t point;
2111
2112         point[0] = PRVM_serveredictvector(ent, origin)[0];
2113         point[1] = PRVM_serveredictvector(ent, origin)[1];
2114         point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, mins)[2] + 1;
2115
2116         // DRESK - Support for Entity Contents Transition Event
2117         // NOTE: Some logic needed to be slightly re-ordered
2118         // to not affect performance and allow for the feature.
2119
2120         // Acquire Super Contents Prior to Resets
2121         cont = SV_PointSuperContents(point);
2122         // Acquire Native Contents Here
2123         nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
2124
2125         // DRESK - Support for Entity Contents Transition Event
2126         if(PRVM_serveredictfloat(ent, watertype))
2127                 // Entity did NOT Spawn; Check
2128                 SV_CheckContentsTransition(ent, nNativeContents);
2129
2130
2131         PRVM_serveredictfloat(ent, waterlevel) = 0;
2132         PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2133         cont = SV_PointSuperContents(point);
2134         if (cont & (SUPERCONTENTS_LIQUIDSMASK))
2135         {
2136                 PRVM_serveredictfloat(ent, watertype) = nNativeContents;
2137                 PRVM_serveredictfloat(ent, waterlevel) = 1;
2138                 point[2] = PRVM_serveredictvector(ent, origin)[2] + (PRVM_serveredictvector(ent, mins)[2] + PRVM_serveredictvector(ent, maxs)[2])*0.5;
2139                 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2140                 {
2141                         PRVM_serveredictfloat(ent, waterlevel) = 2;
2142                         point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2];
2143                         if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2144                                 PRVM_serveredictfloat(ent, waterlevel) = 3;
2145                 }
2146         }
2147
2148         return PRVM_serveredictfloat(ent, waterlevel) > 1;
2149 }
2150
2151 /*
2152 ============
2153 SV_WallFriction
2154
2155 ============
2156 */
2157 void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
2158 {
2159         float d, i;
2160         vec3_t forward, into, side;
2161
2162         AngleVectors (PRVM_serveredictvector(ent, v_angle), forward, NULL, NULL);
2163         if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
2164         {
2165                 // cut the tangential velocity
2166                 i = DotProduct (stepnormal, PRVM_serveredictvector(ent, velocity));
2167                 VectorScale (stepnormal, i, into);
2168                 VectorSubtract (PRVM_serveredictvector(ent, velocity), into, side);
2169                 PRVM_serveredictvector(ent, velocity)[0] = side[0] * (1 + d);
2170                 PRVM_serveredictvector(ent, velocity)[1] = side[1] * (1 + d);
2171         }
2172 }
2173
2174 #if 0
2175 /*
2176 =====================
2177 SV_TryUnstick
2178
2179 Player has come to a dead stop, possibly due to the problem with limited
2180 float precision at some angle joins in the BSP hull.
2181
2182 Try fixing by pushing one pixel in each direction.
2183
2184 This is a hack, but in the interest of good gameplay...
2185 ======================
2186 */
2187 int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
2188 {
2189         int i, clip;
2190         vec3_t oldorg, dir;
2191
2192         VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
2193         VectorClear (dir);
2194
2195         for (i=0 ; i<8 ; i++)
2196         {
2197                 // try pushing a little in an axial direction
2198                 switch (i)
2199                 {
2200                         case 0: dir[0] = 2; dir[1] = 0; break;
2201                         case 1: dir[0] = 0; dir[1] = 2; break;
2202                         case 2: dir[0] = -2; dir[1] = 0; break;
2203                         case 3: dir[0] = 0; dir[1] = -2; break;
2204                         case 4: dir[0] = 2; dir[1] = 2; break;
2205                         case 5: dir[0] = -2; dir[1] = 2; break;
2206                         case 6: dir[0] = 2; dir[1] = -2; break;
2207                         case 7: dir[0] = -2; dir[1] = -2; break;
2208                 }
2209
2210                 SV_PushEntity (&trace, ent, dir, false, true);
2211
2212                 // retry the original move
2213                 PRVM_serveredictvector(ent, velocity)[0] = oldvel[0];
2214                 PRVM_serveredictvector(ent, velocity)[1] = oldvel[1];
2215                 PRVM_serveredictvector(ent, velocity)[2] = 0;
2216                 clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent));
2217
2218                 if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4
2219                  || fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4)
2220                 {
2221                         Con_DPrint("TryUnstick - success.\n");
2222                         return clip;
2223                 }
2224
2225                 // go back to the original pos and try again
2226                 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
2227         }
2228
2229         // still not moving
2230         VectorClear (PRVM_serveredictvector(ent, velocity));
2231         Con_DPrint("TryUnstick - failure.\n");
2232         return 7;
2233 }
2234 #endif
2235
2236 /*
2237 =====================
2238 SV_WalkMove
2239
2240 Only used by players
2241 ======================
2242 */
2243 void SV_WalkMove (prvm_edict_t *ent)
2244 {
2245         int clip;
2246         int oldonground;
2247         //int originalmove_clip;
2248         int originalmove_flags;
2249         int originalmove_groundentity;
2250         int hitsupercontentsmask;
2251         int type;
2252         vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
2253         trace_t downtrace, trace;
2254         qboolean applygravity;
2255
2256         // if frametime is 0 (due to client sending the same timestamp twice),
2257         // don't move
2258         if (sv.frametime <= 0)
2259                 return;
2260
2261         SV_CheckStuck (ent);
2262
2263         applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
2264
2265         hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
2266
2267         SV_CheckVelocity(ent);
2268
2269         // do a regular slide move unless it looks like you ran into a step
2270         oldonground = (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND;
2271
2272         VectorCopy (PRVM_serveredictvector(ent, origin), start_origin);
2273         VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity);
2274
2275         clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
2276
2277         if(sv_gameplayfix_downtracesupportsongroundflag.integer)
2278         if(!(clip & 1))
2279         {
2280                 // only try this if there was no floor in the way in the trace (no,
2281                 // this check seems to be not REALLY necessary, because if clip & 1,
2282                 // our trace will hit that thing too)
2283                 VectorSet(upmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + 1);
2284                 VectorSet(downmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] - 1);
2285                 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLYMISSILE)
2286                         type = MOVE_MISSILE;
2287                 else if (PRVM_serveredictfloat(ent, solid) == SOLID_TRIGGER || PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
2288                         type = MOVE_NOMONSTERS; // only clip against bmodels
2289                 else
2290                         type = MOVE_NORMAL;
2291                 trace = SV_TraceBox(upmove, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
2292                 if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
2293                         clip |= 1; // but we HAVE found a floor
2294         }
2295
2296         // if the move did not hit the ground at any point, we're not on ground
2297         if(!(clip & 1))
2298                 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2299
2300         SV_CheckVelocity(ent);
2301         SV_LinkEdict(ent);
2302         SV_LinkEdict_TouchAreaGrid(ent);
2303
2304         if(clip & 8) // teleport
2305                 return;
2306
2307         if ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP)
2308                 return;
2309
2310         if (sv_nostep.integer)
2311                 return;
2312
2313         VectorCopy(PRVM_serveredictvector(ent, origin), originalmove_origin);
2314         VectorCopy(PRVM_serveredictvector(ent, velocity), originalmove_velocity);
2315         //originalmove_clip = clip;
2316         originalmove_flags = (int)PRVM_serveredictfloat(ent, flags);
2317         originalmove_groundentity = PRVM_serveredictedict(ent, groundentity);
2318
2319         // if move didn't block on a step, return
2320         if (clip & 2)
2321         {
2322                 // if move was not trying to move into the step, return
2323                 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
2324                         return;
2325
2326                 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY)
2327                 {
2328                         // return if gibbed by a trigger
2329                         if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_WALK)
2330                                 return;
2331
2332                         // only step up while jumping if that is enabled
2333                         if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
2334                                 if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0)
2335                                         return;
2336                 }
2337
2338                 // try moving up and forward to go up a step
2339                 // back to start pos
2340                 VectorCopy (start_origin, PRVM_serveredictvector(ent, origin));
2341                 VectorCopy (start_velocity, PRVM_serveredictvector(ent, velocity));
2342
2343                 // move up
2344                 VectorClear (upmove);
2345                 upmove[2] = sv_stepheight.value;
2346                 if(!SV_PushEntity(&trace, ent, upmove, false, true))
2347                 {
2348                         // we got teleported when upstepping... must abort the move
2349                         return;
2350                 }
2351
2352                 // move forward
2353                 PRVM_serveredictvector(ent, velocity)[2] = 0;
2354                 clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, 0);
2355                 PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2];
2356                 if(clip & 8)
2357                 {
2358                         // we got teleported when upstepping... must abort the move
2359                         // note that z velocity handling may not be what QC expects here, but we cannot help it
2360                         return;
2361                 }
2362
2363                 SV_CheckVelocity(ent);
2364                 SV_LinkEdict(ent);
2365                 SV_LinkEdict_TouchAreaGrid(ent);
2366
2367                 // check for stuckness, possibly due to the limited precision of floats
2368                 // in the clipping hulls
2369                 if (clip
2370                  && fabs(originalmove_origin[1] - PRVM_serveredictvector(ent, origin)[1]) < 0.03125
2371                  && fabs(originalmove_origin[0] - PRVM_serveredictvector(ent, origin)[0]) < 0.03125)
2372                 {
2373                         //Con_Printf("wall\n");
2374                         // stepping up didn't make any progress, revert to original move
2375                         VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2376                         VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2377                         //clip = originalmove_clip;
2378                         PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2379                         PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2380                         // now try to unstick if needed
2381                         //clip = SV_TryUnstick (ent, oldvel);
2382                         return;
2383                 }
2384
2385                 //Con_Printf("step - ");
2386
2387                 // extra friction based on view angle
2388                 if (clip & 2 && sv_wallfriction.integer)
2389                         SV_WallFriction (ent, stepnormal);
2390         }
2391         // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
2392         else if (!sv_gameplayfix_stepdown.integer || PRVM_serveredictfloat(ent, waterlevel) >= 3 || start_velocity[2] >= (1.0 / 32.0) || !oldonground || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
2393                 return;
2394
2395         // move down
2396         VectorClear (downmove);
2397         downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
2398         if(!SV_PushEntity (&downtrace, ent, downmove, false, true))
2399         {
2400                 // we got teleported when downstepping... must abort the move
2401                 return;
2402         }
2403
2404         if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
2405         {
2406                 // this has been disabled so that you can't jump when you are stepping
2407                 // up while already jumping (also known as the Quake2 double jump bug)
2408 #if 0
2409                 // LordHavoc: disabled this check so you can walk on monsters/players
2410                 //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
2411                 {
2412                         //Con_Printf("onground\n");
2413                         PRVM_serveredictfloat(ent, flags) =     (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2414                         PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(downtrace.ent);
2415                 }
2416 #endif
2417         }
2418         else
2419         {
2420                 //Con_Printf("slope\n");
2421                 // if the push down didn't end up on good ground, use the move without
2422                 // the step up.  This happens near wall / slope combinations, and can
2423                 // cause the player to hop up higher on a slope too steep to climb
2424                 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2425                 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2426                 //clip = originalmove_clip;
2427                 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2428                 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2429         }
2430
2431         SV_CheckVelocity(ent);
2432         SV_LinkEdict(ent);
2433         SV_LinkEdict_TouchAreaGrid(ent);
2434 }
2435
2436 //============================================================================
2437
2438 /*
2439 =============
2440 SV_Physics_Follow
2441
2442 Entities that are "stuck" to another entity
2443 =============
2444 */
2445 void SV_Physics_Follow (prvm_edict_t *ent)
2446 {
2447         vec3_t vf, vr, vu, angles, v;
2448         prvm_edict_t *e;
2449
2450         // regular thinking
2451         if (!SV_RunThink (ent))
2452                 return;
2453
2454         // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
2455         e = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, aiment));
2456         if (PRVM_serveredictvector(e, angles)[0] == PRVM_serveredictvector(ent, punchangle)[0] && PRVM_serveredictvector(e, angles)[1] == PRVM_serveredictvector(ent, punchangle)[1] && PRVM_serveredictvector(e, angles)[2] == PRVM_serveredictvector(ent, punchangle)[2])
2457         {
2458                 // quick case for no rotation
2459                 VectorAdd(PRVM_serveredictvector(e, origin), PRVM_serveredictvector(ent, view_ofs), PRVM_serveredictvector(ent, origin));
2460         }
2461         else
2462         {
2463                 angles[0] = -PRVM_serveredictvector(ent, punchangle)[0];
2464                 angles[1] =  PRVM_serveredictvector(ent, punchangle)[1];
2465                 angles[2] =  PRVM_serveredictvector(ent, punchangle)[2];
2466                 AngleVectors (angles, vf, vr, vu);
2467                 v[0] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[0] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[0] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[0];
2468                 v[1] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[1] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[1] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[1];
2469                 v[2] = PRVM_serveredictvector(ent, view_ofs)[0] * vf[2] + PRVM_serveredictvector(ent, view_ofs)[1] * vr[2] + PRVM_serveredictvector(ent, view_ofs)[2] * vu[2];
2470                 angles[0] = -PRVM_serveredictvector(e, angles)[0];
2471                 angles[1] =  PRVM_serveredictvector(e, angles)[1];
2472                 angles[2] =  PRVM_serveredictvector(e, angles)[2];
2473                 AngleVectors (angles, vf, vr, vu);
2474                 PRVM_serveredictvector(ent, origin)[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + PRVM_serveredictvector(e, origin)[0];
2475                 PRVM_serveredictvector(ent, origin)[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + PRVM_serveredictvector(e, origin)[1];
2476                 PRVM_serveredictvector(ent, origin)[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + PRVM_serveredictvector(e, origin)[2];
2477         }
2478         VectorAdd (PRVM_serveredictvector(e, angles), PRVM_serveredictvector(ent, v_angle), PRVM_serveredictvector(ent, angles));
2479         SV_LinkEdict(ent);
2480         //SV_LinkEdict_TouchAreaGrid(ent);
2481 }
2482
2483 /*
2484 ==============================================================================
2485
2486 TOSS / BOUNCE
2487
2488 ==============================================================================
2489 */
2490
2491 /*
2492 =============
2493 SV_CheckWaterTransition
2494
2495 =============
2496 */
2497 void SV_CheckWaterTransition (prvm_edict_t *ent)
2498 {
2499         int cont;
2500         cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_serveredictvector(ent, origin)));
2501         if (!PRVM_serveredictfloat(ent, watertype))
2502         {
2503                 // just spawned here
2504                 PRVM_serveredictfloat(ent, watertype) = cont;
2505                 PRVM_serveredictfloat(ent, waterlevel) = 1;
2506                 return;
2507         }
2508
2509         // DRESK - Support for Entity Contents Transition Event
2510         // NOTE: Call here BEFORE updating the watertype below,
2511         // and suppress watersplash sound if a valid function
2512         // call was made to allow for custom "splash" sounds.
2513         if( !SV_CheckContentsTransition(ent, cont) )
2514         { // Contents Transition Function Invalid; Potentially Play Water Sound
2515                 // check if the entity crossed into or out of water
2516                 if (sv_sound_watersplash.string && ((PRVM_serveredictfloat(ent, watertype) == CONTENTS_WATER || PRVM_serveredictfloat(ent, watertype) == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)))
2517                         SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false);
2518         }
2519
2520         if (cont <= CONTENTS_WATER)
2521         {
2522                 PRVM_serveredictfloat(ent, watertype) = cont;
2523                 PRVM_serveredictfloat(ent, waterlevel) = 1;
2524         }
2525         else
2526         {
2527                 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2528                 PRVM_serveredictfloat(ent, waterlevel) = 0;
2529         }
2530 }
2531
2532 /*
2533 =============
2534 SV_Physics_Toss
2535
2536 Toss, bounce, and fly movement.  When onground, do nothing.
2537 =============
2538 */
2539 void SV_Physics_Toss (prvm_edict_t *ent)
2540 {
2541         trace_t trace;
2542         vec3_t move;
2543         vec_t movetime;
2544         int bump;
2545         prvm_edict_t *groundentity;
2546
2547 // if onground, return without moving
2548         if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2549         {
2550                 groundentity = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, groundentity));
2551                 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2552                 {
2553                         // don't stick to ground if onground and moving upward
2554                         PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2555                 }
2556                 else if (!PRVM_serveredictedict(ent, groundentity) || !sv_gameplayfix_noairborncorpse.integer)
2557                 {
2558                         // we can trust FL_ONGROUND if groundentity is world because it never moves
2559                         return;
2560                 }
2561                 else if (ent->priv.server->suspendedinairflag && groundentity->priv.server->free)
2562                 {
2563                         // if ent was supported by a brush model on previous frame,
2564                         // and groundentity is now freed, set groundentity to 0 (world)
2565                         // which leaves it suspended in the air
2566                         PRVM_serveredictedict(ent, groundentity) = 0;
2567                         if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer)
2568                                 return;
2569                 }
2570                 else if (BoxesOverlap(ent->priv.server->cullmins, ent->priv.server->cullmaxs, groundentity->priv.server->cullmins, groundentity->priv.server->cullmaxs))
2571                 {
2572                         // don't slide if still touching the groundentity
2573                         return;
2574                 }
2575         }
2576         ent->priv.server->suspendedinairflag = false;
2577
2578         SV_CheckVelocity (ent);
2579
2580 // add gravity
2581         if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_TOSS || PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2582                 PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
2583
2584 // move angles
2585         VectorMA (PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2586
2587         movetime = sv.frametime;
2588         for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
2589         {
2590         // move origin
2591                 VectorScale (PRVM_serveredictvector(ent, velocity), movetime, move);
2592                 if(!SV_PushEntity (&trace, ent, move, true, true))
2593                         return; // teleported
2594                 if (ent->priv.server->free)
2595                         return;
2596                 if (trace.bmodelstartsolid)
2597                 {
2598                         // try to unstick the entity
2599                         SV_UnstickEntity(ent);
2600                         if(!SV_PushEntity (&trace, ent, move, false, true))
2601                                 return; // teleported
2602                         if (ent->priv.server->free)
2603                                 return;
2604                 }
2605                 if (trace.fraction == 1)
2606                         break;
2607                 movetime *= 1 - min(1, trace.fraction);
2608                 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE)
2609                 {
2610                         float bouncefactor;
2611                         bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2612                         if (!bouncefactor)
2613                                 bouncefactor = 1.0f;
2614
2615                         ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2616                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2617                 }
2618                 else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2619                 {
2620                         float d, ent_gravity;
2621                         float bouncefactor;
2622                         float bouncestop;
2623
2624                         bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2625                         if (!bouncefactor)
2626                                 bouncefactor = 0.5f;
2627
2628                         bouncestop = PRVM_serveredictfloat(ent, bouncestop);
2629                         if (!bouncestop)
2630                                 bouncestop = 60.0f / 800.0f;
2631
2632                         ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2633                         ent_gravity = PRVM_serveredictfloat(ent, gravity);
2634                         if (!ent_gravity)
2635                                 ent_gravity = 1.0f;
2636                         // LordHavoc: fixed grenades not bouncing when fired down a slope
2637                         if (sv_gameplayfix_grenadebouncedownslopes.integer)
2638                         {
2639                                 d = DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity));
2640                                 if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * bouncestop * ent_gravity)
2641                                 {
2642                                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2643                                         PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2644                                         VectorClear (PRVM_serveredictvector(ent, velocity));
2645                                         VectorClear (PRVM_serveredictvector(ent, avelocity));
2646                                 }
2647                                 else
2648                                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2649                         }
2650                         else
2651                         {
2652                                 if (trace.plane.normal[2] > 0.7 && PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * bouncestop * ent_gravity)
2653                                 {
2654                                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2655                                         PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2656                                         VectorClear (PRVM_serveredictvector(ent, velocity));
2657                                         VectorClear (PRVM_serveredictvector(ent, avelocity));
2658                                 }
2659                                 else
2660                                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2661                         }
2662                 }
2663                 else
2664                 {
2665                         ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0);
2666                         if (trace.plane.normal[2] > 0.7)
2667                         {
2668                                 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2669                                 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2670                                 if (PRVM_serveredictfloat(((prvm_edict_t *)trace.ent), solid) == SOLID_BSP)
2671                                         ent->priv.server->suspendedinairflag = true;
2672                                 VectorClear (PRVM_serveredictvector(ent, velocity));
2673                                 VectorClear (PRVM_serveredictvector(ent, avelocity));
2674                         }
2675                         else
2676                                 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2677                 }
2678                 if (!sv_gameplayfix_slidemoveprojectiles.integer || (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_BOUNCE && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE) || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
2679                         break;
2680         }
2681
2682 // check for in water
2683         SV_CheckWaterTransition (ent);
2684 }
2685
2686 /*
2687 ===============================================================================
2688
2689 STEPPING MOVEMENT
2690
2691 ===============================================================================
2692 */
2693
2694 /*
2695 =============
2696 SV_Physics_Step
2697
2698 Monsters freefall when they don't have a ground entity, otherwise
2699 all movement is done with discrete steps.
2700
2701 This is also used for objects that have become still on the ground, but
2702 will fall if the floor is pulled out from under them.
2703 =============
2704 */
2705 void SV_Physics_Step (prvm_edict_t *ent)
2706 {
2707         int flags = (int)PRVM_serveredictfloat(ent, flags);
2708
2709         // DRESK
2710         // Backup Velocity in the event that movetypesteplandevent is called,
2711         // to provide a parameter with the entity's velocity at impact.
2712         vec3_t backupVelocity;
2713         VectorCopy(PRVM_serveredictvector(ent, velocity), backupVelocity);
2714         // don't fall at all if fly/swim
2715         if (!(flags & (FL_FLY | FL_SWIM)))
2716         {
2717                 if (flags & FL_ONGROUND)
2718                 {
2719                         // freefall if onground and moving upward
2720                         // freefall if not standing on a world surface (it may be a lift or trap door)
2721                         if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2722                         {
2723                                 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2724                                 SV_CheckVelocity(ent);
2725                                 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2726                                 SV_LinkEdict(ent);
2727                                 SV_LinkEdict_TouchAreaGrid(ent);
2728                                 ent->priv.server->waterposition_forceupdate = true;
2729                         }
2730                 }
2731                 else
2732                 {
2733                         // freefall if not onground
2734                         int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1;
2735
2736                         SV_CheckVelocity(ent);
2737                         SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2738                         SV_LinkEdict(ent);
2739                         SV_LinkEdict_TouchAreaGrid(ent);
2740
2741                         // just hit ground
2742                         if (hitsound && (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2743                         {
2744                                 // DRESK - Check for Entity Land Event Function
2745                                 if(PRVM_serveredictfunction(ent, movetypesteplandevent))
2746                                 { // Valid Function; Execute
2747                                         // Prepare Parameters
2748                                                 // Assign Velocity at Impact
2749                                                 PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0];
2750                                                 PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
2751                                                 PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
2752                                                 // Assign Self
2753                                                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2754                                         // Execute VM Function
2755                                         PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function");
2756                                 }
2757                                 else
2758                                 // Check for Engine Landing Sound
2759                                 if(sv_sound_land.string)
2760                                         SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false);
2761                         }
2762                         ent->priv.server->waterposition_forceupdate = true;
2763                 }
2764         }
2765
2766 // regular thinking
2767         if (!SV_RunThink(ent))
2768                 return;
2769
2770         if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
2771         {
2772                 ent->priv.server->waterposition_forceupdate = false;
2773                 VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
2774                 SV_CheckWaterTransition(ent);
2775         }
2776 }
2777
2778 //============================================================================
2779
2780 static void SV_Physics_Entity (prvm_edict_t *ent)
2781 {
2782         // don't run think/move on newly spawned projectiles as it messes up
2783         // movement interpolation and rocket trails, and is inconsistent with
2784         // respect to entities spawned in the same frame
2785         // (if an ent spawns a higher numbered ent, it moves in the same frame,
2786         //  but if it spawns a lower numbered ent, it doesn't - this never moves
2787         //  ents in the first frame regardless)
2788         qboolean runmove = ent->priv.server->move;
2789         ent->priv.server->move = true;
2790         if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
2791                 return;
2792         switch ((int) PRVM_serveredictfloat(ent, movetype))
2793         {
2794         case MOVETYPE_PUSH:
2795         case MOVETYPE_FAKEPUSH:
2796                 SV_Physics_Pusher (ent);
2797                 break;
2798         case MOVETYPE_NONE:
2799                 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2800                 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2801                         SV_RunThink (ent);
2802                 break;
2803         case MOVETYPE_FOLLOW:
2804                 SV_Physics_Follow (ent);
2805                 break;
2806         case MOVETYPE_NOCLIP:
2807                 if (SV_RunThink(ent))
2808                 {
2809                         SV_CheckWater(ent);
2810                         VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2811                         VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2812                 }
2813                 SV_LinkEdict(ent);
2814                 break;
2815         case MOVETYPE_STEP:
2816                 SV_Physics_Step (ent);
2817                 break;
2818         case MOVETYPE_WALK:
2819                 if (SV_RunThink (ent))
2820                         SV_WalkMove (ent);
2821                 break;
2822         case MOVETYPE_TOSS:
2823         case MOVETYPE_BOUNCE:
2824         case MOVETYPE_BOUNCEMISSILE:
2825         case MOVETYPE_FLYMISSILE:
2826         case MOVETYPE_FLY:
2827                 // regular thinking
2828                 if (SV_RunThink (ent))
2829                         SV_Physics_Toss (ent);
2830                 break;
2831         case MOVETYPE_PHYSICS:
2832                 if (SV_RunThink(ent))
2833                 {
2834                         SV_LinkEdict(ent);
2835                         SV_LinkEdict_TouchAreaGrid(ent);
2836                 }
2837                 break;
2838         default:
2839                 Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2840                 break;
2841         }
2842 }
2843
2844 void SV_Physics_ClientMove(void)
2845 {
2846         prvm_edict_t *ent;
2847         ent = host_client->edict;
2848
2849         // call player physics, this needs the proper frametime
2850         PRVM_serverglobalfloat(frametime) = sv.frametime;
2851         SV_ClientThink();
2852
2853         // call standard client pre-think, with frametime = 0
2854         PRVM_serverglobalfloat(time) = sv.time;
2855         PRVM_serverglobalfloat(frametime) = 0;
2856         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2857         PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2858         PRVM_serverglobalfloat(frametime) = sv.frametime;
2859
2860         // make sure the velocity is sane (not a NaN)
2861         SV_CheckVelocity(ent);
2862
2863         // perform MOVETYPE_WALK behavior
2864         SV_WalkMove (ent);
2865
2866         // call standard player post-think, with frametime = 0
2867         PRVM_serverglobalfloat(time) = sv.time;
2868         PRVM_serverglobalfloat(frametime) = 0;
2869         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2870         PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2871         PRVM_serverglobalfloat(frametime) = sv.frametime;
2872
2873         if(PRVM_serveredictfloat(ent, fixangle))
2874         {
2875                 // angle fixing was requested by physics code...
2876                 // so store the current angles for later use
2877                 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2878                 host_client->fixangle_angles_set = TRUE;
2879
2880                 // and clear fixangle for the next frame
2881                 PRVM_serveredictfloat(ent, fixangle) = 0;
2882         }
2883 }
2884
2885 static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
2886 {
2887         // don't do physics on disconnected clients, FrikBot relies on this
2888         if (!host_client->spawned)
2889                 return;
2890
2891         // make sure the velocity is sane (not a NaN)
2892         SV_CheckVelocity(ent);
2893
2894         // don't run physics here if running asynchronously
2895         if (host_client->clmovement_inputtimeout <= 0)
2896         {
2897                 SV_ClientThink();
2898                 //host_client->cmd.time = max(host_client->cmd.time, sv.time);
2899         }
2900
2901         // make sure the velocity is still sane (not a NaN)
2902         SV_CheckVelocity(ent);
2903
2904         // call standard client pre-think
2905         PRVM_serverglobalfloat(time) = sv.time;
2906         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2907         PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2908
2909         // make sure the velocity is still sane (not a NaN)
2910         SV_CheckVelocity(ent);
2911 }
2912
2913 static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
2914 {
2915         // don't do physics on disconnected clients, FrikBot relies on this
2916         if (!host_client->spawned)
2917                 return;
2918
2919         // make sure the velocity is sane (not a NaN)
2920         SV_CheckVelocity(ent);
2921
2922         // call standard player post-think
2923         PRVM_serverglobalfloat(time) = sv.time;
2924         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2925         PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2926
2927         // make sure the velocity is still sane (not a NaN)
2928         SV_CheckVelocity(ent);
2929
2930         if(PRVM_serveredictfloat(ent, fixangle))
2931         {
2932                 // angle fixing was requested by physics code...
2933                 // so store the current angles for later use
2934                 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2935                 host_client->fixangle_angles_set = TRUE;
2936
2937                 // and clear fixangle for the next frame
2938                 PRVM_serveredictfloat(ent, fixangle) = 0;
2939         }
2940
2941         // decrement the countdown variable used to decide when to go back to
2942         // synchronous physics
2943         if (host_client->clmovement_inputtimeout > sv.frametime)
2944                 host_client->clmovement_inputtimeout -= sv.frametime;
2945         else
2946                 host_client->clmovement_inputtimeout = 0;
2947 }
2948
2949 static void SV_Physics_ClientEntity(prvm_edict_t *ent)
2950 {
2951         // don't do physics on disconnected clients, FrikBot relies on this
2952         if (!host_client->spawned)
2953         {
2954                 memset(&host_client->cmd, 0, sizeof(host_client->cmd));
2955                 return;
2956         }
2957
2958         // make sure the velocity is sane (not a NaN)
2959         SV_CheckVelocity(ent);
2960
2961         switch ((int) PRVM_serveredictfloat(ent, movetype))
2962         {
2963         case MOVETYPE_PUSH:
2964         case MOVETYPE_FAKEPUSH:
2965                 SV_Physics_Pusher (ent);
2966                 break;
2967         case MOVETYPE_NONE:
2968                 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2969                 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2970                         SV_RunThink (ent);
2971                 break;
2972         case MOVETYPE_FOLLOW:
2973                 SV_Physics_Follow (ent);
2974                 break;
2975         case MOVETYPE_NOCLIP:
2976                 SV_RunThink(ent);
2977                 SV_CheckWater(ent);
2978                 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2979                 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2980                 break;
2981         case MOVETYPE_STEP:
2982                 SV_Physics_Step (ent);
2983                 break;
2984         case MOVETYPE_WALK:
2985                 SV_RunThink (ent);
2986                 // don't run physics here if running asynchronously
2987                 if (host_client->clmovement_inputtimeout <= 0)
2988                         SV_WalkMove (ent);
2989                 break;
2990         case MOVETYPE_TOSS:
2991         case MOVETYPE_BOUNCE:
2992         case MOVETYPE_BOUNCEMISSILE:
2993         case MOVETYPE_FLYMISSILE:
2994                 // regular thinking
2995                 SV_RunThink (ent);
2996                 SV_Physics_Toss (ent);
2997                 break;
2998         case MOVETYPE_FLY:
2999                 SV_RunThink (ent);
3000                 SV_WalkMove (ent);
3001                 break;
3002         case MOVETYPE_PHYSICS:
3003                 SV_RunThink (ent);
3004                 break;
3005         default:
3006                 Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
3007                 break;
3008         }
3009
3010         SV_CheckVelocity (ent);
3011
3012         SV_LinkEdict(ent);
3013         SV_LinkEdict_TouchAreaGrid(ent);
3014
3015         SV_CheckVelocity (ent);
3016 }
3017
3018 /*
3019 ================
3020 SV_Physics
3021
3022 ================
3023 */
3024 void SV_Physics (void)
3025 {
3026         int i;
3027         prvm_edict_t *ent;
3028
3029 // let the progs know that a new frame has started
3030         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3031         PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3032         PRVM_serverglobalfloat(time) = sv.time;
3033         PRVM_serverglobalfloat(frametime) = sv.frametime;
3034         PRVM_ExecuteProgram (PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
3035
3036         // run physics engine
3037         World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value);
3038
3039 //
3040 // treat each object in turn
3041 //
3042
3043         // if force_retouch, relink all the entities
3044         if (PRVM_serverglobalfloat(force_retouch) > 0)
3045                 for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3046                         if (!ent->priv.server->free)
3047                                 SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
3048
3049         if (sv_gameplayfix_consistentplayerprethink.integer)
3050         {
3051                 // run physics on the client entities in 3 stages
3052                 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3053                         if (!ent->priv.server->free)
3054                                 SV_Physics_ClientEntity_PreThink(ent);
3055
3056                 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3057                         if (!ent->priv.server->free)
3058                                 SV_Physics_ClientEntity(ent);
3059
3060                 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3061                         if (!ent->priv.server->free)
3062                                 SV_Physics_ClientEntity_PostThink(ent);
3063         }
3064         else
3065         {
3066                 // run physics on the client entities
3067                 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3068                 {
3069                         if (!ent->priv.server->free)
3070                         {
3071                                 SV_Physics_ClientEntity_PreThink(ent);
3072                                 SV_Physics_ClientEntity(ent);
3073                                 SV_Physics_ClientEntity_PostThink(ent);
3074                         }
3075                 }
3076         }
3077
3078         // run physics on all the non-client entities
3079         if (!sv_freezenonclients.integer)
3080         {
3081                 for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3082                         if (!ent->priv.server->free)
3083                                 SV_Physics_Entity(ent);
3084                 // make a second pass to see if any ents spawned this frame and make
3085                 // sure they run their move/think
3086                 if (sv_gameplayfix_delayprojectiles.integer < 0)
3087                         for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3088                                 if (!ent->priv.server->move && !ent->priv.server->free)
3089                                         SV_Physics_Entity(ent);
3090         }
3091
3092         if (PRVM_serverglobalfloat(force_retouch) > 0)
3093                 PRVM_serverglobalfloat(force_retouch) = max(0, PRVM_serverglobalfloat(force_retouch) - 1);
3094
3095         // LordHavoc: endframe support
3096         if (PRVM_serverfunction(EndFrame))
3097         {
3098                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3099                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3100                 PRVM_serverglobalfloat(time) = sv.time;
3101                 PRVM_ExecuteProgram (PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
3102         }
3103
3104         // decrement prog->num_edicts if the highest number entities died
3105         for (;PRVM_ED_CanAlloc(PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
3106
3107         if (!sv_freezenonclients.integer)
3108                 sv.time += sv.frametime;
3109 }