mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-05 22:43:46 +00:00
## About The Pull Request Fixes #93280 It would give you the null rod arm, then equip the null rod, then try to give you the null rod arm again, which removed your null rod arm and caused... problems ## Changelog 🆑 Melbert fix: Fixed chainsaw nullrod /🆑
157 lines
6.7 KiB
Plaintext
157 lines
6.7 KiB
Plaintext
/**
|
|
* This makes an arbitrary item into a "prosthetic limb"
|
|
*/
|
|
/datum/component/item_as_prosthetic_limb
|
|
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
|
/// The item that is the prosthetic limb
|
|
VAR_PRIVATE/obj/item/item_limb
|
|
/// Prob of losing the arm on attack
|
|
var/drop_prob = 100
|
|
|
|
/datum/component/item_as_prosthetic_limb/Initialize(obj/item/prosthetic_item, drop_prob = 100)
|
|
if(!isbodypart(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
var/obj/item/bodypart/bodyparent = parent
|
|
if(bodyparent.body_zone != BODY_ZONE_L_ARM && bodyparent.body_zone != BODY_ZONE_R_ARM)
|
|
return COMPONENT_INCOMPATIBLE
|
|
if(isnull(bodyparent.owner))
|
|
return COMPONENT_INCOMPATIBLE
|
|
|
|
bodyparent.bodypart_flags |= BODYPART_PSEUDOPART|BODYPART_IMPLANTED
|
|
src.item_limb = prosthetic_item // calls register_item() in registerWithParent()
|
|
src.drop_prob = drop_prob
|
|
|
|
/datum/component/item_as_prosthetic_limb/InheritComponent(datum/component/new_comp, i_am_original, obj/item/prosthetic_item, drop_prob = 100)
|
|
if(prosthetic_item)
|
|
unregister_item(item_limb)
|
|
register_item(prosthetic_item)
|
|
|
|
src.drop_prob = drop_prob
|
|
|
|
/datum/component/item_as_prosthetic_limb/proc/register_item(obj/item/prosthetic_item)
|
|
SEND_SIGNAL(prosthetic_item, COMSIG_ITEM_PRE_USED_AS_PROSTHETIC, parent)
|
|
item_limb = prosthetic_item
|
|
RegisterSignal(prosthetic_item, COMSIG_QDELETING, PROC_REF(qdel_limb))
|
|
RegisterSignal(prosthetic_item, COMSIG_MOVABLE_MOVED, PROC_REF(limb_moved))
|
|
// adds a bunch of flags to the item to make it act like a limb
|
|
prosthetic_item.item_flags |= (HAND_ITEM|ABSTRACT)
|
|
prosthetic_item.interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP
|
|
ADD_TRAIT(prosthetic_item, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT)
|
|
// update the name of the real limb to match the item, so you see "their chainsaw arm is wounded"
|
|
var/obj/item/bodypart/bodyparent = parent
|
|
// ensures the item is in the proper place
|
|
switch(bodyparent.body_zone)
|
|
if(BODY_ZONE_R_ARM)
|
|
bodyparent.name = "right [prosthetic_item.name]"
|
|
bodyparent.plaintext_zone = "right [prosthetic_item.name]"
|
|
bodyparent.owner.put_in_r_hand(prosthetic_item)
|
|
if(BODY_ZONE_L_ARM)
|
|
bodyparent.name = "left [prosthetic_item.name]"
|
|
bodyparent.plaintext_zone = "left [prosthetic_item.name]"
|
|
bodyparent.owner.put_in_l_hand(prosthetic_item)
|
|
SEND_SIGNAL(prosthetic_item, COMSIG_ITEM_POST_USED_AS_PROSTHETIC, parent)
|
|
|
|
/datum/component/item_as_prosthetic_limb/proc/unregister_item(obj/item/prosthetic_item)
|
|
item_limb = null
|
|
UnregisterSignal(prosthetic_item, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED))
|
|
// nothing to be done if it's being thrown away
|
|
if(QDELING(prosthetic_item))
|
|
return
|
|
|
|
// reset all the flags
|
|
prosthetic_item.item_flags &= ~(HAND_ITEM|ABSTRACT)
|
|
prosthetic_item.interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP
|
|
REMOVE_TRAIT(prosthetic_item, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT)
|
|
// note: default behavior is to keep the item in the contents of the arm
|
|
// so if the limb is deleted by some unknown means (supermatter?), the item will also be deleted
|
|
SEND_SIGNAL(prosthetic_item, COMSIG_ITEM_DROPPED_FROM_PROSTHETIC, parent)
|
|
|
|
/datum/component/item_as_prosthetic_limb/proc/register_limb(obj/item/bodypart/bodyparent)
|
|
RegisterSignal(bodyparent, COMSIG_BODYPART_REMOVED, PROC_REF(clear_comp))
|
|
RegisterSignals(bodyparent.owner, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_LIVING_UNARMED_ATTACK), PROC_REF(pop_limb))
|
|
|
|
/datum/component/item_as_prosthetic_limb/proc/unregister_limb(obj/item/bodypart/bodyparent)
|
|
UnregisterSignal(bodyparent, COMSIG_BODYPART_REMOVED)
|
|
if(bodyparent.owner) // may be null frim removal
|
|
UnregisterSignal(bodyparent.owner, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_LIVING_UNARMED_ATTACK))
|
|
|
|
/datum/component/item_as_prosthetic_limb/RegisterWithParent()
|
|
register_limb(parent)
|
|
register_item(item_limb)
|
|
|
|
/datum/component/item_as_prosthetic_limb/UnregisterFromParent()
|
|
unregister_limb(parent)
|
|
unregister_item(item_limb)
|
|
|
|
/// If the fake limb (the item) is deleted, the real limb goes with it.
|
|
/datum/component/item_as_prosthetic_limb/proc/qdel_limb(obj/item/source)
|
|
SIGNAL_HANDLER
|
|
|
|
if(QDELING(parent))
|
|
return
|
|
qdel(parent) // which nulls all the references and signals
|
|
|
|
/// If the item is removed from our hands somehow, the real limb has to go
|
|
/datum/component/item_as_prosthetic_limb/proc/limb_moved(obj/item/source)
|
|
SIGNAL_HANDLER
|
|
|
|
if(QDELING(parent))
|
|
return
|
|
var/obj/item/bodypart/bodyparent = parent
|
|
if(source.loc == bodyparent.owner)
|
|
return
|
|
qdel(parent) // which nulls all the references and signals
|
|
|
|
/// When the bodypart is removed, we will drop the item on the ground, and then delete the the real limb.
|
|
/datum/component/item_as_prosthetic_limb/proc/clear_comp(datum/source, mob/living/carbon/owner)
|
|
SIGNAL_HANDLER
|
|
|
|
UnregisterSignal(owner, list(COMSIG_MOB_ITEM_ATTACK, COMSIG_LIVING_UNARMED_ATTACK))
|
|
if(item_limb.loc == owner)
|
|
item_limb.forceMove(owner.drop_location())
|
|
if(QDELING(parent))
|
|
return
|
|
qdel(parent) // which nulls all the references and signals
|
|
|
|
/// Attacking with the fake limb (the item) can cause it to fall off, which in turn will result in the real limb being deleted.
|
|
/datum/component/item_as_prosthetic_limb/proc/pop_limb(mob/living/source, ...)
|
|
SIGNAL_HANDLER
|
|
|
|
if(source.get_active_hand() != parent)
|
|
return NONE
|
|
if(!prob(drop_prob))
|
|
return NONE
|
|
|
|
var/obj/item/bodypart/bodyparent = parent
|
|
source.visible_message(
|
|
span_warning("As [source] attempts to swing with [source.p_their()] [bodyparent.name], it falls right off!"),
|
|
span_warning("As you attempt to swing with [source.p_their()] [bodyparent.name], it falls right off!"),
|
|
visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE,
|
|
)
|
|
bodyparent.dismember(silent = TRUE) // which removes the limb, which qdels us (which nulls all the references and signals)
|
|
return COMPONENT_CANCEL_ATTACK_CHAIN
|
|
|
|
/**
|
|
* Makes the passed item into a "prosthetic limb" of this mod, replacing any existing arm
|
|
*
|
|
* Returns the created pseudopart
|
|
*/
|
|
/mob/living/carbon/proc/make_item_prosthetic(obj/item/some_thing, target_zone = BODY_ZONE_R_ARM, fall_prob = 0)
|
|
if(HAS_TRAIT_FROM(some_thing, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT))
|
|
CRASH("make_item_prosthetic given an item that is already a prosthetic limb!")
|
|
|
|
var/obj/item/bodypart/existing = get_bodypart(target_zone)
|
|
existing?.drop_limb(special = TRUE)
|
|
|
|
var/obj/item/bodypart/bodypart_to_attach = newBodyPart(target_zone)
|
|
bodypart_to_attach.change_appearance(icon = 'icons/mob/augmentation/surplus_augments.dmi', id = BODYPART_ID_ROBOTIC, greyscale = FALSE, dimorphic = FALSE)
|
|
bodypart_to_attach.try_attach_limb(src)
|
|
bodypart_to_attach.AddComponent(/datum/component/item_as_prosthetic_limb, some_thing, fall_prob)
|
|
|
|
if(bodypart_to_attach.owner != src)
|
|
stack_trace("make_item_prosthetic failed to attach to owner!")
|
|
qdel(bodypart_to_attach)
|
|
return null
|
|
|
|
return bodypart_to_attach
|