summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTEXT.md20
-rw-r--r--src/esp.cpp34
-rw-r--r--src/gui.cpp47
-rw-r--r--src/hl2h.cpp54
-rw-r--r--src/hl2h.h15
-rw-r--r--src/menu.cpp40
-rw-r--r--src/netvars.cpp5
7 files changed, 190 insertions, 25 deletions
diff --git a/CONTEXT.md b/CONTEXT.md
index 78f7c75..d7ea752 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -264,12 +264,24 @@ vocabulary / decisions.
264- Aimbot vischeck (`MASK_VISIBLE`/world-only) differs from triggerbot 264- Aimbot vischeck (`MASK_VISIBLE`/world-only) differs from triggerbot
265 (`MASK_SHOT`/all entities): glass and static props can behave differently. 265 (`MASK_SHOT`/all entities): glass and static props can behave differently.
266 266
267## Stucklaunch assist
268
269- Optional Movement feature; Active is off by default.
270- While engaged it holds jump, alternates +use every 2 ticks to regrab a
271 physics prop, optionally alternates +attack while the gravity gun is
272 active, and air-strafes the hops.
273- Engagement comes from `m_hGroundEntity`, latched for ~0.5 s so the prop
274 stays "active" during each hop. If that netvar is unavailable it runs
275 whenever the feature is active, so bind it to a key.
276- It does not spawn or move props. The player still supplies the prop and the
277 small initial speed. Pallets and brush physboxes work best.
278
267## Roadmap / TODO 279## Roadmap / TODO
268 280
269- **GUI**: replace/augment the VGUI ISurface menu with an immediate-mode GUI 281- **Stucklaunch tuning**: use-spam period, prop class coverage, and a possible
270 (Dear ImGui or a custom implementation); needs a design grill first. 282 pause/unpause variant still need in-game testing.
271- **Server-side spread/recoil control**: optional single-player writes to the 283- **Server-side spread/recoil control**: not planned; recoil and accuracy
272 pistol accuracy penalty and view punch, and a true zero-cone hook if wanted. 284 penalties are intentionally left stock.
273- **Distance weapon spread thesis**: addressed by Spread control; stock HL2 285- **Distance weapon spread thesis**: addressed by Spread control; stock HL2
274 hitscan damage is range-independent, so distance efficiency is the cone. 286 hitscan damage is range-independent, so distance efficiency is the cone.
275 287
diff --git a/src/esp.cpp b/src/esp.cpp
index 64ee83f..bda6232 100644
--- a/src/esp.cpp
+++ b/src/esp.cpp
@@ -1131,6 +1131,40 @@ static void spread_compute() {
1131 g_spread_ready = true; 1131 g_spread_ready = true;
1132} 1132}
1133 1133
1134bool entity_is_physics_prop(int idx) {
1135 if (idx <= 0 || idx > 4096)
1136 return false;
1137 void *net = entity_networkable(idx);
1138 const char *cls = net ? entity_class_name(net, nullptr) : nullptr;
1139 void *ent = entitylist_get(idx);
1140 const char *model = ent ? entity_model_name(ent) : nullptr;
1141 if (cls && (strstr(cls, "prop_physics") || strstr(cls, "physbox")))
1142 return true;
1143 if (model && (strstr(model, "props_junk") || strstr(model, "props_physics")))
1144 return true;
1145 return false;
1146}
1147
1148bool active_weapon_is_gravity_gun(void *local_ent) {
1149 if (!local_ent || g_net.activeweapon < 0)
1150 return false;
1151 uint32_t h = *(uint32_t *)((uintptr_t)local_ent + g_net.activeweapon);
1152 if (h == 0xFFFFFFFFu)
1153 return false;
1154 int idx = (int)(h & 0xFFFF);
1155 if (idx <= 0 || idx > 4096)
1156 return false;
1157 void *wep = entitylist_get(idx);
1158 void *net = entity_networkable(idx);
1159 const char *cls = net ? entity_class_name(net, nullptr) : nullptr;
1160 const char *model = wep ? entity_model_name(wep) : nullptr;
1161 if (cls && strstr(cls, "physcannon"))
1162 return true;
1163 if (model && (strstr(model, "physcannon") || strstr(model, "w_physics")))
1164 return true;
1165 return false;
1166}
1167
1134static bool active_weapon_is_shotgun(void *local_ent) { 1168static bool active_weapon_is_shotgun(void *local_ent) {
1135 if (!local_ent || g_net.activeweapon < 0) 1169 if (!local_ent || g_net.activeweapon < 0)
1136 return false; 1170 return false;
diff --git a/src/gui.cpp b/src/gui.cpp
index 0d5b458..dc0e4eb 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -293,6 +293,19 @@ static void build_cards() {
293 add_card(0, &g_abh, "ABH", "Accelerate on the jump tick by facing away " 293 add_card(0, &g_abh, "ABH", "Accelerate on the jump tick by facing away "
294 "from the velocity.", true); 294 "from the velocity.", true);
295 295
296 int sl = add_card(0, &g_stucklaunch, "Stucklaunch",
297 "Hop on a physics prop while spamming grab to build "
298 "speed in a small space.",
299 true);
300 add_toggle(sl, "Use spam",
301 "Rapidly press +use to keep regrabbing the prop.",
302 &g_stucklaunch_use_spam);
303 add_toggle(sl, "Gravity gun spam",
304 "Rapidly press +attack while holding the gravity gun.",
305 &g_stucklaunch_gravspam);
306 add_toggle(sl, "Auto-strafe", "Air-strafe each hop.",
307 &g_stucklaunch_autostrafe);
308
296 int jb = add_card(0, &g_jumpbug, "Jumpbug", 309 int jb = add_card(0, &g_jumpbug, "Jumpbug",
297 "Duck+jump when landing would hurt.", true); 310 "Duck+jump when landing would hurt.", true);
298 add_toggle(jb, "Assist timing", 311 add_toggle(jb, "Assist timing",
@@ -523,26 +536,40 @@ static void text_in(const Rect &clip, int x, int y, const char *s,
523 return; 536 return;
524 if (x >= clip.x + clip.w) 537 if (x >= clip.x + clip.w)
525 return; 538 return;
526 if (x + text_w(s, tall) > clip.x + clip.w) 539
527 x = clip.x + clip.w - text_w(s, tall); 540 // Available space from x to the clip edge, optionally capped by max_w.
528 if (max_w > 0 && text_w(s, tall) > max_w) { 541 // Truncate first, then clamp: shifting before truncating used to draw the
529 char buf[256]; 542 // text outside the tooltip/button box.
543 int avail = clip.x + clip.w - x;
544 if (max_w > 0 && max_w < avail)
545 avail = max_w;
546 if (avail <= 0)
547 return;
548
549 char buf[256];
550 const char *draw = s;
551 int w = text_w(s, tall);
552 if (w > avail) {
530 snprintf(buf, sizeof(buf), "%s", s); 553 snprintf(buf, sizeof(buf), "%s", s);
531 int n = (int)strlen(buf); 554 int n = (int)strlen(buf);
532 while (n > 3 && text_w(buf, tall) > max_w) 555 int dots = text_w("...", tall);
556 while (n > 0 && text_w(buf, tall) + dots > avail)
533 buf[--n] = 0; 557 buf[--n] = 0;
534 if (n > 3 && n < (int)sizeof(buf) - 3) { 558 if (n > 0 && n + 3 < (int)sizeof(buf)) {
535 buf[n++] = '.'; 559 buf[n++] = '.';
536 buf[n++] = '.'; 560 buf[n++] = '.';
537 buf[n++] = '.'; 561 buf[n++] = '.';
538 buf[n] = 0; 562 buf[n] = 0;
539 } 563 }
540 s_text_color(c.r, c.g, c.b, c.a); 564 draw = buf;
541 draw_text_raw(x, y, buf, font, tall); 565 w = text_w(draw, tall);
542 return;
543 } 566 }
567 if (x + w > clip.x + clip.w)
568 x = clip.x + clip.w - w;
569 if (x < clip.x)
570 x = clip.x;
544 s_text_color(c.r, c.g, c.b, c.a); 571 s_text_color(c.r, c.g, c.b, c.a);
545 draw_text_raw(x, y, s, font, tall); 572 draw_text_raw(x, y, draw, font, tall);
546} 573}
547 574
548static Rect clip_rect(const Rect &r, const Rect &clip) { 575static Rect clip_rect(const Rect &r, const Rect &clip) {
diff --git a/src/hl2h.cpp b/src/hl2h.cpp
index c51d35e..63fdcdc 100644
--- a/src/hl2h.cpp
+++ b/src/hl2h.cpp
@@ -169,6 +169,44 @@ 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 return true; // no netvar: the bind is the only safeguard
177 static int last_prop_tick = -100000;
178 uint32_t h = *(uint32_t *)((uintptr_t)ent + g_net.groundentity);
179 int gi = (h == 0xFFFFFFFFu) ? 0 : (int)(h & 0xFFFF);
180 bool on = gi > 0 && gi <= 4096 && entity_is_physics_prop(gi);
181 if (on)
182 last_prop_tick = tick;
183 return tick - last_prop_tick < 32; // ~0.5 s at 66 tick
184}
185
186// Stucklaunch assist. The player supplies the physics prop and a little
187// initial speed; this holds jump, alternates +use (and optionally the gravity
188// gun's +attack) to keep regrabbing the prop, and air-strafes the hops.
189static void stucklaunch_apply(CUserCmd *cmd, void *local_ent, bool onground,
190 const float *vel) {
191 cmd->buttons |= IN_JUMP;
192 int phase = (cmd->tick_count / 2) & 1;
193 if (stucklaunch_use_spam_enabled()) {
194 if (phase == 0)
195 cmd->buttons |= IN_USE;
196 else
197 cmd->buttons &= ~IN_USE;
198 }
199 if (stucklaunch_gravspam_enabled() &&
200 active_weapon_is_gravity_gun(local_ent)) {
201 if (phase == 0)
202 cmd->buttons |= IN_ATTACK;
203 else
204 cmd->buttons &= ~IN_ATTACK;
205 }
206 if (stucklaunch_autostrafe_enabled() && !onground)
207 apply_autostrafe(cmd, vel);
208}
209
172// --------------------------------------------------------------------------- 210// ---------------------------------------------------------------------------
173// jumpbug 211// jumpbug
174// --------------------------------------------------------------------------- 212// ---------------------------------------------------------------------------
@@ -576,8 +614,15 @@ static void do_move(int seq, float frametime) {
576 return; 614 return;
577 } 615 }
578 616
579 bool bhop_on = feature_active(FEAT_BHOP); 617 bool stuck_on = feature_active(FEAT_STUCKLAUNCH);
580 bool abh_on = feature_active(FEAT_ABH); 618 bool stuck_engaged = stuck_on && stucklaunch_prop_ok(ent, cmd->tick_count);
619 if (stuck_engaged) {
620 stucklaunch_apply(cmd, ent, onground, vel);
621 note_modified(cmd, flags, vel);
622 }
623
624 bool bhop_on = !stuck_engaged && feature_active(FEAT_BHOP);
625 bool abh_on = !stuck_engaged && feature_active(FEAT_ABH);
581 626
582 static bool lastground = false; 627 static bool lastground = false;
583 628
@@ -628,7 +673,8 @@ static void do_move(int seq, float frametime) {
628 } 673 }
629 } 674 }
630 675
631 if (jumpbug_apply(cmd, localIdx, ent, flags, vel, frametime)) 676 if (!stuck_engaged &&
677 jumpbug_apply(cmd, localIdx, ent, flags, vel, frametime))
632 note_modified(cmd, flags, vel); 678 note_modified(cmd, flags, vel);
633 679
634 bool melee = feature_active(FEAT_MELEE) && melee_weapon_active(ent); 680 bool melee = feature_active(FEAT_MELEE) && melee_weapon_active(ent);
@@ -866,6 +912,8 @@ static void *setup_thread(void *) {
866 toastf(TOAST_ERROR, "Netvars incomplete; features may be disabled"); 912 toastf(TOAST_ERROR, "Netvars incomplete; features may be disabled");
867 else if (g_net.absvelocity < 0) 913 else if (g_net.absvelocity < 0)
868 toastf(TOAST_WARN, "Jumpbug assist disabled: velocity netvar missing"); 914 toastf(TOAST_WARN, "Jumpbug assist disabled: velocity netvar missing");
915 if (g_net.groundentity < 0)
916 toastf(TOAST_WARN, "Stucklaunch prop detection unavailable; bind it");
869 if (!g_iface.engineserver) 917 if (!g_iface.engineserver)
870 toastf(TOAST_WARN, "Server interfaces missing; jumpbug/spread limited"); 918 toastf(TOAST_WARN, "Server interfaces missing; jumpbug/spread limited");
871 if (!g_iface.debugoverlay) 919 if (!g_iface.debugoverlay)
diff --git a/src/hl2h.h b/src/hl2h.h
index e390aa0..aabe8e9 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -92,6 +92,7 @@ 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
95 // ponytail: mins/maxs may be absent from some HL2 netvar tables; esp.cpp falls back to h=72 96 // 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; } 97 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. 98 // ponytail: m_iMaxHealth isn't a netvar in HL2 SP; esp.cpp falls back to 100.
@@ -171,7 +172,9 @@ enum FeatureId {
171 FEAT_SILENTAIM = 5, 172 FEAT_SILENTAIM = 5,
172 FEAT_JUMPBUG = 6, 173 FEAT_JUMPBUG = 6,
173 FEAT_MELEE = 7, 174 FEAT_MELEE = 7,
174 FEAT_SPREAD = 8 175 FEAT_SPREAD = 8,
176 FEAT_STUCKLAUNCH = 9,
177 FEAT_COUNT = 10
175}; 178};
176enum EspOption { 179enum EspOption {
177 ESP_OPT_SHOW_NEUTRAL = 0, 180 ESP_OPT_SHOW_NEUTRAL = 0,
@@ -203,10 +206,13 @@ struct FeatureState {
203}; 206};
204 207
205extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp, 208extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp,
206 g_aimbot, g_triggerbot, g_silentaim; 209 g_aimbot, g_triggerbot, g_silentaim, g_stucklaunch;
207extern bool g_bhop_autostrafe; 210extern bool g_bhop_autostrafe;
208extern bool g_jumpbug_assist; 211extern bool g_jumpbug_assist;
209extern bool g_spread_no_spread; 212extern bool g_spread_no_spread;
213extern bool g_stucklaunch_use_spam;
214extern bool g_stucklaunch_gravspam;
215extern bool g_stucklaunch_autostrafe;
210extern bool g_aim_bones[AIM_BONE_COUNT]; 216extern bool g_aim_bones[AIM_BONE_COUNT];
211extern int g_aim_smooth; 217extern int g_aim_smooth;
212extern bool g_aim_vischeck; 218extern bool g_aim_vischeck;
@@ -245,6 +251,11 @@ bool esp_option(int opt);
245bool bhop_autostrafe_enabled(); 251bool bhop_autostrafe_enabled();
246bool jumpbug_assist_enabled(); 252bool jumpbug_assist_enabled();
247bool spread_no_spread_enabled(); 253bool spread_no_spread_enabled();
254bool stucklaunch_use_spam_enabled();
255bool stucklaunch_gravspam_enabled();
256bool stucklaunch_autostrafe_enabled();
257bool active_weapon_is_gravity_gun(void *local_ent);
258bool entity_is_physics_prop(int idx);
248unsigned aimbot_bone_mask(); 259unsigned aimbot_bone_mask();
249int aimbot_smooth_step(); 260int aimbot_smooth_step();
250bool aimbot_vischeck_enabled(); 261bool aimbot_vischeck_enabled();
diff --git a/src/menu.cpp b/src/menu.cpp
index 3d008bb..00ba9be 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -44,6 +44,10 @@ 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
48bool g_stucklaunch_use_spam = true;
49bool g_stucklaunch_gravspam = false;
50bool g_stucklaunch_autostrafe = true;
47 51
48// Aimbot bone checklist. Head defaults on (v1 behaviour). 52// Aimbot bone checklist. Head defaults on (v1 behaviour).
49bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false, 53bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false,
@@ -158,6 +162,11 @@ void config_save() {
158 fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active, 162 fprintf(f, "[bhop]\nactive=%d\nbind=%d\nautostrafe=%d\n", g_bhop.active,
159 g_bhop.bind, g_bhop_autostrafe); 163 g_bhop.bind, g_bhop_autostrafe);
160 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); 164 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind);
165 fprintf(f, "[stucklaunch]\nactive=%d\nbind=%d\nuse_spam=%d\n"
166 "gravspam=%d\nautostrafe=%d\n",
167 g_stucklaunch.active, g_stucklaunch.bind,
168 (int)g_stucklaunch_use_spam, (int)g_stucklaunch_gravspam,
169 (int)g_stucklaunch_autostrafe);
161 fprintf(f, "[jumpbug]\nactive=%d\nbind=%d\nassist=%d\n", 170 fprintf(f, "[jumpbug]\nactive=%d\nbind=%d\nassist=%d\n",
162 g_jumpbug.active, g_jumpbug.bind, (int)g_jumpbug_assist); 171 g_jumpbug.active, g_jumpbug.bind, (int)g_jumpbug_assist);
163 fprintf(f, "[melee]\nactive=%d\nbind=%d\n", g_melee.active, g_melee.bind); 172 fprintf(f, "[melee]\nactive=%d\nbind=%d\n", g_melee.active, g_melee.bind);
@@ -204,7 +213,7 @@ static bool config_load() {
204 char line[256]; 213 char line[256];
205 FeatureState *cur = nullptr; 214 FeatureState *cur = nullptr;
206 bool in_esp = false, in_bhop = false, in_aim = false, in_silent = false, 215 bool in_esp = false, in_bhop = false, in_aim = false, in_silent = false,
207 in_jumpbug = false, in_spread = false; 216 in_jumpbug = false, in_spread = false, in_stucklaunch = false;
208 while (fgets(line, sizeof(line), f)) { 217 while (fgets(line, sizeof(line), f)) {
209 line[strcspn(line, "\r\n")] = 0; 218 line[strcspn(line, "\r\n")] = 0;
210 if (line[0] == '[') { 219 if (line[0] == '[') {
@@ -212,6 +221,8 @@ static bool config_load() {
212 cur = &g_bhop; 221 cur = &g_bhop;
213 else if (strstr(line, "[abh]")) 222 else if (strstr(line, "[abh]"))
214 cur = &g_abh; 223 cur = &g_abh;
224 else if (strstr(line, "[stucklaunch]"))
225 cur = &g_stucklaunch;
215 else if (strstr(line, "[jumpbug]")) 226 else if (strstr(line, "[jumpbug]"))
216 cur = &g_jumpbug; 227 cur = &g_jumpbug;
217 else if (strstr(line, "[melee]")) 228 else if (strstr(line, "[melee]"))
@@ -234,6 +245,7 @@ static bool config_load() {
234 in_silent = (cur == &g_silentaim); 245 in_silent = (cur == &g_silentaim);
235 in_jumpbug = (cur == &g_jumpbug); 246 in_jumpbug = (cur == &g_jumpbug);
236 in_spread = (cur == &g_spread); 247 in_spread = (cur == &g_spread);
248 in_stucklaunch = (cur == &g_stucklaunch);
237 } else if (cur) { 249 } else if (cur) {
238 char *eq = strchr(line, '='); 250 char *eq = strchr(line, '=');
239 if (!eq) 251 if (!eq)
@@ -249,6 +261,14 @@ static bool config_load() {
249 if (in_spread && strcmp(key, "no_spread") == 0) { 261 if (in_spread && strcmp(key, "no_spread") == 0) {
250 g_spread_no_spread = atoi(val) != 0; 262 g_spread_no_spread = atoi(val) != 0;
251 } 263 }
264 if (in_stucklaunch) {
265 if (strcmp(key, "use_spam") == 0)
266 g_stucklaunch_use_spam = atoi(val) != 0;
267 else if (strcmp(key, "gravspam") == 0)
268 g_stucklaunch_gravspam = atoi(val) != 0;
269 else if (strcmp(key, "autostrafe") == 0)
270 g_stucklaunch_autostrafe = atoi(val) != 0;
271 }
252 if (in_aim) { 272 if (in_aim) {
253 if (strcmp(key, "smooth") == 0) { 273 if (strcmp(key, "smooth") == 0) {
254 int v = atoi(val); 274 int v = atoi(val);
@@ -327,6 +347,10 @@ void config_reset_defaults() {
327 g_bhop = {true, 0}; 347 g_bhop = {true, 0};
328 g_bhop_autostrafe = true; 348 g_bhop_autostrafe = true;
329 g_abh = {true, 0}; 349 g_abh = {true, 0};
350 g_stucklaunch = {false, 0};
351 g_stucklaunch_use_spam = true;
352 g_stucklaunch_gravspam = false;
353 g_stucklaunch_autostrafe = true;
330 g_jumpbug = {true, 0}; 354 g_jumpbug = {true, 0};
331 g_jumpbug_assist = false; 355 g_jumpbug_assist = false;
332 g_melee = {true, 0}; 356 g_melee = {true, 0};
@@ -432,10 +456,10 @@ static bool key_held(int sc) {
432// feature gate queried from hl2h.cpp do_move(): feature must be Active AND 456// feature gate queried from hl2h.cpp do_move(): feature must be Active AND
433// its bind key held (always-on when unbound). 457// its bind key held (always-on when unbound).
434static FeatureState *feature_state(int feature) { 458static FeatureState *feature_state(int feature) {
435 static FeatureState *feats[9] = {&g_bhop, &g_abh, &g_esp, 459 static FeatureState *feats[FEAT_COUNT] = {
436 &g_aimbot, &g_triggerbot, &g_silentaim, 460 &g_bhop, &g_abh, &g_esp, &g_aimbot, &g_triggerbot,
437 &g_jumpbug, &g_melee, &g_spread}; 461 &g_silentaim, &g_jumpbug, &g_melee, &g_spread, &g_stucklaunch};
438 if (feature < 0 || feature > 8) 462 if (feature < 0 || feature >= FEAT_COUNT)
439 return nullptr; 463 return nullptr;
440 return feats[feature]; 464 return feats[feature];
441} 465}
@@ -467,6 +491,12 @@ bool jumpbug_assist_enabled() { return g_jumpbug_assist; }
467 491
468bool spread_no_spread_enabled() { return g_spread_no_spread; } 492bool spread_no_spread_enabled() { return g_spread_no_spread; }
469 493
494bool stucklaunch_use_spam_enabled() { return g_stucklaunch_use_spam; }
495
496bool stucklaunch_gravspam_enabled() { return g_stucklaunch_gravspam; }
497
498bool stucklaunch_autostrafe_enabled() { return g_stucklaunch_autostrafe; }
499
470unsigned aimbot_bone_mask() { 500unsigned aimbot_bone_mask() {
471 unsigned m = 0; 501 unsigned m = 0;
472 if (g_aim_bones[AIM_BONE_HEAD]) 502 if (g_aim_bones[AIM_BONE_HEAD])
diff --git a/src/netvars.cpp b/src/netvars.cpp
index 3b2d3b8..e304317 100644
--- a/src/netvars.cpp
+++ b/src/netvars.cpp
@@ -92,6 +92,9 @@ 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);
95 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) { 98 } else if (strcmp(pname2, "m_iTeamNum") == 0 && g_net.teamnum < 0) {
96 g_net.teamnum = (int)(base_off + (uint32_t)poff); 99 g_net.teamnum = (int)(base_off + (uint32_t)poff);
97 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) { 100 } else if (strcmp(pname2, "m_vecOrigin") == 0 && g_net.origin < 0) {
@@ -272,7 +275,7 @@ void resolve_netvars() {
272 logf("m_vecAbsVelocity unresolved; jumpbug assist disabled"); 275 logf("m_vecAbsVelocity unresolved; jumpbug assist disabled");
273 logf("netvars: flags=%d velocity=%d movetype=%d health=%d maxhealth=%d " 276 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 " 277 "teamnum=%d origin=%d viewoffset=%d mins=%d maxs=%d lifeste=%d "
275 "modelindex=%d absvelocity=%d activeweapon=%d", 278 "modelindex=%d absvelocity=%d activeweapon=%d groundentity=%d",
276 g_net.flags, g_net.velocity, g_net.movetype, g_net.health, 279 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, 280 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, 281 g_net.mins, g_net.maxs, g_net.lifestate, g_net.modelindex,