diff options
Diffstat (limited to '')
| -rw-r--r-- | src/esp.cpp | 204 |
1 files changed, 153 insertions, 51 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]; |
