summaryrefslogtreecommitdiffstats
path: root/src/esp.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-26 17:30:29 +0100
committersalmonik <salmonik@tuta.io>2026-10-26 17:30:29 +0100
commit92d388116cc19ef728d66ac67eaa4f584e63d895 (patch)
tree5b9438cf8c2f1b4f01eef3eec4a6d91b42ac1acb /src/esp.cpp
parentTriggerbot: crosshair entity trace, hostile-only (diff)
downloadhl2h-92d388116cc19ef728d66ac67eaa4f584e63d895.tar.gz
hl2h-92d388116cc19ef728d66ac67eaa4f584e63d895.zip
Silent aim: exact usercmd angle + fire, restore rendered view
- new top-level Silent aim feature (Active + Bind, default Mouse3) - reuses the shared aim-target selection (bone checklist, nearest selected point, world-only MASK_VISIBLE vischeck) - writes the exact target angle into cmd->viewangles, sets IN_ATTACK for the shot, then immediately restores engine view angles to the player's input view (g_cam_view) so the camera stays where it was - shares the vischeck/bone selection with the aimbot; independent of the aimbot/triggerbot binds - config [silentaim] active/bind
Diffstat (limited to 'src/esp.cpp')
-rw-r--r--src/esp.cpp106
1 files changed, 78 insertions, 28 deletions
diff --git a/src/esp.cpp b/src/esp.cpp
index e6981f7..f7c24ce 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -334,12 +334,16 @@ static QAngle angle_to(const Vector &from, const Vector &to) {
334 return a; 334 return a;
335} 335}
336 336
337bool aimbot_apply(CUserCmd *cmd) { 337static constexpr float AIM_MAX_FOV = 60.0f;
338
339static bool select_aim_target(const QAngle &view, unsigned bone_mask,
340 bool vischeck, const char *tag, int &out_idx,
341 Vector &out_point, float &out_fov) {
342 out_idx = -1;
343 out_point = {};
344 out_fov = 0.0f;
338 if (!g_iface.entitylist || g_net.origin < 0 || g_net.maxs < 0) 345 if (!g_iface.entitylist || g_net.origin < 0 || g_net.maxs < 0)
339 return false; 346 return false;
340 unsigned bone_mask = aimbot_bone_mask();
341 if (!bone_mask)
342 return false;
343 int local = engine_get_local_player(); 347 int local = engine_get_local_player();
344 if (local <= 0) 348 if (local <= 0)
345 return false; 349 return false;
@@ -350,14 +354,11 @@ bool aimbot_apply(CUserCmd *cmd) {
350 *(int *)((uintptr_t)local_ent + g_net.health) <= 0) 354 *(int *)((uintptr_t)local_ent + g_net.health) <= 0)
351 return false; 355 return false;
352 356
353 QAngle view{cmd->viewangles[0], cmd->viewangles[1], 0.0f};
354
355 using Fn = int (*)(void *); 357 using Fn = int (*)(void *);
356 int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist); 358 int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist);
357 if (hi < 0 || hi > 4096) 359 if (hi < 0 || hi > 4096)
358 hi = 4096; 360 hi = 4096;
359 361
360 constexpr float MAX_FOV = 60.0f; // only things near the crosshair
361 struct Candidate { 362 struct Candidate {
362 int idx; 363 int idx;
363 float fov; 364 float fov;
@@ -398,10 +399,9 @@ bool aimbot_apply(CUserCmd *cmd) {
398 Vector approx{origin.x, origin.y, 399 Vector approx{origin.x, origin.y,
399 origin.z + maxz * ((bone_mask & (1u << 1)) ? 0.9f : 0.55f)}; 400 origin.z + maxz * ((bone_mask & (1u << 1)) ? 0.9f : 0.55f)};
400 float fov = getfov(view, angle_to(g_cam_eye, approx)); 401 float fov = getfov(view, angle_to(g_cam_eye, approx));
401 if (fov >= MAX_FOV) 402 if (fov >= AIM_MAX_FOV)
402 continue; 403 continue;
403 404
404 // keep candidates sorted by approximate angle, nearest first
405 int pos = ncands; 405 int pos = ncands;
406 while (pos > 0 && cands[pos - 1].fov > fov) 406 while (pos > 0 && cands[pos - 1].fov > fov)
407 pos--; 407 pos--;
@@ -418,15 +418,14 @@ bool aimbot_apply(CUserCmd *cmd) {
418 double now = esp_now(); 418 double now = esp_now();
419 if (now - last_none >= 2.0) { 419 if (now - last_none >= 2.0) {
420 last_none = now; 420 last_none = now;
421 logf("aimbot: no hostile target within %.0f deg", MAX_FOV); 421 logf("%s: no hostile target within %.0f deg", tag, AIM_MAX_FOV);
422 } 422 }
423 return false; 423 return false;
424 } 424 }
425 425
426 // Walk targets nearest-first. On each, pick the nearest selected hitbox
427 // point that passes vischeck; skip to the next target if all are blocked.
428 int best_idx = -1; 426 int best_idx = -1;
429 Vector best_head{}; 427 Vector best_point{};
428 float best_fov = 0.0f;
430 for (int ci = 0; ci < ncands && best_idx < 0; ci++) { 429 for (int ci = 0; ci < ncands && best_idx < 0; ci++) {
431 int idx = cands[ci].idx; 430 int idx = cands[ci].idx;
432 void *ent = entitylist_get(idx); 431 void *ent = entitylist_get(idx);
@@ -440,40 +439,55 @@ bool aimbot_apply(CUserCmd *cmd) {
440 float f = getfov(view, angle_to(g_cam_eye, pts[i])); 439 float f = getfov(view, angle_to(g_cam_eye, pts[i]));
441 if (f >= aim_fov) 440 if (f >= aim_fov)
442 continue; 441 continue;
443 if (aimbot_vischeck_enabled() && !is_visible(g_cam_eye, pts[i])) 442 if (vischeck && !is_visible(g_cam_eye, pts[i]))
444 continue; 443 continue;
445 aim_fov = f; 444 aim_fov = f;
446 aim_pt = pts[i]; 445 aim_pt = pts[i];
447 } 446 }
448 if (aim_fov <= MAX_FOV && aim_fov < 1e8f) { 447 if (aim_fov <= AIM_MAX_FOV && aim_fov < 1e8f) {
449 best_idx = idx; 448 best_idx = idx;
450 best_head = aim_pt; 449 best_point = aim_pt;
450 best_fov = aim_fov;
451 static int sel_logs = 0; 451 static int sel_logs = 0;
452 if (sel_logs < 5) { 452 if (sel_logs < 5) {
453 sel_logs++; 453 sel_logs++;
454 logf("aimbot: target idx=%d points=%d fov=%.2f vischeck=%d", idx, 454 logf("%s: target idx=%d points=%d fov=%.2f vischeck=%d", tag, idx,
455 npoints, aim_fov, (int)aimbot_vischeck_enabled()); 455 npoints, aim_fov, (int)vischeck);
456 } 456 }
457 } 457 }
458 } 458 }
459
460 if (best_idx < 0) { 459 if (best_idx < 0) {
461 static double last_vis = 0.0; 460 static double last_vis = 0.0;
462 double now = esp_now(); 461 double now = esp_now();
463 if (now - last_vis >= 2.0) { 462 if (now - last_vis >= 2.0) {
464 last_vis = now; 463 last_vis = now;
465 logf("aimbot: no visible aim point (vischeck=%d)", 464 logf("%s: no visible aim point (vischeck=%d)", tag, (int)vischeck);
466 (int)aimbot_vischeck_enabled());
467 } 465 }
468 return false; 466 return false;
469 } 467 }
468 out_idx = best_idx;
469 out_point = best_point;
470 out_fov = best_fov;
471 return true;
472}
470 473
471 QAngle desired = angle_to(g_cam_eye, best_head); 474bool aimbot_apply(CUserCmd *cmd) {
475 unsigned bone_mask = aimbot_bone_mask();
476 if (!bone_mask)
477 return false;
478 QAngle view{cmd->viewangles[0], cmd->viewangles[1], 0.0f};
479 int target = -1;
480 Vector point{};
481 float fov = 0.0f;
482 if (!select_aim_target(view, bone_mask, aimbot_vischeck_enabled(), "aimbot",
483 target, point, fov))
484 return false;
485 QAngle desired = angle_to(g_cam_eye, point);
472 static int want_logs = 0; 486 static int want_logs = 0;
473 if (want_logs < 10) { 487 if (want_logs < 10) {
474 want_logs++; 488 want_logs++;
475 logf("aimbot: aim=(%.1f %.1f %.1f) want=%.2f/%.2f", best_head.x, 489 logf("aimbot: target=%d aim=(%.1f %.1f %.1f) fov=%.2f want=%.2f/%.2f",
476 best_head.y, best_head.z, desired.x, desired.y); 490 target, point.x, point.y, point.z, fov, desired.x, desired.y);
477 } 491 }
478 float dp = desired.x - cmd->viewangles[0]; 492 float dp = desired.x - cmd->viewangles[0];
479 float dy = desired.y - cmd->viewangles[1]; 493 float dy = desired.y - cmd->viewangles[1];
@@ -499,15 +513,11 @@ bool aimbot_apply(CUserCmd *cmd) {
499 cmd->viewangles[0] = np; 513 cmd->viewangles[0] = np;
500 cmd->viewangles[1] = ny; 514 cmd->viewangles[1] = ny;
501 515
502 // cmd->viewangles drives usercmd/prediction, but the rendered camera can
503 // stay on the pre-hook angles. Also push the smoothed angles into the
504 // engine's view (IVEngineClient013 slot 20 = SetViewAngles).
505 if (g_iface.engine) { 516 if (g_iface.engine) {
506 QAngle out{np, ny, 0.0f}; 517 QAngle out{np, ny, 0.0f};
507 using SetViewFn = void (*)(void *, QAngle *); 518 using SetViewFn = void (*)(void *, QAngle *);
508 vfunc<SetViewFn>(g_iface.engine, 20)(g_iface.engine, &out); 519 vfunc<SetViewFn>(g_iface.engine, 20)(g_iface.engine, &out);
509 } 520 }
510
511 static int mod_logs = 0; 521 static int mod_logs = 0;
512 if (mod_logs < 10) { 522 if (mod_logs < 10) {
513 mod_logs++; 523 mod_logs++;
@@ -516,6 +526,46 @@ bool aimbot_apply(CUserCmd *cmd) {
516 return true; 526 return true;
517} 527}
518 528
529bool silent_aim_apply(CUserCmd *cmd) {
530 unsigned bone_mask = aimbot_bone_mask();
531 if (!bone_mask)
532 return false;
533 QAngle orig{g_cam_view.x, g_cam_view.y, g_cam_view.z};
534 QAngle view{orig.x, orig.y, 0.0f};
535 int target = -1;
536 Vector point{};
537 float fov = 0.0f;
538 if (!select_aim_target(view, bone_mask, true, "silentaim", target, point,
539 fov))
540 return false;
541 QAngle desired = angle_to(g_cam_eye, point);
542 float np = desired.x;
543 if (np > 89.0f) np = 89.0f;
544 if (np < -89.0f) np = -89.0f;
545 float ny = desired.y;
546 while (ny > 180.0f) ny -= 360.0f;
547 while (ny < -180.0f) ny += 360.0f;
548
549 cmd->viewangles[0] = np;
550 cmd->viewangles[1] = ny;
551 cmd->viewangles[2] = orig.z;
552
553 // The usercmd keeps the aim angles (shot/prediction); the rendered camera
554 // is restored to where the player was actually looking.
555 if (g_iface.engine) {
556 QAngle restore{orig.x, orig.y, orig.z};
557 using SetViewFn = void (*)(void *, QAngle *);
558 vfunc<SetViewFn>(g_iface.engine, 20)(g_iface.engine, &restore);
559 }
560 cmd->buttons |= IN_ATTACK;
561 static int logs = 0;
562 if (logs < 5) {
563 logs++;
564 logf("silentaim: fire idx=%d fov=%.2f aim=%.2f/%.2f", target, fov, np, ny);
565 }
566 return true;
567}
568
519bool triggerbot_apply(CUserCmd *cmd) { 569bool triggerbot_apply(CUserCmd *cmd) {
520 if (!g_iface.enginetrace || !g_iface.entitylist) 570 if (!g_iface.enginetrace || !g_iface.entitylist)
521 return false; 571 return false;