1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
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 );
}
}
}
|