]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_input.c
fix a typo
[xonotic/darkplaces.git] / cl_input.c
index 3d9f0ad4b122a6bdc1916e0cb4f61118b321da62..b24d8ea186d46da73167eff56d8f14da4fa98281 100644 (file)
@@ -258,9 +258,15 @@ cvar_t cl_movement_friction = {0, "cl_movement_friction", "4"};
 cvar_t cl_movement_edgefriction = {0, "cl_movement_edgefriction", "2"};
 cvar_t cl_movement_stepheight = {0, "cl_movement_stepheight", "18"};
 cvar_t cl_movement_accelerate = {0, "cl_movement_accelerate", "10"};
+cvar_t cl_movement_jumpvelocity = {0, "cl_movement_jumpvelocity", "270"};
 cvar_t cl_gravity = {0, "cl_gravity", "800"};
 cvar_t cl_slowmo = {0, "cl_slowmo", "1"};
 
+cvar_t in_pitch_min = {0, "in_pitch_min", "-90"}; // quake used -70
+cvar_t in_pitch_max = {0, "in_pitch_max", "90"}; // quake used 80
+
+cvar_t m_filter = {CVAR_SAVE, "m_filter","0"};
+
 
 /*
 ================
@@ -314,21 +320,25 @@ void CL_AdjustAngles (void)
        cl.viewangles[ROLL] = bound(-50, cl.viewangles[ROLL], 50);
 }
 
+qboolean cl_ignoremousemove = false;
+
 /*
 ================
-CL_BaseMove
+CL_Move
 
 Send the intended movement message to the server
 ================
 */
-void CL_BaseMove (void)
+void CL_Move (void)
 {
        vec3_t temp;
-       if (cls.signon != SIGNONS)
-               return;
+       float mx, my;
+       static float old_mouse_x = 0, old_mouse_y = 0;
 
+       // clamp before the move to prevent starting with bad angles
        CL_AdjustAngles ();
 
+       // get basic movement from keyboard
        // PRYDON_CLIENTCURSOR needs to survive basemove resets
        VectorCopy (cl.cmd.cursor_screen, temp);
        memset (&cl.cmd, 0, sizeof(cl.cmd));
@@ -352,20 +362,84 @@ void CL_BaseMove (void)
                cl.cmd.forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
        }
 
-//
-// adjust for speed key
-//
+       // adjust for speed key
        if (in_speed.state & 1)
        {
                cl.cmd.forwardmove *= cl_movespeedkey.value;
                cl.cmd.sidemove *= cl_movespeedkey.value;
                cl.cmd.upmove *= cl_movespeedkey.value;
        }
-}
 
+       in_mouse_x = 0;
+       in_mouse_y = 0;
+
+       // allow mice or other external controllers to add to the move
+       IN_Move ();
+
+       // ignore a mouse move if mouse was activated/deactivated this frame
+       if (cl_ignoremousemove)
+       {
+               cl_ignoremousemove = false;
+               in_mouse_x = 0;
+               in_mouse_y = 0;
+       }
+
+       // apply m_filter if it is on
+       mx = in_mouse_x;
+       my = in_mouse_y;
+       if (m_filter.integer)
+       {
+               in_mouse_x = (mx + old_mouse_x) * 0.5;
+               in_mouse_y = (my + old_mouse_y) * 0.5;
+       }
+       old_mouse_x = mx;
+       old_mouse_y = my;
+
+       // if not in menu, apply mouse move to viewangles/movement
+       if (in_client_mouse)
+       {
+               if (cl_prydoncursor.integer)
+               {
+                       // mouse interacting with the scene, mostly stationary view
+                       V_StopPitchDrift();
+                       cl.cmd.cursor_screen[0] += in_mouse_x * sensitivity.value / vid.width;
+                       cl.cmd.cursor_screen[1] += in_mouse_y * sensitivity.value / vid.height;
+               }
+               else if (in_strafe.state & 1)
+               {
+                       // strafing mode, all looking is movement
+                       V_StopPitchDrift();
+                       cl.cmd.sidemove += m_side.value * in_mouse_x * sensitivity.value * cl.viewzoom;
+                       if (noclip_anglehack)
+                               cl.cmd.upmove -= m_forward.value * in_mouse_y * sensitivity.value * cl.viewzoom;
+                       else
+                               cl.cmd.forwardmove -= m_forward.value * in_mouse_y * sensitivity.value * cl.viewzoom;
+               }
+               else if ((in_mlook.state & 1) || freelook.integer)
+               {
+                       // mouselook, lookstrafe causes turning to become strafing
+                       V_StopPitchDrift();
+                       if (lookstrafe.integer)
+                               cl.cmd.sidemove += m_side.value * in_mouse_x * sensitivity.value * cl.viewzoom;
+                       else
+                               cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * sensitivity.value * cl.viewzoom;
+                       cl.viewangles[PITCH] += m_pitch.value * in_mouse_y * sensitivity.value * cl.viewzoom;
+               }
+               else
+               {
+                       // non-mouselook, yaw turning and forward/back movement
+                       cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * sensitivity.value * cl.viewzoom;
+                       cl.cmd.forwardmove -= m_forward.value * in_mouse_y * sensitivity.value * cl.viewzoom;
+               }
+       }
+
+       // clamp after the move to prevent rendering with bad angles
+       CL_AdjustAngles ();
+}
 
 #include "cl_collision.h"
 
+extern void V_CalcRefdef(void);
 void CL_UpdatePrydonCursor(void)
 {
        vec3_t temp, scale;
@@ -376,22 +450,22 @@ void CL_UpdatePrydonCursor(void)
        /*
        if (cl.cmd.cursor_screen[0] < -1)
        {
-               cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - -1) * vid.realwidth * sensitivity.value * cl.viewzoom;
+               cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - -1) * vid.width * sensitivity.value * cl.viewzoom;
                cl.cmd.cursor_screen[0] = -1;
        }
        if (cl.cmd.cursor_screen[0] > 1)
        {
-               cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - 1) * vid.realwidth * sensitivity.value * cl.viewzoom;
+               cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - 1) * vid.width * sensitivity.value * cl.viewzoom;
                cl.cmd.cursor_screen[0] = 1;
        }
        if (cl.cmd.cursor_screen[1] < -1)
        {
-               cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - -1) * vid.realheight * sensitivity.value * cl.viewzoom;
+               cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - -1) * vid.height * sensitivity.value * cl.viewzoom;
                cl.cmd.cursor_screen[1] = -1;
        }
        if (cl.cmd.cursor_screen[1] > 1)
        {
-               cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - 1) * vid.realheight * sensitivity.value * cl.viewzoom;
+               cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - 1) * vid.height * sensitivity.value * cl.viewzoom;
                cl.cmd.cursor_screen[1] = 1;
        }
        */
@@ -406,42 +480,45 @@ void CL_UpdatePrydonCursor(void)
        // trace distance
        VectorScale(scale, 1000000, scale);
 
-       // FIXME: use something other than renderer variables here
-       // (but they need to match)
-       VectorCopy(r_vieworigin, cl.cmd.cursor_start);
+       // calculate current view matrix
+       V_CalcRefdef();
+       VectorClear(temp);
+       Matrix4x4_Transform(&r_refdef.viewentitymatrix, temp, cl.cmd.cursor_start);
        VectorSet(temp, cl.cmd.cursor_screen[2] * scale[2], cl.cmd.cursor_screen[0] * scale[0], cl.cmd.cursor_screen[1] * scale[1]);
-       Matrix4x4_Transform(&r_view_matrix, temp, cl.cmd.cursor_end);
+       Matrix4x4_Transform(&r_refdef.viewentitymatrix, temp, cl.cmd.cursor_end);
+       // trace from view origin to the cursor
        cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber, (chase_active.integer || cl.intermission) ? &cl_entities[cl.playerentity].render : NULL);
        // makes sparks where cursor is
        //CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0);
 }
 
-void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
+void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
 {
-       int i, n, bump, contents, crouch;
-       double edgefriction;
-       double simulatedtime;
-       double currenttime;
-       double newtime;
-       double frametime;
-       double t;
-       vec_t wishspeed, addspeed, accelspeed, f, *playermins, *playermaxs;
-       client_movementqueue_t *q;
-       vec3_t currentorigin, currentvelocity, forward, right, up, wishvel, wishdir, neworigin, currentorigin2, neworigin2, yawangles;
-       trace_t trace, trace2, trace3;
+       int i;
+       int n;
        // remove stale queue items
        n = cl.movement_numqueue;
        cl.movement_numqueue = 0;
-       // calculate time to execute for
-       simulatedtime = cl.mtime[0] + cl_movement_latency.value / 1000.0;
-       for (i = 0;i < n;i++)
-               if (cl.movement_queue[i].time >= cl.mtime[0] && cl.movement_queue[i].time <= simulatedtime)
-                       cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
+       if (cl.servermovesequence)
+       {
+               for (i = 0;i < n;i++)
+                       if (cl.movement_queue[i].sequence > cl.servermovesequence)
+                               cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
+       }
+       else
+       {
+               double simulatedtime = cl.mtime[0] + cl_movement_latency.value / 1000.0;
+               for (i = 0;i < n;i++)
+                       if (cl.movement_queue[i].time >= cl.mtime[0] && cl.movement_queue[i].time <= simulatedtime)
+                               cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
+       }
        // add to input queue if there is room
-       if (cl.movement_numqueue < sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0]))
+       if (cl_movement.integer && cl.movement_numqueue < sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0]) && cl.mtime[0] > cl.mtime[1])
        {
                // add to input queue
-               cl.movement_queue[cl.movement_numqueue].time = simulatedtime;
+               cl.movement_queue[cl.movement_numqueue].sequence = cl.movesequence;
+               cl.movement_queue[cl.movement_numqueue].time = cl.mtime[0] + cl_movement_latency.value / 1000.0;
+               cl.movement_queue[cl.movement_numqueue].frametime = cl.mtime[0] - cl.mtime[1];
                VectorCopy(cl.viewangles, cl.movement_queue[cl.movement_numqueue].viewangles);
                cl.movement_queue[cl.movement_numqueue].move[0] = cl.cmd.forwardmove;
                cl.movement_queue[cl.movement_numqueue].move[1] = cl.cmd.sidemove;
@@ -450,12 +527,48 @@ void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
                cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch;
                cl.movement_numqueue++;
        }
-       cl.movement = false;
-       // abort if client movement is disabled
-       if (!cl_movement.integer || cl.stats[STAT_HEALTH] <= 0)
+       cl.movement = cl_movement.integer && cl.stats[STAT_HEALTH] > 0 && !cls.demoplayback && !cl.intermission;
+       // clear queue if client movement is disabled
+       if (!cl.movement)
+               cl.movement_numqueue = 0;
+       cl.movement_replay = true;
+}
+
+void CL_ClientMovement_Replay(void)
+{
+       int i;
+       int bump;
+       int contents;
+       int crouch;
+       int onground;
+       double edgefriction;
+       double frametime;
+       double t;
+       vec_t wishspeed;
+       vec_t addspeed;
+       vec_t accelspeed;
+       vec_t f;
+       vec_t *playermins;
+       vec_t *playermaxs;
+       vec3_t currentorigin;
+       vec3_t currentvelocity;
+       vec3_t forward;
+       vec3_t right;
+       vec3_t up;
+       vec3_t wishvel;
+       vec3_t wishdir;
+       vec3_t neworigin;
+       vec3_t currentorigin2;
+       vec3_t neworigin2;
+       vec3_t yawangles;
+       trace_t trace;
+       trace_t trace2;
+       trace_t trace3;
+       if (!cl.movement_replay)
                return;
+       cl.movement_replay = false;
+
        // fetch current starting values
-       currenttime = cl.mtime[0];
        VectorCopy(cl_entities[cl.playerentity].state_current.origin, currentorigin);
        VectorCopy(cl.mvelocity[0], currentvelocity);
        // FIXME: try minor nudges in various directions if startsolid to find a
@@ -463,63 +576,23 @@ void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
        // protocols this starts in solid)
        //currentorigin[2] += (1.0 / 32.0); // slight nudge to get out of the floor
        crouch = false; // this will be updated on first move
-       //Con_Printf("%f: ", currenttime);
-       // replay input queue, and remove any stale queue items
+
+       // check if onground
+       VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + 1);
+       VectorSet(neworigin2, currentorigin[0], currentorigin[1], currentorigin[2] - 1);
+       trace = CL_TraceBox(currentorigin2, cl_playercrouchmins, cl_playercrouchmaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
+       onground = trace.fraction < 1 && trace.plane.normal[2] > 0.7;
+       //Con_Printf("%f: ", cl.mtime[0]);
+
+       // replay the input queue to predict current location
        // note: this relies on the fact there's always one queue item at the end
-       for (i = 0, q = cl.movement_queue;i < cl.movement_numqueue;i++, q++)
+
+       for (i = 0;i < cl.movement_numqueue;i++)
        {
-               //newtime = (i == cl.movement_numqueue) ? simulatedtime : q->time;
-               newtime = q->time;
-               frametime = newtime - currenttime;
-               if (frametime < 0)
-                       continue;
+               client_movementqueue_t *q = cl.movement_queue + bound(0, i, cl.movement_numqueue - 1);
+               frametime = q->frametime;
                //Con_Printf(" %f", frametime);
-               currenttime = newtime;
-               if (crouch)
-               {
-                       playermins = cl_playercrouchmins;
-                       playermaxs = cl_playercrouchmaxs;
-               }
-               else
-               {
-                       playermins = cl_playerstandmins;
-                       playermaxs = cl_playerstandmaxs;
-               }
-               for (bump = 0, t = frametime;bump < 8 && VectorLength2(currentvelocity) > 0;bump++)
-               {
-                       VectorMA(currentorigin, t, currentvelocity, neworigin);
-                       trace = CL_TraceBox(currentorigin, playermins, playermaxs, neworigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
-                       if (trace.fraction < 1 && trace.plane.normal[2] == 0)
-                       {
-                               // may be a step or wall, try stepping up
-                               // first move forward at a higher level
-                               VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + cl_movement_stepheight.value);
-                               VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + cl_movement_stepheight.value);
-                               trace2 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
-                               // then move down from there
-                               VectorCopy(trace2.endpos, currentorigin2);
-                               VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], currentorigin[2]);
-                               trace3 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
-                               //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(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125)
-                               {
-                                       trace = trace2;
-                                       VectorCopy(trace3.endpos, trace.endpos);
-                               }
-                       }
-                       if (trace.fraction == 1)
-                       {
-                               VectorCopy(trace.endpos, currentorigin);
-                               break;
-                       }
-                       t *= 1 - trace.fraction;
-                       if (trace.fraction >= 0.001)
-                               VectorCopy(trace.endpos, currentorigin);
-                       f = DotProduct(currentvelocity, trace.plane.normal);
-                       VectorMA(currentvelocity, -f, trace.plane.normal, currentvelocity);
-               }
-               if (i < cl.movement_numqueue)
+               //if (frametime > 0)
                {
                        if (q->crouch)
                        {
@@ -538,6 +611,16 @@ void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
                                                crouch = false;
                                }
                        }
+                       if (crouch)
+                       {
+                               playermins = cl_playercrouchmins;
+                               playermaxs = cl_playercrouchmaxs;
+                       }
+                       else
+                       {
+                               playermins = cl_playerstandmins;
+                               playermaxs = cl_playerstandmaxs;
+                       }
                        // change velocity according to q->viewangles and q->move
                        contents = CL_PointSuperContents(currentorigin);
                        if (contents & SUPERCONTENTS_LIQUIDSMASK)
@@ -549,6 +632,8 @@ void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
                                wishspeed = VectorLength(wishvel);
                                if (wishspeed)
                                        VectorScale(wishvel, 1 / wishspeed, wishdir);
+                               else
+                                       VectorSet( wishdir, 0.0, 0.0, 0.0 );
                                wishspeed = min(wishspeed, cl_movement_maxspeed.value);
                                if (crouch)
                                        wishspeed *= 0.5;
@@ -578,20 +663,24 @@ void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
                        else
                        {
                                // walk
-                               VectorSet(yawangles, 0, cl.viewangles[1], 0);
+                               if (onground && q->jump)
+                               {
+                                       currentvelocity[2] += cl_movement_jumpvelocity.value;
+                                       onground = false;
+                               }
+                               VectorSet(yawangles, 0, q->viewangles[1], 0);
                                AngleVectors(yawangles, forward, right, up);
                                VectorMAM(q->move[0], forward, q->move[1], right, wishvel);
                                wishspeed = VectorLength(wishvel);
                                if (wishspeed)
                                        VectorScale(wishvel, 1 / wishspeed, wishdir);
+                               else
+                                       VectorSet( wishdir, 0.0, 0.0, 0.0 );
                                wishspeed = min(wishspeed, cl_movement_maxspeed.value);
                                if (crouch)
                                        wishspeed *= 0.5;
                                // check if onground
-                               VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + 1);
-                               VectorSet(neworigin2, currentorigin[0], currentorigin[1], currentorigin[2] - 1);
-                               trace = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
-                               if (trace.fraction < 1 && trace.plane.normal[2] > 0.7)
+                               if (onground)
                                {
                                        // apply ground friction
                                        f = sqrt(currentvelocity[0] * currentvelocity[0] + currentvelocity[1] * currentvelocity[1]);
@@ -601,7 +690,7 @@ void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
                                                VectorSet(currentorigin2, currentorigin[0] + currentvelocity[0]*(16/f), currentorigin[1] + currentvelocity[1]*(16/f), currentorigin[2] + playermins[2]);
                                                VectorSet(neworigin2, currentorigin2[0], currentorigin2[1], currentorigin2[2] - 34);
                                                trace = CL_TraceBox(currentorigin2, vec3_origin, vec3_origin, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
-                                               if (trace.fraction < 1)
+                                               if (trace.fraction == 1)
                                                        edgefriction = cl_movement_edgefriction.value;
                                        }
                                        // apply friction
@@ -626,12 +715,61 @@ void CL_ClientMovement(qboolean buttonjump, qboolean buttoncrouch)
                                currentvelocity[2] -= cl_gravity.value * frametime;
                        }
                }
+               //if (i < cl.movement_numqueue - 1 || (cl_movement.integer & 4))
+               {
+                       if (crouch)
+                       {
+                               playermins = cl_playercrouchmins;
+                               playermaxs = cl_playercrouchmaxs;
+                       }
+                       else
+                       {
+                               playermins = cl_playerstandmins;
+                               playermaxs = cl_playerstandmaxs;
+                       }
+                       onground = false;
+                       for (bump = 0, t = frametime;bump < 8 && VectorLength2(currentvelocity) > 0;bump++)
+                       {
+                               VectorMA(currentorigin, t, currentvelocity, neworigin);
+                               trace = CL_TraceBox(currentorigin, playermins, playermaxs, neworigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
+                               if (trace.fraction < 1 && trace.plane.normal[2] == 0)
+                               {
+                                       // may be a step or wall, try stepping up
+                                       // first move forward at a higher level
+                                       VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + cl_movement_stepheight.value);
+                                       VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + cl_movement_stepheight.value);
+                                       trace2 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
+                                       // then move down from there
+                                       VectorCopy(trace2.endpos, currentorigin2);
+                                       VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], currentorigin[2]);
+                                       trace3 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
+                                       //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(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125)
+                                       {
+                                               trace = trace2;
+                                               VectorCopy(trace3.endpos, trace.endpos);
+                                       }
+                               }
+                               if (trace.fraction == 1)
+                               {
+                                       VectorCopy(trace.endpos, currentorigin);
+                                       break;
+                               }
+                               if (trace.plane.normal[2] > 0.7)
+                                       onground = true;
+                               t *= 1 - trace.fraction;
+                               if (trace.fraction >= 0.001)
+                                       VectorCopy(trace.endpos, currentorigin);
+                               f = DotProduct(currentvelocity, trace.plane.normal);
+                               VectorMA(currentvelocity, -f, trace.plane.normal, currentvelocity);
+                       }
+               }
        }
-       //Con_Printf(" :%f\n", currenttime);
        // store replay location
-       cl.movement = true;
        VectorCopy(cl.movement_origin, cl.movement_oldorigin);
        VectorCopy(currentorigin, cl.movement_origin);
+       VectorCopy(currentvelocity, cl.movement_velocity);
        //VectorCopy(currentorigin, cl_entities[cl.playerentity].state_current.origin);
        //VectorSet(cl_entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
 }
@@ -677,6 +815,8 @@ void CL_SendMove(void)
        upmove = cl.cmd.upmove;
 #endif
 
+       CL_UpdatePrydonCursor();
+
        buf.maxsize = 128;
        buf.cursize = 0;
        buf.data = data;
@@ -706,18 +846,79 @@ void CL_SendMove(void)
        if (++cl.movemessages >= 2)
        {
                // send the movement message
-               // PROTOCOL_QUAKE       clc_move = 16 bytes total
-               // PROTOCOL_DARKPLACES1 clc_move = 19 bytes total
-               // PROTOCOL_DARKPLACES2 clc_move = 25 bytes total
-               // PROTOCOL_DARKPLACES3 clc_move = 25 bytes total
-               // PROTOCOL_DARKPLACES4 clc_move = 19 bytes total
-               // PROTOCOL_DARKPLACES5 clc_move = 19 bytes total
-               // PROTOCOL_DARKPLACES6 clc_move = 52 bytes total
-               // 5 bytes
-               MSG_WriteByte (&buf, clc_move);
-               MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
-               if (cl.protocol == PROTOCOL_DARKPLACES6)
+               // PROTOCOL_QUAKE        clc_move = 16 bytes total
+               // PROTOCOL_QUAKEDP      clc_move = 16 bytes total
+               // PROTOCOL_NEHAHRAMOVIE clc_move = 16 bytes total
+               // PROTOCOL_DARKPLACES1  clc_move = 19 bytes total
+               // PROTOCOL_DARKPLACES2  clc_move = 25 bytes total
+               // PROTOCOL_DARKPLACES3  clc_move = 25 bytes total
+               // PROTOCOL_DARKPLACES4  clc_move = 19 bytes total
+               // PROTOCOL_DARKPLACES5  clc_move = 19 bytes total
+               // PROTOCOL_DARKPLACES6  clc_move = 52 bytes total
+               // PROTOCOL_DARKPLACES7  clc_move = 56 bytes total
+               if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
+               {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
+                       // 3 bytes
+                       for (i = 0;i < 3;i++)
+                               MSG_WriteAngle8i (&buf, cl.viewangles[i]);
+                       // 6 bytes
+                       MSG_WriteCoord16i (&buf, forwardmove);
+                       MSG_WriteCoord16i (&buf, sidemove);
+                       MSG_WriteCoord16i (&buf, upmove);
+                       // 2 bytes
+                       MSG_WriteByte (&buf, bits);
+                       MSG_WriteByte (&buf, in_impulse);
+               }
+               else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
+               {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
+                       // 12 bytes
+                       for (i = 0;i < 3;i++)
+                               MSG_WriteAngle32f (&buf, cl.viewangles[i]);
+                       // 6 bytes
+                       MSG_WriteCoord16i (&buf, forwardmove);
+                       MSG_WriteCoord16i (&buf, sidemove);
+                       MSG_WriteCoord16i (&buf, upmove);
+                       // 2 bytes
+                       MSG_WriteByte (&buf, bits);
+                       MSG_WriteByte (&buf, in_impulse);
+               }
+               else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
+               {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
+                       // 6 bytes
+                       for (i = 0;i < 3;i++)
+                               MSG_WriteAngle16i (&buf, cl.viewangles[i]);
+                       // 6 bytes
+                       MSG_WriteCoord16i (&buf, forwardmove);
+                       MSG_WriteCoord16i (&buf, sidemove);
+                       MSG_WriteCoord16i (&buf, upmove);
+                       // 2 bytes
+                       MSG_WriteByte (&buf, bits);
+                       MSG_WriteByte (&buf, in_impulse);
+               }
+               else
                {
+                       // 5 bytes
+                       MSG_WriteByte (&buf, clc_move);
+                       if (cl.protocol != PROTOCOL_DARKPLACES6)
+                       {
+                               if (cl_movement.integer)
+                               {
+                                       cl.movesequence++;
+                                       MSG_WriteLong (&buf, cl.movesequence);
+                               }
+                               else
+                                       MSG_WriteLong (&buf, 0);
+                       }
+                       MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
                        // 6 bytes
                        for (i = 0;i < 3;i++)
                                MSG_WriteAngle16i (&buf, cl.viewangles[i]);
@@ -740,36 +941,6 @@ void CL_SendMove(void)
                        MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
                        MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
                }
-               else
-               {
-                       if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
-                       {
-                               // 3 bytes
-                               for (i = 0;i < 3;i++)
-                                       MSG_WriteAngle8i (&buf, cl.viewangles[i]);
-                       }
-                       else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
-                       {
-                               // 12 bytes
-                               for (i = 0;i < 3;i++)
-                                       MSG_WriteAngle32f (&buf, cl.viewangles[i]);
-                       }
-                       else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
-                       {
-                               // 6 bytes
-                               for (i = 0;i < 3;i++)
-                                       MSG_WriteAngle16i (&buf, cl.viewangles[i]);
-                       }
-                       else
-                               Host_Error("CL_SendMove: unknown cl.protocol %i\n", cl.protocol);
-                       // 6 bytes
-                       MSG_WriteCoord16i (&buf, forwardmove);
-                       MSG_WriteCoord16i (&buf, sidemove);
-                       MSG_WriteCoord16i (&buf, upmove);
-                       // 2 bytes
-                       MSG_WriteByte (&buf, bits);
-                       MSG_WriteByte (&buf, in_impulse);
-               }
        }
 
 #if MOVEAVERAGING
@@ -792,6 +963,7 @@ void CL_SendMove(void)
        }
 
        // PROTOCOL_DARKPLACES6 = 67 bytes per packet
+       // PROTOCOL_DARKPLACES7 = 71 bytes per packet
 
        // deliver the message
        if (cls.demoplayback)
@@ -800,8 +972,8 @@ void CL_SendMove(void)
        if (!buf.cursize)
                return;
 
-       // FIXME: bits & 64 is +button5, Nexuiz specific
-       CL_ClientMovement((bits & 2) != 0, (bits & 64) != 0);
+       // FIXME: bits & 16 is +button5, Nexuiz specific
+       CL_ClientMovement_Input((bits & 2) != 0, (bits & 16) != 0);
 
        if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
        {
@@ -879,7 +1051,12 @@ void CL_InitInput (void)
        Cvar_RegisterVariable(&cl_movement_edgefriction);
        Cvar_RegisterVariable(&cl_movement_stepheight);
        Cvar_RegisterVariable(&cl_movement_accelerate);
+       Cvar_RegisterVariable(&cl_movement_jumpvelocity);
        Cvar_RegisterVariable(&cl_gravity);
        Cvar_RegisterVariable(&cl_slowmo);
+
+       Cvar_RegisterVariable(&in_pitch_min);
+       Cvar_RegisterVariable(&in_pitch_max);
+       Cvar_RegisterVariable(&m_filter);
 }