diff options
| -rw-r--r-- | src/esp.cpp | 117 | ||||
| -rw-r--r-- | src/hl2h.cpp | 7 | ||||
| -rw-r--r-- | src/hl2h.h | 4 | ||||
| -rw-r--r-- | src/menu.cpp | 26 |
4 files changed, 146 insertions, 8 deletions
diff --git a/src/esp.cpp b/src/esp.cpp index 34a702a..1cb8b70 100644 --- a/src/esp.cpp +++ b/src/esp.cpp | |||
| @@ -316,6 +316,123 @@ static void draw_skeleton(const EspTarget &t) { | |||
| 316 | } | 316 | } |
| 317 | } | 317 | } |
| 318 | 318 | ||
| 319 | // --------------------------------------------------------------------------- | ||
| 320 | // aimbot v1: nearest hostile NPC head to the crosshair. | ||
| 321 | // Bounded smoothing: never snap, never overshoot. Each tick moves at most | ||
| 322 | // MAX_STEP degrees toward the target and stops inside DEADZONE. | ||
| 323 | // --------------------------------------------------------------------------- | ||
| 324 | |||
| 325 | static QAngle angle_to(const Vector &from, const Vector &to) { | ||
| 326 | float dx = to.x - from.x, dy = to.y - from.y, dz = to.z - from.z; | ||
| 327 | float horiz = sqrtf(dx * dx + dy * dy); | ||
| 328 | if (horiz < 0.001f) | ||
| 329 | horiz = 0.001f; | ||
| 330 | QAngle a{}; | ||
| 331 | a.x = -atan2f(dz, horiz) * 180.0f / PI_F; // Source: positive pitch = down | ||
| 332 | a.y = atan2f(dy, dx) * 180.0f / PI_F; | ||
| 333 | a.z = 0.0f; | ||
| 334 | return a; | ||
| 335 | } | ||
| 336 | |||
| 337 | bool aimbot_apply(CUserCmd *cmd) { | ||
| 338 | if (!g_iface.entitylist || g_net.origin < 0 || g_net.maxs < 0) | ||
| 339 | return false; | ||
| 340 | int local = engine_get_local_player(); | ||
| 341 | if (local <= 0) | ||
| 342 | return false; | ||
| 343 | void *local_ent = entitylist_get(local); | ||
| 344 | if (!local_ent) | ||
| 345 | return false; | ||
| 346 | if (g_net.health >= 0 && | ||
| 347 | *(int *)((uintptr_t)local_ent + g_net.health) <= 0) | ||
| 348 | return false; | ||
| 349 | |||
| 350 | QAngle view{cmd->viewangles[0], cmd->viewangles[1], 0.0f}; | ||
| 351 | |||
| 352 | using Fn = int (*)(void *); | ||
| 353 | int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist); | ||
| 354 | if (hi < 0 || hi > 4096) | ||
| 355 | hi = 4096; | ||
| 356 | |||
| 357 | constexpr float MAX_FOV = 60.0f; // only things near the crosshair | ||
| 358 | float best_fov = MAX_FOV; | ||
| 359 | int best_idx = -1; | ||
| 360 | Vector best_head{}; | ||
| 361 | |||
| 362 | for (int idx = 1; idx <= hi; idx++) { | ||
| 363 | if (idx == local) | ||
| 364 | continue; | ||
| 365 | void *ent = entitylist_get(idx); | ||
| 366 | if (!ent) | ||
| 367 | continue; | ||
| 368 | void *net = entity_networkable(idx); | ||
| 369 | if (!net) | ||
| 370 | continue; | ||
| 371 | const char *cls = entity_class_name(net, nullptr); | ||
| 372 | if (!cls || !is_npc_class(cls)) | ||
| 373 | continue; | ||
| 374 | |||
| 375 | uintptr_t e = (uintptr_t)ent; | ||
| 376 | int life = g_net.lifestate >= 0 | ||
| 377 | ? (int)*(unsigned char *)(e + g_net.lifestate) | ||
| 378 | : -1; | ||
| 379 | if (life != LIFE_ALIVE) | ||
| 380 | continue; | ||
| 381 | const char *model = entity_model_name(ent); | ||
| 382 | if (model_is_friendly(model) || model_is_neutral(model)) | ||
| 383 | continue; | ||
| 384 | |||
| 385 | float maxz = g_net.maxs >= 0 ? *(float *)(e + g_net.maxs + 8) : 72.0f; | ||
| 386 | if (!(maxz > 4.0f && maxz < 512.0f)) | ||
| 387 | maxz = 72.0f; | ||
| 388 | Vector origin{*(float *)(e + g_net.origin), | ||
| 389 | *(float *)(e + g_net.origin + 4), | ||
| 390 | *(float *)(e + g_net.origin + 8)}; | ||
| 391 | Vector approx{origin.x, origin.y, origin.z + maxz * 0.9f}; | ||
| 392 | float fov = getfov(view, angle_to(g_cam_eye, approx)); | ||
| 393 | if (fov >= best_fov) | ||
| 394 | continue; | ||
| 395 | best_fov = fov; | ||
| 396 | best_idx = idx; | ||
| 397 | best_head = approx; | ||
| 398 | } | ||
| 399 | |||
| 400 | if (best_idx < 0) | ||
| 401 | return false; | ||
| 402 | |||
| 403 | // Refine to the actual head hitbox/bone for the chosen target only. | ||
| 404 | void *best_ent = entitylist_get(best_idx); | ||
| 405 | if (best_ent && bones_update(best_idx, best_ent)) { | ||
| 406 | Vector head; | ||
| 407 | if (head_position(best_idx, head) && | ||
| 408 | getfov(view, angle_to(g_cam_eye, head)) <= MAX_FOV) | ||
| 409 | best_head = head; | ||
| 410 | } | ||
| 411 | |||
| 412 | QAngle desired = angle_to(g_cam_eye, best_head); | ||
| 413 | float dp = desired.x - cmd->viewangles[0]; | ||
| 414 | float dy = desired.y - cmd->viewangles[1]; | ||
| 415 | while (dy > 180.0f) dy -= 360.0f; | ||
| 416 | while (dy < -180.0f) dy += 360.0f; | ||
| 417 | |||
| 418 | constexpr float DEADZONE = 0.05f; | ||
| 419 | constexpr float MAX_STEP = 5.0f; | ||
| 420 | float maxd = fmaxf(fabsf(dp), fabsf(dy)); | ||
| 421 | if (maxd <= DEADZONE) | ||
| 422 | return false; | ||
| 423 | |||
| 424 | float scale = (maxd > MAX_STEP) ? (MAX_STEP / maxd) : 1.0f; | ||
| 425 | float np = cmd->viewangles[0] + dp * scale; | ||
| 426 | float ny = cmd->viewangles[1] + dy * scale; | ||
| 427 | if (np > 89.0f) np = 89.0f; | ||
| 428 | if (np < -89.0f) np = -89.0f; | ||
| 429 | while (ny > 180.0f) ny -= 360.0f; | ||
| 430 | while (ny < -180.0f) ny += 360.0f; | ||
| 431 | cmd->viewangles[0] = np; | ||
| 432 | cmd->viewangles[1] = ny; | ||
| 433 | return true; | ||
| 434 | } | ||
| 435 | |||
| 319 | void esp_draw() { | 436 | void esp_draw() { |
| 320 | if (!g_surface || !g_iface.entitylist || !g_net.esp_ok()) return; | 437 | if (!g_surface || !g_iface.entitylist || !g_net.esp_ok()) return; |
| 321 | if (!g_scr_w) { | 438 | if (!g_scr_w) { |
diff --git a/src/hl2h.cpp b/src/hl2h.cpp index b666585..21fa7ae 100644 --- a/src/hl2h.cpp +++ b/src/hl2h.cpp | |||
| @@ -241,6 +241,13 @@ static void do_move(int seq) { | |||
| 241 | note_modified(cmd, flags, vel); | 241 | note_modified(cmd, flags, vel); |
| 242 | } | 242 | } |
| 243 | } | 243 | } |
| 244 | |||
| 245 | if (feature_active(FEAT_AIMBOT)) { | ||
| 246 | if (aimbot_apply(cmd)) { | ||
| 247 | const float *vel = (const float *)(e + g_net.velocity); | ||
| 248 | note_modified(cmd, flags, vel); | ||
| 249 | } | ||
| 250 | } | ||
| 244 | } | 251 | } |
| 245 | 252 | ||
| 246 | // --------------------------------------------------------------------------- | 253 | // --------------------------------------------------------------------------- |
| @@ -135,7 +135,9 @@ struct QAngle { float x, y, z; }; | |||
| 135 | extern Vector g_cam_eye; | 135 | extern Vector g_cam_eye; |
| 136 | extern Vector g_cam_view; | 136 | extern Vector g_cam_view; |
| 137 | QAngle vector_angles(const Vector &forward); | 137 | QAngle vector_angles(const Vector &forward); |
| 138 | enum FeatureId { FEAT_BHOP = 0, FEAT_ABH = 1, FEAT_ESP = 2 }; | 138 | float getfov(const QAngle &my_view, const QAngle &aim_ang); |
| 139 | bool aimbot_apply(CUserCmd *cmd); | ||
| 140 | enum FeatureId { FEAT_BHOP = 0, FEAT_ABH = 1, FEAT_ESP = 2, FEAT_AIMBOT = 3 }; | ||
| 139 | enum EspOption { | 141 | enum EspOption { |
| 140 | ESP_OPT_SHOW_NEUTRAL = 0, | 142 | ESP_OPT_SHOW_NEUTRAL = 0, |
| 141 | ESP_OPT_SHOW_HEALTHBAR = 1, | 143 | ESP_OPT_SHOW_HEALTHBAR = 1, |
diff --git a/src/menu.cpp b/src/menu.cpp index 6474d69..269174d 100644 --- a/src/menu.cpp +++ b/src/menu.cpp | |||
| @@ -56,6 +56,7 @@ static bool g_bhop_autostrafe = true; | |||
| 56 | 56 | ||
| 57 | static FeatureState g_abh{true, 0}; | 57 | static FeatureState g_abh{true, 0}; |
| 58 | static FeatureState g_esp{true, 0}; | 58 | static FeatureState g_esp{true, 0}; |
| 59 | static FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in menu | ||
| 59 | 60 | ||
| 60 | // ESP sub-options (menu "ESP" children). Defaults match the pre-option | 61 | // ESP sub-options (menu "ESP" children). Defaults match the pre-option |
| 61 | // behaviour: everything on. | 62 | // behaviour: everything on. |
| @@ -77,6 +78,9 @@ static MenuNode g_esp_opt_nodes[ESP_OPT_COUNT] = { | |||
| 77 | {NODE_TOGGLE, "Show name", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_NAME], nullptr, nullptr}, | 78 | {NODE_TOGGLE, "Show name", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_NAME], nullptr, nullptr}, |
| 78 | {NODE_TOGGLE, "Show skeleton", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_SKELETON], nullptr, nullptr}, | 79 | {NODE_TOGGLE, "Show skeleton", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_SKELETON], nullptr, nullptr}, |
| 79 | }; | 80 | }; |
| 81 | static MenuNode g_aimbot_feat{NODE_FEATURE, "Aimbot", false, 1, {}, nullptr, nullptr, nullptr}; | ||
| 82 | static MenuNode g_aimbot_active{NODE_TOGGLE, "Active", false, 0, {}, &g_aimbot.active, nullptr, nullptr}; | ||
| 83 | static MenuNode g_aimbot_bind{NODE_BIND, "Bind", false, 0, {}, nullptr, &g_aimbot.bind, nullptr}; | ||
| 80 | 84 | ||
| 81 | static MenuNode *g_visible[32]; // flattened visible nodes for arrow navigation | 85 | static MenuNode *g_visible[32]; // flattened visible nodes for arrow navigation |
| 82 | static int g_visible_count = 0; | 86 | static int g_visible_count = 0; |
| @@ -90,13 +94,17 @@ static void build_tree() { | |||
| 90 | g_bhop_feat.child_count = 2; | 94 | g_bhop_feat.child_count = 2; |
| 91 | g_abh_feat.children[0] = &g_abh_active; | 95 | g_abh_feat.children[0] = &g_abh_active; |
| 92 | g_esp_feat.children[0] = &g_esp_active; | 96 | g_esp_feat.children[0] = &g_esp_active; |
| 97 | g_aimbot_feat.children[0] = &g_aimbot_active; | ||
| 98 | g_aimbot_feat.children[1] = &g_aimbot_bind; | ||
| 99 | g_aimbot_feat.child_count = 2; | ||
| 93 | for (int i = 0; i < ESP_OPT_COUNT; i++) | 100 | for (int i = 0; i < ESP_OPT_COUNT; i++) |
| 94 | g_esp_feat.children[i + 1] = &g_esp_opt_nodes[i]; | 101 | g_esp_feat.children[i + 1] = &g_esp_opt_nodes[i]; |
| 95 | g_esp_feat.child_count = ESP_OPT_COUNT + 1; | 102 | g_esp_feat.child_count = ESP_OPT_COUNT + 1; |
| 96 | g_root.children[0] = &g_bhop_feat; | 103 | g_root.children[0] = &g_bhop_feat; |
| 97 | g_root.children[1] = &g_abh_feat; | 104 | g_root.children[1] = &g_abh_feat; |
| 98 | g_root.children[2] = &g_esp_feat; | 105 | g_root.children[2] = &g_esp_feat; |
| 99 | g_root.child_count = 3; | 106 | g_root.children[3] = &g_aimbot_feat; |
| 107 | g_root.child_count = 4; | ||
| 100 | } | 108 | } |
| 101 | 109 | ||
| 102 | static int g_depth[32]; // depth of each visible row (for indentation) | 110 | static int g_depth[32]; // depth of each visible row (for indentation) |
| @@ -159,6 +167,8 @@ static void config_save() { | |||
| 159 | fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active, | 167 | fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active, |
| 160 | g_bhop.bind, g_bhop_autostrafe); | 168 | g_bhop.bind, g_bhop_autostrafe); |
| 161 | fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); | 169 | fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); |
| 170 | fprintf(f, "[aimbot]\nactive=%d\nbind=%d\n", g_aimbot.active, | ||
| 171 | g_aimbot.bind); | ||
| 162 | fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n" | 172 | fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n" |
| 163 | "healthnum=%d\nname=%d\nskeleton=%d\n", | 173 | "healthnum=%d\nname=%d\nskeleton=%d\n", |
| 164 | g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL], | 174 | g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL], |
| @@ -184,6 +194,8 @@ static void config_load() { | |||
| 184 | cur = &g_abh; | 194 | cur = &g_abh; |
| 185 | else if (strstr(line, "[esp]")) | 195 | else if (strstr(line, "[esp]")) |
| 186 | cur = &g_esp; | 196 | cur = &g_esp; |
| 197 | else if (strstr(line, "[aimbot]")) | ||
| 198 | cur = &g_aimbot; | ||
| 187 | else | 199 | else |
| 188 | cur = nullptr; | 200 | cur = nullptr; |
| 189 | in_esp = (cur == &g_esp); | 201 | in_esp = (cur == &g_esp); |
| @@ -319,8 +331,8 @@ static bool key_pressed(int sc) { | |||
| 319 | // feature gate queried from hl2h.cpp do_move(): feature must be Active AND | 331 | // feature gate queried from hl2h.cpp do_move(): feature must be Active AND |
| 320 | // its bind key held (always-on when unbound). | 332 | // its bind key held (always-on when unbound). |
| 321 | bool feature_active(int feature) { | 333 | bool feature_active(int feature) { |
| 322 | static FeatureState *feats[3] = {&g_bhop, &g_abh, &g_esp}; | 334 | static FeatureState *feats[4] = {&g_bhop, &g_abh, &g_esp, &g_aimbot}; |
| 323 | if (feature < 0 || feature > 2) | 335 | if (feature < 0 || feature > 3) |
| 324 | return false; | 336 | return false; |
| 325 | FeatureState *f = feats[feature]; | 337 | FeatureState *f = feats[feature]; |
| 326 | if (!f->active) | 338 | if (!f->active) |
| @@ -376,7 +388,7 @@ static void menu_handle_input() { | |||
| 376 | MenuNode *n = g_visible[g_selected]; | 388 | MenuNode *n = g_visible[g_selected]; |
| 377 | if (n->bind_ptr) { | 389 | if (n->bind_ptr) { |
| 378 | // clear same bind from other features | 390 | // clear same bind from other features |
| 379 | FeatureState *features[] = {&g_bhop, &g_abh}; | 391 | FeatureState *features[] = {&g_bhop, &g_abh, &g_aimbot}; |
| 380 | for (auto *f : features) | 392 | for (auto *f : features) |
| 381 | if (&f->bind != n->bind_ptr && f->bind == i) | 393 | if (&f->bind != n->bind_ptr && f->bind == i) |
| 382 | f->bind = 0; | 394 | f->bind = 0; |
| @@ -578,10 +590,10 @@ void outer_draw() { | |||
| 578 | draw_text(270, 10 + i * 20, "[press key]"); | 590 | draw_text(270, 10 + i * 20, "[press key]"); |
| 579 | else { | 591 | else { |
| 580 | /* stable name for current bind */ | 592 | /* stable name for current bind */ |
| 581 | static char bn[2][32]; | 593 | static char bn[3][32]; |
| 582 | static FeatureState *feats[] = {&g_bhop, &g_abh}; | 594 | static FeatureState *feats[] = {&g_bhop, &g_abh, &g_aimbot}; |
| 583 | int fi = 0; | 595 | int fi = 0; |
| 584 | for (int k = 0; k < 2; k++) | 596 | for (int k = 0; k < 3; k++) |
| 585 | if (n->bind_ptr == &feats[k]->bind) | 597 | if (n->bind_ptr == &feats[k]->bind) |
| 586 | fi = k; | 598 | fi = k; |
| 587 | snprintf(bn[fi], 32, "[%s]", scancode_name(*n->bind_ptr)); | 599 | snprintf(bn[fi], 32, "[%s]", scancode_name(*n->bind_ptr)); |
