From e2e15d557944b2a5ca062cf7633f7f4cfa9566e8 Mon Sep 17 00:00:00 2001
From: Luc <89928798+lewcc@users.noreply.github.com>
Date: Sun, 25 Sep 2022 12:47:09 -0400
Subject: [PATCH] [GBP: NO UPDATE] Fixes xeno surgery (#19119)
* Fixes optable
* Xeno surgery works again, but at what cost?
---
code/__DEFINES/mobs.dm | 2 +-
code/game/machinery/OpTable.dm | 12 +-
code/game/machinery/computer/Operating.dm | 14 +-
code/game/objects/items.dm | 2 +-
.../hallucinations/effects/moderate.dm | 2 +-
code/modules/surgery/organs/pain.dm | 8 +-
code/modules/surgery/organs_internal.dm | 168 ++++++++++++++----
7 files changed, 161 insertions(+), 47 deletions(-)
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 84b25c97d17..bb4e7e4d30c 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -273,7 +273,7 @@
#define isnewplayer(A) (istype((A), /mob/new_player))
#define isorgan(A) (istype((A), /obj/item/organ/external))
-#define hasorgans(A) (ishuman(A))
+#define hasorgans(A) (iscarbon(A))
#define is_admin(user) (check_rights(R_ADMIN, 0, (user)) != 0)
diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm
index 16c001bce66..ff7c8c65297 100644
--- a/code/game/machinery/OpTable.dm
+++ b/code/game/machinery/OpTable.dm
@@ -8,7 +8,7 @@
use_power = IDLE_POWER_USE
idle_power_usage = 1
active_power_usage = 5
- var/mob/living/carbon/human/patient
+ var/mob/living/carbon/patient
var/obj/machinery/computer/operating/computer
buckle_lying = -1
var/no_icon_updates = FALSE //set this to TRUE if you don't want the icons ever changing
@@ -64,13 +64,13 @@
* Updates the `patient` var to be the mob occupying the table
*/
/obj/machinery/optable/proc/update_patient()
- var/mob/living/carbon/human/M = locate(/mob/living/carbon/human, loc)
- if(M && IS_HORIZONTAL(M))
- patient = M
+ var/mob/living/carbon/C = locate(/mob/living/carbon, loc)
+ if(C && IS_HORIZONTAL(C))
+ patient = C
else
patient = null
if(!no_icon_updates)
- if(patient && patient.pulse)
+ if(C && C.pulse)
icon_state = "table2-active"
else
icon_state = "table2-idle"
@@ -107,7 +107,7 @@
set name = "Climb On Table"
set category = "Object"
set src in oview(1)
- if(usr.stat || !ishuman(usr) || usr.restrained() || !check_table())
+ if(usr.stat || !iscarbon(usr) || usr.restrained() || !check_table())
return
take_patient(usr, usr)
diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm
index fa87540701d..1fae66002c4 100644
--- a/code/game/machinery/computer/Operating.dm
+++ b/code/game/machinery/computer/Operating.dm
@@ -64,7 +64,7 @@
/obj/machinery/computer/operating/ui_data(mob/user)
var/list/data = list()
- var/mob/living/carbon/human/occupant
+ var/mob/living/carbon/occupant
if(table)
occupant = table.patient
data["hasOccupant"] = occupant ? 1 : 0
@@ -111,11 +111,12 @@
occupantData["btFaren"] = ((occupant.bodytemperature - T0C) * (9.0/5.0))+ 32
if(ishuman(occupant) && !(NO_BLOOD in occupant.dna.species.species_traits))
+ var/mob/living/carbon/human/H = occupant
occupantData["pulse"] = occupant.get_pulse(GETPULSE_TOOL)
occupantData["hasBlood"] = 1
occupantData["bloodLevel"] = round(occupant.blood_volume)
- occupantData["bloodMax"] = occupant.max_blood
- occupantData["bloodPercent"] = round(100*(occupant.blood_volume/occupant.max_blood), 0.01) //copy pasta ends here
+ occupantData["bloodMax"] = H.max_blood
+ occupantData["bloodPercent"] = round(100*(occupant.blood_volume/H.max_blood), 0.01) //copy pasta ends here
occupantData["bloodType"] = occupant.dna.blood_type
if(length(occupant.surgeries))
@@ -198,7 +199,12 @@
if(isNewPatient)
atom_say("New patient detected, loading stats")
- atom_say("[table.patient], [table.patient.dna.blood_type] blood, [patientStatus]")
+ var/blood_type_msg
+ if(ishuman(table.patient))
+ blood_type_msg = table.patient.dna.blood_type
+ else
+ blood_type_msg = "\[ERROR: UNKNOWN\]"
+ atom_say("[table.patient], [blood_type_msg] blood, [patientStatus]")
SStgui.update_uis(src)
patientStatusHolder = table.patient.stat
currentPatient = table.patient
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 6891cf3b2f1..80b5a32c17c 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -263,7 +263,7 @@ GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons
/obj/item/attack_hand(mob/user as mob, pickupfireoverride = FALSE)
if(!user) return 0
- if(hasorgans(user))
+ if(ishuman(user))
var/mob/living/carbon/human/H = user
var/obj/item/organ/external/temp = H.bodyparts_by_name["r_hand"]
if(user.hand)
diff --git a/code/modules/hallucinations/effects/moderate.dm b/code/modules/hallucinations/effects/moderate.dm
index b48517304ee..b4569d1189f 100644
--- a/code/modules/hallucinations/effects/moderate.dm
+++ b/code/modules/hallucinations/effects/moderate.dm
@@ -91,7 +91,7 @@
/obj/effect/hallucination/fake_item/attack_hand(mob/living/user)
if(user != target)
return
- if(hasorgans(user))
+ if(ishuman(user))
var/mob/living/carbon/human/H = user
var/obj/item/organ/external/temp = H.bodyparts_by_name["r_hand"]
if(user.hand)
diff --git a/code/modules/surgery/organs/pain.dm b/code/modules/surgery/organs/pain.dm
index f78cfb2f8f9..007afbed201 100644
--- a/code/modules/surgery/organs/pain.dm
+++ b/code/modules/surgery/organs/pain.dm
@@ -1,4 +1,4 @@
-/mob/living/carbon/human
+/mob/living/carbon
var/last_pain_message = ""
var/next_pain_time = 0
@@ -7,7 +7,7 @@
*
* Returns TRUE if the mob can feel pain, FALSE otherwise
*/
-/mob/living/carbon/human/proc/can_feel_pain()
+/mob/living/carbon/proc/can_feel_pain()
if(stat >= UNCONSCIOUS)
return FALSE
if(reagents.has_reagent("morphine"))
@@ -21,7 +21,7 @@
// partname is the name of a body part
// amount is a num from 1 to 100
-/mob/living/carbon/human/proc/pain(partname, amount)
+/mob/living/carbon/proc/pain(partname, amount)
if(!can_feel_pain())
return
if(world.time < next_pain_time)
@@ -41,7 +41,7 @@
// message is the custom message to be displayed
-/mob/living/carbon/human/proc/custom_pain(message)
+/mob/living/carbon/proc/custom_pain(message)
if(!can_feel_pain())
return
diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm
index f7de06c23e8..b92cc9c6a5a 100644
--- a/code/modules/surgery/organs_internal.dm
+++ b/code/modules/surgery/organs_internal.dm
@@ -50,9 +50,18 @@
/datum/surgery/organ_manipulation/alien
name = "Alien Organ Manipulation"
- possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_PRECISE_GROIN, BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH)
+ requires_bodypart = FALSE // xenos just don't have "bodyparts"
+ possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD, BODY_ZONE_PRECISE_GROIN, BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)
target_mobtypes = list(/mob/living/carbon/alien/humanoid)
- steps = list(/datum/surgery_step/saw_carapace,/datum/surgery_step/cut_carapace, /datum/surgery_step/retract_carapace,/datum/surgery_step/proxy/manipulate_organs,)
+ steps = list(
+ /datum/surgery_step/saw_carapace,
+ /datum/surgery_step/cut_carapace,
+ /datum/surgery_step/retract_carapace,
+ /datum/surgery_step/proxy/manipulate_organs/alien,
+ /datum/surgery_step/generic/seal_carapace
+ )
+
+
/datum/surgery/organ_manipulation/can_start(mob/user, mob/living/carbon/target)
@@ -122,11 +131,49 @@
/datum/surgery/intermediate/bleeding
)
+// have to redefine all of these because xenos don't technically have bodyparts.
+/datum/surgery/intermediate/manipulate/extract/xeno
+ requires_bodypart = FALSE
+
+/datum/surgery/intermediate/manipulate/implant/xeno
+ requires_bodypart = FALSE
+
+/datum/surgery/intermediate/manipulate/mend/xeno
+ requires_bodypart = FALSE
+
+/datum/surgery/intermediate/manipulate/clean/xeno
+ requires_bodypart = FALSE
+
+/datum/surgery_step/proxy/manipulate_organs/alien
+ name = "Manipulate Organs Xeno (proxy)"
+ branches = list(
+ /datum/surgery/intermediate/manipulate/extract/xeno,
+ /datum/surgery/intermediate/manipulate/implant/xeno,
+ /datum/surgery/intermediate/manipulate/mend/xeno,
+ /datum/surgery/intermediate/manipulate/clean/xeno
+ )
+
// Internal surgeries.
/datum/surgery_step/internal
can_infect = TRUE
blood_level = SURGERY_BLOODSPREAD_HANDS
+/**
+ * Get an internal list of organs for a zone (or an external organ).
+ *
+ * Helper function since we end up calling this a ton to work with carbons
+ */
+/datum/surgery_step/internal/proc/get_organ_list(target_zone, mob/living/carbon/target, obj/item/organ/external/affected)
+ var/list/organs
+
+ if(affected && istype(affected))
+ organs = affected.internal_organs
+ else
+ organs = target.get_organs_zone(target_zone)
+
+ return organs
+
+
/datum/surgery_step/internal/manipulate_organs/mend
name = "mend organs"
allowed_tools = list(
@@ -146,7 +193,7 @@
return tool_name
-/datum/surgery_step/internal/manipulate_organs/mend/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery)
+/datum/surgery_step/internal/manipulate_organs/mend/begin_step(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
var/tool_name = get_tool_name(tool)
var/obj/item/organ/external/affected = target.get_organ(target_zone)
@@ -157,8 +204,9 @@
var/any_organs_damaged = FALSE
+ var/list/organs = get_organ_list(target_zone, target, affected)
- for(var/obj/item/organ/internal/I in affected.internal_organs)
+ for(var/obj/item/organ/internal/I in organs)
if(I && I.damage)
any_organs_damaged = TRUE
if(!I.is_robotic() && !istype(tool, /obj/item/stack/nanopaste))
@@ -177,8 +225,8 @@
return SURGERY_BEGINSTEP_SKIP
if(affected)
- var/mob/living/carbon/human/H = target
- H.custom_pain("The pain in your [affected.name] is living hell!")
+ var/mob/living/carbon/C = target
+ C.custom_pain("The pain in your [affected.name] is living hell!")
return ..()
@@ -188,7 +236,9 @@
if(!hasorgans(target))
return SURGERY_STEP_INCOMPLETE
- for(var/obj/item/organ/internal/I in affected.internal_organs)
+ var/list/organs = get_organ_list(target_zone, target, affected)
+
+ for(var/obj/item/organ/internal/I in organs)
if(I)
I.surgeryize()
if(I && I.damage)
@@ -209,11 +259,12 @@
/datum/surgery_step/internal/manipulate_organs/mend/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery)
if(!hasorgans(target))
return SURGERY_STEP_INCOMPLETE
+
var/obj/item/organ/external/affected = target.get_organ(target_zone)
user.visible_message(
- " [user]'s hand slips, getting mess and tearing the inside of [target]'s [affected.name] with [tool]!",
- " Your hand slips, getting mess and tearing the inside of [target]'s [affected.name] with [tool]!"
+ " [user]'s hand slips, getting messy and tearing the inside of [target]'s [parse_zone(target_zone)] with [tool]!",
+ " Your hand slips, getting messy and tearing the inside of [target]'s [parse_zone(target_zone)] with [tool]!"
)
var/dam_amt = 2
@@ -224,9 +275,12 @@
else if(istype(tool, /obj/item/stack/medical/bruise_pack) || istype(tool, /obj/item/stack/nanopaste))
dam_amt = 5
target.adjustToxLoss(10)
- affected.receive_damage(5)
+ if(affected)
+ affected.receive_damage(5)
- for(var/obj/item/organ/internal/I in affected.internal_organs)
+ var/list/organs = get_organ_list(target_zone, target, affected)
+
+ for(var/obj/item/organ/internal/I in organs)
if(I && I.damage && !(I.tough))
I.receive_damage(dam_amt,0)
@@ -421,26 +475,27 @@
var/obj/item/reagent_containers/C = tool
- var/mob/living/carbon/human/H = target
- var/obj/item/organ/external/affected = H.get_organ(user.zone_selected)
+ var/obj/item/organ/external/affected = target.get_organ(user.zone_selected)
- for(var/obj/item/organ/internal/I in affected.internal_organs)
- if(I)
- if(C.reagents.total_volume <= 0) //end_step handles if there is not enough reagent
- user.visible_message(
- "[user] notices [tool] is empty.",
- "You notice [tool] is empty."
- )
- return SURGERY_BEGINSTEP_SKIP
+ var/list/organs = get_organ_list(target_zone, target, affected)
- var/msg = "[user] starts pouring some of [tool] over [target]'s [I.name]."
- var/self_msg = "You start pouring some of [tool] over [target]'s [I.name]."
- if(istype(C, /obj/item/reagent_containers/syringe))
- msg = "[user] begins injecting [tool] into [target]'s [I.name]."
- self_msg = "You begin injecting [tool] into [target]'s [I.name]."
- user.visible_message(msg, self_msg)
- if(H && affected)
- H.custom_pain("Something burns horribly in your [affected.name]!")
+ for(var/obj/item/organ/internal/I in organs)
+ if(!I)
+ continue
+ if(C.reagents.total_volume <= 0) //end_step handles if there is not enough reagent
+ user.visible_message(
+ "[user] notices [tool] is empty.",
+ "You notice [tool] is empty."
+ )
+ return SURGERY_BEGINSTEP_SKIP
+
+ var/msg = "[user] starts pouring some of [tool] over [target]'s [I.name]."
+ var/self_msg = "You start pouring some of [tool] over [target]'s [I.name]."
+ if(istype(C, /obj/item/reagent_containers/syringe))
+ msg = "[user] begins injecting [tool] into [target]'s [I.name]."
+ self_msg = "You begin injecting [tool] into [target]'s [I.name]."
+ user.visible_message(msg, self_msg)
+ target.custom_pain("Something burns horribly in your [parse_zone(target_zone)]!")
return ..()
@@ -452,6 +507,8 @@
var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ var/list/organs = get_organ_list(target_zone, target, affected)
+
var/obj/item/reagent_containers/C = tool
var/datum/reagents/R = C.reagents
var/ethanol = 0 //how much alcohol is in the thing
@@ -467,7 +524,7 @@
spaceacillin = R.get_reagent_amount("spaceacillin")
- for(var/obj/item/organ/internal/I in affected.internal_organs)
+ for(var/obj/item/organ/internal/I in organs)
if(!I) // if you have a null organ I wish you the best
continue
if(I.germ_level < INFECTION_LEVEL_ONE / 2 && !(I.status & ORGAN_DEAD)) // not dead, don't need to inject mito either
@@ -735,4 +792,55 @@
user.visible_message(msg, self_msg)
return SURGERY_STEP_RETRY
+// redefine cauterize for every step because of course it relies on get_organ()
+/datum/surgery_step/generic/seal_carapace/
+ name = "seal carapace"
+
+ allowed_tools = list(
+ /obj/item/scalpel/laser = 100,
+ TOOL_CAUTERY = 100,
+ /obj/item/clothing/mask/cigarette = 90,
+ /obj/item/lighter = 60,
+ TOOL_WELDER = 30
+ )
+
+ time = 2.4 SECONDS
+
+/datum/surgery_step/generic/seal_carapace/proc/zone_name(target_zone)
+ var/zone = target_zone
+
+ if(target_zone == BODY_ZONE_CHEST)
+ zone = "torso"
+ else if(target_zone == BODY_ZONE_PRECISE_GROIN)
+ zone = "lower abdomen"
+
+ return zone
+
+/datum/surgery_step/generic/seal_carapace/begin_step(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ var/zone = zone_name(target_zone)
+ user.visible_message(
+ "[user] is beginning to cauterize the incision on [target]'s [zone] with \the [tool].",
+ "You are beginning to cauterize the incision on [target]'s [zone] with \the [tool]."
+ )
+ target.custom_pain("Your [zone] is being burned!")
+ return ..()
+
+/datum/surgery_step/generic/seal_carapace/end_step(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ var/zone = zone_name(target_zone)
+ user.visible_message(
+ "[user] cauterizes the incision on [target]'s [zone] with \the [tool].",
+ "You cauterize the incision on [target]'s [zone] with \the [tool]."
+ )
+ return SURGERY_STEP_CONTINUE
+
+/datum/surgery_step/generic/seal_carapace/fail_step(mob/living/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
+ var/zone = zone_name(target_zone)
+ user.visible_message(
+ "[user]'s hand slips, leaving a small burn on [target]'s [zone] with \the [tool]!",
+ "Your hand slips, leaving a small burn on [target]'s [zone] with \the [tool]!"
+ )
+ target.apply_damage(3, BURN, target_zone)
+ return SURGERY_STEP_RETRY
+
+
#undef MITO_REVIVAL_COST