summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--CONTEXT.md18
-rw-r--r--src/esp.cpp241
-rw-r--r--src/gui.cpp3
-rw-r--r--src/hl2h.h3
-rw-r--r--src/menu.cpp10
-rw-r--r--src/netvars.cpp7
6 files changed, 243 insertions, 39 deletions
diff --git a/CONTEXT.md b/CONTEXT.md
index c8bc54e..56a1a65 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -82,6 +82,7 @@ Relevant vtable slots (this build):
82| `m_nModelIndex` | `0x7C` | 82| `m_nModelIndex` | `0x7C` |
83| `m_vecAbsVelocity` (client local, not netvar) | `0x11C` | 83| `m_vecAbsVelocity` (client local, not netvar) | `0x11C` |
84| `m_hActiveWeapon` (client netvar; server fallback `0x824`) | resolved by name | 84| `m_hActiveWeapon` (client netvar; server fallback `0x824`) | resolved by name |
85| `m_hOwnerEntity` / `m_hOwner` (held weapons) | resolved by name |
85 86
86- Eye position = `m_vecOrigin + m_vecViewOffset` on **all three axes**. 87- Eye position = `m_vecOrigin + m_vecViewOffset` on **all three axes**.
87 (The old code added the X component to Z, which left the eye ~64 units low.) 88 (The old code added the X component to Z, which left the eye ~64 units low.)
@@ -271,16 +272,19 @@ vocabulary / decisions.
271## Valuable items 272## Valuable items
272 273
273- Visuals feature; Active is on by default and unbound (always-on). 274- Visuals feature; Active is on by default and unbound (always-on).
274- Scans the client entity list every 100 ms for item models/classes and tags 275- Scans the client entity list every 100 ms and tags health, ammo, armor/suit,
275 health, ammo, armor/suit, supply crates and generic items. 276 world weapon pickups, the two supply-crate models and generic items.
276- Each tag is a colored marker with a name and optional distance, filtered by 277- Each tag is a colored marker with a name and optional distance, filtered by
277 category toggles and a max-distance slider. Drawn through walls and 278 category toggles and a max-distance slider. Drawn through walls and
278 independently of the hostile NPC ESP. 279 independently of the hostile NPC ESP.
279- Detection is model-first (`models/items/...`, `models/healthvial.mdl`, 280- Ammo labels are specific where the model is known: pistol, SMG, AR2, .357,
280 `models/props_combine/*_charger*.mdl`, `models/w_longjump.mdl`) with class 281 crossbow, shotgun, sniper, flares, AR2 grenade, RPG rocket, plus ammo-crate
281 fallbacks. Generic breakable wood/plastic/metal crates are tagged as 282 variants. Unknown ammo falls back to "Ammo".
282 "Crate"; crate chunk debris is ignored. Weapon pickups are intentionally 283- Weapons are world pickups only: the active weapon and anything with a valid
283 not tagged. 284 `m_hOwner`/`m_hOwnerEntity` handle is skipped.
285- Only `item_item_crate` and `item_beacon_crate` are tagged as supply crates.
286 Other breakable crates are intentionally ignored; crate chunk debris is
287 skipped.
284 288
285## Roadmap / TODO 289## Roadmap / TODO
286 290
diff --git a/src/esp.cpp b/src/esp.cpp
index 0d64c78..afdedac 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -1343,7 +1343,14 @@ void esp_draw() {
1343// Valuable item tags 1343// Valuable item tags
1344// --------------------------------------------------------------------------- 1344// ---------------------------------------------------------------------------
1345 1345
1346enum ItemKind { IK_HEALTH, IK_AMMO, IK_ARMOR, IK_CRATE, IK_OTHER }; 1346enum ItemKind {
1347 IK_HEALTH,
1348 IK_AMMO,
1349 IK_ARMOR,
1350 IK_WEAPON,
1351 IK_CRATE,
1352 IK_OTHER
1353};
1347 1354
1348struct ItemTarget { 1355struct ItemTarget {
1349 int idx; 1356 int idx;
@@ -1366,6 +1373,78 @@ static bool item_icontains(const char *hay, const char *needle) {
1366 return false; 1373 return false;
1367} 1374}
1368 1375
1376static bool item_handle_valid(uint32_t h) {
1377 return h != 0 && h != 0xFFFFFFFFu;
1378}
1379
1380// Weapons held by the player or an NPC are not world pickups.
1381static bool item_weapon_is_owned(void *ent) {
1382 if (!ent)
1383 return false;
1384 if (g_net.owner >= 0) {
1385 uint32_t h = *(uint32_t *)((uintptr_t)ent + g_net.owner);
1386 if (item_handle_valid(h))
1387 return true;
1388 }
1389 if (g_net.weapon_owner >= 0) {
1390 uint32_t h = *(uint32_t *)((uintptr_t)ent + g_net.weapon_owner);
1391 if (item_handle_valid(h))
1392 return true;
1393 }
1394 return false;
1395}
1396
1397static int local_active_weapon_idx(int local_idx) {
1398 if (local_idx <= 0 || g_net.activeweapon < 0)
1399 return -1;
1400 void *local = entitylist_get(local_idx);
1401 if (!local)
1402 return -1;
1403 uint32_t h = *(uint32_t *)((uintptr_t)local + g_net.activeweapon);
1404 if (!item_handle_valid(h))
1405 return -1;
1406 return (int)(h & 0xFFFF);
1407}
1408
1409static int classify_weapon(const char *model, const char *cls, char *label,
1410 size_t outn) {
1411 if (!item_icontains(model, "models/weapons/w_") &&
1412 !item_icontains(cls, "weapon"))
1413 return 0;
1414 if (item_icontains(model, "w_crowbar"))
1415 snprintf(label, outn, "Crowbar");
1416 else if (item_icontains(model, "w_pistol"))
1417 snprintf(label, outn, "Pistol");
1418 else if (item_icontains(model, "w_357"))
1419 snprintf(label, outn, "Revolver");
1420 else if (item_icontains(model, "w_smg1") ||
1421 item_icontains(model, "w_smg2"))
1422 snprintf(label, outn, "SMG");
1423 else if (item_icontains(model, "w_ar2"))
1424 snprintf(label, outn, "AR2");
1425 else if (item_icontains(model, "w_shotgun"))
1426 snprintf(label, outn, "Shotgun");
1427 else if (item_icontains(model, "w_crossbow"))
1428 snprintf(label, outn, "Crossbow");
1429 else if (item_icontains(model, "w_rpg"))
1430 snprintf(label, outn, "RPG");
1431 else if (item_icontains(model, "w_frag") ||
1432 item_icontains(model, "w_grenade"))
1433 snprintf(label, outn, "Grenade");
1434 else if (item_icontains(model, "w_physcannon") ||
1435 item_icontains(model, "w_physics"))
1436 snprintf(label, outn, "Gravity gun");
1437 else if (item_icontains(model, "w_stunstick"))
1438 snprintf(label, outn, "Stunstick");
1439 else if (item_icontains(model, "w_bugbait"))
1440 snprintf(label, outn, "Bugbait");
1441 else if (item_icontains(model, "w_sniper"))
1442 snprintf(label, outn, "Sniper");
1443 else
1444 snprintf(label, outn, "Weapon");
1445 return 1;
1446}
1447
1369static int classify_item(const char *model, const char *cls, char *label, 1448static int classify_item(const char *model, const char *cls, char *label,
1370 size_t outn) { 1449 size_t outn) {
1371 if (!model && !cls) 1450 if (!model && !cls)
@@ -1403,40 +1482,100 @@ static int classify_item(const char *model, const char *cls, char *label,
1403 snprintf(label, outn, "Suit charger"); 1482 snprintf(label, outn, "Suit charger");
1404 return IK_ARMOR; 1483 return IK_ARMOR;
1405 } 1484 }
1485
1486 // Only the two item-crate models are supply crates. Other crates are just
1487 // breakable map props and deliberately not tagged.
1406 if (item_icontains(model, "item_item_crate") || 1488 if (item_icontains(model, "item_item_crate") ||
1407 item_icontains(model, "item_beacon_crate")) { 1489 item_icontains(model, "item_beacon_crate")) {
1408 snprintf(label, outn, "Supply crate"); 1490 snprintf(label, outn, "Supply crate");
1409 return IK_CRATE; 1491 return IK_CRATE;
1410 } 1492 }
1493
1494 if (item_icontains(model, "ammocrate_pistol")) {
1495 snprintf(label, outn, "Pistol ammo crate");
1496 return IK_AMMO;
1497 }
1498 if (item_icontains(model, "ammocrate_smg1")) {
1499 snprintf(label, outn, "SMG ammo crate");
1500 return IK_AMMO;
1501 }
1502 if (item_icontains(model, "ammocrate_ar2")) {
1503 snprintf(label, outn, "AR2 ammo crate");
1504 return IK_AMMO;
1505 }
1506 if (item_icontains(model, "ammocrate_rockets")) {
1507 snprintf(label, outn, "RPG ammo crate");
1508 return IK_AMMO;
1509 }
1510 if (item_icontains(model, "ammocrate_buckshot")) {
1511 snprintf(label, outn, "Shotgun ammo crate");
1512 return IK_AMMO;
1513 }
1514 if (item_icontains(model, "ammocrate_grenade")) {
1515 snprintf(label, outn, "Grenade crate");
1516 return IK_AMMO;
1517 }
1518 if (item_icontains(model, "ammocrate_smg2")) {
1519 snprintf(label, outn, "SMG grenade crate");
1520 return IK_AMMO;
1521 }
1411 if (item_icontains(model, "ammocrate")) { 1522 if (item_icontains(model, "ammocrate")) {
1412 snprintf(label, outn, "Ammo crate"); 1523 snprintf(label, outn, "Ammo crate");
1413 return IK_AMMO; 1524 return IK_AMMO;
1414 } 1525 }
1415 // Generic breakable crates (wood/plastic/metal) are supply caches too. 1526
1416 if (item_icontains(model, "crate")) {
1417 snprintf(label, outn, "Crate");
1418 return IK_CRATE;
1419 }
1420 if (item_icontains(model, "w_missile_closed")) { 1527 if (item_icontains(model, "w_missile_closed")) {
1421 snprintf(label, outn, "RPG ammo"); 1528 snprintf(label, outn, "RPG rocket");
1529 return IK_AMMO;
1530 }
1531 if (item_icontains(model, "boxsrounds")) {
1532 snprintf(label, outn, "Pistol ammo");
1533 return IK_AMMO;
1534 }
1535 if (item_icontains(model, "boxmrounds")) {
1536 snprintf(label, outn, "SMG ammo");
1537 return IK_AMMO;
1538 }
1539 if (item_icontains(model, "boxlrounds") ||
1540 item_icontains(model, "combine_rifle_cartridge") ||
1541 item_icontains(model, "combine_rifle_ammo")) {
1542 snprintf(label, outn, "AR2 ammo");
1543 return IK_AMMO;
1544 }
1545 if (item_icontains(model, "357ammo") ||
1546 item_icontains(model, "357ammobox")) {
1547 snprintf(label, outn, ".357 ammo");
1548 return IK_AMMO;
1549 }
1550 if (item_icontains(model, "crossbowrounds")) {
1551 snprintf(label, outn, "Crossbow bolts");
1552 return IK_AMMO;
1553 }
1554 if (item_icontains(model, "boxbuckshot")) {
1555 snprintf(label, outn, "Shotgun shells");
1556 return IK_AMMO;
1557 }
1558 if (item_icontains(model, "boxsniperrounds")) {
1559 snprintf(label, outn, "Sniper ammo");
1560 return IK_AMMO;
1561 }
1562 if (item_icontains(model, "boxflares") ||
1563 item_icontains(model, "models/items/flare")) {
1564 snprintf(label, outn, "Flares");
1565 return IK_AMMO;
1566 }
1567 if (item_icontains(model, "ar2_grenade")) {
1568 snprintf(label, outn, "AR2 grenade");
1422 return IK_AMMO; 1569 return IK_AMMO;
1423 } 1570 }
1424 if (item_icontains(model, "models/items/")) { 1571 if (item_icontains(model, "models/items/")) {
1425 if (item_icontains(model, "crossbowrounds")) 1572 snprintf(label, outn, "Ammo");
1426 snprintf(label, outn, "Crossbow bolts");
1427 else if (item_icontains(model, "ar2_grenade"))
1428 snprintf(label, outn, "AR2 grenade");
1429 else if (item_icontains(model, "357ammo"))
1430 snprintf(label, outn, "357 ammo");
1431 else if (item_icontains(model, "boxbuckshot"))
1432 snprintf(label, outn, "Buckshot");
1433 else if (item_icontains(model, "boxsniperrounds"))
1434 snprintf(label, outn, "Sniper ammo");
1435 else
1436 snprintf(label, outn, "Ammo");
1437 return IK_AMMO; 1573 return IK_AMMO;
1438 } 1574 }
1439 1575
1576 if (classify_weapon(model, cls, label, outn) == 1)
1577 return IK_WEAPON;
1578
1440 if (item_icontains(cls, "healthkit") || item_icontains(cls, "healthvial") || 1579 if (item_icontains(cls, "healthkit") || item_icontains(cls, "healthvial") ||
1441 item_icontains(cls, "wallhealth")) { 1580 item_icontains(cls, "wallhealth")) {
1442 snprintf(label, outn, "Health"); 1581 snprintf(label, outn, "Health");
@@ -1447,8 +1586,7 @@ static int classify_item(const char *model, const char *cls, char *label,
1447 snprintf(label, outn, "Armor"); 1586 snprintf(label, outn, "Armor");
1448 return IK_ARMOR; 1587 return IK_ARMOR;
1449 } 1588 }
1450 if (item_icontains(cls, "itemcrate") || 1589 if (item_icontains(cls, "itemcrate")) {
1451 item_icontains(cls, "dynamicresupply")) {
1452 snprintf(label, outn, "Supply crate"); 1590 snprintf(label, outn, "Supply crate");
1453 return IK_CRATE; 1591 return IK_CRATE;
1454 } 1592 }
@@ -1456,9 +1594,9 @@ static int classify_item(const char *model, const char *cls, char *label,
1456 snprintf(label, outn, "Ammo"); 1594 snprintf(label, outn, "Ammo");
1457 return IK_AMMO; 1595 return IK_AMMO;
1458 } 1596 }
1459 if (item_icontains(cls, "crate")) { 1597 if (item_icontains(cls, "weapon")) {
1460 snprintf(label, outn, "Crate"); 1598 snprintf(label, outn, "Weapon");
1461 return IK_CRATE; 1599 return IK_WEAPON;
1462 } 1600 }
1463 if (item_icontains(cls, "item") || item_icontains(cls, "pickup")) { 1601 if (item_icontains(cls, "item") || item_icontains(cls, "pickup")) {
1464 snprintf(label, outn, "Item"); 1602 snprintf(label, outn, "Item");
@@ -1472,6 +1610,7 @@ static bool item_kind_enabled(int kind) {
1472 case IK_HEALTH: return g_item_health; 1610 case IK_HEALTH: return g_item_health;
1473 case IK_AMMO: return g_item_ammo; 1611 case IK_AMMO: return g_item_ammo;
1474 case IK_ARMOR: return g_item_armor; 1612 case IK_ARMOR: return g_item_armor;
1613 case IK_WEAPON: return g_item_weapons;
1475 case IK_CRATE: return g_item_crates; 1614 case IK_CRATE: return g_item_crates;
1476 default: return true; 1615 default: return true;
1477 } 1616 }
@@ -1491,8 +1630,25 @@ static void items_collect(int local_idx) {
1491 int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist); 1630 int hi = vfunc<Fn>(g_iface.entitylist, 6)(g_iface.entitylist);
1492 if (hi < 0 || hi > 4096) 1631 if (hi < 0 || hi > 4096)
1493 hi = 4096; 1632 hi = 4096;
1494 1633 int active_idx = local_active_weapon_idx(local_idx);
1634 static bool cats_logged = false;
1635 if (!cats_logged) {
1636 cats_logged = true;
1637 logf("items: categories health=%d ammo=%d armor=%d weapons=%d "
1638 "crates=%d distance=%d max=%d",
1639 (int)g_item_health, (int)g_item_ammo, (int)g_item_armor,
1640 (int)g_item_weapons, (int)g_item_crates, (int)g_item_distance,
1641 g_item_max_dist);
1642 }
1495 static int dbg_lines = 0; 1643 static int dbg_lines = 0;
1644 static int prop_logs = 0;
1645 static int crate_logs = 0;
1646 static bool owner_warned = false;
1647 if (!owner_warned && g_net.owner < 0 && g_net.weapon_owner < 0) {
1648 owner_warned = true;
1649 logf("items: weapon owner netvar unavailable; held weapons may tag");
1650 }
1651
1496 for (int idx = 1; idx <= hi && g_nitems < 192; idx++) { 1652 for (int idx = 1; idx <= hi && g_nitems < 192; idx++) {
1497 if (idx == local_idx) 1653 if (idx == local_idx)
1498 continue; 1654 continue;
@@ -1506,7 +1662,14 @@ static void items_collect(int local_idx) {
1506 const char *model = entity_model_name(ent); 1662 const char *model = entity_model_name(ent);
1507 char label[48]; 1663 char label[48];
1508 int kind = classify_item(model, cls, label, sizeof(label)); 1664 int kind = classify_item(model, cls, label, sizeof(label));
1509 if (kind < 0) 1665
1666 bool propish = item_icontains(cls, "crate") ||
1667 item_icontains(model, "crate") ||
1668 item_icontains(cls, "physicsprop") ||
1669 item_icontains(cls, "breakableprop") ||
1670 item_icontains(cls, "func_breakable") ||
1671 item_icontains(cls, "physbox");
1672 if (kind < 0 && !propish)
1510 continue; 1673 continue;
1511 1674
1512 Vector origin{*(float *)((uintptr_t)ent + g_net.origin), 1675 Vector origin{*(float *)((uintptr_t)ent + g_net.origin),
@@ -1516,9 +1679,31 @@ static void items_collect(int local_idx) {
1516 float dy = origin.y - g_cam_eye.y; 1679 float dy = origin.y - g_cam_eye.y;
1517 float dz = origin.z - g_cam_eye.z; 1680 float dz = origin.z - g_cam_eye.z;
1518 float dist = sqrtf(dx * dx + dy * dy + dz * dz); 1681 float dist = sqrtf(dx * dx + dy * dy + dz * dz);
1682
1683 if (propish && prop_logs < 24) {
1684 prop_logs++;
1685 logf("item prop: idx=%d cls=%s model=%s kind=%d dist=%.0f "
1686 "origin=(%.0f %.0f %.0f)",
1687 idx, cls ? cls : "?", model ? model : "?", kind, dist, origin.x,
1688 origin.y, origin.z);
1689 }
1690 if (kind < 0)
1691 continue;
1692
1693 if (kind == IK_WEAPON) {
1694 if (idx == active_idx || item_weapon_is_owned(ent))
1695 continue;
1696 }
1519 if (g_item_max_dist > 0 && dist > (float)g_item_max_dist) 1697 if (g_item_max_dist > 0 && dist > (float)g_item_max_dist)
1520 continue; 1698 continue;
1521 1699
1700 if (kind == IK_CRATE && crate_logs < 8) {
1701 crate_logs++;
1702 logf("item crate: idx=%d cls=%s model=%s origin=(%.0f %.0f %.0f)", idx,
1703 cls ? cls : "?", model ? model : "?", origin.x, origin.y,
1704 origin.z);
1705 }
1706
1522 ItemTarget &t = g_item_targets[g_nitems++]; 1707 ItemTarget &t = g_item_targets[g_nitems++];
1523 t.idx = idx; 1708 t.idx = idx;
1524 t.kind = kind; 1709 t.kind = kind;
@@ -1540,7 +1725,8 @@ static void items_collect(int local_idx) {
1540void esp_draw_items() { 1725void esp_draw_items() {
1541 if (!g_surface || !g_iface.entitylist || g_net.origin < 0) 1726 if (!g_surface || !g_iface.entitylist || g_net.origin < 0)
1542 return; 1727 return;
1543 if (!g_item_health && !g_item_ammo && !g_item_armor && !g_item_crates) 1728 if (!g_item_health && !g_item_ammo && !g_item_armor && !g_item_weapons &&
1729 !g_item_crates)
1544 return; 1730 return;
1545 int local = engine_get_local_player(); 1731 int local = engine_get_local_player();
1546 if (local <= 0) 1732 if (local <= 0)
@@ -1569,6 +1755,7 @@ void esp_draw_items() {
1569 case IK_HEALTH: r = 90; g = 255; b = 130; break; 1755 case IK_HEALTH: r = 90; g = 255; b = 130; break;
1570 case IK_AMMO: r = 255; g = 210; b = 80; break; 1756 case IK_AMMO: r = 255; g = 210; b = 80; break;
1571 case IK_ARMOR: r = 90; g = 180; b = 255; break; 1757 case IK_ARMOR: r = 90; g = 180; b = 255; break;
1758 case IK_WEAPON: r = 120; g = 230; b = 255; break;
1572 case IK_CRATE: r = 220; g = 150; b = 255; break; 1759 case IK_CRATE: r = 220; g = 150; b = 255; break;
1573 default: break; 1760 default: break;
1574 } 1761 }
diff --git a/src/gui.cpp b/src/gui.cpp
index eb9a964..29fa60b 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -350,7 +350,7 @@ static void build_cards() {
350 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]);
351 351
352 int items = add_card(2, &g_item_esp, "Valuable items", 352 int items = add_card(2, &g_item_esp, "Valuable items",
353 "Tag medkits, ammo, armor and supply crates.", true); 353 "Tag medkits, ammo, armor, weapons and supply crates.", true);
354 add_toggle(items, "Medkits / health", 354 add_toggle(items, "Medkits / health",
355 "Tag health kits, health vials and health chargers.", 355 "Tag health kits, health vials and health chargers.",
356 &g_item_health); 356 &g_item_health);
@@ -358,6 +358,7 @@ static void build_cards() {
358 &g_item_ammo); 358 &g_item_ammo);
359 add_toggle(items, "Armor / suit", "Tag batteries, HEV suits and chargers.", 359 add_toggle(items, "Armor / suit", "Tag batteries, HEV suits and chargers.",
360 &g_item_armor); 360 &g_item_armor);
361 add_toggle(items, "Weapons", "Tag world weapon pickups.", &g_item_weapons);
361 add_toggle(items, "Supply crates", "Tag item and beacon crates.", 362 add_toggle(items, "Supply crates", "Tag item and beacon crates.",
362 &g_item_crates); 363 &g_item_crates);
363 add_toggle(items, "Show distance", "Append the distance in units.", 364 add_toggle(items, "Show distance", "Append the distance in units.",
diff --git a/src/hl2h.h b/src/hl2h.h
index 8aeef7a..cc11e0d 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -92,6 +92,8 @@ 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 owner = -1; // client m_hOwnerEntity handle
96 int weapon_owner = -1; // client m_hOwner handle (C_BaseCombatWeapon)
95 // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72 97 // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72
96 bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; } 98 bool ok() const { return flags >= 0 && velocity >= 0 && movetype >= 0; }
97 // ponytail: m_iMaxHealth isn't a netvar in HL2 SP; esp.cpp falls back to 100. 99 // ponytail: m_iMaxHealth isn't a netvar in HL2 SP; esp.cpp falls back to 100.
@@ -212,6 +214,7 @@ extern bool g_spread_no_spread;
212extern bool g_item_health; 214extern bool g_item_health;
213extern bool g_item_ammo; 215extern bool g_item_ammo;
214extern bool g_item_armor; 216extern bool g_item_armor;
217extern bool g_item_weapons;
215extern bool g_item_crates; 218extern bool g_item_crates;
216extern bool g_item_distance; 219extern bool g_item_distance;
217extern int g_item_max_dist; 220extern int g_item_max_dist;
diff --git a/src/menu.cpp b/src/menu.cpp
index af8d10d..69c3b45 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -48,6 +48,7 @@ FeatureState g_item_esp{true, 0}; // valuable item tags, always-on by default
48bool g_item_health = true; 48bool g_item_health = true;
49bool g_item_ammo = true; 49bool g_item_ammo = true;
50bool g_item_armor = true; 50bool g_item_armor = true;
51bool g_item_weapons = true;
51bool g_item_crates = true; 52bool g_item_crates = true;
52bool g_item_distance = true; 53bool g_item_distance = true;
53int g_item_max_dist = 2500; 54int g_item_max_dist = 2500;
@@ -184,10 +185,10 @@ void config_save() {
184 fprintf(f, "[silentaim]\nactive=%d\nbind=%d\nfov=%d\n", g_silentaim.active, 185 fprintf(f, "[silentaim]\nactive=%d\nbind=%d\nfov=%d\n", g_silentaim.active,
185 g_silentaim.bind, g_silent_fov); 186 g_silentaim.bind, g_silent_fov);
186 fprintf(f, "[items]\nactive=%d\nbind=%d\nhealth=%d\nammo=%d\n" 187 fprintf(f, "[items]\nactive=%d\nbind=%d\nhealth=%d\nammo=%d\n"
187 "armor=%d\ncrates=%d\ndistance=%d\nmax_dist=%d\n", 188 "armor=%d\nweapons=%d\ncrates=%d\ndistance=%d\nmax_dist=%d\n",
188 g_item_esp.active, g_item_esp.bind, (int)g_item_health, 189 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_ammo, (int)g_item_armor, (int)g_item_weapons,
190 (int)g_item_distance, g_item_max_dist); 191 (int)g_item_crates, (int)g_item_distance, g_item_max_dist);
191 fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n" 192 fprintf(f, "[esp]\nactive=%d\nbind=%d\nneutral=%d\nhealthbar=%d\n"
192 "healthnum=%d\nname=%d\nskeleton=%d\nbox=%d\nspeedgraph=%d\n", 193 "healthnum=%d\nname=%d\nskeleton=%d\nbox=%d\nspeedgraph=%d\n",
193 g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL], 194 g_esp.active, g_esp.bind, g_esp_opt[ESP_OPT_SHOW_NEUTRAL],
@@ -271,6 +272,8 @@ static bool config_load() {
271 g_item_ammo = atoi(val) != 0; 272 g_item_ammo = atoi(val) != 0;
272 else if (strcmp(key, "armor") == 0) 273 else if (strcmp(key, "armor") == 0)
273 g_item_armor = atoi(val) != 0; 274 g_item_armor = atoi(val) != 0;
275 else if (strcmp(key, "weapons") == 0)
276 g_item_weapons = atoi(val) != 0;
274 else if (strcmp(key, "crates") == 0) 277 else if (strcmp(key, "crates") == 0)
275 g_item_crates = atoi(val) != 0; 278 g_item_crates = atoi(val) != 0;
276 else if (strcmp(key, "distance") == 0) 279 else if (strcmp(key, "distance") == 0)
@@ -372,6 +375,7 @@ void config_reset_defaults() {
372 g_item_health = true; 375 g_item_health = true;
373 g_item_ammo = true; 376 g_item_ammo = true;
374 g_item_armor = true; 377 g_item_armor = true;
378 g_item_weapons = true;
375 g_item_crates = true; 379 g_item_crates = true;
376 g_item_distance = true; 380 g_item_distance = true;
377 g_item_max_dist = 2500; 381 g_item_max_dist = 2500;
diff --git a/src/netvars.cpp b/src/netvars.cpp
index 3b2d3b8..4980acc 100644
--- a/src/netvars.cpp
+++ b/src/netvars.cpp
@@ -92,6 +92,10 @@ 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_hOwnerEntity") == 0 && g_net.owner < 0) {
96 g_net.owner = (int)(base_off + (uint32_t)poff);
97 } else if (strcmp(pname2, "m_hOwner") == 0 && g_net.weapon_owner < 0) {
98 g_net.weapon_owner = (int)(base_off + (uint32_t)poff);
95 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) { 99 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) {
96 g_net.teamnum = (int)(base_off + (uint32_t)poff); 100 g_net.teamnum = (int)(base_off + (uint32_t)poff);
97 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) { 101 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) {
@@ -272,7 +276,8 @@ void resolve_netvars() {
272 logf("m_vecAbsVelocity unresolved; jumpbug assist disabled"); 276 logf("m_vecAbsVelocity unresolved; jumpbug assist disabled");
273 logf("netvars: flags=%d velocity=%d movetype=%d health=%d maxhealth=%d " 277 logf("netvars: flags=%d velocity=%d movetype=%d health=%d maxhealth=%d "
274 "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d lifeste=%d " 278 "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d lifeste=%d "
275 "modelindex=%d absvelocity=%d activeweapon=%d", 279 "modelindex=%d absvelocity=%d activeweapon=%d owner=%d "
280 "weapon_owner=%d",
276 g_net.flags, g_net.velocity, g_net.movetype, g_net.health, 281 g_net.flags, g_net.velocity, g_net.movetype, g_net.health,
277 g_net.maxhealth, g_net.teamnum, g_net.origin, g_net.viewoffset, 282 g_net.maxhealth, g_net.teamnum, g_net.origin, g_net.viewoffset,
278 g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex, 283 g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex,