Fixes surgeries runtiming constantly when having the surgery initator open, fixes some surgeries missing sounds (#81307)

## About The Pull Request

Fixes #79318 

- See the issue for more information. I fixed the runtimes as expected,
and then removed `SURGERY_REQUIRE_LIMB` from some surgeries which don't
actually require a limb, such as implant removal, dissection, and living
revival. I could've easily missed some, and as a result some surgeries
are lost to the void and unselectable, but from what I could tell in
testing it seems... fine.

- Adds `SHOULD_CALL_PARENT` to surgery `can_start`. Cleans up some
surgery `can_start` overrides.

- Adds missing sounds to puncture repair surgery. 

## Changelog

🆑 Melbert
fix: Fixed Puncture Repair surgery not having surgical sounds
fix: Fixed Surgery Initiator potentially showing invalid surgeries 
/🆑
This commit is contained in:
MrMelbert
2024-02-08 13:37:02 +01:00
committed by GitHub
parent ab69286f9c
commit a40986353d
21 changed files with 102 additions and 113 deletions
+22 -27
View File
@@ -81,32 +81,31 @@
/datum/component/surgery_initiator/proc/get_available_surgeries(mob/user, mob/living/target)
var/list/available_surgeries = list()
var/mob/living/carbon/carbon_target
var/obj/item/bodypart/affecting
if (iscarbon(target))
carbon_target = target
affecting = carbon_target.get_bodypart(check_zone(user.zone_selected))
var/obj/item/bodypart/affecting = target.get_bodypart(check_zone(user.zone_selected))
for(var/datum/surgery/surgery as anything in GLOB.surgeries_list)
if(!surgery.possible_locs.Find(user.zone_selected))
continue
if(affecting)
if(!(surgery.surgery_flags & SURGERY_REQUIRE_LIMB))
if(!is_type_in_list(target, surgery.target_mobtypes))
continue
if(isnull(affecting))
if(surgery.surgery_flags & SURGERY_REQUIRE_LIMB)
continue
else
if(surgery.requires_bodypart_type && !(affecting.bodytype & surgery.requires_bodypart_type))
continue
if(surgery.targetable_wound && !affecting.get_wound_type(surgery.targetable_wound))
continue
if((surgery.surgery_flags & SURGERY_REQUIRES_REAL_LIMB) && (affecting.bodypart_flags & BODYPART_PSEUDOPART))
continue
else if(carbon_target && (surgery.surgery_flags & SURGERY_REQUIRE_LIMB)) //mob with no limb in surgery zone when we need a limb
continue
if(IS_IN_INVALID_SURGICAL_POSITION(target, surgery))
continue
if(!surgery.can_start(user, target))
continue
for(var/path in surgery.target_mobtypes)
if(istype(target, path))
available_surgeries += surgery
break
available_surgeries += surgery
return available_surgeries
@@ -284,24 +283,20 @@
target.balloon_alert(user, "can't start the surgery!")
return
var/obj/item/bodypart/affecting_limb
var/selected_zone = user.zone_selected
var/obj/item/bodypart/affecting_limb = target.get_bodypart(check_zone(selected_zone))
if (iscarbon(target))
var/mob/living/carbon/carbon_target = target
affecting_limb = carbon_target.get_bodypart(check_zone(selected_zone))
if ((surgery.surgery_flags & SURGERY_REQUIRE_LIMB) == isnull(affecting_limb))
if (surgery.surgery_flags & SURGERY_REQUIRE_LIMB)
target.balloon_alert(user, "patient has no [parse_zone(selected_zone)]!")
else
target.balloon_alert(user, "patient has \a [parse_zone(selected_zone)]!")
if ((surgery.surgery_flags & SURGERY_REQUIRE_LIMB) && isnull(affecting_limb))
target.balloon_alert(user, "patient has no [parse_zone(selected_zone)]!")
return
if (!isnull(affecting_limb) && surgery.requires_bodypart_type && !(affecting_limb.bodytype & surgery.requires_bodypart_type))
target.balloon_alert(user, "not the right type of limb!")
return
if (!isnull(affecting_limb))
if(surgery.requires_bodypart_type && !(affecting_limb.bodytype & surgery.requires_bodypart_type))
target.balloon_alert(user, "not the right type of limb!")
return
if(surgery.targetable_wound && !affecting_limb.get_wound_type(surgery.targetable_wound))
target.balloon_alert(user, "no wound to operate on!")
return
if (IS_IN_INVALID_SURGICAL_POSITION(target, surgery))
target.balloon_alert(user, "patient is not lying down!")
@@ -14,10 +14,12 @@
/datum/surgery/organ_extraction/can_start(mob/user, mob/living/carbon/target)
if(!ishuman(user))
return FALSE
var/mob/living/carbon/human/H = user
if(H.dna.species.id == SPECIES_ABDUCTOR)
if(!..())
return FALSE
if(isabductor(user))
return TRUE
for(var/obj/item/implant/abductor/A in H.implants)
var/mob/living/non_abductor = user
if(locate(/obj/item/implant/abductor) in non_abductor.implants)
return TRUE
return FALSE
+2 -1
View File
@@ -10,7 +10,8 @@
)
/datum/surgery/autopsy/can_start(mob/user, mob/living/patient)
. = ..()
if(!..())
return FALSE
if(patient.stat != DEAD)
return FALSE
if(HAS_TRAIT_FROM(patient, TRAIT_DISSECTED, AUTOPSY_TRAIT))
-21
View File
@@ -20,13 +20,6 @@
/datum/surgery_step/close,
)
/datum/surgery/repair_bone_hairline/can_start(mob/living/user, mob/living/carbon/target)
. = ..()
if(.)
var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
return(targeted_bodypart.get_wound_type(targetable_wound))
///// Repair Compound Fracture (Critical)
/datum/surgery/repair_bone_compound
name = "Repair Compound Fracture"
@@ -49,12 +42,6 @@
/datum/surgery_step/close,
)
/datum/surgery/repair_bone_compound/can_start(mob/living/user, mob/living/carbon/target)
. = ..()
if(.)
var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
return(targeted_bodypart.get_wound_type(targetable_wound))
//SURGERY STEPS
///// Repair Hairline Fracture (Severe)
@@ -217,14 +204,6 @@
/datum/surgery_step/repair_skull
)
/datum/surgery/cranial_reconstruction/can_start(mob/living/user, mob/living/carbon/target)
. = ..()
if(!.)
return FALSE
var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
return !isnull(targeted_bodypart.get_wound_type(targetable_wound))
/datum/surgery_step/clamp_bleeders/discard_skull_debris
name = "discard skull debris (hemostat)"
implements = list(
+1 -4
View File
@@ -24,10 +24,7 @@
failure_sound = 'sound/surgery/organ2.ogg'
/datum/surgery/brain_surgery/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/internal/brain/target_brain = target.get_organ_slot(ORGAN_SLOT_BRAIN)
if(!target_brain)
return FALSE
return TRUE
return target.get_organ_slot(ORGAN_SLOT_BRAIN) && ..()
/datum/surgery_step/fix_brain/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
display_results(
+8 -6
View File
@@ -20,12 +20,14 @@
)
/datum/surgery/debride/can_start(mob/living/user, mob/living/carbon/target)
if(!istype(target))
return FALSE
if(..())
var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
var/datum/wound/burn/flesh/burn_wound = targeted_bodypart.get_wound_type(targetable_wound)
return(burn_wound && burn_wound.infestation > 0)
. = ..()
if(!.)
return .
var/datum/wound/burn/flesh/burn_wound = target.get_bodypart(user.zone_selected).get_wound_type(targetable_wound)
// Should be guaranteed to have the wound by this point
ASSERT(burn_wound, "[type] on [target] has no burn wound when it should have been guaranteed to have one by can_start")
return burn_wound.infestation > 0
//SURGERY STEPS
+1 -3
View File
@@ -16,9 +16,7 @@
)
/datum/surgery/core_removal/can_start(mob/user, mob/living/target)
if(target.stat == DEAD)
return TRUE
return FALSE
return target.stat == DEAD && ..()
//extract brain
/datum/surgery_step/extract_core
+3 -4
View File
@@ -14,10 +14,9 @@
/datum/surgery/coronary_bypass/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/internal/heart/target_heart = target.get_organ_slot(ORGAN_SLOT_HEART)
if(target_heart)
if(target_heart.damage > 60 && !target_heart.operated)
return TRUE
return FALSE
if(isnull(target_heart) || target_heart.damage < 60 || target_heart.operated)
return FALSE
return ..()
//an incision but with greater bleed, and a 90% base success chance
+1 -4
View File
@@ -23,10 +23,7 @@
time = 64
/datum/surgery/ear_surgery/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/internal/ears/target_ears = target.get_organ_slot(ORGAN_SLOT_EARS)
if(!target_ears)
return FALSE
return TRUE
return target.get_organ_slot(ORGAN_SLOT_EARS) && ..()
/datum/surgery_step/fix_ears/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
display_results(
@@ -10,16 +10,19 @@
/datum/surgery_step/experimental_dissection,
/datum/surgery_step/close,
)
surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB | SURGERY_MORBID_CURIOSITY
surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_MORBID_CURIOSITY
possible_locs = list(BODY_ZONE_CHEST)
target_mobtypes = list(/mob/living)
/datum/surgery/advanced/experimental_dissection/can_start(mob/user, mob/living/target)
. = ..()
if(!.)
return .
if(HAS_TRAIT_FROM(target, TRAIT_DISSECTED, EXPERIMENTAL_SURGERY_TRAIT))
return FALSE
if(target.stat != DEAD)
return FALSE
return .
/datum/surgery_step/experimental_dissection
name = "dissection"
@@ -44,8 +47,7 @@
var/obj/item/research_notes/hand_dossier = user.get_inactive_held_item()
hand_dossier.merge(the_dossier)
var/obj/item/bodypart/target_chest = target.get_bodypart(BODY_ZONE_CHEST)
target.apply_damage(80, BRUTE, target_chest)
target.apply_damage(80, BRUTE, BODY_ZONE_CHEST)
ADD_TRAIT(target, TRAIT_DISSECTED, EXPERIMENTAL_SURGERY_TRAIT)
return ..()
@@ -61,8 +63,7 @@
var/obj/item/research_notes/hand_dossier = user.get_inactive_held_item()
hand_dossier.merge(the_dossier)
var/obj/item/bodypart/L = target.get_bodypart(BODY_ZONE_CHEST)
target.apply_damage(80, BRUTE, L)
target.apply_damage(80, BRUTE, BODY_ZONE_CHEST)
return TRUE
///Calculates how many research points dissecting 'target' is worth.
+1 -2
View File
@@ -21,8 +21,7 @@
time = 64
/datum/surgery/eye_surgery/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/internal/eyes/target_eyes = target.get_organ_slot(ORGAN_SLOT_EYES)
return !isnull(target_eyes)
return target.get_organ_slot(ORGAN_SLOT_EYES) && ..()
/datum/surgery_step/fix_eyes/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
display_results(
+3 -5
View File
@@ -16,10 +16,9 @@
/datum/surgery/gastrectomy/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/internal/stomach/target_stomach = target.get_organ_slot(ORGAN_SLOT_STOMACH)
if(target_stomach)
if(target_stomach.damage > 50 && !target_stomach.operated)
return TRUE
return FALSE
if(isnull(target_stomach) || target_stomach.damage < 50 || target_stomach.operated)
return FALSE
return ..()
////Gastrectomy, because we truly needed a way to repair stomachs.
//95% chance of success to be consistent with most organ-repairing surgeries.
@@ -72,4 +71,3 @@
span_warning("[user] cuts the wrong part of [target]'s stomach!"),
)
display_pain(target, "Your stomach throbs with pain; it's not getting any better!")
+6 -2
View File
@@ -2,7 +2,7 @@
target_mobtypes = list(/mob/living)
requires_bodypart_type = NONE
replaced_by = /datum/surgery
surgery_flags = SURGERY_IGNORE_CLOTHES | SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB
surgery_flags = SURGERY_IGNORE_CLOTHES | SURGERY_REQUIRE_RESTING
possible_locs = list(BODY_ZONE_CHEST)
steps = list(
/datum/surgery_step/incise,
@@ -18,8 +18,11 @@
/datum/surgery/healing/can_start(mob/user, mob/living/patient)
. = ..()
if(!.)
return .
if(!(patient.mob_biotypes & (MOB_ORGANIC|MOB_HUMANOID)))
return FALSE
return .
/datum/surgery/healing/New(surgery_target, surgery_location, surgery_bodypart)
..()
@@ -27,7 +30,8 @@
steps = list(
/datum/surgery_step/incise/nobleed,
healing_step_type, //hehe cheeky
/datum/surgery_step/close)
/datum/surgery_step/close,
)
/datum/surgery_step/heal
name = "repair body (hemostat)"
+3 -4
View File
@@ -15,10 +15,9 @@
/datum/surgery/hepatectomy/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/internal/liver/target_liver = target.get_organ_slot(ORGAN_SLOT_LIVER)
if(target_liver)
if(target_liver.damage > 50 && !target_liver.operated)
return TRUE
return FALSE
if(isnull(target_liver) || target_liver.damage < 50 || target_liver.operated)
return FALSE
return ..()
////hepatectomy, removes damaged parts of the liver so that the liver may regenerate properly
//95% chance of success, not 100 because organs are delicate
+2
View File
@@ -2,6 +2,7 @@
name = "Implant Removal"
target_mobtypes = list(/mob/living)
possible_locs = list(BODY_ZONE_CHEST)
surgery_flags = SURGERY_REQUIRE_RESTING
steps = list(
/datum/surgery_step/incise,
/datum/surgery_step/clamp_bleeders,
@@ -83,6 +84,7 @@
name = "Implant Removal"
requires_bodypart_type = BODYTYPE_ROBOTIC
target_mobtypes = list(/mob/living/carbon/human) // Simpler mobs don't have bodypart types
surgery_flags = parent_type::surgery_flags | SURGERY_REQUIRE_LIMB
steps = list(
/datum/surgery_step/mechanic_open,
/datum/surgery_step/open_hatch,
+9 -3
View File
@@ -10,9 +10,9 @@
)
/datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target)
if(HAS_TRAIT(target, TRAIT_FAT) && target.nutrition >= NUTRITION_LEVEL_WELL_FED)
return TRUE
return FALSE
if(!HAS_TRAIT(target, TRAIT_FAT) || target.nutrition >= NUTRITION_LEVEL_WELL_FED)
return FALSE
return ..()
//cut fat
@@ -24,6 +24,10 @@
/obj/item/hatchet = 35,
/obj/item/knife/butcher = 25)
time = 64
preop_sound = list(
/obj/item/circular_saw = 'sound/surgery/saw.ogg',
/obj/item = 'sound/surgery/scalpel1.ogg',
)
/datum/surgery_step/cut_fat/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
user.visible_message(span_notice("[user] begins to cut away [target]'s excess fat."), span_notice("You begin to cut away [target]'s excess fat..."))
@@ -55,6 +59,8 @@
TOOL_SCREWDRIVER = 45,
TOOL_WIRECUTTER = 35)
time = 32
preop_sound = 'sound/surgery/retractor1.ogg'
success_sound = 'sound/surgery/retractor2.ogg'
/datum/surgery_step/remove_fat/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
display_results(
+3 -4
View File
@@ -13,10 +13,9 @@
/datum/surgery/lobectomy/can_start(mob/user, mob/living/carbon/target)
var/obj/item/organ/internal/lungs/target_lungs = target.get_organ_slot(ORGAN_SLOT_LUNGS)
if(target_lungs)
if(target_lungs.damage > 60 && !target_lungs.operated)
return TRUE
return FALSE
if(isnull(target_lungs) || target_lungs.damage < 60 || target_lungs.operated)
return FALSE
return ..()
//lobectomy, removes the most damaged lung lobe with a 95% base success chance
@@ -17,6 +17,8 @@
)
/datum/surgery/prosthetic_replacement/can_start(mob/user, mob/living/carbon/target)
if(!..())
return FALSE
if(!iscarbon(target))
return FALSE
var/mob/living/carbon/carbon_target = target
+9 -6
View File
@@ -27,13 +27,13 @@
)
/datum/surgery/repair_puncture/can_start(mob/living/user, mob/living/carbon/target)
if(!istype(target))
return FALSE
. = ..()
if(.)
var/obj/item/bodypart/targeted_bodypart = target.get_bodypart(user.zone_selected)
var/datum/wound/burn/flesh/pierce_wound = targeted_bodypart.get_wound_type(targetable_wound)
return(pierce_wound && pierce_wound.blood_flow > 0)
if(!.)
return .
var/datum/wound/pierce/bleed/pierce_wound = target.get_bodypart(user.zone_selected).get_wound_type(targetable_wound)
ASSERT(pierce_wound, "[type] on [target] has no pierce wound when it should have been guaranteed to have one by can_start")
return pierce_wound.blood_flow > 0
//SURGERY STEPS
@@ -45,6 +45,7 @@
TOOL_SCALPEL = 85,
TOOL_WIRECUTTER = 40)
time = 3 SECONDS
preop_sound = 'sound/surgery/hemostat1.ogg'
/datum/surgery_step/repair_innards/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
var/datum/wound/pierce/bleed/pierce_wound = surgery.operated_wound
@@ -104,6 +105,8 @@
TOOL_WELDER = 70,
/obj/item = 30)
time = 4 SECONDS
preop_sound = 'sound/surgery/cautery1.ogg'
success_sound = 'sound/surgery/cautery2.ogg'
/datum/surgery_step/seal_veins/tool_check(mob/user, obj/item/tool)
if(implement_type == TOOL_WELDER || implement_type == /obj/item)
+2 -1
View File
@@ -5,7 +5,7 @@
requires_bodypart_type = NONE
possible_locs = list(BODY_ZONE_CHEST)
target_mobtypes = list(/mob/living)
surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_REQUIRE_LIMB | SURGERY_MORBID_CURIOSITY
surgery_flags = SURGERY_REQUIRE_RESTING | SURGERY_MORBID_CURIOSITY
steps = list(
/datum/surgery_step/incise,
/datum/surgery_step/retract_skin,
@@ -123,6 +123,7 @@
/datum/surgery/revival/carbon
possible_locs = list(BODY_ZONE_HEAD)
target_mobtypes = list(/mob/living/carbon)
surgery_flags = parent_type::surgery_flags | SURGERY_REQUIRE_LIMB
/datum/surgery/revival/carbon/is_valid_target(mob/living/carbon/patient)
var/obj/item/organ/internal/brain/target_brain = patient.get_organ_slot(ORGAN_SLOT_BRAIN)
+13 -8
View File
@@ -20,17 +20,19 @@
var/list/possible_locs = list()
///Mobs that are valid to have surgery performed on them.
var/list/target_mobtypes = list(/mob/living/carbon/human)
///The person the surgery is being performed on. Funnily enough, it isn't always a carbon.
var/mob/living/carbon/target
///The specific bodypart being operated on.
var/obj/item/bodypart/operated_bodypart
///The wound datum that is being operated on.
var/datum/wound/operated_wound
///Types of wounds this surgery can target.
var/datum/wound/targetable_wound
///The person the surgery is being performed on. Funnily enough, it isn't always a carbon.
VAR_FINAL/mob/living/carbon/target
///The specific bodypart being operated on.
VAR_FINAL/obj/item/bodypart/operated_bodypart
///The wound datum that is being operated on.
VAR_FINAL/datum/wound/operated_wound
///Types of wounds this surgery can target.
var/targetable_wound
///The types of bodyparts that this surgery can have performed on it. Used for augmented surgeries.
var/requires_bodypart_type = BODYTYPE_ORGANIC
///The speed modifier given to the surgery through external means.
var/speed_modifier = 0
///Whether the surgery requires research to do. You need to add a design if using this!
@@ -69,6 +71,8 @@
/datum/surgery/proc/can_start(mob/user, mob/living/patient) //FALSE to not show in list
SHOULD_CALL_PARENT(TRUE)
. = TRUE
if(replaced_by == /datum/surgery)
return FALSE
@@ -102,6 +106,7 @@
return FALSE
if(type in opcomputer.advanced_surgeries)
return TRUE
return .
/datum/surgery/proc/next_step(mob/living/user, modifiers)
if(location != user.zone_selected)