+ vec_t f;
+ vec3_t neworigin;
+ vec3_t currentorigin2;
+ vec3_t neworigin2;
+ vec3_t primalvelocity;
+ trace_t trace;
+ trace_t trace2;
+ trace_t trace3;
+ CL_ClientMovement_UpdateStatus(s);
+ VectorCopy(s->velocity, primalvelocity);
+ for (bump = 0, t = s->cmd.frametime;bump < 8 && VectorLength2(s->velocity) > 0;bump++)
+ {
+ VectorMA(s->origin, t, s->velocity, neworigin);
+ trace = CL_Move(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ 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, s->origin[0], s->origin[1], s->origin[2] + cl.movevars_stepheight);
+ VectorSet(neworigin2, neworigin[0], neworigin[1], s->origin[2] + cl.movevars_stepheight);
+ trace2 = CL_Move(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ if (!trace2.startsolid)
+ {
+ // then move down from there
+ VectorCopy(trace2.endpos, currentorigin2);
+ VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], s->origin[2]);
+ trace3 = CL_Move(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ //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);
+ }
+ }
+ }
+
+ // check if it moved at all
+ if (trace.fraction >= 0.001)
+ VectorCopy(trace.endpos, s->origin);
+
+ // check if it moved all the way
+ if (trace.fraction == 1)
+ break;
+
+ //if (trace.plane.normal[2] > 0.7)
+ // s->onground = true;
+
+ t -= t * trace.fraction;
+
+ f = DotProduct(s->velocity, trace.plane.normal);
+ VectorMA(s->velocity, -f, trace.plane.normal, s->velocity);
+ }
+ if (s->waterjumptime > 0)
+ VectorCopy(primalvelocity, s->velocity);
+}
+
+
+void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s)
+{
+ vec_t wishspeed;
+ vec_t f;
+ vec3_t wishvel;
+ vec3_t wishdir;
+
+ // water jump only in certain situations
+ // this mimics quakeworld code
+ if (s->cmd.jump && s->waterlevel == 2 && s->velocity[2] >= -180)
+ {
+ vec3_t forward;
+ vec3_t yawangles;
+ vec3_t spot;
+ VectorSet(yawangles, 0, s->cmd.viewangles[1], 0);
+ AngleVectors(yawangles, forward, NULL, NULL);
+ VectorMA(s->origin, 24, forward, spot);
+ spot[2] += 8;
+ if (CL_Move(spot, vec3_origin, vec3_origin, spot, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsolid)
+ {
+ spot[2] += 24;
+ if (!CL_Move(spot, vec3_origin, vec3_origin, spot, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsolid)
+ {
+ VectorScale(forward, 50, s->velocity);
+ s->velocity[2] = 310;
+ s->waterjumptime = 2;
+ s->onground = false;
+ s->cmd.canjump = false;
+ }
+ }
+ }
+
+ if (!(s->cmd.forwardmove*s->cmd.forwardmove + s->cmd.sidemove*s->cmd.sidemove + s->cmd.upmove*s->cmd.upmove))
+ {
+ // drift towards bottom
+ VectorSet(wishvel, 0, 0, -60);
+ }
+ else
+ {
+ // swim
+ vec3_t forward;
+ vec3_t right;
+ vec3_t up;
+ // calculate movement vector
+ AngleVectors(s->cmd.viewangles, forward, right, up);
+ VectorSet(up, 0, 0, 1);
+ VectorMAMAM(s->cmd.forwardmove, forward, s->cmd.sidemove, right, s->cmd.upmove, up, wishvel);
+ }
+
+ // split wishvel into wishspeed and wishdir
+ wishspeed = VectorLength(wishvel);
+ if (wishspeed)
+ VectorScale(wishvel, 1 / wishspeed, wishdir);
+ else
+ VectorSet( wishdir, 0.0, 0.0, 0.0 );
+ wishspeed = min(wishspeed, cl.movevars_maxspeed) * 0.7;
+
+ if (s->crouched)
+ wishspeed *= 0.5;
+
+ if (s->waterjumptime <= 0)
+ {
+ // water friction
+ f = 1 - s->cmd.frametime * cl.movevars_waterfriction * s->waterlevel;
+ f = bound(0, f, 1);
+ VectorScale(s->velocity, f, s->velocity);
+
+ // water acceleration
+ f = wishspeed - DotProduct(s->velocity, wishdir);
+ if (f > 0)
+ {
+ f = min(cl.movevars_wateraccelerate * s->cmd.frametime * wishspeed, f);
+ VectorMA(s->velocity, f, wishdir, s->velocity);
+ }
+
+ // holding jump button swims upward slowly
+ if (s->cmd.jump)
+ {
+ if (s->watertype & SUPERCONTENTS_LAVA)
+ s->velocity[2] = 50;
+ else if (s->watertype & SUPERCONTENTS_SLIME)
+ s->velocity[2] = 80;
+ else
+ {
+ if (gamemode == GAME_NEXUIZ)
+ s->velocity[2] = 200;
+ else
+ s->velocity[2] = 100;
+ }
+ }
+ }
+
+ CL_ClientMovement_Move(s);
+}
+
+void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
+{
+ vec_t friction;