From 0547ceb3b0a2bbfbcec9c5dc76d4cba83df490ed Mon Sep 17 00:00:00 2001 From: TimePath Date: Sun, 7 Dec 2014 22:29:35 +1100 Subject: [PATCH] Initial translation --- qcsrc/client/movetypes.qc | 1 - qcsrc/client/movetypes.qh | 19 +- qcsrc/csqcmodellib/cl_player.qc | 636 +++++++++++++++++++++++++++++++- 3 files changed, 647 insertions(+), 9 deletions(-) diff --git a/qcsrc/client/movetypes.qc b/qcsrc/client/movetypes.qc index b536797ce..170d33b99 100644 --- a/qcsrc/client/movetypes.qc +++ b/qcsrc/client/movetypes.qc @@ -1,4 +1,3 @@ -const float MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4; #define GRAVITY_UNAFFECTED_BY_TICRATE (getstati(STAT_MOVEFLAGS) & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) .entity move_groundentity; // FIXME add move_groundnetworkentity? diff --git a/qcsrc/client/movetypes.qh b/qcsrc/client/movetypes.qh index 287226e53..9908698c1 100644 --- a/qcsrc/client/movetypes.qh +++ b/qcsrc/client/movetypes.qh @@ -21,7 +21,7 @@ void Movetype_Physics_MatchServer(float sloppy); void Movetype_Physics_NoMatchServer(); const float MOVETYPE_NONE = 0; -const float MOVETYPE_ANGLENOCLIP = 1; +const float MOVETYPE_ANGLENOCLIP = 1; const float MOVETYPE_ANGLECLIP = 2; const float MOVETYPE_WALK = 3; const float MOVETYPE_STEP = 4; @@ -31,10 +31,15 @@ const float MOVETYPE_PUSH = 7; const float MOVETYPE_NOCLIP = 8; const float MOVETYPE_FLYMISSILE = 9; const float MOVETYPE_BOUNCE = 10; -const float MOVETYPE_BOUNCEMISSILE = 11; // Like bounce but doesn't lose speed on bouncing -const float MOVETYPE_FOLLOW = 12; -const float MOVETYPE_FAKEPUSH = 13; -const float MOVETYPE_FLY_WORLDONLY = 33; +const float MOVETYPE_BOUNCEMISSILE = 11; // Like bounce but doesn't lose speed on bouncing +const float MOVETYPE_FOLLOW = 12; +const float MOVETYPE_FAKEPUSH = 13; +const float MOVETYPE_FLY_WORLDONLY = 33; -const float FL_ITEM = 256; -const float FL_ONGROUND = 512; +const float FL_ITEM = 256; +const float FL_ONGROUND = 512; + +const float MOVEFLAG_Q2AIRACCELERATE = 1; +const float MOVEFLAG_NOGRAVITYONGROUND = 2; +const float MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE = 4; +#define moveflags (getstati(STAT_MOVEFLAGS)) \ No newline at end of file diff --git a/qcsrc/csqcmodellib/cl_player.qc b/qcsrc/csqcmodellib/cl_player.qc index 4f7381a4a..d9b2ac176 100644 --- a/qcsrc/csqcmodellib/cl_player.qc +++ b/qcsrc/csqcmodellib/cl_player.qc @@ -119,6 +119,640 @@ void CSQCPlayer_SavePrediction() csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED; } +// TODO: replace cvar("cl_movement_"...) with getstatf(STAT_MOVEVARS_...) +// TODO: cls.protocol == PROTOCOL_QUAKEWORLD ? +// TODO: water prediction +float pmove_waterjumptime; // weird engine flag we shouldn't really use but have to for now +// TODO: move to a common header +#define vlen2(v) dotproduct(v, v) +void AngleVectors (vector angles, vector forward, vector right, vector up) +{ + float angle, sr, sp, sy, cr, cp, cy; + + angle = angles_y * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles_x * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + if (forward) + { + forward_x = cp*cy; + forward_y = cp*sy; + forward_z = -sp; + } + if (right || up) + { + if (angles_z) + { + angle = angles_z * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + if (right) + { + right_x = -1*(sr*sp*cy+cr*-sy); + right_y = -1*(sr*sp*sy+cr*cy); + right_z = -1*(sr*cp); + } + if (up) + { + up_x = (cr*sp*cy+-sr*-sy); + up_y = (cr*sp*sy+-sr*cy); + up_z = cr*cp; + } + } + else + { + if (right) + { + right_x = sy; + right_y = -cy; + right_z = 0; + } + if (up) + { + up_x = (sp*cy); + up_y = (sp*sy); + up_z = cp; + } + } + } +} + +// TODO: move these elsewhere +vector cl_playerstandmins = '-16 -16 -24'; +vector cl_playerstandmaxs = '16 16 45'; +vector cl_playercrouchmins = '-16 -16 -24'; +vector cl_playercrouchmaxs = '16 16 25'; + +const float unstick_count = 27; +vector unstick_offsets[unstick_count] = +{ +// 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', +}; + +float CSQC_ClientMovement_Unstick(entity s) +{ + float i; + vector neworigin; + for (i = 0; i < unstick_count; i++) + { + neworigin = unstick_offsets[i] + s.origin; + tracebox(neworigin, cl_playercrouchmins, cl_playercrouchmaxs, neworigin, MOVE_NORMAL, s); + if (!trace_startsolid) + { + s.origin = neworigin; + return true; + } + } + // if all offsets failed, give up + return false; +} + +void CSQC_ClientMovement_UpdateStatus(entity s) +{ + float f; + vector origin1, origin2; + + // make sure player is not stuck + CSQC_ClientMovement_Unstick(s); + + // set crouched + if (input_buttons & 16) + { + // wants to crouch, this always works.. + if (!s.pmove_flags & PMF_DUCKED) + s.pmove_flags |= PMF_DUCKED; + } + else + { + // wants to stand, if currently crouching we need to check for a + // low ceiling first + if (s.pmove_flags & PMF_DUCKED) + { + tracebox(s.origin, cl_playerstandmins, cl_playerstandmaxs, s.origin, MOVE_NORMAL, s); + if (!trace_startsolid) + s.pmove_flags &= ~PMF_DUCKED; + } + } + if (s.pmove_flags & PMF_DUCKED) + { + s.mins = cl_playercrouchmins; + s.maxs = cl_playercrouchmaxs; + } + else + { + s.mins = cl_playerstandmins; + s.maxs = cl_playerstandmaxs; + } + + // set onground + origin1 = s.origin; + origin1_z += 1; + origin2 = s.origin; + origin2_z -= 1; // -2 causes clientside doublejump bug at above 150fps, raising that to 300fps :) + + tracebox(origin1, s.mins, s.maxs, origin2, MOVE_NORMAL, s); + if(trace_fraction < 1 && trace_plane_normal_z > 0.7) + { + s.pmove_flags |= PMF_ONGROUND; + + // 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 + s.velocity -= f * trace_plane_normal; + } + else + s.pmove_flags &= ~PMF_ONGROUND; // onground = false; + + // set watertype/waterlevel + origin1 = s.origin; + origin1_z += s.mins_z + 1; + s.waterlevel = WATERLEVEL_NONE; + // TODO: convert +// s.watertype = CL_TracePoint(origin1, MOVE_NOMONSTERS, s, 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_TracePoint(origin1, MOVE_NOMONSTERS, s, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) +// { +// s.waterlevel = WATERLEVEL_SWIMMING; +// origin1[2] = s.origin[2] + 22; +// if (CL_TracePoint(origin1, MOVE_NOMONSTERS, s, 0, true, false, NULL, false).startsupercontents & SUPERCONTENTS_LIQUIDSMASK) +// s.waterlevel = WATERLEVEL_SUBMERGED; +// } +// } +// +// // water jump prediction +// if ((s.pmove_flags & PMF_ONGROUND) || s.velocity_z <= 0 || pmove_waterjumptime <= 0) +// pmove_waterjumptime = 0; +} + +void CSQC_ClientMovement_Move(entity s) +{ + float bump; + float t; + float f; + vector neworigin; + vector currentorigin2; + vector neworigin2; + vector primalvelocity; + float old_trace1_fraction; + vector old_trace1_endpos; + vector old_trace1_plane_normal; + float old_trace2_fraction; + vector old_trace2_plane_normal; + CSQC_ClientMovement_UpdateStatus(s); + primalvelocity = s.velocity; + for (bump = 0, t = input_timelength; bump < 8 && vlen2(s.velocity) > 0; bump++) + { + neworigin = s.origin + t * s.velocity; + tracebox(s.origin, s.mins, s.maxs, neworigin, MOVE_NORMAL, s); + old_trace1_fraction = trace_fraction; + old_trace1_endpos = trace_endpos; + old_trace1_plane_normal = trace_plane_normal; + if (trace_fraction < 1 && trace_plane_normal_z == 0) + { + // may be a step or wall, try stepping up + // first move forward at a higher level + currentorigin2 = s.origin; + currentorigin2_z += cvar("cl_movement_stepheight"); + neworigin2 = neworigin; + neworigin2_z = s.origin_z + cvar("cl_movement_stepheight"); + tracebox(currentorigin2, s.mins, s.maxs, neworigin2, MOVE_NORMAL, s); + if (!trace_startsolid) + { + // then move down from there + currentorigin2 = trace_endpos; + neworigin2 = trace_endpos; + neworigin2_z = s.origin_z; + old_trace2_fraction = trace_fraction; + old_trace2_plane_normal = trace_plane_normal; + tracebox(currentorigin2, s.mins, s.maxs, neworigin2, MOVE_NORMAL, s); + //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(trace_endpos_x - old_trace1_endpos_x) >= 0.03125 || fabs(trace_endpos_y - old_trace1_endpos_y) >= 0.03125) + { + trace_fraction = old_trace2_fraction; + trace_endpos = trace_endpos; + trace_plane_normal = old_trace2_plane_normal; + } + else + { + trace_fraction = old_trace1_fraction; + trace_endpos = old_trace1_endpos; + trace_plane_normal = old_trace1_plane_normal; + } + } + } + + // check if it moved at all + if (trace_fraction >= 0.001) + s.origin = trace_endpos; + + // check if it moved all the way + if (trace_fraction == 1) + break; + + // this is only really needed for nogravityonground combined with gravityunaffectedbyticrate + // I'm pretty sure I commented it out solely because it seemed redundant + // this got commented out in a change that supposedly makes the code match QW better + // so if this is broken, maybe put it in an if(cls.protocol != PROTOCOL_QUAKEWORLD) block + if (trace_plane_normal_z > 0.7) + s.pmove_flags |= PMF_ONGROUND; + + t -= t * trace_fraction; + + f = dotproduct(s.velocity, trace_plane_normal); + s.velocity -= f * trace_plane_normal; + } + if (pmove_waterjumptime > 0) + s.velocity = primalvelocity; +} + +float CSQC_IsMoveInDirection(float forward, float side, float angle) +{ + // TODO: move to a common header + #define RAD2DEG(a) ((a) * (180.0f / M_PI)) + #define ANGLEMOD(a) ((a) - 360.0 * floor((a) / 360.0)) + if(forward == 0 && side == 0) + return 0; // avoid division by zero + angle -= RAD2DEG(atan2(side, forward)); + angle = (ANGLEMOD(angle + 180) - 180) / 45; + if(angle > 1) + return 0; + if(angle < -1) + return 0; + return 1 - fabs(angle); + #undef RAD2DEG + #undef ANGLEMOD +} + +float CSQC_GeomLerp(float a, float lerp, float b) +{ + if(a == 0) + { + if(lerp < 1) + return 0; + else + return b; + } + if(b == 0) + { + if(lerp > 0) + return 0; + else + return a; + } + return a * pow(fabs(b / a), lerp); +} + +void CSQC_ClientMovement_Physics_CPM_PM_Aircontrol(entity s, vector wishdir, float wishspeed) +{ + float zspeed, speed, dot, k; + + k = 32 * (2 * CSQC_IsMoveInDirection(input_movevalues_x, input_movevalues_y, 0) - 1); + if(k <= 0) + return; + + k *= bound(0, wishspeed / cvar("cl_movement_maxairspeed"), 1); + + zspeed = s.velocity_z; + s.velocity_z = 0; + speed = vlen(s.velocity); + if (speed) s.velocity /= speed; + + dot = dotproduct(s.velocity, wishdir); + + if(dot > 0) { // we can't change direction while slowing down + k *= pow(dot, cvar("cl_movement_aircontrol_power"))*input_timelength; + speed = max(0, speed - cvar("cl_movement_aircontrol_penalty") * sqrt(max(0, 1 - dot*dot)) * k/32); + k *= cvar("cl_movement_aircontrol"); + s.velocity = speed * s.velocity + k * wishdir; + s.velocity = normalize(s.velocity); + } + + s.velocity *= speed; + s.velocity_z = zspeed; +} + +float CSQC_ClientMovement_Physics_AdjustAirAccelQW(float accelqw, float factor) +{ + return + (accelqw < 0 ? -1 : +1) + * + bound(0.000001, 1 - (1 - fabs(accelqw)) * factor, 1); +} + +void CSQC_ClientMovement_Physics_PM_Accelerate(entity s, vector wishdir, float wishspeed, float wishspeed0, float accel, float accelqw, float stretchfactor, float sidefric, float speedlimit) +{ + float vel_straight; + float vel_z; + vector vel_perpend; + float step; + vector vel_xy; + float vel_xy_current; + float vel_xy_backward, vel_xy_forward; + float speedclamp; + + if(stretchfactor > 0) + speedclamp = stretchfactor; + else if(accelqw < 0) + speedclamp = 1; + else + speedclamp = -1; // no clamping + + if(accelqw < 0) + accelqw = -accelqw; + + if(moveflags & MOVEFLAG_Q2AIRACCELERATE) + wishspeed0 = wishspeed; // don't need to emulate this Q1 bug + + vel_straight = dotproduct(s.velocity, wishdir); + vel_z = s.velocity_z; + vel_xy = s.velocity; + vel_xy_z -= vel_z; + vel_perpend = vel_xy - vel_straight * wishdir; + + step = accel * input_timelength * wishspeed0; + + vel_xy_current = vlen(vel_xy); + if(speedlimit > 0) + accelqw = CSQC_ClientMovement_Physics_AdjustAirAccelQW(accelqw, (speedlimit - bound(wishspeed, vel_xy_current, speedlimit)) / max(1, speedlimit - wishspeed)); + vel_xy_forward = vel_xy_current + bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw); + vel_xy_backward = vel_xy_current - bound(0, wishspeed + vel_xy_current, step) * accelqw - step * (1 - accelqw); + if(vel_xy_backward < 0) + vel_xy_backward = 0; // not that it REALLY occurs that this would cause wrong behaviour afterwards + + vel_straight = vel_straight + bound(0, wishspeed - vel_straight, step) * accelqw + step * (1 - accelqw); + + if(sidefric < 0 && vlen2(vel_perpend)) + // negative: only apply so much sideways friction to stay below the speed you could get by "braking" + { + float f, fmin; + f = max(0, 1 + input_timelength * wishspeed * sidefric); + fmin = (vel_xy_backward*vel_xy_backward - vel_straight*vel_straight) / vlen2(vel_perpend); + // assume: fmin > 1 + // vel_xy_backward*vel_xy_backward - vel_straight*vel_straight > vel_perpend*vel_perpend + // vel_xy_backward*vel_xy_backward > vel_straight*vel_straight + vel_perpend*vel_perpend + // vel_xy_backward*vel_xy_backward > vel_xy * vel_xy + // obviously, this cannot be + if(fmin <= 0) + vel_perpend *= f; + else + { + fmin = sqrt(fmin); + vel_perpend *= max(fmin, f); + } + } + else + vel_perpend *= max(0, 1 - input_timelength * wishspeed * sidefric); + + s.velocity = vel_perpend + vel_straight * wishdir; + + if(speedclamp >= 0) + { + float vel_xy_preclamp; + vel_xy_preclamp = vlen(s.velocity); + if(vel_xy_preclamp > 0) // prevent division by zero + { + vel_xy_current += (vel_xy_forward - vel_xy_current) * speedclamp; + if(vel_xy_current < vel_xy_preclamp) + s.velocity *= (vel_xy_current / vel_xy_preclamp); + } + } + + s.velocity_z += vel_z; +} + +void CSQC_ClientMovement_Physics_Walk(entity s) +{ + float friction; + float wishspeed; + float addspeed; + float accelspeed; + float f; + float gravity; + vector forward = '0 0 0'; + vector right = '0 0 0'; + vector up = '0 0 0'; + vector wishvel; + vector wishdir; + vector yawangles; + + // jump if on ground with jump button pressed but only if it has been + // released at least once since the last jump + if (input_buttons & 2) + { + if ((s.pmove_flags & PMF_ONGROUND) && ((s.pmove_flags & PMF_JUMP_HELD) == 0 || !cvar("cl_movement_track_canjump"))) + { + s.velocity_z += cvar("cl_movement_jumpvelocity"); + s.pmove_flags &= ~PMF_ONGROUND; + s.pmove_flags |= PMF_JUMP_HELD; // canjump = false + } + } + else + s.pmove_flags &= ~PMF_JUMP_HELD; // canjump = true + + // calculate movement vector + yawangles = '0 0 0'; + yawangles_y = input_angles_y; + AngleVectors(yawangles, forward, right, up); + wishvel = input_movevalues_x * forward + input_movevalues_y * right; + + // split wishvel into wishspeed and wishdir + wishspeed = vlen(wishvel); + if (wishspeed) + wishdir = wishvel / wishspeed; + else + wishdir = '0 0 0'; + // check if onground + if ((s.pmove_flags & PMF_ONGROUND)) + { + wishspeed = min(wishspeed, cvar("cl_movement_maxspeed")); + if (s.pmove_flags & PMF_DUCKED) + wishspeed *= 0.5; + + // apply edge friction + f = sqrt(s.velocity_x * s.velocity_x + s.velocity_y * s.velocity_y); + if (f > 0) + { + friction = cvar("cl_movement_friction"); + if (cvar("cl_movement_edgefriction") != 1) + { + vector neworigin2; + vector neworigin3; + // note: QW uses the full player box for the trace, and yet still + // uses s.origin_z + s.mins_z, which is clearly an bug, but + // this mimics it for compatibility + neworigin2 = s.origin; + neworigin2_x += s.velocity_x*(16/f); + neworigin2_y += s.velocity_y*(16/f); + neworigin2_z += s.mins_z; + neworigin3 = neworigin2; + neworigin3_z -= 34; +// if (cls.protocol == PROTOCOL_QUAKEWORLD) + tracebox(neworigin2, s.mins, s.maxs, neworigin3, MOVE_NORMAL, s); +// else +// traceline(neworigin2, neworigin3, MOVE_NORMAL, s); + if (trace_fraction == 1 && !trace_startsolid) + friction *= cvar("cl_movement_edgefriction"); + } + // apply ground friction + f = 1 - input_timelength * friction * ((f < cvar("cl_movement_stopspeed")) ? (cvar("cl_movement_stopspeed") / f) : 1); + f = max(f, 0); + s.velocity *= f; + } + addspeed = wishspeed - dotproduct(s.velocity, wishdir); + if (addspeed > 0) + { + accelspeed = min(cvar("cl_movement_accelerate") * input_timelength * wishspeed, addspeed); + s.velocity += accelspeed * wishdir; + } + gravity = cvar("cl_movement_gravity") * cvar("cl_movement_entgravity") * input_timelength; + if(!(moveflags & MOVEFLAG_NOGRAVITYONGROUND)) + { + if(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s.velocity_z -= gravity * 0.5; + else + s.velocity_z -= gravity; + } +// if (cls.protocol == PROTOCOL_QUAKEWORLD) + s.velocity_z = 0; + if (vlen2(s.velocity)) + CSQC_ClientMovement_Move(s); + if(!(moveflags & MOVEFLAG_NOGRAVITYONGROUND) || !(s.pmove_flags & PMF_ONGROUND)) + { + if(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s.velocity_z -= gravity * 0.5; + } + } + else + { + if (pmove_waterjumptime <= 0) + { + // apply air speed limit + float accel, wishspeed0, wishspeed2, accelqw, strafity; + float accelerating; + + accelqw = cvar("cl_movement_airaccel_qw"); + wishspeed0 = wishspeed; + wishspeed = min(wishspeed, cvar("cl_movement_maxairspeed")); + if (s.pmove_flags & PMF_DUCKED) + wishspeed *= 0.5; + accel = cvar("cl_movement_airaccelerate"); + + accelerating = (dotproduct(s.velocity, wishdir) > 0); + wishspeed2 = wishspeed; + + // CPM: air control + if(cvar("cl_movement_airstopaccelerate") != 0) + { + vector curdir; + curdir_x = s.velocity_x; + curdir_y = s.velocity_y; + curdir_z = 0; + curdir = normalize(curdir); + accel = accel + (cvar("cl_movement_airstopaccelerate") - accel) * max(0, -dotproduct(curdir, wishdir)); + } + strafity = CSQC_IsMoveInDirection(input_movevalues_x, input_movevalues_y, -90) + CSQC_IsMoveInDirection(input_movevalues_x, input_movevalues_y, +90); // if one is nonzero, other is always zero + if(cvar("cl_movement_maxairstrafespeed")) + wishspeed = min(wishspeed, CSQC_GeomLerp(cvar("cl_movement_maxairspeed"), strafity, cvar("cl_movement_maxairstrafespeed"))); + if(cvar("cl_movement_airstrafeaccelerate")) + accel = CSQC_GeomLerp(cvar("cl_movement_airaccelerate"), strafity, cvar("cl_movement_airstrafeaccelerate")); + if(cvar("cl_movement_airstrafeaccel_qw")) + accelqw = + (((strafity > 0.5 ? cvar("cl_movement_airstrafeaccel_qw") : cvar("cl_movement_airaccel_qw")) >= 0) ? +1 : -1) + * + (1 - CSQC_GeomLerp(1 - fabs(cvar("cl_movement_airaccel_qw")), strafity, 1 - fabs(cvar("cl_movement_airstrafeaccel_qw")))); + // !CPM + +// if(cvar("cl_movement_warsowbunny_turnaccel") && accelerating && input_movevalues_y == 0 && input_movevalues_x != 0) +// CSQC_ClientMovement_Physics_PM_AirAccelerate(s, wishdir, wishspeed2); +// else + CSQC_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, wishspeed0, accel, accelqw, cvar("cl_movement_airaccel_qw_stretchfactor"), cvar("cl_movement_airaccel_sideways_friction") / cvar("cl_movement_maxairspeed"), cvar("cl_movement_airspeedlimit_nonqw")); + + if(cvar("cl_movement_aircontrol")) + CSQC_ClientMovement_Physics_CPM_PM_Aircontrol(s, wishdir, wishspeed2); + } + gravity = cvar("cl_movement_gravity") * cvar("cl_movement_entgravity") * input_timelength; + if(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s.velocity_z -= gravity * 0.5; + else + s.velocity_z -= gravity; + CSQC_ClientMovement_Move(s); + if(!(moveflags & MOVEFLAG_NOGRAVITYONGROUND) || !(s.pmove_flags & PMF_ONGROUND)) + { + if(moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE) + s.velocity_z -= gravity * 0.5; + } + } +} + +void CSQC_ClientMovement_PlayerMove(entity s) +{ + //Con_Printf(" %f", frametime); + if (!(input_buttons & 2)) // !jump + s.pmove_flags &= ~PMF_JUMP_HELD; // canjump = true + pmove_waterjumptime -= input_timelength; + CSQC_ClientMovement_UpdateStatus(s); + // TODO +// if (s.waterlevel >= WATERLEVEL_SWIMMING) +// CL_ClientMovement_Physics_Swim(s); +// else + CSQC_ClientMovement_Physics_Walk(s); +} + +void CSQC_ClientMovement_PlayerMove_Frame(entity s) +{ + // if a move is more than 50ms, do it as two moves (matching qwsv) + //Con_Printf("%i ", s.cmd.msec); + if(input_timelength > 0.0005) + { + if (input_timelength > 0.05) + { + input_timelength /= 2; + CSQC_ClientMovement_PlayerMove(s); + } + CSQC_ClientMovement_PlayerMove(s); + } + else + { + // we REALLY need this handling to happen, even if the move is not executed + if (!(input_buttons & 2)) // !jump + s.pmove_flags &= ~PMF_JUMP_HELD; // canjump = true + } +} + +void CSQCPlayer_Physics(void) +{ + switch(cvar("cl_movement")) { + case 2: CSQC_ClientMovement_PlayerMove_Frame(self); break; + case 1: runstandardplayerphysics(self); break; + default: break; + } +} +#undef vlen2 + void CSQCPlayer_PredictTo(float endframe, float apply_error) { CSQCPlayer_Unpredict(); @@ -153,7 +787,7 @@ void CSQCPlayer_PredictTo(float endframe, float apply_error) { if (!getinputstate(csqcplayer_moveframe)) break; - runstandardplayerphysics(self); + CSQCPlayer_Physics(); CSQCPlayer_SetMinsMaxs(); csqcplayer_moveframe++; } -- 2.39.2