summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-27 21:22:47 +0100
committersalmonik <salmonik@tuta.io>2026-10-27 21:22:47 +0100
commit9904891162a6749d39110110c0812a64c241a7ea (patch)
tree676eea2d0933ccb7675be6cac1481cc8208993ec
parentStucklaunch: fix prop detection and add diagnostics (diff)
downloadhl2h-9904891162a6749d39110110c0812a64c241a7ea.tar.gz
hl2h-9904891162a6749d39110110c0812a64c241a7ea.zip
Remove stucklaunch; add valuable-item ESP
- Drop the stucklaunch feature, its settings, diagnostics and m_hGroundEntity resolution. - Add a Visuals feature that scans the client entity list for valuable pickups: health/medkits/chargers, ammo boxes/crates/grenades, batteries, HEV suit modules/chargers, supply crates and generic items. - Model-first classification with class fallbacks; category toggles, distance labels and a max-distance slider. - Draw colored marker/label tags through walls, independent of the hostile NPC ESP. - Persist [items] active/bind/health/ammo/armor/crates/distance/max_dist; Reset restores defaults; GUI card and CONTEXT updated.
-rw-r--r--CONTEXT.md24
-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
7 files changed, 339 insertions, 241 deletions
diff --git a/CONTEXT.md b/CONTEXT.md
index da7138d..c5d8326 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -268,22 +268,20 @@ vocabulary / decisions.
268- Aimbot vischeck (`MASK_VISIBLE`/world-only) differs from triggerbot 268- Aimbot vischeck (`MASK_VISIBLE`/world-only) differs from triggerbot
269 (`MASK_SHOT`/all entities): glass and static props can behave differently. 269 (`MASK_SHOT`/all entities): glass and static props can behave differently.
270 270
271## Stucklaunch assist 271## Valuable items
272 272
273- Optional Movement feature; Active is off by default. 273- Visuals feature; Active is on by default and unbound (always-on).
274- While engaged it holds jump, alternates +use (or +attack/+use as a 274- Scans the client entity list every 100 ms for item models/classes and tags
275 pickup/drop cycle while the gravity gun is active) every N ticks (default 275 health, ammo, armor/suit, supply crates and generic items.
276 2), and air-strafes the hops. 276- Each tag is a colored marker with a name and optional distance, filtered by
277- Engagement comes from `m_hGroundEntity`, latched for ~0.5 s so the prop 277 category toggles and a max-distance slider. Drawn through walls and
278 stays "active" during each hop. If that netvar is unavailable it runs 278 independently of the hostile NPC ESP.
279 whenever the feature is active, so bind it to a key. 279- Detection is model-first (`models/items/...`, `models/healthvial.mdl`,
280- It does not spawn or move props. The player still supplies the prop and the 280 `models/props_combine/*_charger*.mdl`, `models/w_longjump.mdl`) with class
281 small initial speed. Pallets and brush physboxes work best. 281 fallbacks. Weapon pickups are intentionally not tagged.
282 282
283## Roadmap / TODO 283## Roadmap / TODO
284 284
285- **Stucklaunch tuning**: use-spam period, prop class coverage, and a possible
286 pause/unpause variant still need in-game testing.
287- **Server-side spread/recoil control**: not planned; recoil and accuracy 285- **Server-side spread/recoil control**: not planned; recoil and accuracy
288 penalties are intentionally left stock. 286 penalties are intentionally left stock.
289- **Distance weapon spread thesis**: addressed by Spread control; stock HL2 287- **Distance weapon spread thesis**: addressed by Spread control; stock HL2
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,