Files
Aurora.3/code/modules/surgery/organs_internal.dm
T
VMSolidus 4379dd2c1b Surgery Soft Requirement Refactor (#22314)
Skills being based on "Hard Requirements" absolutely suck, and I wasn't
happy with the surgery code being essentially hardcoded around them. So
this PR refactors surgery to use soft requirement checks, based on
modifiers to the success rate probability. Surgeries still state what
skills (if any) they require and at what level, but rather than blocking
the surgery, it instead imposes a penalty(or bonus) on the success
chance based on how much the user's surgical skill differs from the
required level. This actually stacks with the penalties for "non ideal
tools", so if you're completely unskilled in surgery and you attempt to
make an incision with a shard of glass, you're going to have an
extremely hard time.

Individual surgeries also can define how much the success rate is
modified by "skill diff", with the more advanced "surgeon exclusive"
surgeries having extremely large potential modifiers.

I have also added a signal based check for modifiers, which the Morale
component now hooks into. This can also allow for other components,
implants, drugs, etc to modify the surgery chances in the future.

I have manually tested this PR and verified by examining debug
breakpoints in VSCode that the system correctly applies its modifiers.
2026-04-26 19:57:59 +00:00

517 lines
22 KiB
Plaintext

// Internal surgeries.
/singleton/surgery_step/internal
priority = 2
can_infect = TRUE
blood_level = 1
skill_requirements = alist(SURGERY_SKILL_COMPONENT = SKILL_LEVEL_TRAINED)
skill_diff_fail_modifier = SURGERY_DIFFICULTY_EXTREME
/singleton/surgery_step/internal/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
if(affected.encased)
return affected && IS_ORGAN_FULLY_OPEN
if(BP_IS_ROBOTIC(affected))
return affected.augment_limit && affected.open == ORGAN_ENCASED_RETRACTED
else
return affected.augment_limit && affected.open == ORGAN_OPEN_RETRACTED
//////////////////////////////////////////////////////////////////
// CHEST INTERNAL ORGAN SURGERY //
//////////////////////////////////////////////////////////////////
/singleton/surgery_step/internal/fix_organ
name = "Repair Internal Organs"
allowed_tools = list(
/obj/item/stack/medical/advanced/bruise_pack= 100, \
/obj/item/stack/medical/bruise_pack = 20
)
min_duration = 50
max_duration = 70
skill_requirements = alist(SURGERY_SKILL_COMPONENT = SKILL_LEVEL_TRAINED)
/singleton/surgery_step/internal/fix_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
var/is_organ_damaged = FALSE
for(var/obj/item/organ/internal/I in affected.internal_organs)
if(I.is_damaged())
if(BP_IS_ROBOTIC(I))
to_chat(user, SPAN_NOTICE("You notice that \the [I] in [user]'s [affected.name] is a mechanical organ, and is also damaged."))
continue
is_organ_damaged = TRUE
return is_organ_damaged
/singleton/surgery_step/internal/fix_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/tool_name = "\the [tool]"
if(istype(tool, /obj/item/stack/medical/advanced/bruise_pack))
tool_name = "regenerative membrane"
else if(istype(tool, /obj/item/stack/medical/bruise_pack))
tool_name = "some bandaids"
var/obj/item/organ/external/affected = target.get_organ(target_zone)
for(var/obj/item/organ/internal/I in affected.internal_organs)
if(I && I.is_damaged() && !BP_IS_ROBOTIC(I) && (~I.status & ORGAN_DEAD || I.can_recover()))
user.visible_message("[user] starts treating damage to [target]'s [I.name] with [tool_name].", \
"You start treating damage to [target]'s [I.name] with [tool_name]." )
target.custom_pain("The pain in your [affected.name] is living hell!",100, affecting = affected)
..()
/singleton/surgery_step/internal/fix_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/tool_name = "\the [tool]"
if(istype(tool, /obj/item/stack/medical/advanced/bruise_pack))
tool_name = "regenerative membrane"
if(istype(tool, /obj/item/stack/medical/bruise_pack))
tool_name = "some bandaids"
if(!ishuman(target))
return
var/obj/item/organ/external/affected = target.get_organ(target_zone)
for(var/obj/item/organ/internal/I in affected.internal_organs)
if(I && I.is_damaged() && !BP_IS_ROBOTIC(I))
if(I.status & ORGAN_DEAD && I.can_recover())
user.visible_message(SPAN_NOTICE("\The [user] treats damage to [target]'s [I.name] with [tool_name], though it needs to be recovered further."), \
SPAN_NOTICE("You treat damage to [target]'s [I.name] with [tool_name], though it needs to be recovered further.") )
else
user.visible_message(SPAN_NOTICE("[user] treats damage to [target]'s [I.name] with [tool_name]."), \
SPAN_NOTICE("You treat damage to [target]'s [I.name] with [tool_name]."))
I.surgical_fix(user)
user.visible_message("\The [user] finishes treating damage within \the [target]'s [affected.name] with [tool_name].", \
"You finish treating damage within \the [target]'s [affected.name] with [tool_name].")
if(I.status & ORGAN_DEAD)
to_chat(user, SPAN_DANGER("This organ is still dead! You must remove the dead tissue with a scalpel!"))
/singleton/surgery_step/internal/fix_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!ishuman(target))
return
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message(SPAN_WARNING("[user]'s hand slips, getting mess and tearing the inside of [target]'s [affected.name] with \the [tool]!"), \
SPAN_WARNING("Your hand slips, getting mess and tearing the inside of [target]'s [affected.name] with \the [tool]!"))
var/dam_amt = 2
if(istype(tool, /obj/item/stack/medical/advanced/bruise_pack))
target.adjustToxLoss(5)
else if(istype(tool, /obj/item/stack/medical/bruise_pack))
dam_amt = 5
target.adjustToxLoss(10)
target.apply_damage(5, DAMAGE_BRUTE, target_zone, 0, tool)
for(var/obj/item/organ/internal/I in affected.internal_organs)
if(I && I.is_damaged())
I.take_damage(dam_amt,0)
/singleton/surgery_step/internal/fix_organ_robotic //For artificial organs
name = "Repair Robotic Organ"
allowed_tools = list(
/obj/item/stack/nanopaste = 100,
/obj/item/surgery/bone_gel = 30,
TOOL_SCREWDRIVER = 70
)
min_duration = 50
max_duration = 70
skill_requirements = alist(ROBOTICS_SKILL_COMPONENT = SKILL_LEVEL_FAMILIAR)
/singleton/surgery_step/internal/fix_organ_robotic/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
var/is_organ_damaged = 0
for(var/obj/item/organ/internal/I in affected.internal_organs)
if(I.is_damaged())
if(!BP_IS_ROBOTIC(I))
to_chat(user, SPAN_NOTICE("You notice that \the [I] in [user]'s [affected.name] is a biological organ, and is also damaged."))
continue
is_organ_damaged = TRUE
return is_organ_damaged && IS_ORGAN_FULLY_OPEN
/singleton/surgery_step/internal/fix_organ_robotic/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!ishuman(target))
return
var/obj/item/organ/external/affected = target.get_organ(target_zone)
for(var/obj/item/organ/internal/I in affected.internal_organs)
if(I && I.is_damaged())
if(I.robotic >= 2)
user.visible_message("<b>[user]</b> 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)
..()
/singleton/surgery_step/internal/fix_organ_robotic/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!ishuman(target))
return
var/obj/item/organ/external/affected = target.get_organ(target_zone)
for(var/obj/item/organ/internal/I in affected.internal_organs)
if(I && I.is_damaged())
if(I.robotic >= 2)
user.visible_message("<b>[user]</b> repairs [target]'s [I.name] with [tool].", \
SPAN_NOTICE("You repair [target]'s [I.name] with [tool].") )
I.surgical_fix(user)
if(istype(tool, /obj/item/stack/nanopaste))
var/obj/item/stack/nanopaste/nanopaste = tool
nanopaste.use(1)
return
/singleton/surgery_step/internal/fix_organ_robotic/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!ishuman(target))
return
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message(SPAN_WARNING("[user]'s hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!"), \
SPAN_WARNING("Your hand slips, gumming up the mechanisms inside of [target]'s [affected.name] with \the [tool]!"))
target.adjustToxLoss(5)
target.apply_damage(5, DAMAGE_BRUTE, target_zone, 0, tool, damage_flags = tool.damage_flags())
for(var/obj/item/organ/internal/I in affected.internal_organs)
if(I)
I.take_damage(rand(3,5),0)
/singleton/surgery_step/internal/detach_organ
name = "Separate Organ"
priority = 1
allowed_tools = list(
TOOL_SCALPEL = 100,
/obj/item/material/knife = 75,
/obj/item/material/shard = 50
)
min_duration = 70
max_duration = 90
skill_requirements = alist(SURGERY_SKILL_COMPONENT = SKILL_LEVEL_TRAINED)
/singleton/surgery_step/internal/detach_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
if(!(affected && !BP_IS_ROBOTIC(affected)))
return FALSE
target.op_stage.current_organ = null
var/list/attached_organs = list()
for(var/organ in target.internal_organs_by_name)
var/obj/item/organ/I = target.internal_organs_by_name[organ]
/// Zombie organs can't be removed. Mainly to stop the zombie parasite from being removed.
if(I && (I.status & ORGAN_ZOMBIFIED))
continue
if(I && !(I.status & ORGAN_CUT_AWAY) && I.parent_organ == target_zone)
attached_organs |= organ
var/organ_to_remove = tgui_input_list(user, "Which organ do you want to prepare for removal?", "Surgery", attached_organs)
if(!organ_to_remove)
return FALSE
target.op_stage.current_organ = organ_to_remove
return organ_to_remove
/singleton/surgery_step/internal/detach_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message("<b>[user]</b> starts to separate [target]'s [target.op_stage.current_organ] with \the [tool].", \
SPAN_NOTICE("You start to separate [target]'s [target.op_stage.current_organ] with \the [tool]." ))
target.custom_pain("The pain in your [affected.name] is living hell!", 75)
..()
/singleton/surgery_step/internal/detach_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
user.visible_message("<b>[user]</b> has separated [target]'s [target.op_stage.current_organ] with \the [tool]." , \
SPAN_NOTICE("You have separated [target]'s [target.op_stage.current_organ] with \the [tool]."))
var/obj/item/organ/I = target.internal_organs_by_name[target.op_stage.current_organ]
if(I && istype(I))
I.status |= ORGAN_CUT_AWAY
target.update_body()
target.updatehealth()
target.UpdateDamageIcon()
/singleton/surgery_step/internal/detach_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message(SPAN_WARNING("[user]'s hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!"), \
SPAN_WARNING("Your hand slips, slicing an artery inside [target]'s [affected.name] with \the [tool]!"))
affected.sever_artery()
target.apply_damage(rand(30, 50), DAMAGE_BRUTE, target_zone, 0, tool, damage_flags = tool.damage_flags())
/singleton/surgery_step/internal/remove_organ
name = "Remove Organ"
allowed_tools = list(
TOOL_HEMOSTAT = 100, \
TOOL_WIRECUTTER = 75, \
/obj/item/material/kitchen/utensil/fork = 20
)
min_duration = 40
max_duration = 60
skill_requirements = alist(SURGERY_SKILL_COMPONENT = SKILL_LEVEL_TRAINED)
/singleton/surgery_step/internal/remove_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
target.op_stage.current_organ = null
var/list/removable_organs = list()
for(var/organ in target.internal_organs_by_name)
var/obj/item/organ/I = target.internal_organs_by_name[organ]
if((I.status & ORGAN_CUT_AWAY) && I.parent_organ == target_zone)
removable_organs |= organ
var/organ_to_remove = tgui_input_list(user, "Which organ do you want to remove?", "Surgery", removable_organs)
if(!organ_to_remove)
return FALSE
target.op_stage.current_organ = organ_to_remove
return ..()
/singleton/surgery_step/internal/remove_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
user.visible_message("[user] starts removing [target]'s [target.op_stage.current_organ] with \the [tool].", \
"You start removing [target]'s [target.op_stage.current_organ] with \the [tool].")
target.custom_pain("Someone's ripping out your [target.op_stage.current_organ]!", 75)
..()
/singleton/surgery_step/internal/remove_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
user.visible_message(SPAN_NOTICE("[user] has removed [target]'s [target.op_stage.current_organ] with \the [tool]."), \
SPAN_NOTICE("You have removed [target]'s [target.op_stage.current_organ] with \the [tool]."))
// Extract the organ!
if(target.op_stage.current_organ)
var/obj/item/organ/O = target.internal_organs_by_name[target.op_stage.current_organ]
if(O && istype(O))
O.removed(target, user)
target.op_stage.current_organ = null
if(!(O.status & ORGAN_ROBOT))
playsound(target.loc, 'sound/effects/squelch1.ogg', 15, 1)
else
playsound(target.loc, 'sound/items/wrench.ogg', 50, 1)
target.update_body()
target.updatehealth()
target.UpdateDamageIcon()
/singleton/surgery_step/internal/remove_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message(SPAN_WARNING("[user]'s hand slips, damaging [target]'s [affected.name] with \the [tool]!"), \
SPAN_WARNING("Your hand slips, damaging [target]'s [affected.name] with \the [tool]!"))
target.apply_damage(20, DAMAGE_BRUTE, target_zone, 0, tool, damage_flags = tool.damage_flags())
/singleton/surgery_step/internal/replace_organ
name = "Replace Organ"
allowed_tools = list(
/obj/item/organ = 100
)
min_duration = 40
max_duration = 60
skill_requirements = alist(SURGERY_SKILL_COMPONENT = SKILL_LEVEL_TRAINED)
/singleton/surgery_step/internal/replace_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
testing("Attempting to install [tool] failed with parent check!")
return FALSE
var/obj/item/organ/O = tool
var/obj/item/organ/external/affected = target.get_organ(target_zone)
var/organ_compatible
var/organ_missing
if(!istype(O))
return FALSE
if(BP_IS_ROBOTIC(affected) && !BP_IS_ROBOTIC(O))
to_chat(user, SPAN_DANGER("You cannot install a naked organ into a robotic body."))
return SURGERY_FAILURE
if(!target.species)
to_chat(user, SPAN_DANGER("You have no idea what species this person is. Report this on the bug tracker."))
return SURGERY_FAILURE
var/o_is = (O.gender == PLURAL) ? "are" : "is"
var/o_a = (O.gender == PLURAL) ? "" : "a "
var/o_do = (O.gender == PLURAL) ? "don't" : "doesn't"
if(O.organ_tag == "limb")
return FALSE
else if(target.species.has_organ[O.organ_tag] || O.is_augment)
if(O.damage > (O.max_damage * 0.75))
to_chat(user, SPAN_WARNING("\The [O.organ_tag] [o_is] in no state to be transplanted."))
return SURGERY_FAILURE
if(O.species_restricted)
if(!(target.species.name in O.species_restricted))
to_chat(user, SPAN_WARNING("\The [O] is not compatible with \the [target]'s biology."))
return SURGERY_FAILURE
if(O.is_augment)
if(affected.augment_limit)
var/total_augments
for(var/obj/item/organ/internal/I in affected.internal_organs)
if(I.is_augment)
total_augments += 1
if(total_augments >= affected.augment_limit)
to_chat(user, SPAN_WARNING("There is no space left in \the [affected] to implant \the [O]."))
return SURGERY_FAILURE
else
to_chat(user, SPAN_WARNING("There is no space in \the [affected] to implant \the [O]."))
return SURGERY_FAILURE
if(!target.internal_organs_by_name[O.organ_tag])
organ_missing = TRUE
else
to_chat(user, SPAN_WARNING("\The [target] already has [o_a][O.organ_tag]."))
return SURGERY_FAILURE
if(O && affected.limb_name == O.parent_organ)
organ_compatible = TRUE
else
to_chat(user, SPAN_WARNING("\The [O.organ_tag] [o_do] normally go in \the [affected.name]."))
return SURGERY_FAILURE
else
to_chat(user, SPAN_WARNING("You're pretty sure [target.species.name_plural] don't normally have [o_a][O.organ_tag]."))
return SURGERY_FAILURE
return organ_missing && organ_compatible
/singleton/surgery_step/internal/replace_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
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)
..()
/singleton/surgery_step/internal/replace_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message(SPAN_NOTICE("[user] has transplanted \the [tool] into [target]'s [affected.name]."), \
SPAN_NOTICE("You have transplanted \the [tool] into [target]'s [affected.name]."))
var/obj/item/organ/O = tool
if(istype(O) && user.unEquip(O))
O.replaced(target,affected)
playsound(target.loc, 'sound/effects/squelch1.ogg', 50, 1)
target.update_body()
target.updatehealth()
target.UpdateDamageIcon()
/singleton/surgery_step/internal/replace_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
user.visible_message(SPAN_WARNING("[user]'s hand slips, damaging \the [tool]!"), \
SPAN_WARNING("Your hand slips, damaging \the [tool]!"))
var/obj/item/organ/I = tool
if(istype(I))
I.take_damage(rand(3,5),0)
/singleton/surgery_step/internal/attach_organ
name = "Attach Organ"
allowed_tools = list(
/obj/item/surgery/fix_o_vein = 100, \
TOOL_CABLECOIL = 75
)
min_duration = 80
max_duration = 100
skill_requirements = alist(SURGERY_SKILL_COMPONENT = SKILL_LEVEL_TRAINED)
/singleton/surgery_step/internal/attach_organ/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
target.op_stage.current_organ = null
var/list/removable_organs = list()
for(var/organ in target.internal_organs_by_name)
var/obj/item/organ/I = target.internal_organs_by_name[organ]
if(I && (I.status & ORGAN_CUT_AWAY) && !BP_IS_ROBOTIC(I) && I.parent_organ == target_zone)
removable_organs |= organ
var/organ_to_replace = tgui_input_list(user, "Which organ do you want to reattach?", "Surgery", removable_organs)
if(!organ_to_replace)
return FALSE
target.op_stage.current_organ = organ_to_replace
return TRUE
/singleton/surgery_step/internal/attach_organ/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
user.visible_message("[user] begins reattaching [target]'s [target.op_stage.current_organ] with \the [tool].", \
"You start reattaching [target]'s [target.op_stage.current_organ] with \the [tool].")
target.custom_pain("Someone's digging needles into your [target.op_stage.current_organ]!", 75)
..()
/singleton/surgery_step/internal/attach_organ/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
user.visible_message(SPAN_NOTICE("[user] has reattached [target]'s [target.op_stage.current_organ] with \the [tool].") , \
SPAN_NOTICE("You have reattached [target]'s [target.op_stage.current_organ] with \the [tool]."))
var/obj/item/organ/I = target.internal_organs_by_name[target.op_stage.current_organ]
if(I && istype(I))
I.status &= ~ORGAN_CUT_AWAY
target.update_body()
target.updatehealth()
target.UpdateDamageIcon()
/singleton/surgery_step/internal/attach_organ/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message(SPAN_WARNING("[user]'s hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!"), \
SPAN_WARNING("Your hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!"))
target.apply_damage(20, DAMAGE_BRUTE, target_zone, 0, tool, damage_flags = tool.damage_flags())
/singleton/surgery_step/internal/prepare
name = "Prepare Brain"
allowed_tools = list(
/obj/item/surgery/scalpel/manager = 95,
TOOL_DRILL = 75,
/obj/item/pickaxe/ = 5
)
min_duration = 80
max_duration = 100
skill_requirements = alist(ROBOTICS_SKILL_COMPONENT = SKILL_LEVEL_TRAINED)
/singleton/surgery_step/internal/prepare/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
if(!..())
return FALSE
var/obj/item/organ/external/affected = target.get_organ(target_zone)
var/obj/item/organ/internal/brain/sponge = target.internal_organs_by_name[BP_BRAIN]
if(!istype(sponge) || !(sponge in affected.internal_organs))
return FALSE
if(!sponge.can_prepare || sponge.prepared)
return FALSE
target.op_stage.current_organ = sponge
return TRUE
/singleton/surgery_step/internal/prepare/begin_step(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/internal/brain/B = target.op_stage.current_organ
user.visible_message("[user] begins to modify [target]'s [B] to prepare it for Man-Machine-Interface compatibility with \the [tool].", \
"You start to modify [target]'s [B] to prepare it for Man-Machine-Interface compatibility with \the [tool].")
target.custom_pain("Someone's scraping away at your [B]!", 75)
..()
/singleton/surgery_step/internal/prepare/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/internal/brain/B = target.op_stage.current_organ
user.visible_message(SPAN_NOTICE("[user] has modified [target]'s [B] to prepare it for Man-Machine-Interface compatibility with \the [tool].") , \
SPAN_NOTICE("You prepare \the [target]'s brain for Man-Machine-Interface compatibility with \the [tool]."))
B.prepared = TRUE
/singleton/surgery_step/internal/prepare/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message(SPAN_WARNING("[user]'s hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!"), \
SPAN_WARNING("Your hand slips, damaging the flesh in [target]'s [affected.name] with \the [tool]!"))
target.apply_damage(20, DAMAGE_BRUTE, target_zone, 0, tool, damage_flags = tool.damage_flags())