From 77253c5ae76e14d5f26d838ac71b6beb7148aade Mon Sep 17 00:00:00 2001 From: Luc <89928798+lewcc@users.noreply.github.com> Date: Mon, 1 Jul 2024 12:01:17 -0700 Subject: [PATCH] Gives Surgical Drapes a Use (#25686) * Gives drapes some utility for starting surgeries * Adds a nice helping of drapes throughout the codebase * add icon, realize I didn't think that through * Handles blood with signals * whoopsie daisy * range * how about borgs * Apply suggestions from code review Co-authored-by: Matt <116982774+Burzah@users.noreply.github.com> Signed-off-by: Luc <89928798+lewcc@users.noreply.github.com> * burza suggestion * more dgamer reviews * Oops * Update code/modules/surgery/surgery.dm Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com> Signed-off-by: Luc <89928798+lewcc@users.noreply.github.com> --------- Signed-off-by: Luc <89928798+lewcc@users.noreply.github.com> Co-authored-by: Matt <116982774+Burzah@users.noreply.github.com> Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com> --- code/__DEFINES/dcs/signals.dm | 14 ++- code/datums/components/surgery_initiator.dm | 92 ++++++++++++++++++- code/game/atoms.dm | 4 +- .../items/stacks/sheets/sheet_types.dm | 2 + .../objects/items/weapons/storage/backpack.dm | 1 + code/game/objects/mail.dm | 1 + code/game/objects/structures/bedsheet_bin.dm | 4 + code/modules/clothing/under/suit.dm | 5 + .../mob/living/silicon/robot/robot_modules.dm | 3 +- .../supply/supply_packs/pack_medical.dm | 3 +- code/modules/surgery/generic.dm | 16 ++-- code/modules/surgery/surgery.dm | 18 +++- code/modules/surgery/tools.dm | 17 +++- 13 files changed, 157 insertions(+), 23 deletions(-) diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index d3b3a10117de..269585c0239e 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -73,8 +73,10 @@ #define COMSIG_ATOM_HULK_ATTACK "hulk_attack" ///from base of atom/animal_attack(): (/mob/user) #define COMSIG_ATOM_ATTACK_ANIMAL "attack_animal" -///from base of atom/examine(): (/mob) +///from base of atom/examine(): (examining_user, examine_list) #define COMSIG_PARENT_EXAMINE "atom_examine" +///from base of atom/examine_more(): (examining_user, examine_list) +#define COMSIG_PARENT_EXAMINE_MORE "atom_examine_more" ///from base of atom/get_examine_name(): (/mob, list/overrides) #define COMSIG_ATOM_GET_EXAMINE_NAME "atom_examine_name" //Positions for overrides list @@ -508,6 +510,16 @@ //sent from a mob when they set themselves to DNR #define COMSIG_LIVING_SET_DNR "set_dnr" +// Sent from a surgery step when blood is being splashed. (datum/surgery, mob/user, mob/target, zone, obj/item/tool) +#define COMSIG_SURGERY_BLOOD_SPLASH "surgery_blood_splash" + /// If returned from this signal, will prevent any surgery splashing. + #define COMPONENT_BLOOD_SPLASH_HANDLED (1<<0) + +// Sent from a surgery step when organs are being spread from an incision +#define COMSIG_SURGERY_GERM_SPREAD "surgery_germ_spread" + /// If returned from this signal, germ spread will be blocked. + #define COMPONENT_GERM_SPREAD_BLOCK (1<<0) + //ALL OF THESE DO NOT TAKE INTO ACCOUNT WHETHER AMOUNT IS 0 OR LOWER AND ARE SENT REGARDLESS! // none of these are called as of right now, as there is nothing listening for them. diff --git a/code/datums/components/surgery_initiator.dm b/code/datums/components/surgery_initiator.dm index e0a5c1bfcc73..54fd99d2cf84 100644 --- a/code/datums/components/surgery_initiator.dm +++ b/code/datums/components/surgery_initiator.dm @@ -24,6 +24,13 @@ /// Also, note that for anything sharp, SURGERY_INITIATOR_ORGANIC should be set as well. var/valid_starting_types = SURGERY_INITIATOR_ORGANIC + /// How effective this is at preventing infections. + /// 0 = preventing nothing, 1 = preventing any infection + var/germ_prevention_quality = 0 + + /// The sound to play when starting surgeries + var/surgery_start_sound = null + // Replace any other surgery initiator dupe_type = /datum/component/surgery_initiator @@ -43,10 +50,16 @@ /datum/component/surgery_initiator/RegisterWithParent() RegisterSignal(parent, COMSIG_ITEM_ATTACK, PROC_REF(initiate_surgery_moment)) RegisterSignal(parent, COMSIG_ATOM_UPDATE_SHARPNESS, PROC_REF(on_parent_sharpness_change)) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE_MORE, PROC_REF(on_parent_examine_more)) /datum/component/surgery_initiator/UnregisterFromParent() UnregisterSignal(parent, COMSIG_ITEM_ATTACK) UnregisterSignal(parent, COMSIG_ATOM_UPDATE_SHARPNESS) + UnregisterSignal(parent, COMSIG_PARENT_EXAMINE_MORE) + +/datum/component/surgery_initiator/proc/on_parent_examine_more(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER // COMSIG_PARENT_EXAMINE_MORE + examine_list += "You can use this on someone who is laying down to begin surgery on them." /// Keep tabs on the attached item's sharpness. /// This component gets added in atoms when they're made sharp as well. @@ -134,8 +147,14 @@ if(!procedure) return + if(!on_surgery_selection(user, target, procedure)) + return + return try_choose_surgery(user, target, procedure) +/datum/component/surgery_initiator/proc/on_surgery_selection(mob/user, mob/living/target, datum/surgery/target_surgery) + return TRUE + /datum/component/surgery_initiator/proc/get_available_surgeries(mob/user, mob/living/target) var/list/available_surgeries = list() for(var/datum/surgery/surgery in GLOB.surgeries_list) @@ -150,16 +169,19 @@ return available_surgeries +/datum/component/surgery_initiator/proc/cancel_unstarted_surgery_fluff(datum/surgery/the_surgery, mob/living/patient, mob/user, selected_zone) + user.visible_message( + "[user] stops the surgery on [patient]'s [parse_zone(selected_zone)] with [parent].", + "You stop the surgery on [patient]'s [parse_zone(selected_zone)] with [parent].", + ) + /// Does the surgery de-initiation. /datum/component/surgery_initiator/proc/attempt_cancel_surgery(datum/surgery/the_surgery, mob/living/patient, mob/user) var/selected_zone = user.zone_selected /// We haven't even started yet. Any surgery can be cancelled at this point. if(the_surgery.step_number == 1) patient.surgeries -= the_surgery - user.visible_message( - "[user] stops the surgery on [patient]'s [parse_zone(selected_zone)] with [parent].", - "You stop the surgery on [patient]'s [parse_zone(selected_zone)] with [parent].", - ) + cancel_unstarted_surgery_fluff(the_surgery, patient, user, selected_zone) qdel(the_surgery) return TRUE @@ -288,10 +310,17 @@ var/datum/surgery/procedure = new surgery.type(target, selected_zone, affecting_limb) + + RegisterSignal(procedure, COMSIG_SURGERY_BLOOD_SPLASH, PROC_REF(on_blood_splash)) + + procedure.germ_prevention_quality = germ_prevention_quality + show_starting_message(user, target, procedure) log_attack(user, target, "operated on (OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])") + return procedure + /datum/component/surgery_initiator/proc/surgery_needs_exposure(datum/surgery/surgery, mob/living/target) return !surgery.ignore_clothes && !get_location_accessible(target, target.zone_selected) @@ -302,6 +331,14 @@ "You hold [parent] over [target]'s [parse_zone(user.zone_selected)] to prepare for \an [procedure.name].", ) +/datum/component/surgery_initiator/proc/on_prevent_germs() + SIGNAL_HANDLER // + return + +/datum/component/surgery_initiator/proc/on_blood_splash() + SIGNAL_HANDLER // COMSIG_SURGERY_BLOOD_SPLASH + return + /datum/component/surgery_initiator/limb can_cancel = FALSE // don't let a leg cancel a surgery @@ -310,3 +347,50 @@ /datum/component/surgery_initiator/robo/sharp valid_starting_types = SURGERY_INITIATOR_ORGANIC | SURGERY_INITIATOR_ROBOTIC + +/datum/component/surgery_initiator/cloth + can_cancel = FALSE + surgery_start_sound = "rustle" + +/datum/component/surgery_initiator/cloth/show_starting_message(mob/user, mob/living/target, datum/surgery/procedure) + user.visible_message( + "[user] drapes [parent] over [target]'s [parse_zone(user.zone_selected)] to prepare for surgery.", + "You drape [parent] over [target]'s [parse_zone(user.zone_selected)] to prepare for \an [procedure.name].", + ) + +/datum/component/surgery_initiator/cloth/try_choose_surgery(mob/user, mob/living/target, datum/surgery/surgery) + var/datum/surgery/new_procedure = ..() + if(!istype(new_procedure)) + return + + new_procedure.started_with_drapes = TRUE + +/datum/component/surgery_initiator/cloth/on_surgery_selection(mob/user, mob/living/target, datum/surgery/target_surgery) + user.visible_message( + "[user] starts to apply [parent] onto [target].", + "You start to apply [parent] onto [target].", + ) + + if(!isnull(surgery_start_sound)) + playsound(src, surgery_start_sound, 50, TRUE) + + playsound(src, surgery_start_sound) + if(!do_after_once(user, 3 SECONDS, TRUE, target)) + user.visible_message( + "[user] stops applying [parent] onto [target].", + "You stop applying [parent] onto [target]." + ) + return + + + if(!isnull(surgery_start_sound)) + playsound(src, surgery_start_sound, 50, TRUE) + + return TRUE + +/datum/component/surgery_initiator/cloth/on_blood_splash(datum/surgery, mob/user, mob/target, zone, obj/item/tool) + if(prob(90 * germ_prevention_quality)) + target.visible_message("Blood splashes onto the dressing.") + var/obj/item/I = parent // safety: this component can only go onto an item + I.add_mob_blood(target) + return COMPONENT_BLOOD_SPLASH_HANDLED diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 4ed17d0b76ce..78d92c6673d3 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -449,8 +449,8 @@ /atom/proc/examine_more(mob/user) SHOULD_CALL_PARENT(TRUE) RETURN_TYPE(/list) - - return list() + . = list() + SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE_MORE, user, .) /** * Updates the appearence of the icon diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 3a710799b8b4..94585a31f1a3 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -368,6 +368,7 @@ GLOBAL_LIST_INIT(cloth_recipes, list ( )), null, new /datum/stack_recipe("improvised gauze", /obj/item/stack/medical/bruise_pack/improvised, 1, 2, 6), + new /datum/stack_recipe("imrovised drapes", /obj/item/surgical_drapes/improvised, 1), new /datum/stack_recipe("rag", /obj/item/reagent_containers/glass/rag, 1), new /datum/stack_recipe("bedsheet", /obj/item/bedsheet, 3), new /datum/stack_recipe("empty sandbag", /obj/item/emptysandbag, 4), @@ -407,6 +408,7 @@ GLOBAL_LIST_INIT(durathread_recipes, list ( new /datum/stack_recipe("durathread beret", /obj/item/clothing/head/beret/durathread, 2, time = 4 SECONDS), new /datum/stack_recipe("durathread beanie", /obj/item/clothing/head/beanie/durathread, 2, time = 4 SECONDS), new /datum/stack_recipe("durathread bandana", /obj/item/clothing/mask/bandana/durathread, 1, time = 2.5 SECONDS), + new /datum/stack_recipe("surgical drapes", /obj/item/surgical_drapes, 1, time = 3 SECONDS) )) /obj/item/stack/sheet/durathread diff --git a/code/game/objects/items/weapons/storage/backpack.dm b/code/game/objects/items/weapons/storage/backpack.dm index 7d76006723eb..304d37ed247e 100644 --- a/code/game/objects/items/weapons/storage/backpack.dm +++ b/code/game/objects/items/weapons/storage/backpack.dm @@ -596,6 +596,7 @@ new /obj/item/bonegel(src) new /obj/item/bonesetter(src) new /obj/item/FixOVein(src) + new /obj/item/surgical_drapes(src) new /obj/item/clothing/suit/straight_jacket(src) new /obj/item/clothing/mask/muzzle(src) new /obj/item/reagent_containers/glass/bottle/reagent/hydrocodone(src) diff --git a/code/game/objects/mail.dm b/code/game/objects/mail.dm index 6726c7ff2f6f..6175ec810e73 100644 --- a/code/game/objects/mail.dm +++ b/code/game/objects/mail.dm @@ -123,6 +123,7 @@ /obj/item/clothing/glasses/sunglasses, /obj/item/food/snacks/fortunecookie, /obj/item/scalpel/laser/laser1, + /obj/item/surgical_drapes, /obj/item/toy/figure/crew/cmo, /obj/item/toy/figure/crew/chemist, /obj/item/toy/figure/crew/geneticist, diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index 91106241eaff..90ddae2fd6d8 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -26,6 +26,10 @@ LINEN BINS var/list/nightmare_messages = list("black") var/comfort = 0.5 +/obj/item/bedsheet/Initialize(mapload) + . = ..() + AddComponent(/datum/component/surgery_initiator/cloth, null, 0.45) // honestly, not bad. + /obj/item/bedsheet/attack_hand(mob/user) if(isturf(loc) && user.Move_Pulled(src)) // make sure its on the ground first, prevents a speed exploit return diff --git a/code/modules/clothing/under/suit.dm b/code/modules/clothing/under/suit.dm index 9ebee0602d99..f15b44f7ca3d 100644 --- a/code/modules/clothing/under/suit.dm +++ b/code/modules/clothing/under/suit.dm @@ -9,6 +9,11 @@ "Kidan" = 'icons/mob/clothing/species/kidan/under/suit.dmi' ) +/obj/item/clothing/under/suit/Initialize(mapload) + . = ..() + // better than nothing! ghetto surgery time + AddComponent(/datum/component/surgery_initiator/cloth, null, 0.1) + /obj/item/clothing/under/suit/black name = "black suit" desc = "A black suit and red tie. Very formal." diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm index f1dd7d9fa61e..00f93669a175 100644 --- a/code/modules/mob/living/silicon/robot/robot_modules.dm +++ b/code/modules/mob/living/silicon/robot/robot_modules.dm @@ -355,7 +355,8 @@ /obj/item/stack/medical/ointment/advanced/cyborg, /obj/item/stack/medical/splint/cyborg, /obj/item/stack/nanopaste/cyborg, - /obj/item/gripper/medical + /obj/item/gripper/medical, + /obj/item/surgical_drapes, ) malf_modules = list(/obj/item/gun/syringemalf) special_rechargables = list( diff --git a/code/modules/supply/supply_packs/pack_medical.dm b/code/modules/supply/supply_packs/pack_medical.dm index dba5ff3f29bf..2328591115f2 100644 --- a/code/modules/supply/supply_packs/pack_medical.dm +++ b/code/modules/supply/supply_packs/pack_medical.dm @@ -154,7 +154,8 @@ /obj/item/bonegel, /obj/item/retractor, /obj/item/bonesetter, - /obj/item/circular_saw) + /obj/item/circular_saw, + /obj/item/surgical_drapes) cost = 400 containertype = /obj/structure/closet/crate/secure containername = "surgery crate" diff --git a/code/modules/surgery/generic.dm b/code/modules/surgery/generic.dm index 5411e8c8209f..925bf8b7c640 100644 --- a/code/modules/surgery/generic.dm +++ b/code/modules/surgery/generic.dm @@ -28,8 +28,8 @@ /datum/surgery_step/generic/cut_open/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message( - "[user] starts the incision on [target]'s [affected.name] with \the [tool].", - "You start the incision on [target]'s [affected.name] with \the [tool].", + "[user] starts the incision on [target]'s [affected.name] with [tool].", + "You start the incision on [target]'s [affected.name] with [tool].", chat_message_type = MESSAGE_TYPE_COMBAT ) affected.custom_pain("You feel a horrible pain as if from a sharp knife in your [affected.name]!") @@ -38,8 +38,8 @@ /datum/surgery_step/generic/cut_open/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message( - " [user] has made an incision on [target]'s [affected.name] with \the [tool].", - " You have made an incision on [target]'s [affected.name] with \the [tool].", + "[user] has made an incision on [target]'s [affected.name] with [tool].", + "You have made an incision on [target]'s [affected.name] with [tool].", chat_message_type = MESSAGE_TYPE_COMBAT ) affected.open = ORGAN_ORGANIC_OPEN @@ -49,8 +49,8 @@ /datum/surgery_step/generic/cut_open/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message( - " [user]'s hand slips, slicing open [target]'s [affected.name] in a wrong spot with \the [tool]!", - " Your hand slips, slicing open [target]'s [affected.name] in a wrong spot with \the [tool]!", + "[user]'s hand slips, slicing open [target]'s [affected.name] in a wrong spot with [tool]!", + "Your hand slips, slicing open [target]'s [affected.name] in a wrong spot with [tool]!", chat_message_type = MESSAGE_TYPE_COMBAT ) affected.receive_damage(10) @@ -93,8 +93,8 @@ /datum/surgery_step/generic/clamp_bleeders/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) var/obj/item/organ/external/affected = target.get_organ(target_zone) user.visible_message( - " [user]'s hand slips, tearing blood vessels and causing massive bleeding in [target]'s [affected.name] with \the [tool]!", - " Your hand slips, tearing blood vessels and causing massive bleeding in [target]'s [affected.name] with \the [tool]!", + "[user]'s hand slips, tearing blood vessels and causing massive bleeding in [target]'s [affected.name] with \the [tool]!", + "Your hand slips, tearing blood vessels and causing massive bleeding in [target]'s [affected.name] with \the [tool]!", chat_message_type = MESSAGE_TYPE_COMBAT ) affected.receive_damage(10) diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 20cdc7e04251..35ae69f16ee4 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -44,7 +44,10 @@ var/abstract = FALSE /// Whether this surgery should be cancelled when an organ change happens. (removed if requires bodypart, or added if doesn't require bodypart) var/cancel_on_organ_change = TRUE - + /// Whether the surgery was started with drapes. + var/started_with_drapes = FALSE + /// How likely it should be for the surgery to cause infection: 0-1 + var/germ_prevention_quality = 0 /datum/surgery/New(atom/surgery_target, surgery_location, surgery_bodypart) ..() @@ -440,16 +443,21 @@ SHOULD_CALL_PARENT(TRUE) if(ishuman(target)) var/obj/item/organ/external/affected = target.get_organ(target_zone) - if(can_infect && affected) + if(can_infect && affected && !prob(surgery.germ_prevention_quality)) spread_germs_to_organ(affected, user, tool) if(ishuman(user) && !isalien(target) && prob(60)) var/mob/living/carbon/human/H = user + + var/blood_spread = SEND_SIGNAL(surgery, COMSIG_SURGERY_BLOOD_SPLASH, user, target, target_zone, tool) + if(blood_spread == COMPONENT_BLOOD_SPLASH_HANDLED) + return switch(blood_level) if(SURGERY_BLOODSPREAD_HANDS) + target.visible_message("Blood splashes onto [user]'s hands.") H.make_bloody_hands(target.get_blood_dna_list(), target.get_blood_color()) if(SURGERY_BLOODSPREAD_FULLBODY) + target.visible_message("A spray of blood coats [user].") H.bloody_body(target) - return /** * Finish a surgery step, performing anything that runs on the tail-end of a successful surgery. @@ -484,7 +492,7 @@ * * user - The user who's manipulating the organ. * * tool - The tool the user is using to mess with the organ. */ -/proc/spread_germs_to_organ(obj/item/organ/target_organ, mob/living/carbon/human/user, obj/item/tool) +/datum/surgery_step/proc/spread_germs_to_organ(obj/item/organ/target_organ, mob/living/carbon/human/user, obj/item/tool, datum/surgery/surgery) if(!istype(user) || !istype(target_organ) || target_organ.is_robotic() || target_organ.sterile) return @@ -502,7 +510,7 @@ * * E - An external organ being operated on. * * tool - The tool performing the operation. */ -/proc/spread_germs_by_incision(obj/item/organ/external/E, obj/item/tool) +/datum/surgery_step/proc/spread_germs_by_incision(obj/item/organ/external/E, obj/item/tool, datum/surgery/surgery) if(!is_external_organ(E)) return if(!E.owner) diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index e711b0cf2311..1a012ae609c2 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -274,9 +274,24 @@ /obj/item/surgical_drapes name = "surgical drapes" - desc = "Apearature brand surgical drapes providing privacy and infection control." + desc = "Apearature brand surgical drapes providing privacy and infection control. Built from durathread." icon = 'icons/obj/surgery.dmi' icon_state = "surgical_drapes" w_class = WEIGHT_CLASS_SMALL origin_tech = "biotech=1" attack_verb = list("slapped") + /// How effective this is at preventing infections during surgeries. + var/surgery_effectiveness = 0.9 + +/obj/item/surgical_drapes/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SURGICAL, ROUNDSTART_TRAIT) + AddComponent(/datum/component/surgery_initiator/cloth, null, surgery_effectiveness) + +/obj/item/surgical_drapes/improvised + name = "improvised drapes" + desc = "Hastily-sliced fabric that seems like it'd be useful for surgery. Probably better than the shirt off your back." + icon = 'icons/obj/stacks/miscellaneous.dmi' + icon_state = "empty-sandbags" + origin_tech = null + surgery_effectiveness = 0.67