summaryrefslogtreecommitdiff
path: root/cheat/internal_rewrite/ragebot_resolver.cpp
diff options
context:
space:
mode:
authorboris <wzn@moneybot.cc>2018-11-28 16:00:02 +1300
committerboris <wzn@moneybot.cc>2018-11-28 16:00:02 +1300
commit3d412a4b30a9f7c7f51ea6562e694315948bd3da (patch)
tree26d67dfd1f3e5fd12903ad13e85d0cb8bcf8f21c /cheat/internal_rewrite/ragebot_resolver.cpp
parente4729e4393d90271a3814c7a79950a660c48325a (diff)
cleaned up
in short, the cheat and loader are now separate solutions. unused stuff was moved into the legacy solution in case anyone wants to compile it or whatever. i can change this back if you want to. also, i configured the loader to compile in x64, and have separate build types for linux and win64
Diffstat (limited to 'cheat/internal_rewrite/ragebot_resolver.cpp')
-rw-r--r--cheat/internal_rewrite/ragebot_resolver.cpp626
1 files changed, 626 insertions, 0 deletions
diff --git a/cheat/internal_rewrite/ragebot_resolver.cpp b/cheat/internal_rewrite/ragebot_resolver.cpp
new file mode 100644
index 0000000..1b29305
--- /dev/null
+++ b/cheat/internal_rewrite/ragebot_resolver.cpp
@@ -0,0 +1,626 @@
+#include "ragebot.hpp"
+#include "context.hpp"
+#include "base_cheat.hpp"
+#include "math.hpp"
+#include "input_system.hpp"
+
+namespace features
+{
+ constexpr float FLT_ANG_LBY = 360.f;
+ constexpr float FLT_ANG_MOVING_LBY_UP = -360.f;
+ constexpr float FLT_ANG_180 = 720.f;
+ constexpr float FLT_ANG_FREESTANDING = -720.f;
+ constexpr float FLT_ANG_90 = 480.f;
+ constexpr float FLT_ANG_MINUS_90 = -480.f;
+ constexpr float FLT_ANG_MINUS_135 = -700.f;
+ constexpr float FLT_ANG_135 = 700.f;
+ constexpr float FLT_ANG_PITCH_UP = 1080.f;
+
+ static const std::vector< float > possible_angles_none = {
+ FLT_ANG_MOVING_LBY_UP,
+ FLT_ANG_180,
+ FLT_ANG_90,
+ FLT_ANG_MINUS_90,
+ FLT_ANG_MINUS_135,
+ FLT_ANG_135,
+ };
+
+ static const std::vector< float > possible_angles_normal = {
+ FLT_ANG_MOVING_LBY_UP,
+ FLT_ANG_180,
+ FLT_ANG_135,
+ FLT_ANG_MINUS_135
+ };
+
+ static const std::vector< float > possible_angles_freestanding = {
+ 0.f,
+ 45.f,
+ 90.f,
+ 135.f,
+ 180.f,
+ };
+
+ bool dbg_resolver( ) {
+ static con_var< bool > var{ &data::holder_, fnv( "dbg_resolver" ), false };
+ return var( );
+ }
+
+ int c_ragebot::c_resolver::try_freestanding( c_base_player* ent ) {
+ if( !( ent->m_fFlags( ) & FL_ONGROUND ) || ( ent->get_anim_velocity( ).length2d( ) > 0.1f && !ent->is_fakewalking( ) ) )
+ return -1;
+
+ int ret_dir = -1;
+ float cur_damage = 0.f;
+
+ vec3_t enemy_pos = ent->m_vecOrigin( );
+ enemy_pos.z = ent->get_hitbox_pos( 0 ).z;
+
+ vec3_t local_pos = g_ctx.m_local->get_eye_pos( );
+ local_pos -= g_ctx.m_local->m_vecOrigin( );
+ local_pos += g_ctx.m_last_origin;
+
+ vec3_t aim_angle = math::vector_angles(
+ enemy_pos,
+ local_pos
+ );
+
+ auto get_damage = [ & ]( const vec3_t& start, const vec3_t& end, c_base_player* a, c_base_player* b ) {
+ static weapon_info_t wpn_data{ };
+ wpn_data.damage = 200;
+ wpn_data.range_modifier = 1.0f;
+ wpn_data.penetration = 3.0f;
+ wpn_data.armor_ratio = 0.5f;
+ wpn_data.range = 8192.f;
+
+ fire_bullet_data_t data{ };
+ data.src = start;
+ data.travel_range = ( end - data.src ).length( );
+ data.traveled = 0.f;
+ data.to_travel = data.travel_range;
+
+ vec3_t angle = math::vector_angles( start, end );
+ data.direction = math::angle_vectors( angle );
+
+ data.direction.normalize_vector( );
+
+ if( g_cheat.m_autowall.fire_bullet( a, b, &wpn_data, data, false, false ) ) {
+ return data.current_damage;
+ }
+
+ return -1.f;
+ };
+
+ auto trace_ent_pos = [ & ]( vec3_t start, vec3_t end, c_base_player* ent ) {
+ Ray_t ray;
+ CGameTrace tr;
+ CTraceFilter filter;
+
+ const vec3_t min( -2.f, -2.f, -2.f );
+ const vec3_t max( 2.f, 2.f, 2.f );
+
+ ray.Init( start, end, min, max );
+ filter.pSkip = ent;
+
+ g_csgo.m_trace( )->TraceRay( ray, MASK_SHOT, &filter, &tr );
+
+ return tr.endpos;
+ };
+
+ float local_dist = 75.f;
+ float enemy_dist = 75.f;
+
+ float start_dmg = get_damage( enemy_pos, local_pos, g_ctx.m_local, ent );
+
+ auto test_dmg = [ & ]( float dist, float enemy_dist, float delta = 50.f ) {
+ vec3_t enemy_left = math::get_rotated_pos( enemy_pos, aim_angle.y - 90.f, enemy_dist );
+ vec3_t enemy_right = math::get_rotated_pos( enemy_pos, aim_angle.y + 90.f, enemy_dist );
+
+ enemy_left = trace_ent_pos( enemy_pos, enemy_left, ent );
+ enemy_right = trace_ent_pos( enemy_pos, enemy_right, ent );
+
+ vec3_t local_left = math::get_rotated_pos( local_pos, aim_angle.y + 90.f, dist );
+ vec3_t local_right = math::get_rotated_pos( local_pos, aim_angle.y - 90.f, dist );
+
+ local_left = trace_ent_pos( local_pos, local_left, g_ctx.m_local );
+ local_right = trace_ent_pos( local_pos, local_right, g_ctx.m_local );
+
+ float dmg_left = get_damage( local_left, enemy_left, g_ctx.m_local, ent )
+ + get_damage( local_right, enemy_left, g_ctx.m_local, ent );
+
+ float dmg_right = get_damage( local_left, enemy_right, g_ctx.m_local, ent )
+ + get_damage( local_right, enemy_right, g_ctx.m_local, ent );
+
+ if( std::abs( dmg_left - dmg_right ) < delta )
+ return false;
+
+ float max_dmg = math::max( dmg_left, dmg_right );
+ ret_dir = dmg_left > dmg_right;
+
+ cur_damage = max_dmg;
+ return max_dmg > delta;
+ };
+
+ float radius = std::floorf( ( g_ctx.m_local->get_hitbox_pos( 0 ) - g_ctx.m_local->get_hitbox_pos( HITBOX_PELVIS ) ).length2d( ) );
+ radius = radius >= 15.f ? 20.f : 10.f;
+
+ float enemy_radius = std::floorf( ( ent->get_hitbox_pos( 0 ) - ent->get_hitbox_pos( HITBOX_PELVIS ) ).length2d( ) );
+ enemy_radius = enemy_radius >= 15.f ? 20.f : 10.f;
+
+ if( !test_dmg( enemy_radius + 1.f, radius + 1.f, 25.f ) ) {
+ if( cur_damage < start_dmg * 2.f )
+ return -1;
+ }
+
+ bool found = false;
+
+ for( size_t i = 5; i > 0; --i ) {
+ float cur_dist = local_dist / i;
+ float cur_enemy_dist = enemy_dist / i;
+
+ if( cur_dist < radius )
+ continue;
+
+ if( cur_enemy_dist < enemy_radius )
+ continue;
+
+ if( test_dmg( cur_enemy_dist, cur_dist, 125.f / i ) ) {
+ found = true;
+ break;
+ } else if( cur_damage > 125.f / i )
+ break;
+ }
+
+ if( !found )
+ return -1;
+
+ return ret_dir;
+ }
+
+ void c_ragebot::c_resolver::resolve_log_t::update( int ent_index ) {
+ static C_AnimationLayer last_layer[ 65 ]{ };
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( ent_index );
+
+ if( !ent || ent == g_ctx.m_local || !ent->is_player( ) || !ent->is_alive( ) || ent->ce( )->IsDormant( ) || !ent->has_valid_anim( ) ) {
+ m_was_invalid = true;
+ m_has_valid_lby = false;
+ return;
+ }
+
+ if( m_was_invalid && m_last_pos.dist_to( ent->m_vecOrigin( ) ) > 4.f )
+ reset( );
+
+ if( !( ent->m_fFlags( ) & FL_ONGROUND ) ) {
+ m_state = R_NONE;
+ return;
+ }
+
+ if( ent->get_anim_velocity( ).length2d( ) > 0.1f && !ent->is_fakewalking( ) ) {
+ m_state = R_NONE;
+ m_has_valid_lby = true;
+ m_last_moving_lby = ent->m_flLowerBodyYawTarget( );
+ return;
+ }
+
+ m_last_pos = ent->m_vecOrigin( );
+
+ m_was_invalid = false;
+
+ int freestanding = g_cheat.m_ragebot.m_resolver->try_freestanding( ent );
+
+ if( freestanding != -1 ) {
+ m_state = R_FREESTANDING;
+ }
+ else
+ m_state = R_NORMAL;
+
+ if( m_last_freestanding != freestanding )
+ m_angle_change = true;
+
+ m_last_freestanding = freestanding;
+ m_has_valid_lby = true;
+ }
+
+ void c_ragebot::c_resolver::resolve_log_t::reset( ) {
+ //assuming theyre STILL not moving this shouldnt change
+ //however if they are, it will be reset to none anyway
+ m_state = R_NONE;
+ m_last_update = 0.f;
+ m_last_lby = 0.f;
+ m_missed_shots = 0;
+ memset( m_shots, 0, sizeof( m_shots ) );
+ memset( m_logged, 0, sizeof( m_logged ) );
+ memset( m_logged_shots, 0, sizeof( m_logged ) );
+ }
+
+ std::vector< float > c_ragebot::c_resolver::get_shot_vec( int ent ) {
+ auto& data = m_data[ ent ];
+
+ if( data.m_state == R_NORMAL )
+ return possible_angles_normal;
+ if( data.m_state == R_FREESTANDING )
+ return possible_angles_freestanding;
+
+ return possible_angles_none;
+ }
+
+ float c_ragebot::c_resolver::get_shot_yaw( int shots, int ent_index ) {
+ auto& data = m_data[ ent_index ];
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( ent_index );
+
+ auto vec = get_shot_vec( ent_index );
+
+ float new_ang = vec.at( shots % vec.size( ) );
+ float new_yaw = 0.f;
+
+ float ang = math::vector_angles( ent->m_vecOrigin( ), g_ctx.m_last_origin ).y;
+
+ if( data.m_state == R_FREESTANDING ) {
+ ang += ( data.m_last_freestanding == 1 ? 90.f : -90.f );
+
+ float sign = data.m_last_freestanding == 1 ? 1.f : -1.f;
+
+ return ang + new_ang * sign;
+ }
+
+ if( new_ang == FLT_ANG_LBY )
+ new_yaw = ent->m_flLowerBodyYawTarget( );
+ else if( new_ang == FLT_ANG_MOVING_LBY_UP ) {
+ if( !data.m_has_valid_lby && !g_settings.rage.pitch_resolver ) {
+ return get_shot_yaw( ++get_resolver_shots( ent_index ), ent_index );
+ }
+
+ auto delta = std::remainderf( data.m_last_moving_lby - data.m_last_lby, 360.f );
+ bool breaking_lby = std::abs( delta ) > 35.f;
+
+ new_yaw = breaking_lby ? data.m_last_moving_lby : data.m_last_lby;
+ }
+ else if( new_ang == FLT_ANG_180 ) {
+ new_yaw = ang - 180.f;
+ }
+ else if( new_ang == FLT_ANG_MINUS_90 ) {
+ new_yaw = ang - 90.f;
+ }
+ else if( new_ang == FLT_ANG_90 ) {
+ new_yaw = ang + 90.f;
+ }
+ else if( new_ang == FLT_ANG_135 )
+ new_yaw = ang + 135.f;
+ else if( new_ang == FLT_ANG_MINUS_135 )
+ new_yaw = ang - 135.f;
+ else
+ new_yaw = std::remainderf( ent->m_flLowerBodyYawTarget( ) + new_ang, 360.f );
+
+ return new_yaw;
+ }
+
+ void c_ragebot::c_resolver::aimbot( int ent_index, int hitbox, vec3_t angle, vec3_t position, vec3_t min, vec3_t max, float radius ) {
+ if( !g_cheat.m_player_mgr.is_cheater( ent_index ) )
+ return;
+
+ auto& data = m_data[ ent_index ];
+
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( ent_index );
+ bool moving = ent->get_anim_velocity( ).length2d( ) > 0.1f && ( ent->m_fFlags( ) & FL_ONGROUND );
+
+ if( moving && !ent->is_fakewalking( ) ) {
+ return;
+ }
+
+ if( !data.m_state ) {
+ increment_shots( ent_index );
+ return;
+ }
+
+ auto model = ent->ce( )->GetModel( );
+ auto hdr = g_csgo.m_model_info( )->GetStudiomodel( model );
+ auto set = hdr->pHitboxSet( ent->m_nHitboxSet( ) );
+
+ if( hitbox == HITBOX_HEAD ) {
+ auto box = set->pHitbox( 0 );
+ if( box ) {
+ auto dist = box->bbmin.dist_to( box->bbmax );
+
+ context::shot_data_t new_shot{ };
+ new_shot.m_angle = angle;
+ new_shot.m_enemy_pos = position;
+ new_shot.m_enemy_index = ent_index;
+ new_shot.m_local_pos = g_ctx.m_local->get_eye_pos( );
+ new_shot.m_resolver_shots = get_resolver_shots( ent_index );
+ new_shot.m_resolver_state = true;
+ new_shot.m_hitbox.min = min;
+ new_shot.m_hitbox.min = max;
+ new_shot.m_hitbox.radius = radius;
+ new_shot.m_missed = true;
+ new_shot.m_hitgroup = HITGROUP_HEAD;
+
+ g_ctx.m_last_shot++;
+ g_ctx.m_last_shot %= 128;
+ g_ctx.m_shot_data[ g_ctx.m_last_shot ] = new_shot;
+
+ g_ctx.m_has_incremented_shots = true;
+
+
+ data.m_snapshot[ g_ctx.m_last_shot ] = data;
+
+ if( data.m_logged[ data.m_state ] ) {
+ if( !--data.m_logged_shots[ data.m_state ] ) {
+ data.m_logged[ data.m_state ] = false;
+ }
+ }
+ else {
+ int shots = get_resolver_shots( ent_index );
+
+ increment_shots( ent_index );
+
+#if _DEBUG
+ if( dbg_resolver( ) ) {
+ char str[ 128 ];
+ sprintf_s< 128 >( str, "[\3moneybot\1] incrementing shots from %d to %d"
+ "[\3moneybot\1] resolver state: %d\n", shots, get_resolver_shots( ent_index ), data.m_state );
+
+ g_csgo.m_clientmode( )->m_pChatElement->ChatPrintf( 0, 0, str );
+ }
+#endif
+ }
+ }
+ }
+ else {
+ matrix3x4 bone_matrix[ 128 ];
+ if( model && hdr && set && ent->ce( )->SetupBones( bone_matrix, 128, 0x100, g_csgo.m_globals->m_curtime ) ) {
+ auto box = set->pHitbox( hitbox );
+ if( !box ) return;
+
+ auto origin = ent->m_vecOrigin( );
+
+ vec3_t shot_pos = position;
+ vec3_t rotated_center;
+
+ vec3_t offset = position - origin;
+ float radius = offset.length2d( );
+ float cosine = offset.x / radius;
+
+ float deg = RAD2DEG( acos( cosine ) );
+ if( offset.y < 0 ) deg += 360.f;
+
+ float rot = ( deg - 180.f ) * ( M_PI / 180.f );
+ rotated_center.x = origin.x + cos( rot ) * radius;
+ rotated_center.y = origin.y + sin( rot ) * radius;
+ rotated_center.z = position.z;
+
+ Ray_t ray;
+ CTraceFilterOneEntity filter;
+ CGameTrace tr_center;
+ CGameTrace tr_rot;
+
+ filter.ent = ent;
+
+ ray.Init( g_ctx.m_local->get_eye_pos( ), position );
+ g_csgo.m_trace( )->TraceRay( ray, MASK_SHOT, &filter, &tr_center );
+
+ ray.Init( g_ctx.m_local->get_eye_pos( ), rotated_center );
+ g_csgo.m_trace( )->TraceRay( ray, MASK_SHOT, &filter, &tr_rot );
+
+ bool is_within = tr_center.hitbox == tr_rot.hitbox;
+
+ if( !is_within ) {
+ auto dist = box->bbmin.dist_to( box->bbmax );
+
+ context::shot_data_t new_shot{ };
+ new_shot.m_angle = angle;
+ new_shot.m_enemy_pos = position;
+ new_shot.m_enemy_index = ent_index;
+ new_shot.m_local_pos = g_ctx.m_local->get_eye_pos( );
+ new_shot.m_resolver_shots = get_resolver_shots( ent_index );
+ new_shot.m_resolver_state = true;
+ new_shot.m_hitbox.min = min;
+ new_shot.m_hitbox.min = max;
+ new_shot.m_hitbox.radius = radius;
+ new_shot.m_missed = true;
+ new_shot.m_hitgroup = util::hitbox_to_hitgroup( hitbox );
+
+ g_ctx.m_last_shot++;
+ g_ctx.m_last_shot %= 128;
+ g_ctx.m_shot_data[ g_ctx.m_last_shot ] = new_shot;
+
+ g_ctx.m_has_incremented_shots = true;
+
+ data.m_snapshot[ g_ctx.m_last_shot ] = data;
+
+ if( data.m_logged[ data.m_state ] ) {
+ if( !--data.m_logged_shots[ data.m_state ] ) {
+ data.m_logged[ data.m_state ] = false;
+ }
+ }
+ else {
+ int shots = get_resolver_shots( ent_index );
+ increment_shots( ent_index );
+
+#if _DEBUG
+ if( dbg_resolver( ) ) {
+ char str[ 128 ];
+ sprintf_s< 128 >( str, "[\3moneybot\1] incrementing shots from %d to %d"
+ "[\3moneybot\1] resolver state: %d\n", shots, get_resolver_shots( ent_index ), data.m_state );
+
+ g_csgo.m_clientmode( )->m_pChatElement->ChatPrintf( 0, 0, str );
+ }
+#endif
+ }
+ }
+ }
+ }
+
+ //printf( "resolver: logging aimbot shot %d missed: %d state: %d time: %f\n",
+ // data.m_shots, data.m_missed_shots[ data.m_breaking ], data.m_breaking, g_Interfaces.Globals->curtime );
+ }
+
+ void c_ragebot::c_resolver::increment_shots( int ent_index ) {
+ get_resolver_shots( ent_index )++;
+ m_data[ ent_index ].m_missed_shots++;
+ m_data[ ent_index ].m_angle_change = true;
+ }
+
+ void c_ragebot::c_resolver::on_missed_spread( int ent_index, int shots ) {
+ if( !g_cheat.m_player_mgr.is_cheater( ent_index ) )
+ return;
+
+ auto& data = m_data[ ent_index ];
+ auto& snapshot = data.m_snapshot[ shots % 150 ];
+
+ data.m_shots[ snapshot.m_state ] = snapshot.m_shots[ snapshot.m_state ];
+
+ if( snapshot.m_logged[ snapshot.m_state ] ) {
+ data.m_logged[ snapshot.m_state ] = true;
+ data.m_logged_shots[ snapshot.m_state ] = snapshot.m_logged_shots[ snapshot.m_state ];
+ }
+ }
+
+ void c_ragebot::c_resolver::listener( int ent_index, int shots ) {
+ if( !g_cheat.m_player_mgr.is_cheater( ent_index ) )
+ return;
+
+ auto& data = m_data[ ent_index ];
+ auto& snapshot = data.m_snapshot[ shots ];
+
+ auto nci = g_csgo.m_engine( )->GetNetChannelInfo( );
+ if( !nci )
+ return;
+
+ auto weapon = g_ctx.m_local->get_weapon( );
+ if( !weapon )
+ return;
+
+ auto rate = weapon->get_wpn_info( )->cycle_time;
+
+ data.m_shots[ snapshot.m_state ] = snapshot.m_shots[ snapshot.m_state ];
+ data.m_logged[ snapshot.m_state ] = true;
+
+ int latency_shots = ( nci->GetLatency( 0 ) + g_csgo.m_globals->m_frametime ) / rate + 1;
+
+ data.m_logged_shots[ snapshot.m_state ] = latency_shots;
+
+#if _DEBUG
+ if( dbg_resolver( ) ) {
+ char str[ 128 ];
+ sprintf_s< 128 >( str, "[\3moneybot\1] resolver: logging %d shots for %d with %d", data.m_logged_shots[ data.m_state ], ent_index, get_resolver_shots( ent_index ) );
+
+ g_csgo.m_clientmode( )->m_pChatElement->ChatPrintf( 0, 0, str );
+ }
+#endif
+ }
+
+ void c_ragebot::c_resolver::update_player( int i ) {
+ if( !g_settings.rage.enabled( ) || !g_settings.rage.resolver( ) )
+ return;
+
+ if( !g_cheat.m_player_mgr.is_cheater( i ) )
+ return;
+
+ auto ent = g_csgo.m_entlist( )->GetClientEntity( i );
+ bool was_invalid = m_data[ i ].m_was_invalid;
+
+ m_data[ i ].update( i );
+ if( g_settings.rage.resolver_override( ) ) {
+ if( g_input.is_key_pressed( g_settings.rage.resolver_override_key( ) ) ) {
+ int dir = manual_override( ent );
+ if( dir ) {
+ if( dir != m_data[ i ].m_overriding )
+ m_data[ i ].m_angle_change = true;
+
+ //to be finished
+ m_data[ i ].m_overriding = dir;
+ return;
+ }
+ }
+ }
+
+ m_data[ i ].m_overriding = 0;
+ brute_force( ent );
+ }
+
+ void c_ragebot::c_resolver::frame_stage_notify( ) {
+ if( !g_settings.rage.enabled( ) || !g_settings.rage.resolver( ) )
+ return;
+
+ if( !g_ctx.run_frame( ) || !g_ctx.m_local->is_valid( ) )
+ return;
+
+ for( int i{ 1 }; i < g_csgo.m_globals->m_maxclients; ++i ) {
+ auto ent = g_csgo.m_entlist( )->GetClientEntity< >( i );
+
+ if( !ent || ent == g_ctx.m_local || ent->ce( )->IsDormant( ) || !ent->is_player( )
+ || !ent->is_alive( ) || !g_cheat.m_player_mgr.is_cheater( i ) ) {
+ m_data[ i ].m_was_invalid = true;
+ m_data[ i ].m_has_valid_lby = false;
+ continue;
+ }
+
+ if( ent->m_iTeamNum( ) == g_ctx.m_local->m_iTeamNum( ) && !g_settings.rage.friendlies )
+ continue;
+
+ //update_player( i );
+ }
+ }
+
+ void c_ragebot::c_resolver::force_yaw( c_base_player* ent, float yaw ) {
+ ent->m_angEyeAngles( ).y = yaw;// + 180.f;
+ }
+
+ int c_ragebot::c_resolver::manual_override( c_base_player* ent ) {
+ if( ent->get_animdata( ).m_anim_velocity.length2d( ) > 0.1f && !ent->is_fakewalking( ) ) { //no point in overriding moving targets, it will also fuck up backtrack records otherwise
+ return OVERRIDE_NONE;
+ }
+
+ vec3_t pos;
+ vec3_t angle;
+ vec3_t local_angle;
+ vec3_t local_pos;
+ float delta;
+ float dist;
+
+
+ local_pos = g_ctx.m_local->m_vecOrigin( );
+ g_csgo.m_engine( )->GetViewAngles( local_angle );
+ pos = ent->get_hitbox_pos( 0 );
+
+ angle = math::vector_angles( local_pos, pos );
+ dist = pos.dist_to( local_pos );
+ delta = ( angle - local_angle ).clamp( ).y;
+ float yaw_delta = sin( DEG2RAD( ( angle - local_angle ).clamp( ).y ) ) * dist;
+
+ if( std::abs( yaw_delta ) < 25.f ) {
+ force_yaw( ent, angle.y );
+ return OVERRIDE_CENTER;
+ }
+ else {
+ force_yaw( ent, angle.y + ( ( delta < 0.f ) ? 90.f : -90.f ) );
+ return delta > 0.f ? OVERRIDE_LEFT : OVERRIDE_RIGHT;
+ }
+ }
+
+ void c_ragebot::c_resolver::force_lby( c_base_player* ent ) {
+ force_yaw( ent, ent->m_flLowerBodyYawTarget( ) );
+ }
+
+ void c_ragebot::c_resolver::brute_force( c_base_player* ent ) {
+ if( ent->m_flSimulationTime( ) == g_cheat.m_ragebot.m_lagcomp->get_last_updated_simtime( ent->ce( )->GetIndex( ) ) )
+ return;
+
+ if( ent->get_anim_velocity( ).length( ) > 0.1f && ( ent->m_fFlags( ) & FL_ONGROUND ) && !ent->is_fakewalking( ) ) {
+ m_data[ ent->ce( )->GetIndex( ) ].m_last_moving_lby = ent->m_flLowerBodyYawTarget( );
+ m_data[ ent->ce( )->GetIndex( ) ].m_has_valid_lby = true;
+ force_lby( ent );
+ return;
+ }
+
+ int i = ent->ce( )->GetIndex( );
+ int s = get_resolver_shots( i );
+ auto vec = get_shot_vec( i );
+
+ if( vec.at( s % vec.size( ) ) == FLT_ANG_MOVING_LBY_UP && g_settings.rage.pitch_resolver )
+ ent->m_angEyeAngles( ).x = -89.f;
+
+ float new_yaw = get_shot_yaw( get_resolver_shots( i ), i );
+
+ force_yaw( ent, new_yaw );
+ }
+} \ No newline at end of file