]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/csqcmodellib/cl_player.qc
Merge branch 'master' into Mario/qc_physics_prehax
[xonotic/xonotic-data.pk3dir.git] / qcsrc / csqcmodellib / cl_player.qc
index e22a2ab39abad0988050b568ffdd45bb28e54a1e..4360527674e16be74180abadb8a95aac5279e226 100644 (file)
  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  * IN THE SOFTWARE.
  */
+#if defined(CSQC)
+       #include "../dpdefs/csprogsdefs.qh"
+       #include "../client/defs.qh"
+       #include "../common/constants.qh"
+       #include "../common/stats.qh"
+       #include "../common/util.qh"
+       #include "interpolate.qh"
+       #include "../client/main.qh"
+       #include "common.qh"
+       #include "cl_model.qh"
+       #include "cl_player.qh"
+#elif defined(MENUQC)
+#elif defined(SVQC)
+#endif
 
-var float autocvar_cl_movement_errorcompensation = 0;
+float autocvar_cl_movement_errorcompensation = 0;
+int autocvar_cl_movement = 1;
 
 // engine stuff
-#define REFDEFFLAG_TELEPORTED 1
-#define REFDEFFLAG_JUMPING 2
 float pmove_onground; // weird engine flag we shouldn't really use but have to for now
 
 vector csqcplayer_origin, csqcplayer_velocity;
-float csqcplayer_sequence, player_pmflags;
+float csqcplayer_sequence;
+int player_pmflags;
 float csqcplayer_moveframe;
 vector csqcplayer_predictionerroro;
 vector csqcplayer_predictionerrorv;
@@ -91,12 +105,12 @@ void CSQCPlayer_Unpredict()
        self.origin = csqcplayer_origin;
        self.velocity = csqcplayer_velocity;
        csqcplayer_moveframe = csqcplayer_sequence+1; //+1 because the recieved frame has the move already done (server side)
-       self.pmove_flags = player_pmflags;
+       self.flags = player_pmflags;
 }
 
 void CSQCPlayer_SetMinsMaxs()
 {
-       if(self.pmove_flags & PMF_DUCKED)
+       if(self.flags & FL_DUCKED)
        {
                self.mins = PL_CROUCH_MIN;
                self.maxs = PL_CROUCH_MAX;
@@ -112,645 +126,34 @@ void CSQCPlayer_SetMinsMaxs()
 
 void CSQCPlayer_SavePrediction()
 {
-       player_pmflags = self.pmove_flags;
+       player_pmflags = self.flags;
        csqcplayer_origin = self.origin;
        csqcplayer_velocity = self.velocity;
        csqcplayer_sequence = servercommandframe;
        csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
 }
 
-// TODO: cls.protocol == PROTOCOL_QUAKEWORLD ?
-// TODO: water prediction
-float pmove_waterjumptime; // weird engine flag we shouldn't really use but have to for now
-// TODO: move to a common header
-#define vlen2(v) dotproduct(v, v)
-void AngleVectors (vector angles, vector forward, vector right, vector up)
-{
-       float angle, sr, sp, sy, cr, cp, cy;
-
-       angle = angles_y * (M_PI*2 / 360);
-       sy = sin(angle);
-       cy = cos(angle);
-       angle = angles_x * (M_PI*2 / 360);
-       sp = sin(angle);
-       cp = cos(angle);
-       if (forward)
-       {
-               forward_x = cp*cy;
-               forward_y = cp*sy;
-               forward_z = -sp;
-       }
-       if (right || up)
-       {
-               if (angles_z)
-               {
-                       angle = angles_z * (M_PI*2 / 360);
-                       sr = sin(angle);
-                       cr = cos(angle);
-                       if (right)
-                       {
-                               right_x = -1*(sr*sp*cy+cr*-sy);
-                               right_y = -1*(sr*sp*sy+cr*cy);
-                               right_z = -1*(sr*cp);
-                       }
-                       if (up)
-                       {
-                               up_x = (cr*sp*cy+-sr*-sy);
-                               up_y = (cr*sp*sy+-sr*cy);
-                               up_z = cr*cp;
-                       }
-               }
-               else
-               {
-                       if (right)
-                       {
-                               right_x = sy;
-                               right_y = -cy;
-                               right_z = 0;
-                       }
-                       if (up)
-                       {
-                               up_x = (sp*cy);
-                               up_y = (sp*sy);
-                               up_z = cp;
-                       }
-               }
-       }
-}
-
-// TODO: move these elsewhere
-vector cl_playerstandmins = '-16 -16 -24';
-vector cl_playerstandmaxs = '16 16 45';
-vector cl_playercrouchmins = '-16 -16 -24';
-vector cl_playercrouchmaxs = '16 16 25';
-
-const float unstick_count = 27;
-vector unstick_offsets[unstick_count] =
-{
-// 1 no nudge (just return the original if this test passes)
-       '0.000   0.000  0.000',
-// 6 simple nudges
-       ' 0.000  0.000  0.125', '0.000  0.000 -0.125',
-       '-0.125  0.000  0.000', '0.125  0.000  0.000',
-       ' 0.000 -0.125  0.000', '0.000  0.125  0.000',
-// 4 diagonal flat nudges
-       '-0.125 -0.125  0.000', '0.125 -0.125  0.000',
-       '-0.125  0.125  0.000', '0.125  0.125  0.000',
-// 8 diagonal upward nudges
-       '-0.125  0.000  0.125', '0.125  0.000  0.125',
-       ' 0.000 -0.125  0.125', '0.000  0.125  0.125',
-       '-0.125 -0.125  0.125', '0.125 -0.125  0.125',
-       '-0.125  0.125  0.125', '0.125  0.125  0.125',
-// 8 diagonal downward nudges
-       '-0.125  0.000 -0.125', '0.125  0.000 -0.125',
-       ' 0.000 -0.125 -0.125', '0.000  0.125 -0.125',
-       '-0.125 -0.125 -0.125', '0.125 -0.125 -0.125',
-       '-0.125  0.125 -0.125', '0.125  0.125 -0.125',
-};
-
-float CSQC_ClientMovement_Unstick(entity s)
-{
-       float i;
-       vector neworigin;
-       for (i = 0; i < unstick_count; i++)
-       {
-               neworigin = unstick_offsets[i] + s.origin;
-               tracebox(neworigin, cl_playercrouchmins, cl_playercrouchmaxs, neworigin, MOVE_NORMAL, s);
-               if (!trace_startsolid)
-               {
-                       s.origin = neworigin;
-                       return true;
-               }
-       }
-       // if all offsets failed, give up
-       return false;
-}
-
-void CSQC_ClientMovement_UpdateStatus(entity s)
-{
-       float f;
-       vector origin1, origin2;
-
-       // make sure player is not stuck
-       CSQC_ClientMovement_Unstick(s);
-
-       // set crouched
-       if (input_buttons & 16)
-       {
-               // wants to crouch, this always works..
-               if (!s.pmove_flags & PMF_DUCKED)
-                       s.pmove_flags |= PMF_DUCKED;
-       }
-       else
-       {
-               // wants to stand, if currently crouching we need to check for a
-               // low ceiling first
-               if (s.pmove_flags & PMF_DUCKED)
-               {
-                       tracebox(s.origin, cl_playerstandmins, cl_playerstandmaxs, s.origin, MOVE_NORMAL, s);
-                       if (!trace_startsolid)
-                               s.pmove_flags &= ~PMF_DUCKED;
-               }
-       }
-       if (s.pmove_flags & PMF_DUCKED)
-       {
-               s.mins = cl_playercrouchmins;
-               s.maxs = cl_playercrouchmaxs;
-       }
-       else
-       {
-               s.mins = cl_playerstandmins;
-               s.maxs = cl_playerstandmaxs;
-       }
-
-       // set onground
-       origin1 = s.origin;
-       origin1_z += 1;
-       origin2 = s.origin;
-    origin2_z -= 1; // -2 causes clientside doublejump bug at above 150fps, raising that to 300fps :)
-
-       tracebox(origin1, s.mins, s.maxs, origin2, MOVE_NORMAL, s);
-       if(trace_fraction < 1 && trace_plane_normal_z > 0.7)
-       {
-               s.pmove_flags |= PMF_ONGROUND;
-
-               // this code actually "predicts" an impact; so let's clip velocity first
-               f = dotproduct(s.velocity, trace_plane_normal);
-               if(f < 0) // only if moving downwards actually
-                       s.velocity -= f * trace_plane_normal;
-       }
-       else
-               s.pmove_flags &= ~PMF_ONGROUND; // onground = false;
-
-       // set watertype/waterlevel
-       origin1 = s.origin;
-       origin1_z += s.mins_z + 1;
-       s.waterlevel = WATERLEVEL_NONE;
-       // TODO: convert
-//     s.watertype = CL_TracePoint(origin1, MOVE_NOMONSTERS, s, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK;
-//     if (s.watertype)
-//     {
-//             s.waterlevel = WATERLEVEL_WETFEET;
-//             origin1[2] = s.origin[2] + (s.mins[2] + s.maxs[2]) * 0.5f;
-//             if (CL_TracePoint(origin1, MOVE_NOMONSTERS, s, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
-//             {
-//                     s.waterlevel = WATERLEVEL_SWIMMING;
-//                     origin1[2] = s.origin[2] + 22;
-//                     if (CL_TracePoint(origin1, MOVE_NOMONSTERS, s, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
-//                             s.waterlevel = WATERLEVEL_SUBMERGED;
-//             }
-//     }
-//
-//     // water jump prediction
-//     if ((s.pmove_flags & PMF_ONGROUND) || s.velocity_z <= 0 || pmove_waterjumptime <= 0)
-//             pmove_waterjumptime = 0;
-}
-
-void CSQC_ClientMovement_Move(entity s)
-{
-       float bump;
-       float t;
-       float f;
-       vector neworigin;
-       vector currentorigin2;
-       vector neworigin2;
-       vector primalvelocity;
-       float old_trace1_fraction;
-       vector old_trace1_endpos;
-       vector old_trace1_plane_normal;
-       float old_trace2_fraction;
-       vector old_trace2_plane_normal;
-       CSQC_ClientMovement_UpdateStatus(s);
-       primalvelocity = s.velocity;
-       for (bump = 0, t = input_timelength; bump < 8 && vlen2(s.velocity) > 0; bump++)
-       {
-               neworigin = s.origin + t * s.velocity;
-               tracebox(s.origin, s.mins, s.maxs, neworigin, MOVE_NORMAL, s);
-               old_trace1_fraction = trace_fraction;
-               old_trace1_endpos = trace_endpos;
-               old_trace1_plane_normal = trace_plane_normal;
-               if (trace_fraction < 1 && trace_plane_normal_z == 0)
-               {
-                       // may be a step or wall, try stepping up
-                       // first move forward at a higher level
-                       currentorigin2 = s.origin;
-                       currentorigin2_z += getstatf(STAT_MOVEVARS_STEPHEIGHT);
-                       neworigin2 = neworigin;
-                       neworigin2_z = s.origin_z + getstatf(STAT_MOVEVARS_STEPHEIGHT);
-                       tracebox(currentorigin2, s.mins, s.maxs, neworigin2, MOVE_NORMAL, s);
-                       if (!trace_startsolid)
-                       {
-                               // then move down from there
-                               currentorigin2 = trace_endpos;
-                               neworigin2 = trace_endpos;
-                               neworigin2_z = s.origin_z;
-                               old_trace2_fraction = trace_fraction;
-                               old_trace2_plane_normal = trace_plane_normal;
-                               tracebox(currentorigin2, s.mins, s.maxs, neworigin2, MOVE_NORMAL, s);
-                               //Con_Printf("%f %f %f %f : %f %f %f %f : %f %f %f %f\n", trace.fraction, trace.endpos[0], trace.endpos[1], trace.endpos[2], trace2.fraction, trace2.endpos[0], trace2.endpos[1], trace2.endpos[2], trace3.fraction, trace3.endpos[0], trace3.endpos[1], trace3.endpos[2]);
-                               // accept the new trace if it made some progress
-                               if (fabs(trace_endpos_x - old_trace1_endpos_x) >= 0.03125 || fabs(trace_endpos_y - old_trace1_endpos_y) >= 0.03125)
-                               {
-                                       trace_fraction = old_trace2_fraction;
-                                       trace_endpos = trace_endpos;
-                                       trace_plane_normal = old_trace2_plane_normal;
-                               }
-                               else
-                               {
-                                       trace_fraction = old_trace1_fraction;
-                                       trace_endpos = old_trace1_endpos;
-                                       trace_plane_normal = old_trace1_plane_normal;
-                               }
-                       }
-               }
-
-               // check if it moved at all
-               if (trace_fraction >= 0.001)
-                       s.origin = trace_endpos;
-
-               // check if it moved all the way
-               if (trace_fraction == 1)
-                       break;
-
-               // this is only really needed for nogravityonground combined with gravityunaffectedbyticrate
-               // <LordHavoc> I'm pretty sure I commented it out solely because it seemed redundant
-               // this got commented out in a change that supposedly makes the code match QW better
-               // so if this is broken, maybe put it in an if(cls.protocol != PROTOCOL_QUAKEWORLD) block
-               if (trace_plane_normal_z > 0.7)
-                       s.pmove_flags |= PMF_ONGROUND;
-
-               t -= t * trace_fraction;
-
-               f = dotproduct(s.velocity, trace_plane_normal);
-               s.velocity -= f * trace_plane_normal;
-       }
-       if (pmove_waterjumptime > 0)
-               s.velocity = primalvelocity;
-}
-
-float CSQC_IsMoveInDirection(float forward, float side, float angle)
-{
-       // TODO: move to a common header
-       #define RAD2DEG(a) ((a) * (180.0f / M_PI))
-       #define ANGLEMOD(a) ((a) - 360.0 * floor((a) / 360.0))
-       if(forward == 0 && side == 0)
-               return 0; // avoid division by zero
-       angle -= RAD2DEG(atan2(side, forward));
-       angle = (ANGLEMOD(angle + 180) - 180) / 45;
-       if(angle > 1)
-               return 0;
-       if(angle < -1)
-               return 0;
-       return 1 - fabs(angle);
-       #undef RAD2DEG
-       #undef ANGLEMOD
-}
-
-float CSQC_GeomLerp(float a, float lerp, float b)
-{
-       if(a == 0)
-       {
-               if(lerp < 1)
-                       return 0;
-               else
-                       return b;
-       }
-       if(b == 0)
-       {
-               if(lerp > 0)
-                       return 0;
-               else
-                       return a;
-       }
-       return a * pow(fabs(b / a), lerp);
-}
-
-void CSQC_ClientMovement_Physics_CPM_PM_Aircontrol(entity s, vector wishdir, float wishspeed)
-{
-       float zspeed, speed, dot, k;
-
-       k = 32 * (2 * CSQC_IsMoveInDirection(input_movevalues_x, input_movevalues_y, 0) - 1);
-       if(k <= 0)
-               return;
-
-       k *= bound(0, wishspeed / getstatf(STAT_MOVEVARS_MAXAIRSPEED), 1);
-
-       zspeed = s.velocity_z;
-       s.velocity_z = 0;
-       speed = vlen(s.velocity);
-       if (speed) s.velocity /= speed;
-
-       dot = dotproduct(s.velocity, wishdir);
-
-       if(dot > 0) { // we can't change direction while slowing down
-               k *= pow(dot, getstatf(STAT_MOVEVARS_AIRCONTROL_POWER))*input_timelength;
-               speed = max(0, speed - getstatf(STAT_MOVEVARS_AIRCONTROL_PENALTY) * sqrt(max(0, 1 - dot*dot)) * k/32);
-               k *= getstatf(STAT_MOVEVARS_AIRCONTROL);
-               s.velocity = speed * s.velocity + k * wishdir;
-               s.velocity = normalize(s.velocity);
-       }
-
-       s.velocity *= speed;
-       s.velocity_z = zspeed;
-}
-
-float CSQC_ClientMovement_Physics_AdjustAirAccelQW(float accelqw, float factor)
-{
-       return
-               (accelqw < 0 ? -1 : +1)
-               *
-               bound(0.000001, 1 - (1 - fabs(accelqw)) * factor, 1);
-}
-
-void CSQC_ClientMovement_Physics_PM_Accelerate(entity s, vector wishdir, float wishspeed, float wishspeed0, float accel, float accelqw, float stretchfactor, float sidefric, float speedlimit)
-{
-       float vel_straight;
-       float vel_z;
-       vector vel_perpend;
-       float step;
-       vector vel_xy;
-       float vel_xy_current;
-       float vel_xy_backward, vel_xy_forward;
-       float speedclamp;
-
-       if(stretchfactor > 0)
-               speedclamp = stretchfactor;
-       else if(accelqw < 0)
-               speedclamp = 1;
-       else
-               speedclamp = -1; // no clamping
-
-       if(accelqw < 0)
-               accelqw = -accelqw;
-
-       if(moveflags & MOVEFLAG_Q2AIRACCELERATE)
-               wishspeed0 = wishspeed; // don't need to emulate this Q1 bug
-
-       vel_straight = dotproduct(s.velocity, wishdir);
-       vel_z = s.velocity_z;
-       vel_xy = s.velocity;
-       vel_xy_z -= vel_z;
-       vel_perpend = vel_xy - vel_straight * wishdir;
-
-       step = accel * input_timelength * wishspeed0;
-
-       vel_xy_current  = vlen(vel_xy);
-       if(speedlimit > 0)
-               accelqw = CSQC_ClientMovement_Physics_AdjustAirAccelQW(accelqw, (speedlimit - bound(wishspeed, vel_xy_current, speedlimit)) / max(1, speedlimit - wishspeed));
-       vel_xy_forward  = vel_xy_current + bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
-       vel_xy_backward = vel_xy_current - bound(0, wishspeed + vel_xy_current, step) * accelqw - step * (1 - accelqw);
-       if(vel_xy_backward < 0)
-               vel_xy_backward = 0; // not that it REALLY occurs that this would cause wrong behaviour afterwards
-
-       vel_straight    = vel_straight   + bound(0, wishspeed - vel_straight,   step) * accelqw + step * (1 - accelqw);
-
-       if(sidefric < 0 && vlen2(vel_perpend))
-               // negative: only apply so much sideways friction to stay below the speed you could get by "braking"
-       {
-               float f, fmin;
-               f = max(0, 1 + input_timelength * wishspeed * sidefric);
-               fmin = (vel_xy_backward*vel_xy_backward - vel_straight*vel_straight) / vlen2(vel_perpend);
-               // assume: fmin > 1
-               // vel_xy_backward*vel_xy_backward - vel_straight*vel_straight > vel_perpend*vel_perpend
-               // vel_xy_backward*vel_xy_backward > vel_straight*vel_straight + vel_perpend*vel_perpend
-               // vel_xy_backward*vel_xy_backward > vel_xy * vel_xy
-               // obviously, this cannot be
-               if(fmin <= 0)
-                       vel_perpend *= f;
-               else
-               {
-                       fmin = sqrt(fmin);
-                       vel_perpend *= max(fmin, f);
-               }
-       }
-       else
-               vel_perpend *= max(0, 1 - input_timelength * wishspeed * sidefric);
-
-       s.velocity = vel_perpend + vel_straight * wishdir;
-
-       if(speedclamp >= 0)
-       {
-               float vel_xy_preclamp;
-               vel_xy_preclamp = vlen(s.velocity);
-               if(vel_xy_preclamp > 0) // prevent division by zero
-               {
-                       vel_xy_current += (vel_xy_forward - vel_xy_current) * speedclamp;
-                       if(vel_xy_current < vel_xy_preclamp)
-                               s.velocity *= (vel_xy_current / vel_xy_preclamp);
-               }
-       }
-
-       s.velocity_z += vel_z;
-}
-
-void CSQC_ClientMovement_Physics_Walk(entity s)
-{
-       float friction;
-       float wishspeed;
-       float addspeed;
-       float accelspeed;
-       float f;
-       float gravity;
-       vector forward = '0 0 0';
-       vector right = '0 0 0';
-       vector up = '0 0 0';
-       vector wishvel;
-       vector wishdir;
-       vector yawangles;
-
-       // jump if on ground with jump button pressed but only if it has been
-       // released at least once since the last jump
-       if (input_buttons & 2)
-       {
-               if ((s.pmove_flags & PMF_ONGROUND) && ((s.pmove_flags & PMF_JUMP_HELD) == 0 || !cvar("cl_movement_track_canjump")))
-               {
-                       s.velocity_z += getstatf(STAT_MOVEVARS_JUMPVELOCITY);
-                       s.pmove_flags &= ~PMF_ONGROUND;
-                       s.pmove_flags |= PMF_JUMP_HELD; // canjump = false
-               }
-       }
-       else
-               s.pmove_flags &= ~PMF_JUMP_HELD; // canjump = true
-
-       // calculate movement vector
-       yawangles = '0 0 0';
-       yawangles_y = input_angles_y;
-       AngleVectors(yawangles, forward, right, up);
-       wishvel = input_movevalues_x * forward + input_movevalues_y * right;
-
-       // split wishvel into wishspeed and wishdir
-       wishspeed = vlen(wishvel);
-       if (wishspeed)
-               wishdir = wishvel / wishspeed;
-       else
-               wishdir = '0 0 0';
-       // check if onground
-       if ((s.pmove_flags & PMF_ONGROUND))
-       {
-               wishspeed = min(wishspeed, getstatf(STAT_MOVEVARS_MAXSPEED));
-               if (s.pmove_flags & PMF_DUCKED)
-                       wishspeed *= 0.5;
-
-               // apply edge friction
-               f = sqrt(s.velocity_x * s.velocity_x + s.velocity_y * s.velocity_y);
-               if (f > 0)
-               {
-                       friction = getstatf(STAT_MOVEVARS_FRICTION);
-                       if (getstatf(STAT_MOVEVARS_EDGEFRICTION) != 1)
-                       {
-                               vector neworigin2;
-                               vector neworigin3;
-                               // note: QW uses the full player box for the trace, and yet still
-                               // uses s.origin_z + s.mins_z, which is clearly an bug, but
-                               // this mimics it for compatibility
-                               neworigin2 = s.origin;
-                               neworigin2_x += s.velocity_x*(16/f);
-                               neworigin2_y += s.velocity_y*(16/f);
-                               neworigin2_z += s.mins_z;
-                               neworigin3 = neworigin2;
-                               neworigin3_z -= 34;
-//                             if (cls.protocol == PROTOCOL_QUAKEWORLD)
-                                       tracebox(neworigin2, s.mins, s.maxs, neworigin3, MOVE_NORMAL, s);
-//                             else
-//                                     traceline(neworigin2, neworigin3, MOVE_NORMAL, s);
-                               if (trace_fraction == 1 && !trace_startsolid)
-                                       friction *= getstatf(STAT_MOVEVARS_EDGEFRICTION);
-                       }
-                       // apply ground friction
-                       f = 1 - input_timelength * friction * ((f < getstatf(STAT_MOVEVARS_STOPSPEED)) ? (getstatf(STAT_MOVEVARS_STOPSPEED) / f) : 1);
-                       f = max(f, 0);
-                       s.velocity *= f;
-               }
-               addspeed = wishspeed - dotproduct(s.velocity, wishdir);
-               if (addspeed > 0)
-               {
-                       accelspeed = min(getstatf(STAT_MOVEVARS_ACCELERATE) * input_timelength * wishspeed, addspeed);
-                       s.velocity += accelspeed * wishdir;
-               }
-               gravity = getstatf(STAT_MOVEVARS_GRAVITY) * getstatf(STAT_MOVEVARS_ENTGRAVITY) * input_timelength;
-               if(!(moveflags & MOVEFLAG_NOGRAVITYONGROUND))
-               {
-                       if(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
-                               s.velocity_z -= gravity * 0.5;
-                       else
-                               s.velocity_z -= gravity;
-               }
-//             if (cls.protocol == PROTOCOL_QUAKEWORLD)
-                       s.velocity_z = 0;
-               if (vlen2(s.velocity))
-                       CSQC_ClientMovement_Move(s);
-               if(!(moveflags & MOVEFLAG_NOGRAVITYONGROUND) || !(s.pmove_flags & PMF_ONGROUND))
-               {
-                       if(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
-                               s.velocity_z -= gravity * 0.5;
-               }
-       }
-       else
-       {
-               if (pmove_waterjumptime <= 0)
-               {
-                       // apply air speed limit
-                       float accel, wishspeed0, wishspeed2, accelqw, strafity;
-                       float accelerating;
-
-                       accelqw = getstatf(STAT_MOVEVARS_AIRACCEL_QW);
-                       wishspeed0 = wishspeed;
-                       wishspeed = min(wishspeed, getstatf(STAT_MOVEVARS_MAXAIRSPEED));
-                       if (s.pmove_flags & PMF_DUCKED)
-                               wishspeed *= 0.5;
-                       accel = getstatf(STAT_MOVEVARS_AIRACCELERATE);
-
-                       accelerating = (dotproduct(s.velocity, wishdir) > 0);
-                       wishspeed2 = wishspeed;
-
-                       // CPM: air control
-                       if(getstatf(STAT_MOVEVARS_AIRSTOPACCELERATE) != 0)
-                       {
-                               vector curdir;
-                               curdir_x = s.velocity_x;
-                               curdir_y = s.velocity_y;
-                               curdir_z = 0;
-                               curdir = normalize(curdir);
-                               accel = accel + (getstatf(STAT_MOVEVARS_AIRSTOPACCELERATE) - accel) * max(0, -dotproduct(curdir, wishdir));
-                       }
-                       strafity = CSQC_IsMoveInDirection(input_movevalues_x, input_movevalues_y, -90) + CSQC_IsMoveInDirection(input_movevalues_x, input_movevalues_y, +90); // if one is nonzero, other is always zero
-                       if(getstatf(STAT_MOVEVARS_MAXAIRSTRAFESPEED))
-                               wishspeed = min(wishspeed, CSQC_GeomLerp(getstatf(STAT_MOVEVARS_MAXAIRSPEED), strafity, getstatf(STAT_MOVEVARS_MAXAIRSTRAFESPEED)));
-                       if(getstatf(STAT_MOVEVARS_AIRSTRAFEACCELERATE))
-                               accel = CSQC_GeomLerp(getstatf(STAT_MOVEVARS_AIRACCELERATE), strafity, getstatf(STAT_MOVEVARS_AIRSTRAFEACCELERATE));
-                       if(getstatf(STAT_MOVEVARS_AIRSTRAFEACCEL_QW))
-                               accelqw =
-                                       (((strafity > 0.5 ? getstatf(STAT_MOVEVARS_AIRSTRAFEACCEL_QW) : getstatf(STAT_MOVEVARS_AIRACCEL_QW)) >= 0) ? +1 : -1)
-                                       *
-                                       (1 - CSQC_GeomLerp(1 - fabs(getstatf(STAT_MOVEVARS_AIRACCEL_QW)), strafity, 1 - fabs(getstatf(STAT_MOVEVARS_AIRSTRAFEACCEL_QW))));
-                       // !CPM
-
-//                     if(getstatf(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL) && accelerating && input_movevalues_y == 0 && input_movevalues_x != 0)
-//                             CSQC_ClientMovement_Physics_PM_AirAccelerate(s, wishdir, wishspeed2);
-//                     else
-                               CSQC_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, wishspeed0, accel, accelqw, getstatf(STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR), getstatf(STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION) / getstatf(STAT_MOVEVARS_MAXAIRSPEED), getstatf(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW));
-
-                       if(getstatf(STAT_MOVEVARS_AIRCONTROL))
-                               CSQC_ClientMovement_Physics_CPM_PM_Aircontrol(s, wishdir, wishspeed2);
-               }
-               gravity = getstatf(STAT_MOVEVARS_GRAVITY) * getstatf(STAT_MOVEVARS_ENTGRAVITY) * input_timelength;
-               if(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
-                       s.velocity_z -= gravity * 0.5;
-               else
-                       s.velocity_z -= gravity;
-               CSQC_ClientMovement_Move(s);
-               if(!(moveflags & MOVEFLAG_NOGRAVITYONGROUND) || !(s.pmove_flags & PMF_ONGROUND))
-               {
-                       if(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
-                               s.velocity_z -= gravity * 0.5;
-               }
-       }
-}
-
-void CSQC_ClientMovement_PlayerMove(entity s)
-{
-       //Con_Printf(" %f", frametime);
-       if (!(input_buttons & 2)) // !jump
-               s.pmove_flags &= ~PMF_JUMP_HELD; // canjump = true
-       pmove_waterjumptime -= input_timelength;
-       CSQC_ClientMovement_UpdateStatus(s);
-       // TODO
-//     if (s.waterlevel >= WATERLEVEL_SWIMMING)
-//             CL_ClientMovement_Physics_Swim(s);
-//     else
-               CSQC_ClientMovement_Physics_Walk(s);
-}
+void CSQC_ClientMovement_PlayerMove_Frame();
 
-void CSQC_ClientMovement_PlayerMove_Frame(entity s)
+void PM_Movement_Move()
 {
-       // if a move is more than 50ms, do it as two moves (matching qwsv)
-       //Con_Printf("%i ", s.cmd.msec);
-       if(input_timelength > 0.0005)
-       {
-               if (input_timelength > 0.05)
-               {
-                       input_timelength /= 2;
-                       CSQC_ClientMovement_PlayerMove(s);
-               }
-               CSQC_ClientMovement_PlayerMove(s);
-       }
-       else
-       {
-               // we REALLY need this handling to happen, even if the move is not executed
-               if (!(input_buttons & 2)) // !jump
-                       s.pmove_flags &= ~PMF_JUMP_HELD; // canjump = true
-       }
+       runstandardplayerphysics(self);
+#ifdef CSQC
+       self.flags = 
+                       ((self.pmove_flags & PMF_DUCKED) ? FL_DUCKED : 0) |
+                       (!(self.pmove_flags & PMF_JUMP_HELD) ? FL_JUMPRELEASED : 0) |
+                       ((self.pmove_flags & PMF_ONGROUND) ? FL_ONGROUND : 0);
+#endif
 }
 
 void CSQCPlayer_Physics(void)
 {
-       switch(cvar("cl_movement")) {
-               case 2: CSQC_ClientMovement_PlayerMove_Frame(self); break;
-               case 1: runstandardplayerphysics(self); break;
-               default: break;
+       switch(autocvar_cl_movement)
+       {
+               case 1: CSQC_ClientMovement_PlayerMove_Frame(); break;
+               case 2: PM_Movement_Move(); break;
        }
 }
-#undef vlen2
 
 void CSQCPlayer_PredictTo(float endframe, float apply_error)
 {
@@ -797,13 +200,11 @@ void CSQCPlayer_PredictTo(float endframe, float apply_error)
        input_angles = view_angles;
 }
 
-float CSQCPlayer_IsLocalPlayer()
+bool CSQCPlayer_IsLocalPlayer()
 {
        return (self == csqcplayer);
 }
 
-void(entity e, float fl) V_CalcRefdef = #640; // DP_CSQC_V_CALCREFDEF
-
 void CSQCPlayer_SetCamera()
 {
        vector v0;
@@ -815,26 +216,22 @@ void CSQCPlayer_SetCamera()
                oldself = self;
                self = csqcplayer;
 
-#ifdef COMPAT_XON050_ENGINE
-               if(servercommandframe == 0 || clientcommandframe == 0 || !(checkextension("DP_CSQC_V_CALCREFDEF") || checkextension("DP_CSQC_V_CALCREFDEF_WIP1")))
-#else
                if(servercommandframe == 0 || clientcommandframe == 0)
-#endif
                {
                        InterpolateOrigin_Do();
                        self.view_ofs = '0 0 1' * getstati(STAT_VIEWHEIGHT);
 
                        // get crouch state from the server
-                       if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS_z)
-                               self.pmove_flags &= ~PMF_DUCKED;
-                       else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS_z)
-                               self.pmove_flags |= PMF_DUCKED;
+                       if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+                               self.flags &= ~FL_DUCKED;
+                       else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+                               self.flags |= FL_DUCKED;
 
                        // get onground state from the server
                        if(pmove_onground)
-                               self.pmove_flags |= PMF_ONGROUND;
+                               self.flags |= FL_ONGROUND;
                        else
-                               self.pmove_flags &= ~PMF_ONGROUND;
+                               self.flags &= ~FL_ONGROUND;
 
                        CSQCPlayer_SetMinsMaxs();
 
@@ -857,38 +254,38 @@ void CSQCPlayer_SetCamera()
                                o = self.origin;
                                v = v0;
                                csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
-                               CSQCPlayer_PredictTo(servercommandframe + 1, FALSE);
-                               CSQCPlayer_SetPredictionError(self.origin - o, self.velocity - v, pmove_onground - !!(self.pmove_flags & PMF_ONGROUND));
+                               CSQCPlayer_PredictTo(servercommandframe + 1, false);
+                               CSQCPlayer_SetPredictionError(self.origin - o, self.velocity - v, pmove_onground - !!(self.flags & FL_ONGROUND));
                                self.origin = o;
                                self.velocity = v;
 
                                // get crouch state from the server
-                               if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS_z)
-                                       self.pmove_flags &= ~PMF_DUCKED;
-                               else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS_z)
-                                       self.pmove_flags |= PMF_DUCKED;
+                               if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+                                       self.flags &= ~FL_DUCKED;
+                               else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+                                       self.flags |= FL_DUCKED;
 
                                // get onground state from the server
                                if(pmove_onground)
-                                       self.pmove_flags |= PMF_ONGROUND;
+                                       self.flags |= FL_ONGROUND;
                                else
-                                       self.pmove_flags &= ~PMF_ONGROUND;
+                                       self.flags &= ~FL_ONGROUND;
 
                                CSQCPlayer_SavePrediction();
                        }
-                       CSQCPlayer_PredictTo(clientcommandframe + 1, TRUE);
+                       CSQCPlayer_PredictTo(clientcommandframe + 1, true);
 
 #ifdef CSQCMODEL_SERVERSIDE_CROUCH
                        // get crouch state from the server (LAG)
-                       if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS_z)
-                               self.pmove_flags &= ~PMF_DUCKED;
-                       else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS_z)
-                               self.pmove_flags |= PMF_DUCKED;
+                       if(getstati(STAT_VIEWHEIGHT) == PL_VIEW_OFS.z)
+                               self.flags &= ~FL_DUCKED;
+                       else if(getstati(STAT_VIEWHEIGHT) == PL_CROUCH_VIEW_OFS.z)
+                               self.flags |= FL_DUCKED;
 #endif
 
                        CSQCPlayer_SetMinsMaxs();
 
-                       self.angles_y = input_angles_y;
+                       self.angles_y = input_angles.y;
                }
 
                // relink
@@ -898,11 +295,7 @@ void CSQCPlayer_SetCamera()
        }
 
        entity view;
-#ifdef COMPAT_XON050_ENGINE
-       view = CSQCModel_server2csqc((spectatee_status > 0) ? spectatee_status : player_localentnum);
-#else
        view = CSQCModel_server2csqc(player_localentnum);
-#endif
 
        if(view && view != csqcplayer)
        {
@@ -913,18 +306,9 @@ void CSQCPlayer_SetCamera()
                self = oldself;
        }
 
-#ifdef COMPAT_XON050_ENGINE
-       if(view && !(checkextension("DP_CSQC_V_CALCREFDEF") || checkextension("DP_CSQC_V_CALCREFDEF_WIP1")))
-       {
-               // legacy code, not totally correct, but good enough for not having V_CalcRefdef
-               setproperty(VF_ORIGIN, view.origin + '0 0 1' * getstati(STAT_VIEWHEIGHT));
-               setproperty(VF_ANGLES, view_angles);
-       }
-       else
-#endif
        if(view)
        {
-               var float refdefflags = 0;
+               int refdefflags = 0;
 
                if(view.csqcmodel_teleported)
                        refdefflags |= REFDEFFLAG_TELEPORTED;