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"};
#include "cl_collision.h"
+extern void V_CalcRefdef(void);
void CL_UpdatePrydonCursor(void)
{
vec3_t temp, scale;
// 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;
int n;
+ // remove stale queue items
+ n = cl.movement_numqueue;
+ cl.movement_numqueue = 0;
+ 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.integer && cl.movement_numqueue < (int)(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].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;
+ cl.movement_queue[cl.movement_numqueue].move[2] = cl.cmd.upmove;
+ cl.movement_queue[cl.movement_numqueue].jump = buttonjump;
+ cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch;
+ cl.movement_numqueue++;
+ }
+ 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 simulatedtime;
- double currenttime;
- double newtime;
double frametime;
double t;
vec_t wishspeed;
trace_t trace;
trace_t trace2;
trace_t trace3;
- // remove stale queue items
- n = cl.movement_numqueue;
- cl.movement_numqueue = 0;
- // calculate time to execute for
- currenttime = cl.mtime[0];
- simulatedtime = currenttime + 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]))
- {
- // add to input queue
- cl.movement_queue[cl.movement_numqueue].time = simulatedtime;
- 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;
- cl.movement_queue[cl.movement_numqueue].move[2] = cl.cmd.upmove;
- cl.movement_queue[cl.movement_numqueue].jump = buttonjump;
- cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch;
- cl.movement_numqueue++;
- }
+ if (!cl.movement_replay)
+ return;
+ cl.movement_replay = false;
+
// fetch current starting values
VectorCopy(cl_entities[cl.playerentity].state_current.origin, currentorigin);
VectorCopy(cl.mvelocity[0], currentvelocity);
// 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
- // 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++)
+
+ 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;
+ client_movementqueue_t *q = cl.movement_queue + bound(0, i, cl.movement_numqueue - 1);
+ frametime = q->frametime;
//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))
+ //if (frametime > 0)
{
- client_movementqueue_t *q = cl.movement_queue + i - 1;
if (q->crouch)
{
// wants to crouch, this always works...
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;
else
{
// walk
+ 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]);
currentvelocity[2] -= cl_gravity.value * frametime;
}
}
- if (i > 0 || (cl_movement.integer & 2))
- if (i < cl.movement_numqueue - 1 || (cl_movement.integer & 4))
+ //if (i < cl.movement_numqueue - 1 || (cl_movement.integer & 4))
{
if (crouch)
{
playermins = cl_playerstandmins;
playermaxs = cl_playerstandmaxs;
}
+ onground = false;
for (bump = 0, t = frametime;bump < 8 && VectorLength2(currentvelocity) > 0;bump++)
{
VectorMA(currentorigin, t, currentvelocity, neworigin);
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);
}
}
}
- //Con_Printf(" :%f\n", currenttime);
// store replay location
VectorCopy(cl.movement_origin, cl.movement_oldorigin);
VectorCopy(currentorigin, cl.movement_origin);
upmove = cl.cmd.upmove;
#endif
+ CL_UpdatePrydonCursor();
+
buf.maxsize = 128;
buf.cursize = 0;
buf.data = data;
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]);
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
}
// PROTOCOL_DARKPLACES6 = 67 bytes per packet
+ // PROTOCOL_DARKPLACES7 = 71 bytes per packet
// deliver the message
if (cls.demoplayback)
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)
{
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);