+ */
+
+ vel_straight = DotProduct(s->velocity, wishdir);
+ vel_z = s->velocity[2];
+ VectorMA(s->velocity, -vel_straight, wishdir, vel_perpend);
+ vel_perpend[2] -= vel_z;
+
+ f = wishspeed - vel_straight;
+ if(f > 0)
+ vel_straight += min(f, s->movevars_accelerate * s->q.frametime * wishspeed) * s->movevars_airaccel_qw;
+ if(wishspeed > 0)
+ vel_straight += min(wishspeed, s->movevars_accelerate * s->q.frametime * wishspeed) * (1 - s->movevars_airaccel_qw);
+
+ VectorM(1 - (s->q.frametime * (wishspeed / s->movevars_maxairspeed) * s->movevars_airaccel_sideways_friction), vel_perpend, vel_perpend);
+
+ VectorMA(vel_perpend, vel_straight, wishdir, s->velocity);
+ s->velocity[2] += vel_z;
+ }
+ s->velocity[2] -= cl_gravity.value * s->q.frametime;
+ CL_ClientMovement_Move(s);
+ }
+}
+
+void CL_ClientMovement_PlayerMove(cl_clientmovement_state_t *s)
+{
+ //Con_Printf(" %f", frametime);
+ if (!s->q.jump)
+ s->canjump = true;
+ s->waterjumptime -= s->q.frametime;
+ CL_ClientMovement_UpdateStatus(s);
+ if (s->waterlevel >= WATERLEVEL_SWIMMING)
+ CL_ClientMovement_Physics_Swim(s);
+ else
+ CL_ClientMovement_Physics_Walk(s);
+}
+
+void CL_ClientMovement_Replay(void)
+{
+ int i;
+ cl_clientmovement_state_t s;
+
+ if (!cl.movement_replay)
+ return;
+ cl.movement_replay = false;
+
+ // set up starting state for the series of moves
+ memset(&s, 0, sizeof(s));
+ VectorCopy(cl.entities[cl.playerentity].state_current.origin, s.origin);
+ VectorCopy(cl.mvelocity[0], s.velocity);
+ s.crouched = true; // will be updated on first move
+ s.canjump = cl.movement_replay_canjump;
+
+ // set up movement variables
+ if (cls.protocol == PROTOCOL_QUAKEWORLD)
+ {
+ s.movevars_gravity = cl.qw_movevars_gravity;
+ s.movevars_stopspeed = cl.qw_movevars_stopspeed;
+ s.movevars_maxspeed = cl.qw_movevars_maxspeed;
+ s.movevars_spectatormaxspeed = cl.qw_movevars_spectatormaxspeed;
+ s.movevars_accelerate = cl.qw_movevars_accelerate;
+ s.movevars_airaccelerate = cl.qw_movevars_airaccelerate;
+ s.movevars_wateraccelerate = cl.qw_movevars_wateraccelerate;
+ s.movevars_friction = cl.qw_movevars_friction;
+ s.movevars_waterfriction = cl.qw_movevars_waterfriction;
+ s.movevars_entgravity = cl.qw_movevars_entgravity;
+ s.movevars_jumpvelocity = cl_movement_jumpvelocity.value;
+ s.movevars_edgefriction = cl_movement_edgefriction.value;
+ s.movevars_maxairspeed = cl_movement_maxairspeed.value;
+ s.movevars_stepheight = cl_movement_stepheight.value;
+ s.movevars_airaccel_qw = 1.0;
+ s.movevars_airaccel_sideways_friction = 0.0;
+ }
+ else
+ {
+ s.movevars_gravity = sv_gravity.value;
+ s.movevars_stopspeed = cl_movement_stopspeed.value;
+ s.movevars_maxspeed = cl_movement_maxspeed.value;
+ s.movevars_spectatormaxspeed = cl_movement_maxspeed.value;
+ s.movevars_accelerate = cl_movement_accelerate.value;
+ s.movevars_airaccelerate = cl_movement_airaccelerate.value < 0 ? cl_movement_accelerate.value : cl_movement_airaccelerate.value;
+ s.movevars_wateraccelerate = cl_movement_wateraccelerate.value < 0 ? cl_movement_accelerate.value : cl_movement_wateraccelerate.value;
+ s.movevars_friction = cl_movement_friction.value;
+ s.movevars_waterfriction = cl_movement_waterfriction.value < 0 ? cl_movement_friction.value : cl_movement_waterfriction.value;
+ s.movevars_entgravity = 1;
+ s.movevars_jumpvelocity = cl_movement_jumpvelocity.value;
+ s.movevars_edgefriction = cl_movement_edgefriction.value;
+ s.movevars_maxairspeed = cl_movement_maxairspeed.value;
+ s.movevars_stepheight = cl_movement_stepheight.value;
+ s.movevars_airaccel_qw = cl_movement_airaccel_qw.value;
+ s.movevars_airaccel_sideways_friction = cl_movement_airaccel_sideways_friction.value;
+ }
+
+ cl.movement_predicted = (cl_movement.integer && cls.signon == SIGNONS && cl.stats[STAT_HEALTH] > 0 && !cl.intermission) && ((cls.protocol != PROTOCOL_DARKPLACES6 && cls.protocol != PROTOCOL_DARKPLACES7) || cl.servermovesequence);
+ if (cl.movement_predicted)
+ {
+ //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;i < cl.movement_numqueue;i++)
+ {
+ s.q = cl.movement_queue[i];
+ // if a move is more than 50ms, do it as two moves (matching qwsv)
+ if (s.q.frametime > 0.05)