Tether improvements and fixes (#89174)

## About The Pull Request

Fixes tether stacking via beacons, you can freely cut your tether while
moving, and cutting/snapping MODsuit tethers now also snaps the beacon
they're connected to if said beacon was generated by a MODsuit
projectile. Retracting the gloves or deactivating your MODsuit also
snaps MODtethers you've created using it.

Closes #88869
Closes #88866
Closes #89170

## Changelog
🆑
qol: Snapping tethers now also removes their beacons
qol: You can now cut tethers that you're attached to while in motion
qol: Tethers now snap when you retract your gloves or disable your
MODsuit
fix: Fixed tether stacking issues
/🆑
This commit is contained in:
SmArtKar
2025-01-23 19:14:30 +01:00
committed by GitHub
parent 2f13dd799e
commit e6aa18531a
3 changed files with 53 additions and 5 deletions
@@ -148,3 +148,6 @@
/// From /atom/proc/set_density(new_value) for when an atom changes density
#define COMSIG_ATOM_DENSITY_CHANGED "atom_density_change"
/// From /datum/component/tether/UnregisterFromParent()
#define COMSIG_ATOM_TETHER_SNAPPED "atom_tether_snapped"
+12 -3
View File
@@ -62,6 +62,7 @@
if (!isnull(parent_module))
RegisterSignals(parent_module, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED, COMSIG_MOD_TETHER_SNAP), PROC_REF(snap))
RegisterSignal(parent_module, COMSIG_MODULE_TRIGGERED, PROC_REF(on_parent_use))
/datum/component/tether/UnregisterFromParent()
UnregisterSignal(parent, list(COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_MOVED))
@@ -71,11 +72,13 @@
UnregisterSignal(tether_target, list(COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_MOVED, COMSIG_QDELETING))
if (!isnull(tether_trait_source) && !no_target_trait)
REMOVE_TRAIT(tether_target, TRAIT_TETHER_ATTACHED, tether_trait_source)
SEND_SIGNAL(tether_target, COMSIG_ATOM_TETHER_SNAPPED, tether_trait_source)
if (!QDELETED(tether_beam))
UnregisterSignal(tether_beam.visuals, list(COMSIG_CLICK, COMSIG_QDELETING))
qdel(tether_beam)
if (!QDELETED(embed_target))
UnregisterSignal(embed_target, list(COMSIG_ITEM_UNEMBEDDED, COMSIG_QDELETING))
SEND_SIGNAL(parent, COMSIG_ATOM_TETHER_SNAPPED, tether_trait_source)
/datum/component/tether/proc/check_tether(atom/source, new_loc)
SIGNAL_HANDLER
@@ -143,6 +146,12 @@
playsound(atom_target, 'sound/effects/snap.ogg', 50, TRUE)
qdel(src)
/datum/component/tether/proc/on_parent_use(obj/item/mod/module/module, atom/target)
SIGNAL_HANDLER
if (get_turf(target) == get_turf(tether_target))
return MOD_ABORT_USE
/datum/component/tether/proc/on_delete()
SIGNAL_HANDLER
qdel(src)
@@ -174,7 +183,7 @@
var/list/modifiers = params2list(params)
if(LAZYACCESS(modifiers, CTRL_CLICK))
location.balloon_alert(user, "cutting the tether...")
if (!do_after(user, 2 SECONDS, user))
if (!do_after(user, 2 SECONDS, user, (user == parent || user == tether_target) ? IGNORE_USER_LOC_CHANGE|IGNORE_TARGET_LOC_CHANGE : NONE))
return
qdel(src)
@@ -190,11 +199,11 @@
location.balloon_alert(user, "tether extended")
return
if (cur_dist <= 1)
if (cur_dist <= 0)
location.balloon_alert(user, "too short!")
return
if (cur_dist > get_dist(parent, tether_target))
if (cur_dist > CEILING(get_dist(parent, tether_target), 1))
cur_dist -= 1
location.balloon_alert(user, "tether shortened")
return
@@ -114,8 +114,10 @@
.["cut_tethers"] = add_ui_configuration("Cut Tethers", "button", "scissors")
/obj/item/mod/module/tether/configure_edit(key, value)
if (key != "cut_tethers")
return
if (key == "cut_tethers")
SEND_SIGNAL(src, COMSIG_MOD_TETHER_SNAP)
/obj/item/mod/module/tether/on_deactivation(display_message, deleting)
SEND_SIGNAL(src, COMSIG_MOD_TETHER_SNAP)
/obj/projectile/tether
@@ -197,6 +199,7 @@
anchor.pixel_x = hitx
anchor.pixel_y = hity
anchor.anchored = TRUE
anchor.parent_module = parent_module
firer.AddComponent(/datum/component/tether, anchor, 7, "MODtether", parent_module = parent_module, tether_trait_source = REF(parent_module))
/obj/projectile/tether/Destroy()
@@ -210,6 +213,17 @@
icon = 'icons/obj/clothing/modsuit/mod_modules.dmi'
max_integrity = 60
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT
/// MODsuit tether module that created our projectile
var/obj/item/mod/module/tether/parent_module
/obj/item/tether_anchor/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_ATOM_TETHER_SNAPPED, PROC_REF(tether_snapped))
/obj/item/tether_anchor/Destroy(force)
// We don't need to worry about hanging refs in case our parent gets destroyed because then it snaps all tethers, which in turn destroys us
parent_module = null
return ..()
/obj/item/tether_anchor/examine(mob/user)
. = ..()
@@ -229,6 +243,10 @@
balloon_alert(user, "already tethered!")
return
if (parent_module && HAS_TRAIT_FROM(user, TRAIT_TETHER_ATTACHED, REF(parent_module)))
balloon_alert(user, "already tethered!")
return
balloon_alert(user, "attached tether")
user.AddComponent(/datum/component/tether, src, 7, "tether", tether_trait_source = REF(src))
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
@@ -244,6 +262,10 @@
balloon_alert(user, "already tethered!")
return
if (parent_module && HAS_TRAIT_FROM(user, TRAIT_TETHER_ATTACHED, REF(parent_module)))
balloon_alert(user, "already tethered!")
return
if (target == user)
balloon_alert(user, "attached tether")
user.AddComponent(/datum/component/tether, src, 7, "tether", tether_trait_source = REF(src), no_target_trait = TRUE)
@@ -258,10 +280,24 @@
balloon_alert(user, "already tethered!")
return
if (parent_module && HAS_TRAIT_FROM(user, TRAIT_TETHER_ATTACHED, REF(parent_module)))
balloon_alert(user, "already tethered!")
return
balloon_alert(user, "attached tether")
to_chat(target, span_userdanger("[user] attaches a tether to you!"))
target.AddComponent(/datum/component/tether, src, 7, "tether", tether_trait_source = REF(src), no_target_trait = TRUE)
/obj/item/tether_anchor/proc/tether_snapped(datum/component/tether/tether, tether_source)
SIGNAL_HANDLER
if (!parent_module || tether_source != REF(parent_module))
return
// Destroy self if we've been created by a tether module
do_sparks(3, TRUE, src)
qdel(src)
/datum/embedding/tether_projectile
embed_chance = 65 //spiky
fall_chance = 2