#include "quakedef.h"
#include "csprogs.h"
+#include "thread.h"
/*
===============================================================================
-void KeyDown (kbutton_t *b)
+static void KeyDown (kbutton_t *b)
{
int k;
const char *c;
b->state |= 1 + 2; // down + impulse down
}
-void KeyUp (kbutton_t *b)
+static void KeyUp (kbutton_t *b)
{
int k;
const char *c;
b->state |= 4; // impulse up
}
-void IN_KLookDown (void) {KeyDown(&in_klook);}
-void IN_KLookUp (void) {KeyUp(&in_klook);}
-void IN_MLookDown (void) {KeyDown(&in_mlook);}
-void IN_MLookUp (void)
+static void IN_KLookDown (void) {KeyDown(&in_klook);}
+static void IN_KLookUp (void) {KeyUp(&in_klook);}
+static void IN_MLookDown (void) {KeyDown(&in_mlook);}
+static void IN_MLookUp (void)
{
KeyUp(&in_mlook);
if ( !(in_mlook.state&1) && lookspring.value)
V_StartPitchDrift();
}
-void IN_UpDown(void) {KeyDown(&in_up);}
-void IN_UpUp(void) {KeyUp(&in_up);}
-void IN_DownDown(void) {KeyDown(&in_down);}
-void IN_DownUp(void) {KeyUp(&in_down);}
-void IN_LeftDown(void) {KeyDown(&in_left);}
-void IN_LeftUp(void) {KeyUp(&in_left);}
-void IN_RightDown(void) {KeyDown(&in_right);}
-void IN_RightUp(void) {KeyUp(&in_right);}
-void IN_ForwardDown(void) {KeyDown(&in_forward);}
-void IN_ForwardUp(void) {KeyUp(&in_forward);}
-void IN_BackDown(void) {KeyDown(&in_back);}
-void IN_BackUp(void) {KeyUp(&in_back);}
-void IN_LookupDown(void) {KeyDown(&in_lookup);}
-void IN_LookupUp(void) {KeyUp(&in_lookup);}
-void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
-void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
-void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
-void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
-void IN_MoverightDown(void) {KeyDown(&in_moveright);}
-void IN_MoverightUp(void) {KeyUp(&in_moveright);}
-
-void IN_SpeedDown(void) {KeyDown(&in_speed);}
-void IN_SpeedUp(void) {KeyUp(&in_speed);}
-void IN_StrafeDown(void) {KeyDown(&in_strafe);}
-void IN_StrafeUp(void) {KeyUp(&in_strafe);}
-
-void IN_AttackDown(void) {KeyDown(&in_attack);}
-void IN_AttackUp(void) {KeyUp(&in_attack);}
-
-void IN_UseDown(void) {KeyDown(&in_use);}
-void IN_UseUp(void) {KeyUp(&in_use);}
+static void IN_UpDown(void) {KeyDown(&in_up);}
+static void IN_UpUp(void) {KeyUp(&in_up);}
+static void IN_DownDown(void) {KeyDown(&in_down);}
+static void IN_DownUp(void) {KeyUp(&in_down);}
+static void IN_LeftDown(void) {KeyDown(&in_left);}
+static void IN_LeftUp(void) {KeyUp(&in_left);}
+static void IN_RightDown(void) {KeyDown(&in_right);}
+static void IN_RightUp(void) {KeyUp(&in_right);}
+static void IN_ForwardDown(void) {KeyDown(&in_forward);}
+static void IN_ForwardUp(void) {KeyUp(&in_forward);}
+static void IN_BackDown(void) {KeyDown(&in_back);}
+static void IN_BackUp(void) {KeyUp(&in_back);}
+static void IN_LookupDown(void) {KeyDown(&in_lookup);}
+static void IN_LookupUp(void) {KeyUp(&in_lookup);}
+static void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
+static void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
+static void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
+static void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
+static void IN_MoverightDown(void) {KeyDown(&in_moveright);}
+static void IN_MoverightUp(void) {KeyUp(&in_moveright);}
+
+static void IN_SpeedDown(void) {KeyDown(&in_speed);}
+static void IN_SpeedUp(void) {KeyUp(&in_speed);}
+static void IN_StrafeDown(void) {KeyDown(&in_strafe);}
+static void IN_StrafeUp(void) {KeyUp(&in_strafe);}
+
+static void IN_AttackDown(void) {KeyDown(&in_attack);}
+static void IN_AttackUp(void) {KeyUp(&in_attack);}
+
+static void IN_UseDown(void) {KeyDown(&in_use);}
+static void IN_UseUp(void) {KeyUp(&in_use);}
// LordHavoc: added 6 new buttons
-void IN_Button3Down(void) {KeyDown(&in_button3);}
-void IN_Button3Up(void) {KeyUp(&in_button3);}
-void IN_Button4Down(void) {KeyDown(&in_button4);}
-void IN_Button4Up(void) {KeyUp(&in_button4);}
-void IN_Button5Down(void) {KeyDown(&in_button5);}
-void IN_Button5Up(void) {KeyUp(&in_button5);}
-void IN_Button6Down(void) {KeyDown(&in_button6);}
-void IN_Button6Up(void) {KeyUp(&in_button6);}
-void IN_Button7Down(void) {KeyDown(&in_button7);}
-void IN_Button7Up(void) {KeyUp(&in_button7);}
-void IN_Button8Down(void) {KeyDown(&in_button8);}
-void IN_Button8Up(void) {KeyUp(&in_button8);}
-
-void IN_Button9Down(void) {KeyDown(&in_button9);}
-void IN_Button9Up(void) {KeyUp(&in_button9);}
-void IN_Button10Down(void) {KeyDown(&in_button10);}
-void IN_Button10Up(void) {KeyUp(&in_button10);}
-void IN_Button11Down(void) {KeyDown(&in_button11);}
-void IN_Button11Up(void) {KeyUp(&in_button11);}
-void IN_Button12Down(void) {KeyDown(&in_button12);}
-void IN_Button12Up(void) {KeyUp(&in_button12);}
-void IN_Button13Down(void) {KeyDown(&in_button13);}
-void IN_Button13Up(void) {KeyUp(&in_button13);}
-void IN_Button14Down(void) {KeyDown(&in_button14);}
-void IN_Button14Up(void) {KeyUp(&in_button14);}
-void IN_Button15Down(void) {KeyDown(&in_button15);}
-void IN_Button15Up(void) {KeyUp(&in_button15);}
-void IN_Button16Down(void) {KeyDown(&in_button16);}
-void IN_Button16Up(void) {KeyUp(&in_button16);}
-
-void IN_JumpDown (void) {KeyDown(&in_jump);}
-void IN_JumpUp (void) {KeyUp(&in_jump);}
-
-void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
+static void IN_Button3Down(void) {KeyDown(&in_button3);}
+static void IN_Button3Up(void) {KeyUp(&in_button3);}
+static void IN_Button4Down(void) {KeyDown(&in_button4);}
+static void IN_Button4Up(void) {KeyUp(&in_button4);}
+static void IN_Button5Down(void) {KeyDown(&in_button5);}
+static void IN_Button5Up(void) {KeyUp(&in_button5);}
+static void IN_Button6Down(void) {KeyDown(&in_button6);}
+static void IN_Button6Up(void) {KeyUp(&in_button6);}
+static void IN_Button7Down(void) {KeyDown(&in_button7);}
+static void IN_Button7Up(void) {KeyUp(&in_button7);}
+static void IN_Button8Down(void) {KeyDown(&in_button8);}
+static void IN_Button8Up(void) {KeyUp(&in_button8);}
+
+static void IN_Button9Down(void) {KeyDown(&in_button9);}
+static void IN_Button9Up(void) {KeyUp(&in_button9);}
+static void IN_Button10Down(void) {KeyDown(&in_button10);}
+static void IN_Button10Up(void) {KeyUp(&in_button10);}
+static void IN_Button11Down(void) {KeyDown(&in_button11);}
+static void IN_Button11Up(void) {KeyUp(&in_button11);}
+static void IN_Button12Down(void) {KeyDown(&in_button12);}
+static void IN_Button12Up(void) {KeyUp(&in_button12);}
+static void IN_Button13Down(void) {KeyDown(&in_button13);}
+static void IN_Button13Up(void) {KeyUp(&in_button13);}
+static void IN_Button14Down(void) {KeyDown(&in_button14);}
+static void IN_Button14Up(void) {KeyUp(&in_button14);}
+static void IN_Button15Down(void) {KeyDown(&in_button15);}
+static void IN_Button15Up(void) {KeyUp(&in_button15);}
+static void IN_Button16Down(void) {KeyDown(&in_button16);}
+static void IN_Button16Up(void) {KeyUp(&in_button16);}
+
+static void IN_JumpDown (void) {KeyDown(&in_jump);}
+static void IN_JumpUp (void) {KeyUp(&in_jump);}
+
+static void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
in_bestweapon_info_t in_bestweapon_info[IN_BESTWEAPON_MAX];
-void IN_BestWeapon_Register(const char *name, int impulse, int weaponbit, int activeweaponcode, int ammostat, int ammomin)
+static void IN_BestWeapon_Register(const char *name, int impulse, int weaponbit, int activeweaponcode, int ammostat, int ammomin)
{
int i;
for(i = 0; i < IN_BESTWEAPON_MAX && in_bestweapon_info[i].impulse; ++i)
IN_BestWeapon_Register("h", 226, HIT_MJOLNIR, HIT_MJOLNIR, STAT_CELLS, 0); // hipnotic mjolnir hammer
}
-void IN_BestWeapon_Register_f (void)
+static void IN_BestWeapon_Register_f (void)
{
if(Cmd_Argc() == 7)
{
}
}
-void IN_BestWeapon (void)
+static void IN_BestWeapon (void)
{
int i, n;
const char *t;
cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5","how much +speed multiplies keyboard turning speed"};
cvar_t cl_movement = {CVAR_SAVE, "cl_movement", "0", "enables clientside prediction of your player movement"};
+cvar_t cl_movement_replay = {0, "cl_movement_replay", "1", "use engine prediction"};
cvar_t cl_movement_nettimeout = {CVAR_SAVE, "cl_movement_nettimeout", "0.3", "stops predicting moves when server is lagging badly (avoids major performance problems), timeout in seconds"};
cvar_t cl_movement_minping = {CVAR_SAVE, "cl_movement_minping", "0", "whether to use prediction when ping is lower than this value in milliseconds"};
cvar_t cl_movement_track_canjump = {CVAR_SAVE, "cl_movement_track_canjump", "1", "track if the player released the jump key between two jumps to decide if he is able to jump or not; when off, this causes some \"sliding\" slightly above the floor when the jump key is held too long; if the mod allows repeated jumping by holding space all the time, this has to be set to zero too"};
cvar_t cl_nodelta = {0, "cl_nodelta", "0", "disables delta compression of non-player entities in QW network protocol"};
+cvar_t cl_csqc_generatemousemoveevents = {0, "cl_csqc_generatemousemoveevents", "1", "enables calls to CSQC_InputEvent with type 2, for compliance with EXT_CSQC spec"};
+
extern cvar_t v_flipped;
/*
Moves the local angle positions
================
*/
-void CL_AdjustAngles (void)
+static void CL_AdjustAngles (void)
{
float speed;
float up, down;
// allow mice or other external controllers to add to the move
IN_Move ();
+ // send mouse move to csqc
+ if (cl.csqc_loaded && cl_csqc_generatemousemoveevents.integer)
+ {
+ if (cl.csqc_wantsmousemove)
+ {
+ // event type 3 is a DP_CSQC thing
+ static int oldwindowmouse[2];
+ if (oldwindowmouse[0] != in_windowmouse_x || oldwindowmouse[1] != in_windowmouse_y)
+ {
+ CL_VM_InputEvent(3, in_windowmouse_x * vid_conwidth.integer / vid.width, in_windowmouse_y * vid_conheight.integer / vid.height);
+ oldwindowmouse[0] = in_windowmouse_x;
+ oldwindowmouse[1] = in_windowmouse_y;
+ }
+ }
+ else
+ {
+ if (in_mouse_x || in_mouse_y)
+ CL_VM_InputEvent(2, in_mouse_x * vid_conwidth.integer / vid.width, in_mouse_y * vid_conheight.integer / vid.height);
+ }
+ }
+
// apply m_accelerate if it is on
if(m_accelerate.value > 1)
{
}
else
{
- /*
- f = log(averagespeed);
- mi = log(mi);
- ma = log(ma);
- */
f = averagespeed;
- mi = mi;
- ma = ma;
f = (f - mi) / (ma - mi) * (m_accelerate.value - 1) + 1;
}
}
// if not in menu, apply mouse move to viewangles/movement
- if (!key_consoleactive && key_dest == key_game && !cl.csqc_wantsmousemove)
+ if (!key_consoleactive && key_dest == key_game && !cl.csqc_wantsmousemove && cl_prydoncursor.integer <= 0)
{
float modulatedsensitivity = sensitivity.value * cl.sensitivityscale;
- if (cl_prydoncursor.integer > 0)
- {
- // mouse interacting with the scene, mostly stationary view
- V_StopPitchDrift();
- cl.cmd.cursor_screen[0] += in_mouse_x * modulatedsensitivity / vid.width;
- cl.cmd.cursor_screen[1] += in_mouse_y * modulatedsensitivity / vid.height;
- }
- else if (in_strafe.state & 1)
+ if (in_strafe.state & 1)
{
// strafing mode, all looking is movement
V_StopPitchDrift();
}
}
else // don't pitch drift when csqc is controlling the mouse
+ {
+ // mouse interacting with the scene, mostly stationary view
V_StopPitchDrift();
+ // update prydon cursor
+ cl.cmd.cursor_screen[0] = in_windowmouse_x * 2.0 / vid.width - 1.0;
+ cl.cmd.cursor_screen[1] = in_windowmouse_y * 2.0 / vid.height - 1.0;
+ }
if(v_flipped.integer)
{
#include "cl_collision.h"
-void CL_UpdatePrydonCursor(void)
+static void CL_UpdatePrydonCursor(void)
{
vec3_t temp;
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);
}
-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;
- // 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;
-
- // user command
- usercmd_t cmd;
-}
-cl_clientmovement_state_t;
-
#define NUMOFFSETS 27
static vec3_t offsets[NUMOFFSETS] =
{
{-0.125, 0.125, -0.125}, { 0.125, 0.125, -0.125},
};
-qboolean CL_ClientMovement_Unstick(cl_clientmovement_state_t *s)
+static 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, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false).startsolid)
+ if (!CL_TraceBox(neworigin, cl.playercrouchmins, cl.playercrouchmaxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true).startsolid)
{
VectorCopy(neworigin, s->origin);
return true;
return false;
}
-void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s)
+static void CL_ClientMovement_UpdateStatus(cl_clientmovement_state_t *s)
{
+ vec_t f;
vec3_t origin1, origin2;
trace_t trace;
// low ceiling first
if (s->crouched)
{
- trace = CL_TraceBox(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ trace = CL_TraceBox(s->origin, cl.playerstandmins, cl.playerstandmaxs, s->origin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
if (!trace.startsolid)
s->crouched = false;
}
// 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] - 1); // -2 causes clientside doublejump bug at above 150fps, raising that to 300fps :)
- trace = CL_TraceBox(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;
+ trace = CL_TraceBox(origin1, s->mins, s->maxs, origin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
+ if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
+ {
+ s->onground = true;
+
+ // this code actually "predicts" an impact; so let's clip velocity first
+ f = DotProduct(s->velocity, trace.plane.normal);
+ if(f < 0) // only if moving downwards actually
+ VectorMA(s->velocity, -f, trace.plane.normal, s->velocity);
+ }
+ else
+ s->onground = false;
// set watertype/waterlevel
VectorSet(origin1, s->origin[0], s->origin[1], s->origin[2] + s->mins[2] + 1);
s->waterjumptime = 0;
}
-void CL_ClientMovement_Move(cl_clientmovement_state_t *s)
+static void CL_ClientMovement_Move(cl_clientmovement_state_t *s)
{
int bump;
double t;
for (bump = 0, t = s->cmd.frametime;bump < 8 && VectorLength2(s->velocity) > 0;bump++)
{
VectorMA(s->origin, t, s->velocity, neworigin);
- trace = CL_TraceBox(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ trace = CL_TraceBox(s->origin, s->mins, s->maxs, neworigin, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
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_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ trace2 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
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_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ trace3 = CL_TraceBox(currentorigin2, s->mins, s->maxs, neworigin2, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
//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)
}
-void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s)
+static void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s)
{
vec_t wishspeed;
vec_t f;
s->velocity[2] = 80;
else
{
- if (gamemode == GAME_NEXUIZ)
+ if (gamemode == GAME_NEXUIZ || gamemode == GAME_XONOTIC)
s->velocity[2] = 200;
else
s->velocity[2] = 100;
return a * pow(fabs(b / a), lerp);
}
-void CL_ClientMovement_Physics_CPM_PM_Aircontrol(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed)
+static void CL_ClientMovement_Physics_CPM_PM_Aircontrol(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed)
{
vec_t zspeed, speed, dot, k;
dot = DotProduct(s->velocity, wishdir);
if(dot > 0) { // we can't change direction while slowing down
- k *= cl.movevars_aircontrol*pow(dot, cl.movevars_aircontrol_power)*s->cmd.frametime;
+ k *= pow(dot, cl.movevars_aircontrol_power)*s->cmd.frametime;
+ speed = max(0, speed - cl.movevars_aircontrol_penalty * sqrt(max(0, 1 - dot*dot)) * k/32);
+ k *= cl.movevars_aircontrol;
VectorMAM(speed, s->velocity, k, wishdir, s->velocity);
VectorNormalize(s->velocity);
}
s->velocity[2] = zspeed;
}
-float CL_ClientMovement_Physics_AdjustAirAccelQW(float accelqw, float factor)
+static float CL_ClientMovement_Physics_AdjustAirAccelQW(float accelqw, float factor)
{
return
(accelqw < 0 ? -1 : +1)
bound(0.000001, 1 - (1 - fabs(accelqw)) * factor, 1);
}
-void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed, vec_t wishspeed0, vec_t accel, vec_t accelqw, vec_t sidefric, vec_t speedlimit)
+static void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed, vec_t wishspeed0, vec_t accel, vec_t accelqw, vec_t stretchfactor, vec_t sidefric, vec_t speedlimit)
{
vec_t vel_straight;
vec_t vel_z;
vec3_t vel_xy;
vec_t vel_xy_current;
vec_t vel_xy_backward, vel_xy_forward;
- qboolean speedclamp;
+ vec_t speedclamp;
- speedclamp = (accelqw < 0);
- if(speedclamp)
+ if(stretchfactor > 0)
+ speedclamp = stretchfactor;
+ else if(accelqw < 0)
+ speedclamp = 1;
+ else
+ speedclamp = -1; // no clamping
+
+ if(accelqw < 0)
accelqw = -accelqw;
if(cl.moveflags & MOVEFLAG_Q2AIRACCELERATE)
VectorMA(vel_perpend, vel_straight, wishdir, s->velocity);
- if(speedclamp)
+ if(speedclamp >= 0)
{
- vel_xy_current = min(VectorLength(s->velocity), vel_xy_forward);
- if(vel_xy_current > 0) // prevent division by zero
+ vec_t vel_xy_preclamp;
+ vel_xy_preclamp = VectorLength(s->velocity);
+ if(vel_xy_preclamp > 0) // prevent division by zero
{
- VectorNormalize(s->velocity);
- VectorScale(s->velocity, vel_xy_current, s->velocity);
+ vel_xy_current += (vel_xy_forward - vel_xy_current) * speedclamp;
+ if(vel_xy_current < vel_xy_preclamp)
+ VectorScale(s->velocity, (vel_xy_current / vel_xy_preclamp), s->velocity);
}
}
s->velocity[2] += vel_z;
}
-void CL_ClientMovement_Physics_PM_AirAccelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed)
+static void CL_ClientMovement_Physics_PM_AirAccelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed)
{
vec3_t curvel, wishvel, acceldir, curdir;
float addspeed, accelspeed, curspeed;
VectorMA( s->velocity, accelspeed, acceldir, s->velocity );
}
-void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
+static void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
{
vec_t friction;
vec_t wishspeed;
// released at least once since the last jump
if (s->cmd.jump)
{
- if (s->onground && (s->cmd.canjump || !cl_movement_track_canjump.integer)) // FIXME remove this cvar again when canjump logic actually works, or maybe keep it for mods that allow "pogo-ing"
+ if (s->onground && (s->cmd.canjump || !cl_movement_track_canjump.integer))
{
s->velocity[2] += cl.movevars_jumpvelocity;
s->onground = false;
VectorSet(neworigin2, s->origin[0] + s->velocity[0]*(16/f), s->origin[1] + s->velocity[1]*(16/f), s->origin[2] + s->mins[2]);
VectorSet(neworigin3, neworigin2[0], neworigin2[1], neworigin2[2] - 34);
if (cls.protocol == PROTOCOL_QUAKEWORLD)
- trace = CL_TraceBox(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ trace = CL_TraceBox(neworigin2, s->mins, s->maxs, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true);
else
- trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, false);
+ trace = CL_TraceLine(neworigin2, neworigin3, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY | SUPERCONTENTS_PLAYERCLIP, true, true, NULL, true, false);
if (trace.fraction == 1 && !trace.startsolid)
friction *= cl.movevars_edgefriction;
}
// CPM: air control
if(cl.movevars_airstopaccelerate != 0)
- if(DotProduct(s->velocity, wishdir) < 0)
- accel = cl.movevars_airstopaccelerate;
+ {
+ vec3_t curdir;
+ curdir[0] = s->velocity[0];
+ curdir[1] = s->velocity[1];
+ curdir[2] = 0;
+ VectorNormalize(curdir);
+ accel = accel + (cl.movevars_airstopaccelerate - accel) * max(0, -DotProduct(curdir, wishdir));
+ }
strafity = CL_IsMoveInDirection(s->cmd.forwardmove, s->cmd.sidemove, -90) + CL_IsMoveInDirection(s->cmd.forwardmove, s->cmd.sidemove, +90); // if one is nonzero, other is always zero
if(cl.movevars_maxairstrafespeed)
wishspeed = min(wishspeed, CL_GeomLerp(cl.movevars_maxairspeed, strafity, cl.movevars_maxairstrafespeed));
if(cl.movevars_warsowbunny_turnaccel && accelerating && s->cmd.sidemove == 0 && s->cmd.forwardmove != 0)
CL_ClientMovement_Physics_PM_AirAccelerate(s, wishdir, wishspeed2);
else
- CL_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, wishspeed0, accel, accelqw, cl.movevars_airaccel_sideways_friction / cl.movevars_maxairspeed, cl.movevars_airspeedlimit_nonqw);
+ CL_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, wishspeed0, accel, accelqw, cl.movevars_airaccel_qw_stretchfactor, cl.movevars_airaccel_sideways_friction / cl.movevars_maxairspeed, cl.movevars_airspeedlimit_nonqw);
if(cl.movevars_aircontrol)
CL_ClientMovement_Physics_CPM_PM_Aircontrol(s, wishdir, wishspeed2);
}
}
-void CL_ClientMovement_PlayerMove(cl_clientmovement_state_t *s)
+static void CL_ClientMovement_PlayerMove(cl_clientmovement_state_t *s)
{
//Con_Printf(" %f", frametime);
if (!s->cmd.jump)
cl.movevars_maxairspeed = cl.statsf[STAT_MOVEVARS_MAXAIRSPEED];
cl.movevars_stepheight = cl.statsf[STAT_MOVEVARS_STEPHEIGHT];
cl.movevars_airaccel_qw = cl.statsf[STAT_MOVEVARS_AIRACCEL_QW];
+ cl.movevars_airaccel_qw_stretchfactor = cl.statsf[STAT_MOVEVARS_AIRACCEL_QW_STRETCHFACTOR];
cl.movevars_airaccel_sideways_friction = cl.statsf[STAT_MOVEVARS_AIRACCEL_SIDEWAYS_FRICTION];
cl.movevars_friction = cl.statsf[STAT_MOVEVARS_FRICTION];
cl.movevars_wallfriction = cl.statsf[STAT_MOVEVARS_WALLFRICTION];
cl.movevars_airstrafeaccel_qw = cl.statsf[STAT_MOVEVARS_AIRSTRAFEACCEL_QW];
cl.movevars_aircontrol = cl.statsf[STAT_MOVEVARS_AIRCONTROL];
cl.movevars_aircontrol_power = cl.statsf[STAT_MOVEVARS_AIRCONTROL_POWER];
+ cl.movevars_aircontrol_penalty = cl.statsf[STAT_MOVEVARS_AIRCONTROL_PENALTY];
cl.movevars_warsowbunny_airforwardaccel = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL];
cl.movevars_warsowbunny_accel = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_ACCEL];
cl.movevars_warsowbunny_topspeed = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED];
cl.movevars_maxairspeed = cl_movement_maxairspeed.value;
cl.movevars_stepheight = cl_movement_stepheight.value;
cl.movevars_airaccel_qw = cl_movement_airaccel_qw.value;
+ cl.movevars_airaccel_qw_stretchfactor = 0;
cl.movevars_airaccel_sideways_friction = cl_movement_airaccel_sideways_friction.value;
cl.movevars_airstopaccelerate = 0;
cl.movevars_airstrafeaccelerate = 0;
cl.movevars_airstrafeaccel_qw = 0;
cl.movevars_aircontrol = 0;
cl.movevars_aircontrol_power = 2;
+ cl.movevars_aircontrol_penalty = 0;
cl.movevars_warsowbunny_airforwardaccel = 0;
cl.movevars_warsowbunny_accel = 0;
cl.movevars_warsowbunny_topspeed = 0;
cl.movevars_aircontrol_power = 2; // CPMA default
}
+void CL_ClientMovement_PlayerMove_Frame(cl_clientmovement_state_t *s)
+{
+ // if a move is more than 50ms, do it as two moves (matching qwsv)
+ //Con_Printf("%i ", s.cmd.msec);
+ if(s->cmd.frametime > 0.0005)
+ {
+ if (s->cmd.frametime > 0.05)
+ {
+ s->cmd.frametime /= 2;
+ CL_ClientMovement_PlayerMove(s);
+ }
+ CL_ClientMovement_PlayerMove(s);
+ }
+ else
+ {
+ // we REALLY need this handling to happen, even if the move is not executed
+ if (!s->cmd.jump)
+ s->cmd.canjump = true;
+ }
+}
+
void CL_ClientMovement_Replay(void)
{
int i;
double totalmovemsec;
cl_clientmovement_state_t s;
+ VectorCopy(cl.mvelocity[0], cl.movement_velocity);
+
if (cl.movement_predicted && !cl.movement_replay)
return;
+ if (!cl_movement_replay.integer)
+ return;
+
// set up starting state for the series of moves
memset(&s, 0, sizeof(s));
VectorCopy(cl.entities[cl.playerentity].state_current.origin, s.origin);
s.cmd = cl.movecmd[i];
if (i < CL_MAX_USERCMDS - 1)
s.cmd.canjump = cl.movecmd[i+1].canjump;
- // if a move is more than 50ms, do it as two moves (matching qwsv)
- //Con_Printf("%i ", s.cmd.msec);
- if(s.cmd.frametime > 0.0005)
- {
- if (s.cmd.frametime > 0.05)
- {
- s.cmd.frametime /= 2;
- CL_ClientMovement_PlayerMove(&s);
- }
- CL_ClientMovement_PlayerMove(&s);
- cl.movecmd[i].canjump = s.cmd.canjump;
- }
+
+ CL_ClientMovement_PlayerMove_Frame(&s);
+
+ cl.movecmd[i].canjump = s.cmd.canjump;
}
//Con_Printf("\n");
CL_ClientMovement_UpdateStatus(&s);
s.cmd = cl.movecmd[0];
}
- if (cls.demoplayback) // for bob, speedometer
- VectorCopy(cl.mvelocity[0], cl.movement_velocity);
- else
+ if (!cls.demoplayback) // for bob, speedometer
{
cl.movement_replay = false;
// update the interpolation target position and velocity
if (s.onground)
cl.onground = true;
}
-
- // react to onground state changes (for gun bob)
- if (cl.onground)
- {
- if (!cl.oldonground)
- cl.hitgroundtime = cl.movecmd[0].time;
- cl.lastongroundtime = cl.movecmd[0].time;
- }
- cl.oldonground = cl.onground;
}
-void QW_MSG_WriteDeltaUsercmd(sizebuf_t *buf, usercmd_t *from, usercmd_t *to)
+static void QW_MSG_WriteDeltaUsercmd(sizebuf_t *buf, usercmd_t *from, usercmd_t *to)
{
int bits;
cl.latestframenumsposition = (cl.latestframenumsposition + 1) % LATESTFRAMENUMS;
}
+void CL_RotateMoves(const matrix4x4_t *m)
+{
+ // rotate viewangles in all previous moves
+ vec3_t v;
+ vec3_t f, r, u;
+ int i;
+ for (i = 0;i < CL_MAX_USERCMDS;i++)
+ {
+ if (cl.movecmd[i].sequence > cls.servermovesequence)
+ {
+ usercmd_t *c = &cl.movecmd[i];
+ AngleVectors(c->viewangles, f, r, u);
+ Matrix4x4_Transform(m, f, v); VectorCopy(v, f);
+ Matrix4x4_Transform(m, u, v); VectorCopy(v, u);
+ AnglesFromVectors(c->viewangles, f, u, false);
+ }
+ }
+}
+
/*
==============
CL_SendMove
if (in_button16.state & 3) bits |= 262144;
// button bits 19-31 unused currently
// rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen
- if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
- if (cl.cmd.cursor_screen[0] >= 1) bits |= 16;
- if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
- if (cl.cmd.cursor_screen[1] >= 1) bits |= 64;
+ if(cl_prydoncursor.integer > 0)
+ {
+ if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
+ if (cl.cmd.cursor_screen[0] >= 1) bits |= 16;
+ if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
+ if (cl.cmd.cursor_screen[1] >= 1) bits |= 64;
+ }
// set buttons and impulse
cl.cmd.buttons = bits;
break;
case PROTOCOL_DARKPLACES6:
case PROTOCOL_DARKPLACES7:
- // FIXME: cl.cmd.buttons & 16 is +button5, Nexuiz specific
+ // FIXME: cl.cmd.buttons & 16 is +button5, Nexuiz/Xonotic specific
cl.cmd.crouch = (cl.cmd.buttons & 16) != 0;
break;
case PROTOCOL_UNKNOWN:
// 5 bytes
MSG_WriteByte (&buf, clc_move);
MSG_WriteFloat (&buf, cl.cmd.time); // last server packet time
- // 3 bytes
- for (i = 0;i < 3;i++)
- MSG_WriteAngle8i (&buf, cl.cmd.viewangles[i]);
+ // 3 bytes (6 bytes in proquake)
+ if (cls.proquake_servermod == 1) // MOD_PROQUAKE
+ {
+ for (i = 0;i < 3;i++)
+ MSG_WriteAngle16i (&buf, cl.cmd.viewangles[i]);
+ }
+ else
+ {
+ for (i = 0;i < 3;i++)
+ MSG_WriteAngle8i (&buf, cl.cmd.viewangles[i]);
+ }
// 6 bytes
MSG_WriteCoord16i (&buf, cl.cmd.forwardmove);
MSG_WriteCoord16i (&buf, cl.cmd.sidemove);
{
Con_Print("CL_SendMove: lost server connection\n");
CL_Disconnect();
+ SV_LockThreadMutex();
Host_ShutdownServer();
+ SV_UnlockThreadMutex();
}
}
Cvar_RegisterVariable(&cl_movecliptokeyboard);
Cvar_RegisterVariable(&cl_movement);
+ Cvar_RegisterVariable(&cl_movement_replay);
Cvar_RegisterVariable(&cl_movement_nettimeout);
Cvar_RegisterVariable(&cl_movement_minping);
Cvar_RegisterVariable(&cl_movement_track_canjump);
Cvar_RegisterVariable(&cl_netimmediatebuttons);
Cvar_RegisterVariable(&cl_nodelta);
+
+ Cvar_RegisterVariable(&cl_csqc_generatemousemoveevents);
}