From d5aff0fe4d326f5385f92e6d3d22eda781414bc9 Mon Sep 17 00:00:00 2001 From: Geeves <22774890+Geevies@users.noreply.github.com> Date: Thu, 27 Aug 2026 22:40:14 +0000 Subject: [PATCH] Prosthetics Fixes (#23079) * Fixed robotic and mechanically assisted organs retaining or recovering from EMP surge damage incorrectly. * Fixed several prosthetic limb interactions causing inappropriate pain, screams, blood, or organic surgery sounds. For the various tick_surge_damage procs with 'this is intentional' being removed, it's because it was moved to the base level proc which always (generally) fires, which caused double-ticks. image AI usage disclosure: The code for the tweaks here was created using GPT 5.6 Sol. --- code/game/objects/items/weapons/material/knives.dm | 7 ++++--- code/modules/mob/mob.dm | 7 ++++--- code/modules/organs/internal/_internal.dm | 1 - code/modules/organs/organ.dm | 9 +++++++-- code/modules/organs/organ_external.dm | 6 ++---- code/modules/organs/pain.dm | 2 +- code/modules/surgery/implant.dm | 13 ++++++------- code/modules/surgery/organs_internal.dm | 4 ++-- code/modules/surgery/other.dm | 2 +- html/changelogs/Geeves-surge_damage_fix.yml | 7 +++++++ 10 files changed, 34 insertions(+), 24 deletions(-) create mode 100644 html/changelogs/Geeves-surge_damage_fix.yml diff --git a/code/game/objects/items/weapons/material/knives.dm b/code/game/objects/items/weapons/material/knives.dm index 26020c3b2df..10be1785ed2 100644 --- a/code/game/objects/items/weapons/material/knives.dm +++ b/code/game/objects/items/weapons/material/knives.dm @@ -58,11 +58,12 @@ var/obj/S = thing usr.visible_message(SPAN_NOTICE("[usr] starts carefully digging out something in [H == usr ? "themselves" : H]...")) O.take_damage(8, 0, DAMAGE_FLAG_SHARP|DAMAGE_FLAG_EDGE, src) - H.custom_pain(SPAN_DANGER("It burns!"), 50) + H.custom_pain(SPAN_DANGER("It burns!"), 50, affecting = O) if(do_mob(usr, H, 100)) - H.remove_implant(S, FALSE) + H.remove_implant(S, FALSE, O) log_and_message_admins("has extracted [S] out of [key_name(H)]") - H.emote("scream") + if(ORGAN_CAN_FEEL_PAIN(O)) + H.emote("scream") /obj/item/material/knife/ritual name = "ritual knife" diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 4181b869806..e4cd5e38288 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1125,7 +1125,7 @@ /mob/proc/embedded_needs_process() return (embedded.len > 0) -/mob/proc/remove_implant(obj/item/implant, surgical_removal = FALSE) +/mob/proc/remove_implant(obj/item/implant, surgical_removal = FALSE, obj/item/organ/external/affected) if(!LAZYLEN(get_visible_implants(0))) //Yanking out last object - removing verb. remove_verb(src, /mob/proc/yank_out_object) for(var/obj/item/O in pinned) @@ -1134,7 +1134,8 @@ if(!length(pinned)) anchored = 0 implant.dropInto(loc) - implant.add_blood(src) + if(!affected || !BP_IS_ROBOTIC(affected)) + implant.add_blood(src) implant.update_icon() if(istype(implant,/obj/item/implant)) var/obj/item/implant/imp = implant @@ -1157,7 +1158,7 @@ apply_damage((implant.w_class * 7), DAMAGE_BRUTE, affected) if(!BP_IS_ROBOTIC(affected) && prob(implant.w_class * 5) && affected.sever_artery()) //I'M SO ANEMIC I COULD JUST -DIE-. custom_pain("Something tears wetly in your [affected.name] as [implant] is pulled free!", 50, affecting = affected) - . = ..() + . = ..(implant, surgical_removal, affected) /mob/proc/yank_out_object() set category = "Object" diff --git a/code/modules/organs/internal/_internal.dm b/code/modules/organs/internal/_internal.dm index 80355b4a0d4..b7d5294a54d 100644 --- a/code/modules/organs/internal/_internal.dm +++ b/code/modules/organs/internal/_internal.dm @@ -165,7 +165,6 @@ take_damage(owner.chem_effects[toxin_type] * seconds_per_tick) handle_regeneration(seconds_per_tick) - tick_surge_damage(seconds_per_tick) //Yes, this is intentional. /obj/item/organ/internal/proc/handle_regeneration(seconds_per_tick) SHOULD_CALL_PARENT(TRUE) diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm index 4648462e9bf..c9d5c75e98d 100644 --- a/code/modules/organs/organ.dm +++ b/code/modules/organs/organ.dm @@ -181,7 +181,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) if (is_immune) germ_level = 0 - if((BP_IS_ROBOTIC(src) || robotic >= ROBOTIC_MECHANICAL) && surge_damage) + if(surge_damage) tick_surge_damage(seconds_per_tick) if(!owner) @@ -231,6 +231,8 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) do_surge_effects() surge_damage = max(0, surge_damage - (surge_recovery_per_second * seconds_per_tick)) + if(!surge_damage) + clear_surge_effects() return surge_damage /obj/item/organ/proc/do_surge_effects() @@ -294,6 +296,8 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) /obj/item/organ/proc/rejuvenate() damage = 0 + surge_damage = 0 + clear_surge_effects() /obj/item/organ/proc/heal_damage(amount) if(can_recover()) @@ -447,9 +451,10 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) #define MAXIMUM_SURGE_DAMAGE 100 /obj/item/organ/proc/take_surge_damage(var/surge) - if(!BP_IS_ROBOTIC(src)) + if(!(status & ORGAN_ASSISTED)) return //We check earlier, but just to make sure. + START_PROCESSING(SSprocessing, src) surge_damage = clamp(0, surge + surge_damage, MAXIMUM_SURGE_DAMAGE) //We want X seconds at most of hampered movement or what have you. /** diff --git a/code/modules/organs/organ_external.dm b/code/modules/organs/organ_external.dm index b10a564d3ea..f30e5490c13 100644 --- a/code/modules/organs/organ_external.dm +++ b/code/modules/organs/organ_external.dm @@ -782,6 +782,8 @@ This function completely restores a damaged organ to perfect condition. /obj/item/organ/external/proc/need_process() if(BP_IS_ROBOTIC(src)) return surge_damage + if(surge_damage) + return TRUE if(get_pain() || status & (ORGAN_CUT_AWAY|ORGAN_BLEEDING|ORGAN_BROKEN|ORGAN_DESTROYED|ORGAN_SPLINTED|ORGAN_DEAD|ORGAN_MUTATED|ORGAN_ARTERY_CUT) || brute_dam || burn_dam) return TRUE if(last_dam != brute_dam + burn_dam) // Process when we are fully healed up. @@ -813,9 +815,6 @@ This function completely restores a damaged organ to perfect condition. if(!(status & ORGAN_BROKEN)) perma_injury = 0 - if(surge_damage && (status & ORGAN_ASSISTED)) - tick_surge_damage(seconds_per_tick) //Yes, this being here is intentional since this proc does not call ..() unless the owner is null. - //Infections update_germs() @@ -823,7 +822,6 @@ This function completely restores a damaged organ to perfect condition. check_rigsplints() /obj/item/organ/external/do_surge_effects() - START_PROCESSING(SSprocessing, src) if(prob(surge_damage)) owner.custom_pain("The artificial nerves in your [name] scream out in pain!", surge_damage/6) diff --git a/code/modules/organs/pain.dm b/code/modules/organs/pain.dm index 1c377eecda3..db8bab0e9ac 100644 --- a/code/modules/organs/pain.dm +++ b/code/modules/organs/pain.dm @@ -7,7 +7,7 @@ // power decides how much painkillers will stop the message // force means it ignores anti-spam timer /mob/living/carbon/proc/custom_pain(var/message, var/power, var/force, var/obj/item/organ/external/affecting, var/nohalloss) - if(!message || stat || !can_feel_pain() || chem_effects[CE_PAINKILLER] > power) + if(!message || stat || !can_feel_pain() || (affecting && !ORGAN_CAN_FEEL_PAIN(affecting)) || chem_effects[CE_PAINKILLER] > power) return 0 power -= chem_effects[CE_PAINKILLER]/2 //Take the edge off. diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index ed8a182fcfc..9b3e4162739 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -60,7 +60,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts making some space inside [target]'s [get_cavity(affected)] cavity with \the [tool].", \ "You start making some space inside [target]'s [get_cavity(affected)] cavity with \the [tool]." ) - target.custom_pain("The pain in your chest is living hell!",1) + target.custom_pain("The pain in your chest is living hell!", 1, affecting = affected) affected.cavity = CAVITY_OPEN ..() @@ -91,7 +91,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts mending [target]'s [get_cavity(affected)] cavity wall with \the [tool].", \ "You start mending [target]'s [get_cavity(affected)] cavity wall with \the [tool]." ) - target.custom_pain("The pain in your chest is living hell!", 75) + target.custom_pain("The pain in your chest is living hell!", 75, affecting = affected) affected.cavity = CAVITY_CLOSED ..() @@ -125,8 +125,8 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts putting \the [tool] inside [target]'s [get_cavity(affected)] cavity.", \ SPAN_NOTICE("You start putting \the [tool] inside [target]'s [get_cavity(affected)] cavity." )) - target.custom_pain("The pain in your chest is living hell!", 75) - playsound(target.loc, 'sound/effects/squelch1.ogg', 50, 1) + target.custom_pain("The pain in your chest is living hell!", 75, affecting = affected) + playsound(target.loc, BP_IS_ROBOTIC(affected) ? 'sound/items/wrench.ogg' : 'sound/effects/squelch1.ogg', 50, 1) ..() /singleton/surgery_step/cavity/place_item/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -168,7 +168,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts poking around inside [target]'s [affected.name] with \the [tool].", \ "You start poking around inside [target]'s [affected.name] with \the [tool]." ) - target.custom_pain("The pain in your [affected.name] is living hell!", 50) + target.custom_pain("The pain in your [affected.name] is living hell!", 50, affecting = affected) ..() /singleton/surgery_step/cavity/implant_removal/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -203,7 +203,7 @@ worm.detach() worm.leave_host() - playsound(target.loc, 'sound/effects/squelch1.ogg', 50, 1) + playsound(target.loc, BP_IS_ROBOTIC(affected) ? 'sound/items/wrench.ogg' : 'sound/effects/squelch1.ogg', 50, 1) else user.visible_message("[user] could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.", \ SPAN_NOTICE("You could not find anything inside [target]'s [affected.name].") ) @@ -214,4 +214,3 @@ user.visible_message(SPAN_WARNING("[user] loses their grip and stabs [target] with \the [tool]!"), SPAN_WARNING("You lose your grip on \the [tool] and stab [target]!")) affected.sever_artery() target.apply_damage(25, DAMAGE_BRUTE, target_zone) - diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm index 90a8beaa4d5..eecc31d53b2 100644 --- a/code/modules/surgery/organs_internal.dm +++ b/code/modules/surgery/organs_internal.dm @@ -142,7 +142,7 @@ user.visible_message("[user] starts mending the damage to [target]'s [I.name]'s mechanisms.", \ SPAN_NOTICE("You start mending the damage to [target]'s [I.name]'s mechanisms." )) - target.custom_pain("The pain in your [affected.name] is living hell!", 75) + target.custom_pain("The pain in your [affected.name] is living hell!", 75, affecting = affected) ..() /singleton/surgery_step/internal/fix_organ_robotic/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) @@ -383,7 +383,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message("[user] starts transplanting \the [tool] into [target]'s [affected.name].", \ "You start transplanting \the [tool] into [target]'s [affected.name].") - target.custom_pain("Someone's rooting around in your [affected.name]!", 75) + target.custom_pain("Someone's rooting around in your [affected.name]!", 75, affecting = affected) ..() /singleton/surgery_step/internal/replace_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) diff --git a/code/modules/surgery/other.dm b/code/modules/surgery/other.dm index 14e05665682..263f4f13ccc 100644 --- a/code/modules/surgery/other.dm +++ b/code/modules/surgery/other.dm @@ -302,7 +302,7 @@ var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message(SPAN_DANGER("[user] is beginning to amputate [target]'s [affected.name] with \the [tool].") , \ SPAN_DANGER("You begin to cut through [target]'s [affected.amputation_point] with \the [tool].")) - target.custom_pain("Your [affected.amputation_point] is being ripped apart!", 75) + target.custom_pain("Your [affected.amputation_point] is being ripped apart!", 75, affecting = affected) ..() /singleton/surgery_step/amputate/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool) diff --git a/html/changelogs/Geeves-surge_damage_fix.yml b/html/changelogs/Geeves-surge_damage_fix.yml new file mode 100644 index 00000000000..adab8d6dc93 --- /dev/null +++ b/html/changelogs/Geeves-surge_damage_fix.yml @@ -0,0 +1,7 @@ +author: Geeves + +delete-after: True + +changes: + - bugfix: "Fixed robotic and mechanically assisted organs retaining or recovering from EMP surge damage incorrectly." + - bugfix: "Fixed several prosthetic limb interactions causing inappropriate pain, screams, blood, or organic surgery sounds."