mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-14 19:51:59 +00:00
* Refactors species mutanthands into human component * wew --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
171 lines
6.1 KiB
Plaintext
171 lines
6.1 KiB
Plaintext
/**
|
|
* ## Mutant hands component
|
|
*
|
|
* This component applies to humans, and forces them to hold
|
|
* a certain typepath item in every hand no matter what*.
|
|
*
|
|
* For example, zombies being forced to hold "zombie claws" - disallowing them from holding items
|
|
* but giving them powerful weapons to infect people
|
|
*
|
|
* It is suggested that the item path supplied has NODROP (and likely DROPDEL),
|
|
* but nothing's preventing you from not having that.
|
|
*
|
|
* If they lose or gain hands, new mutant hands will be created immediately.
|
|
*
|
|
* Does not override nodrop items that already exist in hand slots.
|
|
* However if those nodrop items are lost, will immediately create a new mutant hand.
|
|
*/
|
|
/datum/component/mutant_hands
|
|
// First come, first serve
|
|
dupe_mode = COMPONENT_DUPE_UNIQUE
|
|
/// The item typepath that we insert into the parent's hands
|
|
var/obj/item/mutant_hand_path = /obj/item/mutant_hand
|
|
|
|
/datum/component/mutant_hands/Initialize(obj/item/mutant_hand_path = /obj/item/mutant_hand)
|
|
if(!ishuman(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
src.mutant_hand_path = mutant_hand_path
|
|
|
|
/datum/component/mutant_hands/RegisterWithParent()
|
|
// Give them a hand before registering ANYTHING just so it's clean
|
|
INVOKE_ASYNC(src, PROC_REF(apply_mutant_hands))
|
|
|
|
RegisterSignals(parent, list(COMSIG_CARBON_POST_ATTACH_LIMB, COMSIG_CARBON_POST_REMOVE_LIMB), PROC_REF(try_reapply_hands))
|
|
RegisterSignal(parent, COMSIG_MOB_EQUIPPED_ITEM, PROC_REF(mob_equipped_item))
|
|
RegisterSignal(parent, COMSIG_MOB_UNEQUIPPED_ITEM, PROC_REF(mob_dropped_item))
|
|
|
|
/datum/component/mutant_hands/UnregisterFromParent()
|
|
UnregisterSignal(parent, list(
|
|
COMSIG_CARBON_POST_ATTACH_LIMB,
|
|
COMSIG_CARBON_POST_REMOVE_LIMB,
|
|
COMSIG_MOB_EQUIPPED_ITEM,
|
|
COMSIG_MOB_UNEQUIPPED_ITEM,
|
|
))
|
|
|
|
// Remove all their hands after unregistering everything so they don't return
|
|
INVOKE_ASYNC(src, PROC_REF(remove_mutant_hands))
|
|
|
|
/**
|
|
* Tries to give the parent mob mutant hands.
|
|
*
|
|
* * If a hand slot is empty, places the mutanthand type into their hand.
|
|
* * If a hand slot is filled with a nodrop item, it will do nothing.
|
|
* * If a hand slot is filled with a non-nodrop item, drops the item to the ground.
|
|
* * If a hand slot is filled with a hand already, does nothing.
|
|
*/
|
|
/datum/component/mutant_hands/proc/apply_mutant_hands()
|
|
var/mob/living/carbon/human/human_parent = parent
|
|
for(var/obj/item/hand_slot as anything in human_parent.held_items)
|
|
// This slot is already a mutant hand
|
|
if(istype(hand_slot, mutant_hand_path))
|
|
continue
|
|
// This slot is not empty
|
|
// Yes the held item lists contains nulls to represent empty hands
|
|
// It saves us a /item cast by using as anything in the loop
|
|
if(!isnull(hand_slot))
|
|
if(HAS_TRAIT(hand_slot, TRAIT_NODROP) || (hand_slot.item_flags & ABSTRACT))
|
|
// There's a nodrop / abstract item in the way of putting a mutant hand in
|
|
// It can stay, for now, but if it gets dropped / unequipped we'll swoop in to replace the slot
|
|
continue
|
|
// Drop any existing non-nodrop items to the ground
|
|
human_parent.dropItemToGround(hand_slot)
|
|
|
|
// Put in hands has a sleep somewhere in there
|
|
human_parent.put_in_hands(new mutant_hand_path(), del_on_fail = TRUE)
|
|
|
|
/**
|
|
* Removes all mutant idems from the parent's hand slots
|
|
*/
|
|
/datum/component/mutant_hands/proc/remove_mutant_hands()
|
|
var/mob/living/carbon/human/human_parent = parent
|
|
for(var/obj/item/hand_slot in human_parent.held_items)
|
|
// Not a mutant hand, don't need to delete it
|
|
if(!istype(hand_slot, mutant_hand_path))
|
|
continue
|
|
|
|
// Just send it to the shadow realm, this will handle unequipping and remove it for us
|
|
qdel(hand_slot)
|
|
|
|
/**
|
|
* Signal proc for any signals that may result in the number of hands of the parent mob changing
|
|
*
|
|
* Always try to re-insert mutanthands if we gain or lose hands
|
|
*/
|
|
/datum/component/mutant_hands/proc/try_reapply_hands(datum/source)
|
|
SIGNAL_HANDLER
|
|
|
|
if(QDELING(src) || QDELING(parent))
|
|
return
|
|
|
|
INVOKE_ASYNC(src, PROC_REF(apply_mutant_hands))
|
|
|
|
/**
|
|
* Signal proc for [COMSIG_MOB_EQUIPPED_ITEM]
|
|
*
|
|
* This is a failsafe - the mob managed to pick up something that isn't a mutant hand
|
|
*/
|
|
/datum/component/mutant_hands/proc/mob_equipped_item(mob/living/carbon/human/source, obj/item/thing, slot)
|
|
SIGNAL_HANDLER
|
|
|
|
if(!(slot & ITEM_SLOT_HANDS)) // Who cares
|
|
return
|
|
|
|
if(istype(thing, mutant_hand_path)) // This is definitely meant to be here
|
|
return
|
|
|
|
if(HAS_TRAIT(thing, TRAIT_NODROP) || (thing.item_flags & ABSTRACT)) // This is meant to be here
|
|
return
|
|
|
|
// We equipped something to hands that wasn't a mutant hand, and wasn't abstract!
|
|
// This means they're meant to have a mutant hand. So help them out.
|
|
INVOKE_ASYNC(src, PROC_REF(apply_mutant_hands))
|
|
|
|
/**
|
|
* Signal proc for [COMSIG_MOB_UNEQUIPPED_ITEM]
|
|
*
|
|
* This is another failsafe - the mob dropped something, maybe from their hands, so try to re-equip
|
|
*/
|
|
/datum/component/mutant_hands/proc/mob_dropped_item(mob/living/carbon/human/source, obj/item/thing)
|
|
SIGNAL_HANDLER
|
|
|
|
if(QDELING(src) || QDELING(parent))
|
|
return
|
|
|
|
if(null in source.held_items)
|
|
INVOKE_ASYNC(src, PROC_REF(apply_mutant_hands))
|
|
|
|
/**
|
|
* Generic mutant hand type for use with the mutant hands component
|
|
* (Technically speaking, the component doesn't require you use this type. But it's here for posterity)
|
|
*
|
|
* Implements nothing except changing its icon state between left and right depending on hand slot equipped in
|
|
*/
|
|
/obj/item/mutant_hand
|
|
name = "mutant hand"
|
|
desc = "Won't somebody give me a hand?"
|
|
icon = 'icons/effects/blood.dmi'
|
|
icon_state = "bloodhand_left"
|
|
base_icon_state = "bloodhand"
|
|
item_flags = ABSTRACT | DROPDEL | HAND_ITEM
|
|
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
|
|
|
|
/obj/item/mutant_hand/Initialize(mapload)
|
|
. = ..()
|
|
ADD_TRAIT(src, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT)
|
|
|
|
/obj/item/mutant_hand/visual_equipped(mob/user, slot)
|
|
. = ..()
|
|
|
|
if(!base_icon_state)
|
|
return
|
|
|
|
// Even hand indexes are right hands,
|
|
// Odd hand indexes are left hand
|
|
// ...But also, we swap it intentionally here,
|
|
// so right icon is shown on the left (Because hands)
|
|
if(user.get_held_index_of_item(src) % 2 == 1)
|
|
icon_state = "[base_icon_state]_right"
|
|
else
|
|
icon_state = "[base_icon_state]_left"
|