diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index c38ca3ae2165..85e3914b8513 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -19,7 +19,7 @@ GLOBAL_LIST_EMPTY(radial_menus) . = ..() icon_state = "radial_slice_focus" if(tooltips) - openToolTip(usr, src, params, title = name) + openToolTip(usr, src, params, title = name, content = desc) /obj/screen/radial/slice/MouseExited(location, control, params) . = ..() @@ -51,10 +51,16 @@ GLOBAL_LIST_EMPTY(radial_menus) parent.finished = TRUE /datum/radial_menu - var/list/choices = list() //List of choice id's - var/list/choices_icons = list() //choice_id -> icon - var/list/choices_values = list() //choice_id -> choice - var/list/page_data = list() //list of choices per page + /// List of choice IDs + var/list/choices = list() + /// choice_id -> icon + var/list/choices_icons = list() + /// choice_id -> choice + var/list/choices_values = list() + /// choice_id -> /datum/radial_menu_choice + var/list/choice_datums = list() + ///list of choices per page + var/list/page_data = list() var/selected_choice @@ -164,6 +170,7 @@ GLOBAL_LIST_EMPTY(radial_menus) E.cut_overlays() E.alpha = 0 E.name = "None" + E.desc = null E.maptext = null E.mouse_opacity = MOUSE_OPACITY_TRANSPARENT E.choice = null @@ -188,21 +195,32 @@ GLOBAL_LIST_EMPTY(radial_menus) E.alpha = 255 E.mouse_opacity = MOUSE_OPACITY_ICON E.cut_overlays() + E.vis_contents.Cut() if(choice_id == NEXT_PAGE_ID) E.name = "Next Page" + E.desc = null E.next_page = TRUE E.add_overlay("radial_next") else if(istext(choices_values[choice_id])) E.name = choices_values[choice_id] + else if(ispath(choices_values[choice_id],/atom)) + var/atom/A = choices_values[choice_id] + E.name = initial(A.name) else var/atom/movable/AM = choices_values[choice_id] //Movables only E.name = AM.name + + if(choices_icons[choice_id]) + E.add_overlay(choices_icons[choice_id]) + + var/datum/radial_menu_choice/choice_datum = choice_datums[choice_id] + if(choice_datum && istext(choice_datum.info)) + E.desc = choice_datum.info + E.choice = choice_id E.maptext = null E.next_page = FALSE - if(choices_icons[choice_id]) - E.add_overlay(choices_icons[choice_id]) /datum/radial_menu/New() close_button = new @@ -231,11 +249,18 @@ GLOBAL_LIST_EMPTY(radial_menus) var/I = extract_image(new_choices[E]) if(I) choices_icons[id] = I + + if (istype(new_choices[E], /datum/radial_menu_choice)) + choice_datums[id] = new_choices[E] setup_menu(use_tooltips) -/datum/radial_menu/proc/extract_image(E) - var/mutable_appearance/MA = new /mutable_appearance(E) +/datum/radial_menu/proc/extract_image(to_extract_from) + if (istype(to_extract_from, /datum/radial_menu_choice)) + var/datum/radial_menu_choice/choice = to_extract_from + to_extract_from = choice.image + + var/mutable_appearance/MA = new /mutable_appearance(to_extract_from) if(MA) MA.layer = ABOVE_HUD_LAYER MA.appearance_flags |= RESET_TRANSFORM @@ -315,3 +340,15 @@ GLOBAL_LIST_EMPTY(radial_menus) if(!menu.custom_check_callback.Invoke()) return return answer + +/// Can be provided to choices in radial menus if you want to provide more information +/datum/radial_menu_choice + /// Required -- what to display for this button + var/image + + /// If provided, will display an info button that will put this text in your chat + var/info + +/datum/radial_menu_choice/Destroy(force, ...) + . = ..() + QDEL_NULL(image) diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm index f9dbc90fef4f..dd54d5b450d1 100644 --- a/code/game/objects/items/kitchen.dm +++ b/code/game/objects/items/kitchen.dm @@ -106,7 +106,9 @@ AddComponent(/datum/component/butchering, 80 - force, 100, force - 10) //bonus chance increases depending on force /obj/item/kitchen/knife/attack(mob/living/carbon/M, mob/living/carbon/user) - if(user.zone_selected == BODY_ZONE_PRECISE_EYES) + if(!user.a_intent == INTENT_HARM && attempt_initiate_surgery(src, M, user)) + return + else if(user.zone_selected == BODY_ZONE_PRECISE_EYES) if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) M = user return eyestab(M,user) diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm index c4e0c4483489..bbb6ccbf7112 100644 --- a/code/game/objects/items/tools/crowbar.dm +++ b/code/game/objects/items/tools/crowbar.dm @@ -20,6 +20,10 @@ toolspeed = 1 armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30) +/obj/item/crowbar/attack(mob/living/M, mob/user) + if(user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) + ..() + /obj/item/crowbar/suicide_act(mob/user) user.visible_message(span_suicide("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index 52e90d6bece8..f3fecffcfc4a 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -74,6 +74,8 @@ return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) /obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) + if(!user.a_intent == INTENT_HARM && attempt_initiate_surgery(src, M, user)) + return if(!istype(M)) return ..() if(user.zone_selected != BODY_ZONE_PRECISE_EYES && user.zone_selected != BODY_ZONE_HEAD) diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index 3bd3fa8f26fe..c1102c83554c 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -95,6 +95,10 @@ dyn_explosion(T, plasmaAmount/5)//20 plasma in a standard welder has a 4 power explosion. no breaches, but enough to kill/dismember holder qdel(src) +/obj/item/weldingtool/attack(mob/living/M, mob/user) + if(!isOn() || user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) + ..() + /obj/item/weldingtool/afterattack(atom/O, mob/user, proximity) . = ..() if(!proximity) diff --git a/code/game/objects/items/tools/wirecutters.dm b/code/game/objects/items/tools/wirecutters.dm index 52e9fd2f2a3c..3dc2a749b2da 100644 --- a/code/game/objects/items/tools/wirecutters.dm +++ b/code/game/objects/items/tools/wirecutters.dm @@ -60,6 +60,8 @@ if(do_after(user, 1.5 SECONDS, C)) to_chat(C, span_notice("You succesfuly remove the durathread strand.")) C.remove_status_effect(STATUS_EFFECT_CHOKINGSTRAND) + else if(!user.a_intent == INTENT_HARM && attempt_initiate_surgery(src, C, user)) + return else ..() diff --git a/code/game/objects/items/tools/wrench.dm b/code/game/objects/items/tools/wrench.dm index 08585cf4ef53..77d1584505ba 100644 --- a/code/game/objects/items/tools/wrench.dm +++ b/code/game/objects/items/tools/wrench.dm @@ -20,6 +20,10 @@ toolspeed = 1 armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 30) +/obj/item/wrench/attack(mob/living/M, mob/user) + if(user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) + ..() + /obj/item/wrench/suicide_act(mob/user) user.visible_message(span_suicide("[user] is beating [user.p_them()]self to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!")) playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1) diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index 75a3cb178ae5..f80c6c2b1939 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -78,6 +78,15 @@ msg += "[t_He] [t_is] moderately deformed!\n" else msg += "[t_He] [t_is] severely deformed!\n" + + if(surgeries.len) + var/surgery_text + for(var/datum/surgery/S in surgeries) + if(!surgery_text) + surgery_text = "[t_He] [t_is] being operated on in \the [S.operated_bodypart]" + else + surgery_text += ", [S.operated_bodypart]" + msg += "[surgery_text].\n" if(HAS_TRAIT(src, TRAIT_DUMB)) msg += "[t_He] seem[p_s()] to be clumsy and unable to think.\n" diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm index 324beccad878..60a34b30803d 100644 --- a/code/modules/mob/living/carbon/human/examine.dm +++ b/code/modules/mob/living/carbon/human/examine.dm @@ -206,7 +206,15 @@ msg += "[t_He] [t_has] moderate cellular damage!\n" else msg += "[t_He] [t_has] severe cellular damage!\n" - + + if(surgeries.len) + var/surgery_text + for(var/datum/surgery/S in surgeries) + if(!surgery_text) + surgery_text = "[t_He] [t_is] being operated on in \the [S.operated_bodypart]" + else + surgery_text += ", [S.operated_bodypart]" + msg += "[surgery_text].\n" if(fire_stacks > 0) msg += "[t_He] [t_is] covered in something flammable.\n" diff --git a/code/modules/surgery/advanced/lobotomy.dm b/code/modules/surgery/advanced/lobotomy.dm index 0bec7ca1f1f5..c90b40a15eba 100644 --- a/code/modules/surgery/advanced/lobotomy.dm +++ b/code/modules/surgery/advanced/lobotomy.dm @@ -1,6 +1,7 @@ /datum/surgery/advanced/lobotomy name = "Lobotomy" desc = "An invasive surgical procedure which guarantees removal of almost all brain traumas, but might cause another permanent trauma in return." + icon_state = "lobotomy" steps = list( /datum/surgery_step/incise, /datum/surgery_step/retract_skin, diff --git a/code/modules/surgery/advanced/revival.dm b/code/modules/surgery/advanced/revival.dm index 2981a884f526..164d1fedb60d 100644 --- a/code/modules/surgery/advanced/revival.dm +++ b/code/modules/surgery/advanced/revival.dm @@ -1,6 +1,7 @@ /datum/surgery/advanced/revival name = "Revival" desc = "An experimental surgical procedure which involves reconstruction and reactivation of the patient's brain even long after death. The body must still be able to sustain life." + icon_state = "revival" steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, diff --git a/code/modules/surgery/amputation.dm b/code/modules/surgery/amputation.dm index 5ad199d41ff6..6a357e482b95 100644 --- a/code/modules/surgery/amputation.dm +++ b/code/modules/surgery/amputation.dm @@ -1,6 +1,8 @@ /datum/surgery/amputation name = "Amputation" + icon_state = "amputation" + desc = "Sever a limb from the torso." steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/sever_limb) target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_HEAD) diff --git a/code/modules/surgery/autopsy.dm b/code/modules/surgery/autopsy.dm index 331a4fb9b4e3..995ca5ec1c94 100644 --- a/code/modules/surgery/autopsy.dm +++ b/code/modules/surgery/autopsy.dm @@ -1,6 +1,9 @@ /datum/surgery/autopsy name = "Autopsy" + desc = "Tells you what last damaged the patient." + icon = 'icons/obj/surgery.dmi' + icon_state = "scalpel" steps = list(/datum/surgery_step/incise, /datum/surgery_step/autopsy) target_mobtypes = list(/mob/living) diff --git a/code/modules/surgery/brain_surgery.dm b/code/modules/surgery/brain_surgery.dm index 953862939643..1d764536b704 100644 --- a/code/modules/surgery/brain_surgery.dm +++ b/code/modules/surgery/brain_surgery.dm @@ -1,5 +1,8 @@ /datum/surgery/brain_surgery name = "Brain surgery" + desc = "This procedure cures all severe and basic traumas and reduces brain damage by a large amount. Failing to fix the brain causes hefty brain damage." + icon = 'icons/obj/surgery.dmi' + icon_state = "brain" steps = list( /datum/surgery_step/incise, /datum/surgery_step/retract_skin, diff --git a/code/modules/surgery/cavity_implant.dm b/code/modules/surgery/cavity_implant.dm index c85e68b73b66..fc8faf3b667e 100644 --- a/code/modules/surgery/cavity_implant.dm +++ b/code/modules/surgery/cavity_implant.dm @@ -1,5 +1,8 @@ /datum/surgery/cavity_implant name = "Cavity implant" + desc = "Implants or removes an object in the chest. Items up to normal size can be implanted, but tiny and small items won't show what they are in the implanting messages." + icon = 'icons/obj/lighting.dmi' + icon_state = "flashlight" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/incise, /datum/surgery_step/handle_cavity, /datum/surgery_step/close) target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_CHEST) diff --git a/code/modules/surgery/core_removal.dm b/code/modules/surgery/core_removal.dm index 9155cf201235..32be2db283f0 100644 --- a/code/modules/surgery/core_removal.dm +++ b/code/modules/surgery/core_removal.dm @@ -1,5 +1,8 @@ /datum/surgery/core_removal name = "Core removal" + desc = "Remove core from slime. Extract core must be repeated for every core if slime has several." + icon = 'icons/mob/slimes.dmi' + icon_state = "grey slime extract" steps = list(/datum/surgery_step/incise, /datum/surgery_step/extract_core) target_mobtypes = list(/mob/living/simple_animal/slime) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) diff --git a/code/modules/surgery/coronary_bypass.dm b/code/modules/surgery/coronary_bypass.dm index 2af4c91b3f88..86c32a148482 100644 --- a/code/modules/surgery/coronary_bypass.dm +++ b/code/modules/surgery/coronary_bypass.dm @@ -1,5 +1,8 @@ /datum/surgery/coronary_bypass name = "Coronary Bypass" + desc = "Restores the heart to a functional state if it is in a non-functional state, making it able to be defibrillated and sustain life. Can only be performed once on an individual heart." + icon = 'icons/obj/surgery.dmi' + icon_state = "heart-off" steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/incise_heart, /datum/surgery_step/coronary_bypass, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_CHEST) diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm index f0457cdc6b39..965d6cd03f59 100644 --- a/code/modules/surgery/dental_implant.dm +++ b/code/modules/surgery/dental_implant.dm @@ -1,5 +1,8 @@ /datum/surgery/dental_implant name = "Dental implant" + desc = "This allows you to insert pills/patches into a tooth cavity, allowing you to pop it any time to ingest it. This works for both stimulants and suicide pills." + icon = 'icons/obj/implants.dmi' + icon_state = "reagents" steps = list(/datum/surgery_step/drill, /datum/surgery_step/insert_pill) possible_locs = list(BODY_ZONE_PRECISE_MOUTH) diff --git a/code/modules/surgery/experimental_dissection.dm b/code/modules/surgery/experimental_dissection.dm index cfa5b4f8ae80..09bd2b66f8fc 100644 --- a/code/modules/surgery/experimental_dissection.dm +++ b/code/modules/surgery/experimental_dissection.dm @@ -1,6 +1,8 @@ /datum/surgery/experimental_dissection name = "Experimental Dissection" desc = "A surgical procedure which deeply analyzes the biology of a corpse, and automatically adds new findings to the research database." + icon = 'icons/obj/implants.dmi' + icon_state = "scan_mode" steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/clamp_bleeders, diff --git a/code/modules/surgery/eye_surgery.dm b/code/modules/surgery/eye_surgery.dm index 6c5661c86503..4f41fb3a1308 100644 --- a/code/modules/surgery/eye_surgery.dm +++ b/code/modules/surgery/eye_surgery.dm @@ -1,5 +1,8 @@ /datum/surgery/eye_surgery name = "Eye surgery" + desc = "Fixes all damage done to eyes, though doesnt fix genetic blindness. Failing to fix the eyes will cause brain damage to the patient." + icon = 'icons/obj/surgery.dmi' + icon_state = "eyeballs" steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/fix_eyes, /datum/surgery_step/close) target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_PRECISE_EYES) diff --git a/code/modules/surgery/healing.dm b/code/modules/surgery/healing.dm index 3735e1185038..421c1eb3f19c 100644 --- a/code/modules/surgery/healing.dm +++ b/code/modules/surgery/healing.dm @@ -1,4 +1,5 @@ /datum/surgery/healing + icon = 'icons/obj/chemical.dmi' steps = list(/datum/surgery_step/incise, /datum/surgery_step/heal, /datum/surgery_step/close) @@ -105,6 +106,7 @@ /***************************BRUTE***************************/ /datum/surgery/healing/brute name = "Tend Wounds (Bruises)" + icon_state = "bandaid_brute" /datum/surgery/healing/brute/basic name = "Tend Wounds (Bruises, Basic)" @@ -170,6 +172,7 @@ /***************************BURN***************************/ /datum/surgery/healing/burn name = "Tend Wounds (Burn)" + icon_state = "bandaid_burn" /datum/surgery/healing/burn/basic name = "Tend Wounds (Burn, Basic)" @@ -236,6 +239,7 @@ /datum/surgery/healing/combo name = "Tend Wounds (Mixture, Basic)" + icon_state = "bandaid_both" replaced_by = /datum/surgery/healing/combo/upgraded requires_tech = TRUE healing_step_type = /datum/surgery_step/heal/combo diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm index 9304f1be5528..507b7bef2244 100644 --- a/code/modules/surgery/helpers.dm +++ b/code/modules/surgery/helpers.dm @@ -19,6 +19,7 @@ if(!current_surgery) var/list/all_surgeries = GLOB.surgeries_list.Copy() var/list/available_surgeries = list() + var/list/radial_list = list() for(var/datum/surgery/S in all_surgeries) if(!S.possible_locs.Find(selected_zone)) @@ -39,12 +40,17 @@ for(var/path in S.target_mobtypes) if(istype(M, path)) available_surgeries[S.name] = S + var/datum/radial_menu_choice/choice = new + choice.image = S.get_icon() + choice.info = S.desc + radial_list[S.name] = choice break if(!available_surgeries.len) + to_chat(user, span_warning("You can't preform any surgeries on [M]'s [parse_zone(selected_zone)]!")) return - - var/P = input("Begin which procedure?", "Surgery", null, null) as null|anything in available_surgeries + + var/P = show_radial_menu(user, M, radial_list, radius = 40, require_near = TRUE, tooltips = TRUE) if(P && user && user.Adjacent(M) && (I in user)) var/datum/surgery/S = available_surgeries[P] @@ -69,11 +75,17 @@ if(S.ignore_clothes || get_location_accessible(M, selected_zone)) var/datum/surgery/procedure = new S.type(M, selected_zone, affecting) - user.visible_message("[user] drapes [I] over [M]'s [parse_zone(selected_zone)] to prepare for surgery.", \ - span_notice("You drape [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].")) + var/datum/surgery_step/step = procedure.get_surgery_step() + user.visible_message("[user] prepares to operate on [M]'s [parse_zone(selected_zone)].", \ + span_notice("You prepare to operate on [M]'s [parse_zone(selected_zone)].")) playsound(get_turf(M), 'sound/items/handling/cloth_drop.ogg', 30, TRUE, falloff = 1) - log_combat(user, M, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])") + if(procedure.step_in_progress) + return + var/try_to_fail = FALSE + if(user.a_intent == INTENT_DISARM) + try_to_fail = TRUE + step.try_op(user, M, user.zone_selected, I, procedure, try_to_fail) else to_chat(user, span_warning("You need to expose [M]'s [parse_zone(selected_zone)] first!")) @@ -84,26 +96,25 @@ /proc/attempt_cancel_surgery(datum/surgery/S, obj/item/I, mob/living/M, mob/user) var/selected_zone = user.zone_selected + to_chat(user, span_notice("You begin to cancel \the [S].")) + if(!do_mob(user, M, 3 SECONDS)) + return if(S.status == 1) M.surgeries -= S - user.visible_message("[user] removes [I] from [M]'s [parse_zone(selected_zone)].", \ - span_notice("You remove [I] from [M]'s [parse_zone(selected_zone)].")) + user.visible_message("[user] stops the surgery on [M]'s [parse_zone(selected_zone)].", \ + span_notice("You stop the surgery on [M]'s [parse_zone(selected_zone)].")) qdel(S) else if(S.can_cancel) - var/close_tool_type = /obj/item/cautery - var/obj/item/close_tool = user.get_inactive_held_item() - var/is_robotic = S.requires_bodypart_type == BODYPART_ROBOTIC - if(is_robotic) - close_tool_type = /obj/item/screwdriver - if(istype(close_tool, close_tool_type) || iscyborg(user)) + var/obj/item/close_tool = user.get_active_held_item() + if(close_tool.tool_behaviour == (S.requires_bodypart_type == BODYPART_ROBOTIC ? TOOL_SCREWDRIVER : TOOL_CAUTERY) || iscyborg(user)) if(S.operated_bodypart) S.operated_bodypart.generic_bleedstacks -= 10 M.surgeries -= S - user.visible_message("[user] closes [M]'s [parse_zone(selected_zone)] with [close_tool] and removes [I].", \ - span_notice("You close [M]'s [parse_zone(selected_zone)] with [close_tool] and remove [I].")) + user.visible_message("[user] closes [M]'s [parse_zone(selected_zone)] with [close_tool].", \ + span_notice("You close [M]'s [parse_zone(selected_zone)] with [close_tool].")) qdel(S) else - to_chat(user, span_warning("You need to hold a [is_robotic ? "screwdriver" : "cautery"] in your inactive hand to stop [M]'s surgery!")) + to_chat(user, span_warning("You need to hold a [S.requires_bodypart_type == BODYPART_ROBOTIC ? "screwdriver" : "cautery"] in your active hand to stop [M]'s surgery!")) /proc/get_location_modifier(mob/M) var/turf/T = get_turf(M) diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm index 24e40312d8b2..5ead081c0fc8 100644 --- a/code/modules/surgery/implant_removal.dm +++ b/code/modules/surgery/implant_removal.dm @@ -1,5 +1,8 @@ /datum/surgery/implant_removal name = "implant removal" + desc = "Extracts implants from the patient. If you don't have an empty implant case in your other hand, the implant will be ruined on extraction." + icon = 'icons/obj/implants.dmi' + icon_state = "implantcase-b" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/extract_implant, /datum/surgery_step/close) target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_CHEST) diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index 25c0deb4f370..56405fb1a813 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -45,6 +45,8 @@ /datum/surgery/augmentation name = "Augmentation" + desc = "Replace a limb with a robot part." + icon_state = "augmentation" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/replace, /datum/surgery_step/saw, /datum/surgery_step/replace_limb) target_mobtypes = list(/mob/living/carbon/human) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) diff --git a/code/modules/surgery/lipoplasty.dm b/code/modules/surgery/lipoplasty.dm index 80d399676eb5..59e0a9b60b30 100644 --- a/code/modules/surgery/lipoplasty.dm +++ b/code/modules/surgery/lipoplasty.dm @@ -1,5 +1,8 @@ /datum/surgery/lipoplasty name = "Lipoplasty" + desc = "Removes excess fat from the patient." + icon = 'icons/obj/food/food.dmi' + icon_state = "meat" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/cut_fat, /datum/surgery_step/remove_fat, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_CHEST) diff --git a/code/modules/surgery/lobectomy.dm b/code/modules/surgery/lobectomy.dm index fa9dabfb0c0c..c73fc138b767 100644 --- a/code/modules/surgery/lobectomy.dm +++ b/code/modules/surgery/lobectomy.dm @@ -1,5 +1,8 @@ /datum/surgery/lobectomy name = "Lobectomy" //not to be confused with lobotomy + desc = "Restores the lungs to a functional state if it is in a non-functional state, making it able to sustain life. Can only be performed once on an individual set of lungs." + icon = 'icons/obj/surgery.dmi' + icon_state = "lungs" steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/saw, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/lobectomy, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_CHEST) diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index da0a825d689b..a27f68fdb38b 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -1,5 +1,7 @@ /datum/surgery/organ_manipulation name = "Organ manipulation" + icon_state = "organ_manipulation" + desc = "This surgery covers operations to remove/insert internal organs, tails, and cyber implants." target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_CHEST, BODY_ZONE_HEAD) requires_real_bodypart = 1 diff --git a/code/modules/surgery/organs/augments_arms.dm b/code/modules/surgery/organs/augments_arms.dm index 10833bf57762..a1140682a993 100644 --- a/code/modules/surgery/organs/augments_arms.dm +++ b/code/modules/surgery/organs/augments_arms.dm @@ -325,8 +325,7 @@ /obj/item/toolset_handler/attack(mob/living/M, mob/user) if(active_tool) - if(istype(active_tool, /obj/item/surgical_drapes)) //of all the things to not have a tool behavior its drapes - attempt_initiate_surgery(src, M, user) + if(!(user.a_intent == INTENT_HARM) && attempt_initiate_surgery(active_tool, M, user)) return ..() diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm index f5dcbdcd139b..374aef33655b 100644 --- a/code/modules/surgery/plastic_surgery.dm +++ b/code/modules/surgery/plastic_surgery.dm @@ -1,5 +1,7 @@ /datum/surgery/plastic_surgery name = "Plastic surgery" + desc = "If the patient's face is damaged and unrecognizable it restores it, otherwise it change the face and identity of the patient." + icon_state = "plastic_surgery" steps = list(/datum/surgery_step/incise, /datum/surgery_step/retract_skin, /datum/surgery_step/reshape_face, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_HEAD) diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm index e158067b4ba6..e7adaf10ca54 100644 --- a/code/modules/surgery/prosthetic_replacement.dm +++ b/code/modules/surgery/prosthetic_replacement.dm @@ -1,5 +1,7 @@ /datum/surgery/prosthetic_replacement name = "Prosthetic replacement" + desc = "Replace a severed limb with either a normal or a robotic limb." + icon_state = "prosthetic_replacement" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/retract_skin, /datum/surgery_step/add_prosthetic) target_mobtypes = list(/mob/living/carbon/human, /mob/living/carbon/monkey) possible_locs = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG, BODY_ZONE_HEAD) diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm index 3b4f542f5d3a..1ef83e512b6c 100644 --- a/code/modules/surgery/remove_embedded_object.dm +++ b/code/modules/surgery/remove_embedded_object.dm @@ -1,8 +1,16 @@ /datum/surgery/embedded_removal name = "Removal of embedded objects" + desc = "Extracts objects stuck in the body such as throwing stars or spears." + icon_state = "embedded_removal" steps = list(/datum/surgery_step/incise, /datum/surgery_step/remove_object, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) +/datum/surgery/repair_bone_hairline/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) + return(targeted_bodypart.embedded_objects) /datum/surgery_step/remove_object name = "remove embedded objects" @@ -13,7 +21,6 @@ var/obj/item/target_item = null var/obj/item/bodypart/L = null - /datum/surgery_step/remove_object/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) L = surgery.operated_bodypart if(L) diff --git a/code/modules/surgery/repair_puncture.dm b/code/modules/surgery/repair_puncture.dm index 7a13400394f1..59936f641564 100644 --- a/code/modules/surgery/repair_puncture.dm +++ b/code/modules/surgery/repair_puncture.dm @@ -8,6 +8,8 @@ ///// Repair puncture wounds /datum/surgery/repair_puncture name = "Repair puncture" + icon = 'icons/obj/stack_medical.dmi' + icon_state = "suture_3" steps = list(/datum/surgery_step/incise, /datum/surgery_step/repair_innards, /datum/surgery_step/seal_veins, /datum/surgery_step/close) // repeat between steps 2 and 3 until healed target_mobtypes = list(/mob/living/carbon) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) diff --git a/code/modules/surgery/stomachpump.dm b/code/modules/surgery/stomachpump.dm index 45b57042b1ed..dfe41cc6608c 100644 --- a/code/modules/surgery/stomachpump.dm +++ b/code/modules/surgery/stomachpump.dm @@ -1,5 +1,7 @@ /datum/surgery/stomach_pump name = "Stomach Pump" + icon = 'icons/obj/surgery.dmi' + icon_state = "stomach" steps = list( /datum/surgery_step/incise, /datum/surgery_step/retract_skin, diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index 6e8e6506fa7d..eae199ee97b5 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -1,26 +1,47 @@ /datum/surgery var/name = "surgery" var/desc = "surgery description" + var/icon = 'icons/misc/surgery_icons.dmi' + var/icon_state var/status = 1 - var/list/steps = list() //Steps in a surgery - var/step_in_progress = 0 //Actively performing a Surgery - var/can_cancel = 1 //Can cancel this surgery after step 1 with cautery - var/list/target_mobtypes = list(/mob/living/carbon/human) //Acceptable Species - var/location = BODY_ZONE_CHEST //Surgery location - var/requires_bodypart_type = BODYPART_ORGANIC //Prevents you from performing an operation on incorrect limbs. 0 for any limb type - var/list/possible_locs = list() //Multiple locations - var/ignore_clothes = 0 //This surgery ignores clothes - var/mob/living/carbon/target //Operation target mob - var/obj/item/bodypart/operated_bodypart //Operable body part - var/datum/wound/operated_wound //The actual wound datum instance we're targeting - var/datum/wound/targetable_wound //The wound type this surgery targets - var/requires_bodypart = TRUE //Surgery available only when a bodypart is present, or only when it is missing. - var/success_multiplier = 0 //Step success propability multiplier - var/requires_real_bodypart = 0 //Some surgeries don't work on limbs that don't really exist - var/lying_required = TRUE //Does the vicitm needs to be lying down. - var/self_operable = FALSE //Can the surgery be performed on yourself. - var/requires_tech = FALSE //handles techweb-oriented surgeries, previously restricted to the /advanced subtype (You still need to add designs) - var/replaced_by //type; doesn't show up if this type exists. Set to /datum/surgery if you want to hide a "base" surgery (useful for typing parents IE healing.dm just make sure to null it out again) + /// Steps in a surgery + var/list/steps = list() + /// Actively performing a Surgery + var/step_in_progress = 0 + /// Can cancel this surgery after step 1 with cautery + var/can_cancel = 1 + /// Acceptable Species + var/list/target_mobtypes = list(/mob/living/carbon/human) + /// Surgery location + var/location = BODY_ZONE_CHEST + /// Prevents you from performing an operation on incorrect limbs. FALSE for any limb type + var/requires_bodypart_type = BODYPART_ORGANIC + /// Multiple locations + var/list/possible_locs = list() + /// If this surgery ignores clothes + var/ignore_clothes = 0 + /// Operation target mob + var/mob/living/carbon/target + /// Operable body part + var/obj/item/bodypart/operated_bodypart + /// The actual wound datum instance we're targeting + var/datum/wound/operated_wound + /// The wound type this surgery targets + var/datum/wound/targetable_wound + /// Surgery available only when a bodypart is present, or only when it is missing. + var/requires_bodypart = TRUE + /// Step success propability multiplier + var/success_multiplier = 0 + /// Some surgeries don't work on limbs that don't really exist + var/requires_real_bodypart = 0 + /// Does the vicitm needs to be lying down. + var/lying_required = TRUE + /// Can the surgery be performed on yourself. + var/self_operable = FALSE + /// Handles techweb-oriented surgeries, previously restricted to the /advanced subtype (You still need to add designs) + var/requires_tech = FALSE + /// Type; doesn't show up if this type exists. Set to /datum/surgery if you want to hide a "base" surgery (useful for typing parents IE healing.dm just make sure to null it out again) + var/replaced_by /datum/surgery/New(surgery_target, surgery_location, surgery_bodypart) ..() @@ -114,9 +135,14 @@ var/obj/item/tool = user.get_active_held_item() if(S.try_op(user, target, user.zone_selected, tool, src, try_to_fail)) return TRUE - if(tool.item_flags & SURGICAL_TOOL) //Just because you used the wrong tool it doesn't mean you meant to whack the patient with it - to_chat(user, span_warning("This step requires a different tool!")) - return TRUE + if(tool) + if(tool.tool_behaviour == TOOL_CAUTERY || (requires_bodypart_type == BODYPART_ROBOTIC && tool.tool_behaviour == TOOL_SCREWDRIVER)) + // Cancel the surgery if a cautery/screwdriver is used AND it's not the tool used in the next step. + attempt_cancel_surgery(src, tool, target, user) + return TRUE + if(tool.item_flags & SURGICAL_TOOL) //Just because you used the wrong tool it doesn't mean you meant to whack the patient with it + to_chat(user, span_warning("This step requires a different tool!")) + return TRUE return FALSE /datum/surgery/proc/get_surgery_step() @@ -147,6 +173,9 @@ return probability + success_multiplier +/datum/surgery/proc/get_icon() + return icon(icon, icon_state) + /datum/surgery/advanced name = "advanced surgery" requires_tech = TRUE diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index 92714731a597..2dc56a6b5f3d 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -113,6 +113,14 @@ prob_chance = implements[implement_type] prob_chance *= surgery.get_probability_multiplier() + // Blood splatters on tools and user + if(tool && prob(20)) + tool.add_mob_blood(target) + to_chat(user, span_warning("Your [tool] gets covered [target]'s blood ")) + if(prob(10)) + user.add_mob_blood(target) + to_chat(user, span_warning("You get covered [target]'s blood ")) + if((prob(prob_chance) || iscyborg(user)) && chem_check(target, user, tool) && !try_to_fail) if(success(user, target, target_zone, tool, surgery)) @@ -121,6 +129,7 @@ else if(failure(user, target, target_zone, tool, surgery)) play_failure_sound(user, target, target_zone, tool, surgery) + advance = TRUE if(!HAS_TRAIT(target, TRAIT_SURGERY_PREPARED) && target.stat != DEAD && !IS_IN_STASIS(target) && fuckup_damage) //not under the effects of anaesthetics or a strong painkiller, harsh penalty to success chance if(!issilicon(user) && !HAS_TRAIT(user, TRAIT_SURGEON)) //borgs and abductors are immune to this @@ -154,7 +163,7 @@ break else sound_file_use = preop_sound - playsound(get_turf(target), sound_file_use, 75, TRUE, falloff = 1) + playsound(get_turf(target), sound_file_use, 30, TRUE, falloff = 2) /datum/surgery_step/proc/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) display_results(user, target, span_notice("You succeed."), @@ -173,7 +182,7 @@ break else sound_file_use = success_sound - playsound(get_turf(target), sound_file_use, 75, TRUE, falloff = 1) + playsound(get_turf(target), sound_file_use, 30, TRUE, falloff = 2) /datum/surgery_step/proc/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) display_results(user, target, span_warning("You screw up!"), @@ -192,7 +201,7 @@ break else sound_file_use = failure_sound - playsound(get_turf(target), sound_file_use, 75, TRUE, falloff = 1) + playsound(get_turf(target), sound_file_use, 30, TRUE, falloff = 2) /datum/surgery_step/proc/tool_check(mob/user, obj/item/tool) return TRUE diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index 5576ac42ed1b..577773fe4322 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -12,6 +12,9 @@ tool_behaviour = TOOL_RETRACTOR w_class = WEIGHT_CLASS_TINY +/obj/item/retractor/attack(mob/living/M, mob/user) + if(user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) + ..() /obj/item/retractor/augment name = "retractor" @@ -45,6 +48,9 @@ w_class = WEIGHT_CLASS_TINY attack_verb = list("attacked", "pinched") +/obj/item/hemostat/attack(mob/living/M, mob/user) + if(user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) + ..() /obj/item/hemostat/augment name = "hemostat" @@ -79,6 +85,9 @@ w_class = WEIGHT_CLASS_TINY attack_verb = list("burnt") +/obj/item/cautery/attack(mob/living/M, mob/user) + if(user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) + ..() /obj/item/cautery/augment name = "cautery" @@ -125,6 +134,9 @@ SSachievements.unlock_achievement(/datum/achievement/likearecord, user.client) return (MANUAL_SUICIDE) +/obj/item/surgicaldrill/attack(mob/living/M, mob/user) + if(user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) + ..() /obj/item/surgicaldrill/augment name = "surgical drill" @@ -167,6 +179,10 @@ . = ..() AddComponent(/datum/component/butchering, 80 * toolspeed, 100, 0) +/obj/item/scalpel/attack(mob/living/M, mob/user) + if(user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) + ..() + /obj/item/scalpel/augment name = "scalpel" desc = "Ultra-sharp blade attached directly to your bone for extra-accuracy." @@ -222,6 +238,10 @@ . = ..() AddComponent(/datum/component/butchering, 40 * toolspeed, 100, 5, 'sound/weapons/circsawhit.ogg') //saws are very accurate and fast at butchering +/obj/item/circular_saw/attack(mob/living/M, mob/user) + if(user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) + ..() + /obj/item/circular_saw/augment name = "circular saw" desc = "A small but very fast spinning saw. Edges dulled to prevent accidental cutting inside of the surgeon." @@ -258,6 +278,10 @@ w_class = WEIGHT_CLASS_SMALL attack_verb = list("corrected", "properly set") +/obj/item/bonesetter/attack(mob/living/M, mob/user) + if(user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) + ..() + /obj/item/bonesetter/bone name = "bone bonesetter" desc = "A bonesetter made of bones... for setting bones with... bones?" @@ -276,7 +300,7 @@ attack_verb = list("slapped") /obj/item/surgical_drapes/attack(mob/living/M, mob/user) - if(!attempt_initiate_surgery(src, M, user)) + if(user.a_intent == INTENT_HARM || !attempt_initiate_surgery(src, M, user)) ..() /obj/item/surgical_drapes/goliath diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi index aa03f6b641a9..dcd970251cf5 100644 Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ diff --git a/icons/misc/surgery_icons.dmi b/icons/misc/surgery_icons.dmi new file mode 100644 index 000000000000..9d2abbf3b180 Binary files /dev/null and b/icons/misc/surgery_icons.dmi differ diff --git a/yogstation/code/modules/surgery/gender_reassignment.dm b/yogstation/code/modules/surgery/gender_reassignment.dm index 25cf89fcada7..c9f040a0225d 100644 --- a/yogstation/code/modules/surgery/gender_reassignment.dm +++ b/yogstation/code/modules/surgery/gender_reassignment.dm @@ -1,5 +1,7 @@ /datum/surgery/gender_reassignment name = "gender reassignment" + desc = "This surgery reassigns a person's gender that of the opposite sex. Failure may result in gender ambiguity." + icon_state = "gender_change" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/reshape_genitals, @@ -42,4 +44,4 @@ user.visible_message(span_warning("[user] accidentally mutilates [target]'s genitals beyond the point of recognition!"), span_warning("You accidentally mutilate [target]'s genitals beyond the point of recognition!")) target.gender = pick(MALE, FEMALE) target.regenerate_icons() - return 1 \ No newline at end of file + return 1 diff --git a/yogstation/code/modules/surgery/healing_surgeries.dm b/yogstation/code/modules/surgery/healing_surgeries.dm index 527a7f4e1330..d30634f5ab2b 100644 --- a/yogstation/code/modules/surgery/healing_surgeries.dm +++ b/yogstation/code/modules/surgery/healing_surgeries.dm @@ -65,10 +65,16 @@ //surgeries go here /datum/surgery/heal_brute name = "patch wounds" + desc = "Heals a body part of brute damage. Useful for allowing a body to be defibrillated." + icon = 'icons/obj/stack_medical.dmi' + icon_state = "brutepack_3" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/debride, /datum/surgery_step/apply_dressing, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD) /datum/surgery/heal_burn name = "treat burns" + desc = "Heals a body part of burn damage. Useful for allowing a body to be defibrillated." + icon = 'icons/obj/stack_medical.dmi' + icon_state = "ointment_3" steps = list(/datum/surgery_step/incise, /datum/surgery_step/clamp_bleeders, /datum/surgery_step/debride, /datum/surgery_step/apply_dressing/burn, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_R_ARM,BODY_ZONE_L_ARM,BODY_ZONE_R_LEG,BODY_ZONE_L_LEG,BODY_ZONE_CHEST,BODY_ZONE_HEAD)