From ea163c157bd30e4c54fa917ffe0465f5a6d1c663 Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 26 Oct 2026 16:15:22 +0100 Subject: ESP: skeleton ESP - render parent->child bone links from the SetupBones world matrices (ISurface DrawLine, projected once per bone) - menu option "Show skeleton" under ESP, persisted as skeleton=1 - skeletons use the same hostile/friendly/neutral colours as the boxes --- src/esp.cpp | 38 +++++++++++++++++++++++++++++++++++++- src/hl2h.h | 3 ++- src/menu.cpp | 10 +++++++--- 3 files changed, 46 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/esp.cpp b/src/esp.cpp index 996a886..b75a7a9 100644 --- a/src/esp.cpp +++ b/src/esp.cpp @@ -11,7 +11,7 @@ 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, + SURF_DrawLine = 15, SURF_GetScreenSize = 38, }; enum { LIFE_ALIVE = 0 }; @@ -271,6 +271,37 @@ 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); } +static void surf_line(int x0, int y0, int x1, int y1) { + using Fn = void (*)(void *, int, int, int, int); + vfunc(g_surface, SURF_DrawLine)(g_surface, x0, y0, x1, y1); +} + +// Draw the parent->child bone links. Bone snapshots are world-space matrices +// from SetupBones; project each bone once and reuse for both endpoints. +static void draw_skeleton(const EspTarget &t) { + int n = bones_count(t.idx); + if (n <= 0 || n > 256) + return; + Vector wp[256]; + float xs[256], ys[256]; + bool ok[256]; + for (int i = 0; i < n; i++) { + ok[i] = bone_pos(t.idx, i, wp[i]) && + world_to_screen(wp[i], xs[i], ys[i]) && std::isfinite(xs[i]) && + std::isfinite(ys[i]); + } + if (t.friendly) + surf_color(60, 255, 60, 255); + else if (t.neutral) + surf_color(220, 220, 220, 255); + else + surf_color(255, 60, 60, 255); + for (int i = 0; i < n; i++) { + int p = bone_parent(t.idx, i); + if (p >= 0 && p < n && ok[i] && ok[p]) + surf_line((int)xs[p], (int)ys[p], (int)xs[i], (int)ys[i]); + } +} void esp_draw() { if (!g_surface || !g_iface.entitylist || !g_net.esp_ok()) return; @@ -285,6 +316,11 @@ void esp_draw() { const EspTarget &t = g_targets[i]; if (t.neutral && !esp_option(ESP_OPT_SHOW_NEUTRAL)) continue; + if (esp_option(ESP_OPT_SHOW_SKELETON)) { + void *ent = entitylist_get(t.idx); + if (ent && bones_update(t.idx, ent)) + draw_skeleton(t); + } if (t.friendly) surf_color(60, 255, 60, 255); else if (t.neutral) surf_color(220, 220, 220, 255); else surf_color(255, 60, 60, 255); diff --git a/src/hl2h.h b/src/hl2h.h index 68d5d55..1eaee10 100644 --- a/src/hl2h.h +++ b/src/hl2h.h @@ -141,7 +141,8 @@ enum EspOption { ESP_OPT_SHOW_HEALTHBAR = 1, ESP_OPT_SHOW_HEALTHNUM = 2, ESP_OPT_SHOW_NAME = 3, - ESP_OPT_COUNT = 4 + ESP_OPT_SHOW_SKELETON = 4, + ESP_OPT_COUNT = 5 }; // --------------------------------------------------------------------------- diff --git a/src/menu.cpp b/src/menu.cpp index 6244002..6474d69 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -59,7 +59,7 @@ static FeatureState g_esp{true, 0}; // ESP sub-options (menu "ESP" children). Defaults match the pre-option // behaviour: everything on. -static bool g_esp_opt[ESP_OPT_COUNT] = {true, true, true, true}; +static bool g_esp_opt[ESP_OPT_COUNT] = {true, true, true, true, true}; // tree static MenuNode g_root{NODE_ROOT, "HL2hake", false, 0, {}, nullptr, nullptr, nullptr}; @@ -75,6 +75,7 @@ static MenuNode g_esp_opt_nodes[ESP_OPT_COUNT] = { {NODE_TOGGLE, "Show healthbar", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_HEALTHBAR], nullptr, nullptr}, {NODE_TOGGLE, "Show healthnum", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_HEALTHNUM], nullptr, nullptr}, {NODE_TOGGLE, "Show name", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_NAME], nullptr, nullptr}, + {NODE_TOGGLE, "Show skeleton", false, 0, {}, &g_esp_opt[ESP_OPT_SHOW_SKELETON], nullptr, nullptr}, }; static MenuNode *g_visible[32]; // flattened visible nodes for arrow navigation @@ -159,10 +160,11 @@ static void config_save() { g_bhop.bind, g_bhop_autostrafe); fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n" - "healthnum=%d\nname=%d\n", + "healthnum=%d\nname=%d\nskeleton=%d\n", g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL], g_esp_opt[ESP_OPT_SHOW_HEALTHBAR], - g_esp_opt[ESP_OPT_SHOW_HEALTHNUM], g_esp_opt[ESP_OPT_SHOW_NAME]); + g_esp_opt[ESP_OPT_SHOW_HEALTHNUM], g_esp_opt[ESP_OPT_SHOW_NAME], + g_esp_opt[ESP_OPT_SHOW_SKELETON]); fclose(f); } @@ -204,6 +206,8 @@ static void config_load() { g_esp_opt[ESP_OPT_SHOW_HEALTHNUM] = atoi(val) != 0; else if (strcmp(key, "name") == 0) g_esp_opt[ESP_OPT_SHOW_NAME] = atoi(val) != 0; + else if (strcmp(key, "skeleton") == 0) + g_esp_opt[ESP_OPT_SHOW_SKELETON] = atoi(val) != 0; } if (strcmp(key, "active") == 0) cur->active = atoi(val) != 0; -- cgit v1.2.3