#include "cl_model.qh"
#include "common.qh"
#include "interpolate.qh"
-#include "../../client/defs.qh"
-#include "../../client/main.qh"
-#include "../../common/constants.qh"
-#include "../../common/physics.qh"
-#include "../../common/stats.qh"
-#include "../../common/triggers/trigger/viewloc.qh"
-#include "../../common/util.qh"
-#include "../../common/viewloc.qh"
float autocvar_cl_movement_errorcompensation = 0;
+bool autocvar_cl_movement_intermissionrunning = false;
// engine stuff
float pmove_onground; // weird engine flag we shouldn't really use but have to for now
return;
}
*/
- if(vlen(o) > 32 || vlen(v) > 192)
+ if(vdist(o, >, 32) || vdist(v, >, 192))
{
//printf("TOO BIG: x=%v v=%v\n", o, v);
return;
void CSQCPlayer_Unpredict(entity this)
{
if (csqcplayer_status == CSQCPLAYERSTATUS_UNPREDICTED) return;
- if (csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED) LOG_FATALF("Cannot unpredict in current status (%d)\n", csqcplayer_status);
+ if (csqcplayer_status != CSQCPLAYERSTATUS_PREDICTED) LOG_FATALF("Cannot unpredict in current status (%d)", csqcplayer_status);
this.origin = csqcplayer_origin;
this.velocity = csqcplayer_velocity;
csqcplayer_moveframe = csqcplayer_sequence + 1; // + 1 because the recieved frame has the move already done (server side)
void CSQCPlayer_SetMinsMaxs(entity this)
{
- if (this.flags & FL_DUCKED)
+ if (IS_DUCKED(this) || !this.isplayermodel)
{
- this.mins = PL_CROUCH_MIN;
- this.maxs = PL_CROUCH_MAX;
- this.view_ofs = PL_CROUCH_VIEW_OFS;
+ this.mins = PHYS_PL_CROUCH_MIN(this);
+ this.maxs = PHYS_PL_CROUCH_MAX(this);
+ this.view_ofs = PHYS_PL_CROUCH_VIEWOFS(this);
}
else
{
- this.mins = PL_MIN;
- this.maxs = PL_MAX;
- this.view_ofs = PL_VIEW_OFS;
+ this.mins = PHYS_PL_MIN(this);
+ this.maxs = PHYS_PL_MAX(this);
+ this.view_ofs = PHYS_PL_VIEWOFS(this);
}
}
}
void CSQC_ClientMovement_PlayerMove_Frame(entity this);
-void _Movetype_Physics_ClientFrame(entity this, float movedt);
-void Movetype_Physics_Spam(entity this) // optimized
+void CSQCPlayer_Physics(entity this)
{
- _Movetype_Physics_ClientFrame(this, PHYS_INPUT_TIMELENGTH);
- if(wasfreed(this))
- return;
+ if(!autocvar_cl_movement) { return; }
- this.avelocity = this.move_avelocity;
- this.velocity = this.move_velocity;
- this.angles = this.move_angles;
- this.flags = BITSET(this.flags, FL_ONGROUND, boolean(this.move_flags & FL_ONGROUND));
- this.flags = BITSET(this.flags, FL_WATERJUMP, boolean(this.move_flags & FL_WATERJUMP));
- this.waterlevel = this.move_waterlevel;
- this.watertype = this.move_watertype;
- setorigin(this, this.move_origin);
-}
+ _Movetype_CheckWater(this); // we apparently need to check water *before* physics so it can use this for water jump
-void CSQCPlayer_Physics(entity this)
-{
- if(autocvar_cl_movement)
- {
- CSQC_ClientMovement_PlayerMove_Frame(this);
+ vector oldv_angle = this.v_angle;
+ vector oldangles = this.angles; // we need to save these, as they're abused by other code
+ this.v_angle = PHYS_INPUT_ANGLES(this);
+ this.angles = PHYS_WORLD_ANGLES(this);
- if(autocvar_cl_movement == 3)
- {
- this.move_origin = this.origin;
- this.move_angles = this.angles;
- //this.move_movetype = MOVETYPE_WALK; // temp
- this.move_velocity = this.velocity;
- this.move_avelocity = this.avelocity;
- this.move_flags = BITSET(this.move_flags, FL_ONGROUND, boolean(this.flags & FL_ONGROUND));
- this.move_flags = BITSET(this.move_flags, FL_WATERJUMP, boolean(this.flags & FL_WATERJUMP));
- this.move_waterlevel = this.waterlevel;
- this.move_watertype = this.watertype;
- Movetype_Physics_Spam(this);
- }
+ CSQC_ClientMovement_PlayerMove_Frame(this);
- this.pmove_flags =
- ((this.flags & FL_DUCKED) ? PMF_DUCKED : 0) |
- (!(this.flags & FL_JUMPRELEASED) ? PMF_JUMP_HELD : 0) |
- ((this.flags & FL_ONGROUND) ? PMF_ONGROUND : 0);
- }
+ Movetype_Physics_NoMatchTicrate(this, PHYS_INPUT_TIMELENGTH, true);
+
+ view_angles = this.v_angle;
+ input_angles = this.angles;
+ this.v_angle = oldv_angle;
+ this.angles = oldangles;
+
+ this.pmove_flags =
+ ((IS_DUCKED(this)) ? PMF_DUCKED : 0) |
+ ((IS_JUMP_HELD(this)) ? PMF_JUMP_HELD : 0) |
+ ((IS_ONGROUND(this)) ? PMF_ONGROUND : 0);
}
void CSQCPlayer_PredictTo(entity this, float endframe, bool apply_error)
#if 0
// we don't need this
// darkplaces makes servercommandframe == 0 in these cases anyway
- if (getstatf(STAT_HEALTH) <= 0)
+ if (STAT(HEALTH) <= 0)
{
csqcplayer_moveframe = clientcommandframe;
getinputstate(csqcplayer_moveframe-1);
- LOG_INFO("the Weird code path got hit\n");
+ LOG_INFO("the Weird code path got hit");
return;
}
#endif
do
{
if (!getinputstate(csqcplayer_moveframe)) break;
+ /*if (input_timelength > 0.0005)
+ {
+ if (input_timelength > 0.05)
+ {
+ input_timelength /= 2;
+ CSQCPlayer_Physics(this);
+ }
+ CSQCPlayer_Physics(this);
+ }*/
CSQCPlayer_Physics(this);
CSQCPlayer_SetMinsMaxs(this);
++csqcplayer_moveframe;
return (this == csqcplayer);
}
-void CSQCPlayer_SetViewLocation()
+float stairsmoothz;
+float autocvar_cl_stairsmoothspeed;
+float autocvar_cl_smoothviewheight;
+float smooth_prevtime;
+float viewheightavg;
+float autocvar_cl_bobfall;
+float autocvar_cl_bobfallcycle;
+float autocvar_cl_bobfallminspeed;
+float bobfall_swing;
+float bobfall_speed;
+vector CSQCPlayer_ApplySmoothing(entity this, vector v)
+{
+ if(this.csqcmodel_teleported || !IS_ONGROUND(this) || autocvar_cl_stairsmoothspeed <= 0)
+ stairsmoothz = v.z;
+ else
+ {
+ if(v.z > stairsmoothz)
+ v.z = stairsmoothz = bound(v.z - PHYS_STEPHEIGHT(this), stairsmoothz + frametime * autocvar_cl_stairsmoothspeed, v.z);
+ else if(v.z < stairsmoothz)
+ v.z = stairsmoothz = bound(v.z, stairsmoothz - frametime * autocvar_cl_stairsmoothspeed, v.z + PHYS_STEPHEIGHT(this));
+ }
+
+ float viewheight = bound(0, (time - smooth_prevtime) / max(0.0001, autocvar_cl_smoothviewheight), 1);
+ viewheightavg = viewheightavg * (1 - viewheight) + this.view_ofs.z * viewheight;
+ v.z += viewheightavg;
+
+ if(autocvar_cl_bobfall && autocvar_cl_bobfallcycle)
+ {
+ if(!IS_ONGROUND(this))
+ {
+ bobfall_speed = bound(-400, this.velocity.z, 0) * bound(0, autocvar_cl_bobfall, 0.1);
+ if(this.velocity.z < -autocvar_cl_bobfallminspeed)
+ bobfall_swing = 1;
+ else
+ bobfall_swing = 0; // really?
+ }
+ else
+ {
+ bobfall_swing = max(0, bobfall_swing - autocvar_cl_bobfallcycle * frametime);
+ float bobfall = sin(M_PI * bobfall_swing) * bobfall_speed;
+ v.z += bobfall;
+ }
+ }
+
+ smooth_prevtime = time;
+
+ return v;
+}
+
+bool autocvar_v_deathtilt;
+float autocvar_v_deathtiltangle;
+void CSQCPlayer_ApplyDeathTilt(entity this)
+{
+ if(!autocvar_v_deathtilt)
+ return;
+ view_angles.y = autocvar_v_deathtiltangle;
+}
+
+float autocvar_v_idlescale;
+float autocvar_v_ipitch_cycle;
+float autocvar_v_iyaw_cycle;
+float autocvar_v_iroll_cycle;
+float autocvar_v_ipitch_level;
+float autocvar_v_iyaw_level;
+float autocvar_v_iroll_level;
+void CSQCPlayer_ApplyIdleScaling(entity this)
+{
+ view_angles.x += autocvar_v_idlescale * sin(time * autocvar_v_ipitch_cycle) * autocvar_v_ipitch_level;
+ view_angles.y += autocvar_v_idlescale * sin(time * autocvar_v_iyaw_cycle) * autocvar_v_iyaw_level;
+ view_angles.z += autocvar_v_idlescale * sin(time * autocvar_v_iroll_cycle) * autocvar_v_iroll_level;
+ setproperty(VF_CL_VIEWANGLES, view_angles); // update view angles as well so we can aim
+}
+
+float autocvar_chase_back;
+float autocvar_chase_up;
+vector CSQCPlayer_ApplyChase(entity this, vector v)
{
- viewloc_SetViewLocation();
+ // TODO: chase_overhead
+ v += this.view_ofs;
+ makevectors(view_angles);
+ tracebox(v, '-4 -4 -4', '4 4 4', v - v_forward * autocvar_chase_back, MOVE_NORMAL, this);
+ v = trace_endpos;
+ tracebox(v, '-4 -4 -4', '4 4 4', v + v_up * autocvar_chase_up, MOVE_NORMAL, this);
+ v = trace_endpos;
+ return v;
}
/** Called once per CSQC_UpdateView() */
void CSQCPlayer_SetCamera()
{
- const vector v0 = pmove_vel; // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
- const float vh = getstati(STAT_VIEWHEIGHT);
- const vector pl_viewofs = PL_VIEW_OFS;
- const vector pl_viewofs_crouch = PL_CROUCH_VIEW_OFS;
- const entity e = csqcplayer;
+ vector v0 = ((intermission && !autocvar_cl_movement_intermissionrunning) ? '0 0 0' : pmove_vel); // TRICK: pmove_vel is set by the engine when we get here. No need to network velocity
+ float vh = PHYS_VIEWHEIGHT(NULL);
+ vector pl_viewofs = PHYS_PL_VIEWOFS(NULL);
+ vector pl_viewofs_crouch = PHYS_PL_CROUCH_VIEWOFS(NULL);
+ entity e = csqcplayer;
if (e)
{
if (servercommandframe == 0 || clientcommandframe == 0)
}
else
{
- const int flg = e.iflags; e.iflags &= ~(IFLAG_ORIGIN | IFLAG_ANGLES);
+ int flg = e.iflags; e.iflags &= ~(IFLAG_ORIGIN | IFLAG_ANGLES);
InterpolateOrigin_Do(e);
e.iflags = flg;
if (csqcplayer_status == CSQCPLAYERSTATUS_FROMSERVER)
{
- const vector o = e.origin;
+ vector o = e.origin;
csqcplayer_status = CSQCPLAYERSTATUS_PREDICTED;
CSQCPlayer_PredictTo(e, servercommandframe + 1, false);
- CSQCPlayer_SetPredictionError(e.origin - o, e.velocity - v0, pmove_onground - boolean(e.flags & FL_ONGROUND));
+ CSQCPlayer_SetPredictionError(e.origin - o, e.velocity - v0, pmove_onground - IS_ONGROUND(e));
e.origin = o;
e.velocity = v0;
InterpolateOrigin_Do(view);
view.view_ofs = '0 0 1' * vh;
}
- int refdefflags = 0;
- if (view.csqcmodel_teleported) refdefflags |= REFDEFFLAG_TELEPORTED;
- if (input_buttons & BIT(1)) refdefflags |= REFDEFFLAG_JUMPING;
+ //int refdefflags = 0;
+ //if (view.csqcmodel_teleported) refdefflags |= REFDEFFLAG_TELEPORTED;
+ //if (input_buttons & BIT(1)) refdefflags |= REFDEFFLAG_JUMPING;
// note: these two only work in WIP2, but are harmless in WIP1
- if (getstati(STAT_HEALTH) <= 0) refdefflags |= REFDEFFLAG_DEAD;
- if (intermission) refdefflags |= REFDEFFLAG_INTERMISSION;
- V_CalcRefdef(view, refdefflags);
+ //if (PHYS_HEALTH(NULL) <= 0 && PHYS_HEALTH(NULL) != -666 && PHYS_HEALTH(NULL) != -2342) refdefflags |= REFDEFFLAG_DEAD;
+ //if (intermission) refdefflags |= REFDEFFLAG_INTERMISSION;
+ vector vieworg = view.origin;
+ if(autocvar_chase_active)
+ vieworg = CSQCPlayer_ApplyChase(view, vieworg);
+ else
+ {
+ vieworg = CSQCPlayer_ApplySmoothing(view, vieworg);
+ if(IS_DEAD(view))
+ CSQCPlayer_ApplyDeathTilt(view);
+ }
+ if(autocvar_v_idlescale)
+ CSQCPlayer_ApplyIdleScaling(view);
+ setproperty(VF_ORIGIN, vieworg);
+ setproperty(VF_ANGLES, view_angles);
+ //V_CalcRefdef(view, refdefflags); // TODO? uses .health stat in the engine when this isn't called here, may be broken!
}
else
{
CSQCPLAYER_HOOK_POSTCAMERASETUP();
}
-void CSQCPlayer_Remove()
+void CSQCPlayer_Remove(entity this)
{
csqcplayer = NULL;
cvar_settemp("cl_movement_replay", "1");