Adds flaying, human butchering and limb surgeries (#94612)

## About The Pull Request

Merry Christmas!

This PR expands on the more gruesome areas of chef content, such as
cannibalism.
Human limbs can now be individually butchered for their meat and skin
with a knife or another butchering implement once the skin has been cut
and retracted (forks now can be used as bootleg retractors). If the limb
contains organs, those will need to be removed first, which also can be
quickly performed with a butchering tool at the cost of damaging the
inhards (head and chest will require the bone to be cut first, which can
be done with a butcher's cleaver if you don't have a saw)
You can also butcher humans whole by right clicking them with a
butchering implement on combat mode, which will attempt to gut/cut apart
the selected limb. Obviously this requires the limb to be prepped first,
so meat hooks/kitchenspikes now allow mobs strung on them to be operated
on without needing drapes. Its a pretty bad spot to be performing
surgeries at though, so beware! Torsos can only be butchered after all
other limbs have been. The gutting/butchering delay is based off the
owner's stat, halving if the limb is detached and doubling if the owner
is still alive and kicking.

<img width="392" height="265" alt="dreamseeker_D7QWbWKStd"
src="https://github.com/user-attachments/assets/050d7c25-3572-4b02-ae93-d8efefe54885"
/>

(The video is too large for github)
https://streamable.com/459a0y

After being butchered, most limbs will leave behind a nonfunctional
skeletal limb (with exceptions like jelly limbs with no skeleton inside)
which is always disabled. Skeleton chests husk their owner, so you'll
need to replace it first.
Gibbers now source their meat from the victim's limbs (and not their
species) at an RNG-based percentage based on the matter bin's tier.

As to allow individual limbs to be butchered, you can now perform (some)
surgeries on individual limbs. There are some obvious restrictions like
zombification or bioware surgeries, but most of the ones that make sense
can be performed on someone's chopped off head as long as you've got the
tools.
Wounds also contribute to surgeries now, major slash wounds count as
cut/open skin (and sealing the vessels would reduce their bleed rate),
and critical blunt wounds count as sawed bones.

I've refactored gibbers, butchering and meat spike code as well as fixed
some backend bugs while I was at it.

## Why It's Good For The Game

While rather gruesome, I feel like the freedom which these mechanics
provide fits us pretty well. We already have plenty of nasty stuff and
this doesn't really go that much further, and a chef serving their own
leg in their dish is pretty funny. (Also you can scrape plasma off
plasmamen bones)
This commit is contained in:
SmArtKar
2025-12-31 12:55:39 -06:00
committed by GitHub
parent 8b74157ccd
commit a4f0dcb76f
70 changed files with 1515 additions and 760 deletions
+98 -54
View File
@@ -78,8 +78,8 @@
var/can_be_disabled = FALSE //Defaults to FALSE, as only human limbs can be disabled, and only the appendages.
///Controls if the limb is disabled. TRUE means it is disabled (similar to being removed, but still present for the sake of targeted interactions).
var/bodypart_disabled = FALSE
///Handles limb disabling by damage. If 0 (0%), a limb can't be disabled via damage. If 1 (100%), it is disabled at max limb damage. Anything between is the percentage of damage against maximum limb damage needed to disable the limb.
var/disabling_threshold_percentage = 0
///Handles limb disabling by damage. If LIMB_NO_DISABLE (-1), a limb can't be disabled via damage. If 1 (100%), it is disabled at max limb damage. Anything between is the percentage of damage against maximum limb damage needed to disable the limb.
var/disabling_threshold_percentage = LIMB_NO_DISABLE
// Damage variables
///A mutiplication of the burn and brute damage that the limb's stored damage contributes to its attached mob's overall wellbeing.
@@ -222,7 +222,15 @@
var/list/bodypart_effects
/// The cached info about the blood this organ belongs to, set during on_removal()
var/list/blood_dna_info
/// What items we drop whenever we're butchered
/// If unset, the bodyparot cannot be butchered
var/list/butcher_drops = null
/// What skeleton limb, if any, we replace ourselves with when butchered?
var/obj/item/bodypart/butcher_replacement = null
/// How much meat do we add to butcher_drops when automatically generating them from our species datum?
var/base_meat_amount = 1
/// Init cache for our butcher drops for sanic speed
var/static/list/butcher_drop_cache = list()
/// What state is the bodypart in for determining surgery availability
VAR_FINAL/surgery_state = NONE
@@ -268,6 +276,11 @@
add_surgical_state(innate_state)
name = "[limb_id] [parse_zone(body_zone)]"
// There's a lot of bodyparts in the world, and we don't need to have separate drops on each and every one of them
var/list/drop_results = get_butcher_drops()
if (length(drop_results))
butcher_drops = string_list(drop_results)
butcher_drop_cache[type] = butcher_drops
update_icon_dropped()
refresh_bleed_rate()
@@ -301,6 +314,16 @@
return FALSE
return ..()
/obj/item/bodypart/proc/get_butcher_drops()
if(!isnull(butcher_drops))
return butcher_drops
if (butcher_drop_cache[type])
return butcher_drop_cache[type]
var/datum/species/species = GLOB.species_list[limb_id]
if (!species || !species.meat || !base_meat_amount)
return null
return list(species.meat = base_meat_amount)
/obj/item/bodypart/proc/on_forced_removal(atom/old_loc, dir, forced, list/old_locs)
SIGNAL_HANDLER
@@ -326,6 +349,10 @@
if(wound_desc)
. += wound_desc
var/surgery_examine = get_surgery_examine()
if(surgery_examine)
. += surgery_examine
/**
* Called when a bodypart is checked for injuries.
*/
@@ -475,8 +502,8 @@
/// Returns surgery examine information for this bodypart
/obj/item/bodypart/proc/get_surgery_examine()
var/t_his = owner.p_their()
var/t_His = owner.p_Their()
var/lowercase_zone = owner ? "[owner.p_their()] [plaintext_zone]" : "[src]"
var/capital_zone = owner ? "[owner.p_Their()] [plaintext_zone]" : capitalize("[src]")
var/single_message = ""
var/list/sub_messages = list()
var/reported_state = surgery_state
@@ -489,42 +516,42 @@
if(HAS_SURGERY_STATE(reported_state, SURGERY_SKIN_CUT))
sub_messages += "skin has been incised"
single_message = "The skin on [t_his] [plaintext_zone] has been incised."
single_message = "The skin on [lowercase_zone] has been incised."
if(HAS_SURGERY_STATE(reported_state, SURGERY_SKIN_OPEN))
sub_messages += "skin is opened"
single_message = "The skin on [t_his] [plaintext_zone] is opened."
single_message = "The skin on [lowercase_zone] is opened."
// We can only see these if the skin is open
// And we check the real state rather than reported_state
if(LIMB_HAS_ANY_SURGERY_STATE(src, ALL_SURGERY_SKIN_STATES))
if(HAS_SURGERY_STATE(reported_state, SURGERY_VESSELS_UNCLAMPED))
sub_messages += "blood vessels are unclamped[cached_bleed_rate ? " and bleeding" : ""]"
single_message = "The blood vessels in [t_his] [plaintext_zone] are unclamped[cached_bleed_rate ? " and bleeding!" : "."]"
single_message = "The blood vessels in [lowercase_zone] are unclamped[cached_bleed_rate ? " and bleeding!" : "."]"
if(HAS_SURGERY_STATE(reported_state, SURGERY_VESSELS_CLAMPED))
sub_messages += "blood vessels are clamped shut"
single_message = "The blood vessels in [t_his] [plaintext_zone] are clamped shut."
single_message = "The blood vessels in [lowercase_zone] are clamped shut."
if(HAS_SURGERY_STATE(reported_state, SURGERY_ORGANS_CUT))
sub_messages += "the organs within have been incised"
single_message = "The organs in [t_his] [plaintext_zone] have been incised."
single_message = "The organs in [lowercase_zone] have been incised."
if(HAS_SURGERY_STATE(reported_state, SURGERY_BONE_SAWED))
sub_messages += "the bones within have been sawed apart"
single_message = "The bones in [t_his] [plaintext_zone] have been sawed apart."
single_message = "The bones in [lowercase_zone] have been sawed apart."
if(HAS_SURGERY_STATE(reported_state, SURGERY_BONE_DRILLED))
sub_messages += "the bones within have been drilled through"
single_message = "The bones in [t_his] [plaintext_zone] have been drilled through."
single_message = "The bones in [lowercase_zone] have been drilled through."
if(HAS_SURGERY_STATE(reported_state, SURGERY_PROSTHETIC_UNSECURED))
sub_messages += "prosthetic item is unsecured"
single_message = "[t_His] [plaintext_zone] is unsecured and loose!"
single_message = "[capital_zone] is unsecured and loose!"
if(HAS_SURGERY_STATE(reported_state, SURGERY_PLASTIC_APPLIED))
sub_messages += "got a layer of plastic applied to it"
single_message = "A layer of plastic has been applied to [t_his] [plaintext_zone]."
single_message = "A layer of plastic has been applied to [lowercase_zone]."
if(HAS_SURGERY_STATE(reported_state, SURGERY_CAVITY_WIDENED))
sub_messages += "the chest cavity is wide open"
single_message = "[t_His] chest cavity is wide open!"
single_message = "[owner?.p_Their() || "The"] chest cavity is wide open!"
if(length(sub_messages) >= 2)
return span_danger("[t_His] [plaintext_zone]'s [english_list(sub_messages)].")
return span_danger("[capital_zone]'s [english_list(sub_messages)].")
if(single_message)
return span_danger(single_message)
return ""
@@ -555,31 +582,34 @@
return
return ..()
/obj/item/bodypart/attackby(obj/item/weapon, mob/user, list/modifiers, list/attack_modifiers)
SHOULD_CALL_PARENT(TRUE)
if(weapon.get_sharpness())
add_fingerprint(user)
if(!contents.len)
to_chat(user, span_warning("There is nothing left inside [src]!"))
return
playsound(loc, 'sound/items/weapons/slice.ogg', 50, TRUE, -1)
user.visible_message(span_warning("[user] begins to cut open [src]."),\
span_notice("You begin to cut open [src]..."))
if(do_after(user, 5.4 SECONDS, target = src))
drop_organs(user, TRUE)
else
return ..()
/obj/item/bodypart/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
SHOULD_CALL_PARENT(TRUE)
..()
. = ..()
if(IS_ORGANIC_LIMB(src))
playsound(get_turf(src), 'sound/misc/splort.ogg', 50, TRUE, -1)
pixel_x = rand(-3, 3)
pixel_y = rand(-3, 3)
/obj/item/bodypart/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(user.combat_mode)
return NONE
var/operation_zone = user.zone_selected
if (deprecise_zone(operation_zone) != body_zone)
operation_zone = body_zone
return user.perform_surgery(src, tool, LAZYACCESS(modifiers, RIGHT_CLICK), operation_zone)
/obj/item/bodypart/examine_more(mob/user)
. = ..()
var/list/operations = GLOB.operations.get_instances_from(GLOB.operations.unlocked)
var/operation_zone = user.zone_selected
if (deprecise_zone(operation_zone) != body_zone)
operation_zone = body_zone
for(var/datum/surgery_operation/operation as anything in operations)
if ((operation.operation_flags & OPERATION_NO_PATIENT_REQUIRED) && operation.show_as_next_step(src, operation_zone))
. += span_notice("You could perform [operation] on [src] with \a [operation.get_recommended_tool()]...")
//empties the bodypart from its organs and other things inside it
/obj/item/bodypart/proc/drop_organs(mob/user, violent_removal)
SHOULD_CALL_PARENT(TRUE)
@@ -593,12 +623,18 @@
for(var/obj/item/organ/bodypart_organ in contents)
if(bodypart_organ.organ_flags & ORGAN_UNREMOVABLE)
continue
if(violent_removal)
bodypart_organ.apply_organ_damage(bodypart_organ.maxHealth * 0.5)
if(owner)
bodypart_organ.Remove(bodypart_organ.owner)
else
if(bodypart_organ.bodypart_remove(src))
if(drop_loc) //can be null if being deleted
bodypart_organ.forceMove(get_turf(drop_loc))
if(!bodypart_organ.Remove(bodypart_organ.owner))
continue
else if(!bodypart_organ.bodypart_remove(src))
continue
if(drop_loc) //can be null if being deleted
bodypart_organ.forceMove(get_turf(drop_loc))
if(drop_loc) //can be null during deletion
for(var/atom/movable/movable as anything in src)
@@ -870,31 +906,31 @@
return brute_dam + burn_dam
//Checks disabled status thresholds
/obj/item/bodypart/proc/update_disabled()
/obj/item/bodypart/proc/update_disabled(update_limbs = TRUE)
SHOULD_CALL_PARENT(TRUE)
if(!owner)
return
if(!can_be_disabled)
set_disabled(FALSE)
set_disabled(FALSE, update_limbs)
CRASH("update_disabled called with can_be_disabled false")
if(HAS_TRAIT(src, TRAIT_PARALYSIS))
set_disabled(TRUE)
set_disabled(TRUE, update_limbs)
return
var/total_damage = brute_dam + burn_dam
// this block of checks is for limbs that can be disabled, but not through pure damage (AKA limbs that suffer wounds, human/monkey parts and such)
if(!disabling_threshold_percentage)
if(disabling_threshold_percentage == LIMB_NO_DISABLE)
if(total_damage < max_damage)
last_maxed = FALSE
else
if(!last_maxed && owner.stat < UNCONSCIOUS)
INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob, emote), "scream")
last_maxed = TRUE
set_disabled(FALSE) // we only care about the paralysis trait
set_disabled(FALSE, update_limbs) // we only care about the paralysis trait
return
// we're now dealing solely with limbs that can be disabled through pure damage, AKA robot parts
@@ -903,15 +939,15 @@
if(owner.stat < UNCONSCIOUS)
INVOKE_ASYNC(owner, TYPE_PROC_REF(/mob, emote), "scream")
last_maxed = TRUE
set_disabled(TRUE)
set_disabled(TRUE, update_limbs)
return
if(bodypart_disabled && total_damage <= max_damage * 0.5) // reenable the limb at 50% health
if(bodypart_disabled && total_damage < max_damage * disabling_threshold_percentage * 0.5) // reenable the limb at 50% of the threshold
last_maxed = FALSE
set_disabled(FALSE)
set_disabled(FALSE, update_limbs)
///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)
/obj/item/bodypart/proc/set_disabled(new_disabled, update_limbs = TRUE)
SHOULD_CALL_PARENT(TRUE)
PROTECTED_PROC(TRUE)
@@ -990,7 +1026,7 @@
RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_NOBLOOD), PROC_REF(on_owner_nobleed_gain))
if(can_be_disabled)
update_disabled()
update_disabled(FALSE)
RegisterSignal(owner, COMSIG_ATOM_RESTYLE, PROC_REF(on_attempt_feature_restyle_mob))
RegisterSignal(owner, COMSIG_COMPONENT_CLEAN_ACT, PROC_REF(on_owner_clean))
@@ -1458,14 +1494,14 @@
// In 99% of situations we won't get to this point if we aren't wired or blooded
// But I'm covering my ass in case someone adds some weird new species
var/surgery_bloodloss = 0
if(biological_state & BIOSTATE_HAS_VESSELS)
var/surgery_bloodloss = 0
// better clamp those up quick
if(HAS_ANY_SURGERY_STATE(surgery_state, SURGERY_VESSELS_UNCLAMPED))
surgery_bloodloss += 1.5
surgery_bloodloss += UNCLAMPED_VESSELS_BLEEDING
// better, but still not exactly ideal
else if(HAS_ANY_SURGERY_STATE(surgery_state, SURGERY_VESSELS_CLAMPED|SURGERY_ORGANS_CUT))
surgery_bloodloss += 0.2
surgery_bloodloss += CLAMPED_VESSELS_BLEEDING
// modify rate so cutting everything open won't nuke people
if(body_zone == BODY_ZONE_HEAD)
@@ -1484,6 +1520,12 @@
for(var/datum/wound/iter_wound as anything in wounds)
cached_bleed_rate += iter_wound.blood_flow
if (!(iter_wound.surgery_states & SURGERY_VESSELS_UNCLAMPED) || !surgery_bloodloss)
continue
// Consider it contirubuted by the wound itself
// Not -surgery_bloodloss as this way clamping the vessels reduces the overall bleeding
cached_bleed_rate -= UNCLAMPED_VESSELS_BLEEDING
surgery_bloodloss = 0
if(owner.body_position == LYING_DOWN)
cached_bleed_rate *= 0.75
@@ -1700,9 +1742,6 @@
/obj/item/bodypart/proc/add_surgical_state(new_states)
if(!new_states)
CRASH("add_surgical_state called with no new states to add")
if((surgery_state & new_states) == new_states)
return
var/old_states = surgery_state
surgery_state |= new_states
update_surgical_state(old_states, new_states)
@@ -1730,11 +1769,16 @@
/// Called when surgical state changes so we can react to it
/obj/item/bodypart/proc/update_surgical_state(old_state, changed_states)
SEND_SIGNAL(src, COMSIG_BODYPART_UPDATING_SURGERY_STATE, old_state, surgery_state, changed_states)
if((surgery_state & changed_states) == changed_states)
return
if(HAS_ANY_SURGERY_STATE(changed_states, SURGERY_ORGANS_CUT|ALL_SURGERY_VESSEL_STATES))
refresh_bleed_rate()
if(isnull(owner))
return
SEND_SIGNAL(owner, COMSIG_LIVING_UPDATING_SURGERY_STATE, old_state, surgery_state, changed_states)
if(HAS_SURGERY_STATE(surgery_state, ALL_SURGERY_FISH_STATES(body_zone)))
owner.AddComponent(/datum/component/fishing_spot, /datum/fish_source/surgery) // no-op if they already have one
@@ -18,6 +18,7 @@
bodypart_flags = BODYPART_UNHUSKABLE
biological_state = (BIO_WOOD|BIO_JOINTED)
custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 2)
butcher_replacement = null
/obj/item/bodypart/arm/left/ghetto/Initialize(mapload, ...)
. = ..()
@@ -43,6 +44,7 @@
bodypart_flags = BODYPART_UNHUSKABLE
biological_state = (BIO_WOOD|BIO_JOINTED)
custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 2)
butcher_replacement = null
/obj/item/bodypart/arm/right/ghetto/Initialize(mapload, ...)
. = ..()
@@ -66,6 +68,7 @@
bodypart_flags = BODYPART_UNHUSKABLE
biological_state = (BIO_WOOD|BIO_JOINTED)
custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 2)
butcher_replacement = null
/obj/item/bodypart/leg/left/ghetto/Initialize(mapload, ...)
. = ..()
@@ -89,6 +92,7 @@
bodypart_flags = BODYPART_UNHUSKABLE
biological_state = (BIO_WOOD|BIO_JOINTED)
custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 2)
butcher_replacement = null
/obj/item/bodypart/leg/right/ghetto/Initialize(mapload, ...)
. = ..()
+10
View File
@@ -25,6 +25,8 @@
unarmed_damage_high = 3
unarmed_effectiveness = 0
bodypart_trait_source = HEAD_TRAIT
butcher_replacement = /obj/item/bodypart/head/skeleton/nonfunctional
base_meat_amount = 0
/// Do we show the information about missing organs upon being examined? Defaults to TRUE, useful for Dullahan heads.
var/show_organs_on_examine = TRUE
@@ -104,6 +106,14 @@
QDEL_NULL(worn_face_offset)
return ..()
/obj/item/bodypart/head/get_butcher_drops()
if(butcher_drops)
return butcher_drops
var/datum/species/species = GLOB.species_list[limb_id]
if (!species || !species.skinned_type)
return null
return list(species.skinned_type = 1)
/obj/item/bodypart/head/grind_results()
return null
+49 -64
View File
@@ -12,6 +12,8 @@
px_y = 0
wound_resistance = 10
bodypart_trait_source = CHEST_TRAIT
base_meat_amount = 2
butcher_replacement = /obj/item/bodypart/chest/skeleton/nonfunctional
///The bodyshape(s) allowed to attach to this chest.
var/acceptable_bodyshape = BODYSHAPE_HUMANOID
///The bodytype(s) allowed to attach to this chest.
@@ -36,6 +38,17 @@
/// Which functional (i.e. flightpotion) wing types (if any) does this bodypart support? If count is >1 a radial menu is used to choose between all icons in list
var/list/wing_types = list(/obj/item/organ/wings/functional/angel)
/obj/item/bodypart/chest/get_butcher_drops()
. = ..()
if(butcher_drops)
return
var/datum/species/species = GLOB.species_list[limb_id]
if (!species || !species.skinned_type)
return
if (!islist(.))
. = list()
.[species.skinned_type] = 1
/obj/item/bodypart/chest/grind_results()
return null
@@ -201,6 +214,25 @@
var/atom/movable/screen/inventory/hand/hand = new_owner.hud_used.hand_slots["[held_index]"]
hand?.update_appearance()
/obj/item/bodypart/arm/set_disabled(new_disabled)
. = ..()
if(isnull(.) || !owner)
return
if(!.)
if(bodypart_disabled)
owner.set_usable_hands(owner.usable_hands - 1)
if(owner.stat < UNCONSCIOUS)
to_chat(owner, span_userdanger("You lose control of your [plaintext_zone]!"))
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/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"]
hand_screen_object?.update_appearance()
/obj/item/bodypart/arm/left
name = "left arm"
desc = "Did you know that the word 'sinister' stems originally from the \
@@ -216,6 +248,7 @@
px_x = -6
px_y = 0
bodypart_trait_source = LEFT_ARM_TRAIT
butcher_replacement = /obj/item/bodypart/arm/left/skeleton/nonfunctional
/obj/item/bodypart/arm/left/apply_ownership(mob/living/carbon/new_owner)
if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_L_ARM))
@@ -248,25 +281,6 @@
UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_ARM))
RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_ARM), PROC_REF(on_owner_paralysis_gain))
/obj/item/bodypart/arm/left/set_disabled(new_disabled)
. = ..()
if(isnull(.) || !owner)
return
if(!.)
if(bodypart_disabled)
owner.set_usable_hands(owner.usable_hands - 1)
if(owner.stat < UNCONSCIOUS)
to_chat(owner, span_userdanger("You lose control of your [plaintext_zone]!"))
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/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"]
hand_screen_object?.update_appearance()
/obj/item/bodypart/arm/left/monkey
icon = 'icons/mob/human/species/monkey/bodyparts.dmi'
icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi'
@@ -316,6 +330,7 @@
px_x = 6
px_y = 0
bodypart_trait_source = RIGHT_ARM_TRAIT
butcher_replacement = /obj/item/bodypart/arm/right/skeleton/nonfunctional
/obj/item/bodypart/arm/right/apply_ownership(mob/living/carbon/new_owner)
if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_R_ARM))
@@ -348,25 +363,6 @@
UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_R_ARM))
RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_ARM), PROC_REF(on_owner_paralysis_gain))
/obj/item/bodypart/arm/right/set_disabled(new_disabled)
. = ..()
if(isnull(.) || !owner)
return
if(!.)
if(bodypart_disabled)
owner.set_usable_hands(owner.usable_hands - 1)
if(owner.stat < UNCONSCIOUS)
to_chat(owner, span_userdanger("You lose control of your [plaintext_zone]!"))
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/atom/movable/screen/inventory/hand/hand_screen_object = owner.hud_used.hand_slots["[held_index]"]
hand_screen_object?.update_appearance()
/obj/item/bodypart/arm/right/monkey
icon = 'icons/mob/human/species/monkey/bodyparts.dmi'
icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi'
@@ -449,6 +445,19 @@
QDEL_NULL(worn_foot_offset)
return ..()
/obj/item/bodypart/leg/set_disabled(new_disabled, update_limbs = TRUE)
. = ..()
if(isnull(.) || !owner || !update_limbs)
return
if(!.)
if(bodypart_disabled)
owner.set_usable_legs(owner.usable_legs - 1)
if(owner.stat < UNCONSCIOUS)
to_chat(owner, span_userdanger("You lose control of your [plaintext_zone]!"))
else if(!bodypart_disabled)
owner.set_usable_legs(owner.usable_legs + 1)
/obj/item/bodypart/leg/left
name = "left leg"
desc = "Some athletes prefer to tie their left shoelaces first for good \
@@ -461,6 +470,7 @@
px_y = 12
can_be_disabled = TRUE
bodypart_trait_source = LEFT_LEG_TRAIT
butcher_replacement = /obj/item/bodypart/leg/left/skeleton/nonfunctional
/obj/item/bodypart/leg/left/apply_ownership(mob/living/carbon/new_owner)
if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_L_LEG))
@@ -493,19 +503,6 @@
UnregisterSignal(owner, SIGNAL_REMOVETRAIT(TRAIT_PARALYSIS_L_LEG))
RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_L_LEG), PROC_REF(on_owner_paralysis_gain))
/obj/item/bodypart/leg/left/set_disabled(new_disabled)
. = ..()
if(isnull(.) || !owner)
return
if(!.)
if(bodypart_disabled)
owner.set_usable_legs(owner.usable_legs - 1)
if(owner.stat < UNCONSCIOUS)
to_chat(owner, span_userdanger("You lose control of your [plaintext_zone]!"))
else if(!bodypart_disabled)
owner.set_usable_legs(owner.usable_legs + 1)
/obj/item/bodypart/leg/left/monkey
icon = 'icons/mob/human/species/monkey/bodyparts.dmi'
icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi'
@@ -552,6 +549,7 @@
px_x = 2
px_y = 12
bodypart_trait_source = RIGHT_LEG_TRAIT
butcher_replacement = /obj/item/bodypart/leg/right/skeleton/nonfunctional
/obj/item/bodypart/leg/right/apply_ownership(mob/living/carbon/new_owner)
if(HAS_TRAIT(new_owner, TRAIT_PARALYSIS_R_LEG))
@@ -585,19 +583,6 @@
RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_PARALYSIS_R_LEG), PROC_REF(on_owner_paralysis_gain))
/obj/item/bodypart/leg/right/set_disabled(new_disabled)
. = ..()
if(isnull(.) || !owner)
return
if(!.)
if(bodypart_disabled)
owner.set_usable_legs(owner.usable_legs - 1)
if(owner.stat < UNCONSCIOUS)
to_chat(owner, span_userdanger("You lose control of your [plaintext_zone]!"))
else if(!bodypart_disabled)
owner.set_usable_legs(owner.usable_legs + 1)
/obj/item/bodypart/leg/right/monkey
icon = 'icons/mob/human/species/monkey/bodyparts.dmi'
icon_static = 'icons/mob/human/species/monkey/bodyparts.dmi'
@@ -44,6 +44,7 @@
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT)
disabling_threshold_percentage = 1
bodypart_flags = BODYPART_UNHUSKABLE
butcher_replacement = null
/obj/item/bodypart/arm/right/robot
name = "cyborg right arm"
@@ -79,6 +80,7 @@
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT)
bodypart_flags = BODYPART_UNHUSKABLE
butcher_replacement = null
/obj/item/bodypart/leg/left/robot
name = "cyborg left leg"
@@ -114,6 +116,7 @@
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT)
bodypart_flags = BODYPART_UNHUSKABLE
butcher_replacement = null
/obj/item/bodypart/leg/left/robot/emp_effect(severity, protection)
. = ..()
@@ -163,6 +166,7 @@
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT)
bodypart_flags = BODYPART_UNHUSKABLE
butcher_replacement = null
/obj/item/bodypart/leg/right/robot/emp_effect(severity, protection)
. = ..()
@@ -209,6 +213,7 @@
damage_examines = list(BRUTE = ROBOTIC_BRUTE_EXAMINE_TEXT, BURN = ROBOTIC_BURN_EXAMINE_TEXT)
bodypart_flags = BODYPART_UNHUSKABLE
butcher_replacement = null
robotic_emp_paralyze_damage_percent_threshold = 0.6
@@ -387,6 +392,7 @@
head_flags = HEAD_EYESPRITES
bodypart_flags = BODYPART_UNHUSKABLE
butcher_replacement = null
var/obj/item/assembly/flash/handheld/flash1 = null
var/obj/item/assembly/flash/handheld/flash2 = null
@@ -11,6 +11,7 @@
head_flags = HEAD_HAIR | HEAD_FACIAL_HAIR | HEAD_DEBRAIN
teeth_count = 0
butcher_replacement = null
/obj/item/bodypart/chest/ghost
icon = 'icons/mob/human/species/ghost.dmi'
@@ -24,6 +25,7 @@
should_draw_greyscale = FALSE
dmg_overlay_type = null
wing_types = null
butcher_replacement = null
/obj/item/bodypart/arm/left/ghost
icon = 'icons/mob/human/species/ghost.dmi'
@@ -34,6 +36,7 @@
limb_id = SPECIES_GHOST
should_draw_greyscale = FALSE
dmg_overlay_type = null
butcher_replacement = null
/obj/item/bodypart/arm/right/ghost
icon = 'icons/mob/human/species/ghost.dmi'
@@ -44,3 +47,4 @@
limb_id = SPECIES_GHOST
should_draw_greyscale = FALSE
dmg_overlay_type = null
butcher_replacement = null
@@ -91,6 +91,7 @@
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
head_flags = HEAD_EYECOLOR | HEAD_EYESPRITES | HEAD_HAIR | HEAD_FACIAL_HAIR
butcher_replacement = null
/obj/item/bodypart/chest/jelly
biological_state = (BIO_FLESH|BIO_BLOODED)
@@ -99,6 +100,7 @@
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
wing_types = list(/obj/item/organ/wings/functional/slime)
butcher_replacement = null
/obj/item/bodypart/chest/jelly/get_butt_sprite()
return icon('icons/mob/butts.dmi', BUTT_SPRITE_SLIME)
@@ -108,24 +110,28 @@
limb_id = SPECIES_JELLYPERSON
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
butcher_replacement = null
/obj/item/bodypart/arm/right/jelly
biological_state = (BIO_FLESH|BIO_BLOODED)
limb_id = SPECIES_JELLYPERSON
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
butcher_replacement = null
/obj/item/bodypart/leg/left/jelly
biological_state = (BIO_FLESH|BIO_BLOODED)
limb_id = SPECIES_JELLYPERSON
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
butcher_replacement = null
/obj/item/bodypart/leg/right/jelly
biological_state = (BIO_FLESH|BIO_BLOODED)
limb_id = SPECIES_JELLYPERSON
dmg_overlay_type = null
burn_modifier = 0.5 // = 1/2x generic burn damage
butcher_replacement = null
///SLIME
/obj/item/bodypart/head/jelly/slime
@@ -377,6 +383,8 @@
dmg_overlay_type = null
head_flags = NONE
bodypart_flags = BODYPART_UNHUSKABLE
scarrable = FALSE
butcher_replacement = null
/obj/item/bodypart/chest/skeleton
biological_state = BIO_BONE
@@ -386,6 +394,8 @@
dmg_overlay_type = null
bodypart_flags = BODYPART_UNHUSKABLE
wing_types = list(/obj/item/organ/wings/functional/skeleton)
scarrable = FALSE
butcher_replacement = null
/obj/item/bodypart/arm/left/skeleton
biological_state = (BIO_BONE|BIO_JOINTED)
@@ -393,6 +403,8 @@
should_draw_greyscale = FALSE
dmg_overlay_type = null
bodypart_flags = BODYPART_UNHUSKABLE
scarrable = FALSE
butcher_replacement = null
/obj/item/bodypart/arm/right/skeleton
biological_state = (BIO_BONE|BIO_JOINTED)
@@ -400,6 +412,8 @@
should_draw_greyscale = FALSE
dmg_overlay_type = null
bodypart_flags = BODYPART_UNHUSKABLE
scarrable = FALSE
butcher_replacement = null
/obj/item/bodypart/leg/left/skeleton
biological_state = (BIO_BONE|BIO_JOINTED)
@@ -407,6 +421,8 @@
should_draw_greyscale = FALSE
dmg_overlay_type = null
bodypart_flags = BODYPART_UNHUSKABLE
scarrable = FALSE
butcher_replacement = null
/obj/item/bodypart/leg/right/skeleton
biological_state = (BIO_BONE|BIO_JOINTED)
@@ -414,6 +430,44 @@
should_draw_greyscale = FALSE
dmg_overlay_type = null
bodypart_flags = BODYPART_UNHUSKABLE
scarrable = FALSE
butcher_replacement = null
/// Degloved bone "limbs"
/obj/item/bodypart/head/skeleton/nonfunctional
limb_id = BODYPART_ID_BONE
// These are always disabled
disabling_threshold_percentage = 0
/obj/item/bodypart/chest/skeleton/nonfunctional
limb_id = BODYPART_ID_BONE
disabling_threshold_percentage = 0
/obj/item/bodypart/chest/skeleton/nonfunctional/on_adding(mob/living/carbon/new_owner)
. = ..()
// Treat people with bone chests as husks for all purposes for now
// Ideally husking should be per-bodypart but this simplifies a lot of behaviors
new_owner.become_husk(SKELETON_TRAIT)
/obj/item/bodypart/chest/skeleton/nonfunctional/on_removal(mob/living/carbon/old_owner)
. = ..()
old_owner.cure_husk(SKELETON_TRAIT)
/obj/item/bodypart/arm/left/skeleton/nonfunctional
limb_id = BODYPART_ID_BONE
disabling_threshold_percentage = 0
/obj/item/bodypart/arm/right/skeleton/nonfunctional
limb_id = BODYPART_ID_BONE
disabling_threshold_percentage = 0
/obj/item/bodypart/leg/left/skeleton/nonfunctional
limb_id = BODYPART_ID_BONE
disabling_threshold_percentage = 0
/obj/item/bodypart/leg/right/skeleton/nonfunctional
limb_id = BODYPART_ID_BONE
disabling_threshold_percentage = 0
///MUSHROOM
/obj/item/bodypart/head/mushroom
@@ -496,6 +550,7 @@
teeth_count = 0
brute_modifier = 0.5
burn_modifier = 0.5
butcher_replacement = null
/obj/item/bodypart/head/golem/Initialize(mapload)
worn_ears_offset = new(
@@ -538,6 +593,7 @@
wing_types = null
brute_modifier = 0.5
burn_modifier = 0.5
butcher_replacement = null
/obj/item/bodypart/chest/golem/Initialize(mapload)
worn_belt_offset = new(
@@ -563,6 +619,7 @@
unarmed_effectiveness = 20
brute_modifier = 0.5
burn_modifier = 0.5
butcher_replacement = null
/obj/item/bodypart/arm/left/golem/Initialize(mapload)
held_hand_offset = new(
@@ -599,6 +656,7 @@
unarmed_effectiveness = 20
brute_modifier = 0.5
burn_modifier = 0.5
butcher_replacement = null
/obj/item/bodypart/arm/right/golem/Initialize(mapload)
held_hand_offset = new(
@@ -634,6 +692,7 @@
unarmed_effectiveness = 25
brute_modifier = 0.5
burn_modifier = 0.5
butcher_replacement = null
/obj/item/bodypart/leg/right/golem
icon = 'icons/mob/human/species/golems.dmi'
+135 -70
View File
@@ -2,23 +2,22 @@
* Attempts to perform a surgery with whatever tool is passed
*
* * src - the surgeon
* * patient - the mob being operated on
* * operating_on - the main thing being operated on, usually a mob, but can be a detached limb
* * potential_tool - the tool being used for the operation (can be null / IMPLEMENT_HAND)
* * intentionally_fail - if TRUE, forces the operation to fail (for testing purposes)
*
* Returns an ITEM_INTERACT_* flag
*/
/mob/living/proc/perform_surgery(mob/living/patient, potential_tool = IMPLEMENT_HAND, intentionally_fail = FALSE)
if(DOING_INTERACTION(src, (HAS_TRAIT(src, TRAIT_HIPPOCRATIC_OATH) ? patient : DOAFTER_SOURCE_SURGERY)))
patient.balloon_alert(src, "already performing surgery!")
/mob/living/proc/perform_surgery(atom/movable/operating_on, potential_tool = IMPLEMENT_HAND, intentionally_fail = FALSE, operating_zone = zone_selected)
if(DOING_INTERACTION(src, (HAS_TRAIT(src, TRAIT_HIPPOCRATIC_OATH) ? operating_on : DOAFTER_SOURCE_SURGERY)))
operating_on.balloon_alert(src, "already performing surgery!")
return ITEM_INTERACT_BLOCKING
// allow cyborgs to use "hands"
if(istype(potential_tool, /obj/item/borg/cyborghug))
potential_tool = IMPLEMENT_HAND
var/operating_zone = zone_selected
var/list/operations = get_available_operations(patient, potential_tool, operating_zone)
var/list/operations = get_available_operations(operating_on, potential_tool, operating_zone)
// we failed to undertake any operations?
if(!length(operations))
@@ -26,7 +25,7 @@
return NONE
var/obj/item/realtool = potential_tool
// try self-cauterization if applicable
if(src == patient)
if(src == operating_on)
var/manual_cauterization = try_manual_cauterize(realtool)
if(manual_cauterization & ITEM_INTERACT_ANY_BLOCKER)
return manual_cauterization
@@ -34,16 +33,25 @@
if(!(realtool.item_flags & SURGICAL_TOOL))
return NONE
// if the targeted limb isn't prepped for surgery, i suppose we can allow an attack
var/obj/item/bodypart/operating = patient.get_bodypart(operating_zone)
var/obj/item/bodypart/operating = null
if (isbodypart(operating_on))
operating = operating_on
else if (isliving(operating_on))
var/mob/living/patient = operating_on
operating = patient.get_bodypart(operating_zone)
if(operating && !HAS_TRAIT(operating, TRAIT_READY_TO_OPERATE))
return NONE
// at this point we can be relatively sure they messed up so let's give a feedback message...
if(!patient.is_location_accessible(operating_zone, IGNORED_OPERATION_CLOTHING_SLOTS))
patient.balloon_alert(src, "operation site is obstructed!")
else if(!IS_LYING_OR_CANNOT_LIE(patient))
patient.balloon_alert(src, "not lying down!")
if (isliving(operating_on))
var/mob/living/patient = operating_on
if(!patient.is_location_accessible(operating_zone, IGNORED_OPERATION_CLOTHING_SLOTS))
patient.balloon_alert(src, "operation site is obstructed!")
else if(!IS_LYING_OR_CANNOT_LIE(patient))
patient.balloon_alert(src, "not lying down!")
else
patient.balloon_alert(src, "nothing to do with [realtool.name]!")
else
patient.balloon_alert(src, "nothing to do with [realtool.name]!")
operating.balloon_alert(src, "nothing to do with [realtool.name]!")
// ...then, block attacking. prevents the surgeon from viciously stabbing the patient on a mistake
return ITEM_INTERACT_BLOCKING
@@ -55,29 +63,29 @@
var/picked = show_radial_menu(
user = src,
anchor = patient,
anchor = operating_on,
choices = radial_operations,
require_near = TRUE,
autopick_single_option = TRUE,
radius = 56,
custom_check = CALLBACK(src, PROC_REF(surgery_check), potential_tool, patient),
custom_check = CALLBACK(src, PROC_REF(surgery_check), potential_tool, operating_on),
)
if(isnull(picked))
return ITEM_INTERACT_BLOCKING
var/datum/surgery_operation/picked_op = operations[picked][1]
var/atom/movable/operating_on = operations[picked][2]
var/atom/movable/operating = operations[picked][2]
var/list/op_info = operations[picked][3]
op_info[OPERATION_TARGET_ZONE] = operating_zone
op_info[OPERATION_FORCE_FAIL] = intentionally_fail
return picked_op.try_perform(operating_on, src, potential_tool, op_info)
return picked_op.try_perform(operating, src, potential_tool, op_info)
/**
* Returns a list of all surgery operations the mob can currently perform on the patient with the potential tool
* Returns a list of all surgery operations the mob can currently perform on the target with the potential tool
*
* * src - the surgeon
* * patient - the mob being operated on
* * operating_on - the mob being operated on, or possibly a detached limb
* * potential_tool - the tool being used for the operation (can be null / IMPLEMENT_HAND)
* * operating_zone - the body zone being operated on
*
@@ -86,17 +94,17 @@
* * [1] - the atom being operated on
* * [2] - a list of option-specific info
*/
/mob/living/proc/get_available_operations(mob/living/patient, potential_tool = IMPLEMENT_HAND, operating_zone = zone_selected)
/mob/living/proc/get_available_operations(atom/movable/operating_on, potential_tool = IMPLEMENT_HAND, operating_zone = zone_selected)
// List of typepaths of operations we *can* do
var/list/possible_operations = GLOB.operations.unlocked.Copy()
// Signals can add operation types to the list to unlock special ones
SEND_SIGNAL(src, COMSIG_LIVING_OPERATING_ON, patient, possible_operations)
SEND_SIGNAL(patient, COMSIG_LIVING_BEING_OPERATED_ON, patient, possible_operations)
SEND_SIGNAL(src, COMSIG_LIVING_OPERATING_ON, operating_on, possible_operations)
SEND_SIGNAL(operating_on, COMSIG_ATOM_BEING_OPERATED_ON, src, possible_operations)
var/list/operations = list()
for(var/datum/surgery_operation/operation as anything in GLOB.operations.get_instances_from(possible_operations))
var/atom/movable/operate_on = operation.get_operation_target(patient, operating_zone)
if(!operation.check_availability(patient, operate_on, src, potential_tool, operating_zone))
var/atom/movable/operate_on = operation.get_operation_target(operating_on, operating_zone)
if(!operation.check_availability(isliving(operating_on) ? operating_on : null, operate_on, src, potential_tool, operating_zone))
continue
var/potential_options = operation.get_radial_options(operate_on, potential_tool, operating_zone)
if(!islist(potential_options))
@@ -111,15 +119,16 @@
return operations
/// Callback for checking if the surgery radial can be kept open
/mob/living/proc/surgery_check(obj/item/tool, mob/living/patient)
/mob/living/proc/surgery_check(obj/item/tool, atom/movable/operating_on)
var/obj/item/holding = get_active_held_item()
if(tool == IMPLEMENT_HAND)
return isnull(holding) || istype(holding, /obj/item/borg/cyborghug) // still holding nothing (or "hands")
if(QDELETED(holding))
return FALSE // i dunno, a stack item? not our problem
return tool == holding.get_proxy_attacker_for(patient, src) // tool (or its proxy) is still being held
return tool == holding.get_proxy_attacker_for(operating_on, src) // tool (or its proxy) is still being held
/// src attempts to cauterize themselves to reset their surgery state. Basically a manual form of the real "close skin" operation
/mob/living/proc/try_manual_cauterize(obj/item/tool)
@@ -463,13 +472,7 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
SHOULD_NOT_SLEEP(TRUE)
SHOULD_BE_PURE(TRUE)
if(isnull(patient) || isnull(operating_on))
return FALSE
if(!(operation_flags & OPERATION_STANDING_ALLOWED) && !IS_LYING_OR_CANNOT_LIE(patient))
return FALSE
if(!(operation_flags & OPERATION_SELF_OPERABLE) && patient == surgeon && !HAS_TRAIT(surgeon, TRAIT_SELF_SURGERY))
if(isnull(operating_on))
return FALSE
if(get_tool_quality(tool) <= 0)
@@ -478,6 +481,17 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
if(!is_available(operating_on, operated_zone))
return FALSE
if(isnull(patient))
if(operation_flags & OPERATION_NO_PATIENT_REQUIRED)
return snowflake_check_availability(operating_on, surgeon, tool, operated_zone)
return FALSE
if(!(operation_flags & OPERATION_STANDING_ALLOWED) && !IS_LYING_OR_CANNOT_LIE(patient))
return FALSE
if(!(operation_flags & OPERATION_SELF_OPERABLE) && patient == surgeon && !HAS_TRAIT(surgeon, TRAIT_SELF_SURGERY))
return FALSE
return snowflake_check_availability(operating_on, surgeon, tool, operated_zone)
/**
@@ -537,10 +551,15 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
if(any_surgery_states_blocked && has_any_surgery_state(operating_on, any_surgery_states_blocked))
return FALSE
var/mob/living/patient = get_patient(operating_on)
if(isnull(patient))
if (!(operation_flags & OPERATION_NO_PATIENT_REQUIRED))
return FALSE
return state_check(operating_on)
if(!state_check(operating_on))
return FALSE
var/mob/living/patient = get_patient(operating_on)
if(!(operation_flags & OPERATION_IGNORE_CLOTHES) && !patient.is_location_accessible(operated_zone, IGNORED_OPERATION_CLOTHING_SLOTS))
return FALSE
@@ -723,11 +742,12 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
// Ignore alllll the penalties (but also all the bonuses)
if(!HAS_TRAIT(surgeon, TRAIT_IGNORE_SURGERY_MODIFIERS))
var/mob/living/patient = get_patient(operating_on)
total_mod *= get_location_modifier(get_turf(patient))
total_mod *= get_morbid_modifier(surgeon, tool)
total_mod *= get_mob_surgery_speed_mod(patient)
if(!isnull(patient)) // Some surgeries can lack patients
total_mod *= get_location_modifier(get_turf(patient))
total_mod *= get_mob_surgery_speed_mod(patient)
// Using TRAIT_SELF_SURGERY on a surgery which doesn't normally allow self surgery imparts a penalty
if(patient == surgeon && HAS_TRAIT(surgeon, TRAIT_SELF_SURGERY) && !(operation_flags & OPERATION_SELF_OPERABLE))
if(operating_on == surgeon && HAS_TRAIT(surgeon, TRAIT_SELF_SURGERY) && !(operation_flags & OPERATION_SELF_OPERABLE))
total_mod *= 1.5
return round(total_mod, 0.01)
@@ -766,6 +786,7 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
/obj/structure/table/optable/abductor = 0.85,
/obj/machinery/stasis = 1.15,
/obj/structure/bed = 1.5,
/obj/structure/kitchenspike = 1.5,
))
var/mod = 2.0
for(var/obj/thingy in operation_turf)
@@ -777,19 +798,19 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
* Determines what gets passed into the try_perform() proc
* If null is returned, the operation cannot be performed
*
* * patient - The mob being operated on
* * operating_on - The mob or detached bodypart being operated on
* * body_zone - The body zone being operated on
*
* Returns the atom/movable being operated on
*/
/datum/surgery_operation/proc/get_operation_target(mob/living/patient, body_zone)
return patient
/datum/surgery_operation/proc/get_operation_target(atom/movable/operating_on, body_zone)
return operating_on
/**
* Called by operating computers to hint that this surgery could come next given the target's current state
*/
/datum/surgery_operation/proc/show_as_next_step(mob/living/potential_patient, operated_zone)
var/atom/movable/operate_on = get_operation_target(potential_patient, operated_zone)
/datum/surgery_operation/proc/show_as_next_step(atom/movable/potential_target, operated_zone)
var/atom/movable/operate_on = get_operation_target(potential_target, operated_zone)
return !isnull(operate_on) && is_available(operate_on, operated_zone)
@@ -809,14 +830,17 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
if(!check_availability(patient, operating_on, surgeon, tool, operation_args[OPERATION_TARGET_ZONE]))
return ITEM_INTERACT_BLOCKING
if(!start_operation(operating_on, surgeon, tool, operation_args))
return ITEM_INTERACT_BLOCKING
var/was_sleeping = (patient.stat != DEAD && HAS_TRAIT(patient, TRAIT_KNOCKEDOUT))
var/was_sleeping = FALSE
var/result = NONE
update_surgery_mood(patient, SURGERY_STATE_STARTED)
SEND_SIGNAL(patient, COMSIG_LIVING_SURGERY_STARTED, src, operating_on, tool)
if(patient)
was_sleeping = (patient.stat != DEAD && HAS_TRAIT(patient, TRAIT_KNOCKEDOUT))
update_surgery_mood(patient, SURGERY_STATE_STARTED)
SEND_SIGNAL(patient, COMSIG_ATOM_SURGERY_STARTED, src, operating_on, tool)
do
operation_args[OPERATION_SPEED] = get_time_modifiers(operating_on, surgeon, tool)
@@ -825,20 +849,23 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
user = surgeon,
// Actual delay is capped - think of the excess time as being added to failure chance instead
delay = time * min(operation_args[OPERATION_SPEED], SURGERY_MODIFIER_FAILURE_THRESHOLD),
target = patient,
target = patient || operating_on,
extra_checks = CALLBACK(src, PROC_REF(operate_check), patient, operating_on, surgeon, tool, operation_args),
// You can only operate on one mob at a time without a hippocratic oath
interaction_key = HAS_TRAIT(surgeon, TRAIT_HIPPOCRATIC_OATH) ? patient : DOAFTER_SOURCE_SURGERY,
interaction_key = HAS_TRAIT(surgeon, TRAIT_HIPPOCRATIC_OATH) ? (patient || operating_on) : DOAFTER_SOURCE_SURGERY,
))
result |= ITEM_INTERACT_BLOCKING
update_surgery_mood(patient, SURGERY_STATE_FAILURE)
if (patient)
update_surgery_mood(patient, SURGERY_STATE_FAILURE)
break
if(ishuman(surgeon))
var/mob/living/carbon/human/surgeon_human = surgeon
surgeon_human.add_blood_DNA_to_items(patient.get_blood_dna_list(), ITEM_SLOT_GLOVES)
else
surgeon.add_mob_blood(patient)
var/list/patient_dna = get_patient_blood_dna(patient, operating_on)
if (patient_dna)
if (ishuman(surgeon))
var/mob/living/carbon/human/surgeon_human = surgeon
surgeon_human.add_blood_DNA_to_items(patient_dna, ITEM_SLOT_GLOVES)
else
surgeon.add_blood_DNA(patient_dna)
// This will annoy doctors immensely
// if(isitem(tool))
@@ -860,11 +887,13 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
if(operation_args[OPERATION_FORCE_FAIL] || prob(clamp(GET_FAILURE_CHANCE(time, operation_args[OPERATION_SPEED]), 0, 99)))
failure(operating_on, surgeon, tool, operation_args)
result |= ITEM_INTERACT_FAILURE
update_surgery_mood(patient, SURGERY_STATE_FAILURE)
if (patient)
update_surgery_mood(patient, SURGERY_STATE_FAILURE)
else
success(operating_on, surgeon, tool, operation_args)
result |= ITEM_INTERACT_SUCCESS
update_surgery_mood(patient, SURGERY_STATE_SUCCESS)
if (patient)
update_surgery_mood(patient, SURGERY_STATE_SUCCESS)
if(isstack(tool))
var/obj/item/stack/tool_stack = tool
@@ -872,13 +901,27 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
while ((operation_flags & OPERATION_LOOPING) && can_loop(patient, operating_on, surgeon, tool, operation_args))
SEND_SIGNAL(patient, COMSIG_LIVING_SURGERY_FINISHED, src, operating_on, tool)
if (!patient)
return result
SEND_SIGNAL(patient, COMSIG_ATOM_SURGERY_FINISHED, src, operating_on, tool)
if(patient.stat == DEAD && was_sleeping)
surgeon.client?.give_award(/datum/award/achievement/jobs/sandman, surgeon)
return result
/datum/surgery_operation/proc/get_patient_blood_dna(mob/living/patient, atom/movable/operating_on)
if (patient)
return patient.get_blood_dna_list()
if (isbodypart(operating_on))
var/obj/item/bodypart/limb = operating_on
return limb.blood_dna_info?.Copy()
if (isorgan(operating_on))
var/obj/item/organ/guts = operating_on
return guts.blood_dna_info?.Copy()
/// Called after an operation to check if it can be repeated/looped
/datum/surgery_operation/proc/can_loop(mob/living/patient, atom/movable/operating_on, mob/living/surgeon, tool, list/operation_args)
PROTECTED_PROC(TRUE)
@@ -893,7 +936,7 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
if(tool_stack.amount <= 0)
return FALSE
if(!surgeon.surgery_check(tool, patient))
if(!surgeon.surgery_check(tool, (operation_flags & OPERATION_NO_PATIENT_REQUIRED) ? patient : (patient || operating_on)))
return FALSE
if(!check_availability(patient, operating_on, surgeon, tool, operation_args[OPERATION_TARGET_ZONE]))
@@ -929,9 +972,15 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
vision_distance = 1,
ignored_mobs = target_detailed ? null : target
)
if(target_detailed)
return
if (!target)
if (operation_flags & OPERATION_NO_PATIENT_REQUIRED)
return
CRASH("[type] operation attempted to call display_results without a patient, despite requiring one!")
var/you_feel = pick("a brief pain", "your body tense up", "an unnerving sensation")
target.show_message(
msg = vague_message || detailed_message || span_notice("You feel [you_feel] as you are operated on."),
@@ -947,6 +996,11 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
if(!pain_message)
return
if (!target)
if (operation_flags & OPERATION_NO_PATIENT_REQUIRED)
return
CRASH("[type] operation attempted to call display_pain without a patient, despite requiring one!")
// Determine how drunk our patient is
var/drunken_patient = target.get_drunk_amount()
// Create a probability to ignore the pain based on drunkenness level
@@ -1043,7 +1097,7 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
if(!pre_preop(operating_on, surgeon, tool, operation_args))
return FALSE
// if pre_preop slept, sanity check that everything is still valid
if(preop_time != world.time && (patient != get_patient(operating_on) || !surgeon.Adjacent(patient) || !surgeon.is_holding(tool) || !operate_check(patient, operating_on, surgeon, tool, operation_args)))
if(preop_time != world.time && (patient != get_patient(operating_on) || !surgeon.Adjacent(patient || operating_on) || !surgeon.is_holding(tool) || !operate_check(patient, operating_on, surgeon, tool, operation_args)))
return FALSE
play_operation_sound(operating_on, surgeon, tool, preop_sound)
@@ -1056,13 +1110,13 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
/datum/surgery_operation/proc/on_preop(atom/movable/operating_on, mob/living/surgeon, tool, list/operation_args)
PROTECTED_PROC(TRUE)
var/mob/living/patient = get_patient(operating_on)
var/atom/movable/display_target = patient || operating_on
display_results(
surgeon,
patient,
span_notice("You begin to operate on [patient]..."),
span_notice("[surgeon] begins to operate on [patient]."),
span_notice("[surgeon] begins to operate on [patient]."),
span_notice("You begin to operate on [display_target]..."),
span_notice("[surgeon] begins to operate on [display_target]."),
span_notice("[surgeon] begins to operate on [display_target]."),
)
/**
@@ -1078,7 +1132,7 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
SSblackbox.record_feedback("tally", "surgeries_completed", 1, type)
surgeon.add_mob_memory(/datum/memory/surgery, deuteragonist = surgeon, surgery_type = name)
SEND_SIGNAL(surgeon, COMSIG_LIVING_SURGERY_SUCCESS, src, operating_on, tool)
SEND_SIGNAL(surgeon, COMSIG_ATOM_SURGERY_SUCCESS, src, operating_on, tool)
play_operation_sound(operating_on, surgeon, tool, success_sound)
on_success(operating_on, surgeon, tool, operation_args)
@@ -1109,7 +1163,7 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
if(operation_flags & OPERATION_NOTABLE)
SSblackbox.record_feedback("tally", "surgeries_failed", 1, type)
SEND_SIGNAL(surgeon, COMSIG_LIVING_SURGERY_FAILED, src, operating_on, tool)
SEND_SIGNAL(surgeon, COMSIG_ATOM_SURGERY_FAILED, src, operating_on, tool)
play_operation_sound(operating_on, surgeon, tool, failure_sound)
on_failure(operating_on, surgeon, tool, operation_args)
@@ -1239,8 +1293,13 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
else if(required_bodytype & BODYTYPE_ORGANIC)
. += "the limb must not be cybernetic"
/datum/surgery_operation/limb/get_operation_target(mob/living/patient, body_zone)
return patient.get_bodypart(deprecise_zone(body_zone))
/datum/surgery_operation/limb/get_operation_target(atom/movable/operating_on, body_zone)
if (isliving(operating_on))
var/mob/living/patient = operating_on
return patient.get_bodypart(deprecise_zone(body_zone))
if (!isbodypart(operating_on))
return null
return operating_on
/datum/surgery_operation/limb/is_available(obj/item/bodypart/limb, operated_zone)
SHOULD_NOT_OVERRIDE(TRUE)
@@ -1248,10 +1307,9 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
// targeting groin will redirect you to the chest
if(limb.body_zone != deprecise_zone(operated_zone))
return FALSE
if(required_bodytype && !(limb.bodytype & required_bodytype))
return FALSE
if(!HAS_TRAIT(limb, TRAIT_READY_TO_OPERATE))
return FALSE
return ..()
@@ -1292,8 +1350,15 @@ GLOBAL_DATUM_INIT(operations, /datum/operation_holder, new)
/datum/surgery_operation/organ/get_default_radial_image()
return get_generic_limb_radial_image(target_type::zone)
/datum/surgery_operation/organ/get_operation_target(mob/living/patient, body_zone)
return patient.get_organ_by_type(target_type)
/datum/surgery_operation/organ/get_operation_target(atom/movable/operating_on, body_zone)
if (isliving(operating_on))
var/mob/living/patient = operating_on
return patient.get_organ_by_type(target_type)
if (!isbodypart(operating_on))
return null
return locate(target_type) in operating_on
/datum/surgery_operation/organ/get_patient(obj/item/organ/organ)
return organ.owner
@@ -10,7 +10,8 @@
)
time = 3.2 SECONDS
operation_flags = OPERATION_STANDING_ALLOWED | OPERATION_PRIORITY_NEXT_STEP | OPERATION_NOTABLE | OPERATION_IGNORE_CLOTHES
all_surgery_states_required = SURGERY_SKIN_OPEN | SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/// List of items that are always allowed to be an arm replacement, even if they fail another requirement.
var/list/always_accepted_prosthetics = list(
/obj/item/chainsaw, // the OG, too large otherwise
@@ -49,7 +50,10 @@
return option
/datum/surgery_operation/prosthetic_replacement/get_operation_target(mob/living/patient, body_zone)
/datum/surgery_operation/prosthetic_replacement/get_operation_target(atom/movable/operating_on, body_zone)
if (!isliving(operating_on))
return null
var/mob/living/patient = operating_on
// We always operate on the chest even if we're targeting left leg or w/e
return patient.get_bodypart(BODY_ZONE_CHEST)
@@ -20,7 +20,8 @@
/obj/item = 'sound/items/handling/surgery/scalpel1.ogg',
)
success_sound = 'sound/items/handling/surgery/organ2.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/limb/amputate/get_recommended_tool()
return TOOL_SAW
@@ -247,9 +247,25 @@
name = "cortex folding"
rnd_name = "Encephalofractoplasty (Cortex Folding)" // it's a stretch - "brain fractal reshaping"
desc = "A biological upgrade which folds a patient's cerebral cortex into a fractal pattern, increasing neural density and flexibility."
status_effect_gained = /datum/status_effect/bioware/cortex/folded
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_NOTABLE | OPERATION_MORBID | OPERATION_LOCKED | OPERATION_NO_PATIENT_REQUIRED
status_effect_gained = /datum/status_effect/bioware/cortex // Not actually applied, simply for compatibility checks
required_zone = BODY_ZONE_HEAD
/datum/surgery_operation/limb/bioware/cortex_folding/state_check(obj/item/bodypart/limb)
. = ..()
if (!.)
return
var/obj/item/organ/brain/brain = locate() in limb
if(isnull(brain))
return FALSE
return !HAS_TRAIT_FROM(brain, TRAIT_SPECIAL_TRAUMA_BOOST, BIOWARE_TRAIT)
/datum/surgery_operation/limb/bioware/cortex_folding/on_success(obj/item/bodypart/limb, mob/living/surgeon, tool, list/operation_args)
. = ..()
var/obj/item/organ/brain/brain = locate() in limb
if(!isnull(brain))
ADD_TRAIT(brain, TRAIT_SPECIAL_TRAUMA_BOOST, BIOWARE_TRAIT)
/datum/surgery_operation/limb/bioware/cortex_folding/on_preop(obj/item/bodypart/limb, mob/living/surgeon, tool)
display_results(
surgeon,
@@ -272,7 +288,8 @@
display_pain(limb.owner, "Your brain feels stronger... and more flexible!")
/datum/surgery_operation/limb/bioware/cortex_folding/on_failure(obj/item/bodypart/limb, mob/living/surgeon, tool)
if(!limb.owner.get_organ_slot(ORGAN_SLOT_BRAIN))
var/obj/item/organ/brain/brain = locate() in limb
if(isnull(brain))
return ..()
display_results(
surgeon,
@@ -282,8 +299,8 @@
span_notice("[surgeon] completes the surgery on [limb.owner]'s brain."),
)
display_pain(limb.owner, "Your head throbs with excruciating pain!")
limb.owner.adjust_organ_loss(ORGAN_SLOT_BRAIN, 60)
limb.owner.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_LOBOTOMY)
brain.apply_organ_damage(60)
brain.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_LOBOTOMY)
/datum/surgery_operation/limb/bioware/cortex_folding/mechanic
rnd_name = "Wetware OS Labyrinthian Programming (Cortex Folding)"
@@ -1,7 +1,7 @@
/datum/surgery_operation/limb/repair_hairline
name = "repair hairline fracture"
desc = "Mend a hairline fracture in a patient's bone."
operation_flags = OPERATION_PRIORITY_NEXT_STEP
operation_flags = OPERATION_PRIORITY_NEXT_STEP | OPERATION_NO_PATIENT_REQUIRED
implements = list(
TOOL_BONESET = 1,
/obj/item/stack/medical/bone_gel = 1,
@@ -27,9 +27,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to repair the fracture in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to repair the fracture in [limb.owner]'s [limb.plaintext_zone] with [tool]."),
span_notice("[surgeon] begins to repair the fracture in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to repair the fracture in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to repair the fracture in [FORMAT_LIMB_OWNER(limb)] with [tool]."),
span_notice("[surgeon] begins to repair the fracture in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "Your [limb.plaintext_zone] aches with pain!")
@@ -40,15 +40,15 @@
display_results(
surgeon,
limb.owner,
span_notice("You successfully repair the fracture in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] successfully repairs the fracture in [limb.owner]'s [limb.plaintext_zone] with [tool]!"),
span_notice("[surgeon] successfully repairs the fracture in [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You successfully repair the fracture in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] successfully repairs the fracture in [FORMAT_LIMB_OWNER(limb)]!"),
span_notice("[surgeon] successfully repairs the fracture in [FORMAT_LIMB_OWNER(limb)]!"),
)
/datum/surgery_operation/limb/reset_compound
name = "reset compound fracture"
desc = "Reset a compound fracture in a patient's bone, preparing it for proper healing."
operation_flags = OPERATION_PRIORITY_NEXT_STEP
operation_flags = OPERATION_PRIORITY_NEXT_STEP | OPERATION_NO_PATIENT_REQUIRED
implements = list(
TOOL_BONESET = 1,
/obj/item/stack/sticky_tape/surgical = 1.66,
@@ -56,7 +56,8 @@
/obj/item/stack/sticky_tape = 5,
)
time = 6 SECONDS
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/limb/reset_compound/get_default_radial_image()
return image(/obj/item/bonesetter)
@@ -74,9 +75,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to reset the bone in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to reset the bone in [limb.owner]'s [limb.plaintext_zone] with [tool]."),
span_notice("[surgeon] begins to reset the bone in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to reset the bone in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to reset the bone in [FORMAT_LIMB_OWNER(limb)] with [tool]."),
span_notice("[surgeon] begins to reset the bone in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "The aching pain in your [limb.plaintext_zone] is overwhelming!")
@@ -87,15 +88,15 @@
display_results(
surgeon,
limb.owner,
span_notice("You successfully reset the bone in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] successfully resets the bone in [limb.owner]'s [limb.plaintext_zone] with [tool]!"),
span_notice("[surgeon] successfully resets the bone in [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You successfully reset the bone in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] successfully resets the bone in [FORMAT_LIMB_OWNER(limb)] with [tool]!"),
span_notice("[surgeon] successfully resets the bone in [FORMAT_LIMB_OWNER(limb)]!"),
)
/datum/surgery_operation/limb/repair_compound
name = "repair compound fracture"
desc = "Mend a compound fracture in a patient's bone."
operation_flags = OPERATION_PRIORITY_NEXT_STEP
operation_flags = OPERATION_PRIORITY_NEXT_STEP | OPERATION_NO_PATIENT_REQUIRED
implements = list(
/obj/item/stack/medical/bone_gel = 1,
/obj/item/stack/sticky_tape/surgical = 1,
@@ -121,9 +122,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to repair the fracture in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to repair the fracture in [limb.owner]'s [limb.plaintext_zone] with [tool]."),
span_notice("[surgeon] begins to repair the fracture in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to repair the fracture in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to repair the fracture in [FORMAT_LIMB_OWNER(limb)] with [tool]."),
span_notice("[surgeon] begins to repair the fracture in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "The aching pain in your [limb.plaintext_zone] is overwhelming!")
@@ -133,15 +134,15 @@
display_results(
surgeon,
limb.owner,
span_notice("You successfully repair the fracture in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] successfully repairs the fracture in [limb.owner]'s [limb.plaintext_zone] with [tool]!"),
span_notice("[surgeon] successfully repairs the fracture in [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You successfully repair the fracture in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] successfully repairs the fracture in [FORMAT_LIMB_OWNER(limb)] with [tool]!"),
span_notice("[surgeon] successfully repairs the fracture in [FORMAT_LIMB_OWNER(limb)]!"),
)
/datum/surgery_operation/limb/prepare_cranium_repair
name = "discard skull debris"
desc = "Clear away bone fragments and debris from a patient's cranial fissure in preparation for repair."
operation_flags = OPERATION_PRIORITY_NEXT_STEP
operation_flags = OPERATION_PRIORITY_NEXT_STEP | OPERATION_NO_PATIENT_REQUIRED
implements = list(
TOOL_HEMOSTAT = 1,
TOOL_WIRECUTTER = 2.5,
@@ -166,9 +167,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to discard the smaller skull debris in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to discard the smaller skull debris in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to poke around in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("You begin to discard the smaller skull debris in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to discard the smaller skull debris in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to poke around in [FORMAT_LIMB_OWNER(limb)]..."),
)
display_pain(limb.owner, "Your brain feels like it's getting stabbed by little shards of glass!")
@@ -180,7 +181,7 @@
/datum/surgery_operation/limb/repair_cranium
name = "repair cranium"
desc = "Mend a cranial fissure in a patient's skull."
operation_flags = OPERATION_PRIORITY_NEXT_STEP
operation_flags = OPERATION_PRIORITY_NEXT_STEP | OPERATION_NO_PATIENT_REQUIRED
implements = list(
/obj/item/stack/medical/bone_gel = 1,
/obj/item/stack/sticky_tape/surgical = 1,
@@ -205,9 +206,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to repair [limb.owner]'s skull as best you can..."),
span_notice("[surgeon] begins to repair [limb.owner]'s skull with [tool]."),
span_notice("[surgeon] begins to repair [limb.owner]'s skull."),
span_notice("You begin to repair [limb.owner || limb]'s skull as best you can..."),
span_notice("[surgeon] begins to repair [limb.owner || limb]'s skull with [tool]."),
span_notice("[surgeon] begins to repair [limb.owner || limb]'s skull."),
)
display_pain(limb.owner, "You can feel pieces of your skull rubbing against your brain!")
@@ -219,7 +220,7 @@
display_results(
surgeon,
limb.owner,
span_notice("You successfully repair [limb.owner]'s skull."),
span_notice("[surgeon] successfully repairs [limb.owner]'s skull with [tool]."),
span_notice("[surgeon] successfully repairs [limb.owner]'s skull.")
span_notice("You successfully repair [limb.owner || limb]'s skull."),
span_notice("[surgeon] successfully repairs [limb.owner || limb]'s skull with [tool]."),
span_notice("[surgeon] successfully repairs [limb.owner || limb]'s skull.")
)
@@ -73,7 +73,7 @@
span_notice("[surgeon] completes the surgery on [organ.owner]'s brain."),
)
display_pain(organ.owner, "Your head throbs with horrible pain!")
organ.owner.adjust_organ_loss(ORGAN_SLOT_BRAIN, 40)
organ.apply_organ_damage(40)
/datum/surgery_operation/organ/brainwash/mechanic
name = "reprogram"
@@ -24,9 +24,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to open [limb.owner]'s [limb.plaintext_zone] cavity wide..."),
span_notice("[surgeon] begins to open [limb.owner]'s [limb.plaintext_zone] cavity wide."),
span_notice("[surgeon] begins to open [limb.owner]'s [limb.plaintext_zone] cavity wide."),
span_notice("You begin to open [FORMAT_LIMB_OWNER(limb)] cavity wide..."),
span_notice("[surgeon] begins to open [FORMAT_LIMB_OWNER(limb)] cavity wide."),
span_notice("[surgeon] begins to open [FORMAT_LIMB_OWNER(limb)] cavity wide."),
)
display_pain(limb.owner, "You can feel pressure as your [limb.plaintext_zone] is being opened wide!")
@@ -91,9 +91,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to insert [tool] into [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to insert [tool] into [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to insert [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to insert [tool] into [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to insert [tool] into [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to insert [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You can feel something being inserted into your [limb.plaintext_zone], it hurts like hell!")
@@ -113,9 +113,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You stuff [tool] into [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] stuffs [tool] into [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("[surgeon] stuffs [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You stuff [tool] into [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] stuffs [tool] into [FORMAT_LIMB_OWNER(limb)]!"),
span_notice("[surgeon] stuffs [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [FORMAT_LIMB_OWNER(limb)]."),
)
@@ -163,9 +163,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to extract [limb.cavity_item] from [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to extract [limb.cavity_item] from [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to extract something from [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to extract [limb.cavity_item] from [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to extract [limb.cavity_item] from [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to extract something from [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a serious pain in your [limb.plaintext_zone]!")
@@ -174,9 +174,9 @@
display_results(
surgeon,
limb.owner,
span_warning("You find nothing to remove from [limb.owner]'s [limb.plaintext_zone]."),
span_warning("[surgeon] finds nothing to remove from [limb.owner]'s [limb.plaintext_zone]."),
span_warning("[surgeon] finds nothing to remove from [limb.owner]'s [limb.plaintext_zone]."),
span_warning("You find nothing to remove from [FORMAT_LIMB_OWNER(limb)]."),
span_warning("[surgeon] finds nothing to remove from [FORMAT_LIMB_OWNER(limb)]."),
span_warning("[surgeon] finds nothing to remove from [FORMAT_LIMB_OWNER(limb)]."),
)
return
@@ -186,9 +186,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You pull [implant] out of [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] pulls [implant] out of [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("[surgeon] pulls something out of [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You pull [implant] out of [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] pulls [implant] out of [FORMAT_LIMB_OWNER(limb)]!"),
span_notice("[surgeon] pulls something out of [FORMAT_LIMB_OWNER(limb)]!"),
)
display_pain(limb.owner, "You can feel [implant.name] being pulled out of you!")
surgeon.put_in_hands(implant)
@@ -9,7 +9,7 @@
TOOL_WIRECUTTER = 2.5,
)
time = 3 SECONDS
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_LOOPING | OPERATION_PRIORITY_NEXT_STEP
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_LOOPING | OPERATION_PRIORITY_NEXT_STEP | OPERATION_NO_PATIENT_REQUIRED
preop_sound = list(
TOOL_SCALPEL = 'sound/items/handling/surgery/scalpel1.ogg',
TOOL_HEMOSTAT = 'sound/items/handling/surgery/hemostat1.ogg',
@@ -56,9 +56,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to excise infected flesh from [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to excise infected flesh from [limb.owner]'s [limb.plaintext_zone] with [tool]."),
span_notice("[surgeon] begins to excise infected flesh from [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to excise infected flesh from [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to excise infected flesh from [FORMAT_LIMB_OWNER(limb)] with [tool]."),
span_notice("[surgeon] begins to excise infected flesh from [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "The infection in your [limb.plaintext_zone] stings like hell! It feels like you're being stabbed!")
@@ -70,17 +70,17 @@
display_results(
surgeon,
limb.owner,
span_notice("You successfully excise some of the infected flesh from [limb.owner]'s [limb.plaintext_zone][get_progress(wound)]."),
span_notice("[surgeon] successfully excises some of the infected flesh from [limb.owner]'s [limb.plaintext_zone] with [tool]!"),
span_notice("[surgeon] successfully excises some of the infected flesh from [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You successfully excise some of the infected flesh from [FORMAT_LIMB_OWNER(limb)][get_progress(wound)]."),
span_notice("[surgeon] successfully excises some of the infected flesh from [FORMAT_LIMB_OWNER(limb)] with [tool]!"),
span_notice("[surgeon] successfully excises some of the infected flesh from [FORMAT_LIMB_OWNER(limb)]!"),
)
/datum/surgery_operation/limb/debride/on_failure(obj/item/bodypart/limb, mob/living/surgeon, obj/item/tool, list/operation_args)
display_results(
surgeon,
limb.owner,
span_notice("You carve away some of the healthy flesh from [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] carves away some of the healthy flesh from [limb.owner]'s [limb.plaintext_zone] with [tool]!"),
span_notice("[surgeon] carves away some of the healthy flesh from [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You carve away some of the healthy flesh from [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] carves away some of the healthy flesh from [FORMAT_LIMB_OWNER(limb)] with [tool]!"),
span_notice("[surgeon] carves away some of the healthy flesh from [FORMAT_LIMB_OWNER(limb)]!"),
)
limb.receive_damage(rand(4, 8), wound_bonus = CANT_WOUND, sharpness = tool.get_sharpness(), damage_source = tool)
@@ -1,11 +1,13 @@
/datum/surgery_operation/limb/add_dental_implant
name = "add dental implant"
desc = "Implant a pill into a patient's teeth."
operation_flags = OPERATION_NO_PATIENT_REQUIRED
implements = list(
/obj/item/reagent_containers/applicator/pill = 1,
)
time = 1.6 SECONDS
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED|SURGERY_BONE_DRILLED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_DRILLED
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/limb/add_dental_implant/all_required_strings()
. = list()
@@ -36,9 +38,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to wedge [tool] in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to wedge \the [tool] in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to wedge something in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to wedge [tool] in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to wedge \the [tool] in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to wedge something in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "Something's being jammed into your [limb.plaintext_zone]!")
@@ -54,20 +56,22 @@
display_results(
surgeon,
limb.owner,
span_notice("You wedge [tool] into [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] wedges [tool] into [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("[surgeon] wedges something into [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You wedge [tool] into [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] wedges [tool] into [FORMAT_LIMB_OWNER(limb)]!"),
span_notice("[surgeon] wedges something into [FORMAT_LIMB_OWNER(limb)]!"),
)
/datum/surgery_operation/limb/remove_dental_implant
name = "remove dental implant"
desc = "Remove a dental implant from a patient's teeth."
operation_flags = OPERATION_NO_PATIENT_REQUIRED
implements = list(
TOOL_HEMOSTAT = 1,
IMPLEMENT_HAND = 1,
)
time = 3.2 SECONDS
all_surgery_states_required = SURGERY_BONE_DRILLED|SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_BONE_DRILLED|SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/limb/remove_dental_implant/get_default_radial_image()
return image(/obj/item/reagent_containers/applicator/pill)
@@ -85,9 +89,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin looking in [limb.owner]'s mouth for dental implants..."),
span_notice("[surgeon] begins to look in [limb.owner]'s mouth."),
span_notice("[surgeon] begins to examine [limb.owner]'s teeth."),
span_notice("You begin looking in [limb.owner || limb]'s mouth for dental implants..."),
span_notice("[surgeon] begins to look in [limb.owner || limb]'s mouth."),
span_notice("[surgeon] begins to examine [limb.owner || limb]'s teeth."),
)
display_pain(limb.owner, "You feel fingers poke around at your teeth.")
@@ -99,9 +103,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You don't find any dental implants in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] doesn't find any dental implants in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] finishes examining [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You don't find any dental implants in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] doesn't find any dental implants in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] finishes examining [FORMAT_LIMB_OWNER(limb)]."),
)
return
@@ -114,9 +118,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You carefully remove [yoinked] from [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] carefully removes [yoinked] from [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] carefully removes something from [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You carefully remove [yoinked] from [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] carefully removes [yoinked] from [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] carefully removes something from [FORMAT_LIMB_OWNER(limb)]."),
)
// Teeth pill code
@@ -7,7 +7,8 @@
operation_flags = OPERATION_LOOPING
required_bodytype = ~BODYTYPE_ROBOTIC
success_sound = 'sound/machines/card_slide.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/limb/filter_blood/all_required_strings()
. = list()
@@ -19,7 +19,7 @@
time = 1.6 SECONDS
preop_sound = 'sound/items/handling/surgery/scalpel1.ogg'
success_sound = 'sound/items/handling/surgery/scalpel2.ogg'
operation_flags = OPERATION_AFFECTS_MOOD
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_NO_PATIENT_REQUIRED
any_surgery_states_blocked = ALL_SURGERY_SKIN_STATES
/// We can't cut mobs with this biostate
var/biostate_blacklist = BIO_CHITIN
@@ -46,9 +46,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to make an incision in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to make an incision in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to make an incision in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to make an incision in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to make an incision in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to make an incision in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a stabbing in your [limb.plaintext_zone].")
@@ -58,13 +58,19 @@
if(!limb.can_bleed())
return
var/blood_name = limb.owner.get_bloodtype()?.get_blood_name() || "Blood"
var/blood_name = limb.owner?.get_bloodtype()?.get_blood_name()
if(!blood_name && length(limb.blood_dna_info))
var/datum/blood_type/blood_type = limb.blood_dna_info[limb.blood_dna_info[1]]
blood_name = blood_type?.get_blood_name()
if(!blood_name)
blood_name = "Blood"
display_results(
surgeon,
limb.owner,
span_notice("[blood_name] pools around the incision in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[blood_name] pools around the incision in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[blood_name] pools around the incision in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[blood_name] pools around the incision in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[blood_name] pools around the incision in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[blood_name] pools around the incision in [FORMAT_LIMB_OWNER(limb)]."),
)
/// Subtype for thick skinned creatures (Xenomorphs)
@@ -95,6 +101,7 @@
name = "retract skin"
desc = "Retract the patient's skin to access their internal organs. \
Causes \"skin open\" surgical state."
operation_flags = OPERATION_NO_PATIENT_REQUIRED
required_bodytype = ~BODYTYPE_ROBOTIC
replaced_by = /datum/surgery_operation/limb/retract_skin/abductor
implements = list(
@@ -102,6 +109,7 @@
TOOL_SCREWDRIVER = 2.25,
TOOL_WIRECUTTER = 2.85,
/obj/item/stack/rods = 2.85,
/obj/item/kitchen/fork = 2.85,
)
time = 2.4 SECONDS
preop_sound = 'sound/items/handling/surgery/retractor1.ogg'
@@ -115,9 +123,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to retract the skin in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to retract the skin in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to retract the skin in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to retract the skin in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to retract the skin in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to retract the skin in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a severe stinging pain spreading across your [limb.plaintext_zone] as the skin is pulled back.")
@@ -136,6 +144,7 @@
desc = "Mend the incision in the patient's skin, closing it up. \
Clears most surgical states."
required_bodytype = ~BODYTYPE_ROBOTIC
operation_flags = OPERATION_PRIORITY_NEXT_STEP | OPERATION_NO_PATIENT_REQUIRED
replaced_by = /datum/surgery_operation/limb/close_skin/abductor
implements = list(
TOOL_CAUTERY = 1,
@@ -181,9 +190,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to mend the incision in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to mend the incision in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to mend the incision in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to mend the incision in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to mend the incision in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to mend the incision in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "Your [limb.plaintext_zone] is being [istype(tool, /obj/item/stack/medical/suture) ? "pinched" : "burned"]!")
@@ -222,9 +231,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to clamp bleeders in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to clamp bleeders in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to clamp bleeders in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to clamp bleeders in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to clamp bleeders in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to clamp bleeders in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a pinch as the bleeding in your [limb.plaintext_zone] is slowed.")
@@ -246,6 +255,7 @@
desc = "Unclamp blood vessels in the patient's body to allow blood flow again. \
Clears \"vessels clamped\" surgical state."
required_bodytype = ~BODYTYPE_ROBOTIC
operation_flags = OPERATION_PRIORITY_NEXT_STEP
replaced_by = /datum/surgery_operation/limb/unclamp_bleeders/abductor
implements = list(
TOOL_HEMOSTAT = 1,
@@ -270,9 +280,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to unclamp bleeders in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to unclamp bleeders in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to unclamp bleeders in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to unclamp bleeders in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to unclamp bleeders in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to unclamp bleeders in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a pressure release as blood starts flowing in your [limb.plaintext_zone] again.")
@@ -310,7 +320,7 @@
/obj/item = 'sound/items/handling/surgery/scalpel1.ogg',
)
success_sound = 'sound/items/handling/surgery/organ2.ogg'
operation_flags = OPERATION_AFFECTS_MOOD
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_NO_PATIENT_REQUIRED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_BONE_SAWED|SURGERY_BONE_DRILLED
@@ -328,9 +338,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to saw through the bone in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to saw through the bone in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to saw through the bone in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to saw through the bone in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to saw through the bone in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to saw through the bone in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a horrid ache spread through the inside of your [limb.plaintext_zone]!")
@@ -341,9 +351,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You saw [limb.owner]'s [limb.plaintext_zone] open."),
span_notice("[surgeon] saws [limb.owner]'s [limb.plaintext_zone] open!"),
span_notice("[surgeon] saws [limb.owner]'s [limb.plaintext_zone] open!"),
span_notice("You saw [FORMAT_LIMB_OWNER(limb)] open."),
span_notice("[surgeon] saws [FORMAT_LIMB_OWNER(limb)] open!"),
span_notice("[surgeon] saws [FORMAT_LIMB_OWNER(limb)] open!"),
)
display_pain(limb.owner, "It feels like something just broke in your [limb.plaintext_zone]!")
@@ -353,6 +363,7 @@
desc = "Repair a patient's cut or broken bones. \
Clears \"bone sawed\" and \"bone drilled\" surgical states."
required_bodytype = ~BODYTYPE_ROBOTIC
operation_flags = OPERATION_PRIORITY_NEXT_STEP
implements = list(
/obj/item/stack/medical/bone_gel = 1,
/obj/item/stack/sticky_tape/surgical = 1,
@@ -382,9 +393,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to fix the bones in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to fix the bones in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to fix the bones in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to fix the bones in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to fix the bones in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to fix the bones in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a grinding sensation in your [limb.plaintext_zone] as the bones are set back in place.")
@@ -398,6 +409,7 @@
desc = "Drill through a patient's bones. \
Causes \"bone drilled\" surgical state."
required_bodytype = ~BODYTYPE_ROBOTIC
operation_flags = OPERATION_PRIORITY_NEXT_STEP
implements = list(
TOOL_DRILL = 1,
/obj/item/screwdriver/power = 1.25,
@@ -426,9 +438,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to drill into the bone in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to drill into the bone in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to drill into the bone in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to drill into the bone in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to drill into the bone in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to drill into the bone in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a horrible piercing pain in your [limb.plaintext_zone]!")
@@ -438,9 +450,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You drill into [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] drills into [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("[surgeon] drills into [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You drill into [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] drills into [FORMAT_LIMB_OWNER(limb)]!"),
span_notice("[surgeon] drills into [FORMAT_LIMB_OWNER(limb)]!"),
)
/datum/surgery_operation/limb/incise_organs
@@ -448,6 +460,7 @@
desc = "Make an incision in patient's internal organ tissue to allow for manipulation or repair. \
Causes \"organs cut\" surgical state."
required_bodytype = ~BODYTYPE_ROBOTIC
operation_flags = OPERATION_PRIORITY_NEXT_STEP
replaced_by = /datum/surgery_operation/limb/incise_organs/abductor
implements = list(
TOOL_SCALPEL = 1,
@@ -477,9 +490,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to make an incision in the organs within [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to make an incision in the organs within [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to make an incision in the organs within [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to make an incision in the organs within [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to make an incision in the organs within [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to make an incision in the organs within [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a stabbing in your [limb.plaintext_zone].")
@@ -490,9 +503,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You make an incision in the organs within [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] makes an incision in the organs within [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("[surgeon] makes an incision in the organs within [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You make an incision in the organs within [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] makes an incision in the organs within [FORMAT_LIMB_OWNER(limb)]!"),
span_notice("[surgeon] makes an incision in the organs within [FORMAT_LIMB_OWNER(limb)]!"),
)
display_pain(limb.owner, "You feel a sharp pain from inside your [limb.plaintext_zone]!")
@@ -10,7 +10,7 @@
/obj/item/knife = 2,
/obj/item = 10, // i think this amounts to a 180% chance of failure (clamped to 99%)
)
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC | OPERATION_NO_PATIENT_REQUIRED
required_bodytype = BODYTYPE_ROBOTIC
time = 2.4 SECONDS
preop_sound = 'sound/items/tools/screwdriver.ogg'
@@ -31,9 +31,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to unscrew the shell of [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to unscrew the shell of [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to unscrew the shell of [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to unscrew the shell of [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to unscrew the shell of [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to unscrew the shell of [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel your [limb.plaintext_zone] grow numb as the shell is unscrewed.", TRUE)
@@ -51,7 +51,7 @@
IMPLEMENT_HAND = 1,
TOOL_CROWBAR = 1,
)
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC | OPERATION_NO_PATIENT_REQUIRED
time = 1 SECONDS
preop_sound = 'sound/items/tools/ratchet.ogg'
success_sound = 'sound/machines/airlock/doorclick.ogg'
@@ -64,9 +64,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to open the hatch holders in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to open the hatch holders in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to open the hatch holders in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to open the hatch holders in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to open the hatch holders in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to open the hatch holders in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "The last faint pricks of tactile sensation fade from your [limb.plaintext_zone] as the hatch is opened.", TRUE)
@@ -88,7 +88,7 @@
/obj/item/knife = 2,
/obj/item = 10,
)
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC | OPERATION_NO_PATIENT_REQUIRED
time = 2.4 SECONDS
preop_sound = 'sound/items/tools/screwdriver.ogg'
success_sound = 'sound/items/tools/screwdriver2.ogg'
@@ -111,9 +111,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to screw the shell of [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to screw the shell of [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to screw the shell of [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to screw the shell of [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to screw the shell of [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to screw the shell of [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel the faint pricks of sensation return as your [limb.plaintext_zone]'s shell is screwed in.", TRUE)
@@ -131,7 +131,7 @@
TOOL_MULTITOOL = 1,
TOOL_HEMOSTAT = 1.33,
)
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC | OPERATION_NO_PATIENT_REQUIRED
time = 2.4 SECONDS
preop_sound = 'sound/items/taperecorder/tape_flip.ogg'
success_sound = 'sound/items/taperecorder/taperecorder_close.ogg'
@@ -145,9 +145,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to prepare electronics in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to prepare electronics in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to prepare electronics in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to prepare electronics in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to prepare electronics in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to prepare electronics in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You can feel a faint buzz in your [limb.plaintext_zone] as the electronics reboot.", TRUE)
@@ -165,7 +165,7 @@
TOOL_WRENCH = 1,
TOOL_RETRACTOR = 1.33,
)
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC | OPERATION_NO_PATIENT_REQUIRED
time = 2.4 SECONDS
preop_sound = 'sound/items/tools/ratchet.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN
@@ -178,9 +178,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to unwrench some bolts in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to unwrench some bolts in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to unwrench some bolts in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to unwrench some bolts in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to unwrench some bolts in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to unwrench some bolts in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a jostle in your [limb.plaintext_zone] as the bolts begin to loosen.", TRUE)
@@ -201,7 +201,7 @@
operation_flags = OPERATION_SELF_OPERABLE | OPERATION_MECHANIC
time = 2.4 SECONDS
preop_sound = 'sound/items/tools/ratchet.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED | OPERATION_NO_PATIENT_REQUIRED
/datum/surgery_operation/limb/mechanic_wrench/state_check(obj/item/bodypart/limb)
return LIMB_HAS_BONES(limb)
@@ -216,9 +216,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to wrench some bolts in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to wrench some bolts in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] begins to wrench some bolts in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to wrench some bolts in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to wrench some bolts in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] begins to wrench some bolts in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a jostle in your [limb.plaintext_zone] as the bolts begin to tighten.", TRUE)
@@ -10,7 +10,8 @@
)
time = 6.4 SECONDS
success_sound = 'sound/items/handling/surgery/hemostat1.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/basic/implant_removal/get_default_radial_image()
return image('icons/obj/medical/syringe.dmi', "implantcase-b")
@@ -19,7 +19,8 @@
/obj/item = 'sound/items/handling/surgery/scalpel1.ogg',
)
success_sound = 'sound/items/handling/surgery/organ2.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/limb/lipoplasty/get_any_tool()
return "Any sharp edged item"
@@ -3,7 +3,7 @@
rnd_name = "Lobotomy (Lobotomy)"
desc = "Repair most of a patient's brain traumas, with the risk of causing new permanent traumas."
rnd_desc = "An invasive surgical procedure which guarantees removal of almost all brain traumas, but might cause another permanent trauma in return."
operation_flags = OPERATION_MORBID | OPERATION_AFFECTS_MOOD | OPERATION_LOCKED | OPERATION_NOTABLE
operation_flags = OPERATION_MORBID | OPERATION_AFFECTS_MOOD | OPERATION_LOCKED | OPERATION_NOTABLE | OPERATION_NO_PATIENT_REQUIRED
implements = list(
TOOL_SCALPEL = 1.15,
/obj/item/melee/energy/sword = 0.55,
@@ -16,7 +16,8 @@
preop_sound = 'sound/items/handling/surgery/scalpel1.ogg'
success_sound = 'sound/items/handling/surgery/scalpel2.ogg'
failure_sound = 'sound/items/handling/surgery/organ2.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED|SURGERY_BONE_SAWED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/organ/lobotomy/get_any_tool()
return "Any sharp edged item"
@@ -29,9 +30,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You begin to perform a lobotomy on [organ.owner]'s brain..."),
span_notice("[surgeon] begins to perform a lobotomy on [organ.owner]'s brain."),
span_notice("[surgeon] begins to perform surgery on [organ.owner]'s brain."),
span_notice("You begin to perform a lobotomy on [FORMAT_ORGAN_OWNER(organ)]'s brain..."),
span_notice("[surgeon] begins to perform a lobotomy on [FORMAT_ORGAN_OWNER(organ)]'s brain."),
span_notice("[surgeon] begins to perform surgery on [FORMAT_ORGAN_OWNER(organ)]'s brain."),
)
display_pain(organ.owner, "Your head pounds with unimaginable pain!")
@@ -39,21 +40,26 @@
display_results(
surgeon,
organ.owner,
span_notice("You successfully perform a lobotomy on [organ.owner]!"),
span_notice("[surgeon] successfully lobotomizes [organ.owner]!"),
span_notice("[surgeon] finishes performing surgery on [organ.owner]'s brain."),
span_notice("You successfully perform a lobotomy on [FORMAT_ORGAN_OWNER(organ)]!"),
span_notice("[surgeon] successfully lobotomizes [FORMAT_ORGAN_OWNER(organ)]!"),
span_notice("[surgeon] finishes performing surgery on [FORMAT_ORGAN_OWNER(organ)]'s brain."),
)
display_pain(organ.owner, "Your head goes totally numb for a moment, the pain is overwhelming!")
organ.cure_all_traumas(TRAUMA_RESILIENCE_LOBOTOMY)
organ.owner.mind?.remove_antag_datum(/datum/antagonist/brainwashed)
if (organ.owner)
organ.owner.mind?.remove_antag_datum(/datum/antagonist/brainwashed)
else if (organ.brainmob)
organ.brainmob.mind?.remove_antag_datum(/datum/antagonist/brainwashed)
if(!prob(75))
return
switch(rand(1, 3))//Now let's see what hopefully-not-important part of the brain we cut off
if(1)
organ.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_MAGIC)
if(2)
if(HAS_TRAIT(organ.owner, TRAIT_SPECIAL_TRAUMA_BOOST) && prob(50))
if(HAS_TRAIT(organ, TRAIT_SPECIAL_TRAUMA_BOOST) && prob(50))
organ.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, TRAUMA_RESILIENCE_MAGIC)
else
organ.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_MAGIC)
@@ -65,21 +71,21 @@
surgeon,
organ.owner,
span_warning("You remove the wrong part, causing more damage!"),
span_notice("[surgeon] unsuccessfully attempts to lobotomize [organ.owner]!"),
span_notice("[surgeon] completes the surgery on [organ.owner]'s brain."),
span_notice("[surgeon] unsuccessfully attempts to lobotomize [FORMAT_ORGAN_OWNER(organ)]!"),
span_notice("[surgeon] completes the surgery on [FORMAT_ORGAN_OWNER(organ)]'s brain."),
)
display_pain(organ.owner, "The pain in your head only seems to get worse!")
organ.apply_organ_damage(80)
switch(rand(1, 3))
if(1)
organ.owner.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_MAGIC)
organ.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_MAGIC)
if(2)
if(HAS_TRAIT(organ.owner, TRAIT_SPECIAL_TRAUMA_BOOST) && prob(50))
organ.owner.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, TRAUMA_RESILIENCE_MAGIC)
if(HAS_TRAIT(organ, TRAIT_SPECIAL_TRAUMA_BOOST) && prob(50))
organ.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, TRAUMA_RESILIENCE_MAGIC)
else
organ.owner.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_MAGIC)
organ.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_MAGIC)
if(3)
organ.owner.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, TRAUMA_RESILIENCE_MAGIC)
organ.gain_trauma_type(BRAIN_TRAUMA_SPECIAL, TRAUMA_RESILIENCE_MAGIC)
/datum/surgery_operation/organ/lobotomy/mechanic
name = "execute neural defragging"
@@ -4,7 +4,7 @@
/datum/surgery_operation/limb/organ_manipulation
name = "organ manipulation"
abstract_type = /datum/surgery_operation/limb/organ_manipulation
operation_flags = OPERATION_MORBID | OPERATION_NOTABLE
operation_flags = OPERATION_MORBID | OPERATION_NOTABLE | OPERATION_NO_PATIENT_REQUIRED
required_bodytype = ~BODYTYPE_ROBOTIC
/// Radial slice datums for every organ type we can manipulate
VAR_PRIVATE/list/cached_organ_manipulation_options
@@ -109,7 +109,7 @@
option.image = get_generic_limb_radial_image(limb.body_zone)
option.image.overlays += add_radial_overlays(organ.type)
option.name = "remove [initial(organ.name)]"
option.info = "Remove [initial(organ.name)] from the patient."
option.info = "Remove [initial(organ.name)] from the [limb.owner ? "patient" : "limb"]."
LAZYSET(cached_organ_manipulation_options, "[organ.type]_remove", option)
options[option] = list("[OPERATION_ACTION]" = "remove", "[OPERATION_REMOVED_ORGAN]" = organ)
@@ -123,7 +123,7 @@
option.image = get_generic_limb_radial_image(limb.body_zone)
option.image.overlays += add_radial_overlays(list(image('icons/hud/screen_gen.dmi', "arrow_large_still"), organ.type))
option.name = "insert [initial(organ.name)]"
option.info = "insert [initial(organ.name)] into the patient."
option.info = "insert [initial(organ.name)] into the [limb.owner ? "patient" : "limb"]."
LAZYSET(cached_organ_manipulation_options, "[organ.type]_insert", option)
var/list/result = list()
@@ -155,9 +155,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to remove [organ.name] from [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to remove [organ.name] from [limb.owner]."),
span_notice("[surgeon] begins to remove something from [limb.owner]."),
span_notice("You begin to remove [organ.name] from [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to remove [organ.name] from [limb.owner || limb]."),
span_notice("[surgeon] begins to remove something from [limb.owner || limb]."),
)
display_pain(limb.owner, "You feel a tugging sensation in your [limb.plaintext_zone]!")
if("insert")
@@ -165,9 +165,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to insert [tool.name] into [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to insert [tool.name] into [limb.owner]."),
span_notice("[surgeon] begins to insert something into [limb.owner]."),
span_notice("You begin to insert [tool.name] into [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to insert [tool.name] into [limb.owner || limb]."),
span_notice("[surgeon] begins to insert something into [limb.owner || limb]."),
)
display_pain(limb.owner, "You can feel something being placed in your [limb.plaintext_zone]!")
@@ -186,27 +186,33 @@
display_results(
surgeon,
limb.owner,
span_notice("You successfully extract [organ.name] from [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] successfully extracts [organ.name] from [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("[surgeon] successfully extracts something from [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You successfully extract [organ.name] from [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] successfully extracts [organ.name] from [FORMAT_LIMB_OWNER(limb)]!"),
span_notice("[surgeon] successfully extracts something from [FORMAT_LIMB_OWNER(limb)]!"),
)
display_pain(limb.owner, "Your [limb.plaintext_zone] throbs with pain, you can't feel your [organ.name] anymore!")
log_combat(surgeon, limb.owner, "surgically removed [organ.name] from")
organ.Remove(limb.owner)
organ.forceMove(limb.owner.drop_location())
log_combat(surgeon, limb.owner || limb, "surgically removed [organ.name] from")
if (limb.owner)
organ.Remove(limb.owner)
else
organ.bodypart_remove(limb)
organ.forceMove(limb.owner ? limb.owner.drop_location() : limb.drop_location())
organ.on_surgical_removal(surgeon, limb, tool)
/datum/surgery_operation/limb/organ_manipulation/proc/on_success_insert_organ(obj/item/bodypart/limb, mob/living/surgeon, obj/item/organ/organ)
surgeon.temporarilyRemoveItemFromInventory(organ, TRUE)
organ.pre_surgical_insertion(surgeon, limb, limb.body_zone)
organ.Insert(limb.owner)
if (limb.owner)
organ.Insert(limb.owner)
else
organ.bodypart_insert(limb)
organ.on_surgical_insertion(surgeon, limb, organ)
display_results(
surgeon,
limb.owner,
span_notice("You successfully insert [organ.name] into [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] successfully inserts [organ.name] into [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] successfully inserts something into [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You successfully insert [organ.name] into [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] successfully inserts [organ.name] into [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] successfully inserts something into [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "Your [limb.plaintext_zone] throbs with pain as your new [organ.name] comes to life!")
@@ -246,7 +252,8 @@
/datum/surgery_operation/limb/organ_manipulation/internal/abductor
name = "experimental organ manipulation"
operation_flags = parent_type::operation_flags | OPERATION_IGNORE_CLOTHES | OPERATION_LOCKED | OPERATION_NO_WIKI
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
bone_locked_organs = "the brain or any chest organs EXCLUDING the heart"
/datum/surgery_operation/limb/organ_manipulation/internal/abductor/organ_check(obj/item/bodypart/limb, obj/item/organ/organ)
@@ -257,7 +264,8 @@
name = "feature manipulation"
desc = "Manipulate features of the patient, such as a moth's wings or a lizard's tail."
replaced_by = /datum/surgery_operation/limb/organ_manipulation/external/abductor
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED|SURGERY_BONE_SAWED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/limb/organ_manipulation/external/organ_check(obj/item/bodypart/limb, obj/item/organ/organ)
return (organ.organ_flags & ORGAN_EXTERNAL)
@@ -277,6 +285,7 @@
/datum/surgery_operation/limb/organ_manipulation/external/abductor
name = "experimental feature manipulation"
operation_flags = parent_type::operation_flags | OPERATION_IGNORE_CLOTHES | OPERATION_LOCKED | OPERATION_NO_WIKI
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
#undef OPERATION_REMOVED_ORGAN
@@ -4,7 +4,7 @@
name = "repair organ"
desc = "Repair a patient's damaged organ."
required_organ_flag = ORGAN_TYPE_FLAGS & ~ORGAN_ROBOTIC
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_NOTABLE
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_NOTABLE | OPERATION_NO_PATIENT_REQUIRED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_ORGANS_CUT|SURGERY_BONE_SAWED
/// What % damage do we heal the organ to on success
/// Note that 0% damage = 100% health
@@ -65,9 +65,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You begin to make an incision in [organ.owner]'s lungs..."),
span_notice("[surgeon] begins to make an incision in [organ.owner]."),
span_notice("[surgeon] begins to make an incision in [organ.owner]."),
span_notice("You begin to make an incision in [FORMAT_ORGAN_OWNER(organ)]'s lungs..."),
span_notice("[surgeon] begins to make an incision in [FORMAT_ORGAN_OWNER(organ)]."),
span_notice("[surgeon] begins to make an incision in [FORMAT_ORGAN_OWNER(organ)]."),
)
display_pain(organ.owner, "You feel a stabbing pain in your chest!")
@@ -76,18 +76,18 @@
display_results(
surgeon,
organ.owner,
span_notice("You successfully excise [organ.owner]'s most damaged lobe."),
span_notice("[surgeon] successfully excises [organ.owner]'s most damaged lobe."),
span_notice("[surgeon] successfully excises [organ.owner]'s most damaged lobe."),
span_notice("You successfully excise [FORMAT_ORGAN_OWNER(organ)]'s most damaged lobe."),
span_notice("[surgeon] successfully excises [FORMAT_ORGAN_OWNER(organ)]'s most damaged lobe."),
span_notice("[surgeon] successfully excises [FORMAT_ORGAN_OWNER(organ)]'s most damaged lobe."),
)
/datum/surgery_operation/organ/repair/lobectomy/on_failure(obj/item/organ/organ, mob/living/surgeon, obj/item/tool, list/operation_args)
. = ..()
organ.owner.losebreath += 4
organ.owner?.losebreath += 4
display_results(
surgeon,
organ.owner,
span_warning("You screw up, failing to excise [organ.owner]'s damaged lobe!"),
span_warning("You screw up, failing to excise [FORMAT_ORGAN_OWNER(organ)]'s damaged lobe!"),
span_warning("[surgeon] screws up!"),
span_warning("[surgeon] screws up!"),
)
@@ -130,9 +130,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You begin to cut out a damaged piece of [organ.owner]'s liver..."),
span_notice("[surgeon] begins to make an incision in [organ.owner]."),
span_notice("[surgeon] begins to make an incision in [organ.owner]."),
span_notice("You begin to cut out a damaged piece of [FORMAT_ORGAN_OWNER(organ)]'s liver..."),
span_notice("[surgeon] begins to make an incision in [FORMAT_ORGAN_OWNER(organ)]."),
span_notice("[surgeon] begins to make an incision in [FORMAT_ORGAN_OWNER(organ)]."),
)
display_pain(organ.owner, "Your abdomen burns in horrific stabbing pain!")
@@ -141,9 +141,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You successfully remove the damaged part of [organ.owner]'s liver."),
span_notice("[surgeon] successfully removes the damaged part of [organ.owner]'s liver."),
span_notice("[surgeon] successfully removes the damaged part of [organ.owner]'s liver."),
span_notice("You successfully remove the damaged part of [FORMAT_ORGAN_OWNER(organ)]'s liver."),
span_notice("[surgeon] successfully removes the damaged part of [FORMAT_ORGAN_OWNER(organ)]'s liver."),
span_notice("[surgeon] successfully removes the damaged part of [FORMAT_ORGAN_OWNER(organ)]'s liver."),
)
display_pain(organ.owner, "The pain receeds slightly!")
@@ -152,9 +152,9 @@
display_results(
surgeon,
organ.owner,
span_warning("You cut the wrong part of [organ.owner]'s liver!"),
span_warning("[surgeon] cuts the wrong part of [organ.owner]'s liver!"),
span_warning("[surgeon] cuts the wrong part of [organ.owner]'s liver!"),
span_warning("You cut the wrong part of [FORMAT_ORGAN_OWNER(organ)]'s liver!"),
span_warning("[surgeon] cuts the wrong part of [FORMAT_ORGAN_OWNER(organ)]'s liver!"),
span_warning("[surgeon] cuts the wrong part of [FORMAT_ORGAN_OWNER(organ)]'s liver!"),
)
display_pain(organ.owner, "The pain in your abdomen intensifies!")
@@ -193,9 +193,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You begin to graft a bypass onto [organ.owner]'s heart..."),
span_notice("[surgeon] begins to graft a bypass onto [organ.owner]'s heart."),
span_notice("[surgeon] begins to graft a bypass onto [organ.owner]'s heart."),
span_notice("You begin to graft a bypass onto [FORMAT_ORGAN_OWNER(organ)]'s heart..."),
span_notice("[surgeon] begins to graft a bypass onto [FORMAT_ORGAN_OWNER(organ)]'s heart."),
span_notice("[surgeon] begins to graft a bypass onto [FORMAT_ORGAN_OWNER(organ)]'s heart."),
)
display_pain(organ.owner, "The pain in your chest is unbearable! You can barely take it anymore!")
@@ -204,22 +204,22 @@
display_results(
surgeon,
organ.owner,
span_notice("You successfully graft a bypass onto [organ.owner]'s heart."),
span_notice("[surgeon] successfully grafts a bypass onto [organ.owner]'s heart."),
span_notice("[surgeon] successfully grafts a bypass onto [organ.owner]'s heart."),
span_notice("You successfully graft a bypass onto [FORMAT_ORGAN_OWNER(organ)]'s heart."),
span_notice("[surgeon] successfully grafts a bypass onto [FORMAT_ORGAN_OWNER(organ)]'s heart."),
span_notice("[surgeon] successfully grafts a bypass onto [FORMAT_ORGAN_OWNER(organ)]'s heart."),
)
display_pain(organ.owner, "The pain in your chest throbs, but your heart feels better than ever!")
/datum/surgery_operation/organ/repair/coronary_bypass/on_failure(obj/item/organ/organ, mob/living/surgeon, obj/item/tool, list/operation_args)
. = ..()
organ.bodypart_owner.adjustBleedStacks(30)
var/blood_name = LOWER_TEXT(organ.owner.get_bloodtype()?.get_blood_name()) || "blood"
organ.bodypart_owner?.adjustBleedStacks(30)
var/blood_name = LOWER_TEXT(organ.owner?.get_bloodtype()?.get_blood_name()) || "blood"
display_results(
surgeon,
organ.owner,
span_warning("You screw up in attaching the graft, and it tears off, tearing part of the heart!"),
span_warning("[surgeon] screws up, causing [blood_name] to spurt out of [organ.owner]'s chest profusely!"),
span_warning("[surgeon] screws up, causing [blood_name] to spurt out of [organ.owner]'s chest profusely!"),
span_warning("[surgeon] screws up, causing [blood_name] to spurt out of [FORMAT_ORGAN_OWNER(organ)]'s chest profusely!"),
span_warning("[surgeon] screws up, causing [blood_name] to spurt out of [FORMAT_ORGAN_OWNER(organ)]'s chest profusely!"),
)
display_pain(organ.owner, "Your chest burns; you feel like you're going insane!")
@@ -268,9 +268,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You begin to cut out a damaged piece of [organ.owner]'s stomach..."),
span_notice("[surgeon] begins to make an incision in [organ.owner]."),
span_notice("[surgeon] begins to make an incision in [organ.owner]."),
span_notice("You begin to cut out a damaged piece of [FORMAT_ORGAN_OWNER(organ)]'s stomach..."),
span_notice("[surgeon] begins to make an incision in [FORMAT_ORGAN_OWNER(organ)]."),
span_notice("[surgeon] begins to make an incision in [FORMAT_ORGAN_OWNER(organ)]."),
)
display_pain(organ.owner, "You feel a horrible stab in your gut!")
@@ -279,9 +279,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You successfully remove the damaged part of [organ.owner]'s stomach."),
span_notice("[surgeon] successfully removes the damaged part of [organ.owner]'s stomach."),
span_notice("[surgeon] successfully removes the damaged part of [organ.owner]'s stomach."),
span_notice("You successfully remove the damaged part of [FORMAT_ORGAN_OWNER(organ)]'s stomach."),
span_notice("[surgeon] successfully removes the damaged part of [FORMAT_ORGAN_OWNER(organ)]'s stomach."),
span_notice("[surgeon] successfully removes the damaged part of [FORMAT_ORGAN_OWNER(organ)]'s stomach."),
)
display_pain(organ.owner, "The pain in your gut receeds slightly!")
@@ -290,9 +290,9 @@
display_results(
surgeon,
organ.owner,
span_warning("You cut the wrong part of [organ.owner]'s stomach!"),
span_warning("[surgeon] cuts the wrong part of [organ.owner]'s stomach!"),
span_warning("[surgeon] cuts the wrong part of [organ.owner]'s stomach!"),
span_warning("You cut the wrong part of [FORMAT_ORGAN_OWNER(organ)]'s stomach!"),
span_warning("[surgeon] cuts the wrong part of [FORMAT_ORGAN_OWNER(organ)]'s stomach!"),
span_warning("[surgeon] cuts the wrong part of [FORMAT_ORGAN_OWNER(organ)]'s stomach!"),
)
display_pain(organ.owner, "The pain in your gut intensifies!")
@@ -326,7 +326,8 @@
time = 6.4 SECONDS
heal_to_percent = 0
repeatable = TRUE
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/organ/repair/ears/all_blocked_strings()
return ..() + list("if the limb has bones, they must be intact")
@@ -341,9 +342,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You begin to fix [organ.owner]'s ears..."),
span_notice("[surgeon] begins to fix [organ.owner]'s ears."),
span_notice("[surgeon] begins to perform surgery on [organ.owner]'s ears."),
span_notice("You begin to fix [FORMAT_ORGAN_OWNER(organ)]'s ears..."),
span_notice("[surgeon] begins to fix [FORMAT_ORGAN_OWNER(organ)]'s ears."),
span_notice("[surgeon] begins to perform surgery on [FORMAT_ORGAN_OWNER(organ)]'s ears."),
)
display_pain(organ.owner, "You feel a dizzying pain in your head!")
@@ -354,32 +355,33 @@
display_results(
surgeon,
organ.owner,
span_notice("You successfully fix [organ.owner]'s ears."),
span_notice("[surgeon] successfully fixes [organ.owner]'s ears."),
span_notice("[surgeon] successfully fixes [organ.owner]'s ears."),
span_notice("You successfully fix [FORMAT_ORGAN_OWNER(organ)]'s ears."),
span_notice("[surgeon] successfully fixes [FORMAT_ORGAN_OWNER(organ)]'s ears."),
span_notice("[surgeon] successfully fixes [FORMAT_ORGAN_OWNER(organ)]'s ears."),
)
display_pain(organ.owner, "Your head swims, but it seems like you can feel your hearing coming back!")
/datum/surgery_operation/organ/repair/ears/on_failure(obj/item/organ/ears/organ, mob/living/surgeon, obj/item/tool, list/operation_args)
var/obj/item/organ/brain/brain = locate() in organ.bodypart_owner
if(brain)
if(isnull(brain))
display_results(
surgeon,
organ.owner,
span_warning("You accidentally stab [organ.owner] right in the brain!"),
span_warning("[surgeon] accidentally stabs [organ.owner] right in the brain!"),
span_warning("[surgeon] accidentally stabs [organ.owner] right in the brain!"),
)
display_pain(organ.owner, "You feel a visceral stabbing pain right through your head, into your brain!")
organ.owner.adjust_organ_loss(ORGAN_SLOT_BRAIN, 70)
else
display_results(
surgeon,
organ.owner,
span_warning("You accidentally stab [organ.owner] right in the brain! Or would have, if [organ.owner] had a brain."),
span_warning("[surgeon] accidentally stabs [organ.owner] right in the brain! Or would have, if [organ.owner] had a brain."),
span_warning("[surgeon] accidentally stabs [organ.owner] right in the brain!"),
span_warning("You accidentally stab [FORMAT_ORGAN_OWNER(organ)] right in the brain! Or would have, if [FORMAT_ORGAN_OWNER(organ)] had a brain."),
span_warning("[surgeon] accidentally stabs [FORMAT_ORGAN_OWNER(organ)] right in the brain! Or would have, if [FORMAT_ORGAN_OWNER(organ)] had a brain."),
span_warning("[surgeon] accidentally stabs [FORMAT_ORGAN_OWNER(organ)] right in the brain!"),
)
return
display_results(
surgeon,
organ.owner,
span_warning("You accidentally stab [FORMAT_ORGAN_OWNER(organ)] right in the brain!"),
span_warning("[surgeon] accidentally stabs [FORMAT_ORGAN_OWNER(organ)] right in the brain!"),
span_warning("[surgeon] accidentally stabs [FORMAT_ORGAN_OWNER(organ)] right in the brain!"),
)
display_pain(organ.owner, "You feel a visceral stabbing pain right through your head, into your brain!")
organ.apply_organ_damage(70)
/datum/surgery_operation/organ/repair/eyes
name = "eye surgery"
@@ -395,7 +397,8 @@
target_type = /obj/item/organ/eyes
heal_to_percent = 0
repeatable = TRUE
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/organ/repair/eyes/all_blocked_strings()
return ..() + list("if the limb has bones, they must be intact")
@@ -413,46 +416,46 @@
display_results(
surgeon,
organ.owner,
span_notice("You begin to fix [organ.owner]'s eyes..."),
span_notice("[surgeon] begins to fix [organ.owner]'s eyes."),
span_notice("[surgeon] begins to perform surgery on [organ.owner]'s eyes."),
span_notice("You begin to fix [FORMAT_ORGAN_OWNER(organ)]'s eyes..."),
span_notice("[surgeon] begins to fix [FORMAT_ORGAN_OWNER(organ)]'s eyes."),
span_notice("[surgeon] begins to perform surgery on [FORMAT_ORGAN_OWNER(organ)]'s eyes."),
)
display_pain(organ.owner, "You feel a stabbing pain in your eyes!")
/datum/surgery_operation/organ/repair/eyes/on_success(obj/item/organ/organ, mob/living/surgeon, obj/item/tool, list/operation_args)
. = ..()
organ.owner.remove_status_effect(/datum/status_effect/temporary_blindness)
organ.owner.set_eye_blur_if_lower(70 SECONDS) //this will fix itself slowly.
organ.owner?.remove_status_effect(/datum/status_effect/temporary_blindness)
organ.owner?.set_eye_blur_if_lower(70 SECONDS) //this will fix itself slowly.
display_results(
surgeon,
organ.owner,
span_notice("You successfully fix [organ.owner]'s eyes."),
span_notice("[surgeon] successfully fixes [organ.owner]'s eyes."),
span_notice("[surgeon] successfully fixes [organ.owner]'s eyes."),
span_notice("You successfully fix [FORMAT_ORGAN_OWNER(organ)]'s eyes."),
span_notice("[surgeon] successfully fixes [FORMAT_ORGAN_OWNER(organ)]'s eyes."),
span_notice("[surgeon] successfully fixes [FORMAT_ORGAN_OWNER(organ)]'s eyes."),
)
display_pain(organ.owner, "Your vision blurs, but it seems like you can see a little better now!")
/datum/surgery_operation/organ/repair/eyes/on_failure(obj/item/organ/organ, mob/living/surgeon, obj/item/tool, list/operation_args)
var/obj/item/organ/brain/brain = locate() in organ.bodypart_owner
if(brain)
if(isnull(brain))
display_results(
surgeon,
organ.owner,
span_warning("You accidentally stab [organ.owner] right in the brain!"),
span_warning("[surgeon] accidentally stabs [organ.owner] right in the brain!"),
span_warning("[surgeon] accidentally stabs [organ.owner] right in the brain!"),
span_warning("You accidentally stab [FORMAT_ORGAN_OWNER(organ)] right in the brain! Or would have, if [FORMAT_ORGAN_OWNER(organ)] had a brain."),
span_warning("[surgeon] accidentally stabs [FORMAT_ORGAN_OWNER(organ)] right in the brain! Or would have, if [FORMAT_ORGAN_OWNER(organ)] had a brain."),
span_warning("[surgeon] accidentally stabs [FORMAT_ORGAN_OWNER(organ)] right in the brain!"),
)
display_pain(organ.owner, "You feel a visceral stabbing pain right through your head, into your brain!")
organ.owner.adjust_organ_loss(ORGAN_SLOT_BRAIN, 70)
return
else
display_results(
surgeon,
organ.owner,
span_warning("You accidentally stab [organ.owner] right in the brain! Or would have, if [organ.owner] had a brain."),
span_warning("[surgeon] accidentally stabs [organ.owner] right in the brain! Or would have, if [organ.owner] had a brain."),
span_warning("[surgeon] accidentally stabs [organ.owner] right in the brain!"),
)
display_results(
surgeon,
organ.owner,
span_warning("You accidentally stab [FORMAT_ORGAN_OWNER(organ)] right in the brain!"),
span_warning("[surgeon] accidentally stabs [FORMAT_ORGAN_OWNER(organ)] right in the brain!"),
span_warning("[surgeon] accidentally stabs [FORMAT_ORGAN_OWNER(organ)] right in the brain!"),
)
display_pain(organ.owner, "You feel a visceral stabbing pain right through your head, into your brain!")
organ.apply_organ_damage(70)
/datum/surgery_operation/organ/repair/brain
name = "brain surgery"
@@ -472,7 +475,8 @@
heal_to_percent = 0.25
failure_damage_percent = 0.3
repeatable = TRUE
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/organ/repair/brain/state_check(obj/item/organ/brain/organ)
return TRUE // always available so you can intentionally fail it
@@ -481,9 +485,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You begin to fix [organ.owner]'s brain..."),
span_notice("[surgeon] begins to fix [organ.owner]'s brain."),
span_notice("[surgeon] begins to perform surgery on [organ.owner]'s brain."),
span_notice("You begin to fix [FORMAT_ORGAN_OWNER(organ)]'s brain..."),
span_notice("[surgeon] begins to fix [FORMAT_ORGAN_OWNER(organ)]'s brain."),
span_notice("[surgeon] begins to perform surgery on [FORMAT_ORGAN_OWNER(organ)]'s brain."),
)
display_pain(organ.owner, "Your head pounds with unimaginable pain!")
@@ -492,15 +496,18 @@
display_results(
surgeon,
organ.owner,
span_notice("You succeed in fixing [organ.owner]'s brain."),
span_notice("[surgeon] successfully fixes [organ.owner]'s brain!"),
span_notice("[surgeon] completes the surgery on [organ.owner]'s brain."),
span_notice("You succeed in fixing [FORMAT_ORGAN_OWNER(organ)]'s brain."),
span_notice("[surgeon] successfully fixes [FORMAT_ORGAN_OWNER(organ)]'s brain!"),
span_notice("[surgeon] completes the surgery on [FORMAT_ORGAN_OWNER(organ)]'s brain."),
)
display_pain(organ.owner, "The pain in your head receeds, thinking becomes a bit easier!")
organ.owner.mind?.remove_antag_datum(/datum/antagonist/brainwashed)
if (organ.owner)
organ.owner.mind?.remove_antag_datum(/datum/antagonist/brainwashed)
else if (organ.brainmob)
organ.brainmob.mind?.remove_antag_datum(/datum/antagonist/brainwashed)
organ.cure_all_traumas(TRAUMA_RESILIENCE_SURGERY)
if(organ.damage > organ.maxHealth * 0.1)
to_chat(surgeon, "[organ.owner]'s brain looks like it could be fixed further.")
to_chat(surgeon, "[FORMAT_ORGAN_OWNER(organ)]'s brain looks like it could be fixed further.")
/datum/surgery_operation/organ/repair/brain/on_failure(obj/item/organ/brain/organ, mob/living/surgeon, obj/item/tool, list/operation_args)
. = ..()
@@ -509,7 +516,7 @@
organ.owner,
span_warning("You screw up, causing more damage!"),
span_warning("[surgeon] screws up, causing brain damage!"),
span_notice("[surgeon] completes the surgery on [organ.owner]'s brain."),
span_notice("[surgeon] completes the surgery on [FORMAT_ORGAN_OWNER(organ)]'s brain."),
)
display_pain(organ.owner, "Your head throbs with horrible pain; thinking hurts!")
organ.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_LOBOTOMY)
@@ -3,7 +3,7 @@
rnd_name = "Paxopsy (Pacification)"
desc = "Remove aggressive tendencies from a patient's brain."
rnd_desc = "A surgical procedure which permanently inhibits the aggression center of the brain, making the patient unwilling to cause direct harm."
operation_flags = OPERATION_MORBID | OPERATION_LOCKED | OPERATION_NOTABLE
operation_flags = OPERATION_MORBID | OPERATION_LOCKED | OPERATION_NOTABLE | OPERATION_NO_PATIENT_REQUIRED
implements = list(
TOOL_HEMOSTAT = 1,
TOOL_SCREWDRIVER = 2.85,
@@ -15,7 +15,8 @@
failure_sound = 'sound/items/handling/surgery/organ2.ogg'
required_organ_flag = ORGAN_TYPE_FLAGS & ~ORGAN_ROBOTIC
target_type = /obj/item/organ/brain
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED|SURGERY_BONE_SAWED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/organ/pacify/get_default_radial_image()
return image(/atom/movable/screen/alert/status_effect/high::overlay_icon, /atom/movable/screen/alert/status_effect/high::overlay_state)
@@ -24,9 +25,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You begin to pacify [organ.owner]..."),
span_notice("[surgeon] begins to fix [organ.owner]'s brain."),
span_notice("[surgeon] begins to perform surgery on [organ.owner]'s brain."),
span_notice("You begin to pacify [FORMAT_ORGAN_OWNER(organ)]..."),
span_notice("[surgeon] begins to fix [FORMAT_ORGAN_OWNER(organ)]'s brain."),
span_notice("[surgeon] begins to perform surgery on [FORMAT_ORGAN_OWNER(organ)]'s brain."),
)
display_pain(organ.owner, "Your head pounds with unimaginable pain!")
@@ -34,9 +35,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You succeed in pacifying [organ.owner]."),
span_notice("[surgeon] successfully fixes [organ.owner]!"),
span_notice("[surgeon] completes the surgery on [organ.owner]'s brain."),
span_notice("You succeed in pacifying [FORMAT_ORGAN_OWNER(organ)]."),
span_notice("[surgeon] successfully fixes [FORMAT_ORGAN_OWNER(organ)]!"),
span_notice("[surgeon] completes the surgery on [FORMAT_ORGAN_OWNER(organ)]'s brain."),
)
display_pain(organ.owner, "Your head pounds... the concept of violence flashes in your head, and nearly makes you hurl!")
organ.gain_trauma(/datum/brain_trauma/severe/pacifism, TRAUMA_RESILIENCE_LOBOTOMY)
@@ -45,9 +46,9 @@
display_results(
surgeon,
organ.owner,
span_notice("You screw up, rewiring [organ.owner]'s brain the wrong way around..."),
span_notice("You screw up, rewiring [FORMAT_ORGAN_OWNER(organ)]'s brain the wrong way around..."),
span_warning("[surgeon] screws up, causing brain damage!"),
span_notice("[surgeon] completes the surgery on [organ.owner]'s brain."),
span_notice("[surgeon] completes the surgery on [FORMAT_ORGAN_OWNER(organ)]'s brain."),
)
display_pain(organ.owner, "Your head pounds, and it feels like it's getting worse!")
organ.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_LOBOTOMY)
@@ -116,7 +116,7 @@
success_sound = 'sound/effects/blob/attackblob.ogg'
failure_sound = 'sound/effects/blob/blobattack.ogg'
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_PLASTIC_APPLIED
any_surgery_states_blocked = SURGERY_PLASTIC_APPLIED|SURGERY_VESSELS_UNCLAMPED
/datum/surgery_operation/limb/add_plastic/get_default_radial_image()
return image(/obj/item/stack/sheet/plastic)
@@ -8,7 +8,7 @@
)
time = 3 SECONDS
preop_sound = 'sound/items/handling/surgery/hemostat1.ogg'
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_PRIORITY_NEXT_STEP
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_PRIORITY_NEXT_STEP | OPERATION_NO_PATIENT_REQUIRED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_ORGANS_CUT
/datum/surgery_operation/limb/repair_puncture/get_default_radial_image()
@@ -27,9 +27,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to realign the torn blood vessels in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to realign the torn blood vessels in [limb.owner]'s [limb.plaintext_zone] with [tool]."),
span_notice("[surgeon] begins to realign the torn blood vessels in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to realign the torn blood vessels in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to realign the torn blood vessels in [FORMAT_LIMB_OWNER(limb)] with [tool]."),
span_notice("[surgeon] begins to realign the torn blood vessels in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a horrible stabbing pain in your [limb.plaintext_zone]!")
@@ -42,9 +42,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You successfully realign the last of the torn blood vessels in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] successfully realigns the last of the torn blood vessels in [limb.owner]'s [limb.plaintext_zone] with [tool]!"),
span_notice("[surgeon] successfully realigns the last of the torn blood vessels in [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You successfully realign the last of the torn blood vessels in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] successfully realigns the last of the torn blood vessels in [FORMAT_LIMB_OWNER(limb)] with [tool]!"),
span_notice("[surgeon] successfully realigns the last of the torn blood vessels in [FORMAT_LIMB_OWNER(limb)]!"),
)
return
@@ -52,18 +52,18 @@
display_results(
surgeon,
limb.owner,
span_notice("You successfully realign some of the blood vessels in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] successfully realigns some of the blood vessels in [limb.owner]'s [limb.plaintext_zone] with [tool]!"),
span_notice("[surgeon] successfully realigns some of the blood vessels in [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You successfully realign some of the blood vessels in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] successfully realigns some of the blood vessels in [FORMAT_LIMB_OWNER(limb)] with [tool]!"),
span_notice("[surgeon] successfully realigns some of the blood vessels in [FORMAT_LIMB_OWNER(limb)]!"),
)
/datum/surgery_operation/limb/repair_puncture/on_failure(obj/item/bodypart/limb, mob/living/surgeon, tool, list/operation_args)
display_results(
surgeon,
limb.owner,
span_notice("You jerk apart some of the blood vessels in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] jerks apart some of the blood vessels in [limb.owner]'s [limb.plaintext_zone] with [tool]!"),
span_notice("[surgeon] jerks apart some of the blood vessels in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You jerk apart some of the blood vessels in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] jerks apart some of the blood vessels in [FORMAT_LIMB_OWNER(limb)] with [tool]!"),
span_notice("[surgeon] jerks apart some of the blood vessels in [FORMAT_LIMB_OWNER(limb)]."),
)
limb.receive_damage(rand(4, 8), wound_bonus = 10, sharpness = SHARP_EDGED, damage_source = tool)
@@ -79,7 +79,7 @@
)
time = 3.2 SECONDS
preop_sound = 'sound/items/handling/surgery/hemostat1.ogg'
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_PRIORITY_NEXT_STEP
operation_flags = OPERATION_AFFECTS_MOOD | OPERATION_PRIORITY_NEXT_STEP | OPERATION_NO_PATIENT_REQUIRED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_ORGANS_CUT
/datum/surgery_operation/limb/seal_veins/get_default_radial_image()
@@ -108,9 +108,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You begin to seal the realigned blood vessels in [limb.owner]'s [limb.plaintext_zone]..."),
span_notice("[surgeon] begins to seal the realigned blood vessels in [limb.owner]'s [limb.plaintext_zone] with [tool]."),
span_notice("[surgeon] begins to seal the realigned blood vessels in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("You begin to seal the realigned blood vessels in [FORMAT_LIMB_OWNER(limb)]..."),
span_notice("[surgeon] begins to seal the realigned blood vessels in [FORMAT_LIMB_OWNER(limb)] with [tool]."),
span_notice("[surgeon] begins to seal the realigned blood vessels in [FORMAT_LIMB_OWNER(limb)]."),
)
display_pain(limb.owner, "You feel a burning sensation in your [limb.plaintext_zone]!")
@@ -122,9 +122,9 @@
display_results(
surgeon,
limb.owner,
span_notice("You successfully seal the last of the ruptured blood vessels in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] successfully seals the last of the ruptured blood vessels in [limb.owner]'s [limb.plaintext_zone] with [tool]!"),
span_notice("[surgeon] successfully seals the last of the ruptured blood vessels in [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You successfully seal the last of the ruptured blood vessels in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] successfully seals the last of the ruptured blood vessels in [FORMAT_LIMB_OWNER(limb)] with [tool]!"),
span_notice("[surgeon] successfully seals the last of the ruptured blood vessels in [FORMAT_LIMB_OWNER(limb)]!"),
)
return
@@ -132,7 +132,7 @@
display_results(
surgeon,
limb.owner,
span_notice("You successfully seal some of the blood vessels in [limb.owner]'s [limb.plaintext_zone]."),
span_notice("[surgeon] successfully seals some of the blood vessels in [limb.owner]'s [limb.plaintext_zone] with [tool]!"),
span_notice("[surgeon] successfully seals some of the blood vessels in [limb.owner]'s [limb.plaintext_zone]!"),
span_notice("You successfully seal some of the blood vessels in [FORMAT_LIMB_OWNER(limb)]."),
span_notice("[surgeon] successfully seals some of the blood vessels in [FORMAT_LIMB_OWNER(limb)] with [tool]!"),
span_notice("[surgeon] successfully seals some of the blood vessels in [FORMAT_LIMB_OWNER(limb)]!"),
)
@@ -50,6 +50,13 @@
return FALSE
return TRUE
/datum/surgery_operation/limb/replace_limb/pre_preop(atom/movable/operating_on, mob/living/surgeon, obj/item/bodypart/tool, list/operation_args)
if(!length(tool.contents))
return TRUE
// Prevents quickly filling someone with high-tier organs by augmenting them with a pre-stuffed limb
to_chat(surgeon, span_warning("[tool] needs to be empty in order to be attached!"))
return FALSE
/datum/surgery_operation/limb/replace_limb/on_preop(obj/item/bodypart/limb, mob/living/surgeon, obj/item/bodypart/tool, list/operation_args)
// purposefully doesn't use plaintext zone for more context on what is being replaced with what
display_results(
@@ -11,7 +11,8 @@
operation_flags = OPERATION_LOCKED | OPERATION_NOTABLE
time = 20 SECONDS
target_type = /obj/item/organ/wings/moth
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED
all_surgery_states_required = SURGERY_SKIN_OPEN
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
required_organ_flag = NONE
/datum/surgery_operation/organ/fix_wings/get_default_radial_image()
@@ -9,7 +9,8 @@
)
time = 5 SECONDS
operation_flags = OPERATION_MORBID | OPERATION_LOCKED | OPERATION_NOTABLE
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_VESSELS_CLAMPED|SURGERY_BONE_SAWED
all_surgery_states_required = SURGERY_SKIN_OPEN|SURGERY_BONE_SAWED
any_surgery_states_blocked = SURGERY_VESSELS_UNCLAMPED
var/list/zombie_chems = list(
/datum/reagent/medicine/rezadone,
/datum/reagent/toxin/zombiepowder,
@@ -405,7 +405,7 @@
. = ..()
UnregisterSignal(organ_owner, COMSIG_LIVING_OPERATING_ON)
/obj/item/organ/cyberimp/brain/surgical_processor/proc/check_surgery(datum/source, mob/living/patient, list/operations)
/obj/item/organ/cyberimp/brain/surgical_processor/proc/check_surgery(datum/source, atom/movable/operating_on, list/operations)
SIGNAL_HANDLER
if(organ_flags & (ORGAN_FAILING|ORGAN_EMP))
+11 -1
View File
@@ -305,7 +305,7 @@
/obj/item/organ/proc/on_surgical_removal(mob/living/user, obj/item/bodypart/limb, obj/item/tool)
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ORGAN_SURGICALLY_REMOVED, user, limb.owner, limb.body_zone, tool)
RemoveElement(/datum/element/decal/blood, _color = limb.owner.get_bloodtype()?.get_color() || BLOOD_COLOR_RED)
RemoveElement(/datum/element/decal/blood, _color = get_organ_blood_color(limb) || BLOOD_COLOR_RED)
/**
* Proc that gets called when the organ is surgically inserted by someone. Seem familiar?
@@ -325,3 +325,13 @@
CRASH("[src]'s ([type]) swap_zone was called with invalid zone [target_zone]")
zone = target_zone
slot = valid_zones[zone]
/obj/item/organ/proc/get_organ_blood_color(obj/item/bodypart/limb)
var/blood_color = owner?.get_bloodtype()?.get_color()
if (!limb)
return blood_color
if (!blood_color)
blood_color = limb.owner?.get_bloodtype()?.get_color()
if (!blood_color && length(limb.blood_dna_info))
blood_color = get_color_from_blood_list(limb.blood_dna_info)
return blood_color
+1 -1
View File
@@ -401,7 +401,7 @@
if(downloaded)
. += mutable_appearance(src.icon, "+downloaded")
/obj/item/surgical_processor/proc/check_surgery(datum/source, mob/living/patient, list/operations)
/obj/item/surgical_processor/proc/check_surgery(datum/source, atom/movable/operating_on, list/operations)
SIGNAL_HANDLER
operations |= loaded_surgeries