diff options
| author | salmonik <salmonik@tuta.io> | 2026-09-14 16:47:32 +0200 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-09-14 16:47:32 +0200 |
| commit | 8af245ae414cb548a2188030ed8a52b31986252f (patch) | |
| tree | 0c77362c60b3441ddbb9d4da80944e667f24a927 /src/esp.cpp | |
| parent | Remove Climb feature; keep bind system for aimbot prep (mouse buttons bindable) (diff) | |
| download | hl2h-8af245ae414cb548a2188030ed8a52b31986252f.tar.gz hl2h-8af245ae414cb548a2188030ed8a52b31986252f.zip | |
Default map d1_town_01 (intro-less, enemies spawned)
Diffstat (limited to 'src/esp.cpp')
| -rw-r--r-- | src/esp.cpp | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/esp.cpp b/src/esp.cpp new file mode 100644 index 0000000..87d0b80 --- /dev/null +++ b/src/esp.cpp | |||
| @@ -0,0 +1,124 @@ | |||
| 1 | // esp.cpp — ESP drawing + shared world_to_screen / entity gather (aimbot reuses these) | ||
| 2 | #include "hl2h.h" | ||
| 3 | #include <cmath> | ||
| 4 | #include <cstring> | ||
| 5 | #include <cstddef> | ||
| 6 | |||
| 7 | static constexpr float PI_F = 3.14159265358979323846f; | ||
| 8 | |||
| 9 | // ISurface slots (binary = SDK header + 4, disassembly-confirmed) | ||
| 10 | enum SurfSlot { | ||
| 11 | SURF_DrawSetColor = 10, SURF_FilledRect = 12, SURF_OutlinedRect = 14, | ||
| 12 | SURF_GetScreenSize = 38, | ||
| 13 | }; | ||
| 14 | |||
| 15 | struct EspTarget { | ||
| 16 | float sx, sy; // screen pos of feet | ||
| 17 | float h; // box height px | ||
| 18 | float health, maxhealth; | ||
| 19 | int teamnum; | ||
| 20 | char name[48]; | ||
| 21 | }; | ||
| 22 | static EspTarget g_targets[128]; | ||
| 23 | static int g_ntargets = 0; | ||
| 24 | static int g_scr_w = 0, g_scr_h = 0; | ||
| 25 | static bool g_esp_logged = false; | ||
| 26 | |||
| 27 | bool world_to_screen(const Vector &w, float &sx, float &sy) { | ||
| 28 | float pitch = g_cam_view.x * PI_F / 180.0f; | ||
| 29 | float yaw = g_cam_view.y * PI_F / 180.0f; | ||
| 30 | float sp = sinf(pitch), cp = cosf(pitch); | ||
| 31 | float syy = sinf(yaw), cy = cosf(yaw); | ||
| 32 | float fwd[3] = {cp * cy, cp * syy, -sp}; | ||
| 33 | float right[3] = {syy, -cy, 0}; | ||
| 34 | float up[3] = {sp * cy, sp * syy, cp}; | ||
| 35 | float dx = w.x - g_cam_eye.x, dy = w.y - g_cam_eye.y, dz = w.z - g_cam_eye.z; | ||
| 36 | float z = dx * fwd[0] + dy * fwd[1] + dz * fwd[2]; | ||
| 37 | if (z < 1.0f) return false; | ||
| 38 | float x = dx * right[0] + dy * right[1] + dz * right[2]; | ||
| 39 | float y = dx * up[0] + dy * up[1] + dz * up[2]; | ||
| 40 | float tanfov = tanf(75.0f * 0.5f * PI_F / 180.0f); | ||
| 41 | sx = (float)g_scr_w * 0.5f + (x / z) * ((float)g_scr_w * 0.5f / tanfov); | ||
| 42 | sy = (float)g_scr_h * 0.5f - (y / z) * ((float)g_scr_w * 0.5f / tanfov); | ||
| 43 | return true; | ||
| 44 | } | ||
| 45 | |||
| 46 | static void esp_collect(int local_idx) { | ||
| 47 | g_ntargets = 0; | ||
| 48 | using Fn = int (*)(void *); | ||
| 49 | int maxent = vfunc<Fn>(g_iface.entitylist, 5)(g_iface.entitylist); // GetHighestEntityIndex | ||
| 50 | if (maxent < 0 || maxent > 512) maxent = 512; | ||
| 51 | for (int idx = 0; idx <= maxent && g_ntargets < 128; idx++) { | ||
| 52 | if (idx == local_idx) continue; | ||
| 53 | void *ent = entitylist_get(idx); | ||
| 54 | if (!ent) continue; | ||
| 55 | uintptr_t e = (uintptr_t)ent; | ||
| 56 | float hpv = (float)*(int *)(e + g_net.health); // m_iHealth is int | ||
| 57 | if (!(hpv > 0)) continue; | ||
| 58 | Vector origin{*(float *)(e + g_net.origin), *(float *)(e + g_net.origin + 4), | ||
| 59 | *(float *)(e + g_net.origin + 8)}; | ||
| 60 | // ponytail: maxs netvar may be unresolved; fixed 72-unit torso fallback | ||
| 61 | float maxsz = g_net.maxs >= 0 ? *(float *)(e + g_net.maxs) : 72.0f; | ||
| 62 | Vector top{origin.x, origin.y, origin.z + maxsz}; | ||
| 63 | float sx, sy, tx, ty; | ||
| 64 | if (!world_to_screen(origin, sx, sy) || !world_to_screen(top, tx, ty)) | ||
| 65 | continue; | ||
| 66 | float h = sy - ty; | ||
| 67 | if (h < 4.0f || sy < 0 || ty > (float)g_scr_h) continue; // behind / offscreen | ||
| 68 | EspTarget &t = g_targets[g_ntargets++]; | ||
| 69 | t.sx = sx; t.sy = sy; t.h = h; | ||
| 70 | t.health = hpv; | ||
| 71 | t.maxhealth = (float)*(int *)(e + g_net.maxhealth); | ||
| 72 | if (t.maxhealth <= 0) t.maxhealth = hpv; | ||
| 73 | // classname via IClientNetworkable::GetClientClass (slot 2) -> m_pNetworkName @ +8 | ||
| 74 | using CCFn = void *(*)(void *); | ||
| 75 | void *cc = vfunc<CCFn>(ent, 2)(ent); | ||
| 76 | const char *nn = cc ? *(const char **)((uintptr_t)cc + 8) : nullptr; | ||
| 77 | strncpy(t.name, nn ? nn : "?", sizeof(t.name) - 1); | ||
| 78 | t.name[sizeof(t.name) - 1] = 0; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | static void surf_rect(int filled, int x0, int y0, int x1, int y1) { | ||
| 83 | using Fn = void (*)(void *, int, int, int, int); | ||
| 84 | vfunc<Fn>(g_surface, filled ? SURF_FilledRect : SURF_OutlinedRect)(g_surface, x0, y0, x1, y1); | ||
| 85 | } | ||
| 86 | static void surf_color(int r, int g, int b, int a) { | ||
| 87 | using Fn = void (*)(void *, int, int, int, int); | ||
| 88 | vfunc<Fn>(g_surface, SURF_DrawSetColor)(g_surface, r, g, b, a); | ||
| 89 | } | ||
| 90 | |||
| 91 | void esp_draw() { | ||
| 92 | if (!g_surface || !g_iface.entitylist || !g_net.esp_ok()) return; | ||
| 93 | if (!g_scr_w) { | ||
| 94 | using Fn = void (*)(void *, int &, int &); | ||
| 95 | vfunc<Fn>(g_surface, SURF_GetScreenSize)(g_surface, g_scr_w, g_scr_h); | ||
| 96 | logf("ESP: screen %dx%d", g_scr_w, g_scr_h); | ||
| 97 | if (!g_scr_w) return; | ||
| 98 | } | ||
| 99 | esp_collect(engine_get_local_player()); | ||
| 100 | if (g_ntargets && !g_esp_logged) { | ||
| 101 | g_esp_logged = true; | ||
| 102 | logf("ESP: first draw, %d targets", g_ntargets); | ||
| 103 | } | ||
| 104 | for (int i = 0; i < g_ntargets; i++) { | ||
| 105 | const EspTarget &t = g_targets[i]; | ||
| 106 | // team color: 3 combine red, 2 rebels green, else white | ||
| 107 | if (t.teamnum == 3) surf_color(255, 60, 60, 255); | ||
| 108 | else if (t.teamnum == 2) surf_color(60, 255, 60, 255); | ||
| 109 | else surf_color(255, 255, 255, 255); | ||
| 110 | float w = t.h * 0.45f; // ponytail: constant aspect, no OBB width — swap for m_vecMins/maxs span later | ||
| 111 | surf_rect(0, (int)(t.sx - w / 2), (int)(t.sy - t.h), (int)(t.sx + w / 2), (int)t.sy); | ||
| 112 | // health bar under box | ||
| 113 | float frac = t.health / t.maxhealth; | ||
| 114 | if (frac > 1) frac = 1; | ||
| 115 | surf_color(0, 0, 0, 200); | ||
| 116 | surf_rect(1, (int)(t.sx - w / 2), (int)t.sy + 1, (int)(t.sx + w / 2), (int)t.sy + 4); | ||
| 117 | if (frac > 0.5f) surf_color(40, 255, 40, 255); | ||
| 118 | else if (frac > 0.25f) surf_color(255, 255, 0, 255); | ||
| 119 | else surf_color(255, 40, 40, 255); | ||
| 120 | surf_rect(1, (int)(t.sx - w / 2), (int)t.sy + 2, | ||
| 121 | (int)(t.sx - w / 2 + w * frac), (int)t.sy + 3); | ||
| 122 | draw_text_col((int)(t.sx - w / 2), (int)(t.sy - t.h) - 14, t.name, 255, 255, 255); | ||
| 123 | } | ||
| 124 | } | ||
