diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-26 16:39:11 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-26 16:39:11 +0100 |
| commit | ccdcd4ad0483b98c9c20bd1304ad062ef8af3a4b (patch) | |
| tree | 5a766a3b72ac442a4e7f1537afb07b6cb09e90bd /src/esp.cpp | |
| parent | ESP: generic full-bone skeleton for non-humanoid NPCs (headcrabs, crows, ...) (diff) | |
| download | hl2h-ccdcd4ad0483b98c9c20bd1304ad062ef8af3a4b.tar.gz hl2h-ccdcd4ad0483b98c9c20bd1304ad062ef8af3a4b.zip | |
Aimbot: head-only nearest-to-crosshair with bounded smoothing
- select the hostile NPC whose (approximate) head is closest in angle to the
crosshair, then refine to its actual head hitbox/bone
- aimbot menu feature (Active + Bind, default Mouse5, rebindable via the
existing bind chooser); config [aimbot] active/bind
- never snap: move at most 5 degrees per tick toward the target, shortest-path
yaw, pitch clamped to +/-89, 0.05 degree deadzone; no overshoot/oscillation
- fixes the usercmd CRC after modifying viewangles
- skip when dead; ignores friendly/neutral entities (crows, citizens, ...)
Diffstat (limited to 'src/esp.cpp')
| -rw-r--r-- | src/esp.cpp | 117 |
1 files changed, 117 insertions, 0 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) { |
