// 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); } }