summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-10-27 20:17:07 +0100
committersalmonik <salmonik@tuta.io>2026-10-27 20:17:07 +0100
commit59432708a4ae926e4be2959dfbb2b4eb80be3fd6 (patch)
tree3233f49d2c9b3affbb97d832b4afdccbfb5f43b6 /src
parentFix tooltip truncation; add Stucklaunch assist (diff)
downloadhl2h-59432708a4ae926e4be2959dfbb2b4eb80be3fd6.tar.gz
hl2h-59432708a4ae926e4be2959dfbb2b4eb80be3fd6.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/gui.cpp4
-rw-r--r--src/hl2h.cpp34
-rw-r--r--src/hl2h.h2
-rw-r--r--src/menu.cpp14
4 files changed, 41 insertions, 13 deletions
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() {
301 "Rapidly press +use to keep regrabbing the prop.", 301 "Rapidly press +use to keep regrabbing the prop.",
302 &g_stucklaunch_use_spam); 302 &g_stucklaunch_use_spam);
303 add_toggle(sl, "Gravity gun spam", 303 add_toggle(sl, "Gravity gun spam",
304 "Rapidly press +attack while holding the gravity gun.", 304 "Alternate +attack and +use while holding the gravity gun.",
305 &g_stucklaunch_gravspam); 305 &g_stucklaunch_gravspam);
306 add_toggle(sl, "Auto-strafe", "Air-strafe each hop.", 306 add_toggle(sl, "Auto-strafe", "Air-strafe each hop.",
307 &g_stucklaunch_autostrafe); 307 &g_stucklaunch_autostrafe);
308 add_slider(sl, "Spam rate", "Ticks between spam toggles; higher is slower.",
309 1, 16, &g_stucklaunch_spam_ticks);
308 310
309 int jb = add_card(0, &g_jumpbug, "Jumpbug", 311 int jb = add_card(0, &g_jumpbug, "Jumpbug",
310 "Duck+jump when landing would hurt.", true); 312 "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) {
178 uint32_t h = *(uint32_t *)((uintptr_t)ent + g_net.groundentity); 178 uint32_t h = *(uint32_t *)((uintptr_t)ent + g_net.groundentity);
179 int gi = (h == 0xFFFFFFFFu) ? 0 : (int)(h & 0xFFFF); 179 int gi = (h == 0xFFFFFFFFu) ? 0 : (int)(h & 0xFFFF);
180 bool on = gi > 0 && gi <= 4096 && entity_is_physics_prop(gi); 180 bool on = gi > 0 && gi <= 4096 && entity_is_physics_prop(gi);
181 if (on) 181 if (on) {
182 static int prop_logs = 0;
183 if (prop_logs < 4) {
184 prop_logs++;
185 logf("stucklaunch: prop idx=%d", gi);
186 }
182 last_prop_tick = tick; 187 last_prop_tick = tick;
188 }
183 return tick - last_prop_tick < 32; // ~0.5 s at 66 tick 189 return tick - last_prop_tick < 32; // ~0.5 s at 66 tick
184} 190}
185 191
@@ -189,20 +195,28 @@ static bool stucklaunch_prop_ok(void *ent, int tick) {
189static void stucklaunch_apply(CUserCmd *cmd, void *local_ent, bool onground, 195static void stucklaunch_apply(CUserCmd *cmd, void *local_ent, bool onground,
190 const float *vel) { 196 const float *vel) {
191 cmd->buttons |= IN_JUMP; 197 cmd->buttons |= IN_JUMP;
192 int phase = (cmd->tick_count / 2) & 1; 198 int period = stucklaunch_spam_ticks();
193 if (stucklaunch_use_spam_enabled()) { 199 if (period < 1)
200 period = 1;
201 int phase = (cmd->tick_count / period) & 1;
202 bool gravity = stucklaunch_gravspam_enabled() &&
203 active_weapon_is_gravity_gun(local_ent);
204 if (gravity) {
205 // Pick up with +attack, drop with +use on the next half-cycle. Pressing
206 // both together would punt instead of regrabbing.
207 if (phase == 0) {
208 cmd->buttons |= IN_ATTACK;
209 cmd->buttons &= ~IN_USE;
210 } else {
211 cmd->buttons |= IN_USE;
212 cmd->buttons &= ~IN_ATTACK;
213 }
214 } else if (stucklaunch_use_spam_enabled()) {
194 if (phase == 0) 215 if (phase == 0)
195 cmd->buttons |= IN_USE; 216 cmd->buttons |= IN_USE;
196 else 217 else
197 cmd->buttons &= ~IN_USE; 218 cmd->buttons &= ~IN_USE;
198 } 219 }
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) 220 if (stucklaunch_autostrafe_enabled() && !onground)
207 apply_autostrafe(cmd, vel); 221 apply_autostrafe(cmd, vel);
208} 222}
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;
213extern bool g_stucklaunch_use_spam; 213extern bool g_stucklaunch_use_spam;
214extern bool g_stucklaunch_gravspam; 214extern bool g_stucklaunch_gravspam;
215extern bool g_stucklaunch_autostrafe; 215extern bool g_stucklaunch_autostrafe;
216extern int g_stucklaunch_spam_ticks;
216extern bool g_aim_bones[AIM_BONE_COUNT]; 217extern bool g_aim_bones[AIM_BONE_COUNT];
217extern int g_aim_smooth; 218extern int g_aim_smooth;
218extern bool g_aim_vischeck; 219extern bool g_aim_vischeck;
@@ -254,6 +255,7 @@ bool spread_no_spread_enabled();
254bool stucklaunch_use_spam_enabled(); 255bool stucklaunch_use_spam_enabled();
255bool stucklaunch_gravspam_enabled(); 256bool stucklaunch_gravspam_enabled();
256bool stucklaunch_autostrafe_enabled(); 257bool stucklaunch_autostrafe_enabled();
258int stucklaunch_spam_ticks();
257bool active_weapon_is_gravity_gun(void *local_ent); 259bool active_weapon_is_gravity_gun(void *local_ent);
258bool entity_is_physics_prop(int idx); 260bool entity_is_physics_prop(int idx);
259unsigned aimbot_bone_mask(); 261unsigned 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
48bool g_stucklaunch_use_spam = true; 48bool g_stucklaunch_use_spam = true;
49bool g_stucklaunch_gravspam = false; 49bool g_stucklaunch_gravspam = false;
50bool g_stucklaunch_autostrafe = true; 50bool g_stucklaunch_autostrafe = true;
51int g_stucklaunch_spam_ticks = 2;
51 52
52// Aimbot bone checklist. Head defaults on (v1 behaviour). 53// Aimbot bone checklist. Head defaults on (v1 behaviour).
53bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false, 54bool g_aim_bones[AIM_BONE_COUNT] = {true, false, false,
@@ -163,10 +164,10 @@ void config_save() {
163 g_bhop.bind, g_bhop_autostrafe); 164 g_bhop.bind, g_bhop_autostrafe);
164 fprintf(f, "[abh]\nactive=%d\nbind=%d\n", g_abh.active, g_abh.bind); 165 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 fprintf(f, "[stucklaunch]\nactive=%d\nbind=%d\nuse_spam=%d\n"
166 "gravspam=%d\nautostrafe=%d\n", 167 "gravspam=%d\nautostrafe=%d\nspam_ticks=%d\n",
167 g_stucklaunch.active, g_stucklaunch.bind, 168 g_stucklaunch.active, g_stucklaunch.bind,
168 (int)g_stucklaunch_use_spam, (int)g_stucklaunch_gravspam, 169 (int)g_stucklaunch_use_spam, (int)g_stucklaunch_gravspam,
169 (int)g_stucklaunch_autostrafe); 170 (int)g_stucklaunch_autostrafe, g_stucklaunch_spam_ticks);
170 fprintf(f, "[jumpbug]\nactive=%d\nbind=%d\nassist=%d\n", 171 fprintf(f, "[jumpbug]\nactive=%d\nbind=%d\nassist=%d\n",
171 g_jumpbug.active, g_jumpbug.bind, (int)g_jumpbug_assist); 172 g_jumpbug.active, g_jumpbug.bind, (int)g_jumpbug_assist);
172 fprintf(f, "[melee]\nactive=%d\nbind=%d\n", g_melee.active, g_melee.bind); 173 fprintf(f, "[melee]\nactive=%d\nbind=%d\n", g_melee.active, g_melee.bind);
@@ -268,6 +269,12 @@ static bool config_load() {
268 g_stucklaunch_gravspam = atoi(val) != 0; 269 g_stucklaunch_gravspam = atoi(val) != 0;
269 else if (strcmp(key, "autostrafe") == 0) 270 else if (strcmp(key, "autostrafe") == 0)
270 g_stucklaunch_autostrafe = atoi(val) != 0; 271 g_stucklaunch_autostrafe = atoi(val) != 0;
272 else if (strcmp(key, "spam_ticks") == 0) {
273 int v = atoi(val);
274 if (v < 1) v = 1;
275 if (v > 16) v = 16;
276 g_stucklaunch_spam_ticks = v;
277 }
271 } 278 }
272 if (in_aim) { 279 if (in_aim) {
273 if (strcmp(key, "smooth") == 0) { 280 if (strcmp(key, "smooth") == 0) {
@@ -351,6 +358,7 @@ void config_reset_defaults() {
351 g_stucklaunch_use_spam = true; 358 g_stucklaunch_use_spam = true;
352 g_stucklaunch_gravspam = false; 359 g_stucklaunch_gravspam = false;
353 g_stucklaunch_autostrafe = true; 360 g_stucklaunch_autostrafe = true;
361 g_stucklaunch_spam_ticks = 2;
354 g_jumpbug = {true, 0}; 362 g_jumpbug = {true, 0};
355 g_jumpbug_assist = false; 363 g_jumpbug_assist = false;
356 g_melee = {true, 0}; 364 g_melee = {true, 0};
@@ -497,6 +505,8 @@ bool stucklaunch_gravspam_enabled() { return g_stucklaunch_gravspam; }
497 505
498bool stucklaunch_autostrafe_enabled() { return g_stucklaunch_autostrafe; } 506bool stucklaunch_autostrafe_enabled() { return g_stucklaunch_autostrafe; }
499 507
508int stucklaunch_spam_ticks() { return g_stucklaunch_spam_ticks; }
509
500unsigned aimbot_bone_mask() { 510unsigned aimbot_bone_mask() {
501 unsigned m = 0; 511 unsigned m = 0;
502 if (g_aim_bones[AIM_BONE_HEAD]) 512 if (g_aim_bones[AIM_BONE_HEAD])