diff --git a/code/__DEFINES/living.dm b/code/__DEFINES/living.dm index 119e8b33f1a9..ea3d08346dfe 100644 --- a/code/__DEFINES/living.dm +++ b/code/__DEFINES/living.dm @@ -50,3 +50,6 @@ /// If the mob enters shock, they will have +1 cure condition (helps cure it faster) #define TRAIT_ABATES_SHOCK "shock_abated" + +/// The trait that determines if someone has the robotic limb reattachment quirk. +#define TRAIT_ROBOTIC_LIMBATTACHMENT "trait_robotic_limbattachment" // Sticking this here because Melbert told me to diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 020e0d36c015..2912c7b30fce 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -360,7 +360,11 @@ if(ishuman(victim)) var/mob/living/carbon/human/human_victim = victim - if(HAS_TRAIT(victim, TRAIT_LIMBATTACHMENT)) + // NON-MODULE CHANGE START + if (!HAS_TRAIT(victim, TRAIT_LIMBATTACHMENT) && !(bodytype & BODYTYPE_ROBOTIC)) //if we're trying to attach something that's not robotic, and we don't have the generic trait, end out + return + if(HAS_TRAIT(victim, TRAIT_LIMBATTACHMENT) || HAS_TRAIT(victim, TRAIT_ROBOTIC_LIMBATTACHMENT)) + // NON-MODULE CHANGE END if(!human_victim.get_bodypart(body_zone)) user.temporarilyRemoveItemFromInventory(src, TRUE) if(!try_attach_limb(victim)) diff --git a/maplestation.dme b/maplestation.dme index 40d6cc981133..53dc92474b50 100644 --- a/maplestation.dme +++ b/maplestation.dme @@ -6445,6 +6445,7 @@ #include "maplestation_modules\code\modules\research\machinery\_production.dm" #include "maplestation_modules\code\modules\research\techweb\_research.dm" #include "maplestation_modules\code\modules\research\techweb\all_nodes.dm" +#include "maplestation_modules\code\modules\robotic_limb_detach\robot_limb_detach_quirk.dm" #include "maplestation_modules\code\modules\surgery\organs\augments_arms.dm" #include "maplestation_modules\code\modules\surgery\organs\autosurgeon.dm" #include "maplestation_modules\code\modules\surgery\organs\ears.dm" diff --git a/maplestation_modules/code/datums/pain/pain.dm b/maplestation_modules/code/datums/pain/pain.dm index fdea19ae986c..5b87aba1b188 100644 --- a/maplestation_modules/code/datums/pain/pain.dm +++ b/maplestation_modules/code/datums/pain/pain.dm @@ -126,7 +126,7 @@ body_zones[new_limb.body_zone] = new_limb - if(special) + if(special || (HAS_TRAIT(source, TRAIT_ROBOTIC_LIMBATTACHMENT) && (new_limb.bodytype & BODYTYPE_ROBOTIC))) new_limb.pain = 0 else adjust_bodypart_pain(new_limb.body_zone, new_limb.pain) @@ -152,10 +152,11 @@ body_zones -= bad_zone UnregisterSignal(lost_limb, COMSIG_QDELETING) - if(!QDELETED(parent) && !special) - var/limb_removed_pain = (dismembered ? PAIN_LIMB_DISMEMBERED : PAIN_LIMB_REMOVED) - adjust_bodypart_pain(BODY_ZONE_CHEST, limb_removed_pain) - adjust_bodypart_pain(BODY_ZONES_MINUS_CHEST, limb_removed_pain / 3) + if(!QDELETED(parent)) + if(!special && !(HAS_TRAIT(source, TRAIT_ROBOTIC_LIMBATTACHMENT) && (lost_limb.bodytype & BODYTYPE_ROBOTIC))) + var/limb_removed_pain = (dismembered ? PAIN_LIMB_DISMEMBERED : PAIN_LIMB_REMOVED) + adjust_bodypart_pain(BODY_ZONE_CHEST, limb_removed_pain) + adjust_bodypart_pain(BODY_ZONES_MINUS_CHEST, limb_removed_pain / 3) if(!QDELETED(lost_limb)) lost_limb.pain = initial(lost_limb.pain) diff --git a/maplestation_modules/code/modules/robotic_limb_detach/robot_limb_detach_quirk.dm b/maplestation_modules/code/modules/robotic_limb_detach/robot_limb_detach_quirk.dm new file mode 100644 index 000000000000..aa2c81fbba87 --- /dev/null +++ b/maplestation_modules/code/modules/robotic_limb_detach/robot_limb_detach_quirk.dm @@ -0,0 +1,84 @@ +/datum/quirk/robot_limb_detach + name = "Cybernetic Limb Mounts" + desc = "You are able to detach and reattach any installed robotic limbs with very little effort." + gain_text = span_notice("Internal sensors report limb disengagement protocols are ready and waiting.") + lose_text = span_notice("ERROR: LIMB DISENGAGEMENT PROTOCOLS OFFLINE.") + medical_record_text = "Patient bears quick-attach and release limb joint cybernetics." + value = 0 + mob_trait = TRAIT_ROBOTIC_LIMBATTACHMENT + icon = FA_ICON_HANDSHAKE_SIMPLE_SLASH + quirk_flags = QUIRK_HUMAN_ONLY + /// The action we add with this quirk in add(), used for easy deletion later + var/datum/action/cooldown/added_action + +/datum/quirk/robot_limb_detach/add(client/client_source) + var/mob/living/carbon/human/human_holder = quirk_holder + var/datum/action/cooldown/robot_self_amputation/limb_action = new() + limb_action.Grant(human_holder) + added_action = limb_action + +/datum/quirk/robot_limb_detach/remove() + QDEL_NULL(added_action) + +/datum/action/cooldown/robot_self_amputation + name = "Detach a robotic limb" + desc = "Disengage one of your robotic limbs from your cybernetic mounts. Requires you to not be restrained or otherwise under duress." + button_icon = 'icons/mob/actions/actions_spells.dmi' + button_icon_state = "autotomy" + + cooldown_time = 1 SECONDS + check_flags = AB_CHECK_CONSCIOUS | AB_CHECK_HANDS_BLOCKED | AB_CHECK_INCAPACITATED + + var/list/exclusions = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD) + +/datum/action/cooldown/robot_self_amputation/proc/detaching_check(mob/living/carbon/human/target, obj/item/bodypart/limb_to_detach) + return !QDELETED(limb_to_detach) && limb_to_detach.owner == target + +/datum/action/cooldown/robot_self_amputation/Activate(mob/living/carbon/human/target) + if(!ishuman(target)) + return + + if(HAS_TRAIT(target, TRAIT_NODISMEMBER)) + to_chat(target, span_warning("ERROR: LIMB DISENGAGEMENT PROTOCOLS OFFLINE. Seek out a maintenance technician.")) + return + + + var/list/robot_parts = list() + for (var/obj/item/bodypart/possible_part as anything in target.bodyparts) + if ((possible_part.bodytype & BODYTYPE_ROBOTIC) && !(possible_part.body_zone in exclusions)) //only robot limbs and only if they're not crucial to our like, ongoing life, you know? + robot_parts += possible_part + + if (!length(robot_parts)) + to_chat(target, "ERROR: Limb disengagement protocols report no compatible cybernetics currently installed. Seek out a maintenance technician.") + return + + var/obj/item/bodypart/limb_to_detach = tgui_input_list(target, "Limb to detach", "Cybernetic Limb Detachment", sort_names(robot_parts)) + if (QDELETED(src) || QDELETED(target) || QDELETED(limb_to_detach) || limb_to_detach.owner != target) + return + + if (length(limb_to_detach.wounds) >= 1) + target.balloon_alert(target, "can't detach wounded limbs!") + playsound(target, 'sound/machines/buzz-sigh.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + return + var/leg_check = IGNORE_USER_LOC_CHANGE + if (istype(limb_to_detach, /obj/item/bodypart/leg)) + leg_check = NONE + + target.balloon_alert(target, "detaching limb...") + playsound(target, 'sound/items/rped.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + target.visible_message(span_notice("[target] shuffles [target.p_their()] [limb_to_detach.name] forward, actuators hissing and whirring as [target.p_they()] disengage[target.p_s()] the limb from its mount...")) + + if(do_after(target, 1 SECONDS, timed_action_flags = leg_check, extra_checks = CALLBACK(src, PROC_REF(detaching_check), target, limb_to_detach))) + StartCooldown() + target.visible_message(span_notice("With a gentle twist, [target] finally pries [target.p_their()] [limb_to_detach.name] free from its socket.")) + limb_to_detach.drop_limb() + target.put_in_hands(limb_to_detach) + target.balloon_alert(target, "limb detached!") + if(prob(5)) + playsound(target, 'sound/items/champagne_pop.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + else + playsound(target, 'sound/items/deconstruct.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + else + target.balloon_alert(target, "interrupted!") + playsound(target, 'sound/machines/buzz-sigh.ogg', 25, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + return TRUE