summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/esp.cpp318
-rw-r--r--src/gui.cpp32
-rw-r--r--src/hl2h.cpp93
-rw-r--r--src/hl2h.h24
-rw-r--r--src/menu.cpp84
-rw-r--r--src/netvars.cpp5
6 files changed, 328 insertions, 228 deletions
diff --git a/src/esp.cpp b/src/esp.cpp
index ca7bae0..d10a2cf 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -1132,71 +1132,6 @@ static void spread_compute() {
1132 g_spread_ready = true; 1132 g_spread_ready = true;
1133} 1133}
1134 1134
1135static bool icontains(const char *hay, const char *needle) {
1136 if (!hay || !needle || !*needle)
1137 return false;
1138 size_t n = strlen(needle);
1139 for (const char *p = hay; *p; p++)
1140 if (strncasecmp(p, needle, n) == 0)
1141 return true;
1142 return false;
1143}
1144
1145bool entity_is_physics_prop(int idx) {
1146 if (idx <= 0 || idx > 4096)
1147 return false;
1148 void *ent = entitylist_get(idx);
1149 if (!ent)
1150 return false;
1151 int mt = -1;
1152 // The reliable signal: physics objects use MOVETYPE_VPHYSICS. The client
1153 // class is CPhysicsProp / CPhysBox, not the server's prop_physics name.
1154 if (g_net.movetype >= 0) {
1155 mt = *(int *)((uintptr_t)ent + g_net.movetype);
1156 if (mt == MOVETYPE_VPHYSICS)
1157 return true;
1158 }
1159 void *net = entity_networkable(idx);
1160 const char *cls = net ? entity_class_name(net, nullptr) : nullptr;
1161 const char *model = entity_model_name(ent);
1162 bool is_prop = icontains(cls, "physicsprop") || icontains(cls, "physbox") ||
1163 icontains(cls, "prop_physics") ||
1164 icontains(model, "props_junk") ||
1165 icontains(model, "props_physics") ||
1166 icontains(model, "props_c17") ||
1167 icontains(model, "props_interiors") ||
1168 icontains(model, "props_lab");
1169 if (!is_prop) {
1170 static int miss_logs = 0;
1171 if (miss_logs < 6) {
1172 miss_logs++;
1173 logf("stucklaunch prop? idx=%d movetype=%d cls=%s model=%s", idx, mt,
1174 cls ? cls : "?", model ? model : "?");
1175 }
1176 }
1177 return is_prop;
1178}
1179
1180bool active_weapon_is_gravity_gun(void *local_ent) {
1181 if (!local_ent || g_net.activeweapon < 0)
1182 return false;
1183 uint32_t h = *(uint32_t *)((uintptr_t)local_ent + g_net.activeweapon);
1184 if (h == 0xFFFFFFFFu)
1185 return false;
1186 int idx = (int)(h & 0xFFFF);
1187 if (idx <= 0 || idx > 4096)
1188 return false;
1189 void *wep = entitylist_get(idx);
1190 void *net = entity_networkable(idx);
1191 const char *cls = net ? entity_class_name(net, nullptr) : nullptr;
1192 const char *model = wep ? entity_model_name(wep) : nullptr;
1193 if (cls && strstr(cls, "physcannon"))
1194 return true;
1195 if (model && (strstr(model, "physcannon") || strstr(model, "w_physics")))
1196 return true;
1197 return false;
1198}
1199
1200static bool active_weapon_is_shotgun(void *local_ent) { 1135static bool active_weapon_is_shotgun(void *local_ent) {
1201 if (!local_ent || g_net.activeweapon < 0) 1136 if (!local_ent || g_net.activeweapon < 0)
1202 return false; 1137 return false;
@@ -1402,3 +1337,256 @@ void esp_draw() {
1402 1337
1403 draw_speed_graph(); 1338 draw_speed_graph();
1404} 1339}
1340
1341
1342// ---------------------------------------------------------------------------
1343// Valuable item tags
1344// ---------------------------------------------------------------------------
1345
1346enum ItemKind { IK_HEALTH, IK_AMMO, IK_ARMOR, IK_CRATE, IK_OTHER };
1347
1348struct ItemTarget {
1349 int idx;
1350 int kind;
1351 Vector origin;
1352 char label[48];
1353};
1354
1355static ItemTarget g_item_targets[192];
1356static int g_nitems = 0;
1357static bool g_items_logged = false;
1358
1359static bool item_icontains(const char *hay, const char *needle) {
1360 if (!hay || !needle || !*needle)
1361 return false;
1362 size_t n = strlen(needle);
1363 for (const char *p = hay; *p; p++)
1364 if (strncasecmp(p, needle, n) == 0)
1365 return true;
1366 return false;
1367}
1368
1369static int classify_item(const char *model, const char *cls, char *label,
1370 size_t outn) {
1371 if (!model && !cls)
1372 return -1;
1373
1374 if (item_icontains(model, "healthkit")) {
1375 snprintf(label, outn, "Medkit");
1376 return IK_HEALTH;
1377 }
1378 if (item_icontains(model, "healthvial")) {
1379 snprintf(label, outn, "Health vial");
1380 return IK_HEALTH;
1381 }
1382 if (item_icontains(model, "health_charger")) {
1383 snprintf(label, outn, "Health charger");
1384 return IK_HEALTH;
1385 }
1386 if (item_icontains(model, "battery")) {
1387 snprintf(label, outn, "Battery");
1388 return IK_ARMOR;
1389 }
1390 if (item_icontains(model, "hevsuit")) {
1391 snprintf(label, outn, "HEV suit");
1392 return IK_ARMOR;
1393 }
1394 if (item_icontains(model, "w_longjump")) {
1395 snprintf(label, outn, "Long jump");
1396 return IK_ARMOR;
1397 }
1398 if (item_icontains(model, "suit_charger")) {
1399 snprintf(label, outn, "Suit charger");
1400 return IK_ARMOR;
1401 }
1402 if (item_icontains(model, "item_item_crate") ||
1403 item_icontains(model, "item_beacon_crate")) {
1404 snprintf(label, outn, "Supply crate");
1405 return IK_CRATE;
1406 }
1407 if (item_icontains(model, "ammocrate")) {
1408 snprintf(label, outn, "Ammo crate");
1409 return IK_AMMO;
1410 }
1411 if (item_icontains(model, "w_missile_closed")) {
1412 snprintf(label, outn, "RPG ammo");
1413 return IK_AMMO;
1414 }
1415 if (item_icontains(model, "models/items/")) {
1416 if (item_icontains(model, "crossbowrounds"))
1417 snprintf(label, outn, "Crossbow bolts");
1418 else if (item_icontains(model, "ar2_grenade"))
1419 snprintf(label, outn, "AR2 grenade");
1420 else if (item_icontains(model, "357ammo"))
1421 snprintf(label, outn, "357 ammo");
1422 else if (item_icontains(model, "boxbuckshot"))
1423 snprintf(label, outn, "Buckshot");
1424 else if (item_icontains(model, "boxsniperrounds"))
1425 snprintf(label, outn, "Sniper ammo");
1426 else
1427 snprintf(label, outn, "Ammo");
1428 return IK_AMMO;
1429 }
1430
1431 if (item_icontains(cls, "healthkit") || item_icontains(cls, "healthvial") ||
1432 item_icontains(cls, "wallhealth")) {
1433 snprintf(label, outn, "Health");
1434 return IK_HEALTH;
1435 }
1436 if (item_icontains(cls, "battery") || item_icontains(cls, "itemsuit") ||
1437 item_icontains(cls, "recharge")) {
1438 snprintf(label, outn, "Armor");
1439 return IK_ARMOR;
1440 }
1441 if (item_icontains(cls, "itemcrate") ||
1442 item_icontains(cls, "dynamicresupply")) {
1443 snprintf(label, outn, "Supply crate");
1444 return IK_CRATE;
1445 }
1446 if (item_icontains(cls, "item_ammo") || item_icontains(cls, "itemammo")) {
1447 snprintf(label, outn, "Ammo");
1448 return IK_AMMO;
1449 }
1450 if (item_icontains(cls, "item") || item_icontains(cls, "pickup")) {
1451 snprintf(label, outn, "Item");
1452 return IK_OTHER;
1453 }
1454 return -1;
1455}
1456
1457static bool item_kind_enabled(int kind) {
1458 switch (kind) {
1459 case IK_HEALTH: return g_item_health;
1460 case IK_AMMO: return g_item_ammo;
1461 case IK_ARMOR: return g_item_armor;
1462 case IK_CRATE: return g_item_crates;
1463 default: return true;
1464 }
1465}
1466
1467static void items_collect(int local_idx) {
1468 static double last_scan = 0.0;
1469 double now = esp_now();
1470 if (now - last_scan < 0.10)
1471 return;
1472 last_scan = now;
1473 g_nitems = 0;
1474 if (!g_iface.entitylist || g_net.origin < 0 || g_net.modelindex < 0)
1475 return;
1476
1477 using Fn = int (*)(void *);
1478 int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist);
1479 if (hi < 0 || hi > 4096)
1480 hi = 4096;
1481
1482 static int dbg_lines = 0;
1483 for (int idx = 1; idx <= hi && g_nitems < 192; idx++) {
1484 if (idx == local_idx)
1485 continue;
1486 void *ent = entitylist_get(idx);
1487 if (!ent)
1488 continue;
1489 void *net = entity_networkable(idx);
1490 if (!net)
1491 continue;
1492 const char *cls = entity_class_name(net, nullptr);
1493 const char *model = entity_model_name(ent);
1494 char label[48];
1495 int kind = classify_item(model, cls, label, sizeof(label));
1496 if (kind < 0)
1497 continue;
1498
1499 Vector origin{*(float *)((uintptr_t)ent + g_net.origin),
1500 *(float *)((uintptr_t)ent + g_net.origin + 4),
1501 *(float *)((uintptr_t)ent + g_net.origin + 8)};
1502 float dx = origin.x - g_cam_eye.x;
1503 float dy = origin.y - g_cam_eye.y;
1504 float dz = origin.z - g_cam_eye.z;
1505 float dist = sqrtf(dx * dx + dy * dy + dz * dz);
1506 if (g_item_max_dist > 0 && dist > (float)g_item_max_dist)
1507 continue;
1508
1509 ItemTarget &t = g_item_targets[g_nitems++];
1510 t.idx = idx;
1511 t.kind = kind;
1512 t.origin = origin;
1513 snprintf(t.label, sizeof(t.label), "%s", label);
1514 if (dbg_lines < 8) {
1515 dbg_lines++;
1516 logf("item: idx=%d kind=%d cls=%s model=%s", idx, kind,
1517 cls ? cls : "?", model ? model : "?");
1518 }
1519 }
1520
1521 if (!g_items_logged) {
1522 g_items_logged = true;
1523 logf("items: tagging %d valuable entities", g_nitems);
1524 }
1525}
1526
1527void esp_draw_items() {
1528 if (!g_surface || !g_iface.entitylist || g_net.origin < 0)
1529 return;
1530 if (!g_item_health && !g_item_ammo && !g_item_armor && !g_item_crates)
1531 return;
1532 int local = engine_get_local_player();
1533 if (local <= 0)
1534 return;
1535 if (!g_scr_w) {
1536 using Fn = void (*)(void *, int &, int &);
1537 vfunc<Fn>(g_surface, SURF_GetScreenSize)(g_surface, g_scr_w, g_scr_h);
1538 if (!g_scr_w)
1539 return;
1540 }
1541 items_collect(local);
1542
1543 for (int i = 0; i < g_nitems; i++) {
1544 const ItemTarget &t = g_item_targets[i];
1545 if (!item_kind_enabled(t.kind))
1546 continue;
1547 float sx, sy;
1548 if (!world_to_screen(t.origin, sx, sy))
1549 continue;
1550 if (sx < -40 || sx > (float)g_scr_w + 40 || sy < -20 ||
1551 sy > (float)g_scr_h + 20)
1552 continue;
1553
1554 int r = 230, g = 230, b = 230;
1555 switch (t.kind) {
1556 case IK_HEALTH: r = 90; g = 255; b = 130; break;
1557 case IK_AMMO: r = 255; g = 210; b = 80; break;
1558 case IK_ARMOR: r = 90; g = 180; b = 255; break;
1559 case IK_CRATE: r = 220; g = 150; b = 255; break;
1560 default: break;
1561 }
1562 int x = (int)sx, y = (int)sy;
1563 surf_color(r, g, b, 255);
1564 surf_rect(0, x - 4, y - 4, x + 4, y + 4);
1565 surf_line(x - 8, y, x - 5, y);
1566 surf_line(x + 5, y, x + 8, y);
1567 surf_line(x, y - 8, x, y - 5);
1568 surf_line(x, y + 5, x, y + 8);
1569
1570 float dx = t.origin.x - g_cam_eye.x;
1571 float dy = t.origin.y - g_cam_eye.y;
1572 float dz = t.origin.z - g_cam_eye.z;
1573 int dist = (int)sqrtf(dx * dx + dy * dy + dz * dz);
1574 char text[96];
1575 if (g_item_distance)
1576 snprintf(text, sizeof(text), "%s %du", t.label, dist);
1577 else
1578 snprintf(text, sizeof(text), "%s", t.label);
1579 int tw = (int)strlen(text) * 9;
1580 int tx = x + 10;
1581 if (tx + tw > g_scr_w - 4)
1582 tx = x - 10 - tw;
1583 if (tx < 4)
1584 tx = 4;
1585 int ty = y - 7;
1586 if (ty < 0)
1587 ty = 0;
1588 if (ty + 16 > g_scr_h)
1589 ty = g_scr_h - 16;
1590 draw_text_col(tx, ty, text, r, g, b);
1591 }
1592}
diff --git a/src/gui.cpp b/src/gui.cpp
index 156e496..eb9a964 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -299,21 +299,6 @@ static void build_cards() {
299 add_card(0, &g_abh, "ABH", "Accelerate on the jump tick by facing away " 299 add_card(0, &g_abh, "ABH", "Accelerate on the jump tick by facing away "
300 "from the velocity.", true); 300 "from the velocity.", true);
301 301
302 int sl = add_card(0, &g_stucklaunch, "Stucklaunch",
303 "Hop on a physics prop while spamming grab to build "
304 "speed in a small space.",
305 true);
306 add_toggle(sl, "Use spam",
307 "Rapidly press +use to keep regrabbing the prop.",
308 &g_stucklaunch_use_spam);
309 add_toggle(sl, "Gravity gun spam",
310 "Alternate +attack and +use while holding the gravity gun.",
311 &g_stucklaunch_gravspam);
312 add_toggle(sl, "Auto-strafe", "Air-strafe each hop.",
313 &g_stucklaunch_autostrafe);
314 add_slider(sl, "Spam rate", "Ticks between spam toggles; higher is slower.",
315 1, 16, &g_stucklaunch_spam_ticks);
316
317 int jb = add_card(0, &g_jumpbug, "Jumpbug", 302 int jb = add_card(0, &g_jumpbug, "Jumpbug",
318 "Duck+jump when landing would hurt.", true); 303 "Duck+jump when landing would hurt.", true);
319 add_toggle(jb, "Assist timing", 304 add_toggle(jb, "Assist timing",
@@ -364,6 +349,23 @@ static void build_cards() {
364 for (int i = 0; i < ESP_OPT_COUNT; i++) 349 for (int i = 0; i < ESP_OPT_COUNT; i++)
365 add_toggle(esp, esp_names[i], esp_descs[i], &g_esp_opt[i]); 350 add_toggle(esp, esp_names[i], esp_descs[i], &g_esp_opt[i]);
366 351
352 int items = add_card(2, &g_item_esp, "Valuable items",
353 "Tag medkits, ammo, armor and supply crates.", true);
354 add_toggle(items, "Medkits / health",
355 "Tag health kits, health vials and health chargers.",
356 &g_item_health);
357 add_toggle(items, "Ammo", "Tag ammo boxes, crates and grenades.",
358 &g_item_ammo);
359 add_toggle(items, "Armor / suit", "Tag batteries, HEV suits and chargers.",
360 &g_item_armor);
361 add_toggle(items, "Supply crates", "Tag item and beacon crates.",
362 &g_item_crates);
363 add_toggle(items, "Show distance", "Append the distance in units.",
364 &g_item_distance);
365 add_slider(items, "Max distance",
366 "Items farther away than this are not tagged.", 250, 5000,
367 &g_item_max_dist);
368
367 int spread = add_card(3, &g_spread, "Spread control", 369 int spread = add_card(3, &g_spread, "Spread control",
368 "Choose a server shot seed that tightens the cone.", 370 "Choose a server shot seed that tightens the cone.",
369 true); 371 true);
diff --git a/src/hl2h.cpp b/src/hl2h.cpp
index defdd27..c51d35e 100644
--- a/src/hl2h.cpp
+++ b/src/hl2h.cpp
@@ -169,75 +169,6 @@ static void apply_autostrafe(CUserCmd *cmd, const float *vel) {
169 cmd->sidemove = (dx * rx + dy * ry) * 450.0f; 169 cmd->sidemove = (dx * rx + dy * ry) * 450.0f;
170} 170}
171 171
172// True while the player stands on (or just left) a physics prop. m_hGroundEntity
173// is latched briefly because it clears during each hop.
174static bool stucklaunch_prop_ok(void *ent, int tick) {
175 if (g_net.groundentity < 0) {
176 static bool logged = false;
177 if (!logged) {
178 logged = true;
179 logf("stucklaunch: m_hGroundEntity unavailable; prop detection off");
180 }
181 return true; // no netvar: the bind is the only safeguard
182 }
183 static int last_prop_tick = -100000;
184 uint32_t h = *(uint32_t *)((uintptr_t)ent + g_net.groundentity);
185 int gi = (h == 0xFFFFFFFFu) ? 0 : (int)(h & 0xFFFF);
186 bool on = gi > 0 && gi <= 4096 && entity_is_physics_prop(gi);
187 if (on) {
188 static int prop_logs = 0;
189 if (prop_logs < 4) {
190 prop_logs++;
191 logf("stucklaunch: prop idx=%d engaged", gi);
192 }
193 last_prop_tick = tick;
194 } else {
195 static int miss_logs = 0;
196 if (miss_logs < 4) {
197 miss_logs++;
198 logf("stucklaunch: ground h=%#x idx=%d is not a physics prop", h, gi);
199 }
200 }
201 return tick - last_prop_tick < 32; // ~0.5 s at 66 tick
202}
203
204// Stucklaunch assist. The player supplies the physics prop and a little
205// initial speed; this holds jump, alternates +use (and optionally the gravity
206// gun's +attack) to keep regrabbing the prop, and air-strafes the hops.
207static void stucklaunch_apply(CUserCmd *cmd, void *local_ent, bool onground,
208 const float *vel) {
209 static bool engaged_logged = false;
210 if (!engaged_logged) {
211 engaged_logged = true;
212 logf("stucklaunch: applying jump/spam (onground=%d)", (int)onground);
213 }
214 cmd->buttons |= IN_JUMP;
215 int period = stucklaunch_spam_ticks();
216 if (period < 1)
217 period = 1;
218 int phase = (cmd->tick_count / period) & 1;
219 bool gravity = stucklaunch_gravspam_enabled() &&
220 active_weapon_is_gravity_gun(local_ent);
221 if (gravity) {
222 // Pick up with +attack, drop with +use on the next half-cycle. Pressing
223 // both together would punt instead of regrabbing.
224 if (phase == 0) {
225 cmd->buttons |= IN_ATTACK;
226 cmd->buttons &= ~IN_USE;
227 } else {
228 cmd->buttons |= IN_USE;
229 cmd->buttons &= ~IN_ATTACK;
230 }
231 } else if (stucklaunch_use_spam_enabled()) {
232 if (phase == 0)
233 cmd->buttons |= IN_USE;
234 else
235 cmd->buttons &= ~IN_USE;
236 }
237 if (stucklaunch_autostrafe_enabled() && !onground)
238 apply_autostrafe(cmd, vel);
239}
240
241// --------------------------------------------------------------------------- 172// ---------------------------------------------------------------------------
242// jumpbug 173// jumpbug
243// --------------------------------------------------------------------------- 174// ---------------------------------------------------------------------------
@@ -645,23 +576,8 @@ static void do_move(int seq, float frametime) {
645 return; 576 return;
646 } 577 }
647 578
648 bool stuck_on = feature_active(FEAT_STUCKLAUNCH); 579 bool bhop_on = feature_active(FEAT_BHOP);
649 if (g_stucklaunch.active) { 580 bool abh_on = feature_active(FEAT_ABH);
650 static bool state_logged = false;
651 if (!state_logged) {
652 state_logged = true;
653 logf("stucklaunch: active=1 run=%d bind=%d groundoff=%d",
654 (int)stuck_on, g_stucklaunch.bind, g_net.groundentity);
655 }
656 }
657 bool stuck_engaged = stuck_on && stucklaunch_prop_ok(ent, cmd->tick_count);
658 if (stuck_engaged) {
659 stucklaunch_apply(cmd, ent, onground, vel);
660 note_modified(cmd, flags, vel);
661 }
662
663 bool bhop_on = !stuck_engaged && feature_active(FEAT_BHOP);
664 bool abh_on = !stuck_engaged && feature_active(FEAT_ABH);
665 581
666 static bool lastground = false; 582 static bool lastground = false;
667 583
@@ -712,8 +628,7 @@ static void do_move(int seq, float frametime) {
712 } 628 }
713 } 629 }
714 630
715 if (!stuck_engaged && 631 if (jumpbug_apply(cmd, localIdx, ent, flags, vel, frametime))
716 jumpbug_apply(cmd, localIdx, ent, flags, vel, frametime))
717 note_modified(cmd, flags, vel); 632 note_modified(cmd, flags, vel);
718 633
719 bool melee = feature_active(FEAT_MELEE) && melee_weapon_active(ent); 634 bool melee = feature_active(FEAT_MELEE) && melee_weapon_active(ent);
@@ -951,8 +866,6 @@ static void *setup_thread(void *) {
951 toastf(TOAST_ERROR, "Netvars incomplete; features may be disabled"); 866 toastf(TOAST_ERROR, "Netvars incomplete; features may be disabled");
952 else if (g_net.absvelocity < 0) 867 else if (g_net.absvelocity < 0)
953 toastf(TOAST_WARN, "Jumpbug assist disabled: velocity netvar missing"); 868 toastf(TOAST_WARN, "Jumpbug assist disabled: velocity netvar missing");
954 if (g_net.groundentity < 0)
955 toastf(TOAST_WARN, "Stucklaunch prop detection unavailable; bind it");
956 if (!g_iface.engineserver) 869 if (!g_iface.engineserver)
957 toastf(TOAST_WARN, "Server interfaces missing; jumpbug/spread limited"); 870 toastf(TOAST_WARN, "Server interfaces missing; jumpbug/spread limited");
958 if (!g_iface.debugoverlay) 871 if (!g_iface.debugoverlay)
diff --git a/src/hl2h.h b/src/hl2h.h
index d6729cb..8aeef7a 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -92,7 +92,6 @@ struct NetVars {
92 int modelindex = -1; 92 int modelindex = -1;
93 int absvelocity = -1; // client C_BaseEntity::m_vecAbsVelocity (prediction) 93 int absvelocity = -1; // client C_BaseEntity::m_vecAbsVelocity (prediction)
94 int activeweapon = -1; // client m_hActiveWeapon handle 94 int activeweapon = -1; // client m_hActiveWeapon handle
95 int groundentity = -1; // client m_hGroundEntity handle
96 // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72 95 // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72
97 bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; } 96 bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; }
98 // ponytail: m_iMaxHealth isn't a netvar in HL2 SP; esp.cpp falls back to 100. 97 // ponytail: m_iMaxHealth isn't a netvar in HL2 SP; esp.cpp falls back to 100.
@@ -141,7 +140,7 @@ struct CUserCmd {
141 140
142enum { IN_ATTACK = 1 << 0, IN_JUMP = 1 << 1, IN_DUCK = 1 << 2, IN_USE = 1 << 5, IN_ATTACK2 = 1 << 11, IN_SPEED = 1 << 17 }; 141enum { IN_ATTACK = 1 << 0, IN_JUMP = 1 << 1, IN_DUCK = 1 << 2, IN_USE = 1 << 5, IN_ATTACK2 = 1 << 11, IN_SPEED = 1 << 17 };
143enum { FL_ONGROUND = 1 << 0, FL_DUCKING = 1 << 1, FL_INWATER = 1 << 9 }; 142enum { FL_ONGROUND = 1 << 0, FL_DUCKING = 1 << 1, FL_INWATER = 1 << 9 };
144enum { MOVETYPE_WALK = 2, MOVETYPE_VPHYSICS = 6, MOVETYPE_NOCLIP = 8, MOVETYPE_LADDER = 9 }; 143enum { MOVETYPE_WALK = 2, MOVETYPE_NOCLIP = 8, MOVETYPE_LADDER = 9 };
145 144
146// --------------------------------------------------------------------------- 145// ---------------------------------------------------------------------------
147// vector math 146// vector math
@@ -173,7 +172,7 @@ enum FeatureId {
173 FEAT_JUMPBUG = 6, 172 FEAT_JUMPBUG = 6,
174 FEAT_MELEE = 7, 173 FEAT_MELEE = 7,
175 FEAT_SPREAD = 8, 174 FEAT_SPREAD = 8,
176 FEAT_STUCKLAUNCH = 9, 175 FEAT_ITEM_ESP = 9,
177 FEAT_COUNT = 10 176 FEAT_COUNT = 10
178}; 177};
179enum EspOption { 178enum EspOption {
@@ -206,14 +205,16 @@ struct FeatureState {
206}; 205};
207 206
208extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp, 207extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp,
209 g_aimbot, g_triggerbot, g_silentaim, g_stucklaunch; 208 g_aimbot, g_triggerbot, g_silentaim, g_item_esp;
210extern bool g_bhop_autostrafe; 209extern bool g_bhop_autostrafe;
211extern bool g_jumpbug_assist; 210extern bool g_jumpbug_assist;
212extern bool g_spread_no_spread; 211extern bool g_spread_no_spread;
213extern bool g_stucklaunch_use_spam; 212extern bool g_item_health;
214extern bool g_stucklaunch_gravspam; 213extern bool g_item_ammo;
215extern bool g_stucklaunch_autostrafe; 214extern bool g_item_armor;
216extern int g_stucklaunch_spam_ticks; 215extern bool g_item_crates;
216extern bool g_item_distance;
217extern int g_item_max_dist;
217extern bool g_aim_bones[AIM_BONE_COUNT]; 218extern bool g_aim_bones[AIM_BONE_COUNT];
218extern int g_aim_smooth; 219extern int g_aim_smooth;
219extern bool g_aim_vischeck; 220extern bool g_aim_vischeck;
@@ -252,12 +253,6 @@ bool esp_option(int opt);
252bool bhop_autostrafe_enabled(); 253bool bhop_autostrafe_enabled();
253bool jumpbug_assist_enabled(); 254bool jumpbug_assist_enabled();
254bool spread_no_spread_enabled(); 255bool spread_no_spread_enabled();
255bool stucklaunch_use_spam_enabled();
256bool stucklaunch_gravspam_enabled();
257bool stucklaunch_autostrafe_enabled();
258int stucklaunch_spam_ticks();
259bool active_weapon_is_gravity_gun(void *local_ent);
260bool entity_is_physics_prop(int idx);
261unsigned aimbot_bone_mask(); 256unsigned aimbot_bone_mask();
262int aimbot_smooth_step(); 257int aimbot_smooth_step();
263bool aimbot_vischeck_enabled(); 258bool aimbot_vischeck_enabled();
@@ -270,6 +265,7 @@ void *entitylist_get(int idx);
270int engine_get_local_player(); 265int engine_get_local_player();
271void draw_text_col(int x, int y, const char *s, int r, int g, int b); 266void draw_text_col(int x, int y, const char *s, int r, int g, int b);
272void esp_draw(); 267void esp_draw();
268void esp_draw_items();
273bool world_to_screen(const Vector &w, float &sx, float &sy); 269bool world_to_screen(const Vector &w, float &sx, float &sy);
274void set_silent_restore(const QAngle &angles); 270void set_silent_restore(const QAngle &angles);
275bool is_visible(const Vector &eye, const Vector &point); 271bool is_visible(const Vector &eye, const Vector &point);
diff --git a/src/menu.cpp b/src/menu.cpp
index cc3890a..af8d10d 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -44,11 +44,13 @@ FeatureState g_esp{true, 0};
44FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in the GUI 44FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in the GUI
45FeatureState g_triggerbot{true, 603}; // default Mouse4 45FeatureState g_triggerbot{true, 603}; // default Mouse4
46FeatureState g_silentaim{true, 602}; // default Mouse3 46FeatureState g_silentaim{true, 602}; // default Mouse3
47FeatureState g_stucklaunch{false, 0}; // opt-in movement assist 47FeatureState g_item_esp{true, 0}; // valuable item tags, always-on by default
48bool g_stucklaunch_use_spam = true; 48bool g_item_health = true;
49bool g_stucklaunch_gravspam = false; 49bool g_item_ammo = true;
50bool g_stucklaunch_autostrafe = true; 50bool g_item_armor = true;
51int g_stucklaunch_spam_ticks = 2; 51bool g_item_crates = true;
52bool g_item_distance = true;
53int g_item_max_dist = 2500;
52 54
53// Aimbot bone checklist. Head defaults on (v1 behaviour). 55// Aimbot bone checklist. Head defaults on (v1 behaviour).
54bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false, 56bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false,
@@ -163,11 +165,6 @@ void config_save() {
163 fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active, 165 fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active,
164 g_bhop.bind, g_bhop_autostrafe); 166 g_bhop.bind, g_bhop_autostrafe);
165 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); 167 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind);
166 fprintf(f, "[stucklaunch]\nactive=%d\nbind=%d\nuse_spam=%d\n"
167 "gravspam=%d\nautostrafe=%d\nspam_ticks=%d\n",
168 g_stucklaunch.active, g_stucklaunch.bind,
169 (int)g_stucklaunch_use_spam, (int)g_stucklaunch_gravspam,
170 (int)g_stucklaunch_autostrafe, g_stucklaunch_spam_ticks);
171 fprintf(f, "[jumpbug]\nactive=%d\nbind=%d\nassist=%d\n", 168 fprintf(f, "[jumpbug]\nactive=%d\nbind=%d\nassist=%d\n",
172 g_jumpbug.active, g_jumpbug.bind, (int)g_jumpbug_assist); 169 g_jumpbug.active, g_jumpbug.bind, (int)g_jumpbug_assist);
173 fprintf(f, "[melee]\nactive=%d\nbind=%d\n", g_melee.active, g_melee.bind); 170 fprintf(f, "[melee]\nactive=%d\nbind=%d\n", g_melee.active, g_melee.bind);
@@ -186,6 +183,11 @@ void config_save() {
186 g_triggerbot.bind); 183 g_triggerbot.bind);
187 fprintf(f, "[silentaim]\nactive=%d\nbind=%d\nfov=%d\n", g_silentaim.active, 184 fprintf(f, "[silentaim]\nactive=%d\nbind=%d\nfov=%d\n", g_silentaim.active,
188 g_silentaim.bind, g_silent_fov); 185 g_silentaim.bind, g_silent_fov);
186 fprintf(f, "[items]\nactive=%d\nbind=%d\nhealth=%d\nammo=%d\n"
187 "armor=%d\ncrates=%d\ndistance=%d\nmax_dist=%d\n",
188 g_item_esp.active, g_item_esp.bind, (int)g_item_health,
189 (int)g_item_ammo, (int)g_item_armor, (int)g_item_crates,
190 (int)g_item_distance, g_item_max_dist);
189 fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n" 191 fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n"
190 "healthnum=%d\nname=%d\nskeleton=%d\nbox=%d\nspeedgraph=%d\n", 192 "healthnum=%d\nname=%d\nskeleton=%d\nbox=%d\nspeedgraph=%d\n",
191 g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL], 193 g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL],
@@ -214,7 +216,7 @@ static bool config_load() {
214 char line[256]; 216 char line[256];
215 FeatureState *cur = nullptr; 217 FeatureState *cur = nullptr;
216 bool in_esp = false, in_bhop = false, in_aim = false, in_silent = false, 218 bool in_esp = false, in_bhop = false, in_aim = false, in_silent = false,
217 in_jumpbug = false, in_spread = false, in_stucklaunch = false; 219 in_jumpbug = false, in_spread = false, in_items = false;
218 while (fgets(line, sizeof(line), f)) { 220 while (fgets(line, sizeof(line), f)) {
219 line[strcspn(line, "\r\n")] = 0; 221 line[strcspn(line, "\r\n")] = 0;
220 if (line[0] == '[') { 222 if (line[0] == '[') {
@@ -222,8 +224,6 @@ static bool config_load() {
222 cur = &g_bhop; 224 cur = &g_bhop;
223 else if (strstr(line, "[abh]")) 225 else if (strstr(line, "[abh]"))
224 cur = &g_abh; 226 cur = &g_abh;
225 else if (strstr(line, "[stucklaunch]"))
226 cur = &g_stucklaunch;
227 else if (strstr(line, "[jumpbug]")) 227 else if (strstr(line, "[jumpbug]"))
228 cur = &g_jumpbug; 228 cur = &g_jumpbug;
229 else if (strstr(line, "[melee]")) 229 else if (strstr(line, "[melee]"))
@@ -232,6 +232,8 @@ static bool config_load() {
232 cur = &g_spread; 232 cur = &g_spread;
233 else if (strstr(line, "[esp]")) 233 else if (strstr(line, "[esp]"))
234 cur = &g_esp; 234 cur = &g_esp;
235 else if (strstr(line, "[items]"))
236 cur = &g_item_esp;
235 else if (strstr(line, "[aimbot]")) 237 else if (strstr(line, "[aimbot]"))
236 cur = &g_aimbot; 238 cur = &g_aimbot;
237 else if (strstr(line, "[triggerbot]")) 239 else if (strstr(line, "[triggerbot]"))
@@ -246,7 +248,7 @@ static bool config_load() {
246 in_silent = (cur == &g_silentaim); 248 in_silent = (cur == &g_silentaim);
247 in_jumpbug = (cur == &g_jumpbug); 249 in_jumpbug = (cur == &g_jumpbug);
248 in_spread = (cur == &g_spread); 250 in_spread = (cur == &g_spread);
249 in_stucklaunch = (cur == &g_stucklaunch); 251 in_items = (cur == &g_item_esp);
250 } else if (cur) { 252 } else if (cur) {
251 char *eq = strchr(line, '='); 253 char *eq = strchr(line, '=');
252 if (!eq) 254 if (!eq)
@@ -262,18 +264,22 @@ static bool config_load() {
262 if (in_spread && strcmp(key, "no_spread") == 0) { 264 if (in_spread && strcmp(key, "no_spread") == 0) {
263 g_spread_no_spread = atoi(val) != 0; 265 g_spread_no_spread = atoi(val) != 0;
264 } 266 }
265 if (in_stucklaunch) { 267 if (in_items) {
266 if (strcmp(key, "use_spam") == 0) 268 if (strcmp(key, "health") == 0)
267 g_stucklaunch_use_spam = atoi(val) != 0; 269 g_item_health = atoi(val) != 0;
268 else if (strcmp(key, "gravspam") == 0) 270 else if (strcmp(key, "ammo") == 0)
269 g_stucklaunch_gravspam = atoi(val) != 0; 271 g_item_ammo = atoi(val) != 0;
270 else if (strcmp(key, "autostrafe") == 0) 272 else if (strcmp(key, "armor") == 0)
271 g_stucklaunch_autostrafe = atoi(val) != 0; 273 g_item_armor = atoi(val) != 0;
272 else if (strcmp(key, "spam_ticks") == 0) { 274 else if (strcmp(key, "crates") == 0)
275 g_item_crates = atoi(val) != 0;
276 else if (strcmp(key, "distance") == 0)
277 g_item_distance = atoi(val) != 0;
278 else if (strcmp(key, "max_dist") == 0) {
273 int v = atoi(val); 279 int v = atoi(val);
274 if (v < 1) v = 1; 280 if (v < 250) v = 250;
275 if (v > 16) v = 16; 281 if (v > 5000) v = 5000;
276 g_stucklaunch_spam_ticks = v; 282 g_item_max_dist = v;
277 } 283 }
278 } 284 }
279 if (in_aim) { 285 if (in_aim) {
@@ -354,11 +360,6 @@ void config_reset_defaults() {
354 g_bhop = {true, 0}; 360 g_bhop = {true, 0};
355 g_bhop_autostrafe = true; 361 g_bhop_autostrafe = true;
356 g_abh = {true, 0}; 362 g_abh = {true, 0};
357 g_stucklaunch = {false, 0};
358 g_stucklaunch_use_spam = true;
359 g_stucklaunch_gravspam = false;
360 g_stucklaunch_autostrafe = true;
361 g_stucklaunch_spam_ticks = 2;
362 g_jumpbug = {true, 0}; 363 g_jumpbug = {true, 0};
363 g_jumpbug_assist = false; 364 g_jumpbug_assist = false;
364 g_melee = {true, 0}; 365 g_melee = {true, 0};
@@ -367,6 +368,13 @@ void config_reset_defaults() {
367 g_esp = {true, 0}; 368 g_esp = {true, 0};
368 for (int i = 0; i < ESP_OPT_COUNT; i++) 369 for (int i = 0; i < ESP_OPT_COUNT; i++)
369 g_esp_opt[i] = true; 370 g_esp_opt[i] = true;
371 g_item_esp = {true, 0};
372 g_item_health = true;
373 g_item_ammo = true;
374 g_item_armor = true;
375 g_item_crates = true;
376 g_item_distance = true;
377 g_item_max_dist = 2500;
370 g_aimbot = {true, 604}; 378 g_aimbot = {true, 604};
371 g_triggerbot = {true, 603}; 379 g_triggerbot = {true, 603};
372 g_silentaim = {true, 602}; 380 g_silentaim = {true, 602};
@@ -476,7 +484,7 @@ static bool key_held(int sc) {
476static FeatureState *feature_state(int feature) { 484static FeatureState *feature_state(int feature) {
477 static FeatureState *feats[FEAT_COUNT] = { 485 static FeatureState *feats[FEAT_COUNT] = {
478 &g_bhop, &g_abh, &g_esp, &g_aimbot, &g_triggerbot, 486 &g_bhop, &g_abh, &g_esp, &g_aimbot, &g_triggerbot,
479 &g_silentaim, &g_jumpbug, &g_melee, &g_spread, &g_stucklaunch}; 487 &g_silentaim, &g_jumpbug, &g_melee, &g_spread, &g_item_esp};
480 if (feature < 0 || feature >= FEAT_COUNT) 488 if (feature < 0 || feature >= FEAT_COUNT)
481 return nullptr; 489 return nullptr;
482 return feats[feature]; 490 return feats[feature];
@@ -509,14 +517,6 @@ bool jumpbug_assist_enabled() { return g_jumpbug_assist; }
509 517
510bool spread_no_spread_enabled() { return g_spread_no_spread; } 518bool spread_no_spread_enabled() { return g_spread_no_spread; }
511 519
512bool stucklaunch_use_spam_enabled() { return g_stucklaunch_use_spam; }
513
514bool stucklaunch_gravspam_enabled() { return g_stucklaunch_gravspam; }
515
516bool stucklaunch_autostrafe_enabled() { return g_stucklaunch_autostrafe; }
517
518int stucklaunch_spam_ticks() { return g_stucklaunch_spam_ticks; }
519
520unsigned aimbot_bone_mask() { 520unsigned aimbot_bone_mask() {
521 unsigned m = 0; 521 unsigned m = 0;
522 if (g_aim_bones[AIM_BONE_HEAD]) 522 if (g_aim_bones[AIM_BONE_HEAD])
@@ -658,8 +658,10 @@ void outer_draw() {
658 // HL2H_DRAW_TEST=1 draws a probe rect without needing the GUI open 658 // HL2H_DRAW_TEST=1 draws a probe rect without needing the GUI open
659 static bool draw_test = getenv("HL2H_DRAW_TEST") != nullptr; 659 static bool draw_test = getenv("HL2H_DRAW_TEST") != nullptr;
660 bool esp_on = feature_active(FEAT_ESP); 660 bool esp_on = feature_active(FEAT_ESP);
661 bool items_on = feature_active(FEAT_ITEM_ESP);
661 bool toasts = gui_toasts_active(); 662 bool toasts = gui_toasts_active();
662 if (!g_surface || (!gui_is_open() && !draw_test && !esp_on && !toasts)) 663 if (!g_surface ||
664 (!gui_is_open() && !draw_test && !esp_on && !items_on && !toasts))
663 return; 665 return;
664 666
665 // Level/menu -> game transitions can invalidate the VGUI font handle. 667 // Level/menu -> game transitions can invalidate the VGUI font handle.
@@ -709,6 +711,8 @@ void outer_draw() {
709 surf_push_make_current(panel, false); 711 surf_push_make_current(panel, false);
710 if (esp_on && overlay_font) 712 if (esp_on && overlay_font)
711 esp_draw(); 713 esp_draw();
714 if (items_on && overlay_font)
715 esp_draw_items();
712 if (draw_test && overlay_font) { 716 if (draw_test && overlay_font) {
713 surf_draw_set_color(255, 0, 0, 255); 717 surf_draw_set_color(255, 0, 0, 255);
714 surf_draw_filled_rect(20, 20, 180, 60); 718 surf_draw_filled_rect(20, 20, 180, 60);
diff --git a/src/netvars.cpp b/src/netvars.cpp
index e304317..3b2d3b8 100644
--- a/src/netvars.cpp
+++ b/src/netvars.cpp
@@ -92,9 +92,6 @@ static void collect_netvars(uintptr_t table, uintptr_t base_off, int depth) {
92 } else if (strcmp(pname2, "m_hActiveWeapon") == 0 && 92 } else if (strcmp(pname2, "m_hActiveWeapon") == 0 &&
93 g_net.activeweapon < 0) { 93 g_net.activeweapon < 0) {
94 g_net.activeweapon = (int)(base_off + (uint32_t)poff); 94 g_net.activeweapon = (int)(base_off + (uint32_t)poff);
95 } else if (strcmp(pname2, "m_hGroundEntity") == 0 &&
96 g_net.groundentity < 0) {
97 g_net.groundentity = (int)(base_off + (uint32_t)poff);
98 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) { 95 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) {
99 g_net.teamnum = (int)(base_off + (uint32_t)poff); 96 g_net.teamnum = (int)(base_off + (uint32_t)poff);
100 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) { 97 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) {
@@ -275,7 +272,7 @@ void resolve_netvars() {
275 logf("m_vecAbsVelocity unresolved; jumpbug assist disabled"); 272 logf("m_vecAbsVelocity unresolved; jumpbug assist disabled");
276 logf("netvars: flags=%d velocity=%d movetype=%d health=%d maxhealth=%d " 273 logf("netvars: flags=%d velocity=%d movetype=%d health=%d maxhealth=%d "
277 "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d lifeste=%d " 274 "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d lifeste=%d "
278 "modelindex=%d absvelocity=%d activeweapon=%d groundentity=%d", 275 "modelindex=%d absvelocity=%d activeweapon=%d",
279 g_net.flags, g_net.velocity, g_net.movetype, g_net.health, 276 g_net.flags, g_net.velocity, g_net.movetype, g_net.health,
280 g_net.maxhealth, g_net.teamnum, g_net.origin, g_net.viewoffset, 277 g_net.maxhealth, g_net.teamnum, g_net.origin, g_net.viewoffset,
281 g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex, 278 g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex,