From 7c4b7cdb9a9dd24248f2fbc5df975eae35274408 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Fri, 11 Sep 2020 23:21:46 +0200 Subject: [PATCH] [MIRROR] limb disabled refactor (#757) * limb disabled refactor (#53374) Fixes #53219 Nukes is_disabled() Turns several variable value changes into events. bodypart_disabled turned into a boolean value. BODYPART_DISABLED_WOUND turned into TRAIT_DISABLED_BY_WOUND. Not the cleanest thing out there, but it works. Cleans some code and reduces number of updates, as only the extremities have a disabled effect. * limb disabled refactor Co-authored-by: Rohesie --- code/__DEFINES/mobs.dm | 5 - code/__DEFINES/traits.dm | 5 +- code/_onclick/other_mobs.dm | 4 +- code/datums/brain_damage/severe.dm | 4 +- code/datums/wounds/_wounds.dm | 38 ++- code/datums/wounds/bones.dm | 2 +- code/datums/wounds/burns.dm | 8 +- code/datums/wounds/loss.dm | 2 +- code/modules/mob/living/carbon/carbon.dm | 6 +- .../mob/living/carbon/human/examine.dm | 13 +- .../mob/living/carbon/human/human_defense.dm | 2 +- code/modules/surgery/bodyparts/_bodyparts.dm | 285 ++++++++++++++---- .../surgery/bodyparts/dismemberment.dm | 4 +- code/modules/surgery/bodyparts/parts.dm | 284 +++++++++++------ 14 files changed, 485 insertions(+), 177 deletions(-) diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm index 77de678bd1f..d2892ffae65 100644 --- a/code/__DEFINES/mobs.dm +++ b/code/__DEFINES/mobs.dm @@ -63,11 +63,6 @@ #define BODYPART_ORGANIC 1 #define BODYPART_ROBOTIC 2 -#define BODYPART_NOT_DISABLED 0 -#define BODYPART_DISABLED_DAMAGE 1 -#define BODYPART_DISABLED_PARALYSIS 2 -#define BODYPART_DISABLED_WOUND 3 - #define DEFAULT_BODYPART_ICON_ORGANIC 'icons/mob/human_parts_greyscale.dmi' #define DEFAULT_BODYPART_ICON_ROBOTIC 'icons/mob/augmentation/augments.dmi' diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 2b74bd98042..bd1f2311a86 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -203,7 +203,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_KNOW_ENGI_WIRES "know_engi_wires" //non-mob traits -#define TRAIT_PARALYSIS "paralysis" //Used for limb-based paralysis, where replacing the limb will fix it +/// Used for limb-based paralysis, where replacing the limb will fix it. +#define TRAIT_PARALYSIS "paralysis" +/// Used for limbs. +#define TRAIT_DISABLED_BY_WOUND "disabled-by-wound" ///Used for managing KEEP_TOGETHER in [appearance_flags] #define TRAIT_KEEP_TOGETHER "keep-together" diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm index e777f4a1778..4fe601ee690 100644 --- a/code/_onclick/other_mobs.dm +++ b/code/_onclick/other_mobs.dm @@ -7,8 +7,8 @@ /mob/living/carbon/human/UnarmedAttack(atom/A, proximity) if(!has_active_hand()) //can't attack without a hand. var/obj/item/bodypart/check_arm = get_active_hand() - if(check_arm && check_arm.is_disabled() == BODYPART_DISABLED_WOUND) - to_chat(src, "The damage in your [check_arm.name] is preventing you from using it! Get it fixed, or at least splinted!") + if(check_arm?.bodypart_disabled) + to_chat(src, "Your [check_arm.name] is in no condition to be used.") return to_chat(src, "You look at your arm and sigh.") diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index 77747f2c853..f40d46ba254 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -104,13 +104,13 @@ ..() for(var/X in paralysis_traits) ADD_TRAIT(owner, X, "trauma_paralysis") - owner.update_disabled_bodyparts() + /datum/brain_trauma/severe/paralysis/on_lose() ..() for(var/X in paralysis_traits) REMOVE_TRAIT(owner, X, "trauma_paralysis") - owner.update_disabled_bodyparts() + /datum/brain_trauma/severe/paralysis/paraplegic random_gain = FALSE diff --git a/code/datums/wounds/_wounds.dm b/code/datums/wounds/_wounds.dm index 833631aa3cb..032ab38152e 100644 --- a/code/datums/wounds/_wounds.dm +++ b/code/datums/wounds/_wounds.dm @@ -95,7 +95,7 @@ QDEL_NULL(attached_surgery) if(limb?.wounds && (src in limb.wounds)) // destroy can call remove_wound() and remove_wound() calls qdel, so we check to make sure there's anything to remove first remove_wound() - limb = null + set_limb(null) victim = null return ..() @@ -129,7 +129,7 @@ return victim = L.owner - limb = L + set_limb(L) LAZYADD(victim.all_wounds, src) LAZYADD(limb.wounds, src) limb.update_wounds() @@ -192,13 +192,45 @@ already_scarred = TRUE remove_wound(replaced=TRUE) new_wound.apply_wound(limb, old_wound = src, smited = smited) + . = new_wound qdel(src) - return new_wound /// The immediate negative effects faced as a result of the wound /datum/wound/proc/wound_injury(datum/wound/old_wound = null) return + +/// Proc called to change the variable `limb` and react to the event. +/datum/wound/proc/set_limb(new_value) + if(limb == new_value) + return FALSE //Limb can either be a reference to something or `null`. Returning the number variable makes it clear no change was made. + . = limb + limb = new_value + if(. && disabling) + var/obj/item/bodypart/old_limb = . + REMOVE_TRAIT(old_limb, TRAIT_PARALYSIS, src) + REMOVE_TRAIT(old_limb, TRAIT_DISABLED_BY_WOUND, src) + if(limb) + if(disabling) + ADD_TRAIT(limb, TRAIT_PARALYSIS, src) + ADD_TRAIT(limb, TRAIT_DISABLED_BY_WOUND, src) + + +/// Proc called to change the variable `disabling` and react to the event. +/datum/wound/proc/set_disabling(new_value) + if(disabling == new_value) + return + . = disabling + disabling = new_value + if(disabling) + if(!. && limb) //Gained disabling. + ADD_TRAIT(limb, TRAIT_PARALYSIS, src) + ADD_TRAIT(limb, TRAIT_DISABLED_BY_WOUND, src) + else if(. && limb) //Lost disabling. + REMOVE_TRAIT(limb, TRAIT_PARALYSIS, src) + REMOVE_TRAIT(limb, TRAIT_DISABLED_BY_WOUND, src) + + /// Additional beneficial effects when the wound is gained, in case you want to give a temporary boost to allow the victim to try an escape or last stand /datum/wound/proc/second_wind() switch(severity) diff --git a/code/datums/wounds/bones.dm b/code/datums/wounds/bones.dm index 98354ff1ef2..8f91ae0eb70 100644 --- a/code/datums/wounds/bones.dm +++ b/code/datums/wounds/bones.dm @@ -177,7 +177,7 @@ interaction_efficiency_penalty = interaction_efficiency_penalty if(initial(disabling)) - disabling = !limb.current_gauze + set_disabling(!limb.current_gauze) limb.update_wounds() diff --git a/code/datums/wounds/burns.dm b/code/datums/wounds/burns.dm index a998f3645f5..afea9801279 100644 --- a/code/datums/wounds/burns.dm +++ b/code/datums/wounds/burns.dm @@ -82,19 +82,19 @@ if(WOUND_INFECTION_SEVERE to WOUND_INFECTION_CRITICAL) if(!disabling && prob(2)) to_chat(victim, "Your [limb.name] completely locks up, as you struggle for control against the infection!") - disabling = TRUE + set_disabling(TRUE) else if(disabling && prob(8)) to_chat(victim, "You regain sensation in your [limb.name], but it's still in terrible shape!") - disabling = FALSE + set_disabling(FALSE) else if(prob(20)) victim.adjustToxLoss(0.5) if(WOUND_INFECTION_CRITICAL to WOUND_INFECTION_SEPTIC) if(!disabling && prob(3)) to_chat(victim, "You suddenly lose all sensation of the festering infection in your [limb.name]!") - disabling = TRUE + set_disabling(TRUE) else if(disabling && prob(3)) to_chat(victim, "You can barely feel your [limb.name] again, and you have to strain to retain motor control!") - disabling = FALSE + set_disabling(FALSE) else if(prob(1)) to_chat(victim, "You contemplate life without your [limb.name]...") victim.adjustToxLoss(0.75) diff --git a/code/datums/wounds/loss.dm b/code/datums/wounds/loss.dm index 259d5b83980..4adb5cb2577 100644 --- a/code/datums/wounds/loss.dm +++ b/code/datums/wounds/loss.dm @@ -46,7 +46,7 @@ victim.visible_message(msg, "Your [dismembered_part.name] [occur_text]!") - limb = dismembered_part + set_limb(dismembered_part) severity = WOUND_SEVERITY_LOSS second_wind() log_wound(victim, src) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 5318df68098..b2a9cc45b91 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -967,7 +967,7 @@ var/r_arm_index_next = 0 for(var/bodypart_path in bodyparts) var/obj/item/bodypart/bodypart_instance = new bodypart_path() - bodypart_instance.owner = src + bodypart_instance.set_owner(src) bodyparts.Remove(bodypart_path) add_bodypart(bodypart_instance) switch(bodypart_instance.body_part) @@ -1016,10 +1016,6 @@ var/obj/item/organ/I = X I.Insert(src) -/mob/living/carbon/proc/update_disabled_bodyparts() - for(var/B in bodyparts) - var/obj/item/bodypart/BP = B - BP.update_disabled() /mob/living/carbon/vv_get_dropdown() . = ..() diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 355c1bb1c2e..19751deb6c7 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -157,12 +157,13 @@ for(var/X in disabled) var/obj/item/bodypart/body_part = X var/damage_text - if(body_part.is_disabled() != BODYPART_DISABLED_WOUND) // skip if it's disabled by a wound (cuz we'll be able to see the bone sticking out!) - if(!(body_part.get_damage(include_stamina = FALSE) >= body_part.max_damage)) //we don't care if it's stamcritted - damage_text = "limp and lifeless" - else - damage_text = (body_part.brute_dam >= body_part.burn_dam) ? body_part.heavy_brute_msg : body_part.heavy_burn_msg - msg += "[capitalize(t_his)] [body_part.name] is [damage_text]!\n" + if(HAS_TRAIT(body_part, TRAIT_DISABLED_BY_WOUND)) + continue // skip if it's disabled by a wound (cuz we'll be able to see the bone sticking out!) + if(!(body_part.get_damage(include_stamina = FALSE) >= body_part.max_damage)) //we don't care if it's stamcritted + damage_text = "limp and lifeless" + else + damage_text = (body_part.brute_dam >= body_part.burn_dam) ? body_part.heavy_brute_msg : body_part.heavy_burn_msg + msg += "[capitalize(t_his)] [body_part.name] is [damage_text]!\n" //stores missing limbs var/l_limbs_missing = 0 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 951558b3e6d..6a85c5e63b6 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -717,7 +717,7 @@ if(status == "OK" || status == "no damage") no_damage = TRUE var/isdisabled = "" - if(LB.is_disabled()) + if(LB.bodypart_disabled) isdisabled = " is disabled" if(no_damage) isdisabled += " but otherwise" diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index d5907ce04b6..a3976a66c32 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -22,7 +22,12 @@ var/held_index = 0 //are we a hand? if so, which one! var/is_pseudopart = FALSE //For limbs that don't really exist, eg chainsaws - var/bodypart_disabled = BODYPART_NOT_DISABLED //If disabled, limb is as good as missing + ///If disabled, limb is as good as missing. + var/bodypart_disabled = FALSE + ///Multiplied by max_damage it returns the threshold which defines a limb being disabled or not. From 0 to 1. + var/disable_threshold = 1 + ///Controls whether bodypart_disabled makes sense or not for this limb. + var/can_be_disabled = FALSE var/body_damage_coeff = 1 //Multiplier of the limb's damage that gets applied to the mob var/stam_damage_coeff = 0.75 var/brutestate = 0 @@ -91,6 +96,25 @@ var/obj/item/self_grasp/grasped_by +/obj/item/bodypart/Initialize(mapload) + . = ..() + if(can_be_disabled) + RegisterSignal(src, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS), .proc/on_paralysis_trait_gain) + RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS), .proc/on_paralysis_trait_loss) + + +/obj/item/bodypart/Destroy() + if(owner) + owner.remove_bodypart(src) + set_owner(null) + for(var/wound in wounds) + qdel(wound) // wounds is a lazylist, and each wound removes itself from it on deletion. + if(length(wounds)) + stack_trace("[type] qdeleted with [length(wounds)] uncleared wounds") + wounds.Cut() + return ..() + + /obj/item/bodypart/examine(mob/user) . = ..() if(brute_dam > DAMAGE_PRECISION) @@ -98,14 +122,10 @@ if(burn_dam > DAMAGE_PRECISION) . += "This limb has [burn_dam > 30 ? "severe" : "minor"] burns." + /obj/item/bodypart/blob_act() take_damage(max_damage) -/obj/item/bodypart/Destroy() - if(owner) - owner.remove_bodypart(src) - owner = null - return ..() /obj/item/bodypart/attack(mob/living/carbon/C, mob/user) if(ishuman(C)) @@ -171,13 +191,6 @@ return bodypart_organs -/obj/item/bodypart/proc/consider_processing() - if(stamina_dam > DAMAGE_PRECISION) - . = TRUE - //else if.. else if.. so on. - else - . = FALSE - needs_processing = . //Return TRUE to get whatever mob this is in to update health. /obj/item/bodypart/proc/on_life(stam_regen) @@ -279,21 +292,24 @@ if(can_inflict <= 0) return FALSE - - brute_dam += brute - burn_dam += burn + if(brute) + set_brute_dam(brute_dam + brute) + if(burn) + set_burn_dam(burn_dam + burn) //We've dealt the physical damages, if there's room lets apply the stamina damage. - stamina_dam += round(clamp(stamina, 0, max_stamina_damage - stamina_dam), DAMAGE_PRECISION) + if(stamina) + set_stamina_dam(stamina_dam + round(clamp(stamina, 0, max_stamina_damage - stamina_dam), DAMAGE_PRECISION)) - if(owner && updating_health) - owner.updatehealth() - if(stamina > DAMAGE_PRECISION) - owner.update_stamina() - owner.stam_regen_start_time = world.time + STAMINA_REGEN_BLOCK_TIME - . = TRUE - consider_processing() - update_disabled() + if(owner) + if(can_be_disabled) + update_disabled() + if(updating_health) + owner.updatehealth() + if(stamina > DAMAGE_PRECISION) + owner.update_stamina() + owner.stam_regen_start_time = world.time + STAMINA_REGEN_BLOCK_TIME + . = TRUE return update_bodypart_damage_state() || . /// Allows us to roll for and apply a wound without actually dealing damage. Used for aggregate wounding power with pellet clouds @@ -468,19 +484,53 @@ //Cannot remove negative damage (i.e. apply damage) /obj/item/bodypart/proc/heal_damage(brute, burn, stamina, required_status, updating_health = TRUE) - if(required_status && (status != required_status)) //So we can only heal certain kinds of limbs, ie robotic vs organic. + if(required_status && status != required_status) //So we can only heal certain kinds of limbs, ie robotic vs organic. return - brute_dam = round(max(brute_dam - brute, 0), DAMAGE_PRECISION) - burn_dam = round(max(burn_dam - burn, 0), DAMAGE_PRECISION) - stamina_dam = round(max(stamina_dam - stamina, 0), DAMAGE_PRECISION) - if(owner && updating_health) - owner.updatehealth() - consider_processing() - update_disabled() + if(brute) + set_brute_dam(round(max(brute_dam - brute, 0), DAMAGE_PRECISION)) + if(burn) + set_burn_dam(round(max(burn_dam - burn, 0), DAMAGE_PRECISION)) + if(stamina) + set_stamina_dam(round(max(stamina_dam - stamina, 0), DAMAGE_PRECISION)) + + if(owner) + if(can_be_disabled) + update_disabled() + if(updating_health) + owner.updatehealth() cremation_progress = min(0, cremation_progress - ((brute_dam + burn_dam)*(100/max_damage))) return update_bodypart_damage_state() + +///Proc to hook behavior associated to the change of the brute_dam variable's value. +/obj/item/bodypart/proc/set_brute_dam(new_value) + if(brute_dam == new_value) + return + . = brute_dam + brute_dam = new_value + + +///Proc to hook behavior associated to the change of the burn_dam variable's value. +/obj/item/bodypart/proc/set_burn_dam(new_value) + if(burn_dam == new_value) + return + . = burn_dam + burn_dam = new_value + + +///Proc to hook behavior associated to the change of the stamina_dam variable's value. +/obj/item/bodypart/proc/set_stamina_dam(new_value) + if(stamina_dam == new_value) + return + . = stamina_dam + stamina_dam = new_value + if(stamina_dam > DAMAGE_PRECISION) + needs_processing = TRUE + else + needs_processing = FALSE + + //Returns total damage. /obj/item/bodypart/proc/get_damage(include_stamina = FALSE) var/total = brute_dam + burn_dam @@ -488,51 +538,166 @@ total = max(total, stamina_dam) return total + //Checks disabled status thresholds /obj/item/bodypart/proc/update_disabled() if(!owner) return - if(!isnull(set_disabled(is_disabled()))) //set_disabled will return null when there's no change - owner.update_mobility() + if(!can_be_disabled) + set_disabled(FALSE) + CRASH("update_disabled called with can_be_disabled false") -/obj/item/bodypart/proc/is_disabled() - if(!owner) - return if(HAS_TRAIT(src, TRAIT_PARALYSIS)) - return BODYPART_DISABLED_PARALYSIS - for(var/i in wounds) - var/datum/wound/W = i - if(W.disabling) - return BODYPART_DISABLED_WOUND - if(can_dismember() && !HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE)) - . = bodypart_disabled //inertia, to avoid limbs healing 0.1 damage and being re-enabled + set_disabled(TRUE) + return - if(get_damage(TRUE) >= max_damage * (HAS_TRAIT(owner, TRAIT_EASYLIMBWOUND) ? 0.6 : 1)) //Easy limb disable disables the limb at 40% health instead of 0% - if(!last_maxed) + var/total_damage = max(brute_dam + burn_dam, stamina_dam) + + if(total_damage >= max_damage * disable_threshold) //Easy limb disable disables the limb at 40% health instead of 0% + if(!last_maxed) + if(owner.stat < UNCONSCIOUS) owner.emote("scream") - last_maxed = TRUE - if(!is_organic_limb() || stamina_dam >= max_damage) - return BODYPART_DISABLED_DAMAGE - else if(bodypart_disabled && (get_damage(TRUE) <= (max_damage * 0.8))) // reenabled at 80% now instead of 50% as of wounds update - last_maxed = FALSE - return BODYPART_NOT_DISABLED - else - return BODYPART_NOT_DISABLED - return BODYPART_NOT_DISABLED + last_maxed = TRUE + set_disabled(TRUE) + return + + if(bodypart_disabled && total_damage <= max_damage * 0.8) // reenabled at 80% now instead of 50% as of wounds update + last_maxed = FALSE + set_disabled(FALSE) +///Proc to change the value of the `disabled` variable and react to the event of its change. /obj/item/bodypart/proc/set_disabled(new_disabled) - if(isnull(new_disabled) || bodypart_disabled == new_disabled || !owner) + if(bodypart_disabled == new_disabled) return . = bodypart_disabled bodypart_disabled = new_disabled - if(bodypart_disabled && owner.get_item_for_held_index(held_index)) - owner.dropItemToGround(owner.get_item_for_held_index(held_index)) + + if(!owner) + return + if(bodypart_disabled) + if(!.) + owner.update_mobility() + else if (.) + owner.update_mobility() owner.update_health_hud() //update the healthdoll owner.update_body() +///Proc to change the value of the `owner` variable and react to the event of its change. +/obj/item/bodypart/proc/set_owner(new_owner) + if(owner == new_owner) + return FALSE //`null` is a valid option, so we need to use a num var to make it clear no change was made. + . = owner + owner = new_owner + var/needs_update_disabled = FALSE //Only really relevant if there's an owner + if(.) + var/mob/living/carbon/old_owner = . + if(can_be_disabled) + if(HAS_TRAIT(old_owner, TRAIT_EASYLIMBWOUND)) + disable_threshold = initial(disable_threshold) + needs_update_disabled = TRUE + UnregisterSignal(old_owner, list( + SIGNAL_REMOVETRAIT(TRAIT_EASYLIMBWOUND), + SIGNAL_ADDTRAIT(TRAIT_EASYLIMBWOUND), + )) + if(initial(can_be_disabled)) + if(HAS_TRAIT(old_owner, TRAIT_NOLIMBDISABLE)) + if(!owner || !HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE)) + set_can_be_disabled(initial(can_be_disabled)) + needs_update_disabled = TRUE + UnregisterSignal(old_owner, list( + SIGNAL_REMOVETRAIT(TRAIT_NOLIMBDISABLE), + SIGNAL_ADDTRAIT(TRAIT_NOLIMBDISABLE), + )) + if(owner) + if(can_be_disabled) + if(HAS_TRAIT(owner, TRAIT_EASYLIMBWOUND)) + disable_threshold = 0.6 + needs_update_disabled = TRUE + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_EASYLIMBWOUND), .proc/on_owner_easylimbwound_trait_loss) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_EASYLIMBWOUND), .proc/on_owner_easylimbwound_trait_gain) + if(initial(can_be_disabled)) + if(HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE)) + set_can_be_disabled(FALSE) + needs_update_disabled = FALSE + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_NOLIMBDISABLE), .proc/on_owner_nolimbdisable_trait_loss) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_NOLIMBDISABLE), .proc/on_owner_nolimbdisable_trait_gain) + if(needs_update_disabled) + update_disabled() + + +///Proc to change the value of the `can_be_disabled` variable and react to the event of its change. +/obj/item/bodypart/proc/set_can_be_disabled(new_can_be_disabled) + if(can_be_disabled == new_can_be_disabled) + return + . = can_be_disabled + can_be_disabled = new_can_be_disabled + if(can_be_disabled) + if(owner) + if(HAS_TRAIT(owner, TRAIT_NOLIMBDISABLE)) + CRASH("set_can_be_disabled to TRUE with for limb whose owner has TRAIT_NOLIMBDISABLE") + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS), .proc/on_paralysis_trait_gain) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS), .proc/on_paralysis_trait_loss) + if(HAS_TRAIT(owner, TRAIT_EASYLIMBWOUND)) + disable_threshold = 0.6 + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_EASYLIMBWOUND), .proc/on_owner_easylimbwound_trait_loss) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_EASYLIMBWOUND), .proc/on_owner_easylimbwound_trait_gain) + update_disabled() + else if(.) + if(owner) + UnregisterSignal(owner, list( + SIGNAL_ADDTRAIT(TRAIT_PARALYSIS), + SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS), + SIGNAL_REMOVETRAIT(TRAIT_EASYLIMBWOUND), + SIGNAL_ADDTRAIT(TRAIT_EASYLIMBWOUND), + )) + set_disabled(FALSE) + + +///Called when TRAIT_PARALYSIS is added to the limb. +/obj/item/bodypart/proc/on_paralysis_trait_gain(obj/item/bodypart/source) + SIGNAL_HANDLER + if(can_be_disabled) + set_disabled(TRUE) + + +///Called when TRAIT_PARALYSIS is removed from the limb. +/obj/item/bodypart/proc/on_paralysis_trait_loss(obj/item/bodypart/source) + SIGNAL_HANDLER + if(can_be_disabled) + update_disabled() + + +///Called when TRAIT_NOLIMBDISABLE is added to the owner. +/obj/item/bodypart/proc/on_owner_nolimbdisable_trait_gain(mob/living/carbon/source) + SIGNAL_HANDLER + set_can_be_disabled(FALSE) + + +///Called when TRAIT_NOLIMBDISABLE is removed from the owner. +/obj/item/bodypart/proc/on_owner_nolimbdisable_trait_loss(mob/living/carbon/source) + SIGNAL_HANDLER + set_can_be_disabled(initial(can_be_disabled)) + + +///Called when TRAIT_EASYLIMBWOUND is added to the owner. +/obj/item/bodypart/proc/on_owner_easylimbwound_trait_gain(mob/living/carbon/source) + SIGNAL_HANDLER + disable_threshold = 0.6 + if(can_be_disabled) + update_disabled() + + +///Called when TRAIT_EASYLIMBWOUND is removed from the owner. +/obj/item/bodypart/proc/on_owner_easylimbwound_trait_loss(mob/living/carbon/source) + SIGNAL_HANDLER + disable_threshold = initial(disable_threshold) + if(can_be_disabled) + update_disabled() + + //Updates an organ's brute/burn states for use by update_damage_overlays() //Returns 1 if we need to update overlays. 0 otherwise. /obj/item/bodypart/proc/update_bodypart_damage_state() @@ -754,7 +919,7 @@ QDEL_NULL(current_gauze) wound_damage_multiplier = dam_mul - update_disabled() + /obj/item/bodypart/proc/get_bleed_rate() if(status != BODYPART_ORGANIC) // maybe in the future we can bleed oil from aug parts, but not now diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm index 12a5e424f53..41c7aafdf7e 100644 --- a/code/modules/surgery/bodyparts/dismemberment.dm +++ b/code/modules/surgery/bodyparts/dismemberment.dm @@ -455,8 +455,8 @@ L = newBodyPart(limb_zone, 0, 0) if(L) if(!noheal) - L.brute_dam = 0 - L.burn_dam = 0 + L.set_brute_dam(0) + L.set_burn_dam(0) L.brutestate = 0 L.burnstate = 0 diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm index 40cf4b50b16..dc3ee8258e6 100644 --- a/code/modules/surgery/bodyparts/parts.dm +++ b/code/modules/surgery/bodyparts/parts.dm @@ -72,35 +72,62 @@ held_index = 1 px_x = -6 px_y = 0 + can_be_disabled = TRUE -/obj/item/bodypart/l_arm/is_disabled() - if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM)) - return BODYPART_DISABLED_PARALYSIS - return ..() + +/obj/item/bodypart/l_arm/set_owner(new_owner) + . = ..() + if(. == FALSE) + return + var/mob/living/carbon/owner = null + if(owner) + if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM)) + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), .proc/on_owner_paralysis_loss) + else + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), .proc/on_owner_paralysis_gain) + if(.) + var/mob/living/carbon/old_owner = . + if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_L_ARM)) + UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM)) + if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_L_ARM)) + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + else + UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM)) + + +///Proc to react to the owner gaining the TRAIT_PARALYSIS_L_ARM trait. +/obj/item/bodypart/l_arm/proc/on_owner_paralysis_gain(mob/living/carbon/source) + SIGNAL_HANDLER + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM)) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM), .proc/on_owner_paralysis_loss) + + +///Proc to react to the owner losing the TRAIT_PARALYSIS_L_ARM trait. +/obj/item/bodypart/l_arm/proc/on_owner_paralysis_loss(mob/living/carbon/source) + SIGNAL_HANDLER + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_ARM) + UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM)) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), .proc/on_owner_paralysis_gain) /obj/item/bodypart/l_arm/set_disabled(new_disabled) . = ..() - if(isnull(.)) + if(isnull(.) || !owner) return - if(. == BODYPART_NOT_DISABLED) - if(bodypart_disabled != BODYPART_NOT_DISABLED) - owner.set_usable_hands(owner.usable_hands + 1) - else if(bodypart_disabled == BODYPART_NOT_DISABLED) - owner.set_usable_hands(owner.usable_hands - 1) - switch(bodypart_disabled) - if(BODYPART_DISABLED_DAMAGE) + + if(!.) + if(bodypart_disabled) + owner.set_usable_hands(owner.usable_hands - 1) if(owner.stat < UNCONSCIOUS) - owner.emote("scream") - if(owner.stat < DEAD) - to_chat(owner, "Your [name] is too damaged to function!") + to_chat(owner, "Your lose control of your [name]!") if(held_index) owner.dropItemToGround(owner.get_item_for_held_index(held_index)) - if(BODYPART_DISABLED_PARALYSIS) - if(owner.stat < DEAD) - to_chat(owner, "You can't feel your [name]!") - if(held_index) - owner.dropItemToGround(owner.get_item_for_held_index(held_index)) + else if(!bodypart_disabled) + owner.set_usable_hands(owner.usable_hands + 1) + if(owner.hud_used) var/obj/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"] hand_screen_object?.update_icon() @@ -119,12 +146,14 @@ icon_state = "alien_l_arm" px_x = 0 px_y = 0 - dismemberable = 0 + dismemberable = FALSE + can_be_disabled = FALSE max_damage = 100 animal_origin = ALIEN_BODYPART /obj/item/bodypart/l_arm/devil - dismemberable = 0 + dismemberable = FALSE + can_be_disabled = FALSE max_damage = 5000 animal_origin = DEVIL_BODYPART @@ -145,35 +174,62 @@ px_x = 6 px_y = 0 max_stamina_damage = 50 + can_be_disabled = TRUE -/obj/item/bodypart/r_arm/is_disabled() - if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM)) - return BODYPART_DISABLED_PARALYSIS - return ..() + +/obj/item/bodypart/r_arm/set_owner(new_owner) + . = ..() + if(. == FALSE) + return + var/mob/living/carbon/owner = null + if(owner) + if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM)) + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), .proc/on_owner_paralysis_loss) + else + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), .proc/on_owner_paralysis_gain) + if(.) + var/mob/living/carbon/old_owner = . + if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_R_ARM)) + UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM)) + if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_R_ARM)) + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + else + UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM)) + + +///Proc to react to the owner gaining the TRAIT_PARALYSIS_R_ARM trait. +/obj/item/bodypart/r_arm/proc/on_owner_paralysis_gain(mob/living/carbon/source) + SIGNAL_HANDLER + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM)) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM), .proc/on_owner_paralysis_loss) + + +///Proc to react to the owner losing the TRAIT_PARALYSIS_R_ARM trait. +/obj/item/bodypart/r_arm/proc/on_owner_paralysis_loss(mob/living/carbon/source) + SIGNAL_HANDLER + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_ARM) + UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM)) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), .proc/on_owner_paralysis_gain) /obj/item/bodypart/r_arm/set_disabled(new_disabled) . = ..() - if(isnull(.)) + if(isnull(.) || !owner) return - if(. == BODYPART_NOT_DISABLED) - if(bodypart_disabled != BODYPART_NOT_DISABLED) - owner.set_usable_hands(owner.usable_hands + 1) - else if(bodypart_disabled == BODYPART_NOT_DISABLED) - owner.set_usable_hands(owner.usable_hands - 1) - switch(bodypart_disabled) - if(BODYPART_DISABLED_DAMAGE) + + if(!.) + if(bodypart_disabled) + owner.set_usable_hands(owner.usable_hands - 1) if(owner.stat < UNCONSCIOUS) - owner.emote("scream") - if(owner.stat < DEAD) - to_chat(owner, "Your [name] is too damaged to function!") + to_chat(owner, "Your lose control of your [name]!") if(held_index) owner.dropItemToGround(owner.get_item_for_held_index(held_index)) - if(BODYPART_DISABLED_PARALYSIS) - if(owner.stat < DEAD) - to_chat(owner, "You can't feel your [name]!") - if(held_index) - owner.dropItemToGround(owner.get_item_for_held_index(held_index)) + else if(!bodypart_disabled) + owner.set_usable_hands(owner.usable_hands + 1) + if(owner.hud_used) var/obj/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"] hand_screen_object?.update_icon() @@ -192,12 +248,14 @@ icon_state = "alien_r_arm" px_x = 0 px_y = 0 - dismemberable = 0 + dismemberable = FALSE + can_be_disabled = FALSE max_damage = 100 animal_origin = ALIEN_BODYPART /obj/item/bodypart/r_arm/devil - dismemberable = 0 + dismemberable = FALSE + can_be_disabled = FALSE max_damage = 5000 animal_origin = DEVIL_BODYPART @@ -215,31 +273,58 @@ px_x = -2 px_y = 12 max_stamina_damage = 50 + can_be_disabled = TRUE -/obj/item/bodypart/l_leg/is_disabled() - if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG)) - return BODYPART_DISABLED_PARALYSIS - return ..() + +/obj/item/bodypart/l_leg/set_owner(new_owner) + . = ..() + if(. == FALSE) + return + if(owner) + if(HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG)) + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG), .proc/on_owner_paralysis_loss) + else + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG), .proc/on_owner_paralysis_gain) + if(.) + var/mob/living/carbon/old_owner = . + if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_L_LEG)) + UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG)) + if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_L_LEG)) + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) + else + UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG)) + + +///Proc to react to the owner gaining the TRAIT_PARALYSIS_L_LEG trait. +/obj/item/bodypart/l_leg/proc/on_owner_paralysis_gain(mob/living/carbon/source) + SIGNAL_HANDLER + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) + UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG)) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG), .proc/on_owner_paralysis_loss) + + +///Proc to react to the owner losing the TRAIT_PARALYSIS_L_LEG trait. +/obj/item/bodypart/l_leg/proc/on_owner_paralysis_loss(mob/living/carbon/source) + SIGNAL_HANDLER + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_L_LEG) + UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG)) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG), .proc/on_owner_paralysis_gain) /obj/item/bodypart/l_leg/set_disabled(new_disabled) . = ..() - if(isnull(.)) + if(isnull(.) || !owner) return - if(. == BODYPART_NOT_DISABLED) - if(bodypart_disabled != BODYPART_NOT_DISABLED) - owner.set_usable_legs(owner.usable_legs + 1) - else if(bodypart_disabled == BODYPART_NOT_DISABLED) - owner.set_usable_legs(owner.usable_legs - 1) - switch(bodypart_disabled) - if(BODYPART_DISABLED_DAMAGE) + + if(!.) + if(bodypart_disabled) + owner.set_usable_legs(owner.usable_legs - 1) if(owner.stat < UNCONSCIOUS) - owner.emote("scream") - if(owner.stat < DEAD) - to_chat(owner, "Your [name] is too damaged to function!") - if(BODYPART_DISABLED_PARALYSIS) - if(owner.stat < DEAD) - to_chat(owner, "You can't feel your [name]!") + to_chat(owner, "Your lose control of your [name]!") + else if(!bodypart_disabled) + owner.set_usable_legs(owner.usable_legs + 1) /obj/item/bodypart/l_leg/digitigrade @@ -258,12 +343,14 @@ icon_state = "alien_l_leg" px_x = 0 px_y = 0 - dismemberable = 0 + dismemberable = FALSE + can_be_disabled = FALSE max_damage = 100 animal_origin = ALIEN_BODYPART /obj/item/bodypart/l_leg/devil - dismemberable = 0 + dismemberable = FALSE + can_be_disabled = FALSE max_damage = 5000 animal_origin = DEVIL_BODYPART @@ -283,31 +370,58 @@ px_x = 2 px_y = 12 max_stamina_damage = 50 + can_be_disabled = TRUE -/obj/item/bodypart/r_leg/is_disabled() - if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG)) - return BODYPART_DISABLED_PARALYSIS - return ..() + +/obj/item/bodypart/r_leg/set_owner(new_owner) + . = ..() + if(. == FALSE) + return + if(owner) + if(HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG)) + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG), .proc/on_owner_paralysis_loss) + else + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG), .proc/on_owner_paralysis_gain) + if(.) + var/mob/living/carbon/old_owner = . + if(HAS_TRAIT(old_owner, TRAIT_PARALYSIS_R_LEG)) + UnregisterSignal(old_owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG)) + if(!owner || !HAS_TRAIT(owner, TRAIT_PARALYSIS_R_LEG)) + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) + else + UnregisterSignal(old_owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG)) + + +///Proc to react to the owner gaining the TRAIT_PARALYSIS_R_LEG trait. +/obj/item/bodypart/r_leg/proc/on_owner_paralysis_gain(mob/living/carbon/source) + SIGNAL_HANDLER + ADD_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) + UnregisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG)) + RegisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG), .proc/on_owner_paralysis_loss) + + +///Proc to react to the owner losing the TRAIT_PARALYSIS_R_LEG trait. +/obj/item/bodypart/r_leg/proc/on_owner_paralysis_loss(mob/living/carbon/source) + SIGNAL_HANDLER + REMOVE_TRAIT(src, TRAIT_PARALYSIS, TRAIT_PARALYSIS_R_LEG) + UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_LEG)) + RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG), .proc/on_owner_paralysis_gain) /obj/item/bodypart/r_leg/set_disabled(new_disabled) . = ..() - if(isnull(.)) + if(isnull(.) || !owner) return - if(. == BODYPART_NOT_DISABLED) - if(bodypart_disabled != BODYPART_NOT_DISABLED) - owner.set_usable_legs(owner.usable_legs + 1) - else if(bodypart_disabled == BODYPART_NOT_DISABLED) - owner.set_usable_legs(owner.usable_legs - 1) - switch(bodypart_disabled) - if(BODYPART_DISABLED_DAMAGE) + + if(!.) + if(bodypart_disabled) + owner.set_usable_legs(owner.usable_legs - 1) if(owner.stat < UNCONSCIOUS) - owner.emote("scream") - if(owner.stat < DEAD) - to_chat(owner, "Your [name] is too damaged to function!") - if(BODYPART_DISABLED_PARALYSIS) - if(owner.stat < DEAD) - to_chat(owner, "You can't feel your [name]!") + to_chat(owner, "Your lose control of your [name]!") + else if(!bodypart_disabled) + owner.set_usable_legs(owner.usable_legs + 1) /obj/item/bodypart/r_leg/digitigrade @@ -326,11 +440,13 @@ icon_state = "alien_r_leg" px_x = 0 px_y = 0 - dismemberable = 0 + dismemberable = FALSE + can_be_disabled = FALSE max_damage = 100 animal_origin = ALIEN_BODYPART /obj/item/bodypart/r_leg/devil - dismemberable = 0 + dismemberable = FALSE + can_be_disabled = FALSE max_damage = 5000 animal_origin = DEVIL_BODYPART