From 59432708a4ae926e4be2959dfbb2b4eb80be3fd6 Mon Sep 17 00:00:00 2001 From: salmonik Date: Tue, 27 Oct 2026 20:17:07 +0100 Subject: Stucklaunch: alternate attack/use and expose spam rate - Gravity-gun spam now alternates +attack (grab) and +use (drop) instead of pressing both together, which would punt the prop. - Add a Spam rate slider (1..16 ticks, default 2) so the pickup/drop cycle can be tuned; it persists as spam_ticks in [stucklaunch]. - Log the prop index the first few times a stucklaunch engages to aid testing. --- CONTEXT.md | 6 +++--- src/gui.cpp | 4 +++- src/hl2h.cpp | 34 ++++++++++++++++++++++++---------- src/hl2h.h | 2 ++ src/menu.cpp | 14 ++++++++++++-- 5 files changed, 44 insertions(+), 16 deletions(-) diff --git a/CONTEXT.md b/CONTEXT.md index d7ea752..eccf7e2 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -267,9 +267,9 @@ vocabulary / decisions. ## Stucklaunch assist - Optional Movement feature; Active is off by default. -- While engaged it holds jump, alternates +use every 2 ticks to regrab a - physics prop, optionally alternates +attack while the gravity gun is - active, and air-strafes the hops. +- While engaged it holds jump, alternates +use (or +attack/+use as a + pickup/drop cycle while the gravity gun is active) every N ticks (default + 2), and air-strafes the hops. - Engagement comes from `m_hGroundEntity`, latched for ~0.5 s so the prop stays "active" during each hop. If that netvar is unavailable it runs whenever the feature is active, so bind it to a key. diff --git a/src/gui.cpp b/src/gui.cpp index dc0e4eb..fc95d1f 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -301,10 +301,12 @@ static void build_cards() { "Rapidly press +use to keep regrabbing the prop.", &g_stucklaunch_use_spam); add_toggle(sl, "Gravity gun spam", - "Rapidly press +attack while holding the gravity gun.", + "Alternate +attack and +use while holding the gravity gun.", &g_stucklaunch_gravspam); add_toggle(sl, "Auto-strafe", "Air-strafe each hop.", &g_stucklaunch_autostrafe); + add_slider(sl, "Spam rate", "Ticks between spam toggles; higher is slower.", + 1, 16, &g_stucklaunch_spam_ticks); int jb = add_card(0, &g_jumpbug, "Jumpbug", "Duck+jump when landing would hurt.", true); diff --git a/src/hl2h.cpp b/src/hl2h.cpp index 63fdcdc..84de815 100644 --- a/src/hl2h.cpp +++ b/src/hl2h.cpp @@ -178,8 +178,14 @@ static bool stucklaunch_prop_ok(void *ent, int tick) { uint32_t h = *(uint32_t *)((uintptr_t)ent + g_net.groundentity); int gi = (h == 0xFFFFFFFFu) ? 0 : (int)(h & 0xFFFF); bool on = gi > 0 && gi <= 4096 && entity_is_physics_prop(gi); - if (on) + if (on) { + static int prop_logs = 0; + if (prop_logs < 4) { + prop_logs++; + logf("stucklaunch: prop idx=%d", gi); + } last_prop_tick = tick; + } return tick - last_prop_tick < 32; // ~0.5 s at 66 tick } @@ -189,20 +195,28 @@ static bool stucklaunch_prop_ok(void *ent, int tick) { static void stucklaunch_apply(CUserCmd *cmd, void *local_ent, bool onground, const float *vel) { cmd->buttons |= IN_JUMP; - int phase = (cmd->tick_count / 2) & 1; - if (stucklaunch_use_spam_enabled()) { + int period = stucklaunch_spam_ticks(); + if (period < 1) + period = 1; + int phase = (cmd->tick_count / period) & 1; + bool gravity = stucklaunch_gravspam_enabled() && + active_weapon_is_gravity_gun(local_ent); + if (gravity) { + // Pick up with +attack, drop with +use on the next half-cycle. Pressing + // both together would punt instead of regrabbing. + if (phase == 0) { + cmd->buttons |= IN_ATTACK; + cmd->buttons &= ~IN_USE; + } else { + cmd->buttons |= IN_USE; + cmd->buttons &= ~IN_ATTACK; + } + } else if (stucklaunch_use_spam_enabled()) { if (phase == 0) cmd->buttons |= IN_USE; else cmd->buttons &= ~IN_USE; } - if (stucklaunch_gravspam_enabled() && - active_weapon_is_gravity_gun(local_ent)) { - if (phase == 0) - cmd->buttons |= IN_ATTACK; - else - cmd->buttons &= ~IN_ATTACK; - } if (stucklaunch_autostrafe_enabled() && !onground) apply_autostrafe(cmd, vel); } diff --git a/src/hl2h.h b/src/hl2h.h index aabe8e9..2607ece 100644 --- a/src/hl2h.h +++ b/src/hl2h.h @@ -213,6 +213,7 @@ extern bool g_spread_no_spread; extern bool g_stucklaunch_use_spam; extern bool g_stucklaunch_gravspam; extern bool g_stucklaunch_autostrafe; +extern int g_stucklaunch_spam_ticks; extern bool g_aim_bones[AIM_BONE_COUNT]; extern int g_aim_smooth; extern bool g_aim_vischeck; @@ -254,6 +255,7 @@ bool spread_no_spread_enabled(); bool stucklaunch_use_spam_enabled(); bool stucklaunch_gravspam_enabled(); bool stucklaunch_autostrafe_enabled(); +int stucklaunch_spam_ticks(); bool active_weapon_is_gravity_gun(void *local_ent); bool entity_is_physics_prop(int idx); unsigned aimbot_bone_mask(); diff --git a/src/menu.cpp b/src/menu.cpp index 00ba9be..0b8e20b 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -48,6 +48,7 @@ FeatureState g_stucklaunch{false, 0}; // opt-in movement assist bool g_stucklaunch_use_spam = true; bool g_stucklaunch_gravspam = false; bool g_stucklaunch_autostrafe = true; +int g_stucklaunch_spam_ticks = 2; // Aimbot bone checklist. Head defaults on (v1 behaviour). bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false, @@ -163,10 +164,10 @@ void config_save() { g_bhop.bind, g_bhop_autostrafe); fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); fprintf(f, "[stucklaunch]\nactive=%d\nbind=%d\nuse_spam=%d\n" - "gravspam=%d\nautostrafe=%d\n", + "gravspam=%d\nautostrafe=%d\nspam_ticks=%d\n", g_stucklaunch.active, g_stucklaunch.bind, (int)g_stucklaunch_use_spam, (int)g_stucklaunch_gravspam, - (int)g_stucklaunch_autostrafe); + (int)g_stucklaunch_autostrafe, g_stucklaunch_spam_ticks); fprintf(f, "[jumpbug]\nactive=%d\nbind=%d\nassist=%d\n", g_jumpbug.active, g_jumpbug.bind, (int)g_jumpbug_assist); fprintf(f, "[melee]\nactive=%d\nbind=%d\n", g_melee.active, g_melee.bind); @@ -268,6 +269,12 @@ static bool config_load() { g_stucklaunch_gravspam = atoi(val) != 0; else if (strcmp(key, "autostrafe") == 0) g_stucklaunch_autostrafe = atoi(val) != 0; + else if (strcmp(key, "spam_ticks") == 0) { + int v = atoi(val); + if (v < 1) v = 1; + if (v > 16) v = 16; + g_stucklaunch_spam_ticks = v; + } } if (in_aim) { if (strcmp(key, "smooth") == 0) { @@ -351,6 +358,7 @@ void config_reset_defaults() { g_stucklaunch_use_spam = true; g_stucklaunch_gravspam = false; g_stucklaunch_autostrafe = true; + g_stucklaunch_spam_ticks = 2; g_jumpbug = {true, 0}; g_jumpbug_assist = false; g_melee = {true, 0}; @@ -497,6 +505,8 @@ bool stucklaunch_gravspam_enabled() { return g_stucklaunch_gravspam; } bool stucklaunch_autostrafe_enabled() { return g_stucklaunch_autostrafe; } +int stucklaunch_spam_ticks() { return g_stucklaunch_spam_ticks; } + unsigned aimbot_bone_mask() { unsigned m = 0; if (g_aim_bones[AIM_BONE_HEAD]) -- cgit v1.2.3