diff --git a/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Features/CMisc/CMisc.cpp b/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Features/CMisc/CMisc.cpp index c5f4d12..5fa5d05 100644 --- a/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Features/CMisc/CMisc.cpp +++ b/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Features/CMisc/CMisc.cpp @@ -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( i ) / k_Segments ) * 2.f * k_Pi; + const float flAngle1 = ( static_cast( 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( 255 * ( 1.f - flHp / 100.f ) ) , static_cast( 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( pEntity ); + + if ( pController == GetCL_Players()->GetLocalPlayerController() ) + continue; + + auto* pPawn = pController->m_hPawn().Get(); + + 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( 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( pPawn->m_iHealth() ); + } + + if ( flFov < Best.flFov ) + { + Best.pPawn = pPawn; + Best.vAimPoint = vAimPoint; + Best.AimAngles = AimAngles; + Best.flFov = flFov; + Best.flHealth = static_cast( 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( 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( 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 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 { diff --git a/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Features/CMisc/CMisc.hpp b/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Features/CMisc/CMisc.hpp index b173a8f..dffb7ed 100644 --- a/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Features/CMisc/CMisc.hpp +++ b/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Features/CMisc/CMisc.hpp @@ -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*; diff --git a/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/GUI/CAndromedaMenu.cpp b/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/GUI/CAndromedaMenu.cpp index 7547a5f..724ffc4 100644 --- a/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/GUI/CAndromedaMenu.cpp +++ b/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/GUI/CAndromedaMenu.cpp @@ -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 ); diff --git a/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Settings/Settings.hpp b/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Settings/Settings.hpp index 2d19902..83309c9 100644 --- a/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Settings/Settings.hpp +++ b/Andromeda-CS2-Base/Andromeda-CS2-Base/AndromedaClient/Settings/Settings.hpp @@ -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