From 5e0da3a04772ed85bb31c33972223524ae59ef01 Mon Sep 17 00:00:00 2001 From: BluBerry016 <50649185+unit0016@users.noreply.github.com> Date: Mon, 6 May 2024 03:20:17 -0400 Subject: [PATCH] Ports effigy-se #814 (Leashes) (#2306) * Ports effigy-se #814 * Implements all non-signal related suggestions in preparation for the shuffling * Moves around everything but the attack logic * oops * compile fix, removes the attack signal * Replaces currently_leashed with a weakref to the component; maintains attack(), implements the rest of the signal suggestions * mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm * Fixes - New Bugs; Accidentally Comitting Something I shouldn't have; but fixes all but leash creation for realsies. And the balloon alert for unleashing * remove_leash is the final runtime issue(tm) and the final problem in general assuming everything else looks good * All but a runtime (remove shog debug before unmarking draft) * This is apparently redundant behavior. * Kill the debug prefs bypass * will this keep the good runtimes down? * Update modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> * h! * Fixes weakref implementation (oorah) * Functional! * Update modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> * Update modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> * Update modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> * mmmmmmmmmmmm * Fix dropped message; Add Resist/OOC Escape Functionality * Update modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> * Update modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm CI already fails so I'm pulling this unpatched (needs to call owner's breakouttime; not it's own) so I can bulk fix 'em all at once Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> * Update modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> * Fixes, To Test * By god; but is that (cascade) ugly! Get in here before- * mmm can you tell i'm getting tired * i did it AGAIN lmaooo. let's be glad i'm not coding something important like that jobs refactor from 2021 * Update modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm --------- Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com> --- .../_erp_disabled_item_enforcement.dm | 5 + .../lewd_items/code/lewd_items/leash.dm | 135 ++++++++++++++++++ .../code/lewd_machinery/lustwish.dm | 1 + .../modular_items/lewd_items/code/verbs.dm | 5 + tgstation.dme | 1 + 5 files changed, 147 insertions(+) create mode 100644 modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm diff --git a/modular_nova/modules/modular_items/lewd_items/code/lewd_items/_erp_disabled_item_enforcement.dm b/modular_nova/modules/modular_items/lewd_items/code/lewd_items/_erp_disabled_item_enforcement.dm index ae31c91448d..176e615653f 100644 --- a/modular_nova/modules/modular_items/lewd_items/code/lewd_items/_erp_disabled_item_enforcement.dm +++ b/modular_nova/modules/modular_items/lewd_items/code/lewd_items/_erp_disabled_item_enforcement.dm @@ -227,3 +227,8 @@ . = ..() if(CONFIG_GET(flag/disable_lewd_items)) return INITIALIZE_HINT_QDEL + +/obj/item/clothing/erp_leash/Initialize(mapload) + . = ..() + if(CONFIG_GET(flag/disable_lewd_items)) + return INITIALIZE_HINT_QDEL diff --git a/modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm b/modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm new file mode 100644 index 00000000000..fcd15308986 --- /dev/null +++ b/modular_nova/modules/modular_items/lewd_items/code/lewd_items/leash.dm @@ -0,0 +1,135 @@ +/obj/item/clothing/erp_leash + name = "leash" + desc = "A guiding hand's best friend; in a sleek, semi-elastic package. Can either clip to a collar or be affixed to the neck on its own." + icon = 'modular_nova/modules/modular_items/lewd_items/icons/obj/lewd_clothing/lewd_belts.dmi' + worn_icon = 'modular_nova/modules/modular_items/lewd_items/icons/mob/lewd_clothing/lewd_belts.dmi' + icon_state = "neckleash_pink" + equip_sound = 'sound/items/equip/toolbelt_equip.ogg' + drop_sound = 'sound/items/handling/toolbelt_drop.ogg' + slot_flags = ITEM_SLOT_BELT + breakouttime = 3 SECONDS + /// Weakref to the leash component we're using, if it exists. + var/datum/weakref/our_leash_component + + unique_reskin = list( + "Pink" = "neckleash_pink", + "Teal" = "neckleash_teal", + ) + + COOLDOWN_DECLARE(tug_cd) + +/// HERE BE DRAGONS /// + +/// Checks; leashing start +/obj/item/clothing/erp_leash/attack(mob/living/carbon/human/to_be_leashed, mob/living/user, params) + var/datum/component/leash/erp/the_leash_component = our_leash_component?.resolve() + if(the_leash_component) + if(the_leash_component.parent == to_be_leashed) // We're hooked to them; and we have a component. Get 'em out! + remove_leash(to_be_leashed) + return + else + our_leash_component = null + /// Check if we even CAN leash someone / if someone is leashing themselves. If so; prevent it. + if(!istype(to_be_leashed) || user == to_be_leashed) + return + /// Check their ERP prefs; if they don't allow sextoys: BTFO + if(!to_be_leashed.check_erp_prefs(/datum/preference/toggle/erp/sex_toy, user, src)) + to_chat(user, span_danger("[to_be_leashed] doesn't want you to do that.")) + return + /// Actually start the leashing part here + to_be_leashed.visible_message(span_warning("[user] raises the [src] to [to_be_leashed]'s neck!"),\ + span_userdanger("[user] starts to bring the [src] to your neck!"),\ + span_hear("You hear a light click as pressure builds in the air around your neck.")) + if(!do_after(user, 2 SECONDS, to_be_leashed)) + return + create_leash(user, to_be_leashed) + +/// Leash Initialization +/obj/item/clothing/erp_leash/proc/create_leash(mob/user, mob/ouppy) + if(!istype(ouppy)) + return + + ouppy.AddComponent(/datum/component/leash/erp, src, 2) + if(our_leash_component.resolve()) // The component will immediately delete itself if there's an existing one; this sanity checks for feedback on if it failed. + ouppy.balloon_alert(user, "leashed!") + return + else to_chat(user, span_danger("There's a leash attached to [ouppy] already.")) + +/// Leash removal +/obj/item/clothing/erp_leash/proc/remove_leash(mob/free_bird) + free_bird?.balloon_alert_to_viewers("unhooked") + qdel(our_leash_component.resolve()) + +/* + Leash Component +*/ + +/datum/component/leash/erp + dupe_mode = COMPONENT_DUPE_UNIQUE + dupe_type = /datum/component/leash + +// 'owner' refers the leash item, while 'parent' refers to the one it's affixed to. +/datum/component/leash/erp/RegisterWithParent() + . = ..() + // Owner Signals + RegisterSignal(owner, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_item_attack_self)) + RegisterSignal(owner, COMSIG_ITEM_DROPPED, PROC_REF(on_item_dropped)) + // Parent Signals + RegisterSignal(parent, COMSIG_LIVING_RESIST, PROC_REF(on_parent_resist)) + if(istype(owner, /obj/item/clothing/erp_leash)) + var/obj/item/clothing/erp_leash/our_leash = owner + our_leash.our_leash_component = WEAKREF(src) + +/datum/component/leash/erp/UnregisterFromParent() + if(owner) // Destroy() sets owner to null + UnregisterSignal(owner, list(COMSIG_ITEM_ATTACK_SELF, COMSIG_ITEM_DROPPED)) + UnregisterSignal(parent, COMSIG_LIVING_RESIST) + return ..() + +/datum/component/leash/erp/Destroy() // Have to do this here too + UnregisterSignal(owner, list(COMSIG_ITEM_ATTACK_SELF, COMSIG_ITEM_DROPPED)) + if(istype(owner, /obj/item/clothing/erp_leash)) + var/obj/item/clothing/erp_leash/our_leash = owner + our_leash.our_leash_component = null + return ..() + + +/datum/component/leash/erp/proc/on_item_attack_self(datum/source, mob/user) + SIGNAL_HANDLER + + if(istype(source, /obj/item/clothing/erp_leash)) + var/obj/item/clothing/erp_leash/leash_hookin = source + if(!COOLDOWN_FINISHED(leash_hookin, tug_cd)) + return + if(istype(parent, /mob/living)) + var/mob/living/yoinked = parent + yoinked.Move(get_step_towards(yoinked,user)) + yoinked.adjustStaminaLoss(10) + yoinked.visible_message(span_warning("[yoinked] is pulled in as [user] tugs the [source]!"),\ + span_userdanger("[user] suddenly tugs the [source], pulling you closer!"),\ + span_userdanger("A sudden tug against your neck pulls you ahead!")) + COOLDOWN_START(leash_hookin, tug_cd, 1 SECONDS) + +/datum/component/leash/erp/proc/on_item_dropped(datum/source, mob/user) + SIGNAL_HANDLER + + if(istype(parent, /mob)) + var/mob/our_parent = parent + our_parent.balloon_alert_to_viewers("unhooked") + qdel(src) + +/datum/component/leash/erp/proc/on_parent_resist(datum/source, mob/user) + SIGNAL_HANDLER + INVOKE_ASYNC(src, PROC_REF(do_resist)) + +/datum/component/leash/erp/proc/do_resist(datum/source, mob/user) + if(istype(parent, /mob) && istype(owner,/obj/item)) + var/mob/our_parent = parent + var/obj/item/our_owner = owner + our_parent.visible_message(span_warning("[our_parent] attempts to unhook [our_parent.p_them()]self from the leash!"), \ + span_userdanger("You start to unhook yourself from the leash..."), \ + span_userdanger("You fumble in the dark, looking to unhook the leash...")) + if(do_after(our_parent, our_owner.breakouttime, target = our_parent)) + to_chat(our_parent, span_notice("You unhook yourself from the leash.")) + qdel(src) + else qdel(src) // If they're not an item; something is very wrong - qdel anyways without the breakout time. diff --git a/modular_nova/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm b/modular_nova/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm index 90dc7d236a2..2d504344b0c 100644 --- a/modular_nova/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm +++ b/modular_nova/modules/modular_items/lewd_items/code/lewd_machinery/lustwish.dm @@ -101,6 +101,7 @@ //neck /obj/item/key/collar = 48, + /obj/item/clothing/erp_leash = 8, /obj/item/clothing/neck/kink_collar = 8, /obj/item/clothing/neck/human_petcollar = 8, /obj/item/clothing/neck/human_petcollar/choker = 8, diff --git a/modular_nova/modules/modular_items/lewd_items/code/verbs.dm b/modular_nova/modules/modular_items/lewd_items/code/verbs.dm index 6c7860b47b3..b5440aeee21 100644 --- a/modular_nova/modules/modular_items/lewd_items/code/verbs.dm +++ b/modular_nova/modules/modular_items/lewd_items/code/verbs.dm @@ -47,4 +47,9 @@ log_message("[equipped_item] was removed from [key_name(src)].", LOG_ATTACK) dropItemToGround(equipped_item, TRUE) + // Leashes are treated a smidge different than the rest of the clothing; and need their own handling here. + var/leash_check = src?.GetComponent(/datum/component/leash/erp) + if(leash_check) + qdel(leash_check) + return TRUE diff --git a/tgstation.dme b/tgstation.dme index 87bef689ffc..7fc5be527d8 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -7813,6 +7813,7 @@ #include "modular_nova\modules\modular_items\lewd_items\code\lewd_items\feather.dm" #include "modular_nova\modules\modular_items\lewd_items\code\lewd_items\fleshlight.dm" #include "modular_nova\modules\modular_items\lewd_items\code\lewd_items\kinky_shocker.dm" +#include "modular_nova\modules\modular_items\lewd_items\code\lewd_items\leash.dm" #include "modular_nova\modules\modular_items\lewd_items\code\lewd_items\leather_whip.dm" #include "modular_nova\modules\modular_items\lewd_items\code\lewd_items\magic_wand.dm" #include "modular_nova\modules\modular_items\lewd_items\code\lewd_items\pinkcuffs.dm"