Add legit aimbot: smooth aim, per-hitbox toggles, humanization (reaction, target lock, jitter) and RCS with first-bullet option
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user