From f027e325b4a4ab3fb5c30941d4d4ac387afd5fad Mon Sep 17 00:00:00 2001 From: Interception&? <137328283+intercepti0n@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:39:13 +0300 Subject: [PATCH] disable old & enable new surgery_step --- baystation12.dme | 18 +--- code/_helpers/surgery.dm | 45 +++++++++ code/_helpers/unsorted.dm | 24 ----- code/_onclick/item_attack.dm | 8 +- code/datums/surgery/_defines.dm | 23 +++++ code/datums/surgery/surgery_item.dm | 17 ++++ code/datums/surgery/surgery_status.dm | 18 ++++ code/datums/surgery/surgery_step.dm | 138 ++++++++++++++++++++++++++ 8 files changed, 251 insertions(+), 40 deletions(-) create mode 100644 code/_helpers/surgery.dm create mode 100644 code/datums/surgery/_defines.dm create mode 100644 code/datums/surgery/surgery_item.dm create mode 100644 code/datums/surgery/surgery_status.dm create mode 100644 code/datums/surgery/surgery_step.dm diff --git a/baystation12.dme b/baystation12.dme index a5849c2e91e..305b9635bdd 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -153,6 +153,7 @@ #include "code\_helpers\spawn_sync.dm" #include "code\_helpers\sql.dm" #include "code\_helpers\storage.dm" +#include "code\_helpers\surgery.dm" #include "code\_helpers\text.dm" #include "code\_helpers\text_processor.dm" #include "code\_helpers\text_sql_encoding.dm" @@ -450,6 +451,10 @@ #include "code\datums\supplypacks\security.dm" #include "code\datums\supplypacks\supply.dm" #include "code\datums\supplypacks\supplypack.dm" +#include "code\datums\surgery\_defines.dm" +#include "code\datums\surgery\surgery_item.dm" +#include "code\datums\surgery\surgery_status.dm" +#include "code\datums\surgery\surgery_step.dm" #include "code\datums\trading\_trading_defines.dm" #include "code\datums\trading\ai.dm" #include "code\datums\trading\armor.dm" @@ -2801,19 +2806,6 @@ #include "code\modules\splash_text\splash_text.dm" #include "code\modules\supermatter\setup_supermatter.dm" #include "code\modules\supermatter\supermatter.dm" -#include "code\modules\surgery\_defines.dm" -#include "code\modules\surgery\bones.dm" -#include "code\modules\surgery\encased.dm" -#include "code\modules\surgery\face.dm" -#include "code\modules\surgery\generic.dm" -#include "code\modules\surgery\implant.dm" -#include "code\modules\surgery\limb_reattach.dm" -#include "code\modules\surgery\metroids.dm" -#include "code\modules\surgery\organs_internal.dm" -#include "code\modules\surgery\other.dm" -#include "code\modules\surgery\robotics.dm" -#include "code\modules\surgery\surgery.dm" -#include "code\modules\surgery\~defines.dm" #include "code\modules\synthesized_instruments\echo_editor.dm" #include "code\modules\synthesized_instruments\env_editor.dm" #include "code\modules\synthesized_instruments\event_manager.dm" diff --git a/code/_helpers/surgery.dm b/code/_helpers/surgery.dm new file mode 100644 index 00000000000..82273874c93 --- /dev/null +++ b/code/_helpers/surgery.dm @@ -0,0 +1,45 @@ +/proc/sort_surgeries() + var/gap = length(GLOB.surgery_steps) + var/swapped = 1 + while (gap > 1 || swapped) + swapped = 0 + if(gap > 1) + gap = round(gap / 1.247330950103979) + if(gap < 1) + gap = 1 + for(var/i = 1; gap + i <= length(GLOB.surgery_steps); i++) + var/datum/surgery_step/l = GLOB.surgery_steps[i] //Fucking hate + var/datum/surgery_step/r = GLOB.surgery_steps[gap+i] //how lists work here + if(l.priority < r.priority) + GLOB.surgery_steps.Swap(i, gap + i) + swapped = 1 + +//check if mob is lying down on something we can operate him on. +/proc/can_operate(mob/living/carbon/M, mob/living/carbon/user) + var/turf/T = get_turf(M) + if(locate(/obj/machinery/optable, T)) + . = TRUE + if(locate(/obj/structure/bed, T)) + . = TRUE + if(locate(/obj/structure/table, T)) + . = TRUE + if(locate(/obj/effect/rune/, T)) + . = TRUE + + if(M == user) + var/hitzone = check_zone(user.zone_sel.selecting) + var/list/badzones = list(BP_HEAD) + if(user.hand) + badzones += BP_L_ARM + badzones += BP_L_HAND + else + badzones += BP_R_ARM + badzones += BP_R_HAND + if(hitzone in badzones) + return FALSE + +/proc/agjust_organ_image(obj/item/organ/O) + var/image/I = image(icon = O.icon, icon_state = O.icon_state) + I.overlays = O.overlays + I.pixel_y = -5 + return I diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index 21965c85b96..691d9e11bba 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -945,30 +945,6 @@ var/global/list/common_tools = list( /obj/item/clothing/mask/smokable/cigarette/can_puncture() return lit -//check if mob is lying down on something we can operate him on. -/proc/can_operate(mob/living/carbon/M, mob/living/carbon/user) - var/turf/T = get_turf(M) - if(locate(/obj/machinery/optable, T)) - . = TRUE - if(locate(/obj/structure/bed, T)) - . = TRUE - if(locate(/obj/structure/table, T)) - . = TRUE - if(locate(/obj/effect/rune/, T)) - . = TRUE - - if(M == user) - var/hitzone = check_zone(user.zone_sel.selecting) - var/list/badzones = list(BP_HEAD) - if(user.hand) - badzones += BP_L_ARM - badzones += BP_L_HAND - else - badzones += BP_R_ARM - badzones += BP_R_HAND - if(hitzone in badzones) - return FALSE - /proc/reverse_direction(dir) switch(dir) if(NORTH) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 43e521e7207..12d39adae99 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -140,9 +140,11 @@ avoid code duplication. This includes items that may sometimes act as a standard /mob/living/attackby(obj/item/I, mob/user) if(!ismob(user)) - return 0 - if(can_operate(src, user) && I.do_surgery(src, user)) //Surgery - return 1 + return FALSE + + if(can_operate(src, user) && I.do_surgery(src, user)) + return TRUE + return I.attack(src, user, user.zone_sel.selecting) /mob/living/carbon/human/attackby(obj/item/I, mob/user) diff --git a/code/datums/surgery/_defines.dm b/code/datums/surgery/_defines.dm new file mode 100644 index 00000000000..b40bfe993dd --- /dev/null +++ b/code/datums/surgery/_defines.dm @@ -0,0 +1,23 @@ +/// Causes hands to become bloody. +#define BLOODY_HANDS (1 << 0) +/// Causes body to become bloody. +#define BLOODY_BODY (1 << 1) + +/// Delta multiplier for all surgeries, ranges from 0.9 to 1.1. +#define SURGERY_DURATION_DELTA rand(9, 11) / 10 + +#define SURGERY_FAILURE -1 +#define SURGERY_BLOCKED -2 + +#define CUT_DURATION 30 +#define AMPUTATION_DURATION 125 +#define CLAMP_DURATION 35 +#define RETRACT_DURATION 25 +#define CAUTERIZE_DURATION 35 +#define GLUE_BONE_DURATION 35 +#define BONE_MEND_DURATION 40 +#define SAW_DURATION 50 +#define DRILL_DURATION 70 +#define ATTACH_DURATION 50 +#define ORGAN_FIX_DURATION 35 +#define CONNECT_DURATION 50 diff --git a/code/datums/surgery/surgery_item.dm b/code/datums/surgery/surgery_item.dm new file mode 100644 index 00000000000..a477a625e54 --- /dev/null +++ b/code/datums/surgery/surgery_item.dm @@ -0,0 +1,17 @@ +/obj/item/proc/do_surgery(mob/living/carbon/target, mob/living/user) + if (!istype(target)) + return FALSE + + if (user.a_intent == I_HURT) + return FALSE + + var/zone = user.zone_sel.selecting + if(zone in target.surgery_status.ongoing_steps) + to_chat(user, SPAN("warning", "You can't operate on this area while surgery is already in progress.")) + return TRUE + + for(var/datum/surgery_step/S in GLOB.surgery_steps) + if(S.do_step(user, target, src, zone)) + return TRUE + + return FALSE diff --git a/code/datums/surgery/surgery_status.dm b/code/datums/surgery/surgery_status.dm new file mode 100644 index 00000000000..e8d72abb8ad --- /dev/null +++ b/code/datums/surgery/surgery_status.dm @@ -0,0 +1,18 @@ +/datum/surgery_status + /** + * List of zones where surgery steps are currently performed. + */ + var/list/ongoing_steps = list() + /** + * Associative list of string -> type, where string is zone name and + * type is a reference to an operated organ. + */ + var/list/operated_organs = list() + +/datum/surgery_status/proc/start_surgery(obj/item/organ/target_organ, target_zone) + LAZYADD(ongoing_steps, target_zone) + LAZYADDASSOC(operated_organs, target_zone, target_organ) + +/datum/surgery_status/proc/stop_surgery(target_zone) + LAZYREMOVE(ongoing_steps, target_zone) + LAZYREMOVE(operated_organs, target_zone) diff --git a/code/datums/surgery/surgery_step.dm b/code/datums/surgery/surgery_step.dm new file mode 100644 index 00000000000..36cadb65f19 --- /dev/null +++ b/code/datums/surgery/surgery_step.dm @@ -0,0 +1,138 @@ +/datum/surgery_step + var/can_infect = FALSE + var/accessible = FALSE + var/delicate = FALSE + var/blood_level = 0 + var/shock_level = 0 + var/priority = 0 + var/duration = 0 + var/list/allowed_tools = null + +/// tool check -> organ selection -> organ checks -> surgery init -> orher stuff +/datum/surgery_step/proc/do_step(atom/user, mob/living/carbon/human/target, obj/item/tool, target_zone) + if(!check_tool(tool)) + return FALSE + + if(accessible && !check_clothing(target, target_zone)) + return FALSE + + var/obj/item/organ/target_organ = target.get_organ(pick_organ_tag(user, target, target_zone)) + if(!check_organ(target, target_organ, tool, target_zone)) + return FALSE + + // At this point we can access selected organ via `surgery_status`. + target.surgery_status.start_surgery(target_organ, target_zone) + initiate(user, target, tool, target_zone) + target.surgery_status.stop_surgery(target_zone) + + target.update_surgery() + + return TRUE + +/datum/surgery_step/proc/check_tool(obj/item/tool) + var/bool = (tool.type in allowed_tools) + return bool + +/datum/surgery_step/proc/check_clothing(mob/living/carbon/target, target_zone) + var/list/clothes = get_target_clothes(target, target_zone) + for(var/obj/item/clothing/C in clothes) + if(C.body_parts_covered & body_part_flags[target_zone]) + return FALSE + return TRUE + +/datum/surgery_step/proc/check_organ(mob/living/carbon/human/target, obj/item/organ/target_organ, obj/item/tool, target_zone) + if(!istype(target_organ)) + return FALSE + + return TRUE + +/datum/surgery_step/proc/pick_organ_tag(atom/user, mob/living/carbon/target, target_zone) + return target_zone + +/datum/surgery_step/proc/initiate(mob/user, mob/living/carbon/human/target, obj/item/tool, target_zone) + var/obj/item/target_organ = target.surgery_status.operated_organs[target_zone] + if(can_infect && target_organ) + spread_germs_to_organ(user, target_organ) + + if(ishuman(user) && prob(60)) + var/mob/living/carbon/human/H = user + if(blood_level & BLOODY_HANDS) + H.bloody_hands(target, 0) + if(blood_level & BLOODY_BODY) + H.bloody_body(target, 0) + + if(shock_level) + target.shock_stage = max(target.shock_stage, shock_level) + + var/success_chance = calc_success_chance(user, target, tool) + var/surgery_duration = SURGERY_DURATION_DELTA * duration * tool.surgery_speed + if(prob(success_chance) && do_mob(user, target, surgery_duration)) + success(user, target, tool, target_zone) + else + failure(user, target, tool, target_zone) + +/datum/surgery_step/proc/spread_germs_to_organ(mob/living/carbon/human/user, obj/item/organ/external/target_organ) + if(!istype(user) || !istype(target_organ)) + return + + var/germ_level = user.germ_level + var/obj/item/clothing/gloves/G = user.gloves + if(istype(G) && !(G.clipped && prob(75))) + germ_level = G.germ_level + + target_organ.germ_level = max(germ_level, target_organ.germ_level) + +/datum/surgery_step/proc/calc_success_chance(mob/living/user, mob/living/carbon/human/target, obj/item/tool, target_zone) + . = allowed_tools[tool.type] + if(user == target) + . -= 10 + + if(ishuman(user)) + var/mob/living/carbon/human/H = user + . -= round(H.shock_stage * 0.5) + if(H.eye_blurry) + . -= 20 + if(H.eye_blind) + . -= 60 + + if(delicate) + if(ishuman(user) && user?.slurring) + . -= 10 + if(!target.lying) + . -= 30 + + var/turf/T = get_turf(target) + if(locate(/obj/machinery/optable, T)) + . -= 0 + else if(locate(/obj/structure/bed, T)) + . -= 5 + else if(locate(/obj/structure/table, T)) + . -= 10 + else if(locate(/obj/effect/rune/, T)) + . -= 10 + + . = max(., 0) + +/datum/surgery_step/proc/success(mob/user, mob/living/carbon/human/target, obj/item/tool, target_zone) + pass() + +/datum/surgery_step/proc/failure(mob/user, mob/living/carbon/human/target, obj/item/tool, target_zone) + pass() + +/datum/surgery_step/proc/announce_preop(mob/living/user, self_message, blind_message) + user.visible_message( + self_message, + blind_message + ) + +/datum/surgery_step/proc/announce_success(mob/living/user, self_message, blind_message) + user.visible_message( + SPAN("notice", self_message), + SPAN("notice", blind_message) + ) + +/datum/surgery_step/proc/announce_failure(mob/living/user, self_message, blind_message) + user.visible_message( + SPAN("warning", self_message), + SPAN("warning", blind_message) + )