Add ragebot with nospread, auto stop/fire, recoil control and separate Legitbot/Ragebot GUI tabs

This commit is contained in:
2026-08-05 18:12:08 +02:00
parent f2482195b4
commit 12ae5bef43
5 changed files with 349 additions and 0 deletions
@@ -24,6 +24,7 @@
#include <GameClient/CL_Weapons.hpp> #include <GameClient/CL_Weapons.hpp>
#include <GameClient/CL_Trace.hpp> #include <GameClient/CL_Trace.hpp>
#include <GameClient/CL_Bypass.hpp> #include <GameClient/CL_Bypass.hpp>
#include <GameClient/CL_VisibleCheck.hpp>
#include <GameClient/CEntityCache/CEntityCache.hpp> #include <GameClient/CEntityCache/CEntityCache.hpp>
#include <CS2/SDK/Types/CBaseTypes.hpp> #include <CS2/SDK/Types/CBaseTypes.hpp>
#include <CS2/SDK/FunctionListSDK.hpp> #include <CS2/SDK/FunctionListSDK.hpp>
@@ -479,6 +480,9 @@ auto CMisc::OnCreateMove( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
if ( Settings::Triggerbot::Active ) if ( Settings::Triggerbot::Active )
RunTriggerbot( pInput , pUserCmd ); RunTriggerbot( pInput , pUserCmd );
if ( Settings::Ragebot::Active )
RunRagebot( pInput , pUserCmd );
if ( Settings::Misc::Bunnyhop ) if ( Settings::Misc::Bunnyhop )
{ {
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn(); auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
@@ -1335,6 +1339,246 @@ auto CMisc::RunTriggerbot( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
} }
} }
auto CMisc::CalculateRagebotFov( const QAngle& ViewAngles , const QAngle& AimAngles ) -> float
{
const float flPitch = std::fabsf( Math::AngleNormalize( AimAngles.m_x - ViewAngles.m_x ) );
const float flYaw = std::fabsf( Math::AngleNormalize( AimAngles.m_y - ViewAngles.m_y ) );
return std::sqrtf( flPitch * flPitch + flYaw * flYaw );
}
auto CMisc::RunRagebot( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
{
m_bRagebotFiring = false;
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
if ( !pLocalPawn || !pLocalPawn->IsAlive() )
return;
const auto WeaponType = GetCL_Weapons()->GetLocalWeaponType();
const bool bIsGun = WeaponType == CSWeaponType_t::WEAPONTYPE_PISTOL ||
WeaponType == CSWeaponType_t::WEAPONTYPE_SUBMACHINEGUN ||
WeaponType == CSWeaponType_t::WEAPONTYPE_RIFLE ||
WeaponType == CSWeaponType_t::WEAPONTYPE_SHOTGUN ||
WeaponType == CSWeaponType_t::WEAPONTYPE_SNIPER_RIFLE ||
WeaponType == CSWeaponType_t::WEAPONTYPE_MACHINEGUN ||
WeaponType == CSWeaponType_t::WEAPONTYPE_TASER;
if ( !bIsGun )
return;
bool bShouldRun = false;
switch ( Settings::Ragebot::Mode )
{
case 1:
{
bShouldRun = true;
}
break;
case 2:
{
const bool bKeyDown = ( GetAsyncKeyState( Settings::Ragebot::Key ) & 0x8000 ) != 0;
if ( bKeyDown && !m_bRagebotKeyDown )
m_bRagebotToggledOn = !m_bRagebotToggledOn;
m_bRagebotKeyDown = bKeyDown;
bShouldRun = m_bRagebotToggledOn;
}
break;
default:
{
const bool bKeyDown = ( GetAsyncKeyState( Settings::Ragebot::Key ) & 0x8000 ) != 0;
bShouldRun = bKeyDown;
}
break;
}
if ( !bShouldRun )
return;
auto* pWeapon = GetCL_Weapons()->GetLocalActiveWeapon();
if ( !pWeapon )
return;
const float flInaccuracy = C_CSWeaponBaseGun_GetInaccuracy( pWeapon , nullptr , nullptr );
const float flSpread = C_CSWeaponBaseGun_GetSpread( pWeapon );
const int iItemDefIdx = GetCL_Weapons()->GetLocalWeaponDefinitionIndex();
const Vector3 vEyeOrigin = GetCL_Players()->GetLocalEyeOrigin();
const QAngle ViewAngles = *CCSGOInput_GetViewAngles( pInput , 0 );
C_CSPlayerPawn* pBestPawn = nullptr;
QAngle BestAngles;
float flBestFov = 9999.f;
const auto& CachedVec = GetEntityCache()->GetCachedEntity();
std::scoped_lock Lock( GetEntityCache()->GetLock() );
for ( const auto& CachedEntity : *CachedVec )
{
if ( CachedEntity.m_Type != CachedEntity_t::PLAYER_CONTROLLER )
continue;
auto* pEntity = CachedEntity.m_Handle.Get();
if ( !pEntity )
continue;
auto* pController = reinterpret_cast<CCSPlayerController*>( pEntity );
if ( pController == GetCL_Players()->GetLocalPlayerController() )
continue;
auto* pPawn = pController->m_hPawn().Get<C_CSPlayerPawn>();
if ( !pPawn || !pPawn->IsPlayerPawn() || pPawn == pLocalPawn || !pPawn->IsAlive() )
continue;
if ( Settings::Ragebot::IgnoreTeammates && pPawn->m_iTeamNum() == pLocalPawn->m_iTeamNum() )
continue;
const char* szBoneName = "head_0";
switch ( Settings::Ragebot::Hitbox )
{
case 0: szBoneName = "head_0"; break;
case 2: szBoneName = "spine_3"; break;
case 3: szBoneName = "pelvis"; break;
case 4: szBoneName = "ankle_l"; break;
default: szBoneName = "pelvis"; break;
}
const Vector3 vAimPoint = GetCL_Bones()->GetBonePositionByName( pPawn , szBoneName );
if ( vAimPoint.IsZero() )
continue;
Vector3 vDelta = vAimPoint - vEyeOrigin;
if ( vDelta.Length() < 0.01f )
continue;
if ( Settings::Ragebot::VisibleOnly && !GetCL_VisibleCheck()->IsBoneVisible( pPawn , vAimPoint ) )
continue;
QAngle AimAngles;
Math::VectorAngles( vDelta.Normalized() , AimAngles );
if ( Settings::Ragebot::Recoil )
{
const auto& PunchCache = pLocalPawn->m_aimPunchCache();
if ( PunchCache.Count() > 0 )
{
constexpr float k_PunchScale = 2.f;
AimAngles.m_x -= PunchCache[ 0 ].m_x * k_PunchScale;
AimAngles.m_y -= PunchCache[ 0 ].m_y * k_PunchScale;
}
}
if ( Settings::Ragebot::NoSpread )
{
constexpr float k_RadToDeg = 180.f / 3.14159265358979f;
for ( auto i = 0; i < 3; i++ )
{
int iTick = 0;
if ( pUserCmd && pUserCmd->cmd.base().has_client_tick() )
iTick = pUserCmd->cmd.base().client_tick();
const auto iSeed = static_cast<int>( GetSpreadSeed( AimAngles , iTick ) );
const auto sv = CalculateSeedSpread( iSeed + 1 , flInaccuracy , flSpread , iItemDefIdx );
AimAngles.m_x -= sv.y * k_RadToDeg;
AimAngles.m_y += sv.x * k_RadToDeg;
}
}
Math::NormalizeAngles( AimAngles );
Math::ClampAngles( AimAngles );
const float flFov = CalculateRagebotFov( ViewAngles , AimAngles );
if ( flFov > static_cast<float>( Settings::Ragebot::FOV ) )
continue;
if ( flFov < flBestFov )
{
flBestFov = flFov;
pBestPawn = pPawn;
BestAngles = AimAngles;
}
}
if ( !pBestPawn )
return;
if ( Settings::Ragebot::Hitchance > 0 )
{
const float flHitchance = CalculateHitchance( pInput , pBestPawn , BestAngles , Settings::Ragebot::HitchanceSamples );
if ( ( flHitchance * 100.f ) < static_cast<float>( Settings::Ragebot::Hitchance ) )
return;
}
if ( Settings::Ragebot::AutoStop )
{
const Vector3 Velocity = pLocalPawn->m_vecVelocity();
const float flSpeed = Velocity.Length2D();
if ( flSpeed > 5.f )
{
constexpr float k_Pi = 3.14159265358979f;
const float flVelYaw = std::atan2f( Velocity.m_y , Velocity.m_x ) * ( 180.f / k_Pi );
float flDelta = flVelYaw - ViewAngles.m_y;
while ( flDelta > 180.f )
flDelta -= 360.f;
while ( flDelta < -180.f )
flDelta += 360.f;
auto& uButtons = pUserCmd->button_states.buttonstate1;
if ( flDelta > -45.f && flDelta <= 45.f )
uButtons |= IN_BACK;
else if ( flDelta > 45.f && flDelta <= 135.f )
uButtons |= IN_MOVELEFT;
else if ( flDelta > 135.f || flDelta <= -135.f )
uButtons |= IN_FORWARD;
else
uButtons |= IN_MOVERIGHT;
pUserCmd->cmd.mutable_base()->mutable_buttons_pb()->set_buttonstate1( uButtons );
}
}
GetCL_Bypass()->SetViewAngles( &BestAngles , pInput , pUserCmd );
if ( Settings::Ragebot::AutoFire )
{
GetCL_Bypass()->SetAttack( pUserCmd , true );
m_bRagebotFiring = true;
}
}
static thread_local std::mt19937 g_TriggerRng( std::random_device{}() ); static thread_local std::mt19937 g_TriggerRng( std::random_device{}() );
auto CMisc::CalculateHitchance( CCSGOInput* pInput , C_CSPlayerPawn* pTarget , const QAngle& ViewAngles , const int Samples ) -> float auto CMisc::CalculateHitchance( CCSGOInput* pInput , C_CSPlayerPawn* pTarget , const QAngle& ViewAngles , const int Samples ) -> float
@@ -35,8 +35,10 @@ public:
private: private:
auto RunTriggerbot( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void; auto RunTriggerbot( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void;
auto RunRagebot( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void;
auto CalculateHitchance( CCSGOInput* pInput , C_CSPlayerPawn* pTarget , const QAngle& ViewAngles , const int Samples ) -> float; auto CalculateHitchance( CCSGOInput* pInput , C_CSPlayerPawn* pTarget , const QAngle& ViewAngles , const int Samples ) -> float;
auto CalculateSeedDirection( CCSGOInput* pInput , CUserCmd* pUserCmd , Vector3* vOutDirection ) -> bool; auto CalculateSeedDirection( CCSGOInput* pInput , CUserCmd* pUserCmd , Vector3* vOutDirection ) -> bool;
auto CalculateRagebotFov( const QAngle& ViewAngles , const QAngle& AimAngles ) -> float;
auto RunMovement( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void; auto RunMovement( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void;
auto RunAutoStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void; auto RunAutoStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void;
@@ -77,6 +79,10 @@ private:
bool m_bRightHeld = false; bool m_bRightHeld = false;
bool m_bForwardHeld = false; bool m_bForwardHeld = false;
bool m_bBackHeld = false; bool m_bBackHeld = false;
std::atomic_bool m_bRagebotFiring = false;
bool m_bRagebotKeyDown = false;
bool m_bRagebotToggledOn = false;
}; };
auto GetMisc() -> CMisc*; auto GetMisc() -> CMisc*;
@@ -72,6 +72,18 @@ auto CAndromedaMenu::OnRenderMenu() -> void
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
if ( ImGui::BeginTabItem( "Legitbot" ) )
{
RenderLegitbotPanel();
ImGui::EndTabItem();
}
if ( ImGui::BeginTabItem( "Ragebot" ) )
{
RenderRagebotPanel();
ImGui::EndTabItem();
}
if ( ImGui::BeginTabItem( "Misc" ) ) if ( ImGui::BeginTabItem( "Misc" ) )
{ {
RenderMiscPanel(); RenderMiscPanel();
@@ -367,7 +379,10 @@ auto CAndromedaMenu::RenderMiscPanel() -> void
Checkbox( "Hitmarker" , Settings::Misc::Hitmarker ); Checkbox( "Hitmarker" , Settings::Misc::Hitmarker );
Checkbox( "Hit Sound" , Settings::Misc::HitSound ); Checkbox( "Hit Sound" , Settings::Misc::HitSound );
}
auto CAndromedaMenu::RenderLegitbotPanel() -> void
{
ImGui::SeparatorText( "Triggerbot" ); ImGui::SeparatorText( "Triggerbot" );
Checkbox( "Triggerbot" , Settings::Triggerbot::Active ); Checkbox( "Triggerbot" , Settings::Triggerbot::Active );
@@ -436,6 +451,72 @@ auto CAndromedaMenu::RenderMiscPanel() -> void
} }
} }
auto CAndromedaMenu::RenderRagebotPanel() -> void
{
ImGui::SeparatorText( "Ragebot" );
Checkbox( "Enabled" , Settings::Ragebot::Active );
if ( Settings::Ragebot::Active )
{
const char* RageModeItems[] =
{
"Hold Key" , "Always" , "Toggle"
};
Combo( "Mode" , Settings::Ragebot::Mode , RageModeItems , IM_ARRAYSIZE( RageModeItems ) );
static const char* RageKeyItems[] =
{
"Alt" , "Shift" , "Ctrl" , "Mouse 4" , "Mouse 5" , "Q" , "E" , "F" , "X" , "C" , "V" , "B" , "Space"
};
static const int RageKeys[] =
{
VK_MENU , VK_SHIFT , VK_CONTROL , 0x04 , 0x05 , 0x51 , 0x45 , 0x46 , 0x58 , 0x43 , 0x56 , 0x42 , VK_SPACE
};
int iKeyIdx = 0;
for ( int i = 0; i < IM_ARRAYSIZE( RageKeys ); i++ )
{
if ( RageKeys[ i ] == Settings::Ragebot::Key )
{
iKeyIdx = i;
break;
}
}
if ( Combo( "Key" , iKeyIdx , RageKeyItems , IM_ARRAYSIZE( RageKeyItems ) ) )
Settings::Ragebot::Key = RageKeys[ iKeyIdx ];
const char* HitboxItems[] =
{
"Head" , "Nearest" , "Chest" , "Stomach" , "Legs"
};
Combo( "Hitbox" , Settings::Ragebot::Hitbox , HitboxItems , IM_ARRAYSIZE( HitboxItems ) );
SliderInt( "FOV" , Settings::Ragebot::FOV , 1 , 180 );
ImGui::Separator();
Checkbox( "NoSpread" , Settings::Ragebot::NoSpread );
Checkbox( "Auto Fire" , Settings::Ragebot::AutoFire );
Checkbox( "Auto Stop" , Settings::Ragebot::AutoStop );
Checkbox( "Recoil Control" , Settings::Ragebot::Recoil );
Checkbox( "Teammates ignorieren" , Settings::Ragebot::IgnoreTeammates );
Checkbox( "Nur sichtbar" , Settings::Ragebot::VisibleOnly );
ImGui::Separator();
SliderInt( "Hitchance (%)" , Settings::Ragebot::Hitchance , 0 , 100 , Settings::Ragebot::Hitchance > 0 ? "%d%%" : "%d (aus)" );
if ( Settings::Ragebot::Hitchance > 0 )
SliderInt( "Hitchance Samples" , Settings::Ragebot::HitchanceSamples , 16 , 128 );
}
}
auto CAndromedaMenu::RenderConfigPanel() -> void auto CAndromedaMenu::RenderConfigPanel() -> void
{ {
ImGui::SeparatorText( "Menu" ); ImGui::SeparatorText( "Menu" );
@@ -16,6 +16,8 @@ private:
auto RenderMusicPanel() -> void; auto RenderMusicPanel() -> void;
auto RenderConfigPanel() -> void; auto RenderConfigPanel() -> void;
auto RenderMiscPanel() -> void; auto RenderMiscPanel() -> void;
auto RenderLegitbotPanel() -> void;
auto RenderRagebotPanel() -> void;
private: private:
auto Checkbox( const char* szLabel , bool& bValue ) -> bool; auto Checkbox( const char* szLabel , bool& bValue ) -> bool;
@@ -88,6 +88,22 @@ namespace Settings
inline auto HitchanceSamples = 64; inline auto HitchanceSamples = 64;
inline auto SeedTrigger = false; // deterministic: only fire if the real bullet (current random_seed) would hit inline auto SeedTrigger = false; // deterministic: only fire if the real bullet (current random_seed) would hit
} }
namespace Ragebot
{
inline auto Active = false;
inline auto Mode = 0; // 0 = Hold Key, 1 = Always, 2 = Toggle
inline auto Key = VK_MENU; // Alt
inline auto Hitbox = 0; // 0 = Head, 1 = Nearest, 2 = Chest, 3 = Stomach, 4 = Legs
inline auto FOV = 10; // degrees
inline auto Hitchance = 70; // percent, 0 = off
inline auto HitchanceSamples = 64;
inline auto AutoFire = true;
inline auto AutoStop = true;
inline auto NoSpread = true;
inline auto Recoil = true;
inline auto IgnoreTeammates = true;
inline auto VisibleOnly = true;
}
namespace Colors namespace Colors
{ {
namespace Visual namespace Visual