1351 lines
34 KiB
C++
1351 lines
34 KiB
C++
#include "CMisc.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <ctime>
|
|
#include <mmsystem.h>
|
|
|
|
#pragma comment( lib , "winmm.lib" )
|
|
|
|
#include <CS2/SDK/SDK.hpp>
|
|
#include <CS2/SDK/Interface/IEngineToClient.hpp>
|
|
#include <CS2/SDK/Interface/IGameEvent.hpp>
|
|
#include <CS2/SDK/Update/CCSGOInput.hpp>
|
|
#include <CS2/SDK/Update/CUserCmd.hpp>
|
|
#include <CS2/SDK/Types/CEntityData.hpp>
|
|
|
|
#include <AndromedaClient/Settings/Settings.hpp>
|
|
#include <AndromedaClient/Fonts/CFontManager.hpp>
|
|
#include <AndromedaClient/Render/CRenderStackSystem.hpp>
|
|
|
|
#include <GameClient/CL_Players.hpp>
|
|
#include <GameClient/CL_Weapons.hpp>
|
|
#include <GameClient/CL_Trace.hpp>
|
|
#include <GameClient/CL_Bypass.hpp>
|
|
#include <GameClient/CEntityCache/CEntityCache.hpp>
|
|
#include <CS2/SDK/Types/CBaseTypes.hpp>
|
|
#include <CS2/SDK/FunctionListSDK.hpp>
|
|
|
|
#include <random>
|
|
|
|
#include <ImGui/imgui.h>
|
|
|
|
namespace
|
|
{
|
|
// Deterministic Valve RNG (matches the game's math::random_seed generator).
|
|
class CValveRng
|
|
{
|
|
public:
|
|
auto Seed( int s ) -> void
|
|
{
|
|
m_State = -std::abs( s );
|
|
m_Index = 0;
|
|
m_bSeeded = false;
|
|
}
|
|
|
|
auto Generate() -> int
|
|
{
|
|
if ( !m_bSeeded )
|
|
{
|
|
auto v = -m_State;
|
|
|
|
if ( v < 1 )
|
|
v = 1;
|
|
|
|
for ( int j = 39; j >= 0; --j )
|
|
{
|
|
v = LCG( v );
|
|
|
|
if ( j < 32 )
|
|
m_Table[ j ] = v;
|
|
}
|
|
|
|
m_State = v;
|
|
m_Index = m_Table[ 0 ];
|
|
m_bSeeded = true;
|
|
}
|
|
|
|
m_State = LCG( m_State );
|
|
|
|
const auto Index = m_Index / 0x4000000;
|
|
m_Index = m_Table[ Index ];
|
|
m_Table[ Index ] = m_State;
|
|
|
|
return m_Index;
|
|
}
|
|
|
|
auto RandomFloat( float Min = 0.f , float Max = 1.f ) -> float
|
|
{
|
|
const auto Raw = Generate();
|
|
const auto Norm = std::fminf( 0.99999988f , static_cast<float>( Raw ) * 4.6566129e-10f );
|
|
|
|
return Min + Norm * ( Max - Min );
|
|
}
|
|
|
|
private:
|
|
static auto LCG( int State ) -> int
|
|
{
|
|
const auto k = State / 127773;
|
|
auto Result = 16807 * ( State - k * 127773 ) - 2836 * k;
|
|
|
|
if ( Result < 0 )
|
|
Result += 2147483647;
|
|
|
|
return Result;
|
|
}
|
|
|
|
int m_State = 0;
|
|
int m_Index = 0;
|
|
int m_Table[ 32 ]{};
|
|
bool m_bSeeded = false;
|
|
};
|
|
|
|
// Minimal SHA-1 (for computing the spread seed from angles + tick).
|
|
class CSha1
|
|
{
|
|
public:
|
|
auto Reset() -> void
|
|
{
|
|
m_State[ 0 ] = 0x67452301;
|
|
m_State[ 1 ] = 0xEFCDAB89;
|
|
m_State[ 2 ] = 0x98BADCFE;
|
|
m_State[ 3 ] = 0x10325476;
|
|
m_State[ 4 ] = 0xC3D2E1F0;
|
|
m_Count = 0;
|
|
}
|
|
|
|
auto Update( const void* pData , std::size_t Len ) -> void
|
|
{
|
|
const auto* pBytes = static_cast<const uint8_t*>( pData );
|
|
auto Index = static_cast<std::size_t>( m_Count & 63 );
|
|
m_Count += Len;
|
|
|
|
std::size_t i = 0;
|
|
|
|
if ( Index )
|
|
{
|
|
auto PartLen = 64 - Index;
|
|
|
|
if ( Len >= PartLen )
|
|
{
|
|
std::memcpy( m_Buffer + Index , pBytes , PartLen );
|
|
Transform( m_Buffer );
|
|
i = PartLen;
|
|
}
|
|
else
|
|
{
|
|
std::memcpy( m_Buffer + Index , pBytes , Len );
|
|
return;
|
|
}
|
|
}
|
|
|
|
for ( ; i + 64 <= Len; i += 64 )
|
|
Transform( pBytes + i );
|
|
|
|
if ( i < Len )
|
|
std::memcpy( m_Buffer , pBytes + i , Len - i );
|
|
}
|
|
|
|
auto Final() -> void
|
|
{
|
|
uint8_t Padding[ 64 ]{};
|
|
Padding[ 0 ] = 0x80;
|
|
|
|
const auto Index = static_cast<std::size_t>( m_Count & 63 );
|
|
const auto PadLen = ( Index < 56 ) ? ( 56 - Index ) : ( 120 - Index );
|
|
const auto BitCount = m_Count * 8;
|
|
|
|
Update( Padding , PadLen );
|
|
|
|
uint8_t Bits[ 8 ]{};
|
|
|
|
for ( int i = 0; i < 8; ++i )
|
|
Bits[ 7 - i ] = static_cast<uint8_t>( BitCount >> ( i * 8 ) );
|
|
|
|
Update( Bits , 8 );
|
|
|
|
for ( int i = 0; i < 5; ++i )
|
|
{
|
|
m_Digest[ i * 4 + 0 ] = static_cast<uint8_t>( m_State[ i ] >> 24 );
|
|
m_Digest[ i * 4 + 1 ] = static_cast<uint8_t>( m_State[ i ] >> 16 );
|
|
m_Digest[ i * 4 + 2 ] = static_cast<uint8_t>( m_State[ i ] >> 8 );
|
|
m_Digest[ i * 4 + 3 ] = static_cast<uint8_t>( m_State[ i ] );
|
|
}
|
|
}
|
|
|
|
auto GetFirstUInt32() const -> uint32_t
|
|
{
|
|
uint32_t Result;
|
|
std::memcpy( &Result , m_Digest , sizeof Result );
|
|
return Result;
|
|
}
|
|
|
|
private:
|
|
static auto RotL( uint32_t v , int n ) -> uint32_t
|
|
{
|
|
return ( v << n ) | ( v >> ( 32 - n ) );
|
|
}
|
|
|
|
auto Transform( const uint8_t* pBlock ) -> void
|
|
{
|
|
uint32_t w[ 80 ]{};
|
|
|
|
for ( int i = 0; i < 16; ++i )
|
|
w[ i ] = static_cast<uint32_t>( pBlock[ i * 4 ] ) << 24 | static_cast<uint32_t>( pBlock[ i * 4 + 1 ] ) << 16 | static_cast<uint32_t>( pBlock[ i * 4 + 2 ] ) << 8 | static_cast<uint32_t>( pBlock[ i * 4 + 3 ] );
|
|
|
|
for ( int i = 16; i < 80; ++i )
|
|
w[ i ] = RotL( w[ i - 3 ] ^ w[ i - 8 ] ^ w[ i - 14 ] ^ w[ i - 16 ] , 1 );
|
|
|
|
auto a = m_State[ 0 ];
|
|
auto b = m_State[ 1 ];
|
|
auto c = m_State[ 2 ];
|
|
auto d = m_State[ 3 ];
|
|
auto e = m_State[ 4 ];
|
|
|
|
for ( int i = 0; i < 80; ++i )
|
|
{
|
|
uint32_t f , k;
|
|
|
|
if ( i < 20 )
|
|
{
|
|
f = ( b & c ) | ( ( ~b ) & d );
|
|
k = 0x5A827999;
|
|
}
|
|
else if ( i < 40 )
|
|
{
|
|
f = b ^ c ^ d;
|
|
k = 0x6ED9EBA1;
|
|
}
|
|
else if ( i < 60 )
|
|
{
|
|
f = ( b & c ) | ( b & d ) | ( c & d );
|
|
k = 0x8F1BBCDC;
|
|
}
|
|
else
|
|
{
|
|
f = b ^ c ^ d;
|
|
k = 0xCA62C1D6;
|
|
}
|
|
|
|
const auto Temp = RotL( a , 5 ) + f + e + k + w[ i ];
|
|
e = d;
|
|
d = c;
|
|
c = RotL( b , 30 );
|
|
b = a;
|
|
a = Temp;
|
|
}
|
|
|
|
m_State[ 0 ] += a;
|
|
m_State[ 1 ] += b;
|
|
m_State[ 2 ] += c;
|
|
m_State[ 3 ] += d;
|
|
m_State[ 4 ] += e;
|
|
}
|
|
|
|
uint32_t m_State[ 5 ]{};
|
|
std::uint64_t m_Count = 0;
|
|
uint8_t m_Buffer[ 64 ]{};
|
|
uint8_t m_Digest[ 20 ]{};
|
|
};
|
|
|
|
auto NormalizeAngle( float Angle ) -> float
|
|
{
|
|
return Angle - std::floorf( Angle * 0.0027777778f + 0.5f ) * 360.0f;
|
|
}
|
|
|
|
auto QuantizeAngle( float Angle ) -> float
|
|
{
|
|
return std::floorf( NormalizeAngle( Angle ) * 2.0f ) * 0.5f;
|
|
}
|
|
|
|
auto GetSpreadSeed( const QAngle& ViewAngles , int Tick ) -> uint32_t
|
|
{
|
|
struct
|
|
{
|
|
float Pitch;
|
|
float Yaw;
|
|
int PlayerRenderTick;
|
|
} Buffer{};
|
|
|
|
Buffer.Pitch = QuantizeAngle( ViewAngles.m_x );
|
|
Buffer.Yaw = QuantizeAngle( ViewAngles.m_y );
|
|
Buffer.PlayerRenderTick = Tick;
|
|
|
|
CSha1 Hash;
|
|
Hash.Reset();
|
|
Hash.Update( &Buffer , 12 );
|
|
Hash.Final();
|
|
|
|
return Hash.GetFirstUInt32();
|
|
}
|
|
|
|
struct SeedSpread2_t
|
|
{
|
|
float x = 0.f;
|
|
float y = 0.f;
|
|
};
|
|
|
|
auto CalculateSeedSpread( int Seed , float Inaccuracy , float Spread , int ItemDefIdx ) -> SeedSpread2_t
|
|
{
|
|
constexpr auto k_RevolverId = 64;
|
|
constexpr auto k_NegevId = 28;
|
|
constexpr auto k_TwoPi = 6.2831853f;
|
|
|
|
CValveRng Rng;
|
|
Rng.Seed( Seed );
|
|
|
|
auto InacR = Rng.RandomFloat( 0.f , 1.f );
|
|
const auto InacA = Rng.RandomFloat( 0.f , k_TwoPi );
|
|
|
|
if ( ItemDefIdx == k_RevolverId )
|
|
InacR = 1.f - ( InacR * InacR );
|
|
else if ( ItemDefIdx == k_NegevId )
|
|
InacR = 1.f - ( InacR * InacR );
|
|
|
|
InacR *= Inaccuracy;
|
|
|
|
auto SprR = Rng.RandomFloat( 0.f , 1.f );
|
|
const auto SprA = Rng.RandomFloat( 0.f , k_TwoPi );
|
|
|
|
if ( ItemDefIdx == k_RevolverId )
|
|
SprR = 1.f - ( SprR * SprR );
|
|
else if ( ItemDefIdx == k_NegevId )
|
|
SprR = 1.f - ( SprR * SprR );
|
|
|
|
SprR *= Spread;
|
|
|
|
return
|
|
{
|
|
std::cosf( SprA ) * SprR + std::cosf( InacA ) * InacR,
|
|
std::sinf( SprA ) * SprR + std::sinf( InacA ) * InacR
|
|
};
|
|
}
|
|
}
|
|
|
|
static CMisc g_CMisc{};
|
|
|
|
auto CMisc::OnRender() -> void
|
|
{
|
|
if ( !Settings::Misc::Watermark && !Settings::Misc::Speedometer )
|
|
return;
|
|
|
|
auto& pFont = GetFontManager()->m_VerdanaFont;
|
|
float Y = 8.f;
|
|
|
|
if ( Settings::Misc::Speedometer )
|
|
{
|
|
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
|
|
|
|
if ( pLocalPawn && pLocalPawn->IsAlive() )
|
|
{
|
|
const float flSpeed = pLocalPawn->m_vecVelocity().Length2D() * 0.05f;
|
|
|
|
char szBuffer[ 64 ];
|
|
std::snprintf( szBuffer , sizeof szBuffer , XorStr( "%.0f u/s" ) , flSpeed );
|
|
|
|
pFont.DrawString( 8 , Y , ImColor( 255 , 255 , 255 ) , FW1_LEFT , "%s" , szBuffer );
|
|
}
|
|
|
|
Y += pFont.GetFontSize();
|
|
}
|
|
|
|
if ( !Settings::Misc::Watermark )
|
|
return;
|
|
|
|
const auto t = std::time( nullptr );
|
|
std::tm tm{};
|
|
localtime_s( &tm , &t );
|
|
|
|
char szBuffer[ 128 ];
|
|
|
|
std::snprintf( szBuffer , sizeof szBuffer , XorStr( "Evicted | FPS: %.0f | %02d:%02d:%02d" ) , ImGui::GetIO().Framerate , tm.tm_hour , tm.tm_min , tm.tm_sec );
|
|
|
|
pFont.DrawString( 8 , Y , ImColor( 255 , 255 , 0 ) , FW1_LEFT , "%s" , szBuffer );
|
|
}
|
|
|
|
auto CMisc::OnClientOutput() -> void
|
|
{
|
|
if ( !SDK::Interfaces::EngineToClient()->IsInGame() )
|
|
return;
|
|
|
|
if ( Settings::Misc::SpectatorList )
|
|
{
|
|
auto* pLocalController = GetCL_Players()->GetLocalPlayerController();
|
|
|
|
auto* pFont = &GetFontManager()->m_VerdanaFont;
|
|
|
|
if ( pLocalController && pFont )
|
|
{
|
|
const CHandle LocalPawnHandle = pLocalController->m_hPawn();
|
|
|
|
const auto DisplaySize = ImGui::GetIO().DisplaySize;
|
|
|
|
const float ListX = DisplaySize.x - 8.f;
|
|
float ListY = pFont->GetFontSize() + 12.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 == pLocalController )
|
|
continue;
|
|
|
|
auto* pPawn = pController->m_hPawn().Get<C_CSPlayerPawn>();
|
|
|
|
if ( !pPawn || !pPawn->IsPlayerPawn() )
|
|
continue;
|
|
|
|
auto* pObserverServices = pPawn->m_pObserverServices();
|
|
|
|
if ( !pObserverServices )
|
|
continue;
|
|
|
|
const auto ObserverMode = pObserverServices->m_iObserverMode();
|
|
|
|
if ( ObserverMode != OBS_MODE_IN_EYE && ObserverMode != OBS_MODE_CHASE )
|
|
continue;
|
|
|
|
if ( pObserverServices->m_hObserverTarget() != LocalPawnHandle )
|
|
continue;
|
|
|
|
const char* szName = pController->m_sSanitizedPlayerName();
|
|
|
|
if ( !szName || !szName[ 0 ] )
|
|
continue;
|
|
|
|
GetRenderStackSystem()->DrawString( pFont , ImVec2( ListX , ListY ) , FW1_RIGHT | FW1_TOP , ImColor( 255 , 255 , 255 ) , "%s" , szName );
|
|
|
|
ListY += pFont->GetFontSize() + 2.f;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( Settings::Triggerbot::Active && Settings::Triggerbot::DrawIndicator )
|
|
{
|
|
if ( m_bTargetInCrosshair )
|
|
{
|
|
const auto DisplaySize = ImGui::GetIO().DisplaySize;
|
|
|
|
const ImVec2 Center( DisplaySize.x * 0.5f , DisplaySize.y * 0.5f );
|
|
|
|
const ImColor IndicatorColor = m_bTriggerFiring ? ImColor( 0 , 255 , 0 ) : ImColor( 255 , 200 , 0 );
|
|
|
|
GetRenderStackSystem()->DrawCircleFilled( Center , 3.f , IndicatorColor );
|
|
}
|
|
}
|
|
|
|
if ( Settings::Misc::Hitmarker )
|
|
{
|
|
if ( m_HitTime.time_since_epoch().count() > 0 )
|
|
{
|
|
const auto Elapsed = std::chrono::duration<float>( std::chrono::steady_clock::now() - m_HitTime ).count();
|
|
|
|
if ( Elapsed <= 0.25f )
|
|
{
|
|
const auto DisplaySize = ImGui::GetIO().DisplaySize;
|
|
|
|
const ImVec2 Center( DisplaySize.x * 0.5f , DisplaySize.y * 0.5f );
|
|
|
|
const float Size = 6.f;
|
|
|
|
GetRenderStackSystem()->DrawLine( ImVec2( Center.x - Size , Center.y - Size ) , ImVec2( Center.x - 2.f , Center.y - 2.f ) , ImColor( 255 , 255 , 255 ) , 1.5f );
|
|
GetRenderStackSystem()->DrawLine( ImVec2( Center.x + Size , Center.y - Size ) , ImVec2( Center.x + 2.f , Center.y - 2.f ) , ImColor( 255 , 255 , 255 ) , 1.5f );
|
|
GetRenderStackSystem()->DrawLine( ImVec2( Center.x - Size , Center.y + Size ) , ImVec2( Center.x - 2.f , Center.y + 2.f ) , ImColor( 255 , 255 , 255 ) , 1.5f );
|
|
GetRenderStackSystem()->DrawLine( ImVec2( Center.x + Size , Center.y + Size ) , ImVec2( Center.x + 2.f , Center.y + 2.f ) , ImColor( 255 , 255 , 255 ) , 1.5f );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto CMisc::OnCreateMove( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
|
|
{
|
|
if ( !pUserCmd )
|
|
return;
|
|
|
|
if ( Settings::Triggerbot::Active )
|
|
RunTriggerbot( pInput , pUserCmd );
|
|
|
|
if ( Settings::Misc::Bunnyhop )
|
|
{
|
|
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
|
|
|
|
if ( pLocalPawn && pLocalPawn->IsAlive() )
|
|
{
|
|
constexpr auto FL_ONGROUND = 1u;
|
|
|
|
const bool bOnGround = ( pLocalPawn->m_fFlags() & FL_ONGROUND ) != 0;
|
|
const bool bHoldingJump = ( pUserCmd->button_states.buttonstate1 & IN_JUMP ) != 0;
|
|
|
|
if ( bHoldingJump )
|
|
{
|
|
if ( bOnGround )
|
|
{
|
|
if ( Settings::Misc::PerfectBhop )
|
|
GetCL_Bypass()->SetJump( pUserCmd , true );
|
|
else
|
|
pUserCmd->button_states.buttonstate1 |= IN_JUMP;
|
|
}
|
|
else
|
|
{
|
|
pUserCmd->button_states.buttonstate1 &= ~IN_JUMP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RunMovement( pInput , pUserCmd );
|
|
|
|
if ( Settings::Misc::FOVChanger )
|
|
{
|
|
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
|
|
|
|
if ( pLocalPawn )
|
|
{
|
|
if ( auto* pCameraServices = pLocalPawn->m_pCameraServices(); pCameraServices )
|
|
pCameraServices->m_iFOV() = static_cast<uint32>( Settings::Misc::FOV );
|
|
}
|
|
}
|
|
}
|
|
|
|
auto CMisc::RunMovement( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
|
|
{
|
|
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
|
|
|
|
if ( !pLocalPawn || !pLocalPawn->IsAlive() )
|
|
{
|
|
m_bWasOnGround = false;
|
|
return;
|
|
}
|
|
|
|
const auto flFlags = pLocalPawn->m_fFlags();
|
|
|
|
constexpr uint32 FL_ONGROUND = 1u;
|
|
|
|
const bool bOnGround = ( flFlags & FL_ONGROUND ) != 0;
|
|
|
|
if ( Settings::Misc::SubtickStrafe )
|
|
RunSubtickStrafe( pInput , pUserCmd , pLocalPawn , bOnGround );
|
|
else if ( Settings::Misc::NullStrafe )
|
|
RunNullStrafe( pInput , pUserCmd , pLocalPawn , bOnGround );
|
|
else if ( Settings::Misc::AutoStrafe )
|
|
RunAutoStrafe( pInput , pUserCmd , pLocalPawn , bOnGround );
|
|
|
|
if ( Settings::Misc::JumpBug )
|
|
{
|
|
if ( !bOnGround && pLocalPawn->m_flFallVelocity() > 430.f )
|
|
{
|
|
pUserCmd->button_states.buttonstate1 &= ~IN_DUCK;
|
|
GetCL_Bypass()->SetJump( pUserCmd , true );
|
|
}
|
|
}
|
|
|
|
if ( Settings::Misc::EdgeBug )
|
|
RunEdgeBug( pInput , pUserCmd , pLocalPawn , bOnGround );
|
|
|
|
if ( Settings::Misc::EdgeJump )
|
|
{
|
|
if ( m_bWasOnGround && !bOnGround )
|
|
{
|
|
if ( pUserCmd->button_states.buttonstate1 & ( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ) )
|
|
GetCL_Bypass()->SetJump( pUserCmd , true );
|
|
}
|
|
}
|
|
|
|
if ( Settings::Misc::JumpCrouch )
|
|
{
|
|
if ( bOnGround && ( pUserCmd->button_states.buttonstate1 & IN_JUMP ) )
|
|
pUserCmd->button_states.buttonstate1 |= IN_DUCK;
|
|
}
|
|
|
|
if ( Settings::Misc::LongJump )
|
|
{
|
|
if ( !bOnGround )
|
|
pUserCmd->button_states.buttonstate1 |= IN_DUCK;
|
|
}
|
|
|
|
if ( Settings::Misc::PixelSurf )
|
|
{
|
|
if ( !bOnGround )
|
|
{
|
|
pUserCmd->button_states.buttonstate1 |= IN_DUCK;
|
|
}
|
|
else
|
|
{
|
|
if ( pUserCmd->button_states.buttonstate1 & ( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ) )
|
|
GetCL_Bypass()->SetJump( pUserCmd , true );
|
|
}
|
|
}
|
|
|
|
if ( Settings::Misc::FastStop )
|
|
{
|
|
if ( bOnGround )
|
|
{
|
|
if ( !( pUserCmd->button_states.buttonstate1 & ( IN_FORWARD | IN_BACK | IN_MOVELEFT | IN_MOVERIGHT ) ) )
|
|
{
|
|
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 );
|
|
|
|
auto* pViewAngles = CCSGOInput_GetViewAngles( pInput , 0 );
|
|
|
|
if ( pViewAngles )
|
|
{
|
|
float flDelta = flVelYaw - pViewAngles->m_y;
|
|
|
|
while ( flDelta > 180.f )
|
|
flDelta -= 360.f;
|
|
|
|
while ( flDelta < -180.f )
|
|
flDelta += 360.f;
|
|
|
|
if ( flDelta > -45.f && flDelta <= 45.f )
|
|
pUserCmd->button_states.buttonstate1 |= IN_BACK;
|
|
else if ( flDelta > 45.f && flDelta <= 135.f )
|
|
pUserCmd->button_states.buttonstate1 |= IN_MOVELEFT;
|
|
else if ( flDelta > 135.f || flDelta <= -135.f )
|
|
pUserCmd->button_states.buttonstate1 |= IN_FORWARD;
|
|
else
|
|
pUserCmd->button_states.buttonstate1 |= IN_MOVERIGHT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( Settings::Misc::SlowWalk )
|
|
pUserCmd->button_states.buttonstate1 |= IN_SPEED;
|
|
|
|
m_bWasOnGround = bOnGround;
|
|
}
|
|
|
|
auto CMisc::RunAutoStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void
|
|
{
|
|
if ( bOnGround )
|
|
return;
|
|
|
|
if ( pUserCmd->button_states.buttonstate1 & ( IN_FORWARD | IN_BACK ) )
|
|
return;
|
|
|
|
const Vector3 Velocity = pLocalPawn->m_vecVelocity();
|
|
|
|
const float flSpeed = Velocity.Length2D();
|
|
|
|
if ( flSpeed < 0.1f )
|
|
return;
|
|
|
|
constexpr float k_Pi = 3.14159265358979f;
|
|
|
|
const float flVelYaw = std::atan2f( Velocity.m_y , Velocity.m_x ) * ( 180.f / k_Pi );
|
|
|
|
auto* pViewAngles = CCSGOInput_GetViewAngles( pInput , 0 );
|
|
|
|
if ( !pViewAngles )
|
|
return;
|
|
|
|
float flDelta = flVelYaw - pViewAngles->m_y;
|
|
|
|
while ( flDelta > 180.f )
|
|
flDelta -= 360.f;
|
|
|
|
while ( flDelta < -180.f )
|
|
flDelta += 360.f;
|
|
|
|
constexpr float k_TurnSpeed = 5.f;
|
|
|
|
QAngle NewAngles = *pViewAngles;
|
|
|
|
if ( flDelta > 0.f )
|
|
{
|
|
NewAngles.m_y += k_TurnSpeed;
|
|
pUserCmd->button_states.buttonstate1 |= IN_MOVERIGHT;
|
|
}
|
|
else
|
|
{
|
|
NewAngles.m_y -= k_TurnSpeed;
|
|
pUserCmd->button_states.buttonstate1 |= IN_MOVELEFT;
|
|
}
|
|
|
|
GetCL_Bypass()->SetViewAngles( &NewAngles , pInput , pUserCmd );
|
|
}
|
|
|
|
auto CMisc::RunNullStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void
|
|
{
|
|
if ( bOnGround )
|
|
return;
|
|
|
|
if ( !pUserCmd || !pLocalPawn )
|
|
return;
|
|
|
|
auto* pBaseCmd = pUserCmd->cmd.mutable_base();
|
|
|
|
if ( !pBaseCmd )
|
|
return;
|
|
|
|
auto* pViewAngles = CCSGOInput_GetViewAngles( pInput , 0 );
|
|
|
|
if ( !pViewAngles )
|
|
return;
|
|
|
|
const Vector3 Velocity = pLocalPawn->m_vecVelocity();
|
|
|
|
const float flSpeed = Velocity.Length2D();
|
|
|
|
if ( flSpeed <= 10.f )
|
|
return;
|
|
|
|
constexpr float k_Pi = 3.14159265358979f;
|
|
|
|
const float flVelYaw = std::atan2f( Velocity.m_y , Velocity.m_x );
|
|
const float flViewYaw = pViewAngles->m_y * ( k_Pi / 180.f );
|
|
const float flRelativeYaw = flVelYaw - flViewYaw;
|
|
|
|
const float flForward = std::clamp( -std::cosf( flRelativeYaw ) , -1.f , 1.f );
|
|
const float flLeft = std::clamp( -std::sinf( flRelativeYaw ) , -1.f , 1.f );
|
|
|
|
pBaseCmd->set_forwardmove( flForward );
|
|
pBaseCmd->set_leftmove( flLeft );
|
|
|
|
GetCL_Bypass()->AddProcessSubTick( 0 , false , 0.f , pBaseCmd->forwardmove() - m_flLastForwardMove , pBaseCmd->leftmove() - m_flLastLeftMove );
|
|
|
|
m_flLastForwardMove = pBaseCmd->forwardmove();
|
|
m_flLastLeftMove = pBaseCmd->leftmove();
|
|
}
|
|
|
|
auto CMisc::RunSubtickStrafe( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void
|
|
{
|
|
if ( bOnGround )
|
|
return;
|
|
|
|
if ( !pUserCmd || !pLocalPawn )
|
|
return;
|
|
|
|
auto* pBaseCmd = pUserCmd->cmd.mutable_base();
|
|
|
|
if ( !pBaseCmd )
|
|
return;
|
|
|
|
auto* pViewAngles = CCSGOInput_GetViewAngles( pInput , 0 );
|
|
|
|
if ( !pViewAngles )
|
|
return;
|
|
|
|
constexpr float k_Pi = 3.14159265358979f;
|
|
constexpr int k_SubtickCount = 32;
|
|
constexpr float k_TickInterval = 1.f / 64.f;
|
|
constexpr float k_FrameTime = k_TickInterval / static_cast<float>( k_SubtickCount );
|
|
constexpr float k_SvAiraccelerate = 12.f;
|
|
constexpr float k_SvAirMaxWishspeed = 30.f;
|
|
constexpr float k_SvGravity = 800.f;
|
|
constexpr float k_MaxSpeed = 250.f;
|
|
|
|
const auto uButtons = pUserCmd->button_states.buttonstate1;
|
|
const bool bLeft = ( uButtons & IN_MOVELEFT ) != 0;
|
|
const bool bRight = ( uButtons & IN_MOVERIGHT ) != 0;
|
|
|
|
float flYawOffset = 0.f;
|
|
|
|
if ( bLeft )
|
|
flYawOffset += 90.f;
|
|
|
|
if ( bRight )
|
|
flYawOffset -= 90.f;
|
|
|
|
if ( uButtons & IN_FORWARD )
|
|
flYawOffset *= 0.5f;
|
|
else if ( uButtons & IN_BACK )
|
|
flYawOffset = -flYawOffset * 0.5f + 180.f;
|
|
|
|
const float flCmdForward = pBaseCmd->forwardmove();
|
|
const float flCmdLeft = pBaseCmd->leftmove();
|
|
|
|
Vector3 VelocitySim = pLocalPawn->m_vecVelocity();
|
|
|
|
float flLastImpulseForward = m_flLastForwardMove;
|
|
float flLastImpulseLeft = m_flLastLeftMove;
|
|
|
|
for ( auto i = 0; i < k_SubtickCount; ++i )
|
|
{
|
|
pBaseCmd->set_forwardmove( flCmdForward );
|
|
pBaseCmd->set_leftmove( flCmdLeft );
|
|
|
|
float flSpeed = VelocitySim.Length2D();
|
|
|
|
if ( flSpeed > 0.0001f )
|
|
{
|
|
const float flYawRad = pViewAngles->m_y * ( k_Pi / 180.f );
|
|
|
|
const Vector3 vForward( std::cosf( flYawRad ) , std::sinf( flYawRad ) , 0.f );
|
|
const Vector3 vRight( -std::sinf( flYawRad ) , std::cosf( flYawRad ) , 0.f );
|
|
|
|
Vector3 vWishDir
|
|
{
|
|
( vForward.m_x * flCmdForward * k_MaxSpeed ) + ( vRight.m_x * flCmdLeft * k_MaxSpeed ),
|
|
( vForward.m_y * flCmdForward * k_MaxSpeed ) + ( vRight.m_y * flCmdLeft * k_MaxSpeed ),
|
|
0.f
|
|
};
|
|
|
|
float flWishSpeed = vWishDir.Length2D();
|
|
|
|
if ( flWishSpeed > 0.0001f )
|
|
{
|
|
vWishDir.m_x /= flWishSpeed;
|
|
vWishDir.m_y /= flWishSpeed;
|
|
}
|
|
|
|
flWishSpeed = std::fminf( flWishSpeed , k_MaxSpeed );
|
|
|
|
const float flCappedWish = std::fminf( flWishSpeed , k_SvAirMaxWishspeed );
|
|
const float flCurrentSpeed = ( VelocitySim.m_x * vWishDir.m_x ) + ( VelocitySim.m_y * vWishDir.m_y );
|
|
const float flAddSpeed = flCappedWish - flCurrentSpeed;
|
|
|
|
if ( flAddSpeed > 0.f )
|
|
{
|
|
const float flAccelSpeed = k_SvAiraccelerate * k_MaxSpeed * k_FrameTime;
|
|
const float flGain = std::fminf( flAccelSpeed * 0.5f , flAddSpeed );
|
|
|
|
VelocitySim.m_x += vWishDir.m_x * flGain;
|
|
VelocitySim.m_y += vWishDir.m_y * flGain;
|
|
}
|
|
}
|
|
|
|
VelocitySim.m_z -= k_SvGravity * k_FrameTime;
|
|
flSpeed = VelocitySim.Length2D();
|
|
|
|
if ( flSpeed >= 10.f )
|
|
{
|
|
pBaseCmd->set_forwardmove( 0.f );
|
|
pBaseCmd->set_leftmove( 0.f );
|
|
|
|
const float flVelocityAngle = std::atan2f( VelocitySim.m_y , VelocitySim.m_x ) * ( 180.f / k_Pi );
|
|
|
|
const float flAccelSpeed = k_SvAiraccelerate * k_MaxSpeed * k_FrameTime;
|
|
const float flOptimalFloor = std::fmaxf( flAccelSpeed * 0.5f , k_SvAirMaxWishspeed - flAccelSpeed * 0.5f );
|
|
const float flIdealAngle = std::clamp( std::atanf( flOptimalFloor / flSpeed ) * ( 180.f / k_Pi ) , 0.f , 45.f );
|
|
|
|
float flTargetYaw = pViewAngles->m_y + flYawOffset;
|
|
|
|
while ( flTargetYaw > 180.f )
|
|
flTargetYaw -= 360.f;
|
|
|
|
while ( flTargetYaw < -180.f )
|
|
flTargetYaw += 360.f;
|
|
|
|
float flVelocityDelta = flTargetYaw - flVelocityAngle;
|
|
|
|
while ( flVelocityDelta > 180.f )
|
|
flVelocityDelta -= 360.f;
|
|
|
|
while ( flVelocityDelta < -180.f )
|
|
flVelocityDelta += 360.f;
|
|
|
|
if ( ( std::fabsf( flVelocityDelta ) > 170.f && flSpeed > 80.f ) || ( flVelocityDelta > flIdealAngle && flSpeed > 80.f ) )
|
|
{
|
|
flTargetYaw = flVelocityAngle + flIdealAngle;
|
|
pBaseCmd->set_leftmove( -1.f );
|
|
}
|
|
else if ( -flIdealAngle <= flVelocityDelta || flSpeed <= 80.f )
|
|
{
|
|
if ( m_bSideSwitch )
|
|
{
|
|
flTargetYaw = flTargetYaw - flIdealAngle;
|
|
pBaseCmd->set_leftmove( -1.f );
|
|
}
|
|
else
|
|
{
|
|
flTargetYaw = flTargetYaw + flIdealAngle;
|
|
pBaseCmd->set_leftmove( 1.f );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flTargetYaw = flVelocityAngle - flIdealAngle;
|
|
pBaseCmd->set_leftmove( 1.f );
|
|
}
|
|
|
|
while ( flTargetYaw > 180.f )
|
|
flTargetYaw -= 360.f;
|
|
|
|
while ( flTargetYaw < -180.f )
|
|
flTargetYaw += 360.f;
|
|
|
|
RotateMoveToYaw( pBaseCmd , flTargetYaw , pViewAngles->m_y );
|
|
}
|
|
|
|
GetCL_Bypass()->AddProcessSubTick( 0 , false , static_cast<float>( i ) / static_cast<float>( k_SubtickCount ) , pBaseCmd->forwardmove() - flLastImpulseForward , pBaseCmd->leftmove() - flLastImpulseLeft );
|
|
|
|
flLastImpulseForward = pBaseCmd->forwardmove();
|
|
flLastImpulseLeft = pBaseCmd->leftmove();
|
|
|
|
m_bSideSwitch = !m_bSideSwitch;
|
|
}
|
|
|
|
m_flLastForwardMove = flLastImpulseForward;
|
|
m_flLastLeftMove = flLastImpulseLeft;
|
|
}
|
|
|
|
auto CMisc::RotateMoveToYaw( CBaseUserCmdPB* pBaseCmd , const float flTargetYaw , const float flViewYaw ) -> void
|
|
{
|
|
const float k_Pi = 3.14159265358979f;
|
|
|
|
const float flTargetRad = flTargetYaw * ( k_Pi / 180.f );
|
|
const float flViewRad = flViewYaw * ( k_Pi / 180.f );
|
|
|
|
const float flForwardMove = pBaseCmd->forwardmove();
|
|
const float flSideMove = pBaseCmd->leftmove();
|
|
|
|
const Vector3 vTargetForward( std::cosf( flTargetRad ) , std::sinf( flTargetRad ) , 0.f );
|
|
const Vector3 vTargetRight( -std::sinf( flTargetRad ) , std::cosf( flTargetRad ) , 0.f );
|
|
|
|
const Vector3 vViewForward( std::cosf( flViewRad ) , std::sinf( flViewRad ) , 0.f );
|
|
const Vector3 vViewRight( -std::sinf( flViewRad ) , std::cosf( flViewRad ) , 0.f );
|
|
|
|
const Vector3 vMove = vTargetForward * flForwardMove + vTargetRight * flSideMove;
|
|
|
|
const float flCorrectedForward = ( vViewForward.m_x * vMove.m_x ) + ( vViewForward.m_y * vMove.m_y );
|
|
const float flCorrectedSide = ( vViewRight.m_x * vMove.m_x ) + ( vViewRight.m_y * vMove.m_y );
|
|
|
|
pBaseCmd->set_forwardmove( std::clamp( -flCorrectedForward , -1.f , 1.f ) );
|
|
pBaseCmd->set_leftmove( std::clamp( -flCorrectedSide , -1.f , 1.f ) );
|
|
}
|
|
|
|
auto CMisc::RunEdgeBug( CCSGOInput* pInput , CUserCmd* pUserCmd , C_CSPlayerPawn* pLocalPawn , bool bOnGround ) -> void
|
|
{
|
|
if ( bOnGround )
|
|
return;
|
|
|
|
if ( !pUserCmd || !pLocalPawn )
|
|
return;
|
|
|
|
const Vector3 Velocity = pLocalPawn->m_vecVelocity();
|
|
|
|
if ( Velocity.m_z >= 0.f )
|
|
return;
|
|
|
|
constexpr float k_Pi = 3.14159265358979f;
|
|
constexpr float k_TickInterval = 1.f / 64.f;
|
|
constexpr float k_HalfWidth = 16.f;
|
|
constexpr float k_ProbeDist = 32.f;
|
|
|
|
const Vector3 vOrigin = pLocalPawn->m_vOldOrigin();
|
|
|
|
const Vector3 vNextPos
|
|
{
|
|
vOrigin.m_x + Velocity.m_x * k_TickInterval,
|
|
vOrigin.m_y + Velocity.m_y * k_TickInterval,
|
|
vOrigin.m_z + Velocity.m_z * k_TickInterval
|
|
};
|
|
|
|
const float flVelocityYaw = std::atan2f( Velocity.m_y , Velocity.m_x ) * ( 180.f / k_Pi );
|
|
|
|
const Vector3 vOffsets[]
|
|
{
|
|
Vector3( 0.f , 0.f , 0.f ),
|
|
Vector3( k_HalfWidth , k_HalfWidth , 0.f ),
|
|
Vector3( k_HalfWidth , -k_HalfWidth , 0.f ),
|
|
Vector3( -k_HalfWidth , k_HalfWidth , 0.f ),
|
|
Vector3( -k_HalfWidth , -k_HalfWidth , 0.f )
|
|
};
|
|
|
|
Ray_t Ray;
|
|
CGameTrace GameTrace;
|
|
CTraceFilter Filter( 0x1C1003 , pLocalPawn , 3 , 15 );
|
|
|
|
Vector3 vEdgeNormal;
|
|
|
|
bool bFoundEdge = false;
|
|
|
|
for ( const auto& vOffset : vOffsets )
|
|
{
|
|
const Vector3 vProbeStart
|
|
{
|
|
vNextPos.m_x + vOffset.m_x,
|
|
vNextPos.m_y + vOffset.m_y,
|
|
vNextPos.m_z
|
|
};
|
|
|
|
// Ground probe straight down below this corner.
|
|
Ray.Start = vProbeStart;
|
|
Ray.End = vProbeStart;
|
|
Ray.End.m_z -= k_ProbeDist;
|
|
|
|
if ( !IGamePhysicsQuery_TraceShape( SDK::Pointers::CVPhys2World() , Ray , Ray.Start , Ray.End , &Filter , &GameTrace ) )
|
|
continue;
|
|
|
|
const float flGroundFraction = GameTrace.flFraction;
|
|
|
|
// Wall probe in the direction of travel at the same height.
|
|
Ray.Start = vProbeStart;
|
|
Ray.Start.m_z -= 2.f;
|
|
Ray.End = Ray.Start;
|
|
Ray.End.m_x += std::cosf( flVelocityYaw * ( k_Pi / 180.f ) ) * k_ProbeDist;
|
|
Ray.End.m_y += std::sinf( flVelocityYaw * ( k_Pi / 180.f ) ) * k_ProbeDist;
|
|
|
|
if ( !IGamePhysicsQuery_TraceShape( SDK::Pointers::CVPhys2World() , Ray , Ray.Start , Ray.End , &Filter , &GameTrace ) )
|
|
continue;
|
|
|
|
// Open ground below + wall ahead = pixel / edge surface.
|
|
if ( flGroundFraction > 0.9f && GameTrace.flFraction < 0.95f )
|
|
{
|
|
bFoundEdge = true;
|
|
vEdgeNormal = GameTrace.vecNormal;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !bFoundEdge )
|
|
return;
|
|
|
|
// Only assist when the edge is below us (steep / vertical-ish face).
|
|
if ( vEdgeNormal.m_z > 0.7f )
|
|
return;
|
|
|
|
GetCL_Bypass()->SetJump( pUserCmd , true );
|
|
}
|
|
|
|
auto CMisc::RunTriggerbot( CCSGOInput* pInput , CUserCmd* pUserCmd ) -> void
|
|
{
|
|
auto Reset = [ & ]()
|
|
{
|
|
m_bTriggerShooting = false;
|
|
m_TriggerArmTime = {};
|
|
m_ShotStartTime = {};
|
|
|
|
m_bTargetInCrosshair = false;
|
|
m_bTriggerFiring = false;
|
|
};
|
|
|
|
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
|
|
|
|
if ( !pLocalPawn || !pLocalPawn->IsAlive() )
|
|
{
|
|
Reset();
|
|
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 )
|
|
{
|
|
Reset();
|
|
return;
|
|
}
|
|
|
|
if ( Settings::Triggerbot::ScopedOnly )
|
|
{
|
|
if ( WeaponType == CSWeaponType_t::WEAPONTYPE_SNIPER_RIFLE && !pLocalPawn->m_bIsScoped() )
|
|
{
|
|
Reset();
|
|
return;
|
|
}
|
|
}
|
|
|
|
bool bShouldRun = false;
|
|
|
|
switch ( Settings::Triggerbot::Mode )
|
|
{
|
|
case 1:
|
|
{
|
|
bShouldRun = true;
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
const bool bKeyDown = ( GetAsyncKeyState( Settings::Triggerbot::Key ) & 0x8000 ) != 0;
|
|
|
|
if ( bKeyDown && !m_bTriggerKeyDown )
|
|
m_bTriggerToggledOn = !m_bTriggerToggledOn;
|
|
|
|
m_bTriggerKeyDown = bKeyDown;
|
|
|
|
bShouldRun = m_bTriggerToggledOn;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
{
|
|
const bool bKeyDown = ( GetAsyncKeyState( Settings::Triggerbot::Key ) & 0x8000 ) != 0;
|
|
|
|
bShouldRun = bKeyDown;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if ( !bShouldRun )
|
|
{
|
|
Reset();
|
|
return;
|
|
}
|
|
|
|
TriggerTraceResult_t Result;
|
|
|
|
if ( Settings::Triggerbot::SeedTrigger )
|
|
{
|
|
Vector3 vDirection;
|
|
|
|
if ( CalculateSeedDirection( pInput , pUserCmd , &vDirection ) )
|
|
Result = GetCL_Trace()->TraceDirectionToHitGroup( &vDirection );
|
|
}
|
|
else
|
|
{
|
|
Result = GetCL_Trace()->TraceToHitGroup( pInput );
|
|
}
|
|
|
|
auto* pTargetPawn = reinterpret_cast<C_CSPlayerPawn*>( Result.pHitEntity );
|
|
|
|
bool bTargetValid = false;
|
|
|
|
if ( pTargetPawn && pTargetPawn->IsPlayerPawn() && pTargetPawn != pLocalPawn && pTargetPawn->IsAlive() )
|
|
{
|
|
if ( !Settings::Triggerbot::IgnoreTeammates || pTargetPawn->m_iTeamNum() != pLocalPawn->m_iTeamNum() )
|
|
{
|
|
switch ( Result.nHitGroup )
|
|
{
|
|
case 1: bTargetValid = Settings::Triggerbot::Hitbox_Head; break;
|
|
case 2: bTargetValid = Settings::Triggerbot::Hitbox_Chest; break;
|
|
case 3: bTargetValid = Settings::Triggerbot::Hitbox_Stomach; break;
|
|
case 4:
|
|
case 5: bTargetValid = Settings::Triggerbot::Hitbox_Arms; break;
|
|
case 6:
|
|
case 7: bTargetValid = Settings::Triggerbot::Hitbox_Legs; break;
|
|
default: bTargetValid = true; break;
|
|
}
|
|
|
|
if ( bTargetValid && !Settings::Triggerbot::SeedTrigger && Settings::Triggerbot::Hitchance > 0 )
|
|
{
|
|
const QAngle ViewAngles = *CCSGOInput_GetViewAngles( pInput , 0 );
|
|
|
|
const float flHitchance = CalculateHitchance( pInput , pTargetPawn , ViewAngles , Settings::Triggerbot::HitchanceSamples );
|
|
|
|
if ( ( flHitchance * 100.f ) < static_cast<float>( Settings::Triggerbot::Hitchance ) )
|
|
bTargetValid = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
m_bTargetInCrosshair = bTargetValid;
|
|
|
|
if ( !bTargetValid )
|
|
{
|
|
m_bTriggerShooting = false;
|
|
m_TriggerArmTime = {};
|
|
m_ShotStartTime = {};
|
|
|
|
m_bTriggerFiring = false;
|
|
|
|
return;
|
|
}
|
|
|
|
const auto Now = std::chrono::steady_clock::now();
|
|
|
|
const auto DelayMs = std::chrono::milliseconds( std::max( 0 , Settings::Triggerbot::Delay ) );
|
|
const auto HoldMs = std::chrono::milliseconds( std::max( 0 , Settings::Triggerbot::HoldTime ) );
|
|
|
|
if ( !m_bTriggerShooting )
|
|
{
|
|
if ( m_TriggerArmTime.time_since_epoch().count() == 0 )
|
|
m_TriggerArmTime = Now;
|
|
|
|
if ( ( Now - m_TriggerArmTime ) >= DelayMs )
|
|
{
|
|
m_bTriggerShooting = true;
|
|
m_ShotStartTime = Now;
|
|
m_TriggerArmTime = {};
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( ( Now - m_ShotStartTime ) >= HoldMs )
|
|
{
|
|
m_bTriggerShooting = false;
|
|
m_TriggerArmTime = Now;
|
|
}
|
|
}
|
|
|
|
if ( m_bTriggerShooting )
|
|
{
|
|
GetCL_Bypass()->SetAttack( pUserCmd , true );
|
|
|
|
m_bTriggerFiring = true;
|
|
}
|
|
else
|
|
{
|
|
m_bTriggerFiring = false;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
if ( !pTarget || Samples <= 0 )
|
|
return 0.f;
|
|
|
|
auto* pWeapon = GetCL_Weapons()->GetLocalActiveWeapon();
|
|
|
|
if ( !pWeapon )
|
|
return 0.f;
|
|
|
|
const float flInaccuracy = C_CSWeaponBaseGun_GetInaccuracy( pWeapon , nullptr , nullptr );
|
|
const float flSpread = C_CSWeaponBaseGun_GetSpread( pWeapon );
|
|
|
|
const float flAccuracy = flInaccuracy + flSpread;
|
|
|
|
if ( flAccuracy <= 0.f )
|
|
return 1.f;
|
|
|
|
Vector3 vForward , vRight , vUp;
|
|
|
|
Math::AngleVectors( ViewAngles , vForward , vRight , vUp );
|
|
|
|
const auto vStart = GetCL_Players()->GetLocalEyeOrigin();
|
|
|
|
std::uniform_real_distribution<float> distAngle( 0.f , 6.2831853f );
|
|
std::uniform_real_distribution<float> distRadius( 0.f , 1.f );
|
|
|
|
int Hits = 0;
|
|
|
|
for ( int i = 0; i < Samples; i++ )
|
|
{
|
|
const float flAngle = distAngle( g_TriggerRng );
|
|
const float flRadius = flAccuracy * std::sqrt( distRadius( g_TriggerRng ) );
|
|
|
|
const Vector3 vDirection = ( vForward + vRight * ( std::cos( flAngle ) * flRadius ) + vUp * ( std::sin( flAngle ) * flRadius ) ).Normalized();
|
|
|
|
const Vector3 vEnd = vStart + vDirection * 8192.f;
|
|
|
|
if ( GetCL_Trace()->TraceToEntityEndPos( &vEnd ) == reinterpret_cast<C_BaseEntity*>( pTarget ) )
|
|
Hits++;
|
|
}
|
|
|
|
return static_cast<float>( Hits ) / static_cast<float>( Samples );
|
|
}
|
|
|
|
auto CMisc::CalculateSeedDirection( CCSGOInput* pInput , CUserCmd* pUserCmd , Vector3* vOutDirection ) -> bool
|
|
{
|
|
if ( !pInput || !vOutDirection )
|
|
return false;
|
|
|
|
auto* pWeapon = GetCL_Weapons()->GetLocalActiveWeapon();
|
|
|
|
if ( !pWeapon )
|
|
return false;
|
|
|
|
const QAngle ViewAngles = *CCSGOInput_GetViewAngles( pInput , 0 );
|
|
|
|
int iSeed = 0;
|
|
|
|
if ( pUserCmd && pUserCmd->cmd.base().has_random_seed() )
|
|
{
|
|
iSeed = pUserCmd->cmd.base().random_seed();
|
|
}
|
|
else
|
|
{
|
|
int iTick = 0;
|
|
|
|
if ( pUserCmd && pUserCmd->cmd.base().has_client_tick() )
|
|
iTick = pUserCmd->cmd.base().client_tick();
|
|
|
|
iSeed = static_cast<int>( GetSpreadSeed( ViewAngles , iTick ) );
|
|
}
|
|
|
|
const float flInaccuracy = C_CSWeaponBaseGun_GetInaccuracy( pWeapon , nullptr , nullptr );
|
|
const float flSpread = C_CSWeaponBaseGun_GetSpread( pWeapon );
|
|
|
|
const auto ItemDefIdx = GetCL_Weapons()->GetLocalWeaponDefinitionIndex();
|
|
|
|
const auto sv = CalculateSeedSpread( iSeed + 1 , flInaccuracy , flSpread , ItemDefIdx );
|
|
|
|
Vector3 vForward , vRight , vUp;
|
|
|
|
Math::AngleVectors( ViewAngles , vForward , vRight , vUp );
|
|
|
|
*vOutDirection = ( vForward + vRight * -sv.x + vUp * sv.y ).Normalized();
|
|
|
|
return true;
|
|
}
|
|
|
|
auto CMisc::OnFrameStageNotify( int FrameStage ) -> void
|
|
{
|
|
if ( FrameStage != 6 )
|
|
return;
|
|
|
|
if ( !Settings::Misc::NoFlash )
|
|
return;
|
|
|
|
auto* pLocalPawn = GetCL_Players()->GetLocalPlayerPawn();
|
|
|
|
if ( !pLocalPawn )
|
|
return;
|
|
|
|
pLocalPawn->m_flFlashDuration() = 0.f;
|
|
pLocalPawn->m_flFlashMaxAlpha() = 0.f;
|
|
}
|
|
|
|
auto CMisc::OnFireEventClientSide( IGameEvent* pGameEvent ) -> void
|
|
{
|
|
if ( !pGameEvent )
|
|
return;
|
|
|
|
if ( _strcmpi( pGameEvent->GetName() , XorStr( "player_hurt" ) ) != 0 )
|
|
return;
|
|
|
|
auto* pLocalController = GetCL_Players()->GetLocalPlayerController();
|
|
|
|
if ( !pLocalController )
|
|
return;
|
|
|
|
auto* pAttackerController = pGameEvent->GetPlayerController( XorStr( "attacker" ) );
|
|
|
|
if ( pAttackerController != pLocalController )
|
|
return;
|
|
|
|
const auto Now = std::chrono::steady_clock::now();
|
|
|
|
if ( Settings::Misc::Hitmarker )
|
|
m_HitTime = Now;
|
|
|
|
if ( Settings::Misc::HitSound )
|
|
{
|
|
if ( ( Now - m_HitSoundTime ) > std::chrono::milliseconds( 50 ) )
|
|
{
|
|
m_HitSoundTime = Now;
|
|
|
|
PlaySoundW( L"SystemHand" , nullptr , SND_ALIAS | SND_ASYNC | SND_NODEFAULT );
|
|
}
|
|
}
|
|
}
|
|
|
|
auto GetMisc() -> CMisc*
|
|
{
|
|
return &g_CMisc;
|
|
}
|