Add CS2-valid movement features (W release, instant strafe, snap tap, minijump, subtick-perfect crouch jump)

This commit is contained in:
2026-08-05 17:57:39 +02:00
parent e7e1867cb5
commit f2482195b4
4 changed files with 155 additions and 1 deletions
@@ -537,6 +537,9 @@ auto CMisc::RunMovement( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
const bool bOnGround = ( flFlags & FL_ONGROUND ) != 0; const bool bOnGround = ( flFlags & FL_ONGROUND ) != 0;
if ( Settings::Misc::SnapTap )
RunSnapTap( pUserCmd );
if ( Settings::Misc::SubtickStrafe ) if ( Settings::Misc::SubtickStrafe )
RunSubtickStrafe( pInput , pUserCmd , pLocalPawn , bOnGround ); RunSubtickStrafe( pInput , pUserCmd , pLocalPawn , bOnGround );
else if ( Settings::Misc::NullStrafe ) else if ( Settings::Misc::NullStrafe )
@@ -565,11 +568,29 @@ auto CMisc::RunMovement( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
} }
} }
const bool bJumpHeld = ( pUserCmd->button_states.buttonstate1 & IN_JUMP ) != 0;
const bool bJumpEdge = bJumpHeld && !m_bWasJumping;
if ( Settings::Misc::JumpCrouch ) if ( Settings::Misc::JumpCrouch )
{ {
if ( bOnGround && ( pUserCmd->button_states.buttonstate1 & IN_JUMP ) ) if ( bOnGround && bJumpHeld )
{
pUserCmd->button_states.buttonstate1 |= IN_DUCK; pUserCmd->button_states.buttonstate1 |= IN_DUCK;
pUserCmd->cmd.mutable_base()->mutable_buttons_pb()->set_buttonstate1( pUserCmd->button_states.buttonstate1 );
GetCL_Bypass()->AddProcessSubTick( IN_DUCK , true , 0.0f );
GetCL_Bypass()->AddProcessSubTick( IN_JUMP , true , 0.0f );
} }
}
if ( Settings::Misc::WRelease )
RunWRelease( pUserCmd , bOnGround );
if ( Settings::Misc::InstantStrafe )
RunInstantStrafe( pUserCmd , bOnGround , bJumpEdge );
if ( Settings::Misc::Minijump )
RunMinijump( pUserCmd , bOnGround , bJumpEdge );
if ( Settings::Misc::LongJump ) if ( Settings::Misc::LongJump )
{ {
@@ -636,6 +657,7 @@ auto CMisc::RunMovement( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
pUserCmd->button_states.buttonstate1 |= IN_SPEED; pUserCmd->button_states.buttonstate1 |= IN_SPEED;
m_bWasOnGround = bOnGround; m_bWasOnGround = bOnGround;
m_bWasJumping = ( pUserCmd->button_states.buttonstate1 & IN_JUMP ) != 0;
} }
auto CMisc::RunAutoStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void auto CMisc::RunAutoStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void
@@ -928,6 +950,117 @@ auto CMisc::RotateMoveToYaw( CBaseUserCmdPB* pBaseCmd , const float flTargetYaw
pBaseCmd->set_leftmove( std::clamp( -flCorrectedSide , -1.f , 1.f ) ); pBaseCmd->set_leftmove( std::clamp( -flCorrectedSide , -1.f , 1.f ) );
} }
auto CMisc::RunSnapTap( CUserCmd* pUserCmd ) -> void
{
if ( !pUserCmd )
return;
auto& uButtons = pUserCmd->button_states.buttonstate1;
const bool bLeft = ( uButtons & IN_MOVELEFT ) != 0;
const bool bRight = ( uButtons & IN_MOVERIGHT ) != 0;
const bool bForward = ( uButtons & IN_FORWARD ) != 0;
const bool bBack = ( uButtons & IN_BACK ) != 0;
// Newest key wins: pressing A while D is held releases D and vice versa.
if ( bLeft && m_bRightHeld && !m_bLeftHeld )
uButtons &= ~IN_MOVERIGHT;
if ( bRight && m_bLeftHeld && !m_bRightHeld )
uButtons &= ~IN_MOVELEFT;
if ( bForward && m_bBackHeld && !m_bForwardHeld )
uButtons &= ~IN_BACK;
if ( bBack && m_bForwardHeld && !m_bBackHeld )
uButtons &= ~IN_FORWARD;
pUserCmd->cmd.mutable_base()->mutable_buttons_pb()->set_buttonstate1( uButtons );
m_bLeftHeld = ( uButtons & IN_MOVELEFT ) != 0;
m_bRightHeld = ( uButtons & IN_MOVERIGHT ) != 0;
m_bForwardHeld = ( uButtons & IN_FORWARD ) != 0;
m_bBackHeld = ( uButtons & IN_BACK ) != 0;
}
auto CMisc::RunWRelease( CUserCmd* pUserCmd , bool bOnGround ) -> void
{
if ( !pUserCmd )
return;
constexpr int k_ReleaseTicks = 2;
if ( bOnGround )
{
if ( pUserCmd->button_states.buttonstate1 & IN_JUMP )
m_iWReleaseTicks = k_ReleaseTicks;
else
m_iWReleaseTicks = 0;
return;
}
if ( m_iWReleaseTicks > 0 )
{
auto& uButtons = pUserCmd->button_states.buttonstate1;
uButtons &= ~IN_FORWARD;
pUserCmd->cmd.mutable_base()->set_forwardmove( 0.f );
pUserCmd->cmd.mutable_base()->mutable_buttons_pb()->set_buttonstate1( uButtons );
GetCL_Bypass()->AddProcessSubTick( IN_FORWARD , false , 0.01f , 0.f , 0.f );
--m_iWReleaseTicks;
}
}
auto CMisc::RunInstantStrafe( CUserCmd* pUserCmd , bool bOnGround , bool bJumpEdge ) -> void
{
if ( !pUserCmd )
return;
if ( !bOnGround || !bJumpEdge )
return;
const auto uButtons = pUserCmd->button_states.buttonstate1;
if ( uButtons & IN_MOVELEFT )
GetCL_Bypass()->AddProcessSubTick( IN_MOVELEFT , true , 0.01f );
if ( uButtons & IN_MOVERIGHT )
GetCL_Bypass()->AddProcessSubTick( IN_MOVERIGHT , true , 0.01f );
if ( uButtons & IN_FORWARD )
GetCL_Bypass()->AddProcessSubTick( IN_FORWARD , true , 0.01f );
if ( uButtons & IN_BACK )
GetCL_Bypass()->AddProcessSubTick( IN_BACK , true , 0.01f );
}
auto CMisc::RunMinijump( CUserCmd* pUserCmd , bool bOnGround , bool bJumpEdge ) -> void
{
if ( !pUserCmd )
return;
if ( bOnGround && bJumpEdge )
{
// Crouch-jump for a single tiny hop (minijump) instead of a full jump.
GetCL_Bypass()->AddProcessSubTick( IN_DUCK , true , 0.0f );
GetCL_Bypass()->AddProcessSubTick( IN_JUMP , true , 0.0f );
m_iMinijumpForceRelease = 2;
}
if ( m_iMinijumpForceRelease > 0 )
{
if ( !bOnGround )
GetCL_Bypass()->SetDontJump( pUserCmd , true );
--m_iMinijumpForceRelease;
}
}
auto CMisc::RunEdgeBug( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void auto CMisc::RunEdgeBug( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void
{ {
if ( bOnGround ) if ( bOnGround )
@@ -43,6 +43,10 @@ private:
auto RunNullStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void; auto RunNullStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void;
auto RunSubtickStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void; auto RunSubtickStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void;
auto RunEdgeBug( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void; auto RunEdgeBug( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void;
auto RunSnapTap( CUserCmd* pUserCmd ) -> void;
auto RunWRelease( CUserCmd* pUserCmd , bool bOnGround ) -> void;
auto RunInstantStrafe( CUserCmd* pUserCmd , bool bOnGround , bool bJumpEdge ) -> void;
auto RunMinijump( CUserCmd* pUserCmd , bool bOnGround , bool bJumpEdge ) -> void;
auto RotateMoveToYaw( CBaseUserCmdPB* pBaseCmd , const float flTargetYaw , const float flViewYaw ) -> void; auto RotateMoveToYaw( CBaseUserCmdPB* pBaseCmd , const float flTargetYaw , const float flViewYaw ) -> void;
private: private:
@@ -64,6 +68,15 @@ private:
bool m_bSideSwitch = false; bool m_bSideSwitch = false;
float m_flLastForwardMove = 0.f; float m_flLastForwardMove = 0.f;
float m_flLastLeftMove = 0.f; float m_flLastLeftMove = 0.f;
bool m_bWasJumping = false;
int m_iWReleaseTicks = 0;
int m_iMinijumpForceRelease = 0;
bool m_bLeftHeld = false;
bool m_bRightHeld = false;
bool m_bForwardHeld = false;
bool m_bBackHeld = false;
}; };
auto GetMisc() -> CMisc*; auto GetMisc() -> CMisc*;
@@ -336,10 +336,14 @@ auto CAndromedaMenu::RenderMiscPanel() -> void
Checkbox( "Auto-Strafe" , Settings::Misc::AutoStrafe ); Checkbox( "Auto-Strafe" , Settings::Misc::AutoStrafe );
Checkbox( "Null-Strafe" , Settings::Misc::NullStrafe ); Checkbox( "Null-Strafe" , Settings::Misc::NullStrafe );
Checkbox( "SubTick-Strafe" , Settings::Misc::SubtickStrafe ); Checkbox( "SubTick-Strafe" , Settings::Misc::SubtickStrafe );
Checkbox( "W-Release" , Settings::Misc::WRelease );
Checkbox( "Instant Strafe" , Settings::Misc::InstantStrafe );
Checkbox( "Snap Tap" , Settings::Misc::SnapTap );
Checkbox( "JumpBug" , Settings::Misc::JumpBug ); Checkbox( "JumpBug" , Settings::Misc::JumpBug );
Checkbox( "EdgeBug" , Settings::Misc::EdgeBug ); Checkbox( "EdgeBug" , Settings::Misc::EdgeBug );
Checkbox( "EdgeJump" , Settings::Misc::EdgeJump ); Checkbox( "EdgeJump" , Settings::Misc::EdgeJump );
Checkbox( "JumpCrouch" , Settings::Misc::JumpCrouch ); Checkbox( "JumpCrouch" , Settings::Misc::JumpCrouch );
Checkbox( "Minijump" , Settings::Misc::Minijump );
Checkbox( "Fast-Stop" , Settings::Misc::FastStop ); Checkbox( "Fast-Stop" , Settings::Misc::FastStop );
Checkbox( "LongJump" , Settings::Misc::LongJump ); Checkbox( "LongJump" , Settings::Misc::LongJump );
Checkbox( "Pixel Surf" , Settings::Misc::PixelSurf ); Checkbox( "Pixel Surf" , Settings::Misc::PixelSurf );
@@ -48,10 +48,14 @@ namespace Settings
inline auto AutoStrafe = false; inline auto AutoStrafe = false;
inline auto NullStrafe = false; inline auto NullStrafe = false;
inline auto SubtickStrafe = false; inline auto SubtickStrafe = false;
inline auto WRelease = false;
inline auto InstantStrafe = false;
inline auto SnapTap = false;
inline auto JumpBug = false; inline auto JumpBug = false;
inline auto EdgeBug = false; inline auto EdgeBug = false;
inline auto EdgeJump = false; inline auto EdgeJump = false;
inline auto JumpCrouch = false; inline auto JumpCrouch = false;
inline auto Minijump = false;
inline auto FastStop = false; inline auto FastStop = false;
inline auto LongJump = false; inline auto LongJump = false;
inline auto PixelSurf = false; inline auto PixelSurf = false;