1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
// esp.cpp — ESP drawing + shared world_to_screen / entity gather (aimbot reuses these)
#include "hl2h.h"
#include <cmath>
#include <cstring>
#include <cstddef>
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<Fn>(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<CCFn>(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<Fn>(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<Fn>(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<Fn>(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);
}
}
|