From 8af245ae414cb548a2188030ed8a52b31986252f Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 14 Sep 2026 16:47:32 +0200 Subject: Default map d1_town_01 (intro-less, enemies spawned) --- src/esp.cpp | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 src/esp.cpp (limited to 'src/esp.cpp') 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 @@ +// esp.cpp — ESP drawing + shared world_to_screen / entity gather (aimbot reuses these) +#include "hl2h.h" +#include +#include +#include + +static constexpr float PI_F = 3.14159265358979323846f; + +// ISurface slots (binary = SDK header + 4, disassembly-confirmed) +enum SurfSlot { + SURF_DrawSetColor = 10, SURF_FilledRect = 12, SURF_OutlinedRect = 14, + SURF_GetScreenSize = 38, +}; + +struct EspTarget { + float sx, sy; // screen pos of feet + float h; // box height px + float health, maxhealth; + int teamnum; + char name[48]; +}; +static EspTarget g_targets[128]; +static int g_ntargets = 0; +static int g_scr_w = 0, g_scr_h = 0; +static bool g_esp_logged = false; + +bool world_to_screen(const Vector &w, float &sx, float &sy) { + float pitch = g_cam_view.x * PI_F / 180.0f; + float yaw = g_cam_view.y * PI_F / 180.0f; + float sp = sinf(pitch), cp = cosf(pitch); + float syy = sinf(yaw), cy = cosf(yaw); + float fwd[3] = {cp * cy, cp * syy, -sp}; + float right[3] = {syy, -cy, 0}; + float up[3] = {sp * cy, sp * syy, cp}; + float dx = w.x - g_cam_eye.x, dy = w.y - g_cam_eye.y, dz = w.z - g_cam_eye.z; + float z = dx * fwd[0] + dy * fwd[1] + dz * fwd[2]; + if (z < 1.0f) return false; + float x = dx * right[0] + dy * right[1] + dz * right[2]; + float y = dx * up[0] + dy * up[1] + dz * up[2]; + float tanfov = tanf(75.0f * 0.5f * PI_F / 180.0f); + sx = (float)g_scr_w * 0.5f + (x / z) * ((float)g_scr_w * 0.5f / tanfov); + sy = (float)g_scr_h * 0.5f - (y / z) * ((float)g_scr_w * 0.5f / tanfov); + return true; +} + +static void esp_collect(int local_idx) { + g_ntargets = 0; + using Fn = int (*)(void *); + int maxent = vfunc(g_iface.entitylist, 5)(g_iface.entitylist); // GetHighestEntityIndex + if (maxent < 0 || maxent > 512) maxent = 512; + for (int idx = 0; idx <= maxent && g_ntargets < 128; idx++) { + if (idx == local_idx) continue; + void *ent = entitylist_get(idx); + if (!ent) continue; + uintptr_t e = (uintptr_t)ent; + float hpv = (float)*(int *)(e + g_net.health); // m_iHealth is int + if (!(hpv > 0)) continue; + Vector origin{*(float *)(e + g_net.origin), *(float *)(e + g_net.origin + 4), + *(float *)(e + g_net.origin + 8)}; + // ponytail: maxs netvar may be unresolved; fixed 72-unit torso fallback + float maxsz = g_net.maxs >= 0 ? *(float *)(e + g_net.maxs) : 72.0f; + Vector top{origin.x, origin.y, origin.z + maxsz}; + float sx, sy, tx, ty; + if (!world_to_screen(origin, sx, sy) || !world_to_screen(top, tx, ty)) + continue; + float h = sy - ty; + if (h < 4.0f || sy < 0 || ty > (float)g_scr_h) continue; // behind / offscreen + EspTarget &t = g_targets[g_ntargets++]; + t.sx = sx; t.sy = sy; t.h = h; + t.health = hpv; + t.maxhealth = (float)*(int *)(e + g_net.maxhealth); + if (t.maxhealth <= 0) t.maxhealth = hpv; + // classname via IClientNetworkable::GetClientClass (slot 2) -> m_pNetworkName @ +8 + using CCFn = void *(*)(void *); + void *cc = vfunc(ent, 2)(ent); + const char *nn = cc ? *(const char **)((uintptr_t)cc + 8) : nullptr; + strncpy(t.name, nn ? nn : "?", sizeof(t.name) - 1); + t.name[sizeof(t.name) - 1] = 0; + } +} + +static void surf_rect(int filled, int x0, int y0, int x1, int y1) { + using Fn = void (*)(void *, int, int, int, int); + vfunc(g_surface, filled ? SURF_FilledRect : SURF_OutlinedRect)(g_surface, x0, y0, x1, y1); +} +static void surf_color(int r, int g, int b, int a) { + using Fn = void (*)(void *, int, int, int, int); + vfunc(g_surface, SURF_DrawSetColor)(g_surface, r, g, b, a); +} + +void esp_draw() { + if (!g_surface || !g_iface.entitylist || !g_net.esp_ok()) return; + if (!g_scr_w) { + using Fn = void (*)(void *, int &, int &); + vfunc(g_surface, SURF_GetScreenSize)(g_surface, g_scr_w, g_scr_h); + logf("ESP: screen %dx%d", g_scr_w, g_scr_h); + if (!g_scr_w) return; + } + esp_collect(engine_get_local_player()); + if (g_ntargets && !g_esp_logged) { + g_esp_logged = true; + logf("ESP: first draw, %d targets", g_ntargets); + } + for (int i = 0; i < g_ntargets; i++) { + const EspTarget &t = g_targets[i]; + // team color: 3 combine red, 2 rebels green, else white + if (t.teamnum == 3) surf_color(255, 60, 60, 255); + else if (t.teamnum == 2) surf_color(60, 255, 60, 255); + else surf_color(255, 255, 255, 255); + float w = t.h * 0.45f; // ponytail: constant aspect, no OBB width — swap for m_vecMins/maxs span later + surf_rect(0, (int)(t.sx - w / 2), (int)(t.sy - t.h), (int)(t.sx + w / 2), (int)t.sy); + // health bar under box + float frac = t.health / t.maxhealth; + if (frac > 1) frac = 1; + surf_color(0, 0, 0, 200); + surf_rect(1, (int)(t.sx - w / 2), (int)t.sy + 1, (int)(t.sx + w / 2), (int)t.sy + 4); + if (frac > 0.5f) surf_color(40, 255, 40, 255); + else if (frac > 0.25f) surf_color(255, 255, 0, 255); + else surf_color(255, 40, 40, 255); + surf_rect(1, (int)(t.sx - w / 2), (int)t.sy + 2, + (int)(t.sx - w / 2 + w * frac), (int)t.sy + 3); + draw_text_col((int)(t.sx - w / 2), (int)(t.sy - t.h) - 14, t.name, 255, 255, 255); + } +} -- cgit v1.2.3