summaryrefslogtreecommitdiffstats
path: root/src/esp.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-05 18:09:43 +0100
committersalmonik <salmonik@tuta.io>2026-11-05 18:09:43 +0100
commita5d732920bd56c96e85db1ce2073bebf53e6b1ea (patch)
tree2692a1f19f5b6cc33d015091f3a176062ea9bcf3 /src/esp.cpp
parentGrenade trajectory: actual grenade state, full-length path, rounder rings (diff)
downloadhl2h-a5d732920bd56c96e85db1ce2073bebf53e6b1ea.tar.gz
hl2h-a5d732920bd56c96e85db1ce2073bebf53e6b1ea.zip
Items: keep health chargers visible, add charger diagnostics
The health charger's candidate m_iJuice offset (0x3c8) read 0 on a full charger, so the empty-hide made health chargers disappear entirely. Restrict the hide to suit chargers (verified 0x47c) until the health offset is confirmed; health chargers stay visible. Classify with the server class name when the client class is generic, accept `healthcharger` in the health branch (maps use item_healthcharger / CNewWallHealth, not the func_healthcharger brush), and log up to eight `juice:` lines with the class and both candidate offsets/values.
Diffstat (limited to 'src/esp.cpp')
-rw-r--r--src/esp.cpp33
1 files changed, 28 insertions, 5 deletions
diff --git a/src/esp.cpp b/src/esp.cpp
index c358b2f..3785107 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -2619,7 +2619,8 @@ static int classify_item(const char *model, const char *cls, char *label,
2619 return IK_WEAPON; 2619 return IK_WEAPON;
2620 2620
2621 if (item_icontains(cls, "healthkit") || item_icontains(cls, "healthvial") || 2621 if (item_icontains(cls, "healthkit") || item_icontains(cls, "healthvial") ||
2622 item_icontains(cls, "wallhealth")) { 2622 item_icontains(cls, "wallhealth") ||
2623 item_icontains(cls, "healthcharger")) {
2623 snprintf(label, outn, "Health"); 2624 snprintf(label, outn, "Health");
2624 return IK_HEALTH; 2625 return IK_HEALTH;
2625 } 2626 }
@@ -2668,6 +2669,13 @@ static bool item_is_charger(const char *model, const char *cls) {
2668 item_icontains(cls, "recharge"); 2669 item_icontains(cls, "recharge");
2669} 2670}
2670 2671
2672static bool item_is_suit_charger(const char *model, const char *cls) {
2673 return item_icontains(model, "suit_charger") ||
2674 item_icontains(model, "suitcharger") ||
2675 item_icontains(cls, "recharge") ||
2676 item_icontains(cls, "suitcharger");
2677}
2678
2671static void items_collect(int local_idx) { 2679static void items_collect(int local_idx) {
2672 static double last_scan = 0.0; 2680 static double last_scan = 0.0;
2673 double now = esp_now(); 2681 double now = esp_now();
@@ -2781,6 +2789,10 @@ static void items_collect(int local_idx) {
2781 if (!net) 2789 if (!net)
2782 continue; 2790 continue;
2783 const char *cls = entity_class_name(net, nullptr); 2791 const char *cls = entity_class_name(net, nullptr);
2792 const char *scls = nullptr;
2793 if (g_iface.engineserver &&
2794 (!cls || !*cls || strcmp(cls, "CBaseEntity") == 0))
2795 scls = server_entity_classname(idx);
2784 const char *model = entity_model_name(ent); 2796 const char *model = entity_model_name(ent);
2785 // CPhysicsProp's client m_nModelIndex is often 0 (e.g. item_item_crate); 2797 // CPhysicsProp's client m_nModelIndex is often 0 (e.g. item_item_crate);
2786 // fall back to the server entity's model index, which is set in Spawn(). 2798 // fall back to the server entity's model index, which is set in Spawn().
@@ -2792,13 +2804,24 @@ static void items_collect(int local_idx) {
2792 } 2804 }
2793 char label[128]; 2805 char label[128];
2794 int kind = classify_item(model, cls, label, sizeof(label)); 2806 int kind = classify_item(model, cls, label, sizeof(label));
2807 if (kind < 0 && scls)
2808 kind = classify_item(model, scls, label, sizeof(label));
2795 if (kind < 0) 2809 if (kind < 0)
2796 continue; 2810 continue;
2797 // Health/suit chargers are dispensers that stay useful after a refill, but 2811 // Health/suit chargers are dispensers that stay useful after a refill, but
2798 // an empty one cannot give anything. m_iJuice is 0 when depleted (until it 2812 // an empty suit charger cannot give anything. The health charger's
2799 // recharges); only hide the tag once the server value is readable. 2813 // m_iJuice offset is still being verified (it read 0 on a full charger),
2800 if (item_is_charger(model, cls) && server_item_juice(idx) == 0) 2814 // so it is left visible for now; server_item_juice logs both candidate
2801 continue; 2815 // values for diagnosis.
2816 bool is_charger = item_is_charger(model, cls) ||
2817 (scls && item_is_charger(model, scls));
2818 bool is_suit = item_is_suit_charger(model, cls) ||
2819 (scls && item_is_suit_charger(model, scls));
2820 if (is_charger) {
2821 int juice = server_item_juice(idx);
2822 if (is_suit && juice == 0)
2823 continue;
2824 }
2802 2825
2803 Vector origin{*(float *)((uintptr_t)ent + g_net.origin), 2826 Vector origin{*(float *)((uintptr_t)ent + g_net.origin),
2804 *(float *)((uintptr_t)ent + g_net.origin + 4), 2827 *(float *)((uintptr_t)ent + g_net.origin + 4),