Add legit aimbot: smooth aim, per-hitbox toggles, humanization (reaction, target lock, jitter) and RCS with first-bullet option

This commit is contained in:
2026-08-05 18:27:21 +02:00
parent e51e39f7ed
commit cf5280e34f
4 changed files with 459 additions and 0 deletions
@@ -495,6 +495,52 @@ auto CMisc::OnClientOutput() -> void
}
}
if ( Settings::Legitbot::Active && Settings::Legitbot::DrawFov )
{
const auto DisplaySize = ImGui::GetIO().DisplaySize;
const ImVec2 Center( DisplaySize.x * 0.5f , DisplaySize.y * 0.5f );
constexpr float k_Pi = 3.14159265358979f;
const float flRadius = std::tanf( Settings::Legitbot::FOV * ( k_Pi / 180.f ) ) * ( DisplaySize.y * 0.6f );
constexpr int k_Segments = 48;
for ( int i = 0; i < k_Segments; i++ )
{
const float flAngle0 = ( static_cast<float>( i ) / k_Segments ) * 2.f * k_Pi;
const float flAngle1 = ( static_cast<float>( i + 1 ) / k_Segments ) * 2.f * k_Pi;
const ImVec2 A( Center.x + std::cosf( flAngle0 ) * flRadius , Center.y + std::sinf( flAngle0 ) * flRadius );
const ImVec2 B( Center.x + std::cosf( flAngle1 ) * flRadius , Center.y + std::sinf( flAngle1 ) * flRadius );
GetRenderStackSystem()->DrawLine( A , B , ImColor( 80 , 200 , 255 , 140 ) , 1.f );
}
}
if ( Settings::Legitbot::Active && Settings::Legitbot::DrawTarget )
{
if ( m_bLegitTargetValid )
{
ImVec2 Screen;
if ( Math::WorldToScreen( m_vLegitTargetPoint , Screen ) )
{
const auto DisplaySize = ImGui::GetIO().DisplaySize;
const ImVec2 Center( DisplaySize.x * 0.5f , DisplaySize.y * 0.5f );
const float flHp = std::clamp( m_flLegitTargetHealth , 0.f , 100.f );
const ImColor TargetColor( static_cast<int>( 255 * ( 1.f - flHp / 100.f ) ) , static_cast<int>( 255 * ( flHp / 100.f ) ) , 0 );
GetRenderStackSystem()->DrawLine( Center , Screen , TargetColor , 1.5f );
GetRenderStackSystem()->DrawCircleFilled( Screen , 4.f , TargetColor );
}
}
}
if ( Settings::Misc::Hitmarker )
{
if ( m_HitTime.time_since_epoch().count() > 0 )
@@ -526,6 +572,9 @@ auto CMisc::OnCreateMove( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
if ( Settings::Triggerbot::Active )
RunTriggerbot( pInput , pUserCmd );
if ( Settings::Legitbot::Active )
RunLegitbot( pInput , pUserCmd );
if ( Settings::Ragebot::Active )
RunRagebot( pInput , pUserCmd );
@@ -1795,6 +1844,288 @@ auto CMisc::RunRagebot( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
}
static thread_local std::mt19937 g_TriggerRng( std::random_device{}() );
static thread_local std::mt19937 g_LegitRng( std::random_device{}() );
auto CMisc::RunLegitbot( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
{
m_bLegitTargetValid = 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::Legitbot::Mode )
{
case 1:
{
bShouldRun = true;
}
break;
case 2:
{
const bool bKeyDown = ( GetAsyncKeyState( Settings::Legitbot::Key ) & 0x8000 ) != 0;
if ( bKeyDown && !m_bLegitKeyDown )
m_bLegitToggledOn = !m_bLegitToggledOn;
m_bLegitKeyDown = bKeyDown;
bShouldRun = m_bLegitToggledOn;
}
break;
default:
{
const bool bKeyDown = ( GetAsyncKeyState( Settings::Legitbot::Key ) & 0x8000 ) != 0;
bShouldRun = bKeyDown;
}
break;
}
if ( !bShouldRun )
return;
const Vector3 vEyeOrigin = GetCL_Players()->GetLocalEyeOrigin();
const QAngle ViewAngles = *CCSGOInput_GetViewAngles( pInput , 0 );
struct LegitHitbox
{
const char* szBoneName;
bool bEnabled;
bool bHead;
};
const LegitHitbox Hitboxes[] =
{
{ "head_0" , Settings::Legitbot::Hitbox_Head , true },
{ "neck_0" , Settings::Legitbot::Hitbox_Neck , true },
{ "spine_3" , Settings::Legitbot::Hitbox_Chest , false },
{ "spine_1" , Settings::Legitbot::Hitbox_Stomach , false },
{ "pelvis" , Settings::Legitbot::Hitbox_Pelvis , false },
};
struct LegitCandidate
{
C_CSPlayerPawn* pPawn = nullptr;
Vector3 vAimPoint{};
QAngle AimAngles{};
float flFov = 9999.f;
float flHealth = 0.f;
};
LegitCandidate Best;
bool bLockedSeen = false;
LegitCandidate Locked;
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::Legitbot::IgnoreTeammates && pPawn->m_iTeamNum() == pLocalPawn->m_iTeamNum() )
continue;
constexpr int k_HitboxCount = 5;
bool bAny = false;
Vector3 vAimPoint{};
QAngle AimAngles{};
float flFov = 9999.f;
for ( int i = 0; i < k_HitboxCount; i++ )
{
if ( !Hitboxes[ i ].bEnabled )
continue;
const Vector3 vPoint = GetCL_Bones()->GetBonePositionByName( pPawn , Hitboxes[ i ].szBoneName );
if ( vPoint.IsZero() )
continue;
if ( Settings::Legitbot::VisibleOnly && !GetCL_VisibleCheck()->IsBoneVisible( pPawn , vPoint ) )
continue;
Vector3 vDelta = vPoint - vEyeOrigin;
if ( vDelta.Length() < 0.01f )
continue;
QAngle vAim;
Math::VectorAngles( vDelta.Normalized() , vAim );
const float flPointFov = CalculateRagebotFov( ViewAngles , vAim );
if ( flPointFov < flFov )
{
flFov = flPointFov;
vAimPoint = vPoint;
AimAngles = vAim;
bAny = true;
}
}
if ( !bAny )
continue;
if ( flFov > static_cast<float>( Settings::Legitbot::FOV ) )
continue;
if ( pPawn == m_pLegitTarget )
{
bLockedSeen = true;
Locked.pPawn = pPawn;
Locked.vAimPoint = vAimPoint;
Locked.AimAngles = AimAngles;
Locked.flFov = flFov;
Locked.flHealth = static_cast<float>( pPawn->m_iHealth() );
}
if ( flFov < Best.flFov )
{
Best.pPawn = pPawn;
Best.vAimPoint = vAimPoint;
Best.AimAngles = AimAngles;
Best.flFov = flFov;
Best.flHealth = static_cast<float>( pPawn->m_iHealth() );
}
}
if ( !Best.pPawn )
{
m_pLegitTarget = nullptr;
return;
}
const auto Now = std::chrono::steady_clock::now();
LegitCandidate Target;
if ( bLockedSeen )
{
const bool bLockExpired = ( Now - m_LegitLockTime ) >= std::chrono::milliseconds( Settings::Legitbot::TargetLockTime );
if ( !bLockExpired || Best.pPawn == m_pLegitTarget )
{
Target = Locked;
}
else if ( Best.flFov < Locked.flFov * 0.6f )
{
m_pLegitTarget = Best.pPawn;
m_LegitLockTime = Now;
m_LegitAcquireTime = Now;
Target = Best;
}
else
{
Target = Locked;
}
}
else
{
m_pLegitTarget = Best.pPawn;
m_LegitLockTime = Now;
m_LegitAcquireTime = Now;
Target = Best;
}
const bool bReactionReady = ( Now - m_LegitAcquireTime ) >= std::chrono::milliseconds( Settings::Legitbot::ReactionDelay );
if ( !bReactionReady )
return;
QAngle FinalAngles = Target.AimAngles;
float flSmooth = static_cast<float>( Settings::Legitbot::Smooth );
if ( flSmooth < 1.f )
flSmooth = 1.f;
if ( Settings::Legitbot::FovSmooth && Settings::Legitbot::FOV > 0 )
{
const float flDist = std::clamp( Target.flFov / static_cast<float>( Settings::Legitbot::FOV ) , 0.f , 1.f );
flSmooth = std::max( 1.f , flSmooth * ( 0.5f + 1.5f * flDist ) );
}
Math::SmoothAngles( ViewAngles , Target.AimAngles , FinalAngles , flSmooth );
if ( Settings::Legitbot::RCS )
{
const auto& PunchCache = pLocalPawn->m_aimPunchCache();
if ( PunchCache.Count() > 0 )
{
const float flPunchLen = std::sqrt( PunchCache[ 0 ].m_x * PunchCache[ 0 ].m_x + PunchCache[ 0 ].m_y * PunchCache[ 0 ].m_y );
if ( Settings::Legitbot::RCS_FirstBullet || flPunchLen > 0.5f )
{
FinalAngles.m_x -= PunchCache[ 0 ].m_x * Settings::Legitbot::RCS_Scale;
FinalAngles.m_y -= PunchCache[ 0 ].m_y * Settings::Legitbot::RCS_Scale;
Math::NormalizeAngles( FinalAngles );
Math::ClampAngles( FinalAngles );
}
}
}
if ( Settings::Legitbot::Jitter > 0.f )
{
std::uniform_real_distribution<float> dist( -1.f , 1.f );
FinalAngles.m_x += dist( g_LegitRng ) * Settings::Legitbot::Jitter;
FinalAngles.m_y += dist( g_LegitRng ) * Settings::Legitbot::Jitter;
Math::NormalizeAngles( FinalAngles );
Math::ClampAngles( FinalAngles );
}
GetCL_Bypass()->SetViewAngles( &FinalAngles , pInput , pUserCmd );
if ( Settings::Legitbot::DrawTarget )
{
m_bLegitTargetValid = true;
m_vLegitTargetPoint = Target.vAimPoint;
m_flLegitTargetHealth = Target.flHealth;
}
}
auto CMisc::CalculateHitchance( CCSGOInput* pInput , C_CSPlayerPawn* pTarget , const QAngle& ViewAngles , const int Samples ) -> float
{
@@ -35,6 +35,7 @@ public:
private:
auto RunTriggerbot( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void;
auto RunLegitbot( 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 CalculateSeedDirection( CCSGOInput* pInput , CUserCmd* pUserCmd , Vector3* vOutDirection ) -> bool;
@@ -88,6 +89,15 @@ private:
bool m_bRagebotTargetValid = false;
Vector3 m_vRagebotTargetPoint{};
float m_flRagebotTargetHealth = 0.f;
bool m_bLegitKeyDown = false;
bool m_bLegitToggledOn = false;
bool m_bLegitTargetValid = false;
C_CSPlayerPawn* m_pLegitTarget = nullptr;
std::chrono::steady_clock::time_point m_LegitLockTime{};
std::chrono::steady_clock::time_point m_LegitAcquireTime{};
Vector3 m_vLegitTargetPoint{};
float m_flLegitTargetHealth = 0.f;
};
auto GetMisc() -> CMisc*;
@@ -383,6 +383,89 @@ auto CAndromedaMenu::RenderMiscPanel() -> void
auto CAndromedaMenu::RenderLegitbotPanel() -> void
{
ImGui::SeparatorText( "Legit Aim" );
Checkbox( "Enabled" , Settings::Legitbot::Active );
if ( Settings::Legitbot::Active )
{
const char* LegitModeItems[] =
{
"Hold Key" , "Always" , "Toggle"
};
Combo( "Modus" , Settings::Legitbot::Mode , LegitModeItems , IM_ARRAYSIZE( LegitModeItems ) );
static const char* LegitKeyItems[] =
{
"Alt" , "Shift" , "Ctrl" , "Mouse 4" , "Mouse 5" , "Q" , "E" , "F" , "X" , "C" , "V" , "B" , "Space"
};
static const int LegitKeys[] =
{
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( LegitKeys ); i++ )
{
if ( LegitKeys[ i ] == Settings::Legitbot::Key )
{
iKeyIdx = i;
break;
}
}
if ( Combo( "Key" , iKeyIdx , LegitKeyItems , IM_ARRAYSIZE( LegitKeyItems ) ) )
Settings::Legitbot::Key = LegitKeys[ iKeyIdx ];
ImGui::SeparatorText( "Aim" );
SliderInt( "FOV (Grad)" , Settings::Legitbot::FOV , 1 , 30 );
SliderInt( "Smooth" , Settings::Legitbot::Smooth , 1 , 100 );
Checkbox( "Weicher bei großem Abstand" , Settings::Legitbot::FovSmooth );
ImGui::SeparatorText( "Hitbox" );
Checkbox( "Kopf" , Settings::Legitbot::Hitbox_Head );
Checkbox( "Hals" , Settings::Legitbot::Hitbox_Neck );
Checkbox( "Brust" , Settings::Legitbot::Hitbox_Chest );
Checkbox( "Bauch" , Settings::Legitbot::Hitbox_Stomach );
Checkbox( "Becken" , Settings::Legitbot::Hitbox_Pelvis );
ImGui::SeparatorText( "Humanisierung" );
SliderInt( "Reaktionszeit (ms)" , Settings::Legitbot::ReactionDelay , 0 , 500 );
SliderInt( "Ziel-Sperre (ms)" , Settings::Legitbot::TargetLockTime , 0 , 2000 );
SliderFloat( "Jitter (Grad)" , Settings::Legitbot::Jitter , 0.f , 5.f );
ImGui::SeparatorText( "Recoil" );
Checkbox( "Recoil Control (RCS)" , Settings::Legitbot::RCS );
if ( Settings::Legitbot::RCS )
{
Checkbox( "Auch erster Schuss" , Settings::Legitbot::RCS_FirstBullet );
SliderFloat( "RCS Skalierung" , Settings::Legitbot::RCS_Scale , 0.f , 5.f );
}
ImGui::SeparatorText( "Sicherheit" );
Checkbox( "Teammates ignorieren" , Settings::Legitbot::IgnoreTeammates );
Checkbox( "Nur sichtbar" , Settings::Legitbot::VisibleOnly );
ImGui::SeparatorText( "Overlay" );
Checkbox( "FOV-Kreis" , Settings::Legitbot::DrawFov );
Checkbox( "Ziel markieren" , Settings::Legitbot::DrawTarget );
}
ImGui::SeparatorText( "Triggerbot" );
Checkbox( "Triggerbot" , Settings::Triggerbot::Active );
@@ -138,6 +138,41 @@ namespace Settings
inline auto DrawFov = false; // FOV-Kreis ums Fadenkreuz
inline auto DrawTarget = true; // Ziel markieren
}
namespace Legitbot
{
// --- Aktivierung ---
inline auto Active = false;
inline auto Mode = 0; // 0 = Hold Key, 1 = Always, 2 = Toggle
inline auto Key = VK_MENU; // Alt
// --- Aim ---
inline auto FOV = 8; // degrees
inline auto Smooth = 8; // 1 = sofort, höher = weicher
inline auto FovSmooth = true; // weicher bei großem Abstand zum Fadenkreuz
inline auto Hitbox_Head = true;
inline auto Hitbox_Neck = false;
inline auto Hitbox_Chest = true;
inline auto Hitbox_Stomach = true;
inline auto Hitbox_Pelvis = true;
// --- Humanisierung ---
inline auto ReactionDelay = 100; // ms bis das Ziel erfasst wird
inline auto TargetLockTime = 500; // ms Ziel-Sperre vor Wechsel
inline auto Jitter = 0.f; // Grad zufällige Abweichung (0 = aus)
// --- Recoil ---
inline auto RCS = false; // Recoil Control
inline auto RCS_FirstBullet = true;
inline auto RCS_Scale = 2.f;
// --- Sicherheit ---
inline auto IgnoreTeammates = true;
inline auto VisibleOnly = true;
// --- Overlay ---
inline auto DrawFov = false; // FOV-Kreis ums Fadenkreuz
inline auto DrawTarget = true; // Ziel markieren
}
namespace Colors
{
namespace Visual