summaryrefslogtreecommitdiff
path: root/cheat/gmod/aimbot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cheat/gmod/aimbot.cpp')
-rw-r--r--cheat/gmod/aimbot.cpp404
1 files changed, 404 insertions, 0 deletions
diff --git a/cheat/gmod/aimbot.cpp b/cheat/gmod/aimbot.cpp
new file mode 100644
index 0000000..313b927
--- /dev/null
+++ b/cheat/gmod/aimbot.cpp
@@ -0,0 +1,404 @@
+
+#include "aimbot.hpp"
+#include "interface.hpp"
+#include "settings.hpp"
+#include "context.hpp"
+#include "math.hpp"
+#include "base_cheat.hpp"
+#include "input_system.hpp"
+
+namespace features
+{
+ void c_aimbot::operator()( user_cmd_t* cmd ) {
+ m_cmd = cmd;
+ run( );
+ }
+
+ c_aimbot::aim_target_t c_aimbot::find_best_target( ) const {
+ aim_target_t ret{ -1, vec3_t{ } };
+ vec3_t angle{ };
+
+ g_gmod.m_engine( )->GetViewAngles( angle );
+
+ vec3_t angle_dir = math::angle_vectors( angle );
+ vec3_t eye_pos = g_ctx.m_local->get_eye_pos( );
+ float closest_to = std::numeric_limits< float >::max( );
+
+ for( int i{ 1 }; i <= g_gmod.m_globals->m_maxclients; ++i ) {
+ auto ent = g_gmod.m_entlist( )->GetClientEntity( i );
+ if( !ent || ent == g_ctx.m_local || !ent->is_valid( ) )
+ continue;
+
+ if( g_settings.rage.ignore_team &&
+ g_ctx.m_local->m_iTeamNum( ) == ent->m_iTeamNum( ) )
+ continue;
+
+ if( g_settings.rage.ignore_teamcolor &&
+ g_ctx.m_local->get_team_color( ) == ent->get_team_color( ) )
+ continue;
+
+ if( g_settings.rage.ignore_spawnprot &&
+ ent->m_clrRender( ).a( ) < 250 )
+ continue;
+
+ player_info_t info;
+ if( !g_gmod.m_engine( )->GetPlayerInfo( i, &info ) )
+ continue;
+
+ // whitelisted.
+ if( g_cheat.m_playerlist.is_friend( info.m_steamid ) )
+ continue;
+
+ const auto ent_pos = get_entity_position( ent );
+ if( ent_pos.is_zero( ) )
+ continue;
+
+ auto dir = ( ent_pos - eye_pos );
+ dir.normalize_vector( );
+
+ const float fov = angle_dir.fov_to( dir ) * M_RADPI;
+ if( fov > g_settings.rage.fov )
+ continue;
+
+ if( g_settings.rage.selection_type( ) == 0 ) {
+ if( fov < closest_to ) {
+ closest_to = fov;
+ ret.m_ent_index = i;
+ ret.m_position = ent_pos;
+ }
+ }
+ else if( g_settings.rage.selection_type( ) == 1 ) {
+ float dist = eye_pos.dist_to( ent_pos );
+ if( dist < closest_to ) {
+ closest_to = dist;
+ ret.m_ent_index = i;
+ ret.m_position = ent_pos;
+ }
+ }
+ }
+ return ret;
+ }
+
+ vec3_t c_aimbot::get_entity_position( c_base_player* ent ) const {
+ matrix3x4 matrix[ 256 ]{ };
+ bool found_valid_hitbox{ };
+ // the idea behind this is that some players can have really weird models and our aimbot will not work on them
+ // so if they don't have a valid hitbox, we then get the OOB center of their model and use that instead.
+ // fuck gmod.
+ // const const const const
+ bool hitscan = g_settings.rage.hitbox == -1;
+ const char* hitbox_selection[ ] = {
+ "Head",
+ "Neck",
+ "Pelvis",
+ "Chest"
+ };
+
+
+ if( !ent->ce( )->SetupBones( matrix, 256, 0x100, g_gmod.m_globals->m_curtime ) )
+ return vec3_t{ };
+
+ const auto model = ent->ce( )->GetModel( );
+ if( !model )
+ return vec3_t{ };
+
+ const auto hdr = g_gmod.m_model_info( )->GetStudiomodel( model );
+ if( !hdr )
+ return vec3_t{ };
+
+ const auto set = hdr->get_hitbox_set( ent->m_nHitboxSet( ) );
+ if( !set )
+ return vec3_t{ };
+
+ for( int i{ }; i < set->numhitboxes; ++i ) {
+ const auto hitbox = set->get_hitbox( i );
+ if( !hitbox )
+ continue;
+
+ const auto bone = hdr->get_bone( hitbox->bone );
+ if( !bone )
+ continue;
+
+ const std::string name = bone->get_name( );
+ if( name.empty( ) )
+ continue;
+
+ if( hitscan ) {
+ if( name.find( "Head" ) == std::string::npos )
+ continue;
+ }
+ else {
+ if( name.find( hitbox_selection[ g_settings.rage.hitbox ] ) == std::string::npos )
+ continue;
+ }
+
+ const auto pos = math::vector_transform( ( hitbox->min + hitbox->max ) * 0.5f, matrix[ hitbox->bone ] );
+ if( pos.is_zero( ) )
+ continue;
+
+ found_valid_hitbox = true;
+ if( ent->is_visible( pos ) )
+ return pos;
+ }
+
+ if( hitscan ) { // ghetto but it works fine.
+ for( int i{ }; i < set->numhitboxes; ++i ) {
+ const auto hitbox = set->get_hitbox( i );
+ if( !hitbox )
+ continue;
+
+ const auto pos = math::vector_transform( ( hitbox->min + hitbox->max ) * 0.5f, matrix[ hitbox->bone ] );
+ if( pos.is_zero( ) )
+ continue;
+
+ if( ent->is_visible( pos ) )
+ return pos;
+ }
+ }
+
+ if( !found_valid_hitbox ) {
+ auto pos = ent->ce( )->GetRenderOrigin( );
+ pos += ( ent->m_vecMins( ) + ent->m_vecMaxs( ) ) * 0.5f;
+ if( ent->is_visible( pos ) )
+ return pos;
+ }
+
+ return vec3_t{ };
+ }
+
+ void c_aimbot::fix_accuracy( vec3_t& angle ) {
+ auto srand = []( double seed ) -> void {
+ if( !g_ctx.m_lua )
+ return;
+
+ const auto lua = g_ctx.m_lua;
+
+ lua->GetField( LUA_GLOBALSINDEX, xors( "math" ) );
+ if( !lua->IsType( -1, LUA_TYPE::TYPE_TABLE ) ) {
+ lua->Pop( 1 );
+ return;
+ }
+
+ lua->GetField( -1, xors( "randomseed" ) );
+ if( !lua->IsType( -1, LUA_TYPE::TYPE_FUNCTION ) ) {
+ lua->Pop( 2 );
+ return;
+ }
+
+ lua->PushNumber( seed );
+ lua->Call( 1, 0 );
+
+ lua->Pop( 1 );
+ };
+
+ auto rand = []( const double low, const double high ) -> double {
+ if( !g_ctx.m_lua )
+ return 0.0;
+
+ const auto lua = g_ctx.m_lua;
+
+ lua->GetField( LUA_GLOBALSINDEX, xors( "math" ) );
+ if( !lua->IsType( -1, LUA_TYPE::TYPE_TABLE ) ) {
+ lua->Pop( 1 );
+ return 0.0;
+ }
+
+ lua->GetField( -1, xors( "Rand" ) );
+ if( !lua->IsType( -1, LUA_TYPE::TYPE_FUNCTION ) ) {
+ lua->Pop( 2 );
+ return 0.0;
+ }
+
+ lua->PushNumber( low );
+ lua->PushNumber( high );
+
+ lua->Call( 2, 1 );
+ if( !lua->IsType( -1, LUA_TYPE::TYPE_NUMBER ) ) {
+ lua->Pop( 2 );
+ return 0.0;
+ }
+
+ double rand = lua->GetNumber( -1 );
+
+ lua->Pop( 2 );
+
+ return rand;
+ };
+
+
+ auto weapon = g_ctx.m_local->get_weapon( );
+ if( !weapon )
+ return;
+
+ bool is_cw20 = weapon->is_cw20( ); // own spread handling weapon packs (big).
+ bool is_fas2 = weapon->is_fas2( );
+ bool is_custom = is_cw20 || is_fas2;
+
+ auto weapon_name = weapon->get_class_name( );
+ if( !is_custom && !weapon_name )
+ return;
+
+ auto cone = m_spread[ weapon_name ];
+ if( !is_custom && cone.is_zero( ) )
+ return;
+
+ float cur_cone = weapon->get_custom_cone( );
+ if( is_custom || cur_cone ) { // may be custom weapon similar to FAS2/CW20
+ if ( g_settings.rage.norecoil )
+ angle -= g_ctx.m_local->m_vecPunchAngle( );
+
+ if( !g_settings.rage.nospread )
+ return;
+
+ if( is_cw20 ) {
+ srand( m_cmd->m_cmd_nr );
+
+ if( g_ctx.m_local->m_fFlags( ) & FL_DUCKING )
+ cur_cone *= 0.85f;
+ }
+ else if ( is_fas2 ) {
+ srand( g_ctx.m_local->m_nTickBase( ) * g_gmod.m_globals->m_interval_per_tick ); // FPS has to be over tickrate otherwise this fucks up, do not know how to fix.
+ }
+ else {
+ srand( g_ctx.m_local->m_nTickBase( ) * g_gmod.m_globals->m_interval_per_tick ); // some other custom ones based on FAS2 or CW20 use this.
+ }
+
+ angle.x -= ( float )( rand( -cur_cone, cur_cone ) * 25.0 );
+ angle.y -= ( float )( rand( -cur_cone, cur_cone ) * 25.0 );
+ }
+ else {
+ // if hl2
+ // no recoil... figure this out.
+
+ if( !g_settings.rage.nospread )
+ return;
+
+ util::set_random_seed( m_cmd->m_random_seed & 0xff );
+
+ float rand_a = util::get_random_float( -0.5f, 0.5f ) + util::get_random_float( -0.5f, 0.5f );
+ float rand_b = util::get_random_float( -0.5f, 0.5f ) + util::get_random_float( -0.5f, 0.5f );
+
+ float spread_x = cone.x * rand_a;
+ float spread_y = cone.y * rand_b;
+
+ vec3_t forward, right, up;
+ math::angle_vectors( angle, &forward, &right, &up );
+
+ vec3_t spread_dir = forward + ( right * -spread_x ) + ( up * -spread_y );
+ spread_dir.normalize_vector( );
+
+ angle = math::vector_angles( vec3_t{ }, spread_dir );
+ }
+ }
+
+ void c_aimbot::aim_at_target( const c_aimbot::aim_target_t& target ) {
+ // we're not gonna be checking for m_flNextPrimaryFire due to server side anticheats checking if IN_ATTACK is sent when you can fire, you will get banned.
+ // I'm gonna do some ghetto autopistol if we find that the weapon is not automatic (we can find this easily using a lua member of the weapon).
+ vec3_t eye_pos = g_ctx.m_local->get_eye_pos( );
+ vec3_t angle_to_target = math::vector_angles( eye_pos, target.m_position );
+ auto weapon = g_ctx.m_local->get_weapon( );
+ float yaw = m_cmd->m_viewangles.y;
+
+ fix_accuracy( angle_to_target );
+
+ if( g_settings.rage.silent != 2 || weapon->is_fas2( ) || weapon->is_cw20( ) || weapon->get_custom_cone( ) ) { // These custom weapons cannot do pSilent as they handle shot direction themselves... should probably warn users about this.
+ m_cmd->m_viewangles = angle_to_target.clamp( );
+
+ vec3_t delta = m_last_viewangles - ( m_cmd->m_viewangles - m_last_viewangles );
+ m_cmd->m_mousedx = -( short )( delta.x / 0.022f ); // serverside anticheats detect this stuff.
+ m_cmd->m_mousedy = ( short )( delta.y / 0.022f );
+
+ if( g_settings.rage.silent == 1 ) {
+ vec3_t move = vec3_t( m_cmd->m_forwardmove, m_cmd->m_sidemove, m_cmd->m_upmove );
+ float len = move.length( );
+
+ if( len ) {
+ move = math::angle_vectors( ( math::vector_angles( vec3_t{ }, move ) + vec3_t( 0, m_cmd->m_viewangles.y - yaw, 0 ) ) ) * len;
+ m_cmd->m_forwardmove = move.x;
+ m_cmd->m_sidemove = move.y;
+ }
+ }
+ }
+ else {
+ m_shot_dir = math::angle_vectors( angle_to_target.clamp( ) ); // save for later. this is really inaccurate and i do not know why.
+ m_shot_dir.normalize_vector( );
+ }
+
+ if( g_settings.rage.silent( ) == 0 )
+ g_gmod.m_engine( )->SetViewAngles( m_cmd->m_viewangles );
+
+ if( g_settings.rage.auto_fire )
+ m_cmd->m_buttons |= IN_ATTACK;
+ }
+
+ void c_aimbot::log_shot( c_base_player* ent, fire_bullets_info* info ) {
+ // we log shot spread cones due to not having a proper function to give us weapon spread...
+ if( !ent || !info )
+ return;
+
+ if( info->spread.is_zero( ) )
+ return;
+
+ auto weapon = ent->get_weapon( );
+ if( !weapon )
+ return;
+
+ auto weapon_name = weapon->get_class_name( );
+ if( !weapon_name )
+ return;
+
+ m_spread[ weapon_name ] = info->spread;
+ }
+
+ void c_aimbot::silent( ) {
+ // the idea behind this was using the context menu used in sandbox and darkrp ( C menu )
+ // you can fire anywhere in the menu but it doesn't change your view angles
+ // worldclick stuff gets set in C_GMOD_Player::CreateMove so we must set it after the call to it.
+ // however this method has some problems, the weapon back has to be using the lua call player:GetAimVector() for src direction in FireBullets
+ // otherwise it will not work, 2 of the biggest weapon packs do not use this function so its kinda bork
+ // another problem is that if you do not aim within a 30 degree cone of your target or are close to them, lag compensation will not take effect ( thanks garry )
+ // - kolo
+
+ if( !m_cmd )
+ return;
+
+ m_last_viewangles = m_cmd->m_viewangles; // for mousedx garbage.
+
+ if( !g_settings.rage.enabled )
+ return;
+
+ if( g_settings.rage.silent != 2 )
+ return;
+
+ if( m_shot_dir.is_zero( ) )
+ return;
+
+ m_cmd->m_world_clicking = true;
+ m_cmd->m_world_click_direction = m_shot_dir;
+
+ m_shot_dir = vec3_t{ }; // useless now.
+ }
+
+ void c_aimbot::run( ) {
+ if( !g_settings.rage.enabled )
+ return;
+
+ if( g_settings.rage.activation_type != 0 &&
+ !g_input.is_key_pressed( ( VirtualKeys_t )g_settings.rage.aimkey( ) ) )
+ return;
+
+ auto weapon = g_ctx.m_local->get_weapon( );
+ if( !weapon )
+ return;
+
+ //auto wpn_data = weapon->get_wpn_data( ); // only works for hl2 weapons..
+ //if( !wpn_data ) // however you can get lua weapon data, cast to C_WeaponSWEP and call correct functions.
+ // return;
+
+ auto target = find_best_target( );
+ if( target.m_ent_index != -1 ) {
+ aim_at_target( target );
+ }
+ }
+}
+