diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-27 12:43:59 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-27 12:43:59 +0100 |
| commit | 5adb4303c8ac4969312fa1afd4f254cba65f6ecc (patch) | |
| tree | 5a82f08cef4ae7b9d344826c7b96710eb46db101 /src | |
| parent | Bones: ignore uninitialized/zero bone matrices (diff) | |
| download | hl2h-5adb4303c8ac4969312fa1afd4f254cba65f6ecc.tar.gz hl2h-5adb4303c8ac4969312fa1afd4f254cba65f6ecc.zip | |
Aimbot/silent aim: settable FOV, FOV circle, target locking
- Aimbot -> FOV and Silent aim -> FOV values (1..180 deg from the crosshair)
- Aimbot -> Show FOV circle: projects the FOV cone through the engine's
world->screen transform (hidden for >=89 deg since the boundary is behind
the eye)
- target lock: while a feature has a bind and the key is held, the acquired
target is kept while it is alive and has a visible selected hitbox point;
it only re-acquires when the target dies/leaves visibility or the key is
released. With bind = None both features keep selecting the nearest target.
Diffstat (limited to 'src')
| -rw-r--r-- | src/esp.cpp | 204 | ||||
| -rw-r--r-- | src/hl2h.cpp | 5 | ||||
| -rw-r--r-- | src/hl2h.h | 7 | ||||
| -rw-r--r-- | src/menu.cpp | 72 |
4 files changed, 224 insertions, 64 deletions
diff --git a/src/esp.cpp b/src/esp.cpp index 7583f26..945b234 100644 --- a/src/esp.cpp +++ b/src/esp.cpp | |||
| @@ -274,6 +274,45 @@ static void surf_line(int x0, int y0, int x1, int y1) { | |||
| 274 | vfunc<Fn>(g_surface, SURF_DrawLine)(g_surface, x0, y0, x1, y1); | 274 | vfunc<Fn>(g_surface, SURF_DrawLine)(g_surface, x0, y0, x1, y1); |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | // Screen projection of the aimbot FOV cone boundary, using the engine's own | ||
| 278 | // world->screen transform so it follows the actual aspect/fov. | ||
| 279 | static void draw_fov_circle() { | ||
| 280 | if (!aimbot_fov_circle()) | ||
| 281 | return; | ||
| 282 | float fov = (float)aimbot_fov(); | ||
| 283 | if (fov < 1.0f || fov >= 89.0f) // beyond this the "circle" is behind the eye | ||
| 284 | return; | ||
| 285 | float alpha = fov * PI_F / 180.0f; | ||
| 286 | float yaw = g_cam_view.y * PI_F / 180.0f; | ||
| 287 | float pitch = g_cam_view.x * PI_F / 180.0f; | ||
| 288 | Vector fwd{cosf(pitch) * cosf(yaw), cosf(pitch) * sinf(yaw), -sinf(pitch)}; | ||
| 289 | Vector right{sinf(yaw), -cosf(yaw), 0.0f}; | ||
| 290 | Vector up{right.y * fwd.z - right.z * fwd.y, | ||
| 291 | right.z * fwd.x - right.x * fwd.z, | ||
| 292 | right.x * fwd.y - right.y * fwd.x}; | ||
| 293 | constexpr int N = 48; | ||
| 294 | float xs[N], ys[N]; | ||
| 295 | bool ok[N]; | ||
| 296 | float ca = cosf(alpha), sa = sinf(alpha); | ||
| 297 | for (int i = 0; i < N; i++) { | ||
| 298 | float phi = (2.0f * PI_F * i) / N; | ||
| 299 | float cp = cosf(phi), sp = sinf(phi); | ||
| 300 | Vector d{fwd.x * ca + (right.x * cp + up.x * sp) * sa, | ||
| 301 | fwd.y * ca + (right.y * cp + up.y * sp) * sa, | ||
| 302 | fwd.z * ca + (right.z * cp + up.z * sp) * sa}; | ||
| 303 | Vector p{g_cam_eye.x + d.x * 1024.0f, g_cam_eye.y + d.y * 1024.0f, | ||
| 304 | g_cam_eye.z + d.z * 1024.0f}; | ||
| 305 | ok[i] = world_to_screen(p, xs[i], ys[i]) && std::isfinite(xs[i]) && | ||
| 306 | std::isfinite(ys[i]); | ||
| 307 | } | ||
| 308 | surf_color(255, 255, 255, 160); | ||
| 309 | for (int i = 0; i < N; i++) { | ||
| 310 | int j = (i + 1) % N; | ||
| 311 | if (ok[i] && ok[j]) | ||
| 312 | surf_line((int)xs[i], (int)ys[i], (int)xs[j], (int)ys[j]); | ||
| 313 | } | ||
| 314 | } | ||
| 315 | |||
| 277 | // Draw the parent->child bone links. Bone snapshots are world-space matrices | 316 | // Draw the parent->child bone links. Bone snapshots are world-space matrices |
| 278 | // from SetupBones; project each bone once and reuse for both endpoints. | 317 | // from SetupBones; project each bone once and reuse for both endpoints. |
| 279 | static void draw_skeleton(const EspTarget &t) { | 318 | static void draw_skeleton(const EspTarget &t) { |
| @@ -332,11 +371,20 @@ static QAngle angle_to(const Vector &from, const Vector &to) { | |||
| 332 | return a; | 371 | return a; |
| 333 | } | 372 | } |
| 334 | 373 | ||
| 335 | static constexpr float AIM_MAX_FOV = 60.0f; | 374 | static int g_aim_lock = -1; |
| 375 | static int g_silent_lock = -1; | ||
| 336 | 376 | ||
| 377 | void aimbot_reset_lock() { g_aim_lock = -1; } | ||
| 378 | void silentaim_reset_lock() { g_silent_lock = -1; } | ||
| 379 | |||
| 380 | // max_fov is the angular radius around the crosshair. If lock_idx is non-null | ||
| 381 | // and valid, that target is kept while it is alive and visible (the "do not | ||
| 382 | // switch while the bind is held" rule); a fresh acquisition is ranked by angle | ||
| 383 | // and the nearest visible selected hitbox point. | ||
| 337 | static bool select_aim_target(const QAngle &view, unsigned bone_mask, | 384 | static bool select_aim_target(const QAngle &view, unsigned bone_mask, |
| 338 | bool vischeck, const char *tag, int &out_idx, | 385 | bool vischeck, float max_fov, const char *tag, |
| 339 | Vector &out_point, float &out_fov) { | 386 | int *lock_idx, int &out_idx, Vector &out_point, |
| 387 | float &out_fov) { | ||
| 340 | out_idx = -1; | 388 | out_idx = -1; |
| 341 | out_point = {}; | 389 | out_point = {}; |
| 342 | out_fov = 0.0f; | 390 | out_fov = 0.0f; |
| @@ -352,6 +400,71 @@ static bool select_aim_target(const QAngle &view, unsigned bone_mask, | |||
| 352 | *(int *)((uintptr_t)local_ent + g_net.health) <= 0) | 400 | *(int *)((uintptr_t)local_ent + g_net.health) <= 0) |
| 353 | return false; | 401 | return false; |
| 354 | 402 | ||
| 403 | auto try_target = [&](int idx, bool enforce_fov, Vector &pt, | ||
| 404 | float &fov) -> bool { | ||
| 405 | if (idx <= 0 || idx == local) | ||
| 406 | return false; | ||
| 407 | void *ent = entitylist_get(idx); | ||
| 408 | if (!ent) | ||
| 409 | return false; | ||
| 410 | void *net = entity_networkable(idx); | ||
| 411 | if (!net) | ||
| 412 | return false; | ||
| 413 | const char *cls = entity_class_name(net, nullptr); | ||
| 414 | if (!cls || !is_npc_class(cls)) | ||
| 415 | return false; | ||
| 416 | uintptr_t e = (uintptr_t)ent; | ||
| 417 | int life = g_net.lifestate >= 0 | ||
| 418 | ? (int)*(unsigned char *)(e + g_net.lifestate) | ||
| 419 | : -1; | ||
| 420 | if (life != LIFE_ALIVE) | ||
| 421 | return false; | ||
| 422 | const char *model = entity_model_name(ent); | ||
| 423 | if (model_is_friendly(model) || model_is_neutral(model)) | ||
| 424 | return false; | ||
| 425 | if (!bones_update(idx, ent)) | ||
| 426 | return false; | ||
| 427 | Vector pts[32]; | ||
| 428 | int npoints = aim_points(idx, bone_mask, pts, 32); | ||
| 429 | float best = 1e9f; | ||
| 430 | Vector best_pt{}; | ||
| 431 | for (int i = 0; i < npoints; i++) { | ||
| 432 | float f = getfov(view, angle_to(g_cam_eye, pts[i])); | ||
| 433 | if (enforce_fov && f > max_fov) | ||
| 434 | continue; | ||
| 435 | if (f >= best) | ||
| 436 | continue; | ||
| 437 | if (vischeck && !is_visible(g_cam_eye, pts[i])) | ||
| 438 | continue; | ||
| 439 | best = f; | ||
| 440 | best_pt = pts[i]; | ||
| 441 | } | ||
| 442 | if (best > 1e8f) | ||
| 443 | return false; | ||
| 444 | pt = best_pt; | ||
| 445 | fov = best; | ||
| 446 | return true; | ||
| 447 | }; | ||
| 448 | |||
| 449 | // Keep the locked target while it is alive and has a visible selected point. | ||
| 450 | // No FOV limit on a locked target; only acquisition is FOV-limited. | ||
| 451 | if (lock_idx && *lock_idx >= 0) { | ||
| 452 | Vector pt; | ||
| 453 | float f; | ||
| 454 | if (try_target(*lock_idx, false, pt, f)) { | ||
| 455 | out_idx = *lock_idx; | ||
| 456 | out_point = pt; | ||
| 457 | out_fov = f; | ||
| 458 | static int lock_logs = 0; | ||
| 459 | if (lock_logs < 5) { | ||
| 460 | lock_logs++; | ||
| 461 | logf("%s: lock idx=%d fov=%.2f", tag, out_idx, f); | ||
| 462 | } | ||
| 463 | return true; | ||
| 464 | } | ||
| 465 | *lock_idx = -1; | ||
| 466 | } | ||
| 467 | |||
| 355 | using Fn = int (*)(void *); | 468 | using Fn = int (*)(void *); |
| 356 | int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist); | 469 | int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist); |
| 357 | if (hi < 0 || hi > 4096) | 470 | if (hi < 0 || hi > 4096) |
| @@ -397,7 +510,7 @@ static bool select_aim_target(const QAngle &view, unsigned bone_mask, | |||
| 397 | Vector approx{origin.x, origin.y, | 510 | Vector approx{origin.x, origin.y, |
| 398 | origin.z + maxz * ((bone_mask & (1u << 1)) ? 0.9f : 0.55f)}; | 511 | origin.z + maxz * ((bone_mask & (1u << 1)) ? 0.9f : 0.55f)}; |
| 399 | float fov = getfov(view, angle_to(g_cam_eye, approx)); | 512 | float fov = getfov(view, angle_to(g_cam_eye, approx)); |
| 400 | if (fov >= AIM_MAX_FOV) | 513 | if (fov > max_fov) |
| 401 | continue; | 514 | continue; |
| 402 | 515 | ||
| 403 | int pos = ncands; | 516 | int pos = ncands; |
| @@ -416,57 +529,37 @@ static bool select_aim_target(const QAngle &view, unsigned bone_mask, | |||
| 416 | double now = esp_now(); | 529 | double now = esp_now(); |
| 417 | if (now - last_none >= 2.0) { | 530 | if (now - last_none >= 2.0) { |
| 418 | last_none = now; | 531 | last_none = now; |
| 419 | logf("%s: no hostile target within %.0f deg", tag, AIM_MAX_FOV); | 532 | logf("%s: no hostile target within %.0f deg", tag, max_fov); |
| 420 | } | 533 | } |
| 421 | return false; | 534 | return false; |
| 422 | } | 535 | } |
| 423 | 536 | ||
| 424 | int best_idx = -1; | 537 | for (int ci = 0; ci < ncands; ci++) { |
| 425 | Vector best_point{}; | 538 | Vector pt; |
| 426 | float best_fov = 0.0f; | 539 | float f; |
| 427 | for (int ci = 0; ci < ncands && best_idx < 0; ci++) { | 540 | if (!try_target(cands[ci].idx, true, pt, f)) |
| 428 | int idx = cands[ci].idx; | ||
| 429 | void *ent = entitylist_get(idx); | ||
| 430 | if (!ent || !bones_update(idx, ent)) | ||
| 431 | continue; | 541 | continue; |
| 432 | Vector pts[32]; | 542 | out_idx = cands[ci].idx; |
| 433 | int npoints = aim_points(idx, bone_mask, pts, 32); | 543 | out_point = pt; |
| 434 | float aim_fov = 1e9f; | 544 | out_fov = f; |
| 435 | Vector aim_pt{}; | 545 | if (lock_idx) |
| 436 | for (int i = 0; i < npoints; i++) { | 546 | *lock_idx = out_idx; |
| 437 | float f = getfov(view, angle_to(g_cam_eye, pts[i])); | 547 | static int sel_logs = 0; |
| 438 | if (f >= aim_fov) | 548 | if (sel_logs < 5) { |
| 439 | continue; | 549 | sel_logs++; |
| 440 | if (vischeck && !is_visible(g_cam_eye, pts[i])) | 550 | logf("%s: target idx=%d fov=%.2f vischeck=%d", tag, out_idx, f, |
| 441 | continue; | 551 | (int)vischeck); |
| 442 | aim_fov = f; | ||
| 443 | aim_pt = pts[i]; | ||
| 444 | } | ||
| 445 | if (aim_fov <= AIM_MAX_FOV && aim_fov < 1e8f) { | ||
| 446 | best_idx = idx; | ||
| 447 | best_point = aim_pt; | ||
| 448 | best_fov = aim_fov; | ||
| 449 | static int sel_logs = 0; | ||
| 450 | if (sel_logs < 5) { | ||
| 451 | sel_logs++; | ||
| 452 | logf("%s: target idx=%d points=%d fov=%.2f vischeck=%d", tag, idx, | ||
| 453 | npoints, aim_fov, (int)vischeck); | ||
| 454 | } | ||
| 455 | } | 552 | } |
| 553 | return true; | ||
| 456 | } | 554 | } |
| 457 | if (best_idx < 0) { | 555 | |
| 458 | static double last_vis = 0.0; | 556 | static double last_vis = 0.0; |
| 459 | double now = esp_now(); | 557 | double now = esp_now(); |
| 460 | if (now - last_vis >= 2.0) { | 558 | if (now - last_vis >= 2.0) { |
| 461 | last_vis = now; | 559 | last_vis = now; |
| 462 | logf("%s: no visible aim point (vischeck=%d)", tag, (int)vischeck); | 560 | logf("%s: no visible aim point (vischeck=%d)", tag, (int)vischeck); |
| 463 | } | ||
| 464 | return false; | ||
| 465 | } | 561 | } |
| 466 | out_idx = best_idx; | 562 | return false; |
| 467 | out_point = best_point; | ||
| 468 | out_fov = best_fov; | ||
| 469 | return true; | ||
| 470 | } | 563 | } |
| 471 | 564 | ||
| 472 | bool aimbot_apply(CUserCmd *cmd) { | 565 | bool aimbot_apply(CUserCmd *cmd) { |
| @@ -477,8 +570,12 @@ bool aimbot_apply(CUserCmd *cmd) { | |||
| 477 | int target = -1; | 570 | int target = -1; |
| 478 | Vector point{}; | 571 | Vector point{}; |
| 479 | float fov = 0.0f; | 572 | float fov = 0.0f; |
| 480 | if (!select_aim_target(view, bone_mask, aimbot_vischeck_enabled(), "aimbot", | 573 | float max_fov = (float)aimbot_fov(); |
| 481 | target, point, fov)) | 574 | if (max_fov < 1.0f) max_fov = 1.0f; |
| 575 | if (max_fov > 180.0f) max_fov = 180.0f; | ||
| 576 | int *lock = feature_has_bind(FEAT_AIMBOT) ? &g_aim_lock : nullptr; | ||
| 577 | if (!select_aim_target(view, bone_mask, aimbot_vischeck_enabled(), max_fov, | ||
| 578 | "aimbot", lock, target, point, fov)) | ||
| 482 | return false; | 579 | return false; |
| 483 | QAngle desired = angle_to(g_cam_eye, point); | 580 | QAngle desired = angle_to(g_cam_eye, point); |
| 484 | static int want_logs = 0; | 581 | static int want_logs = 0; |
| @@ -548,8 +645,12 @@ bool silent_aim_apply(CUserCmd *cmd) { | |||
| 548 | int target = -1; | 645 | int target = -1; |
| 549 | Vector point{}; | 646 | Vector point{}; |
| 550 | float fov = 0.0f; | 647 | float fov = 0.0f; |
| 551 | if (!select_aim_target(view, bone_mask, true, "silentaim", target, point, | 648 | float max_fov = (float)silentaim_fov(); |
| 552 | fov)) | 649 | if (max_fov < 1.0f) max_fov = 1.0f; |
| 650 | if (max_fov > 180.0f) max_fov = 180.0f; | ||
| 651 | int *lock = feature_has_bind(FEAT_SILENTAIM) ? &g_silent_lock : nullptr; | ||
| 652 | if (!select_aim_target(view, bone_mask, true, max_fov, "silentaim", lock, | ||
| 653 | target, point, fov)) | ||
| 553 | return false; | 654 | return false; |
| 554 | QAngle desired = angle_to(g_cam_eye, point); | 655 | QAngle desired = angle_to(g_cam_eye, point); |
| 555 | float np = desired.x; | 656 | float np = desired.x; |
| @@ -643,6 +744,7 @@ void esp_draw() { | |||
| 643 | logf("ESP: screen %dx%d", g_scr_w, g_scr_h); | 744 | logf("ESP: screen %dx%d", g_scr_w, g_scr_h); |
| 644 | if (!g_scr_w) return; | 745 | if (!g_scr_w) return; |
| 645 | } | 746 | } |
| 747 | draw_fov_circle(); | ||
| 646 | esp_collect(engine_get_local_player()); | 748 | esp_collect(engine_get_local_player()); |
| 647 | for (int i = 0; i < g_ntargets; i++) { | 749 | for (int i = 0; i < g_ntargets; i++) { |
| 648 | const EspTarget &t = g_targets[i]; | 750 | const EspTarget &t = g_targets[i]; |
diff --git a/src/hl2h.cpp b/src/hl2h.cpp index a49acc2..4947b18 100644 --- a/src/hl2h.cpp +++ b/src/hl2h.cpp | |||
| @@ -260,6 +260,11 @@ static void do_move(int seq) { | |||
| 260 | } | 260 | } |
| 261 | } | 261 | } |
| 262 | 262 | ||
| 263 | if (!feature_active(FEAT_AIMBOT) || !feature_has_bind(FEAT_AIMBOT)) | ||
| 264 | aimbot_reset_lock(); | ||
| 265 | if (!feature_active(FEAT_SILENTAIM) || !feature_has_bind(FEAT_SILENTAIM)) | ||
| 266 | silentaim_reset_lock(); | ||
| 267 | |||
| 263 | if (feature_active(FEAT_AIMBOT)) { | 268 | if (feature_active(FEAT_AIMBOT)) { |
| 264 | static bool aim_feature_logged = false; | 269 | static bool aim_feature_logged = false; |
| 265 | if (!aim_feature_logged) { | 270 | if (!aim_feature_logged) { |
| @@ -179,11 +179,18 @@ int server_model_index(void *base); | |||
| 179 | void find_modules(); | 179 | void find_modules(); |
| 180 | void init_conmsg(); | 180 | void init_conmsg(); |
| 181 | bool feature_active(int feature); | 181 | bool feature_active(int feature); |
| 182 | bool feature_has_bind(int feature); | ||
| 183 | bool feature_bind_held(int feature); | ||
| 182 | bool esp_option(int opt); | 184 | bool esp_option(int opt); |
| 183 | bool bhop_autostrafe_enabled(); | 185 | bool bhop_autostrafe_enabled(); |
| 184 | unsigned aimbot_bone_mask(); | 186 | unsigned aimbot_bone_mask(); |
| 185 | int aimbot_smooth_step(); | 187 | int aimbot_smooth_step(); |
| 186 | bool aimbot_vischeck_enabled(); | 188 | bool aimbot_vischeck_enabled(); |
| 189 | int aimbot_fov(); | ||
| 190 | int silentaim_fov(); | ||
| 191 | bool aimbot_fov_circle(); | ||
| 192 | void aimbot_reset_lock(); | ||
| 193 | void silentaim_reset_lock(); | ||
| 187 | void *entitylist_get(int idx); | 194 | void *entitylist_get(int idx); |
| 188 | int engine_get_local_player(); | 195 | int engine_get_local_player(); |
| 189 | void draw_text_col(int x, int y, const char *s, int r, int g, int b); | 196 | void draw_text_col(int x, int y, const char *s, int r, int g, int b); |
diff --git a/src/menu.cpp b/src/menu.cpp index 41d3321..49dd886 100644 --- a/src/menu.cpp +++ b/src/menu.cpp | |||
| @@ -81,6 +81,9 @@ static bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false, | |||
| 81 | false, false, false}; | 81 | false, false, false}; |
| 82 | static int g_aim_smooth = 5; // degrees per tick | 82 | static int g_aim_smooth = 5; // degrees per tick |
| 83 | static bool g_aim_vischeck = true; | 83 | static bool g_aim_vischeck = true; |
| 84 | static int g_aim_fov = 60; // angular distance from the crosshair | ||
| 85 | static bool g_aim_fov_circle = true; | ||
| 86 | static int g_silent_fov = 60; | ||
| 84 | 87 | ||
| 85 | // ESP sub-options (menu "ESP" children). Defaults match the pre-option | 88 | // ESP sub-options (menu "ESP" children). Defaults match the pre-option |
| 86 | // behaviour: everything on. | 89 | // behaviour: everything on. |
| @@ -118,14 +121,19 @@ static MenuNode g_aimbot_bone_nodes[AIM_BONE_COUNT] = { | |||
| 118 | }; | 121 | }; |
| 119 | static MenuNode g_aimbot_smooth_node{NODE_VALUE, "Smoothness", false, 0, {}, nullptr, | 122 | static MenuNode g_aimbot_smooth_node{NODE_VALUE, "Smoothness", false, 0, {}, nullptr, |
| 120 | nullptr, nullptr, &g_aim_smooth, 1, 45, 1}; | 123 | nullptr, nullptr, &g_aim_smooth, 1, 45, 1}; |
| 124 | static MenuNode g_aimbot_fov_node{NODE_VALUE, "FOV", false, 0, {}, nullptr, | ||
| 125 | nullptr, nullptr, &g_aim_fov, 1, 180, 1}; | ||
| 126 | static MenuNode g_aimbot_fov_circle_node{NODE_TOGGLE, "Show FOV circle", false, 0, {}, &g_aim_fov_circle, nullptr, nullptr}; | ||
| 121 | static MenuNode g_triggerbot_feat{NODE_FEATURE, "Triggerbot", false, 1, {}, nullptr, nullptr, nullptr}; | 127 | static MenuNode g_triggerbot_feat{NODE_FEATURE, "Triggerbot", false, 1, {}, nullptr, nullptr, nullptr}; |
| 122 | static MenuNode g_triggerbot_active{NODE_TOGGLE, "Active", false, 0, {}, &g_triggerbot.active, nullptr, nullptr}; | 128 | static MenuNode g_triggerbot_active{NODE_TOGGLE, "Active", false, 0, {}, &g_triggerbot.active, nullptr, nullptr}; |
| 123 | static MenuNode g_triggerbot_bind{NODE_BIND, "Bind", false, 0, {}, nullptr, &g_triggerbot.bind, nullptr}; | 129 | static MenuNode g_triggerbot_bind{NODE_BIND, "Bind", false, 0, {}, nullptr, &g_triggerbot.bind, nullptr}; |
| 124 | static MenuNode g_silentaim_feat{NODE_FEATURE, "Silent aim", false, 1, {}, nullptr, nullptr, nullptr}; | 130 | static MenuNode g_silentaim_feat{NODE_FEATURE, "Silent aim", false, 1, {}, nullptr, nullptr, nullptr}; |
| 125 | static MenuNode g_silentaim_active{NODE_TOGGLE, "Active", false, 0, {}, &g_silentaim.active, nullptr, nullptr}; | 131 | static MenuNode g_silentaim_active{NODE_TOGGLE, "Active", false, 0, {}, &g_silentaim.active, nullptr, nullptr}; |
| 126 | static MenuNode g_silentaim_bind{NODE_BIND, "Bind", false, 0, {}, nullptr, &g_silentaim.bind, nullptr}; | 132 | static MenuNode g_silentaim_bind{NODE_BIND, "Bind", false, 0, {}, nullptr, &g_silentaim.bind, nullptr}; |
| 133 | static MenuNode g_silentaim_fov_node{NODE_VALUE, "FOV", false, 0, {}, nullptr, | ||
| 134 | nullptr, nullptr, &g_silent_fov, 1, 180, 1}; | ||
| 127 | 135 | ||
| 128 | static MenuNode *g_visible[32]; // flattened visible nodes for arrow navigation | 136 | static MenuNode *g_visible[48]; // flattened visible nodes for arrow navigation |
| 129 | static int g_visible_count = 0; | 137 | static int g_visible_count = 0; |
| 130 | static int g_selected = 0; | 138 | static int g_selected = 0; |
| 131 | bool g_menu_open = false; | 139 | bool g_menu_open = false; |
| @@ -142,7 +150,9 @@ static void build_tree() { | |||
| 142 | g_aimbot_feat.children[2] = &g_aimbot_vischeck_node; | 150 | g_aimbot_feat.children[2] = &g_aimbot_vischeck_node; |
| 143 | g_aimbot_feat.children[3] = &g_aimbot_bones_feat; | 151 | g_aimbot_feat.children[3] = &g_aimbot_bones_feat; |
| 144 | g_aimbot_feat.children[4] = &g_aimbot_smooth_node; | 152 | g_aimbot_feat.children[4] = &g_aimbot_smooth_node; |
| 145 | g_aimbot_feat.child_count = 5; | 153 | g_aimbot_feat.children[5] = &g_aimbot_fov_node; |
| 154 | g_aimbot_feat.children[6] = &g_aimbot_fov_circle_node; | ||
| 155 | g_aimbot_feat.child_count = 7; | ||
| 146 | for (int i = 0; i < AIM_BONE_COUNT; i++) | 156 | for (int i = 0; i < AIM_BONE_COUNT; i++) |
| 147 | g_aimbot_bones_feat.children[i] = &g_aimbot_bone_nodes[i]; | 157 | g_aimbot_bones_feat.children[i] = &g_aimbot_bone_nodes[i]; |
| 148 | g_aimbot_bones_feat.child_count = AIM_BONE_COUNT; | 158 | g_aimbot_bones_feat.child_count = AIM_BONE_COUNT; |
| @@ -151,7 +161,8 @@ static void build_tree() { | |||
| 151 | g_triggerbot_feat.child_count = 2; | 161 | g_triggerbot_feat.child_count = 2; |
| 152 | g_silentaim_feat.children[0] = &g_silentaim_active; | 162 | g_silentaim_feat.children[0] = &g_silentaim_active; |
| 153 | g_silentaim_feat.children[1] = &g_silentaim_bind; | 163 | g_silentaim_feat.children[1] = &g_silentaim_bind; |
| 154 | g_silentaim_feat.child_count = 2; | 164 | g_silentaim_feat.children[2] = &g_silentaim_fov_node; |
| 165 | g_silentaim_feat.child_count = 3; | ||
| 155 | for (int i = 0; i < ESP_OPT_COUNT; i++) | 166 | for (int i = 0; i < ESP_OPT_COUNT; i++) |
| 156 | g_esp_feat.children[i + 1] = &g_esp_opt_nodes[i]; | 167 | g_esp_feat.children[i + 1] = &g_esp_opt_nodes[i]; |
| 157 | g_esp_feat.child_count = ESP_OPT_COUNT + 1; | 168 | g_esp_feat.child_count = ESP_OPT_COUNT + 1; |
| @@ -164,10 +175,10 @@ static void build_tree() { | |||
| 164 | g_root.child_count = 6; | 175 | g_root.child_count = 6; |
| 165 | } | 176 | } |
| 166 | 177 | ||
| 167 | static int g_depth[32]; // depth of each visible row (for indentation) | 178 | static int g_depth[48]; // depth of each visible row (for indentation) |
| 168 | 179 | ||
| 169 | static void flatten(MenuNode *node, int depth) { | 180 | static void flatten(MenuNode *node, int depth) { |
| 170 | if (g_visible_count >= 32) | 181 | if (g_visible_count >= 48) |
| 171 | return; | 182 | return; |
| 172 | node->type = (depth == 0) ? NODE_ROOT | 183 | node->type = (depth == 0) ? NODE_ROOT |
| 173 | : (node->child_count > 0) ? NODE_FEATURE | 184 | : (node->child_count > 0) ? NODE_FEATURE |
| @@ -284,17 +295,18 @@ static void config_save() { | |||
| 284 | g_bhop.bind, g_bhop_autostrafe); | 295 | g_bhop.bind, g_bhop_autostrafe); |
| 285 | fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); | 296 | fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); |
| 286 | fprintf(f, "[aimbot]\nactive=%d\nbind=%d\nsmooth=%d\nvischeck=%d\n" | 297 | fprintf(f, "[aimbot]\nactive=%d\nbind=%d\nsmooth=%d\nvischeck=%d\n" |
| 298 | "fov=%d\nfov_circle=%d\n" | ||
| 287 | "bone_head=%d\nbone_torso=%d\nbone_larm=%d\nbone_rarm=%d\n" | 299 | "bone_head=%d\nbone_torso=%d\nbone_larm=%d\nbone_rarm=%d\n" |
| 288 | "bone_lleg=%d\nbone_rleg=%d\n", | 300 | "bone_lleg=%d\nbone_rleg=%d\n", |
| 289 | g_aimbot.active, g_aimbot.bind, g_aim_smooth, | 301 | g_aimbot.active, g_aimbot.bind, g_aim_smooth, |
| 290 | (int)g_aim_vischeck, | 302 | (int)g_aim_vischeck, g_aim_fov, (int)g_aim_fov_circle, |
| 291 | g_aim_bones[AIM_BONE_HEAD], g_aim_bones[AIM_BONE_TORSO], | 303 | g_aim_bones[AIM_BONE_HEAD], g_aim_bones[AIM_BONE_TORSO], |
| 292 | g_aim_bones[AIM_BONE_LARM], g_aim_bones[AIM_BONE_RARM], | 304 | g_aim_bones[AIM_BONE_LARM], g_aim_bones[AIM_BONE_RARM], |
| 293 | g_aim_bones[AIM_BONE_LLEG], g_aim_bones[AIM_BONE_RLEG]); | 305 | g_aim_bones[AIM_BONE_LLEG], g_aim_bones[AIM_BONE_RLEG]); |
| 294 | fprintf(f, "[triggerbot]\nactive=%d\nbind=%d\n", g_triggerbot.active, | 306 | fprintf(f, "[triggerbot]\nactive=%d\nbind=%d\n", g_triggerbot.active, |
| 295 | g_triggerbot.bind); | 307 | g_triggerbot.bind); |
| 296 | fprintf(f, "[silentaim]\nactive=%d\nbind=%d\n", g_silentaim.active, | 308 | fprintf(f, "[silentaim]\nactive=%d\nbind=%d\nfov=%d\n", g_silentaim.active, |
| 297 | g_silentaim.bind); | 309 | g_silentaim.bind, g_silent_fov); |
| 298 | fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n" | 310 | fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n" |
| 299 | "healthnum=%d\nname=%d\nskeleton=%d\nbox=%d\n", | 311 | "healthnum=%d\nname=%d\nskeleton=%d\nbox=%d\n", |
| 300 | g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL], | 312 | g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL], |
| @@ -310,7 +322,7 @@ static void config_load() { | |||
| 310 | return; | 322 | return; |
| 311 | char line[256]; | 323 | char line[256]; |
| 312 | FeatureState *cur = nullptr; | 324 | FeatureState *cur = nullptr; |
| 313 | bool in_esp = false, in_bhop = false, in_aim = false; | 325 | bool in_esp = false, in_bhop = false, in_aim = false, in_silent = false; |
| 314 | while (fgets(line, sizeof(line), f)) { | 326 | while (fgets(line, sizeof(line), f)) { |
| 315 | line[strcspn(line, "\r\n")] = 0; | 327 | line[strcspn(line, "\r\n")] = 0; |
| 316 | if (line[0] == '[') { | 328 | if (line[0] == '[') { |
| @@ -331,6 +343,7 @@ static void config_load() { | |||
| 331 | in_esp = (cur == &g_esp); | 343 | in_esp = (cur == &g_esp); |
| 332 | in_bhop = (cur == &g_bhop); | 344 | in_bhop = (cur == &g_bhop); |
| 333 | in_aim = (cur == &g_aimbot); | 345 | in_aim = (cur == &g_aimbot); |
| 346 | in_silent = (cur == &g_silentaim); | ||
| 334 | } else if (cur) { | 347 | } else if (cur) { |
| 335 | char *eq = strchr(line, '='); | 348 | char *eq = strchr(line, '='); |
| 336 | if (!eq) | 349 | if (!eq) |
| @@ -360,8 +373,21 @@ static void config_load() { | |||
| 360 | g_aim_bones[AIM_BONE_RLEG] = atoi(val) != 0; | 373 | g_aim_bones[AIM_BONE_RLEG] = atoi(val) != 0; |
| 361 | } else if (strcmp(key, "vischeck") == 0) { | 374 | } else if (strcmp(key, "vischeck") == 0) { |
| 362 | g_aim_vischeck = atoi(val) != 0; | 375 | g_aim_vischeck = atoi(val) != 0; |
| 376 | } else if (strcmp(key, "fov") == 0) { | ||
| 377 | int v = atoi(val); | ||
| 378 | if (v < 1) v = 1; | ||
| 379 | if (v > 180) v = 180; | ||
| 380 | g_aim_fov = v; | ||
| 381 | } else if (strcmp(key, "fov_circle") == 0) { | ||
| 382 | g_aim_fov_circle = atoi(val) != 0; | ||
| 363 | } | 383 | } |
| 364 | } | 384 | } |
| 385 | if (in_silent && strcmp(key, "fov") == 0) { | ||
| 386 | int v = atoi(val); | ||
| 387 | if (v < 1) v = 1; | ||
| 388 | if (v > 180) v = 180; | ||
| 389 | g_silent_fov = v; | ||
| 390 | } | ||
| 365 | if (in_esp) { | 391 | if (in_esp) { |
| 366 | if (strcmp(key, "neutral") == 0) | 392 | if (strcmp(key, "neutral") == 0) |
| 367 | g_esp_opt[ESP_OPT_SHOW_NEUTRAL] = atoi(val) != 0; | 393 | g_esp_opt[ESP_OPT_SHOW_NEUTRAL] = atoi(val) != 0; |
| @@ -485,18 +511,32 @@ static bool key_pressed(int sc) { | |||
| 485 | 511 | ||
| 486 | // feature gate queried from hl2h.cpp do_move(): feature must be Active AND | 512 | // feature gate queried from hl2h.cpp do_move(): feature must be Active AND |
| 487 | // its bind key held (always-on when unbound). | 513 | // its bind key held (always-on when unbound). |
| 488 | bool feature_active(int feature) { | 514 | static FeatureState *feature_state(int feature) { |
| 489 | static FeatureState *feats[6] = {&g_bhop, &g_abh, &g_esp, | 515 | static FeatureState *feats[6] = {&g_bhop, &g_abh, &g_esp, |
| 490 | &g_aimbot, &g_triggerbot, | 516 | &g_aimbot, &g_triggerbot, |
| 491 | &g_silentaim}; | 517 | &g_silentaim}; |
| 492 | if (feature < 0 || feature > 5) | 518 | if (feature < 0 || feature > 5) |
| 493 | return false; | 519 | return nullptr; |
| 494 | FeatureState *f = feats[feature]; | 520 | return feats[feature]; |
| 495 | if (!f->active) | 521 | } |
| 522 | |||
| 523 | bool feature_active(int feature) { | ||
| 524 | FeatureState *f = feature_state(feature); | ||
| 525 | if (!f || !f->active) | ||
| 496 | return false; | 526 | return false; |
| 497 | return f->bind == 0 || key_held(f->bind); | 527 | return f->bind == 0 || key_held(f->bind); |
| 498 | } | 528 | } |
| 499 | 529 | ||
| 530 | bool feature_has_bind(int feature) { | ||
| 531 | FeatureState *f = feature_state(feature); | ||
| 532 | return f && f->bind != 0; | ||
| 533 | } | ||
| 534 | |||
| 535 | bool feature_bind_held(int feature) { | ||
| 536 | FeatureState *f = feature_state(feature); | ||
| 537 | return f && f->bind != 0 && key_held(f->bind); | ||
| 538 | } | ||
| 539 | |||
| 500 | bool esp_option(int opt) { | 540 | bool esp_option(int opt) { |
| 501 | return opt >= 0 && opt < ESP_OPT_COUNT && g_esp_opt[opt]; | 541 | return opt >= 0 && opt < ESP_OPT_COUNT && g_esp_opt[opt]; |
| 502 | } | 542 | } |
| @@ -524,6 +564,12 @@ int aimbot_smooth_step() { return g_aim_smooth; } | |||
| 524 | 564 | ||
| 525 | bool aimbot_vischeck_enabled() { return g_aim_vischeck; } | 565 | bool aimbot_vischeck_enabled() { return g_aim_vischeck; } |
| 526 | 566 | ||
| 567 | int aimbot_fov() { return g_aim_fov; } | ||
| 568 | |||
| 569 | int silentaim_fov() { return g_silent_fov; } | ||
| 570 | |||
| 571 | bool aimbot_fov_circle() { return g_aim_fov_circle; } | ||
| 572 | |||
| 527 | static void menu_handle_input() { | 573 | static void menu_handle_input() { |
| 528 | poll_keyboard(); | 574 | poll_keyboard(); |
| 529 | 575 | ||
