]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - sv_phys.c
added sv_areadebug cvar which disables the use of the areagrid (VERY bad
[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 = SV_EntitiesInBox(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 = SV_EntitiesInBox(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 = SV_EntitiesInBox(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 = SV_EntitiesInBox(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 int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_edict_t **resultedicts)
703 {
704         vec3_t paddedmins, paddedmaxs;
705         if (maxedicts < 1 || resultedicts == NULL)
706                 return 0;
707         VectorSet(paddedmins, mins[0] - 10, mins[1] - 10, mins[2] - 1);
708         VectorSet(paddedmaxs, maxs[0] + 10, maxs[1] + 10, maxs[2] + 1);
709         if (sv_areadebug.integer)
710         {
711                 int numresultedicts = 0;
712                 int edictindex;
713                 prvm_edict_t *ed;
714                 for (edictindex = 1;edictindex < prog->num_edicts;edictindex++)
715                 {
716                         ed = PRVM_EDICT_NUM(edictindex);
717                         if (!ed->priv.required->free && BoxesOverlap(PRVM_serveredictvector(ed, absmin), PRVM_serveredictvector(ed, absmax), paddedmins, paddedmaxs))
718                         {
719                                 resultedicts[numresultedicts++] = ed;
720                                 if (numresultedicts == maxedicts)
721                                         break;
722                         }
723                 }
724                 return numresultedicts;
725         }
726         else
727                 return World_EntitiesInBox(&sv.world, paddedmins, paddedmaxs, maxedicts, resultedicts);
728 }
729
730 void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent)
731 {
732         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(touch);
733         PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(ent);
734         PRVM_serverglobalfloat(time) = sv.time;
735         PRVM_serverglobalfloat(trace_allsolid) = false;
736         PRVM_serverglobalfloat(trace_startsolid) = false;
737         PRVM_serverglobalfloat(trace_fraction) = 1;
738         PRVM_serverglobalfloat(trace_inwater) = false;
739         PRVM_serverglobalfloat(trace_inopen) = true;
740         VectorCopy (PRVM_serveredictvector(touch, origin), PRVM_serverglobalvector(trace_endpos));
741         VectorSet (PRVM_serverglobalvector(trace_plane_normal), 0, 0, 1);
742         PRVM_serverglobalfloat(trace_plane_dist) = 0;
743         PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(ent);
744         PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
745         PRVM_serverglobalfloat(trace_dphitcontents) = 0;
746         PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
747         PRVM_serverglobalstring(trace_dphittexturename) = 0;
748         PRVM_ExecuteProgram (PRVM_serveredictfunction(touch, touch), "QC function self.touch is missing");
749 }
750
751 void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
752 {
753         int i, numtouchedicts, old_self, old_other;
754         prvm_edict_t *touch;
755         static prvm_edict_t *touchedicts[MAX_EDICTS];
756
757         if (ent == prog->edicts)
758                 return;         // don't add the world
759
760         if (ent->priv.server->free)
761                 return;
762
763         if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
764                 return;
765
766         // build a list of edicts to touch, because the link loop can be corrupted
767         // by IncreaseEdicts called during touch functions
768         numtouchedicts = SV_EntitiesInBox(ent->priv.server->areamins, ent->priv.server->areamaxs, MAX_EDICTS, touchedicts);
769         if (numtouchedicts > MAX_EDICTS)
770         {
771                 // this never happens
772                 Con_Printf("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS);
773                 numtouchedicts = MAX_EDICTS;
774         }
775
776         old_self = PRVM_serverglobaledict(self);
777         old_other = PRVM_serverglobaledict(other);
778         for (i = 0;i < numtouchedicts;i++)
779         {
780                 touch = touchedicts[i];
781                 if (touch != ent && (int)PRVM_serveredictfloat(touch, solid) == SOLID_TRIGGER && PRVM_serveredictfunction(touch, touch))
782                 {
783                         SV_LinkEdict_TouchAreaGrid_Call(touch, ent);
784                 }
785         }
786         PRVM_serverglobaledict(self) = old_self;
787         PRVM_serverglobaledict(other) = old_other;
788 }
789
790 static void RotateBBox(const vec3_t mins, const vec3_t maxs, const vec3_t angles, vec3_t rotatedmins, vec3_t rotatedmaxs)
791 {
792         vec3_t v, u;
793         matrix4x4_t m;
794         Matrix4x4_CreateFromQuakeEntity(&m, 0, 0, 0, angles[PITCH], angles[YAW], angles[ROLL], 1.0);
795
796         v[0] = mins[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
797                 VectorCopy(u, rotatedmins); VectorCopy(u, rotatedmaxs);
798         v[0] = maxs[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
799                 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];
800                 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];
801         v[0] = mins[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
802                 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];
803                 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];
804         v[0] = maxs[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
805                 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];
806                 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];
807         v[0] = mins[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
808                 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];
809                 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];
810         v[0] = maxs[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
811                 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];
812                 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];
813         v[0] = mins[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
814                 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];
815                 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];
816         v[0] = maxs[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
817                 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];
818                 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];
819 }
820
821 /*
822 ===============
823 SV_LinkEdict
824
825 ===============
826 */
827 void SV_LinkEdict (prvm_edict_t *ent)
828 {
829         dp_model_t *model;
830         vec3_t mins, maxs;
831         int modelindex;
832
833         if (ent == prog->edicts)
834                 return;         // don't add the world
835
836         if (ent->priv.server->free)
837                 return;
838
839         modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
840         if (modelindex < 0 || modelindex >= MAX_MODELS)
841         {
842                 Con_Printf("edict %i: SOLID_BSP with invalid modelindex!\n", PRVM_NUM_FOR_EDICT(ent));
843                 modelindex = 0;
844         }
845         model = SV_GetModelByIndex(modelindex);
846
847         VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
848         VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
849         VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
850
851 // set the abs box
852
853         if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_PHYSICS)
854         {
855                 // TODO maybe should do this for rotating SOLID_BSP too? Would behave better with rotating doors
856                 // TODO special handling for spheres?
857                 RotateBBox(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, angles), mins, maxs);
858                 VectorAdd(PRVM_serveredictvector(ent, origin), mins, mins);
859                 VectorAdd(PRVM_serveredictvector(ent, origin), maxs, maxs);
860         }
861         else if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
862         {
863                 if (model != NULL)
864                 {
865                         if (!model->TraceBox)
866                                 Con_DPrintf("edict %i: SOLID_BSP with non-collidable model\n", PRVM_NUM_FOR_EDICT(ent));
867
868                         if (PRVM_serveredictvector(ent, angles)[0] || PRVM_serveredictvector(ent, angles)[2] || PRVM_serveredictvector(ent, avelocity)[0] || PRVM_serveredictvector(ent, avelocity)[2])
869                         {
870                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmins, mins);
871                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->rotatedmaxs, maxs);
872                         }
873                         else if (PRVM_serveredictvector(ent, angles)[1] || PRVM_serveredictvector(ent, avelocity)[1])
874                         {
875                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmins, mins);
876                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->yawmaxs, maxs);
877                         }
878                         else
879                         {
880                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmins, mins);
881                                 VectorAdd(PRVM_serveredictvector(ent, origin), model->normalmaxs, maxs);
882                         }
883                 }
884                 else
885                 {
886                         // SOLID_BSP with no model is valid, mainly because some QC setup code does so temporarily
887                         VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
888                         VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
889                 }
890         }
891         else
892         {
893                 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), mins);
894                 VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
895         }
896
897 //
898 // to make items easier to pick up and allow them to be grabbed off
899 // of shelves, the abs sizes are expanded
900 //
901         if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
902         {
903                 mins[0] -= 15;
904                 mins[1] -= 15;
905                 mins[2] -= 1;
906                 maxs[0] += 15;
907                 maxs[1] += 15;
908                 maxs[2] += 1;
909         }
910         else
911         {
912                 // because movement is clipped an epsilon away from an actual edge,
913                 // we must fully check even when bounding boxes don't quite touch
914                 mins[0] -= 1;
915                 mins[1] -= 1;
916                 mins[2] -= 1;
917                 maxs[0] += 1;
918                 maxs[1] += 1;
919                 maxs[2] += 1;
920         }
921
922         VectorCopy(mins, PRVM_serveredictvector(ent, absmin));
923         VectorCopy(maxs, PRVM_serveredictvector(ent, absmax));
924
925         World_LinkEdict(&sv.world, ent, mins, maxs);
926 }
927
928 /*
929 ===============================================================================
930
931 Utility functions
932
933 ===============================================================================
934 */
935
936 /*
937 ============
938 SV_TestEntityPosition
939
940 returns true if the entity is in solid currently
941 ============
942 */
943 static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
944 {
945         int contents;
946         vec3_t org;
947         trace_t trace;
948         contents = SV_GenericHitSuperContentsMask(ent);
949         VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
950         trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), ((PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), ent, contents);
951         if (trace.startsupercontents & contents)
952                 return true;
953         else
954         {
955                 if (sv.worldmodel->brushq1.numclipnodes && !VectorCompare(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs)))
956                 {
957                         // q1bsp/hlbsp use hulls and if the entity does not exactly match
958                         // a hull size it is incorrectly tested, so this code tries to
959                         // 'fix' it slightly...
960                         // FIXME: this breaks entities larger than the hull size
961                         int i;
962                         vec3_t v, m1, m2, s;
963                         VectorAdd(org, PRVM_serveredictvector(ent, mins), m1);
964                         VectorAdd(org, PRVM_serveredictvector(ent, maxs), m2);
965                         VectorSubtract(m2, m1, s);
966 #define EPSILON (1.0f / 32.0f)
967                         if (s[0] >= EPSILON*2) {m1[0] += EPSILON;m2[0] -= EPSILON;}
968                         if (s[1] >= EPSILON*2) {m1[1] += EPSILON;m2[1] -= EPSILON;}
969                         if (s[2] >= EPSILON*2) {m1[2] += EPSILON;m2[2] -= EPSILON;}
970                         for (i = 0;i < 8;i++)
971                         {
972                                 v[0] = (i & 1) ? m2[0] : m1[0];
973                                 v[1] = (i & 2) ? m2[1] : m1[1];
974                                 v[2] = (i & 4) ? m2[2] : m1[2];
975                                 if (SV_PointSuperContents(v) & contents)
976                                         return true;
977                         }
978                 }
979         }
980         // if the trace found a better position for the entity, move it there
981         if (VectorDistance2(trace.endpos, PRVM_serveredictvector(ent, origin)) >= 0.0001)
982         {
983 #if 0
984                 // please switch back to this code when trace.endpos sometimes being in solid bug is fixed
985                 VectorCopy(trace.endpos, PRVM_serveredictvector(ent, origin));
986 #else
987                 // verify if the endpos is REALLY outside solid
988                 VectorCopy(trace.endpos, org);
989                 trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), org, MOVE_NOMONSTERS, ent, contents);
990                 if(trace.startsolid)
991                         Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
992                 else
993                         VectorCopy(org, PRVM_serveredictvector(ent, origin));
994 #endif
995         }
996         return false;
997 }
998
999 /*
1000 ================
1001 SV_CheckAllEnts
1002 ================
1003 */
1004 void SV_CheckAllEnts (void)
1005 {
1006         int e;
1007         prvm_edict_t *check;
1008
1009         // see if any solid entities are inside the final position
1010         check = PRVM_NEXT_EDICT(prog->edicts);
1011         for (e = 1;e < prog->num_edicts;e++, check = PRVM_NEXT_EDICT(check))
1012         {
1013                 if (check->priv.server->free)
1014                         continue;
1015                 if (PRVM_serveredictfloat(check, movetype) == MOVETYPE_PUSH
1016                  || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NONE
1017                  || PRVM_serveredictfloat(check, movetype) == MOVETYPE_FOLLOW
1018                  || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NOCLIP
1019                  || PRVM_serveredictfloat(check, movetype) == MOVETYPE_FLY_WORLDONLY)
1020                         continue;
1021
1022                 if (SV_TestEntityPosition (check, vec3_origin))
1023                         Con_Print("entity in invalid position\n");
1024         }
1025 }
1026
1027 // DRESK - Support for Entity Contents Transition Event
1028 /*
1029 ================
1030 SV_CheckContentsTransition
1031
1032 returns true if entity had a valid contentstransition function call
1033 ================
1034 */
1035 int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
1036 {
1037         int bValidFunctionCall;
1038
1039         // Default Valid Function Call to False
1040         bValidFunctionCall = false;
1041
1042         if(PRVM_serveredictfloat(ent, watertype) != nContents)
1043         { // Changed Contents
1044                 // Acquire Contents Transition Function from QC
1045                 if(PRVM_serveredictfunction(ent, contentstransition))
1046                 { // Valid Function; Execute
1047                         // Assign Valid Function
1048                         bValidFunctionCall = true;
1049                         // Prepare Parameters (Original Contents, New Contents)
1050                                 // Original Contents
1051                                 PRVM_G_FLOAT(OFS_PARM0) = PRVM_serveredictfloat(ent, watertype);
1052                                 // New Contents
1053                                 PRVM_G_FLOAT(OFS_PARM1) = nContents;
1054                                 // Assign Self
1055                                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1056                         // Execute VM Function
1057                         PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
1058                 }
1059         }
1060
1061         // Return if Function Call was Valid
1062         return bValidFunctionCall;
1063 }
1064
1065
1066 /*
1067 ================
1068 SV_CheckVelocity
1069 ================
1070 */
1071 void SV_CheckVelocity (prvm_edict_t *ent)
1072 {
1073         int i;
1074         float wishspeed;
1075
1076 //
1077 // bound velocity
1078 //
1079         for (i=0 ; i<3 ; i++)
1080         {
1081                 if (IS_NAN(PRVM_serveredictvector(ent, velocity)[i]))
1082                 {
1083                         Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
1084                         PRVM_serveredictvector(ent, velocity)[i] = 0;
1085                 }
1086                 if (IS_NAN(PRVM_serveredictvector(ent, origin)[i]))
1087                 {
1088                         Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
1089                         PRVM_serveredictvector(ent, origin)[i] = 0;
1090                 }
1091         }
1092
1093         // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
1094         // player_run/player_stand1 does not horribly malfunction if the
1095         // velocity becomes a denormalized float
1096         if (VectorLength2(PRVM_serveredictvector(ent, velocity)) < 0.0001)
1097                 VectorClear(PRVM_serveredictvector(ent, velocity));
1098
1099         // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
1100         wishspeed = DotProduct(PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, velocity));
1101         if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
1102         {
1103                 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
1104                 PRVM_serveredictvector(ent, velocity)[0] *= wishspeed;
1105                 PRVM_serveredictvector(ent, velocity)[1] *= wishspeed;
1106                 PRVM_serveredictvector(ent, velocity)[2] *= wishspeed;
1107         }
1108 }
1109
1110 /*
1111 =============
1112 SV_RunThink
1113
1114 Runs thinking code if time.  There is some play in the exact time the think
1115 function will be called, because it is called before any movement is done
1116 in a frame.  Not used for pushmove objects, because they must be exact.
1117 Returns false if the entity removed itself.
1118 =============
1119 */
1120 qboolean SV_RunThink (prvm_edict_t *ent)
1121 {
1122         int iterations;
1123
1124         // don't let things stay in the past.
1125         // it is possible to start that way by a trigger with a local time.
1126         if (PRVM_serveredictfloat(ent, nextthink) <= 0 || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime)
1127                 return true;
1128
1129         for (iterations = 0;iterations < 128  && !ent->priv.server->free;iterations++)
1130         {
1131                 PRVM_serverglobalfloat(time) = max(sv.time, PRVM_serveredictfloat(ent, nextthink));
1132                 PRVM_serveredictfloat(ent, nextthink) = 0;
1133                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1134                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
1135                 PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1136                 // mods often set nextthink to time to cause a think every frame,
1137                 // we don't want to loop in that case, so exit if the new nextthink is
1138                 // <= the time the qc was told, also exit if it is past the end of the
1139                 // frame
1140                 if (PRVM_serveredictfloat(ent, nextthink) <= PRVM_serverglobalfloat(time) || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer)
1141                         break;
1142         }
1143         return !ent->priv.server->free;
1144 }
1145
1146 /*
1147 ==================
1148 SV_Impact
1149
1150 Two entities have touched, so run their touch functions
1151 ==================
1152 */
1153 extern void VM_SetTraceGlobals(const trace_t *trace);
1154 extern sizebuf_t vm_tempstringsbuf;
1155 void SV_Impact (prvm_edict_t *e1, trace_t *trace)
1156 {
1157         int restorevm_tempstringsbuf_cursize;
1158         int old_self, old_other;
1159         prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
1160
1161         old_self = PRVM_serverglobaledict(self);
1162         old_other = PRVM_serverglobaledict(other);
1163         restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
1164
1165         VM_SetTraceGlobals(trace);
1166
1167         PRVM_serverglobalfloat(time) = sv.time;
1168         if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e1, touch) && PRVM_serveredictfloat(e1, solid) != SOLID_NOT)
1169         {
1170                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e1);
1171                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e2);
1172                 PRVM_ExecuteProgram (PRVM_serveredictfunction(e1, touch), "QC function self.touch is missing");
1173         }
1174
1175         if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e2, touch) && PRVM_serveredictfloat(e2, solid) != SOLID_NOT)
1176         {
1177                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e2);
1178                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e1);
1179                 VectorCopy(PRVM_serveredictvector(e2, origin), PRVM_serverglobalvector(trace_endpos));
1180                 VectorNegate(trace->plane.normal, PRVM_serverglobalvector(trace_plane_normal));
1181                 PRVM_serverglobalfloat(trace_plane_dist) = -trace->plane.dist;
1182                 PRVM_serverglobaledict(trace_ent) = PRVM_EDICT_TO_PROG(e1);
1183                 PRVM_serverglobalfloat(trace_dpstartcontents) = 0;
1184                 PRVM_serverglobalfloat(trace_dphitcontents) = 0;
1185                 PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
1186                 PRVM_serverglobalstring(trace_dphittexturename) = 0;
1187                 PRVM_ExecuteProgram (PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
1188         }
1189
1190         PRVM_serverglobaledict(self) = old_self;
1191         PRVM_serverglobaledict(other) = old_other;
1192         vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
1193 }
1194
1195
1196 /*
1197 ==================
1198 ClipVelocity
1199
1200 Slide off of the impacting object
1201 returns the blocked flags (1 = floor, 2 = step / wall)
1202 ==================
1203 */
1204 #define STOP_EPSILON 0.1
1205 void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
1206 {
1207         int i;
1208         float backoff;
1209
1210         backoff = -DotProduct (in, normal) * overbounce;
1211         VectorMA(in, backoff, normal, out);
1212
1213         for (i = 0;i < 3;i++)
1214                 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
1215                         out[i] = 0;
1216 }
1217
1218
1219 /*
1220 ============
1221 SV_FlyMove
1222
1223 The basic solid body movement clip that slides along multiple planes
1224 Returns the clipflags if the velocity was modified (hit something solid)
1225 1 = floor
1226 2 = wall / step
1227 4 = dead stop
1228 8 = teleported by touch method
1229 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
1230 ============
1231 */
1232 static float SV_Gravity (prvm_edict_t *ent);
1233 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink);
1234 #define MAX_CLIP_PLANES 5
1235 static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask, float stepheight)
1236 {
1237         int blocked, bumpcount;
1238         int i, j, numplanes;
1239         float d, time_left, gravity;
1240         vec3_t dir, push, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
1241 #if 0
1242         vec3_t end;
1243 #endif
1244         trace_t trace;
1245         if (time <= 0)
1246                 return 0;
1247         gravity = 0;
1248
1249         if(sv_gameplayfix_nogravityonground.integer)
1250                 if((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
1251                         applygravity = false;
1252
1253         if (applygravity)
1254         {
1255                 if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
1256                 {
1257                         gravity = SV_Gravity(ent) * 0.5f;
1258                         PRVM_serveredictvector(ent, velocity)[2] -= gravity;
1259                 }
1260                 else
1261                 {
1262                         applygravity = false;
1263                         PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
1264                 }
1265         }
1266         blocked = 0;
1267         VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1268         VectorCopy(PRVM_serveredictvector(ent, velocity), primal_velocity);
1269         numplanes = 0;
1270         time_left = time;
1271         for (bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
1272         {
1273                 if (!PRVM_serveredictvector(ent, velocity)[0] && !PRVM_serveredictvector(ent, velocity)[1] && !PRVM_serveredictvector(ent, velocity)[2])
1274                         break;
1275
1276                 VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
1277                 if(!SV_PushEntity(&trace, ent, push, false, false))
1278                 {
1279                         // we got teleported by a touch function
1280                         // let's abort the move
1281                         blocked |= 8;
1282                         break;
1283                 }
1284
1285                 if (trace.fraction == 1)
1286                         break;
1287                 if (trace.plane.normal[2])
1288                 {
1289                         if (trace.plane.normal[2] > 0.7)
1290                         {
1291                                 // floor
1292                                 blocked |= 1;
1293
1294                                 if (!trace.ent)
1295                                 {
1296                                         Con_Printf ("SV_FlyMove: !trace.ent");
1297                                         trace.ent = prog->edicts;
1298                                 }
1299
1300                                 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
1301                                 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
1302                         }
1303                 }
1304                 else if (stepheight)
1305                 {
1306                         // step - handle it immediately
1307                         vec3_t org;
1308                         vec3_t steppush;
1309                         trace_t steptrace;
1310                         trace_t steptrace2;
1311                         trace_t steptrace3;
1312                         //Con_Printf("step %f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1313                         VectorSet(steppush, 0, 0, stepheight);
1314                         VectorCopy(PRVM_serveredictvector(ent, origin), org);
1315                         if(!SV_PushEntity(&steptrace, ent, steppush, false, false))
1316                         {
1317                                 blocked |= 8;
1318                                 break;
1319                         }
1320                         //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1321                         if(!SV_PushEntity(&steptrace2, ent, push, false, false))
1322                         {
1323                                 blocked |= 8;
1324                                 break;
1325                         }
1326                         //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1327                         VectorSet(steppush, 0, 0, org[2] - PRVM_serveredictvector(ent, origin)[2]);
1328                         if(!SV_PushEntity(&steptrace3, ent, steppush, false, false))
1329                         {
1330                                 blocked |= 8;
1331                                 break;
1332                         }
1333                         //Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
1334                         // accept the new position if it made some progress...
1335                         if (fabs(PRVM_serveredictvector(ent, origin)[0] - org[0]) >= 0.03125 || fabs(PRVM_serveredictvector(ent, origin)[1] - org[1]) >= 0.03125)
1336                         {
1337                                 //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]);
1338                                 trace = steptrace2;
1339                                 VectorCopy(PRVM_serveredictvector(ent, origin), trace.endpos);
1340                                 time_left *= 1 - trace.fraction;
1341                                 numplanes = 0;
1342                                 continue;
1343                         }
1344                         else
1345                         {
1346                                 //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]);
1347                                 VectorCopy(org, PRVM_serveredictvector(ent, origin));
1348                         }
1349                 }
1350                 else
1351                 {
1352                         // step - return it to caller
1353                         blocked |= 2;
1354                         // save the trace for player extrafriction
1355                         if (stepnormal)
1356                                 VectorCopy(trace.plane.normal, stepnormal);
1357                 }
1358                 if (trace.fraction >= 0.001)
1359                 {
1360                         // actually covered some distance
1361                         VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1362                         numplanes = 0;
1363                 }
1364
1365                 time_left *= 1 - trace.fraction;
1366
1367                 // clipped to another plane
1368                 if (numplanes >= MAX_CLIP_PLANES)
1369                 {
1370                         // this shouldn't really happen
1371                         VectorClear(PRVM_serveredictvector(ent, velocity));
1372                         blocked = 3;
1373                         break;
1374                 }
1375
1376                 /*
1377                 for (i = 0;i < numplanes;i++)
1378                         if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
1379                                 break;
1380                 if (i < numplanes)
1381                 {
1382                         VectorAdd(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity));
1383                         continue;
1384                 }
1385                 */
1386
1387                 VectorCopy(trace.plane.normal, planes[numplanes]);
1388                 numplanes++;
1389
1390                 // modify original_velocity so it parallels all of the clip planes
1391                 for (i = 0;i < numplanes;i++)
1392                 {
1393                         ClipVelocity(original_velocity, planes[i], new_velocity, 1);
1394                         for (j = 0;j < numplanes;j++)
1395                         {
1396                                 if (j != i)
1397                                 {
1398                                         // not ok
1399                                         if (DotProduct(new_velocity, planes[j]) < 0)
1400                                                 break;
1401                                 }
1402                         }
1403                         if (j == numplanes)
1404                                 break;
1405                 }
1406
1407                 if (i != numplanes)
1408                 {
1409                         // go along this plane
1410                         VectorCopy(new_velocity, PRVM_serveredictvector(ent, velocity));
1411                 }
1412                 else
1413                 {
1414                         // go along the crease
1415                         if (numplanes != 2)
1416                         {
1417                                 VectorClear(PRVM_serveredictvector(ent, velocity));
1418                                 blocked = 7;
1419                                 break;
1420                         }
1421                         CrossProduct(planes[0], planes[1], dir);
1422                         // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
1423                         VectorNormalize(dir);
1424                         d = DotProduct(dir, PRVM_serveredictvector(ent, velocity));
1425                         VectorScale(dir, d, PRVM_serveredictvector(ent, velocity));
1426                 }
1427
1428                 // if current velocity is against the original velocity,
1429                 // stop dead to avoid tiny occilations in sloping corners
1430                 if (DotProduct(PRVM_serveredictvector(ent, velocity), primal_velocity) <= 0)
1431                 {
1432                         VectorClear(PRVM_serveredictvector(ent, velocity));
1433                         break;
1434                 }
1435         }
1436
1437         //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]);
1438
1439         /*
1440         if ((blocked & 1) == 0 && bumpcount > 1)
1441         {
1442                 // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
1443                 // flag ONGROUND if there's ground under it
1444                 trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, hitsupercontentsmask);
1445         }
1446         */
1447
1448         // LordHavoc: this came from QW and allows you to get out of water more easily
1449         if (sv_gameplayfix_easierwaterjump.integer && ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) && !(blocked & 8))
1450                 VectorCopy(primal_velocity, PRVM_serveredictvector(ent, velocity));
1451         if (applygravity && !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
1452                 PRVM_serveredictvector(ent, velocity)[2] -= gravity;
1453         return blocked;
1454 }
1455
1456 /*
1457 ============
1458 SV_Gravity
1459
1460 ============
1461 */
1462 static float SV_Gravity (prvm_edict_t *ent)
1463 {
1464         float ent_gravity;
1465
1466         ent_gravity = PRVM_serveredictfloat(ent, gravity);
1467         if (!ent_gravity)
1468                 ent_gravity = 1.0f;
1469         return ent_gravity * sv_gravity.value * sv.frametime;
1470 }
1471
1472
1473 /*
1474 ===============================================================================
1475
1476 PUSHMOVE
1477
1478 ===============================================================================
1479 */
1480
1481 static qboolean SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot)
1482 {
1483         int bump;
1484         trace_t stucktrace;
1485         vec3_t stuckorigin;
1486         vec3_t stuckmins, stuckmaxs;
1487         vec3_t goodmins, goodmaxs;
1488         vec3_t testorigin;
1489         vec_t nudge;
1490         vec3_t move;
1491         VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1492         VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1493         VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1494         VectorCopy(pivot, goodmins);
1495         VectorCopy(pivot, goodmaxs);
1496         for (bump = 0;bump < 6;bump++)
1497         {
1498                 int coord = 2-(bump >> 1);
1499                 //int coord = (bump >> 1);
1500                 int dir = (bump & 1);
1501                 int subbump;
1502
1503                 for(subbump = 0; ; ++subbump)
1504                 {
1505                         VectorCopy(stuckorigin, testorigin);
1506                         if(dir)
1507                         {
1508                                 // pushing maxs
1509                                 testorigin[coord] += stuckmaxs[coord] - goodmaxs[coord];
1510                         }
1511                         else
1512                         {
1513                                 // pushing mins
1514                                 testorigin[coord] += stuckmins[coord] - goodmins[coord];
1515                         }
1516
1517                         stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1518                         if (stucktrace.bmodelstartsolid)
1519                         {
1520                                 // BAD BAD, can't fix that
1521                                 return false;
1522                         }
1523
1524                         if (stucktrace.fraction >= 1)
1525                                 break; // it WORKS!
1526
1527                         if(subbump >= 10)
1528                         {
1529                                 // BAD BAD, can't fix that
1530                                 return false;
1531                         }
1532
1533                         // we hit something... let's move out of it
1534                         VectorSubtract(stucktrace.endpos, testorigin, move);
1535                         nudge = DotProduct(stucktrace.plane.normal, move) + 0.03125f; // FIXME cvar this constant
1536                         VectorMA(stuckorigin, nudge, stucktrace.plane.normal, stuckorigin);
1537                 }
1538                 /*
1539                 if(subbump > 0)
1540                         Con_Printf("subbump: %d\n", subbump);
1541                 */
1542
1543                 if(dir)
1544                 {
1545                         // pushing maxs
1546                         goodmaxs[coord] = stuckmaxs[coord];
1547                 }
1548                 else
1549                 {
1550                         // pushing mins
1551                         goodmins[coord] = stuckmins[coord];
1552                 }
1553         }
1554
1555         // WE WIN
1556         VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1557
1558         return true;
1559 }
1560
1561 static qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent)
1562 {
1563         int bump;
1564         trace_t stucktrace;
1565         vec3_t stuckorigin;
1566         vec3_t stuckmins, stuckmaxs;
1567         vec_t nudge;
1568         vec_t separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
1569         if (sv.worldmodel && sv.worldmodel->brushq1.numclipnodes)
1570                 separation = 0.0f; // when using hulls, it can not be enlarged
1571         VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
1572         VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
1573         VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
1574         stuckmins[0] -= separation;
1575         stuckmins[1] -= separation;
1576         stuckmins[2] -= separation;
1577         stuckmaxs[0] += separation;
1578         stuckmaxs[1] += separation;
1579         stuckmaxs[2] += separation;
1580         for (bump = 0;bump < 10;bump++)
1581         {
1582                 stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
1583                 if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
1584                 {
1585                         // found a good location, use it
1586                         VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
1587                         return true;
1588                 }
1589                 nudge = -stucktrace.startdepth;
1590                 VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
1591         }
1592         return false;
1593 }
1594
1595 /*
1596 ============
1597 SV_PushEntity
1598
1599 Does not change the entities velocity at all
1600 The trace struct is filled with the trace that has been done.
1601 Returns true if the push did not result in the entity being teleported by QC code.
1602 ============
1603 */
1604 static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
1605 {
1606         int solid;
1607         int movetype;
1608         int type;
1609         vec3_t mins, maxs;
1610         vec3_t original, original_velocity;
1611         vec3_t start;
1612         vec3_t end;
1613
1614         solid = (int)PRVM_serveredictfloat(ent, solid);
1615         movetype = (int)PRVM_serveredictfloat(ent, movetype);
1616         VectorCopy(PRVM_serveredictvector(ent, mins), mins);
1617         VectorCopy(PRVM_serveredictvector(ent, maxs), maxs);
1618
1619         // move start position out of solids
1620         if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
1621         {
1622                 SV_NudgeOutOfSolid(ent);
1623         }
1624
1625         VectorCopy(PRVM_serveredictvector(ent, origin), start);
1626         VectorAdd(start, push, end);
1627
1628         if (movetype == MOVETYPE_FLYMISSILE)
1629                 type = MOVE_MISSILE;
1630         else if (movetype == MOVETYPE_FLY_WORLDONLY)
1631                 type = MOVE_WORLDONLY;
1632         else if (solid == SOLID_TRIGGER || solid == SOLID_NOT)
1633                 type = MOVE_NOMONSTERS; // only clip against bmodels
1634         else
1635                 type = MOVE_NORMAL;
1636
1637         *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
1638         if (trace->bmodelstartsolid && failonbmodelstartsolid)
1639                 return true;
1640
1641         VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
1642
1643         VectorCopy(PRVM_serveredictvector(ent, origin), original);
1644         VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
1645
1646         SV_LinkEdict(ent);
1647
1648 #if 0
1649         if(!trace->startsolid)
1650         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)
1651         {
1652                 Con_Printf("something eeeeevil happened\n");
1653         }
1654 #endif
1655
1656         if (dolink)
1657                 SV_LinkEdict_TouchAreaGrid(ent);
1658
1659         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))))
1660                 SV_Impact (ent, trace);
1661
1662         return VectorCompare(PRVM_serveredictvector(ent, origin), original) && VectorCompare(PRVM_serveredictvector(ent, velocity), original_velocity);
1663 }
1664
1665
1666 /*
1667 ============
1668 SV_PushMove
1669
1670 ============
1671 */
1672 void SV_PushMove (prvm_edict_t *pusher, float movetime)
1673 {
1674         int i, e, index;
1675         int pusherowner, pusherprog;
1676         int checkcontents;
1677         qboolean rotated;
1678         float savesolid, movetime2, pushltime;
1679         vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org;
1680         int num_moved;
1681         int numcheckentities;
1682         static prvm_edict_t *checkentities[MAX_EDICTS];
1683         dp_model_t *pushermodel;
1684         trace_t trace, trace2;
1685         matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
1686         static unsigned short moved_edicts[MAX_EDICTS];
1687         vec3_t pivot;
1688
1689         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])
1690         {
1691                 PRVM_serveredictfloat(pusher, ltime) += movetime;
1692                 return;
1693         }
1694
1695         switch ((int) PRVM_serveredictfloat(pusher, solid))
1696         {
1697         // LordHavoc: valid pusher types
1698         case SOLID_BSP:
1699         case SOLID_BBOX:
1700         case SOLID_SLIDEBOX:
1701         case SOLID_CORPSE: // LordHavoc: this would be weird...
1702                 break;
1703         // LordHavoc: no collisions
1704         case SOLID_NOT:
1705         case SOLID_TRIGGER:
1706                 VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1707                 VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1708                 PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1709                 PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1710                 PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1711                 PRVM_serveredictfloat(pusher, ltime) += movetime;
1712                 SV_LinkEdict(pusher);
1713                 return;
1714         default:
1715                 Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, solid));
1716                 return;
1717         }
1718         index = (int) PRVM_serveredictfloat(pusher, modelindex);
1719         if (index < 1 || index >= MAX_MODELS)
1720         {
1721                 Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), PRVM_serveredictfloat(pusher, modelindex));
1722                 return;
1723         }
1724         pushermodel = SV_GetModelByIndex(index);
1725         pusherowner = PRVM_serveredictedict(pusher, owner);
1726         pusherprog = PRVM_EDICT_TO_PROG(pusher);
1727
1728         rotated = VectorLength2(PRVM_serveredictvector(pusher, angles)) + VectorLength2(PRVM_serveredictvector(pusher, avelocity)) > 0;
1729
1730         movetime2 = movetime;
1731         VectorScale(PRVM_serveredictvector(pusher, velocity), movetime2, move1);
1732         VectorScale(PRVM_serveredictvector(pusher, avelocity), movetime2, moveangle);
1733         if (moveangle[0] || moveangle[2])
1734         {
1735                 for (i = 0;i < 3;i++)
1736                 {
1737                         if (move1[i] > 0)
1738                         {
1739                                 mins[i] = pushermodel->rotatedmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1740                                 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1741                         }
1742                         else
1743                         {
1744                                 mins[i] = pushermodel->rotatedmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1745                                 maxs[i] = pushermodel->rotatedmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1746                         }
1747                 }
1748         }
1749         else if (moveangle[1])
1750         {
1751                 for (i = 0;i < 3;i++)
1752                 {
1753                         if (move1[i] > 0)
1754                         {
1755                                 mins[i] = pushermodel->yawmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1756                                 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1757                         }
1758                         else
1759                         {
1760                                 mins[i] = pushermodel->yawmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1761                                 maxs[i] = pushermodel->yawmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1762                         }
1763                 }
1764         }
1765         else
1766         {
1767                 for (i = 0;i < 3;i++)
1768                 {
1769                         if (move1[i] > 0)
1770                         {
1771                                 mins[i] = pushermodel->normalmins[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1772                                 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1773                         }
1774                         else
1775                         {
1776                                 mins[i] = pushermodel->normalmins[i] + move1[i] + PRVM_serveredictvector(pusher, origin)[i] - 1;
1777                                 maxs[i] = pushermodel->normalmaxs[i] + PRVM_serveredictvector(pusher, origin)[i] + 1;
1778                         }
1779                 }
1780         }
1781
1782         VectorNegate (moveangle, a);
1783         AngleVectorsFLU (a, forward, left, up);
1784
1785         VectorCopy (PRVM_serveredictvector(pusher, origin), pushorig);
1786         VectorCopy (PRVM_serveredictvector(pusher, angles), pushang);
1787         pushltime = PRVM_serveredictfloat(pusher, ltime);
1788
1789 // move the pusher to its final position
1790
1791         VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
1792         VectorMA (PRVM_serveredictvector(pusher, angles), movetime, PRVM_serveredictvector(pusher, avelocity), PRVM_serveredictvector(pusher, angles));
1793         PRVM_serveredictfloat(pusher, ltime) += movetime;
1794         SV_LinkEdict(pusher);
1795
1796         pushermodel = SV_GetModelFromEdict(pusher);
1797         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);
1798         Matrix4x4_Invert_Simple(&pusherfinalimatrix, &pusherfinalmatrix);
1799
1800         savesolid = PRVM_serveredictfloat(pusher, solid);
1801
1802 // see if any solid entities are inside the final position
1803         num_moved = 0;
1804
1805         if (PRVM_serveredictfloat(pusher, movetype) == MOVETYPE_FAKEPUSH) // Tenebrae's MOVETYPE_PUSH variant that doesn't push...
1806                 numcheckentities = 0;
1807         else // MOVETYPE_PUSH
1808                 numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities);
1809         for (e = 0;e < numcheckentities;e++)
1810         {
1811                 prvm_edict_t *check = checkentities[e];
1812                 int movetype = (int)PRVM_serveredictfloat(check, movetype);
1813                 switch(movetype)
1814                 {
1815                 case MOVETYPE_NONE:
1816                 case MOVETYPE_PUSH:
1817                 case MOVETYPE_FOLLOW:
1818                 case MOVETYPE_NOCLIP:
1819                 case MOVETYPE_FLY_WORLDONLY:
1820                         continue;
1821                 default:
1822                         break;
1823                 }
1824
1825                 if (PRVM_serveredictedict(check, owner) == pusherprog)
1826                         continue;
1827
1828                 if (pusherowner == PRVM_EDICT_TO_PROG(check))
1829                         continue;
1830
1831                 //Con_Printf("%i %s ", PRVM_NUM_FOR_EDICT(check), PRVM_GetString(PRVM_serveredictstring(check, classname)));
1832
1833                 // tell any MOVETYPE_STEP entity that it may need to check for water transitions
1834                 check->priv.server->waterposition_forceupdate = true;
1835
1836                 checkcontents = SV_GenericHitSuperContentsMask(check);
1837
1838                 // if the entity is standing on the pusher, it will definitely be moved
1839                 // if the entity is not standing on the pusher, but is in the pusher's
1840                 // final position, move it
1841                 if (!((int)PRVM_serveredictfloat(check, flags) & FL_ONGROUND) || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher)
1842                 {
1843                         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);
1844                         //trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
1845                         if (!trace.startsolid)
1846                         {
1847                                 //Con_Printf("- not in solid\n");
1848                                 continue;
1849                         }
1850                 }
1851
1852                 VectorLerp(PRVM_serveredictvector(check, mins), 0.5f, PRVM_serveredictvector(check, maxs), pivot);
1853                 //VectorClear(pivot);
1854
1855                 if (rotated)
1856                 {
1857                         vec3_t org2;
1858                         VectorSubtract (PRVM_serveredictvector(check, origin), PRVM_serveredictvector(pusher, origin), org);
1859                         VectorAdd (org, pivot, org);
1860                         org2[0] = DotProduct (org, forward);
1861                         org2[1] = DotProduct (org, left);
1862                         org2[2] = DotProduct (org, up);
1863                         VectorSubtract (org2, org, move);
1864                         VectorAdd (move, move1, move);
1865                 }
1866                 else
1867                         VectorCopy (move1, move);
1868
1869                 //Con_Printf("- pushing %f %f %f\n", move[0], move[1], move[2]);
1870
1871                 VectorCopy (PRVM_serveredictvector(check, origin), check->priv.server->moved_from);
1872                 VectorCopy (PRVM_serveredictvector(check, angles), check->priv.server->moved_fromangles);
1873                 moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check);
1874
1875                 // physics objects need better collisions than this code can do
1876                 if (movetype == MOVETYPE_PHYSICS)
1877                 {
1878                         VectorAdd(PRVM_serveredictvector(check, origin), move, PRVM_serveredictvector(check, origin));
1879                         SV_LinkEdict(check);
1880                         SV_LinkEdict_TouchAreaGrid(check);
1881                         continue;
1882                 }
1883
1884                 // try moving the contacted entity
1885                 PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
1886                 if(!SV_PushEntity (&trace, check, move, true, true))
1887                 {
1888                         // entity "check" got teleported
1889                         PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1890                         PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1891                         continue; // pushed enough
1892                 }
1893                 // FIXME: turn players specially
1894                 PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
1895                 PRVM_serveredictfloat(pusher, solid) = savesolid; // was SOLID_BSP
1896                 //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
1897
1898                 // this trace.fraction < 1 check causes items to fall off of pushers
1899                 // if they pass under or through a wall
1900                 // the groundentity check causes items to fall off of ledges
1901                 if (PRVM_serveredictfloat(check, movetype) != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher))
1902                         PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND;
1903
1904                 // if it is still inside the pusher, block
1905                 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);
1906                 if (trace.startsolid)
1907                 {
1908                         vec3_t move2;
1909                         if(SV_NudgeOutOfSolid_PivotIsKnownGood(check, pivot))
1910                         {
1911                                 // hack to invoke all necessary movement triggers
1912                                 VectorClear(move2);
1913                                 if(!SV_PushEntity(&trace2, check, move2, true, true))
1914                                 {
1915                                         // entity "check" got teleported
1916                                         continue;
1917                                 }
1918                                 // we could fix it
1919                                 continue;
1920                         }
1921
1922                         // still inside pusher, so it's really blocked
1923
1924                         // fail the move
1925                         if (PRVM_serveredictvector(check, mins)[0] == PRVM_serveredictvector(check, maxs)[0])
1926                                 continue;
1927                         if (PRVM_serveredictfloat(check, solid) == SOLID_NOT || PRVM_serveredictfloat(check, solid) == SOLID_TRIGGER)
1928                         {
1929                                 // corpse
1930                                 PRVM_serveredictvector(check, mins)[0] = PRVM_serveredictvector(check, mins)[1] = 0;
1931                                 VectorCopy (PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs));
1932                                 continue;
1933                         }
1934
1935                         VectorCopy (pushorig, PRVM_serveredictvector(pusher, origin));
1936                         VectorCopy (pushang, PRVM_serveredictvector(pusher, angles));
1937                         PRVM_serveredictfloat(pusher, ltime) = pushltime;
1938                         SV_LinkEdict(pusher);
1939
1940                         // move back any entities we already moved
1941                         for (i = 0;i < num_moved;i++)
1942                         {
1943                                 prvm_edict_t *ed = PRVM_EDICT_NUM(moved_edicts[i]);
1944                                 VectorCopy (ed->priv.server->moved_from, PRVM_serveredictvector(ed, origin));
1945                                 VectorCopy (ed->priv.server->moved_fromangles, PRVM_serveredictvector(ed, angles));
1946                                 SV_LinkEdict(ed);
1947                         }
1948
1949                         // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
1950                         if (PRVM_serveredictfunction(pusher, blocked))
1951                         {
1952                                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(pusher);
1953                                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(check);
1954                                 PRVM_ExecuteProgram (PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
1955                         }
1956                         break;
1957                 }
1958         }
1959         PRVM_serveredictvector(pusher, angles)[0] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[0] * (1.0 / 360.0));
1960         PRVM_serveredictvector(pusher, angles)[1] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[1] * (1.0 / 360.0));
1961         PRVM_serveredictvector(pusher, angles)[2] -= 360.0 * floor(PRVM_serveredictvector(pusher, angles)[2] * (1.0 / 360.0));
1962 }
1963
1964 /*
1965 ================
1966 SV_Physics_Pusher
1967
1968 ================
1969 */
1970 void SV_Physics_Pusher (prvm_edict_t *ent)
1971 {
1972         float thinktime, oldltime, movetime;
1973
1974         oldltime = PRVM_serveredictfloat(ent, ltime);
1975
1976         thinktime = PRVM_serveredictfloat(ent, nextthink);
1977         if (thinktime < PRVM_serveredictfloat(ent, ltime) + sv.frametime)
1978         {
1979                 movetime = thinktime - PRVM_serveredictfloat(ent, ltime);
1980                 if (movetime < 0)
1981                         movetime = 0;
1982         }
1983         else
1984                 movetime = sv.frametime;
1985
1986         if (movetime)
1987                 // advances PRVM_serveredictfloat(ent, ltime) if not blocked
1988                 SV_PushMove (ent, movetime);
1989
1990         if (thinktime > oldltime && thinktime <= PRVM_serveredictfloat(ent, ltime))
1991         {
1992                 PRVM_serveredictfloat(ent, nextthink) = 0;
1993                 PRVM_serverglobalfloat(time) = sv.time;
1994                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
1995                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
1996                 PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
1997         }
1998 }
1999
2000
2001 /*
2002 ===============================================================================
2003
2004 CLIENT MOVEMENT
2005
2006 ===============================================================================
2007 */
2008
2009 static float unstickoffsets[] =
2010 {
2011         // poutting -/+z changes first as they are least weird
2012          0,  0,  -1,
2013          0,  0,  1,
2014          // x or y changes
2015         -1,  0,  0,
2016          1,  0,  0,
2017          0, -1,  0,
2018          0,  1,  0,
2019          // x and y changes
2020         -1, -1,  0,
2021          1, -1,  0,
2022         -1,  1,  0,
2023          1,  1,  0,
2024 };
2025
2026 typedef enum unstickresult_e
2027 {
2028         UNSTICK_STUCK = 0,
2029         UNSTICK_GOOD = 1,
2030         UNSTICK_UNSTUCK = 2
2031 }
2032 unstickresult_t;
2033
2034 unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
2035 {
2036         int i, maxunstick;
2037
2038         // if not stuck in a bmodel, just return
2039         if (!SV_TestEntityPosition(ent, vec3_origin))
2040                 return UNSTICK_GOOD;
2041
2042         for (i = 0;i < (int)(sizeof(unstickoffsets) / sizeof(unstickoffsets[0]));i += 3)
2043         {
2044                 if (!SV_TestEntityPosition(ent, unstickoffsets + i))
2045                 {
2046                         VectorCopy(unstickoffsets + i, offset);
2047                         SV_LinkEdict(ent);
2048                         //SV_LinkEdict_TouchAreaGrid(ent);
2049                         return UNSTICK_UNSTUCK;
2050                 }
2051         }
2052
2053         maxunstick = (int) ((PRVM_serveredictvector(ent, maxs)[2] - PRVM_serveredictvector(ent, mins)[2]) * 0.36);
2054         // magic number 0.36 allows unsticking by up to 17 units with the largest supported bbox
2055
2056         for(i = 2; i <= maxunstick; ++i)
2057         {
2058                 VectorClear(offset);
2059                 offset[2] = -i;
2060                 if (!SV_TestEntityPosition(ent, offset))
2061                 {
2062                         SV_LinkEdict(ent);
2063                         //SV_LinkEdict_TouchAreaGrid(ent);
2064                         return UNSTICK_UNSTUCK;
2065                 }
2066                 offset[2] = i;
2067                 if (!SV_TestEntityPosition(ent, offset))
2068                 {
2069                         SV_LinkEdict(ent);
2070                         //SV_LinkEdict_TouchAreaGrid(ent);
2071                         return UNSTICK_UNSTUCK;
2072                 }
2073         }
2074
2075         return UNSTICK_STUCK;
2076 }
2077
2078 qboolean SV_UnstickEntity (prvm_edict_t *ent)
2079 {
2080         vec3_t offset;
2081         switch(SV_UnstickEntityReturnOffset(ent, offset))
2082         {
2083                 case UNSTICK_GOOD:
2084                         return true;
2085                 case UNSTICK_UNSTUCK:
2086                         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]);
2087                         return true;
2088                 case UNSTICK_STUCK:
2089                         if (developer_extra.integer)
2090                                 Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2091                         return false;
2092                 default:
2093                         Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2094                         return false;
2095         }
2096 }
2097
2098 /*
2099 =============
2100 SV_CheckStuck
2101
2102 This is a big hack to try and fix the rare case of getting stuck in the world
2103 clipping hull.
2104 =============
2105 */
2106 void SV_CheckStuck (prvm_edict_t *ent)
2107 {
2108         vec3_t offset;
2109
2110         switch(SV_UnstickEntityReturnOffset(ent, offset))
2111         {
2112                 case UNSTICK_GOOD:
2113                         VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin));
2114                         break;
2115                 case UNSTICK_UNSTUCK:
2116                         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]);
2117                         break;
2118                 case UNSTICK_STUCK:
2119                         VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset);
2120                         if (!SV_TestEntityPosition(ent, offset))
2121                         {
2122                                 Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2123                                 SV_LinkEdict(ent);
2124                                 //SV_LinkEdict_TouchAreaGrid(ent);
2125                         }
2126                         else
2127                                 Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
2128                         break;
2129                 default:
2130                         Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
2131         }
2132 }
2133
2134
2135 /*
2136 =============
2137 SV_CheckWater
2138 =============
2139 */
2140 qboolean SV_CheckWater (prvm_edict_t *ent)
2141 {
2142         int cont;
2143         int nNativeContents;
2144         vec3_t point;
2145
2146         point[0] = PRVM_serveredictvector(ent, origin)[0];
2147         point[1] = PRVM_serveredictvector(ent, origin)[1];
2148         point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, mins)[2] + 1;
2149
2150         // DRESK - Support for Entity Contents Transition Event
2151         // NOTE: Some logic needed to be slightly re-ordered
2152         // to not affect performance and allow for the feature.
2153
2154         // Acquire Super Contents Prior to Resets
2155         cont = SV_PointSuperContents(point);
2156         // Acquire Native Contents Here
2157         nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
2158
2159         // DRESK - Support for Entity Contents Transition Event
2160         if(PRVM_serveredictfloat(ent, watertype))
2161                 // Entity did NOT Spawn; Check
2162                 SV_CheckContentsTransition(ent, nNativeContents);
2163
2164
2165         PRVM_serveredictfloat(ent, waterlevel) = 0;
2166         PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2167         cont = SV_PointSuperContents(point);
2168         if (cont & (SUPERCONTENTS_LIQUIDSMASK))
2169         {
2170                 PRVM_serveredictfloat(ent, watertype) = nNativeContents;
2171                 PRVM_serveredictfloat(ent, waterlevel) = 1;
2172                 point[2] = PRVM_serveredictvector(ent, origin)[2] + (PRVM_serveredictvector(ent, mins)[2] + PRVM_serveredictvector(ent, maxs)[2])*0.5;
2173                 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2174                 {
2175                         PRVM_serveredictfloat(ent, waterlevel) = 2;
2176                         point[2] = PRVM_serveredictvector(ent, origin)[2] + PRVM_serveredictvector(ent, view_ofs)[2];
2177                         if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
2178                                 PRVM_serveredictfloat(ent, waterlevel) = 3;
2179                 }
2180         }
2181
2182         return PRVM_serveredictfloat(ent, waterlevel) > 1;
2183 }
2184
2185 /*
2186 ============
2187 SV_WallFriction
2188
2189 ============
2190 */
2191 void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
2192 {
2193         float d, i;
2194         vec3_t forward, into, side;
2195
2196         AngleVectors (PRVM_serveredictvector(ent, v_angle), forward, NULL, NULL);
2197         if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
2198         {
2199                 // cut the tangential velocity
2200                 i = DotProduct (stepnormal, PRVM_serveredictvector(ent, velocity));
2201                 VectorScale (stepnormal, i, into);
2202                 VectorSubtract (PRVM_serveredictvector(ent, velocity), into, side);
2203                 PRVM_serveredictvector(ent, velocity)[0] = side[0] * (1 + d);
2204                 PRVM_serveredictvector(ent, velocity)[1] = side[1] * (1 + d);
2205         }
2206 }
2207
2208 #if 0
2209 /*
2210 =====================
2211 SV_TryUnstick
2212
2213 Player has come to a dead stop, possibly due to the problem with limited
2214 float precision at some angle joins in the BSP hull.
2215
2216 Try fixing by pushing one pixel in each direction.
2217
2218 This is a hack, but in the interest of good gameplay...
2219 ======================
2220 */
2221 int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
2222 {
2223         int i, clip;
2224         vec3_t oldorg, dir;
2225
2226         VectorCopy (PRVM_serveredictvector(ent, origin), oldorg);
2227         VectorClear (dir);
2228
2229         for (i=0 ; i<8 ; i++)
2230         {
2231                 // try pushing a little in an axial direction
2232                 switch (i)
2233                 {
2234                         case 0: dir[0] = 2; dir[1] = 0; break;
2235                         case 1: dir[0] = 0; dir[1] = 2; break;
2236                         case 2: dir[0] = -2; dir[1] = 0; break;
2237                         case 3: dir[0] = 0; dir[1] = -2; break;
2238                         case 4: dir[0] = 2; dir[1] = 2; break;
2239                         case 5: dir[0] = -2; dir[1] = 2; break;
2240                         case 6: dir[0] = 2; dir[1] = -2; break;
2241                         case 7: dir[0] = -2; dir[1] = -2; break;
2242                 }
2243
2244                 SV_PushEntity (&trace, ent, dir, false, true);
2245
2246                 // retry the original move
2247                 PRVM_serveredictvector(ent, velocity)[0] = oldvel[0];
2248                 PRVM_serveredictvector(ent, velocity)[1] = oldvel[1];
2249                 PRVM_serveredictvector(ent, velocity)[2] = 0;
2250                 clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent));
2251
2252                 if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4
2253                  || fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4)
2254                 {
2255                         Con_DPrint("TryUnstick - success.\n");
2256                         return clip;
2257                 }
2258
2259                 // go back to the original pos and try again
2260                 VectorCopy (oldorg, PRVM_serveredictvector(ent, origin));
2261         }
2262
2263         // still not moving
2264         VectorClear (PRVM_serveredictvector(ent, velocity));
2265         Con_DPrint("TryUnstick - failure.\n");
2266         return 7;
2267 }
2268 #endif
2269
2270 /*
2271 =====================
2272 SV_WalkMove
2273
2274 Only used by players
2275 ======================
2276 */
2277 void SV_WalkMove (prvm_edict_t *ent)
2278 {
2279         int clip;
2280         int oldonground;
2281         //int originalmove_clip;
2282         int originalmove_flags;
2283         int originalmove_groundentity;
2284         int hitsupercontentsmask;
2285         int type;
2286         vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
2287         trace_t downtrace, trace;
2288         qboolean applygravity;
2289
2290         // if frametime is 0 (due to client sending the same timestamp twice),
2291         // don't move
2292         if (sv.frametime <= 0)
2293                 return;
2294
2295         if (sv_gameplayfix_unstickplayers.integer)
2296                 SV_CheckStuck (ent);
2297
2298         applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
2299
2300         hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
2301
2302         SV_CheckVelocity(ent);
2303
2304         // do a regular slide move unless it looks like you ran into a step
2305         oldonground = (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND;
2306
2307         VectorCopy (PRVM_serveredictvector(ent, origin), start_origin);
2308         VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity);
2309
2310         clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
2311
2312         if(sv_gameplayfix_downtracesupportsongroundflag.integer)
2313         if(!(clip & 1))
2314         {
2315                 // only try this if there was no floor in the way in the trace (no,
2316                 // this check seems to be not REALLY necessary, because if clip & 1,
2317                 // our trace will hit that thing too)
2318                 VectorSet(upmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] + 1);
2319                 VectorSet(downmove, PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2] - 1);
2320                 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLYMISSILE)
2321                         type = MOVE_MISSILE;
2322                 else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY)
2323                         type = MOVE_WORLDONLY;
2324                 else if (PRVM_serveredictfloat(ent, solid) == SOLID_TRIGGER || PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
2325                         type = MOVE_NOMONSTERS; // only clip against bmodels
2326                 else
2327                         type = MOVE_NORMAL;
2328                 trace = SV_TraceBox(upmove, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
2329                 if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
2330                         clip |= 1; // but we HAVE found a floor
2331         }
2332
2333         // if the move did not hit the ground at any point, we're not on ground
2334         if(!(clip & 1))
2335                 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2336
2337         SV_CheckVelocity(ent);
2338         SV_LinkEdict(ent);
2339         SV_LinkEdict_TouchAreaGrid(ent);
2340
2341         if(clip & 8) // teleport
2342                 return;
2343
2344         if ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP)
2345                 return;
2346
2347         if (sv_nostep.integer)
2348                 return;
2349
2350         VectorCopy(PRVM_serveredictvector(ent, origin), originalmove_origin);
2351         VectorCopy(PRVM_serveredictvector(ent, velocity), originalmove_velocity);
2352         //originalmove_clip = clip;
2353         originalmove_flags = (int)PRVM_serveredictfloat(ent, flags);
2354         originalmove_groundentity = PRVM_serveredictedict(ent, groundentity);
2355
2356         // if move didn't block on a step, return
2357         if (clip & 2)
2358         {
2359                 // if move was not trying to move into the step, return
2360                 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
2361                         return;
2362
2363                 if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY)
2364                 {
2365                         // return if gibbed by a trigger
2366                         if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_WALK)
2367                                 return;
2368
2369                         // only step up while jumping if that is enabled
2370                         if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
2371                                 if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0)
2372                                         return;
2373                 }
2374
2375                 // try moving up and forward to go up a step
2376                 // back to start pos
2377                 VectorCopy (start_origin, PRVM_serveredictvector(ent, origin));
2378                 VectorCopy (start_velocity, PRVM_serveredictvector(ent, velocity));
2379
2380                 // move up
2381                 VectorClear (upmove);
2382                 upmove[2] = sv_stepheight.value;
2383                 if(!SV_PushEntity(&trace, ent, upmove, false, true))
2384                 {
2385                         // we got teleported when upstepping... must abort the move
2386                         return;
2387                 }
2388
2389                 // move forward
2390                 PRVM_serveredictvector(ent, velocity)[2] = 0;
2391                 clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, 0);
2392                 PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2];
2393                 if(clip & 8)
2394                 {
2395                         // we got teleported when upstepping... must abort the move
2396                         // note that z velocity handling may not be what QC expects here, but we cannot help it
2397                         return;
2398                 }
2399
2400                 SV_CheckVelocity(ent);
2401                 SV_LinkEdict(ent);
2402                 SV_LinkEdict_TouchAreaGrid(ent);
2403
2404                 // check for stuckness, possibly due to the limited precision of floats
2405                 // in the clipping hulls
2406                 if (clip
2407                  && fabs(originalmove_origin[1] - PRVM_serveredictvector(ent, origin)[1]) < 0.03125
2408                  && fabs(originalmove_origin[0] - PRVM_serveredictvector(ent, origin)[0]) < 0.03125)
2409                 {
2410                         //Con_Printf("wall\n");
2411                         // stepping up didn't make any progress, revert to original move
2412                         VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2413                         VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2414                         //clip = originalmove_clip;
2415                         PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2416                         PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2417                         // now try to unstick if needed
2418                         //clip = SV_TryUnstick (ent, oldvel);
2419                         return;
2420                 }
2421
2422                 //Con_Printf("step - ");
2423
2424                 // extra friction based on view angle
2425                 if (clip & 2 && sv_wallfriction.integer)
2426                         SV_WallFriction (ent, stepnormal);
2427         }
2428         // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
2429         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))
2430                 return;
2431
2432         // move down
2433         VectorClear (downmove);
2434         downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
2435         if(!SV_PushEntity (&downtrace, ent, downmove, false, true))
2436         {
2437                 // we got teleported when downstepping... must abort the move
2438                 return;
2439         }
2440
2441         if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
2442         {
2443                 // this has been disabled so that you can't jump when you are stepping
2444                 // up while already jumping (also known as the Quake2 double jump bug)
2445 #if 0
2446                 // LordHavoc: disabled this check so you can walk on monsters/players
2447                 //if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
2448                 {
2449                         //Con_Printf("onground\n");
2450                         PRVM_serveredictfloat(ent, flags) =     (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2451                         PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(downtrace.ent);
2452                 }
2453 #endif
2454         }
2455         else
2456         {
2457                 //Con_Printf("slope\n");
2458                 // if the push down didn't end up on good ground, use the move without
2459                 // the step up.  This happens near wall / slope combinations, and can
2460                 // cause the player to hop up higher on a slope too steep to climb
2461                 VectorCopy(originalmove_origin, PRVM_serveredictvector(ent, origin));
2462                 VectorCopy(originalmove_velocity, PRVM_serveredictvector(ent, velocity));
2463                 //clip = originalmove_clip;
2464                 PRVM_serveredictfloat(ent, flags) = originalmove_flags;
2465                 PRVM_serveredictedict(ent, groundentity) = originalmove_groundentity;
2466         }
2467
2468         SV_CheckVelocity(ent);
2469         SV_LinkEdict(ent);
2470         SV_LinkEdict_TouchAreaGrid(ent);
2471 }
2472
2473 //============================================================================
2474
2475 /*
2476 =============
2477 SV_Physics_Follow
2478
2479 Entities that are "stuck" to another entity
2480 =============
2481 */
2482 void SV_Physics_Follow (prvm_edict_t *ent)
2483 {
2484         vec3_t vf, vr, vu, angles, v;
2485         prvm_edict_t *e;
2486
2487         // regular thinking
2488         if (!SV_RunThink (ent))
2489                 return;
2490
2491         // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
2492         e = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, aiment));
2493         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])
2494         {
2495                 // quick case for no rotation
2496                 VectorAdd(PRVM_serveredictvector(e, origin), PRVM_serveredictvector(ent, view_ofs), PRVM_serveredictvector(ent, origin));
2497         }
2498         else
2499         {
2500                 angles[0] = -PRVM_serveredictvector(ent, punchangle)[0];
2501                 angles[1] =  PRVM_serveredictvector(ent, punchangle)[1];
2502                 angles[2] =  PRVM_serveredictvector(ent, punchangle)[2];
2503                 AngleVectors (angles, vf, vr, vu);
2504                 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];
2505                 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];
2506                 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];
2507                 angles[0] = -PRVM_serveredictvector(e, angles)[0];
2508                 angles[1] =  PRVM_serveredictvector(e, angles)[1];
2509                 angles[2] =  PRVM_serveredictvector(e, angles)[2];
2510                 AngleVectors (angles, vf, vr, vu);
2511                 PRVM_serveredictvector(ent, origin)[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + PRVM_serveredictvector(e, origin)[0];
2512                 PRVM_serveredictvector(ent, origin)[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + PRVM_serveredictvector(e, origin)[1];
2513                 PRVM_serveredictvector(ent, origin)[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + PRVM_serveredictvector(e, origin)[2];
2514         }
2515         VectorAdd (PRVM_serveredictvector(e, angles), PRVM_serveredictvector(ent, v_angle), PRVM_serveredictvector(ent, angles));
2516         SV_LinkEdict(ent);
2517         //SV_LinkEdict_TouchAreaGrid(ent);
2518 }
2519
2520 /*
2521 ==============================================================================
2522
2523 TOSS / BOUNCE
2524
2525 ==============================================================================
2526 */
2527
2528 /*
2529 =============
2530 SV_CheckWaterTransition
2531
2532 =============
2533 */
2534 void SV_CheckWaterTransition (prvm_edict_t *ent)
2535 {
2536         // LordHavoc: bugfixes in this function are keyed to the sv_gameplayfix_bugfixedcheckwatertransition cvar - if this cvar is 0 then all the original bugs should be reenabled for compatibility
2537         int cont;
2538         cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_serveredictvector(ent, origin)));
2539         if (!PRVM_serveredictfloat(ent, watertype))
2540         {
2541                 // just spawned here
2542                 if (!sv_gameplayfix_fixedcheckwatertransition.integer)
2543                 {
2544                         PRVM_serveredictfloat(ent, watertype) = cont;
2545                         PRVM_serveredictfloat(ent, waterlevel) = 1;
2546                         return;
2547                 }
2548         }
2549         // DRESK - Support for Entity Contents Transition Event
2550         // NOTE: Call here BEFORE updating the watertype below,
2551         // and suppress watersplash sound if a valid function
2552         // call was made to allow for custom "splash" sounds.
2553         else if( !SV_CheckContentsTransition(ent, cont) )
2554         { // Contents Transition Function Invalid; Potentially Play Water Sound
2555                 // check if the entity crossed into or out of water
2556                 if (sv_sound_watersplash.string && ((PRVM_serveredictfloat(ent, watertype) == CONTENTS_WATER || PRVM_serveredictfloat(ent, watertype) == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)))
2557                         SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1, false, 1.0f);
2558         }
2559
2560         if (cont <= CONTENTS_WATER)
2561         {
2562                 PRVM_serveredictfloat(ent, watertype) = cont;
2563                 PRVM_serveredictfloat(ent, waterlevel) = 1;
2564         }
2565         else
2566         {
2567                 PRVM_serveredictfloat(ent, watertype) = CONTENTS_EMPTY;
2568                 PRVM_serveredictfloat(ent, waterlevel) = sv_gameplayfix_fixedcheckwatertransition.integer ? 0 : cont;
2569         }
2570 }
2571
2572 /*
2573 =============
2574 SV_Physics_Toss
2575
2576 Toss, bounce, and fly movement.  When onground, do nothing.
2577 =============
2578 */
2579
2580 void SV_Physics_Toss (prvm_edict_t *ent)
2581 {
2582         trace_t trace;
2583         vec3_t move;
2584         vec_t movetime;
2585         int bump;
2586         prvm_edict_t *groundentity;
2587
2588 // if onground, return without moving
2589         if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2590         {
2591                 groundentity = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, groundentity));
2592                 if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2593                 {
2594                         // don't stick to ground if onground and moving upward
2595                         PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2596                 }
2597                 else if (!PRVM_serveredictedict(ent, groundentity) || !sv_gameplayfix_noairborncorpse.integer)
2598                 {
2599                         // we can trust FL_ONGROUND if groundentity is world because it never moves
2600                         return;
2601                 }
2602                 else if (ent->priv.server->suspendedinairflag && groundentity->priv.server->free)
2603                 {
2604                         // if ent was supported by a brush model on previous frame,
2605                         // and groundentity is now freed, set groundentity to 0 (world)
2606                         // which leaves it suspended in the air
2607                         PRVM_serveredictedict(ent, groundentity) = 0;
2608                         if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer)
2609                                 return;
2610                 }
2611                 else if (BoxesOverlap(ent->priv.server->cullmins, ent->priv.server->cullmaxs, groundentity->priv.server->cullmins, groundentity->priv.server->cullmaxs))
2612                 {
2613                         // don't slide if still touching the groundentity
2614                         return;
2615                 }
2616         }
2617         ent->priv.server->suspendedinairflag = false;
2618
2619         SV_CheckVelocity (ent);
2620
2621 // add gravity
2622         if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_TOSS || PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2623                 PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
2624
2625 // move angles
2626         VectorMA (PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2627
2628         movetime = sv.frametime;
2629         for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
2630         {
2631         // move origin
2632                 VectorScale (PRVM_serveredictvector(ent, velocity), movetime, move);
2633                 if(!SV_PushEntity (&trace, ent, move, true, true))
2634                         return; // teleported
2635                 if (ent->priv.server->free)
2636                         return;
2637                 if (trace.bmodelstartsolid)
2638                 {
2639                         // try to unstick the entity
2640                         if (sv_gameplayfix_unstickentities.integer)
2641                                 SV_UnstickEntity(ent);
2642                         if(!SV_PushEntity (&trace, ent, move, false, true))
2643                                 return; // teleported
2644                         if (ent->priv.server->free)
2645                                 return;
2646                 }
2647                 if (trace.fraction == 1)
2648                         break;
2649                 movetime *= 1 - min(1, trace.fraction);
2650                 if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE)
2651                 {
2652                         float bouncefactor;
2653                         bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2654                         if (!bouncefactor)
2655                                 bouncefactor = 1.0f;
2656
2657                         ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2658                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2659                 }
2660                 else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
2661                 {
2662                         float d, ent_gravity;
2663                         float bouncefactor;
2664                         float bouncestop;
2665
2666                         bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
2667                         if (!bouncefactor)
2668                                 bouncefactor = 0.5f;
2669
2670                         bouncestop = PRVM_serveredictfloat(ent, bouncestop);
2671                         if (!bouncestop)
2672                                 bouncestop = 60.0f / 800.0f;
2673
2674                         ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
2675                         ent_gravity = PRVM_serveredictfloat(ent, gravity);
2676                         if (!ent_gravity)
2677                                 ent_gravity = 1.0f;
2678                         // LordHavoc: fixed grenades not bouncing when fired down a slope
2679                         if (sv_gameplayfix_grenadebouncedownslopes.integer)
2680                         {
2681                                 d = DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity));
2682                                 if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * bouncestop * ent_gravity)
2683                                 {
2684                                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2685                                         PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2686                                         VectorClear (PRVM_serveredictvector(ent, velocity));
2687                                         VectorClear (PRVM_serveredictvector(ent, avelocity));
2688                                 }
2689                                 else
2690                                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2691                         }
2692                         else
2693                         {
2694                                 if (trace.plane.normal[2] > 0.7 && PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * bouncestop * ent_gravity)
2695                                 {
2696                                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2697                                         PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2698                                         VectorClear (PRVM_serveredictvector(ent, velocity));
2699                                         VectorClear (PRVM_serveredictvector(ent, avelocity));
2700                                 }
2701                                 else
2702                                         PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2703                         }
2704                 }
2705                 else
2706                 {
2707                         ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0);
2708                         if (trace.plane.normal[2] > 0.7)
2709                         {
2710                                 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
2711                                 PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
2712                                 if (PRVM_serveredictfloat(((prvm_edict_t *)trace.ent), solid) == SOLID_BSP)
2713                                         ent->priv.server->suspendedinairflag = true;
2714                                 VectorClear (PRVM_serveredictvector(ent, velocity));
2715                                 VectorClear (PRVM_serveredictvector(ent, avelocity));
2716                         }
2717                         else
2718                                 PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
2719                 }
2720                 if (!sv_gameplayfix_slidemoveprojectiles.integer || (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_BOUNCE && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE) || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
2721                         break;
2722         }
2723
2724 // check for in water
2725         SV_CheckWaterTransition (ent);
2726 }
2727
2728 /*
2729 ===============================================================================
2730
2731 STEPPING MOVEMENT
2732
2733 ===============================================================================
2734 */
2735
2736 /*
2737 =============
2738 SV_Physics_Step
2739
2740 Monsters freefall when they don't have a ground entity, otherwise
2741 all movement is done with discrete steps.
2742
2743 This is also used for objects that have become still on the ground, but
2744 will fall if the floor is pulled out from under them.
2745 =============
2746 */
2747 void SV_Physics_Step (prvm_edict_t *ent)
2748 {
2749         int flags = (int)PRVM_serveredictfloat(ent, flags);
2750
2751         // DRESK
2752         // Backup Velocity in the event that movetypesteplandevent is called,
2753         // to provide a parameter with the entity's velocity at impact.
2754         vec3_t backupVelocity;
2755         VectorCopy(PRVM_serveredictvector(ent, velocity), backupVelocity);
2756         // don't fall at all if fly/swim
2757         if (!(flags & (FL_FLY | FL_SWIM)))
2758         {
2759                 if (flags & FL_ONGROUND)
2760                 {
2761                         // freefall if onground and moving upward
2762                         // freefall if not standing on a world surface (it may be a lift or trap door)
2763                         if (PRVM_serveredictvector(ent, velocity)[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
2764                         {
2765                                 PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
2766                                 SV_CheckVelocity(ent);
2767                                 SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2768                                 SV_LinkEdict(ent);
2769                                 SV_LinkEdict_TouchAreaGrid(ent);
2770                                 ent->priv.server->waterposition_forceupdate = true;
2771                         }
2772                 }
2773                 else
2774                 {
2775                         // freefall if not onground
2776                         int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1;
2777
2778                         SV_CheckVelocity(ent);
2779                         SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
2780                         SV_LinkEdict(ent);
2781                         SV_LinkEdict_TouchAreaGrid(ent);
2782
2783                         // just hit ground
2784                         if (hitsound && (int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
2785                         {
2786                                 // DRESK - Check for Entity Land Event Function
2787                                 if(PRVM_serveredictfunction(ent, movetypesteplandevent))
2788                                 { // Valid Function; Execute
2789                                         // Prepare Parameters
2790                                                 // Assign Velocity at Impact
2791                                                 PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0];
2792                                                 PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
2793                                                 PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
2794                                                 // Assign Self
2795                                                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2796                                         // Execute VM Function
2797                                         PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function");
2798                                 }
2799                                 else
2800                                 // Check for Engine Landing Sound
2801                                 if(sv_sound_land.string)
2802                                         SV_StartSound(ent, 0, sv_sound_land.string, 255, 1, false, 1.0f);
2803                         }
2804                         ent->priv.server->waterposition_forceupdate = true;
2805                 }
2806         }
2807
2808 // regular thinking
2809         if (!SV_RunThink(ent))
2810                 return;
2811
2812         if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
2813         {
2814                 ent->priv.server->waterposition_forceupdate = false;
2815                 VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
2816                 SV_CheckWaterTransition(ent);
2817         }
2818 }
2819
2820 //============================================================================
2821
2822 static void SV_Physics_Entity (prvm_edict_t *ent)
2823 {
2824         // don't run think/move on newly spawned projectiles as it messes up
2825         // movement interpolation and rocket trails, and is inconsistent with
2826         // respect to entities spawned in the same frame
2827         // (if an ent spawns a higher numbered ent, it moves in the same frame,
2828         //  but if it spawns a lower numbered ent, it doesn't - this never moves
2829         //  ents in the first frame regardless)
2830         qboolean runmove = ent->priv.server->move;
2831         ent->priv.server->move = true;
2832         if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
2833                 return;
2834         switch ((int) PRVM_serveredictfloat(ent, movetype))
2835         {
2836         case MOVETYPE_PUSH:
2837         case MOVETYPE_FAKEPUSH:
2838                 SV_Physics_Pusher (ent);
2839                 break;
2840         case MOVETYPE_NONE:
2841                 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
2842                 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
2843                         SV_RunThink (ent);
2844                 break;
2845         case MOVETYPE_FOLLOW:
2846                 SV_Physics_Follow (ent);
2847                 break;
2848         case MOVETYPE_NOCLIP:
2849                 if (SV_RunThink(ent))
2850                 {
2851                         SV_CheckWater(ent);
2852                         VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
2853                         VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
2854                 }
2855                 SV_LinkEdict(ent);
2856                 break;
2857         case MOVETYPE_STEP:
2858                 SV_Physics_Step (ent);
2859                 break;
2860         case MOVETYPE_WALK:
2861                 if (SV_RunThink (ent))
2862                         SV_WalkMove (ent);
2863                 break;
2864         case MOVETYPE_TOSS:
2865         case MOVETYPE_BOUNCE:
2866         case MOVETYPE_BOUNCEMISSILE:
2867         case MOVETYPE_FLYMISSILE:
2868         case MOVETYPE_FLY:
2869         case MOVETYPE_FLY_WORLDONLY:
2870                 // regular thinking
2871                 if (SV_RunThink (ent))
2872                         SV_Physics_Toss (ent);
2873                 break;
2874         case MOVETYPE_PHYSICS:
2875                 if (SV_RunThink(ent))
2876                 {
2877                         SV_LinkEdict(ent);
2878                         SV_LinkEdict_TouchAreaGrid(ent);
2879                 }
2880                 break;
2881         default:
2882                 Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
2883                 break;
2884         }
2885 }
2886
2887 void SV_Physics_ClientMove(void)
2888 {
2889         prvm_edict_t *ent;
2890         ent = host_client->edict;
2891
2892         // call player physics, this needs the proper frametime
2893         PRVM_serverglobalfloat(frametime) = sv.frametime;
2894         SV_ClientThink();
2895
2896         // call standard client pre-think, with frametime = 0
2897         PRVM_serverglobalfloat(time) = sv.time;
2898         PRVM_serverglobalfloat(frametime) = 0;
2899         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2900         PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2901         PRVM_serverglobalfloat(frametime) = sv.frametime;
2902
2903         // make sure the velocity is sane (not a NaN)
2904         SV_CheckVelocity(ent);
2905
2906         // perform MOVETYPE_WALK behavior
2907         SV_WalkMove (ent);
2908
2909         // call standard player post-think, with frametime = 0
2910         PRVM_serverglobalfloat(time) = sv.time;
2911         PRVM_serverglobalfloat(frametime) = 0;
2912         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2913         PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2914         PRVM_serverglobalfloat(frametime) = sv.frametime;
2915
2916         if(PRVM_serveredictfloat(ent, fixangle))
2917         {
2918                 // angle fixing was requested by physics code...
2919                 // so store the current angles for later use
2920                 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2921                 host_client->fixangle_angles_set = TRUE;
2922
2923                 // and clear fixangle for the next frame
2924                 PRVM_serveredictfloat(ent, fixangle) = 0;
2925         }
2926 }
2927
2928 static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
2929 {
2930         // don't do physics on disconnected clients, FrikBot relies on this
2931         if (!host_client->spawned)
2932                 return;
2933
2934         // make sure the velocity is sane (not a NaN)
2935         SV_CheckVelocity(ent);
2936
2937         // don't run physics here if running asynchronously
2938         if (host_client->clmovement_inputtimeout <= 0)
2939         {
2940                 SV_ClientThink();
2941                 //host_client->cmd.time = max(host_client->cmd.time, sv.time);
2942         }
2943
2944         // make sure the velocity is still sane (not a NaN)
2945         SV_CheckVelocity(ent);
2946
2947         // call standard client pre-think
2948         PRVM_serverglobalfloat(time) = sv.time;
2949         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2950         PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
2951
2952         // make sure the velocity is still sane (not a NaN)
2953         SV_CheckVelocity(ent);
2954 }
2955
2956 static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
2957 {
2958         // don't do physics on disconnected clients, FrikBot relies on this
2959         if (!host_client->spawned)
2960                 return;
2961
2962         // make sure the velocity is sane (not a NaN)
2963         SV_CheckVelocity(ent);
2964
2965         // call standard player post-think
2966         PRVM_serverglobalfloat(time) = sv.time;
2967         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
2968         PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
2969
2970         // make sure the velocity is still sane (not a NaN)
2971         SV_CheckVelocity(ent);
2972
2973         if(PRVM_serveredictfloat(ent, fixangle))
2974         {
2975                 // angle fixing was requested by physics code...
2976                 // so store the current angles for later use
2977                 memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
2978                 host_client->fixangle_angles_set = TRUE;
2979
2980                 // and clear fixangle for the next frame
2981                 PRVM_serveredictfloat(ent, fixangle) = 0;
2982         }
2983
2984         // decrement the countdown variable used to decide when to go back to
2985         // synchronous physics
2986         if (host_client->clmovement_inputtimeout > sv.frametime)
2987                 host_client->clmovement_inputtimeout -= sv.frametime;
2988         else
2989                 host_client->clmovement_inputtimeout = 0;
2990 }
2991
2992 static void SV_Physics_ClientEntity(prvm_edict_t *ent)
2993 {
2994         // don't do physics on disconnected clients, FrikBot relies on this
2995         if (!host_client->spawned)
2996         {
2997                 memset(&host_client->cmd, 0, sizeof(host_client->cmd));
2998                 return;
2999         }
3000
3001         // make sure the velocity is sane (not a NaN)
3002         SV_CheckVelocity(ent);
3003
3004         switch ((int) PRVM_serveredictfloat(ent, movetype))
3005         {
3006         case MOVETYPE_PUSH:
3007         case MOVETYPE_FAKEPUSH:
3008                 SV_Physics_Pusher (ent);
3009                 break;
3010         case MOVETYPE_NONE:
3011                 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
3012                 if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
3013                         SV_RunThink (ent);
3014                 break;
3015         case MOVETYPE_FOLLOW:
3016                 SV_Physics_Follow (ent);
3017                 break;
3018         case MOVETYPE_NOCLIP:
3019                 SV_RunThink(ent);
3020                 SV_CheckWater(ent);
3021                 VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
3022                 VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
3023                 break;
3024         case MOVETYPE_STEP:
3025                 SV_Physics_Step (ent);
3026                 break;
3027         case MOVETYPE_WALK:
3028                 SV_RunThink (ent);
3029                 // don't run physics here if running asynchronously
3030                 if (host_client->clmovement_inputtimeout <= 0)
3031                         SV_WalkMove (ent);
3032                 break;
3033         case MOVETYPE_TOSS:
3034         case MOVETYPE_BOUNCE:
3035         case MOVETYPE_BOUNCEMISSILE:
3036         case MOVETYPE_FLYMISSILE:
3037                 // regular thinking
3038                 SV_RunThink (ent);
3039                 SV_Physics_Toss (ent);
3040                 break;
3041         case MOVETYPE_FLY:
3042         case MOVETYPE_FLY_WORLDONLY:
3043                 SV_RunThink (ent);
3044                 SV_WalkMove (ent);
3045                 break;
3046         case MOVETYPE_PHYSICS:
3047                 SV_RunThink (ent);
3048                 break;
3049         default:
3050                 Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
3051                 break;
3052         }
3053
3054         SV_CheckVelocity (ent);
3055
3056         SV_LinkEdict(ent);
3057         SV_LinkEdict_TouchAreaGrid(ent);
3058
3059         SV_CheckVelocity (ent);
3060 }
3061
3062 /*
3063 ================
3064 SV_Physics
3065
3066 ================
3067 */
3068 void SV_Physics (void)
3069 {
3070         int i;
3071         prvm_edict_t *ent;
3072
3073 // let the progs know that a new frame has started
3074         PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3075         PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3076         PRVM_serverglobalfloat(time) = sv.time;
3077         PRVM_serverglobalfloat(frametime) = sv.frametime;
3078         PRVM_ExecuteProgram (PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
3079
3080         // run physics engine
3081         World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value);
3082
3083 //
3084 // treat each object in turn
3085 //
3086
3087         // if force_retouch, relink all the entities
3088         if (PRVM_serverglobalfloat(force_retouch) > 0)
3089                 for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3090                         if (!ent->priv.server->free)
3091                                 SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
3092
3093         if (sv_gameplayfix_consistentplayerprethink.integer)
3094         {
3095                 // run physics on the client entities in 3 stages
3096                 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3097                         if (!ent->priv.server->free)
3098                                 SV_Physics_ClientEntity_PreThink(ent);
3099
3100                 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3101                         if (!ent->priv.server->free)
3102                                 SV_Physics_ClientEntity(ent);
3103
3104                 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3105                         if (!ent->priv.server->free)
3106                                 SV_Physics_ClientEntity_PostThink(ent);
3107         }
3108         else
3109         {
3110                 // run physics on the client entities
3111                 for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++)
3112                 {
3113                         if (!ent->priv.server->free)
3114                         {
3115                                 SV_Physics_ClientEntity_PreThink(ent);
3116                                 SV_Physics_ClientEntity(ent);
3117                                 SV_Physics_ClientEntity_PostThink(ent);
3118                         }
3119                 }
3120         }
3121
3122         // run physics on all the non-client entities
3123         if (!sv_freezenonclients.integer)
3124         {
3125                 for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3126                         if (!ent->priv.server->free)
3127                                 SV_Physics_Entity(ent);
3128                 // make a second pass to see if any ents spawned this frame and make
3129                 // sure they run their move/think
3130                 if (sv_gameplayfix_delayprojectiles.integer < 0)
3131                         for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
3132                                 if (!ent->priv.server->move && !ent->priv.server->free)
3133                                         SV_Physics_Entity(ent);
3134         }
3135
3136         if (PRVM_serverglobalfloat(force_retouch) > 0)
3137                 PRVM_serverglobalfloat(force_retouch) = max(0, PRVM_serverglobalfloat(force_retouch) - 1);
3138
3139         // LordHavoc: endframe support
3140         if (PRVM_serverfunction(EndFrame))
3141         {
3142                 PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
3143                 PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
3144                 PRVM_serverglobalfloat(time) = sv.time;
3145                 PRVM_ExecuteProgram (PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
3146         }
3147
3148         // decrement prog->num_edicts if the highest number entities died
3149         for (;PRVM_ED_CanAlloc(PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
3150
3151         if (!sv_freezenonclients.integer)
3152                 sv.time += sv.frametime;
3153 }