mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-29 11:32:13 +00:00
Co-authored-by: Will <7099514+Willburd@users.noreply.github.com> Co-authored-by: Cameron Lennox <killer65311@gmail.com>
134 lines
5.6 KiB
Plaintext
134 lines
5.6 KiB
Plaintext
/datum/component/tethered_item
|
|
VAR_PRIVATE/obj/item/host_item
|
|
VAR_PRIVATE/held_path
|
|
VAR_PRIVATE/obj/item/hand_held
|
|
|
|
/datum/component/tethered_item/Initialize(handheld_item_path)
|
|
if(!isitem(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
held_path = handheld_item_path
|
|
host_item = parent
|
|
host_item.verbs += /obj/item/proc/toggle_tethered_handheld
|
|
host_item.actions_types += list(/datum/action/item_action/swap_tethered_item) // AddComponent for this must be called before . = ..() in Initilize()
|
|
RegisterSignal(host_item, COMSIG_ITEM_ATTACK_SELF, PROC_REF(on_attackself))
|
|
RegisterSignal(host_item, COMSIG_PARENT_ATTACKBY, PROC_REF(on_attackby))
|
|
RegisterSignal(host_item, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
|
// Link handheld
|
|
make_handheld()
|
|
|
|
/datum/component/tethered_item/Destroy()
|
|
UnregisterSignal(host_item, COMSIG_ITEM_ATTACK_SELF)
|
|
UnregisterSignal(host_item, COMSIG_PARENT_ATTACKBY)
|
|
UnregisterSignal(host_item, COMSIG_MOVABLE_MOVED)
|
|
host_item.verbs -= /obj/item/proc/toggle_tethered_handheld
|
|
host_item = null
|
|
QDEL_NULL(hand_held)
|
|
. = ..()
|
|
|
|
// Signal handling
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// !!!! IMPORTANT NOTE !!!!
|
|
// Attackself signal is used by ui action hud buttons. As it calls attack_self() directly.
|
|
// Anything that uses this component must intercept attack_hand() and emit COMSIG_ITEM_ATTACK_SELF.
|
|
// This stops you from removing the item from your backpack slot while trying to take the handheld item out.
|
|
// There's no way to block the item pickup code, so it has to be done this way. Unfortunately.
|
|
// Will return COMPONENT_NO_INTERACT if the component handled the action. Otherwise attack_hand() should resolve normally.
|
|
/datum/component/tethered_item/proc/on_attackself(obj/item/source, mob/living/carbon/human/user)
|
|
SIGNAL_HANDLER
|
|
if(hand_held.loc != host_item)
|
|
reattach_handheld()
|
|
return COMPONENT_NO_INTERACT
|
|
//Detach the handset into the user's hands
|
|
if(!slot_check())
|
|
if(ismob(host_item.loc))
|
|
to_chat(user, span_warning("You need to equip \the [host_item] before taking out \the [hand_held]."))
|
|
return
|
|
if(!user.put_in_hands(hand_held))
|
|
to_chat(user, span_warning("You need a free hand to hold the \the [hand_held]!"))
|
|
return
|
|
host_item.update_icon()
|
|
hand_held.update_icon()
|
|
to_chat(user,span_notice("You remove \the [hand_held] from \the [host_item]."))
|
|
return COMPONENT_NO_INTERACT
|
|
|
|
// Signal registry for handheld item
|
|
/datum/component/tethered_item/proc/make_handheld()
|
|
// Not directly a signal handler, but putting this anywhere else makes this way more confusing.
|
|
if(hand_held)
|
|
return
|
|
hand_held = new held_path(host_item)
|
|
hand_held.tethered_host_item = host_item
|
|
RegisterSignal(hand_held, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved))
|
|
RegisterSignal(hand_held, COMSIG_QDELETING, PROC_REF(on_qdelete_handheld))
|
|
|
|
/datum/component/tethered_item/proc/on_qdelete_handheld()
|
|
SIGNAL_HANDLER
|
|
// Safely unregister signals from handheld when it is deleted, then make a new one
|
|
UnregisterSignal(hand_held, COMSIG_MOVABLE_MOVED)
|
|
UnregisterSignal(hand_held, COMSIG_QDELETING)
|
|
hand_held.tethered_host_item = null
|
|
hand_held = null
|
|
// We normally want to remake our handheld item if it gets destroyed, but not if our host is deleting
|
|
if(!QDELETED(host_item))
|
|
make_handheld()
|
|
host_item.update_icon()
|
|
hand_held.update_icon()
|
|
|
|
// Absolutely illegal to be anywhere else except in the slot you were allowed to remove it from
|
|
/datum/component/tethered_item/proc/on_moved(atom/source, atom/oldloc, direction, forced, list/old_locs, momentum_change)
|
|
SIGNAL_HANDLER
|
|
if(hand_held.loc == host_item) // handheld item is safely inside us
|
|
return
|
|
if(slot_check() && hand_held.loc == host_item.loc) // We are safely worn by our mob, and handheld item is safely inside our mob
|
|
return
|
|
// PANIC
|
|
reattach_handheld()
|
|
|
|
// Putting the handset back into our host
|
|
/datum/component/tethered_item/proc/on_attackby(obj/item/source, obj/item/W, mob/user, params)
|
|
SIGNAL_HANDLER
|
|
if(W == hand_held)
|
|
reattach_handheld()
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
// Helpers
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/datum/component/tethered_item/proc/reattach_handheld()
|
|
// Retracts back to host
|
|
var/mob/handheld_mob = hand_held.loc
|
|
if(istype(handheld_mob))
|
|
to_chat(handheld_mob,span_notice("\The [hand_held] retracts back into \the [host_item]."))
|
|
handheld_mob.drop_from_inventory(hand_held, host_item)
|
|
else
|
|
hand_held.forceMove(host_item)
|
|
host_item.update_icon()
|
|
hand_held.update_icon()
|
|
|
|
// Some objects need to communicate the state of the handheld item back to the host
|
|
/datum/component/tethered_item/proc/get_handheld()
|
|
return hand_held
|
|
|
|
// By default this expects to be worn on your back
|
|
/datum/component/tethered_item/proc/slot_check()
|
|
var/mob/M = host_item.loc
|
|
if(!istype(M))
|
|
return FALSE
|
|
if((host_item.slot_flags & SLOT_BACK) && M.get_equipped_item(slot_back) == host_item)
|
|
return TRUE
|
|
if((host_item.slot_flags & SLOT_BELT) && M.get_equipped_item(slot_belt) == host_item)
|
|
return TRUE
|
|
if(M.get_equipped_item(slot_s_store) == host_item) // There is no flag for this, just a whitelist on the suits themselves
|
|
return TRUE
|
|
return FALSE
|
|
|
|
// Helper verbs
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/obj/item/proc/toggle_tethered_handheld()
|
|
set name = "Remove/Replace Handset"
|
|
set category = "Object"
|
|
|
|
// May only remove tethered while in the usr's direct inventory
|
|
if(src.loc != usr)
|
|
return
|
|
SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF, usr)
|