From 61fb177584985ab80b36dbee9f411277127c5cee Mon Sep 17 00:00:00 2001 From: Leland Kemble <70413276+lelandkemble@users.noreply.github.com> Date: Sat, 23 May 2026 11:13:25 -0400 Subject: [PATCH] Fixes several ways you could become permanently immobile (#96112) ## About The Pull Request When the `force_move()` component is applied, it registers two signals on the involved mob, to stop it moving, and a third one on the `move_loop` it's created. The signal on the created loop is there so that when the loop ends, the `force_move` component can delete itself and free the user. However, there are no checks for whether the `move_loop` was successfully created(which isn't the actual problem, although I have made it runtime there so it is easier to catch in the future). The issue is that when creating two identical moveloops, it cancels the creation of the loop, returning nothing even though there is a loop in effect. The fix was to return the existing loop in this scenario, because it's identical to what would have been made had there not been a loop already. ## Why It's Good For The Game fixes #96069 - Certain raptors transfer hits to their owners, and (this seems like an oversight in and of itself) piercing projectiles thus hit twice, which in the case of the honk staff does two slips, two `force_move`s, two loops, and triggers our identical loop problem. fixes #88352 - The issue report is vague and lacking in specific scenarios, but the mention of slipping again fixing it(which it does with this bug, as the new `force_move` component deletes the broken one) makes me pretty sure it's the same bug fixes #95994 - I'm not certain on this one because I don't know how the Parade works internally, but it seems likely that it could cause two slips on the same tile fixes #94515 - I'm just assuming this is the same bug based on it having the same symptoms ## Changelog :cl: fix: Several ways you could become permanently immobile, primarily based around lube & other methods of slipping, have been fixed /:cl: --- code/datums/components/force_move.dm | 2 ++ code/datums/move_manager.dm | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/code/datums/components/force_move.dm b/code/datums/components/force_move.dm index 62fe26d71f7..c69fa0d6c5e 100644 --- a/code/datums/components/force_move.dm +++ b/code/datums/components/force_move.dm @@ -10,6 +10,8 @@ var/mob/mob_parent = parent var/dist = get_dist(mob_parent, target) var/datum/move_loop/loop = GLOB.move_manager.move_towards(mob_parent, target, delay = 1, timeout = dist) + if(!loop) + return COMPONENT_INCOMPATIBLE RegisterSignal(mob_parent, COMSIG_MOB_CLIENT_PRE_LIVING_MOVE, PROC_REF(stop_move)) RegisterSignal(mob_parent, COMSIG_ATOM_PRE_PRESSURE_PUSH, PROC_REF(stop_pressure)) if(spin) diff --git a/code/datums/move_manager.dm b/code/datums/move_manager.dm index 23ddcbecdb7..8b74eb1fe14 100644 --- a/code/datums/move_manager.dm +++ b/code/datums/move_manager.dm @@ -88,7 +88,7 @@ GLOBAL_DATUM_INIT(move_manager, /datum/move_manager, new) return //Give up if(existing_loop?.compare_loops(arglist(args.Copy(2)))) - return //it already exists stop trying to make the same moveloop + return existing_loop //it already exists stop trying to make the same moveloop var/datum/move_loop/new_loop = new loop_type(src, subsystem, parent, priority, flags, extra_info) //Pass the mob to move and ourselves in via new var/list/arguments = args.Copy(6) //Just send the args we've not already dealt with