diff options
| author | salmonik <salmonik@tuta.io> | 2026-10-27 20:15:51 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-10-27 20:15:51 +0100 |
| commit | ba500fef7fbf94725f18541b0e23a45591379dba (patch) | |
| tree | f1eec8ad34e532fb7bcb9172083c78d96bcdca4f /src | |
| parent | Overlay: keep GUI and toasts drawing if the ESP font fails (diff) | |
| download | hl2h-ba500fef7fbf94725f18541b0e23a45591379dba.tar.gz hl2h-ba500fef7fbf94725f18541b0e23a45591379dba.zip | |
Fix tooltip truncation; add Stucklaunch assist
Tooltips: text_in() shifted the x position to fit the full string before
truncating, which drew the tooltip text outside its box. Truncate to the
available width first, then clamp inside the clip.
Stucklaunch (Movement):
- opt-in feature (Active off by default) with its own bind;
- holds jump, alternates +use every 2 ticks to regrab a physics prop,
optionally +attack while the gravity gun is active, and air-strafes;
- engagement uses m_hGroundEntity (client netvar) latched for ~0.5 s so the
prop stays active while airborne; falls back to running whenever active if
the netvar is unavailable, with a startup warning to bind it;
- does not spawn or place props; the player supplies the prop and initial
speed.
Config gets [stucklaunch] active/bind/use_spam/gravspam/autostrafe; Reset
restores those defaults. CONTEXT documents the assist and its limits.
Diffstat (limited to 'src')
| -rw-r--r-- | src/esp.cpp | 34 | ||||
| -rw-r--r-- | src/gui.cpp | 47 | ||||
| -rw-r--r-- | src/hl2h.cpp | 54 | ||||
| -rw-r--r-- | src/hl2h.h | 15 | ||||
| -rw-r--r-- | src/menu.cpp | 40 | ||||
| -rw-r--r-- | src/netvars.cpp | 5 |
6 files changed, 174 insertions, 21 deletions
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 | ||
| 1134 | bool 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 | |||
| 1148 | bool 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 | |||
| 1134 | static bool active_weapon_is_shotgun(void *local_ent) { | 1168 | static 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 | ||
| 548 | static Rect clip_rect(const Rect &r, const Rect &clip) { | 575 | static 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. | ||
| 174 | static 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. | ||
| 189 | static 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) |
| @@ -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 | }; |
| 176 | enum EspOption { | 179 | enum EspOption { |
| 177 | ESP_OPT_SHOW_NEUTRAL = 0, | 180 | ESP_OPT_SHOW_NEUTRAL = 0, |
| @@ -203,10 +206,13 @@ struct FeatureState { | |||
| 203 | }; | 206 | }; |
| 204 | 207 | ||
| 205 | extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp, | 208 | extern 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; |
| 207 | extern bool g_bhop_autostrafe; | 210 | extern bool g_bhop_autostrafe; |
| 208 | extern bool g_jumpbug_assist; | 211 | extern bool g_jumpbug_assist; |
| 209 | extern bool g_spread_no_spread; | 212 | extern bool g_spread_no_spread; |
| 213 | extern bool g_stucklaunch_use_spam; | ||
| 214 | extern bool g_stucklaunch_gravspam; | ||
| 215 | extern bool g_stucklaunch_autostrafe; | ||
| 210 | extern bool g_aim_bones[AIM_BONE_COUNT]; | 216 | extern bool g_aim_bones[AIM_BONE_COUNT]; |
| 211 | extern int g_aim_smooth; | 217 | extern int g_aim_smooth; |
| 212 | extern bool g_aim_vischeck; | 218 | extern bool g_aim_vischeck; |
| @@ -245,6 +251,11 @@ bool esp_option(int opt); | |||
| 245 | bool bhop_autostrafe_enabled(); | 251 | bool bhop_autostrafe_enabled(); |
| 246 | bool jumpbug_assist_enabled(); | 252 | bool jumpbug_assist_enabled(); |
| 247 | bool spread_no_spread_enabled(); | 253 | bool spread_no_spread_enabled(); |
| 254 | bool stucklaunch_use_spam_enabled(); | ||
| 255 | bool stucklaunch_gravspam_enabled(); | ||
| 256 | bool stucklaunch_autostrafe_enabled(); | ||
| 257 | bool active_weapon_is_gravity_gun(void *local_ent); | ||
| 258 | bool entity_is_physics_prop(int idx); | ||
| 248 | unsigned aimbot_bone_mask(); | 259 | unsigned aimbot_bone_mask(); |
| 249 | int aimbot_smooth_step(); | 260 | int aimbot_smooth_step(); |
| 250 | bool aimbot_vischeck_enabled(); | 261 | bool 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}; | |||
| 44 | FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in the GUI | 44 | FeatureState g_aimbot{true, 604}; // default Mouse5, rebindable in the GUI |
| 45 | FeatureState g_triggerbot{true, 603}; // default Mouse4 | 45 | FeatureState g_triggerbot{true, 603}; // default Mouse4 |
| 46 | FeatureState g_silentaim{true, 602}; // default Mouse3 | 46 | FeatureState g_silentaim{true, 602}; // default Mouse3 |
| 47 | FeatureState g_stucklaunch{false, 0}; // opt-in movement assist | ||
| 48 | bool g_stucklaunch_use_spam = true; | ||
| 49 | bool g_stucklaunch_gravspam = false; | ||
| 50 | bool g_stucklaunch_autostrafe = true; | ||
| 47 | 51 | ||
| 48 | // Aimbot bone checklist. Head defaults on (v1 behaviour). | 52 | // Aimbot bone checklist. Head defaults on (v1 behaviour). |
| 49 | bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false, | 53 | bool 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). |
| 434 | static FeatureState *feature_state(int feature) { | 458 | static 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 | ||
| 468 | bool spread_no_spread_enabled() { return g_spread_no_spread; } | 492 | bool spread_no_spread_enabled() { return g_spread_no_spread; } |
| 469 | 493 | ||
| 494 | bool stucklaunch_use_spam_enabled() { return g_stucklaunch_use_spam; } | ||
| 495 | |||
| 496 | bool stucklaunch_gravspam_enabled() { return g_stucklaunch_gravspam; } | ||
| 497 | |||
| 498 | bool stucklaunch_autostrafe_enabled() { return g_stucklaunch_autostrafe; } | ||
| 499 | |||
| 470 | unsigned aimbot_bone_mask() { | 500 | unsigned 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, |
