+ VectorCopy(neworigin, s->origin);
+ return true;
+ }
+ }
+ // if all offsets failed, give up
+ return false;
+}
+
+void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s)
+{
+ vec3_t origin1, origin2;
+ trace_t trace;
+
+ // make sure player is not stuck
+ CL_ClientMovement_Unstick(s);
+
+ // set crouched
+ if (s->q.crouch)
+ {
+ // wants to crouch, this always works..
+ if (!s->crouched)
+ s->crouched = true;
+ }
+ else
+ {
+ // wants to stand, if currently crouching we need to check for a
+ // low ceiling first
+ if (s->crouched)
+ {
+ trace = CL_Move(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ if (!trace.startsolid)
+ s->crouched = false;
+ }
+ }
+ if (s->crouched)
+ {
+ VectorCopy(cl.playercrouchmins, s->mins);
+ VectorCopy(cl.playercrouchmaxs, s->maxs);
+ }
+ else
+ {
+ VectorCopy(cl.playerstandmins, s->mins);
+ VectorCopy(cl.playerstandmaxs, s->maxs);
+ }
+
+ // set onground
+ VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + 1);
+ VectorSet(origin2, s->origin[0], s->origin[1], s->origin[2] - 2);
+ trace = CL_Move(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ s->onground = trace.fraction < 1 && trace.plane.normal[2] > 0.7;
+
+ // set watertype/waterlevel
+ VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + s->mins[2] + 1);
+ s->waterlevel = WATERLEVEL_NONE;
+ s->watertype = CL_Move(origin1, vec3_origin, vec3_origin, origin1, MOVE_NOMONSTERS, NULL, 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_Move(origin1, vec3_origin, vec3_origin, origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
+ {
+ s->waterlevel = WATERLEVEL_SWIMMING;
+ origin1[2] = s->origin[2] + 22;
+ if (CL_Move(origin1, vec3_origin, vec3_origin, origin1, MOVE_NOMONSTERS, NULL, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK)
+ s->waterlevel = WATERLEVEL_SUBMERGED;
+ }
+ }
+
+ // water jump prediction
+ if (s->onground || s->velocity[2] <= 0 || s->waterjumptime <= 0)
+ s->waterjumptime = 0;
+}
+
+void CL_ClientMovement_Move(cl_clientmovement_state_t *s)
+{
+ int bump;
+ double t;
+ 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->q.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] + s->movevars_stepheight);
+ VectorSet(neworigin2, neworigin[0], neworigin[1], s->origin[2] + s->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)