- // fetch current starting values
- 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
- // safe place to start the walk (due to network compression in some
- // 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
- // note: this relies on the fact there's always one queue item at the end
- // abort if client movement is disabled
- cl.movement = cl_movement.integer && cl.stats[STAT_HEALTH] > 0 && !cls.demoplayback;
- if (!cl.movement)
- cl.movement_numqueue = 0;
- for (i = 0;i <= cl.movement_numqueue;i++)
- {
- newtime = (i >= cl.movement_numqueue) ? simulatedtime : cl.movement_queue[i].time;
- frametime = newtime - currenttime;
- if (frametime <= 0)
- continue;
- //Con_Printf(" %f", frametime);
- currenttime = newtime;
- if (i >= 1 && i <= cl.movement_numqueue)
- if (i > 0 || (cl_movement.integer & 8))
- if (i < cl.movement_numqueue - 1 || (cl_movement.integer & 16))
+ cl.movement_replay = true;
+}
+
+typedef enum waterlevel_e
+{
+ WATERLEVEL_NONE,
+ WATERLEVEL_WETFEET,
+ WATERLEVEL_SWIMMING,
+ WATERLEVEL_SUBMERGED
+}
+waterlevel_t;
+
+typedef struct cl_clientmovement_state_s
+{
+ // position
+ vec3_t origin;
+ vec3_t velocity;
+ // current bounding box (different if crouched vs standing)
+ vec3_t mins;
+ vec3_t maxs;
+ // currently on the ground
+ qboolean onground;
+ // currently crouching
+ qboolean crouched;
+ // whether jump button has been released since last jump
+ qboolean canjump;
+ // what kind of water (SUPERCONTENTS_LAVA for instance)
+ int watertype;
+ // how deep
+ waterlevel_t waterlevel;
+ // weird hacks when jumping out of water
+ // (this is in seconds and counts down to 0)
+ float waterjumptime;
+
+ // movement parameters for physics code
+ float movevars_gravity;
+ float movevars_stopspeed;
+ float movevars_maxspeed;
+ float movevars_spectatormaxspeed;
+ float movevars_accelerate;
+ float movevars_airaccelerate;
+ float movevars_wateraccelerate;
+ float movevars_friction;
+ float movevars_waterfriction;
+ float movevars_entgravity;
+ float movevars_jumpvelocity;
+ float movevars_edgefriction;
+ float movevars_maxairspeed;
+ float movevars_stepheight;
+ float movevars_airaccel_qw;
+ float movevars_airaccel_sideways_friction;
+
+ // user command
+ client_movementqueue_t q;
+}
+cl_clientmovement_state_t;
+
+#define NUMOFFSETS 27
+static vec3_t offsets[NUMOFFSETS] =
+{
+// 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},
+};
+
+qboolean CL_ClientMovement_Unstick(cl_clientmovement_state_t *s)
+{
+ int i;
+ vec3_t neworigin;
+ for (i = 0;i < NUMOFFSETS;i++)
+ {
+ VectorAdd(offsets[i], s->origin, neworigin);
+ if (!CL_TraceBox(neworigin, cl.playercrouchmins, cl.playercrouchmaxs, neworigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true).startsolid)