diff --git a/beestation.dme b/beestation.dme index a58e4eb9e3f6c..639846d2d7fe1 100644 --- a/beestation.dme +++ b/beestation.dme @@ -254,6 +254,7 @@ #include "code\__HELPERS\level_traits.dm" #include "code\__HELPERS\maths.dm" #include "code\__HELPERS\matrices.dm" +#include "code\__HELPERS\mob_bodyzone.dm" #include "code\__HELPERS\mobs.dm" #include "code\__HELPERS\mouse_control.dm" #include "code\__HELPERS\names.dm" @@ -2342,6 +2343,7 @@ #include "code\modules\client\preferences\entries\player\tooltips.dm" #include "code\modules\client\preferences\entries\player\ui_style.dm" #include "code\modules\client\preferences\entries\player\window_flashing.dm" +#include "code\modules\client\preferences\entries\player\zone_selection.dm" #include "code\modules\client\preferences\middleware\_middleware.dm" #include "code\modules\client\preferences\middleware\antags.dm" #include "code\modules\client\preferences\middleware\jobs.dm" diff --git a/code/__DEFINES/async.dm b/code/__DEFINES/async.dm index c33f361b9a987..8825de5a30777 100644 --- a/code/__DEFINES/async.dm +++ b/code/__DEFINES/async.dm @@ -17,9 +17,13 @@ #define ASYNC_RETURN(value) created_task.mark_completed(value);\ return; +#define ASYNC_RETURN_TASK(value) return value; + /// Waits for the provided task to be completed, or the timeout to expire. /// Returns null if the timeout expires, or the task's result otherwise. /// Note that if a task's result is null, then null will be returned. +/// This adds a delay for long periods of waiting, so using continue_with +/// is preferred. #define AWAIT(TASK, TIMEOUT) get_result(TASK, TIMEOUT) /proc/get_result(datum/task/task, timeout) diff --git a/code/__DEFINES/bodyparts.dm b/code/__DEFINES/bodyparts.dm index c3d51099e3fb3..a17da968ca9af 100644 --- a/code/__DEFINES/bodyparts.dm +++ b/code/__DEFINES/bodyparts.dm @@ -1 +1,8 @@ #define IS_ORGANIC_LIMB(A) (A.bodytype & BODYTYPE_ORGANIC) + +#define BODYZONE_STYLE_DEFAULT 0 +#define BODYZONE_STYLE_MEDICAL 1 + +#define BODYZONE_CONTEXT_COMBAT 0 +#define BODYZONE_CONTEXT_INJECTION 1 +#define BODYZONE_CONTEXT_ROBOTIC_LIMB_HEALING 2 diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index e74c112a47600..d82eac619e6ca 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -254,6 +254,10 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list( #define GRENADE_NONCLUMSY_FUMBLE 2 #define GRENADE_NO_FUMBLE 3 +#define BODY_GROUP_CHEST_HEAD "chesthead" +#define BODY_GROUP_LEGS "legs" +#define BODY_GROUP_ARMS "arms" + #define BODY_ZONE_HEAD "head" #define BODY_ZONE_CHEST "chest" #define BODY_ZONE_L_ARM "l_arm" diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index fa5b2cbe52b52..1d7fb760ea26c 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -66,6 +66,8 @@ #define COMSIG_KB_MOB_TARGETRIGHTLEG_DOWN "keybinding_mob_targetrightleg_down" #define COMSIG_KB_MOB_TARGETBODYGROIN_DOWN "keybinding_mob_targetbodygroin_down" #define COMSIG_KB_MOB_TARGETLEFTLEG_DOWN "keybinding_mob_targetleftleg_down" +#define COMSIG_KB_MOB_TARGETCYCLEUP_DOWN "keybinding_mob_targetcycleup_down" +#define COMSIG_KB_MOB_TARGETCYCLEDOWN_DOWN "keybinding_mob_targetcycledown_down" #define COMSIG_KB_MOB_PREVENTMOVEMENT_DOWN "keybinding_mob_preventmovement_down" #define COMSIG_KB_MOB_MOVEUP_DOWN "keybinding_mob_moveup_down" #define COMSIG_KB_MOB_MOVEDOWN_DOWN "keybinding_mob_movedown_down" diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index c9da8c7c4b4a1..d43c028ae2f26 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -178,6 +178,9 @@ GLOBAL_PROTECT(undatumized_preference_tags_character) #define PREFERENCE_SHEET_LARGE "preferences_l" #define PREFERENCE_SHEET_HUGE "preferences_h" +#define PREFERENCE_BODYZONE_SIMPLIFIED "Simplified Targeting" // Use the simplified system +#define PREFERENCE_BODYZONE_INTENT "Precise Targeting" // Use the bodyzone intent system + /// Stop loading immediately, inform the user. Do not save the data. #define PREFERENCE_LOAD_ERROR 0 /// There is no data to load, they are a guest and will never have this data. @@ -186,3 +189,4 @@ GLOBAL_PROTECT(undatumized_preference_tags_character) #define PREFERENCE_LOAD_NO_DATA 2 /// Normal behavior - success! #define PREFERENCE_LOAD_SUCCESS 3 + diff --git a/code/__HELPERS/mob_bodyzone.dm b/code/__HELPERS/mob_bodyzone.dm new file mode 100644 index 0000000000000..1c5c4e59dff74 --- /dev/null +++ b/code/__HELPERS/mob_bodyzone.dm @@ -0,0 +1,142 @@ + +#define NOT_PRESENT_COLOUR "#0d0d0d" +#define FULL_HEALTH_COLOUR "#11ff00" +#define LOW_DAMAGE_COLOUR "#d9ff00" +#define POOR_HEALTH_COLOUR "#ff0000" + +/// Displays a UI around the target allowing the user to select which bodypart +/// that they want to act on. +/// Target: The location to show the user interface. +/// Precise: Toggle to include groin, eyes and mouth. If true, implies hide_non_present will be forced to false. +/// Icon Callback: The callback to run in order to get the selection zone overlay. +/// If you want to wait for the result use: AWAIT(select_bodyzone(target)) +/mob/proc/select_bodyzone_from_wheel(atom/target, precise = FALSE, datum/callback/icon_callback, override_zones = null) + DECLARE_ASYNC + if (!client || !client.prefs) + ASYNC_RETURN(null) + if (!icon_callback) + icon_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(select_bodyzone_limb_default)) + // Determine what parts we want to show + var/list/bodyzone_options = list() + var/list/parts = list(BODY_ZONE_HEAD, BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_CHEST, BODY_ZONE_R_LEG, BODY_ZONE_R_ARM) + if (override_zones) + parts = override_zones + for (var/bodyzone in parts) + var/image/created_image = image(icon = ui_style2icon(client.prefs?.read_player_preference(/datum/preference/choiced/ui_style)), icon_state = "zone_sel") + var/selection_overlay = icon_callback.Invoke(src, target, bodyzone, FALSE) + created_image.overlays += selection_overlay + bodyzone_options[bodyzone] = created_image + var/result = show_radial_menu(src, target, bodyzone_options, radius = 40, require_near = TRUE, tooltips = TRUE) + + // Disconnected or no result + if (!result || !client) + ASYNC_RETURN(null) + + // Let the user choose more zones + var/list/suboptions = null + if (precise && result == BODY_ZONE_HEAD) + suboptions = list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH) + else if (precise && result == BODY_ZONE_CHEST) + suboptions = list(BODY_ZONE_CHEST, BODY_ZONE_PRECISE_GROIN) + + if (suboptions) + bodyzone_options = list() + for (var/bodyzone in suboptions) + var/image/created_image = image(icon = ui_style2icon(client.prefs?.read_player_preference(/datum/preference/choiced/ui_style)), icon_state = "zone_sel") + var/selection_overlay = icon_callback.Invoke(src, target, bodyzone, !(bodyzone in parts)) + created_image.overlays += selection_overlay + bodyzone_options[bodyzone] = created_image + result = show_radial_menu(src, target, bodyzone_options, radius = 40, require_near = TRUE, tooltips = TRUE) + + // Disconnected or no result + if (!result || !client) + ASYNC_RETURN(null) + if (!(result in parts) && !(result in suboptions)) + ASYNC_RETURN(null) + ASYNC_RETURN(result) + +/proc/select_bodyzone_limb_default( mob/user, atom/target, bodyzone, is_precise_part = FALSE) + // Create the overlay + var/image/selection_overlay = image(icon = 'icons/mob/zone_sel.dmi', icon_state = bodyzone) + return selection_overlay + +/proc/select_bodyzone_limb_health(accurate_health = FALSE, mob/user, atom/target, bodyzone, is_precise_part = FALSE) + // Get the colours + var/list/healthy = rgb2num(FULL_HEALTH_COLOUR) + var/list/damaged = rgb2num(LOW_DAMAGE_COLOUR) + var/list/unhealthy = rgb2num(POOR_HEALTH_COLOUR) + var/list/not_present = rgb2num(NOT_PRESENT_COLOUR) + // Create the overlay + var/image/selection_overlay = image(icon = 'icons/mob/zone_sel.dmi', icon_state = bodyzone) + // If the target is a mob, then colour the parts according to the part's health + if (isliving(target)) + var/mob/living/living_target = target + var/obj/item/bodypart/target_part = living_target.get_bodypart(bodyzone) + // Determine what colour to make the indicator + var/list/new_colour + var/flash = FALSE + if (!target_part) + if (is_precise_part) + new_colour = healthy + else + new_colour = not_present + else + // 0 = healthy, 1 = dead + var/proportion = target_part.get_damage() / target_part.max_damage + if (!accurate_health) + proportion = proportion > 0 ? max(round(proportion, 1), 0.05) : 0 + else + if (target_part.burn_dam > 0) + var/image/dam_indicator = image(icon = 'icons/mob/zone_dam.dmi', icon_state = "burn") + dam_indicator.appearance_flags = RESET_COLOR | RESET_ALPHA + selection_overlay.overlays += dam_indicator + if (target_part.brute_dam > 0) + var/image/dam_indicator = image(icon = 'icons/mob/zone_dam.dmi', icon_state = "brute") + dam_indicator.appearance_flags = RESET_COLOR | RESET_ALPHA + selection_overlay.overlays += dam_indicator + if (proportion > 0) + new_colour = list( + proportion * unhealthy[1] + (1 - proportion) * damaged[1], + proportion * unhealthy[2] + (1 - proportion) * damaged[2], + proportion * unhealthy[3] + (1 - proportion) * damaged[3], + ) + else + new_colour = healthy + flash = proportion >= 0.01 + // Set the colour + selection_overlay.color = list( + new_colour[1] / 255, + new_colour[2] / 255, + new_colour[3] / 255, + 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + ) + if (flash) + animate(selection_overlay, time = 1 SECONDS, loop = -1, easing = SINE_EASING, color = list( + new_colour[1] / 255, + new_colour[2] / 255, + new_colour[3] / 255, + 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 2, + )) + animate(time = 1 SECONDS, loop = -1, easing = SINE_EASING, color = list( + new_colour[1] / 255, + new_colour[2] / 255, + new_colour[3] / 255, + 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + )) + return selection_overlay + +/mob/proc/_is_holding(obj/item/item) + return get_active_held_item() == item + +#undef NOT_PRESENT_COLOUR +#undef FULL_HEALTH_COLOUR +#undef POOR_HEALTH_COLOUR diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index e8aac70c8206d..f585a80349d20 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -392,7 +392,7 @@ playsound(usr.loc, 'sound/weapons/taser2.ogg', 75, 1) LE.firer = src - LE.def_zone = ran_zone(zone_selected) + LE.def_zone = ran_zone(get_combat_bodyzone(A)) LE.preparePixelProjectile(A, src, params) LE.fire() @@ -473,6 +473,15 @@ /mob/proc/MouseWheelOn(atom/A, delta_x, delta_y, params) SEND_SIGNAL(src, COMSIG_MOB_MOUSE_SCROLL_ON, A, delta_x, delta_y, params) + if (!client) + return + // Send the hotkey action + if (delta_y > 0) + client.keyDown("ScrollUp") + client.keyUp("ScrollUp") + else if (delta_y < 0) + client.keyDown("ScrollDown") + client.keyUp("ScrollDown") /mob/dead/observer/proc/mouse_wheeled(atom/A, delta_x, delta_y, params) SIGNAL_HANDLER diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index a07a3af44cc8e..656986a950f22 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -474,7 +474,7 @@ var/list/modifiers = params2list(params) var/icon_x = text2num(LAZYACCESS(modifiers, ICON_X)) var/icon_y = text2num(LAZYACCESS(modifiers, ICON_Y)) - var/choice = get_zone_at(icon_x, icon_y) + var/choice = get_zone_at(usr, icon_x, icon_y) if (!choice) return 1 @@ -490,7 +490,7 @@ var/list/modifiers = params2list(params) var/icon_x = text2num(LAZYACCESS(modifiers, ICON_X)) var/icon_y = text2num(LAZYACCESS(modifiers, ICON_Y)) - var/choice = get_zone_at(icon_x, icon_y) + var/choice = get_zone_at(usr, icon_x, icon_y) if(hovering == choice) return @@ -517,43 +517,44 @@ vis_contents -= hover_overlays_cache[hovering] hovering = null -/atom/movable/screen/zone_sel/proc/get_zone_at(icon_x, icon_y) +/atom/movable/screen/zone_sel/proc/get_zone_at(mob/user, icon_x, icon_y) + var/simple_mode = user.client?.prefs.read_player_preference(/datum/preference/choiced/zone_select) == PREFERENCE_BODYZONE_SIMPLIFIED switch(icon_y) if(1 to 9) //Legs switch(icon_x) if(10 to 15) - return BODY_ZONE_R_LEG + return simple_mode ? BODY_GROUP_LEGS : BODY_ZONE_R_LEG if(17 to 22) - return BODY_ZONE_L_LEG + return simple_mode ? BODY_GROUP_LEGS : BODY_ZONE_L_LEG if(10 to 13) //Hands and groin switch(icon_x) if(8 to 11) - return BODY_ZONE_R_ARM + return simple_mode ? BODY_GROUP_ARMS : BODY_ZONE_R_ARM if(12 to 20) - return BODY_ZONE_PRECISE_GROIN + return simple_mode ? BODY_GROUP_ARMS : BODY_ZONE_PRECISE_GROIN if(21 to 24) - return BODY_ZONE_L_ARM + return simple_mode ? BODY_GROUP_ARMS : BODY_ZONE_L_ARM if(14 to 22) //Chest and arms to shoulders switch(icon_x) if(8 to 11) - return BODY_ZONE_R_ARM + return simple_mode ? BODY_GROUP_ARMS : BODY_ZONE_R_ARM if(12 to 20) - return BODY_ZONE_CHEST + return simple_mode ? BODY_GROUP_CHEST_HEAD : BODY_ZONE_CHEST if(21 to 24) - return BODY_ZONE_L_ARM + return simple_mode ? BODY_GROUP_ARMS : BODY_ZONE_L_ARM if(23 to 30) //Head, but we need to check for eye or mouth if(icon_x in 12 to 20) switch(icon_y) if(23 to 24) if(icon_x in 15 to 17) - return BODY_ZONE_PRECISE_MOUTH + return simple_mode ? BODY_GROUP_CHEST_HEAD : BODY_ZONE_PRECISE_MOUTH if(26) //Eyeline, eyes are on 15 and 17 if(icon_x in 14 to 18) - return BODY_ZONE_PRECISE_EYES + return simple_mode ? BODY_GROUP_CHEST_HEAD : BODY_ZONE_PRECISE_EYES if(25 to 27) if(icon_x in 15 to 17) - return BODY_ZONE_PRECISE_EYES - return BODY_ZONE_HEAD + return simple_mode ? BODY_GROUP_CHEST_HEAD : BODY_ZONE_PRECISE_EYES + return simple_mode ? BODY_GROUP_CHEST_HEAD : BODY_ZONE_HEAD /atom/movable/screen/zone_sel/proc/set_selected_zone(choice, mob/user) if(user != hud?.mymob) @@ -570,7 +571,7 @@ cut_overlay(selecting_appearance) selecting_appearance = mutable_appearance('icons/mob/screen_gen.dmi', "[selecting]") add_overlay(selecting_appearance) - hud?.mymob?.zone_selected = selecting + hud?.mymob?._set_zone_selected(selecting) /atom/movable/screen/zone_sel/alien icon = 'icons/mob/screen_alien.dmi' @@ -580,7 +581,7 @@ cut_overlay(selecting_appearance) selecting_appearance = mutable_appearance('icons/mob/screen_alien.dmi', "[selecting]") add_overlay(selecting_appearance) - hud?.mymob?.zone_selected = selecting + hud?.mymob?._set_zone_selected(selecting) /atom/movable/screen/zone_sel/robot icon = 'icons/mob/screen_cyborg.dmi' diff --git a/code/datums/components/butchering.dm b/code/datums/components/butchering.dm index b8f66d204cac0..8901bfdba4343 100644 --- a/code/datums/components/butchering.dm +++ b/code/datums/components/butchering.dm @@ -35,7 +35,7 @@ user.show_message("[H]'s neck has already been already cut, you can't make the bleeding any worse!", 1, \ "Their neck has already been already cut, you can't make the bleeding any worse!") return COMPONENT_ITEM_NO_ATTACK - if((H.health <= H.crit_threshold || (user.pulling == H && user.grab_state >= GRAB_NECK) || H.IsSleeping()) && user.zone_selected == BODY_ZONE_HEAD) // Only sleeping, neck grabbed, or crit, can be sliced. + if((H.health <= H.crit_threshold || (user.pulling == H && user.grab_state >= GRAB_NECK) || H.IsSleeping())) // Only sleeping, neck grabbed, or crit, can be sliced. INVOKE_ASYNC(src, PROC_REF(startNeckSlice), source, H, user) return COMPONENT_ITEM_NO_ATTACK diff --git a/code/datums/components/embedded.dm b/code/datums/components/embedded.dm index 5334171425b8f..7216502497aef 100644 --- a/code/datums/components/embedded.dm +++ b/code/datums/components/embedded.dm @@ -256,7 +256,7 @@ /datum/component/embedded/proc/checkRemoval(mob/living/carbon/victim, obj/item/I, mob/user) SIGNAL_HANDLER - if(!istype(victim) || user.zone_selected != limb.body_zone || user.a_intent != INTENT_HELP) + if(!istype(victim) || user.is_zone_selected(limb.body_zone) || user.a_intent != INTENT_HELP) return var/damage_multiplier = 1 diff --git a/code/datums/components/jousting.dm b/code/datums/components/jousting.dm index b5ecc67a5ec7a..17a27da9ef120 100644 --- a/code/datums/components/jousting.dm +++ b/code/datums/components/jousting.dm @@ -55,7 +55,7 @@ var/msg if(damage) msg += "[user] [sharp? "impales" : "slams into"] [target] [sharp? "on" : "with"] their [parent]" - target.apply_damage(damage, BRUTE, user.zone_selected, 0) + target.apply_damage(damage, BRUTE, user.get_combat_bodyzone(target), 0) if(prob(knockdown_chance)) msg += " and knocks [target] [target_buckled? "off of [target.buckled]" : "down"]" if(target_buckled) diff --git a/code/datums/components/pellet_cloud.dm b/code/datums/components/pellet_cloud.dm index 1c855ad6bcf60..846fa4e55637e 100644 --- a/code/datums/components/pellet_cloud.dm +++ b/code/datums/components/pellet_cloud.dm @@ -91,7 +91,7 @@ shooter = user var/turf/targloc = get_turf(target) if(!zone_override) - zone_override = shooter.zone_selected + zone_override = shooter.get_combat_bodyzone(target) for(var/i in 1 to num_pellets) shell.ready_proj(target, user, SUPPRESSED_VERY, zone_override, fired_from) diff --git a/code/datums/elements/mechanical_repair.dm b/code/datums/elements/mechanical_repair.dm index 121654f246bee..298f6bc76773d 100644 --- a/code/datums/elements/mechanical_repair.dm +++ b/code/datums/elements/mechanical_repair.dm @@ -16,36 +16,54 @@ /datum/element/mechanical_repair/proc/try_repair(datum/source, obj/item/I, mob/user) var/mob/living/carbon/human/target = source - var/obj/item/bodypart/affecting = target.get_bodypart(check_zone(user.zone_selected)) + + if(!istype(I, /obj/item/stack/cable_coil) && I.tool_behaviour != TOOL_WELDER) + return // Check to make sure we can repair - if((!affecting || (IS_ORGANIC_LIMB(affecting))) || user.a_intent == INTENT_HARM) + if(user.a_intent == INTENT_HARM) return if(target in user.do_afters) return COMPONENT_NO_AFTERATTACK + var/datum/task/fetch_selected_limb = user.select_bodyzone(target, style = BODYZONE_STYLE_MEDICAL) + fetch_selected_limb.continue_with(CALLBACK(src, PROC_REF(complete_repairs), target, I, user)) + return COMPONENT_NO_AFTERATTACK + +/datum/element/mechanical_repair/proc/complete_repairs(mob/living/carbon/human/target, obj/item/I, mob/user, selected_zone) + if(target in user.do_afters || !user.can_interact_with(target, TRUE) || !user.can_interact_with(I, TRUE)) + return COMPONENT_NO_AFTERATTACK + + var/obj/item/bodypart/affecting = target.get_bodypart(check_zone(selected_zone)) + + if (!affecting || (IS_ORGANIC_LIMB(affecting))) + to_chat(user, "That limb is not robotic!.") + return + // Handles welder repairs on human limbs if(I.tool_behaviour == TOOL_WELDER) - if(I.use_tool(source, user, 0, volume=50, amount=1)) - if(user == target) - user.visible_message("[user] starts to fix some of the dents on [target == user ? "[p_their()]" : "[target]'s"] [parse_zone(affecting.body_zone)].", - "You start fixing some of the dents on [target == user ? "your" : "[target]'s"] [parse_zone(affecting.body_zone)].") - if(!do_after(user, 1.5 SECONDS, target)) - return COMPONENT_NO_AFTERATTACK - item_heal_robotic(target, user, 15, 0, affecting) + do + if(I.use_tool(target, user, 0, volume=50, amount=1)) + if(user == target) + user.visible_message("[user] starts to fix some of the dents on [target == user ? "[p_their()]" : "[target]'s"] [parse_zone(affecting.body_zone)].", + "You start fixing some of the dents on [target == user ? "your" : "[target]'s"] [parse_zone(affecting.body_zone)].") + if(!do_after(user, 1.5 SECONDS, target)) + return COMPONENT_NO_AFTERATTACK + while (item_heal_robotic(target, user, 15, 0, affecting) && user.is_zone_selected(selected_zone) && !QDELETED(I)) user.changeNext_move(CLICK_CD_MELEE * 0.5) //antispam return COMPONENT_NO_AFTERATTACK // Handles cable repairs if(istype(I, /obj/item/stack/cable_coil)) var/obj/item/stack/cable_coil/coil = I - if(user == target) - user.visible_message("[user] starts to fix some of the burn wires in [target == user ? "[p_their()]" : "[target]'s"] [parse_zone(affecting.body_zone)].", - "You start fixing some of the burnt wires in [target == user ? "your" : "[target]'s"] [parse_zone(affecting.body_zone)].") - if(!do_after(user, 1.5 SECONDS, target)) - return COMPONENT_NO_AFTERATTACK - if(coil.amount && item_heal_robotic(target, user, 0, 15, affecting)) - coil.use(1) + do + if(user == target) + user.visible_message("[user] starts to fix some of the burn wires in [target == user ? "[p_their()]" : "[target]'s"] [parse_zone(affecting.body_zone)].", + "You start fixing some of the burnt wires in [target == user ? "your" : "[target]'s"] [parse_zone(affecting.body_zone)].") + if(!do_after(user, 1.5 SECONDS, target)) + return COMPONENT_NO_AFTERATTACK + // Run checks to ensure that we can continue healing. We check coil twice, as we want to break out of the loop if we ran out of coil + while (coil.amount && item_heal_robotic(target, user, 0, 15, affecting) && coil.use(1) && coil.amount && user.is_zone_selected(selected_zone) && !QDELETED(coil)) user.changeNext_move(CLICK_CD_MELEE * 0.5) //antispam return COMPONENT_NO_AFTERATTACK diff --git a/code/datums/keybinding/keybinding.dm b/code/datums/keybinding/keybinding.dm index b77e7ee580364..e306d2b4803a7 100644 --- a/code/datums/keybinding/keybinding.dm +++ b/code/datums/keybinding/keybinding.dm @@ -9,6 +9,10 @@ /// Does this keybind apply regardless of any modifier keys (SHIFT-, ALT-, CTRL-)? /// Important for movement keys, which need to still activate despite other "hold to toggle" bindings on the modifier keys. var/any_modifier = FALSE + /// The typepath of the preference that we must have set to a specific value in order to show + var/required_pref_type = null + /// The value of the preference outlined in required_pref_type that must be set in order to show this keybinding to the user. + var/required_pref_value = null //I don't know why this is done in New() and not down() when it says down(), but that's how it's currently on tg /datum/keybinding/New() @@ -23,4 +27,6 @@ return FALSE /datum/keybinding/proc/can_use(client/user) - return TRUE + if (!required_pref_type) + return TRUE + return user.prefs.read_preference(required_pref_type) == required_pref_value diff --git a/code/datums/keybinding/mob.dm b/code/datums/keybinding/mob.dm index 518d31d78d7b1..8f674cdde5560 100644 --- a/code/datums/keybinding/mob.dm +++ b/code/datums/keybinding/mob.dm @@ -291,12 +291,42 @@ M.toggle_move_intent() return TRUE +/datum/keybinding/mob/prevent_movement + keys = list("Ctrl") + name = "block_movement" + full_name = "Hold to change facing" + description = "While pressed, prevents movement when pressing directional keys; instead just changes your facing direction" + keybind_signal = COMSIG_KB_MOB_PREVENTMOVEMENT_DOWN + +/datum/keybinding/mob/prevent_movement/down(client/user) + . = ..() + if(.) + return + user.movement_locked = TRUE + +/datum/keybinding/mob/prevent_movement/up(client/user) + . = ..() + if(.) + return + user.movement_locked = FALSE + +/** + * =========================== + * Bodyzone targeting section + * =========================== + * + * Precise hotkeys + * + */ + /datum/keybinding/mob/target_head_cycle keys = list("Numpad8") name = "target_head_cycle" full_name = "Target: Cycle head" description = "" keybind_signal = COMSIG_KB_MOB_TARGETCYCLEHEAD_DOWN + required_pref_type = /datum/preference/choiced/zone_select + required_pref_value = PREFERENCE_BODYZONE_INTENT /datum/keybinding/mob/target_head_cycle/down(client/user) . = ..() @@ -312,6 +342,8 @@ full_name = "Target: right arm" description = "" keybind_signal = COMSIG_KB_MOB_TARGETRIGHTARM_DOWN + required_pref_type = /datum/preference/choiced/zone_select + required_pref_value = PREFERENCE_BODYZONE_INTENT /datum/keybinding/mob/target_r_arm/down(client/user) . = ..() @@ -327,6 +359,8 @@ full_name = "Target: Body" description = "" keybind_signal = COMSIG_KB_MOB_TARGETBODYCHEST_DOWN + required_pref_type = /datum/preference/choiced/zone_select + required_pref_value = PREFERENCE_BODYZONE_INTENT /datum/keybinding/mob/target_body_chest/down(client/user) . = ..() @@ -342,6 +376,8 @@ full_name = "Target: left arm" description = "" keybind_signal = COMSIG_KB_MOB_TARGETLEFTARM_DOWN + required_pref_type = /datum/preference/choiced/zone_select + required_pref_value = PREFERENCE_BODYZONE_INTENT /datum/keybinding/mob/target_left_arm/down(client/user) . = ..() @@ -357,6 +393,8 @@ full_name = "Target: Right leg" description = "" keybind_signal = COMSIG_KB_MOB_TARGETRIGHTLEG_DOWN + required_pref_type = /datum/preference/choiced/zone_select + required_pref_value = PREFERENCE_BODYZONE_INTENT /datum/keybinding/mob/target_right_leg/down(client/user) . = ..() @@ -372,6 +410,8 @@ full_name = "Target: Groin" description = "" keybind_signal = COMSIG_KB_MOB_TARGETBODYGROIN_DOWN + required_pref_type = /datum/preference/choiced/zone_select + required_pref_value = PREFERENCE_BODYZONE_INTENT /datum/keybinding/mob/target_body_groin/down(client/user) . = ..() @@ -387,6 +427,8 @@ full_name = "Target: left leg" description = "" keybind_signal = COMSIG_KB_MOB_TARGETLEFTLEG_DOWN + required_pref_type = /datum/preference/choiced/zone_select + required_pref_value = PREFERENCE_BODYZONE_INTENT /datum/keybinding/mob/target_left_leg/down(client/user) . = ..() @@ -396,22 +438,49 @@ user.body_l_leg() return TRUE -/datum/keybinding/mob/prevent_movement - keys = list("Ctrl") - name = "block_movement" - full_name = "Hold to change facing" - description = "While pressed, prevents movement when pressing directional keys; instead just changes your facing direction" - keybind_signal = COMSIG_KB_MOB_PREVENTMOVEMENT_DOWN - -/datum/keybinding/mob/prevent_movement/down(client/user) +/** + * =========================== + * Bodyzone targeting section + * =========================== + * + * Simplified hotkeys + * + */ + +/datum/keybinding/mob/target_higher_zone + keys = list("ScrollUp") + name = "target_higher_zone" + full_name = "Target: Cycle zone up" + description = "Cycles the targeted bodyzone upwards. Leg targeting will become arm targeting, and arm targeting will become body/head targeting." + keybind_signal = COMSIG_KB_MOB_TARGETCYCLEUP_DOWN + required_pref_type = /datum/preference/choiced/zone_select + required_pref_value = PREFERENCE_BODYZONE_SIMPLIFIED + +/datum/keybinding/mob/target_higher_zone/down(client/user) . = ..() if(.) return - user.movement_locked = TRUE + if(!user.mob) + return + user.body_up() + return TRUE -/datum/keybinding/mob/prevent_movement/up(client/user) + +/datum/keybinding/mob/target_lower_zone + keys = list("ScrollDown") + name = "target_lower_zone" + full_name = "Target: Cycle zone down" + description = "Cycles the targeted bodyzone downwards. Head/body targeting will become arm targeting and arm targeting will become leg targeting.." + keybind_signal = COMSIG_KB_MOB_TARGETCYCLEDOWN_DOWN + required_pref_type = /datum/preference/choiced/zone_select + required_pref_value = PREFERENCE_BODYZONE_SIMPLIFIED + +/datum/keybinding/mob/target_lower_zone/down(client/user) . = ..() if(.) return - user.movement_locked = FALSE + if(!user.mob) + return + user.body_down() + return TRUE diff --git a/code/datums/martial/_martial.dm b/code/datums/martial/_martial.dm index aa50a31dd718b..272cc3059ebbf 100644 --- a/code/datums/martial/_martial.dm +++ b/code/datums/martial/_martial.dm @@ -61,7 +61,7 @@ log_combat(A, D, "attempted to [atk_verb]") return 0 - var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected)) + var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.get_combat_bodyzone(D))) var/armor_block = D.run_armor_check(affecting, MELEE) playsound(D.loc, A.dna.species.attack_sound, 25, 1, -1) diff --git a/code/datums/martial/boxing.dm b/code/datums/martial/boxing.dm index 59d5cfdb2e0d6..c29325e261be0 100644 --- a/code/datums/martial/boxing.dm +++ b/code/datums/martial/boxing.dm @@ -25,7 +25,7 @@ return 0 - var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected)) + var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.get_combat_bodyzone(D))) var/armor_block = D.run_armor_check(affecting, MELEE) playsound(D.loc, A.dna.species.attack_sound, 25, 1, -1) diff --git a/code/datums/martial/krav_maga.dm b/code/datums/martial/krav_maga.dm index 643845af95e97..c6f166d298c56 100644 --- a/code/datums/martial/krav_maga.dm +++ b/code/datums/martial/krav_maga.dm @@ -130,7 +130,7 @@ if(check_streak(A,D)) return 1 log_combat(A, D, "punched") - var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected)) + var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.get_combat_bodyzone(D))) var/armor_block = D.run_armor_check(affecting, MELEE) var/picked_hit_type = pick("punched", "kicked") var/bonus_damage = 0 @@ -152,7 +152,7 @@ /datum/martial_art/krav_maga/disarm_act(var/mob/living/carbon/human/A, var/mob/living/carbon/human/D) if(check_streak(A,D)) return 1 - var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.zone_selected)) + var/obj/item/bodypart/affecting = D.get_bodypart(ran_zone(A.get_combat_bodyzone(D))) var/armor_block = D.run_armor_check(affecting, MELEE) if((D.mobility_flags & MOBILITY_STAND)) D.visible_message("[A] reprimands [D]!", \ diff --git a/code/datums/task.dm b/code/datums/task.dm index c9d57fdd83140..c9022064ea5db 100644 --- a/code/datums/task.dm +++ b/code/datums/task.dm @@ -2,6 +2,7 @@ var/result = null var/completed = FALSE var/list/subtasks + var/list/continuation_tasks = list() /// Add a subtask to this subtask. When awaiting a parent task, it will wait for all subtasks to complete /// and then will return a list containing all the results. @@ -14,15 +15,14 @@ CRASH("Attempting to mark a subtask holder as completed. This is not allowed") completed = TRUE src.result = result + for (var/datum/callback/callback as() in continuation_tasks) + callback.InvokeAsync(result) /// Wait for the task to be completed, or the timeout to expire /// Returns true if the task was completed /datum/task/proc/await(timeout = 30 SECONDS) var/start_time = world.time - var/sleep_time = 1 - while(world.time < start_time + timeout && !is_completed()) - sleep(sleep_time) - sleep_time = min(sleep_time * 2, 1 SECONDS) + UNTIL (world.time >= start_time + timeout || is_completed()) // Check for success var/success = length(subtasks) ? TRUE : completed if (length(subtasks) && !result) @@ -41,3 +41,18 @@ return FALSE return TRUE return completed + +/// Continue with a callback once the task has completed, +/// invokes immediately unlike AWAIT which may have a 1 second +/// delay causing it to be unresponsive. +/// This is the most effective option for use with UI or player-controlled +/// responses. +/datum/task/proc/continue_with(datum/callback/callback) + if (!callback) + return + // If the async function wasn't async then + // immediately invoke the continuation task + if (completed) + callback.InvokeAsync(result) + return + continuation_tasks += callback diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 30ea7f6b4fbcf..878bf3ca7e5f2 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -728,7 +728,7 @@ if(QDELETED(thrower) || !istype(thrower)) thrower = null //Let's not pass an invalid reference. else - target_zone = thrower.zone_selected + target_zone = thrower.get_combat_bodyzone(target) var/datum/thrownthing/TT = new(src, target, get_dir(src, target), range, speed, thrower, diagonals_first, force, callback, target_zone) diff --git a/code/game/objects/items/bedsheets.dm b/code/game/objects/items/bedsheets.dm index ba6ba688e78d9..aad4534553160 100644 --- a/code/game/objects/items/bedsheets.dm +++ b/code/game/objects/items/bedsheets.dm @@ -27,8 +27,7 @@ AddElement(/datum/element/bed_tuckable, 0, 0, 0) /obj/item/bedsheet/attack(mob/living/M, mob/user) - if(!attempt_initiate_surgery(src, M, user)) - ..() + attempt_initiate_surgery(src, M, user) /obj/item/bedsheet/attack_self(mob/user) if(!user.CanReach(src)) //No telekenetic grabbing. diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm index ad7e50cdce868..ee83ff4dfb5de 100644 --- a/code/game/objects/items/clown_items.dm +++ b/code/game/objects/items/clown_items.dm @@ -99,7 +99,7 @@ qdel(target) decreaseUses(user) - else if(ishuman(target) && user.zone_selected == BODY_ZONE_PRECISE_MOUTH) + else if(ishuman(target) && user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH)) var/mob/living/carbon/human/H = user user.visible_message("\the [user] washes \the [target]'s mouth out with [src.name]!", "You wash \the [target]'s mouth out with [src.name]!") //washes mouth out with soap sounds better than 'the soap' here if(user.zone_selected == "mouth") H.lip_style = null //removes lipstick diff --git a/code/game/objects/items/cosmetics.dm b/code/game/objects/items/cosmetics.dm index 1690f6e9a1957..69d133edb6a44 100644 --- a/code/game/objects/items/cosmetics.dm +++ b/code/game/objects/items/cosmetics.dm @@ -78,7 +78,7 @@ //you can wipe off lipstick with paper! /obj/item/paper/attack(mob/M, mob/user) - if(user.zone_selected == BODY_ZONE_PRECISE_MOUTH) + if(user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH)) if(!ismob(M)) return @@ -125,93 +125,101 @@ /obj/item/razor/attack(mob/M, mob/user) - if(ishuman(M) && extended == 1 && user.a_intent != INTENT_HARM) - var/mob/living/carbon/human/H = M - var/location = user.zone_selected - var/mirror = FALSE - if(HAS_TRAIT(H, TRAIT_SELF_AWARE) || locate(/obj/structure/mirror) in range(1, H)) - mirror = TRUE - if((location in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_HEAD)) && !H.get_bodypart(BODY_ZONE_HEAD)) - to_chat(user, "[H] doesn't have a head!") - return - if(location == BODY_ZONE_PRECISE_MOUTH) - if(user.a_intent == INTENT_HELP) - if(H.gender == MALE) - INVOKE_ASYNC(src, PROC_REF(new_facial_hairstyle), H, user, mirror) - return - else - return + if(!ishuman(M) || extended != 1 || user.a_intent == INTENT_HARM) + return ..() + var/mob/living/carbon/human/H = M + // Must be targetting the head + if (!user.is_zone_selected(BODY_ZONE_HEAD) && !user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH)) + return ..() + if(!H.get_bodypart(BODY_ZONE_HEAD)) + to_chat(user, "[H] doesn't have a head!") + return + var/mirror = FALSE + if(HAS_TRAIT(H, TRAIT_SELF_AWARE) || locate(/obj/structure/mirror) in range(1, H)) + mirror = TRUE + var/datum/task/select_bodyzone = user.select_bodyzone(M, TRUE, BODYZONE_STYLE_DEFAULT, override_zones = list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH)) + select_bodyzone.continue_with(CALLBACK(src, PROC_REF(razor_action), H, user, mirror)) + +/obj/item/razor/proc/razor_action(mob/living/carbon/human/H, mob/user, mirror, location) + if (!user.can_interact_with(H, TRUE)) + to_chat(user, "[H] is too far away!") + return + if (!user.can_interact_with(src, TRUE)) + to_chat(user, "[src] is too far away!") + return + if(location == BODY_ZONE_PRECISE_MOUTH) + if(user.a_intent == INTENT_HELP) + if(H.gender == MALE) + INVOKE_ASYNC(src, PROC_REF(new_facial_hairstyle), H, user, mirror) + return else - if(!(FACEHAIR in H.dna.species.species_traits)) - to_chat(user, "There is no facial hair to shave!") - return - if(!get_location_accessible(H, location)) - to_chat(user, "The mask is in the way!") - return - if(H.facial_hair_style == "Shaved") - to_chat(user, "Already clean-shaven!") - return + return + else + if(!(FACEHAIR in H.dna.species.species_traits)) + to_chat(user, "There is no facial hair to shave!") + return + if(!get_location_accessible(H, location)) + to_chat(user, "The mask is in the way!") + return + if(H.facial_hair_style == "Shaved") + to_chat(user, "Already clean-shaven!") + return - if(H == user) //shaving yourself - user.visible_message("[user] starts to shave [user.p_their()] facial hair with [src].", \ - "You take a moment to shave your facial hair with [src]...") - if(do_after(user, 50, target = H)) - user.visible_message("[user] shaves [user.p_their()] facial hair clean with [src].", \ - "You finish shaving with [src]. Fast and clean!") - shave(H, location) - else - user.visible_message("[user] tries to shave [H]'s facial hair with [src].", \ - "You start shaving [H]'s facial hair...") - if(do_after(user, 50, target = H)) - user.visible_message("[user] shaves off [H]'s facial hair with [src].", \ - "You shave [H]'s facial hair clean off.") - shave(H, location) + if(H == user) //shaving yourself + user.visible_message("[user] starts to shave [user.p_their()] facial hair with [src].", \ + "You take a moment to shave your facial hair with [src]...") + if(do_after(user, 50, target = H)) + user.visible_message("[user] shaves [user.p_their()] facial hair clean with [src].", \ + "You finish shaving with [src]. Fast and clean!") + shave(H, location) + else + user.visible_message("[user] tries to shave [H]'s facial hair with [src].", \ + "You start shaving [H]'s facial hair...") + if(do_after(user, 50, target = H)) + user.visible_message("[user] shaves off [H]'s facial hair with [src].", \ + "You shave [H]'s facial hair clean off.") + shave(H, location) - else if(location == BODY_ZONE_HEAD) - if(user.a_intent == INTENT_HELP) - INVOKE_ASYNC(src, PROC_REF(new_hairstyle), H, user) + else if(location == BODY_ZONE_HEAD) + if(user.a_intent == INTENT_HELP) + INVOKE_ASYNC(src, PROC_REF(new_hairstyle), H, user) + return + else + if(!(HAIR in H.dna.species.species_traits)) + to_chat(user, "There is no hair to shave!") + return + if(!get_location_accessible(H, location)) + to_chat(user, "The headgear is in the way!") + return + if(H.hair_style == "Bald" || H.hair_style == "Balding Hair" || H.hair_style == "Skinhead") + to_chat(user, "There is not enough hair left to shave!") return - else - if(!(HAIR in H.dna.species.species_traits)) - to_chat(user, "There is no hair to shave!") - return - if(!get_location_accessible(H, location)) - to_chat(user, "The headgear is in the way!") - return - if(H.hair_style == "Bald" || H.hair_style == "Balding Hair" || H.hair_style == "Skinhead") - to_chat(user, "There is not enough hair left to shave!") - return - if(H == user) //shaving yourself - user.visible_message("[user] starts to shave [user.p_their()] head with [src].", \ - "You start to shave your head with [src]...") - if(do_after(user, 5, target = H)) - user.visible_message("[user] shaves [user.p_their()] head with [src].", \ - "You finish shaving with [src].") + if(H == user) //shaving yourself + user.visible_message("[user] starts to shave [user.p_their()] head with [src].", \ + "You start to shave your head with [src]...") + if(do_after(user, 5, target = H)) + user.visible_message("[user] shaves [user.p_their()] head with [src].", \ + "You finish shaving with [src].") + shave(H, location) + else + var/turf/H_loc = H.loc + user.visible_message("[user] tries to shave [H]'s head with [src]!", \ + "You start shaving [H]'s head...") + if(do_after(user, 50, target = H)) + if(H_loc == H.loc) + user.visible_message("[user] shaves [H]'s head bald with [src]!", \ + "You shave [H]'s head bald.") shave(H, location) - else - var/turf/H_loc = H.loc - user.visible_message("[user] tries to shave [H]'s head with [src]!", \ - "You start shaving [H]'s head...") - if(do_after(user, 50, target = H)) - if(H_loc == H.loc) - user.visible_message("[user] shaves [H]'s head bald with [src]!", \ - "You shave [H]'s head bald.") - shave(H, location) - else - ..() - else - ..() /obj/item/razor/proc/new_hairstyle(mob/living/carbon/human/H, mob/user, mirror) - var/location = user.zone_selected if (H == user && !mirror) to_chat(user, "You need a mirror to properly style your own hair!") return if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return var/new_style = input(user, "Select a hair style", "Grooming") as null|anything in GLOB.hair_styles_list - if(!get_location_accessible(H, location)) + if(!get_location_accessible(H, BODY_ZONE_HEAD)) to_chat(user, "The headgear is in the way!") return user.visible_message("[user] tries to change [H]'s hairstyle using [src].", "You try to change [H]'s hairstyle using [src].") @@ -221,14 +229,13 @@ H.update_hair() /obj/item/razor/proc/new_facial_hairstyle(mob/living/carbon/human/H, mob/user, var/mirror) - var/location = user.zone_selected if(H == user && !mirror) to_chat(user, "You need a mirror to properly style your own facial hair!") return if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) return var/new_style = input(user, "Select a facial hair style", "Grooming") as null|anything in GLOB.facial_hair_styles_list - if(!get_location_accessible(H, location)) + if(!get_location_accessible(H, BODY_ZONE_PRECISE_MOUTH)) to_chat(user, "The mask is in the way!") return user.visible_message("[user] tries to change [H]'s facial hair style using [src].", "You try to change [H]'s facial hair style using [src].") diff --git a/code/game/objects/items/defib.dm b/code/game/objects/items/defib.dm index 8a33fb2264bd7..4675d451aa906 100644 --- a/code/game/objects/items/defib.dm +++ b/code/game/objects/items/defib.dm @@ -465,7 +465,7 @@ var/mob/living/carbon/H = M - if(user.zone_selected != BODY_ZONE_CHEST) + if(!user.is_zone_selected(BODY_ZONE_CHEST)) to_chat(user, "You need to target your patient's chest with [src]!") return diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm index 0a1f423d445d1..0af132d8641eb 100644 --- a/code/game/objects/items/devices/flashlight.dm +++ b/code/game/objects/items/devices/flashlight.dm @@ -56,116 +56,120 @@ /obj/item/flashlight/attack(mob/living/carbon/M, mob/living/carbon/human/user) add_fingerprint(user) - if(istype(M) && on && (user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH))) + if (!istype(M) || !on || !user.is_zone_selected(BODY_ZONE_HEAD, precise = FALSE)) + return ..() - if((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) //too dumb to use flashlight properly - return ..() //just hit them in the head + if((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) //too dumb to use flashlight properly + return ..() //just hit them in the head - if(!user.IsAdvancedToolUser()) - to_chat(user, "You don't have the dexterity to do this!") - return + if(!user.IsAdvancedToolUser()) + to_chat(user, "You don't have the dexterity to do this!") + return - if(!M.get_bodypart(BODY_ZONE_HEAD)) - to_chat(user, "[M] doesn't have a head!") - return + if(!M.get_bodypart(BODY_ZONE_HEAD)) + to_chat(user, "[M] doesn't have a head!") + return - if(light_power < 1) - to_chat(user, "\The [src] isn't bright enough to see anything! ") - return + if(light_power < 1) + to_chat(user, "\The [src] isn't bright enough to see anything! ") + return - switch(user.zone_selected) - if(BODY_ZONE_PRECISE_EYES) - if((M.head && M.head.flags_cover & HEADCOVERSEYES) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) || (M.glasses && M.glasses.flags_cover & GLASSESCOVERSEYES)) - to_chat(user, "You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSEYES) ? "helmet" : (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) ? "mask": "glasses"] first.") - return + user.visible_message("[user] shines the light at [M]!", ignored_mobs = list(user)) - var/obj/item/organ/eyes/E = M.getorganslot(ORGAN_SLOT_EYES) - if(!E) - to_chat(user, "[M] doesn't have any eyes!") - return + var/list/results = list() - if(M == user) //they're using it on themselves - if(M.flash_act(visual = 1)) - M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "You wave the light in front of your eyes! Trippy!") - else - M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "You wave the light in front of your eyes.") - else - user.visible_message("[user] directs [src] to [M]'s eyes.", \ - "You direct [src] to [M]'s eyes.") - if(M.stat == DEAD || (M.is_blind()) || !M.flash_act(visual = 1)) //mob is dead or fully blind - to_chat(user, "[M]'s pupils don't react to the light!") - else if(M.has_dna() && M.dna.check_mutation(XRAY)) //mob has X-ray vision - to_chat(user, "[M]'s pupils give an eerie glow!") - else //they're okay! - to_chat(user, "[M]'s pupils narrow.") - - if(BODY_ZONE_PRECISE_MOUTH) - - if(M.is_mouth_covered()) - to_chat(user, "You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSMOUTH) ? "helmet" : "mask"] first.") - return - - var/their = M.p_their() - - var/list/mouth_organs = new - for(var/obj/item/organ/O in M.internal_organs) - if(O.zone == BODY_ZONE_PRECISE_MOUTH) - mouth_organs.Add(O) - var/organ_list = "" - var/organ_count = LAZYLEN(mouth_organs) - if(organ_count) - for(var/I in 1 to organ_count) - if(I > 1) - if(I == mouth_organs.len) - organ_list += ", and " - else - organ_list += ", " - var/obj/item/organ/O = mouth_organs[I] - organ_list += (O.gender == "plural" ? O.name : "\an [O.name]") - - var/pill_count = 0 - for(var/datum/action/item_action/hands_free/activate_pill/AP in M.actions) - pill_count++ - - if(M == user) - var/can_use_mirror = FALSE - if(isturf(user.loc)) - var/obj/structure/mirror/mirror = locate(/obj/structure/mirror, user.loc) - if(mirror) - switch(user.dir) - if(NORTH) - can_use_mirror = mirror.pixel_y > 0 - if(SOUTH) - can_use_mirror = mirror.pixel_y < 0 - if(EAST) - can_use_mirror = mirror.pixel_x > 0 - if(WEST) - can_use_mirror = mirror.pixel_x < 0 - - M.visible_message("[M] directs [src] to [their] mouth.", \ - "You point [src] into your mouth.") - if(!can_use_mirror) - to_chat(user, "You can't see anything without a mirror.") - return - if(organ_count) - to_chat(user, "Inside your mouth [organ_count > 1 ? "are" : "is"] [organ_list].") - else - to_chat(user, "There's nothing inside your mouth.") - if(pill_count) - to_chat(user, "You have [pill_count] implanted pill[pill_count > 1 ? "s" : ""].") - - else - user.visible_message("[user] directs [src] to [M]'s mouth.",\ - "You direct [src] to [M]'s mouth.") - if(organ_count) - to_chat(user, "Inside [their] mouth [organ_count > 1 ? "are" : "is"] [organ_list].") + results += "You shine the light at [M]..." + + /** + * Handle mouth + */ + + if(M.is_mouth_covered()) + results += "[M.p_their()] mouth is covered by [(M.head && M.head.flags_cover & HEADCOVERSMOUTH) ? "a helmet" : "a mask"]." + else + var/their = M.p_their() + + var/list/mouth_organs = new + for(var/obj/item/organ/O in M.internal_organs) + if(O.zone == BODY_ZONE_PRECISE_MOUTH) + mouth_organs.Add(O) + var/organ_list = "" + var/organ_count = LAZYLEN(mouth_organs) + if(organ_count) + for(var/I in 1 to organ_count) + if(I > 1) + if(I == mouth_organs.len) + organ_list += ", and " else - to_chat(user, "[M] doesn't have any organs in [their] mouth.") - if(pill_count) - to_chat(user, "[M] has [pill_count] pill[pill_count > 1 ? "s" : ""] implanted in [their] teeth.") + organ_list += ", " + var/obj/item/organ/O = mouth_organs[I] + organ_list += (O.gender == "plural" ? O.name : "\an [O.name]") + + var/pill_count = 0 + for(var/datum/action/item_action/hands_free/activate_pill/AP in M.actions) + pill_count++ + + if(M == user) + var/can_use_mirror = FALSE + if(isturf(user.loc)) + var/obj/structure/mirror/mirror = locate(/obj/structure/mirror, user.loc) + if(mirror) + switch(user.dir) + if(NORTH) + can_use_mirror = mirror.pixel_y > 0 + if(SOUTH) + can_use_mirror = mirror.pixel_y < 0 + if(EAST) + can_use_mirror = mirror.pixel_x > 0 + if(WEST) + can_use_mirror = mirror.pixel_x < 0 + + if(!can_use_mirror) + to_chat(user, "You can't see anything without a mirror.") + return + if(organ_count) + results += "Inside your mouth [organ_count > 1 ? "are" : "is"] [organ_list]." + else + results += "There's nothing inside your mouth." + if(pill_count) + results += "You have [pill_count] implanted pill[pill_count > 1 ? "s" : ""]." + else + user.visible_message("[user] directs [src] to [M]'s mouth.",\ + "You direct [src] to [M]'s mouth.") + if(organ_count) + results += "Inside [their] mouth [organ_count > 1 ? "are" : "is"] [organ_list]." + else + results += "[M] doesn't have any organs in [their] mouth." + if(pill_count) + results += "[M] has [pill_count] pill[pill_count > 1 ? "s" : ""] implanted in [their] teeth." + + /** + * Handle eyes + */ + + var/obj/item/organ/eyes/E = M.getorganslot(ORGAN_SLOT_EYES) + + if((M.head && M.head.flags_cover & HEADCOVERSEYES) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) || (M.glasses && M.glasses.flags_cover & GLASSESCOVERSEYES)) + results += "[M.p_their()] eyes are covered by [(M.head && M.head.flags_cover & HEADCOVERSEYES) ? "a helmet" : (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) ? "a mask": "some glasses"]." + else if(!E) + results += "[M.p_they()] doesn't have any eyes!" + else if(M == user) + //they're using it on themselves, give less of a report + if(M.flash_act(visual = 1)) + to_chat(user, "You wave the light in front of your eyes! Trippy!") + else + to_chat(user, "You wave the light in front of your eyes.") + return else - return ..() + if(M.stat == DEAD || (M.is_blind()) || !M.flash_act(visual = 1)) //mob is dead or fully blind + results += "[M.p_their(TRUE)] pupils don't react to the light!" + else if(M.has_dna() && M.dna.check_mutation(XRAY)) //mob has X-ray vision + results += "[M.p_their(TRUE)] pupils give an eerie glow!" + else //they're okay! + results += "[M.p_their(TRUE)] pupils narrow." + + to_chat(user, EXAMINE_BLOCK(jointext(results, "\n"))) /obj/item/flashlight/pen name = "penlight" @@ -400,7 +404,7 @@ return TRUE /obj/item/flashlight/emp/attack(mob/living/M, mob/living/user) - if(on && (user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH))) // call original attack when examining organs + if(on && (user.is_zone_selected(BODY_ZONE_PRECISE_EYES, precise_only = TRUE) || user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH, precise_only = TRUE))) // call original attack when examining organs ..() return diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm index 854c23e66aece..6960b2c2d6c0a 100644 --- a/code/game/objects/items/devices/laserpointer.dm +++ b/code/game/objects/items/devices/laserpointer.dm @@ -99,7 +99,7 @@ //human/alien mobs if(iscarbon(target)) var/mob/living/carbon/C = target - if(user.zone_selected == BODY_ZONE_PRECISE_EYES) + if(user.is_zone_selected(BODY_ZONE_PRECISE_EYES)) log_combat(user, C, "shone in the eyes", src) var/severity = 1 diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm index 41de38bc42992..a752a2b8be86f 100644 --- a/code/game/objects/items/kitchen.dm +++ b/code/game/objects/items/kitchen.dm @@ -50,7 +50,7 @@ icon_state = "fork" forkload = null - else if(user.zone_selected == BODY_ZONE_PRECISE_EYES) + else if(user.is_zone_selected(BODY_ZONE_PRECISE_EYES, simplified_probability = 30)) if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50)) M = user return eyestab(M,user) diff --git a/code/game/objects/items/knives.dm b/code/game/objects/items/knives.dm index 81203389c7a6f..e0a0de7a9d215 100644 --- a/code/game/objects/items/knives.dm +++ b/code/game/objects/items/knives.dm @@ -31,7 +31,7 @@ set_butchering() /obj/item/knife/attack(mob/living/carbon/M, mob/living/carbon/user) - if(user.zone_selected == BODY_ZONE_PRECISE_EYES) + if(user.is_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/melee/misc.dm b/code/game/objects/items/melee/misc.dm index c82a1aaddd764..8914f17fac922 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -292,19 +292,20 @@ user.do_attack_animation(target) playsound(get_turf(src), on_stun_sound, 75, 1, -1) additional_effects_carbon(target, user) - if((user.zone_selected == BODY_ZONE_HEAD) || (user.zone_selected == BODY_ZONE_CHEST)) + if((user.is_zone_selected(BODY_ZONE_HEAD)) || (user.is_zone_selected(BODY_ZONE_CHEST))) target.apply_damage(stamina_damage, STAMINA, BODY_ZONE_CHEST, def_check) log_combat(user, target, "stunned", src) target.visible_message(desc["visiblestun"], desc["localstun"]) - if((user.zone_selected == BODY_ZONE_R_LEG) || (user.zone_selected == BODY_ZONE_L_LEG)) + if((user.is_zone_selected(BODY_ZONE_R_LEG)) || (user.is_zone_selected(BODY_ZONE_L_LEG))) target.Knockdown(30) log_combat(user, target, "tripped", src) target.visible_message(desc["visibletrip"], desc["localtrip"]) - if(user.zone_selected == BODY_ZONE_L_ARM) + var/combat_zone = user.get_combat_bodyzone(target) + if(combat_zone == BODY_ZONE_L_ARM) target.apply_damage(50, STAMINA, BODY_ZONE_L_ARM, def_check) log_combat(user, target, "disarmed", src) target.visible_message(desc["visibledisarm"], desc["localdisarm"]) - if(user.zone_selected == BODY_ZONE_R_ARM) + if(combat_zone == BODY_ZONE_R_ARM) target.apply_damage(50, STAMINA, BODY_ZONE_R_ARM, def_check) log_combat(user, target, "disarmed", src) target.visible_message(desc["visibledisarm"], desc["localdisarm"]) @@ -711,7 +712,7 @@ if(!ishuman(target)) return - switch(user.zone_selected) + switch(user.get_combat_bodyzone(target)) if(BODY_ZONE_L_ARM) whip_disarm(user, target, "left") if(BODY_ZONE_R_ARM) diff --git a/code/game/objects/items/robot/robot_items.dm b/code/game/objects/items/robot/robot_items.dm index 8fc40dc90ddab..7cc6957e03195 100644 --- a/code/game/objects/items/robot/robot_items.dm +++ b/code/game/objects/items/robot/robot_items.dm @@ -70,7 +70,7 @@ switch(mode) if(0) if(M.health >= 0) - if(user.zone_selected == BODY_ZONE_HEAD) + if(user.is_zone_selected(BODY_ZONE_HEAD, precise_only = TRUE)) user.visible_message("[user] playfully boops [M] on the head!", \ "You playfully boop [M] on the head!") user.do_attack_animation(M, ATTACK_EFFECT_BOOP) @@ -94,7 +94,7 @@ if(!(M.mobility_flags & MOBILITY_STAND)) user.visible_message("[user] shakes [M] trying to get [M.p_them()] up!", \ "You shake [M] trying to get [M.p_them()] up!") - else if(user.zone_selected == BODY_ZONE_HEAD) + else if(user.is_zone_selected(BODY_ZONE_HEAD, precise_only = TRUE)) user.visible_message("[user] bops [M] on the head!", \ "You bop [M] on the head!") user.do_attack_animation(M, ATTACK_EFFECT_PUNCH) diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index 71d41d697e3cd..6a553a1193053 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -40,6 +40,9 @@ if(!iscarbon(M) && !isanimal(M)) to_chat(user, "You don't know how to apply \the [src] to [M]!") return + + if(M in user.do_afters) //One at a time, please. + return if(isanimal(M)) var/mob/living/simple_animal/critter = M @@ -57,15 +60,33 @@ use(1) return + var/datum/task/select_bodyzone_task = user.select_bodyzone(M, FALSE, BODYZONE_STYLE_MEDICAL) + select_bodyzone_task.continue_with(CALLBACK(src, PROC_REF(do_application), M, user)) + +/obj/item/stack/medical/proc/do_application(mob/living/M, mob/user, zone_selected) + if (!zone_selected) + return + if (!user.can_interact_with(M, TRUE)) + to_chat(user, "You cannot reach [M]!") + return + if (!user.can_interact_with(src, TRUE)) + to_chat(user, "You cannot reach [src]!") + return + if(M.stat == DEAD && !stop_bleeding) + to_chat(user, "\The [M] is dead, you cannot help [M.p_them()]!") + return + if(!iscarbon(M)) + to_chat(user, "You don't know how to apply \the [src] to [M]!") + return var/obj/item/bodypart/affecting var/mob/living/carbon/C = M - affecting = C.get_bodypart(check_zone(user.zone_selected)) + affecting = C.get_bodypart(check_zone(zone_selected)) if(M in user.do_afters) //One at a time, please. return if(!affecting) //Missing limb? - to_chat(user, "[C] doesn't have \a [parse_zone(user.zone_selected)]!") + to_chat(user, "[C] doesn't have \a [parse_zone(zone_selected)]!") return if(ishuman(C)) //apparently only humans bleed? funky. @@ -84,7 +105,7 @@ return if(!(affecting.brute_dam || affecting.burn_dam)) - to_chat(user, "[M]'s [parse_zone(user.zone_selected)] isn't hurt!") + to_chat(user, "[M]'s [parse_zone(zone_selected)] isn't hurt!") return if((affecting.brute_dam && !affecting.burn_dam && !heal_brute) || (affecting.burn_dam && !affecting.brute_dam && !heal_burn)) //suffer diff --git a/code/game/objects/items/stunbaton.dm b/code/game/objects/items/stunbaton.dm index b488427db88a5..29a34635387f9 100644 --- a/code/game/objects/items/stunbaton.dm +++ b/code/game/objects/items/stunbaton.dm @@ -177,7 +177,7 @@ if(!deductcharge(hitcost)) return FALSE - var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected)) + var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.get_combat_bodyzone(target))) var/armor_block = target.run_armor_check(affecting, STAMINA) // L.adjustStaminaLoss(stunforce) target.apply_damage(stunforce, STAMINA, affecting, armor_block) diff --git a/code/game/objects/items/tools/powertools.dm b/code/game/objects/items/tools/powertools.dm index 1e8aa0544a917..b44c3afbe6f4d 100644 --- a/code/game/objects/items/tools/powertools.dm +++ b/code/game/objects/items/tools/powertools.dm @@ -72,7 +72,7 @@ /obj/item/powertool/hand_drill/attack(mob/living/M, mob/living/user) if(!istype(M) || tool_behaviour != TOOL_SCREWDRIVER) return ..() - if(user.zone_selected != BODY_ZONE_PRECISE_EYES && user.zone_selected != BODY_ZONE_HEAD) + if(!user.is_zone_selected(BODY_ZONE_PRECISE_EYES, precise_only = TRUE) && !user.is_zone_selected(BODY_ZONE_HEAD, simplified_probability = 40)) return ..() if(HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to harm [M]!") diff --git a/code/game/objects/items/tools/screwdriver.dm b/code/game/objects/items/tools/screwdriver.dm index 3875a5ec30b1b..14f576faae143 100644 --- a/code/game/objects/items/tools/screwdriver.dm +++ b/code/game/objects/items/tools/screwdriver.dm @@ -55,7 +55,7 @@ /obj/item/screwdriver/attack(mob/living/carbon/M, mob/living/carbon/user) if(!istype(M)) return ..() - if(user.zone_selected != BODY_ZONE_PRECISE_EYES && user.zone_selected != BODY_ZONE_HEAD) + if(!user.is_zone_selected(BODY_ZONE_PRECISE_EYES, precise_only = TRUE) && !user.is_zone_selected(BODY_ZONE_HEAD, simplified_probability = 40)) return ..() if(HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to harm [M]!") diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index c47660c3dc38b..c7961370befa2 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -24,7 +24,7 @@ mrdoombringer sez: and remember kids, if you try and PR a fix for this item's gr for further reading, please see: https://github.com/tgstation/tgstation/pull/30173 and https://translate.google.com/translate?sl=auto&tl=en&js=y&prev=_t&hl=en&ie=UTF-8&u=%2F%2Flurkmore.to%2FSS13&edit-text=&act=url */ /obj/item/banhammer/attack(mob/M, mob/user) - if(user.zone_selected == BODY_ZONE_HEAD) + if(user.is_zone_selected(BODY_ZONE_HEAD, precise_only = FALSE)) M.visible_message("[user] are stroking the head of [M] with a bangammer", "[user] are stroking the head with a bangammer", "you hear a bangammer stroking a head"); else M.visible_message("[M] has been banned FOR NO REISIN by [user]", "You have been banned FOR NO REISIN by [user]", "you hear a banhammer banning someone") @@ -814,7 +814,7 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 user.do_attack_animation(M) var/slap_volume = 50 - if(user.zone_selected == BODY_ZONE_HEAD || user.zone_selected == BODY_ZONE_PRECISE_MOUTH) + if(user.is_zone_selected(BODY_ZONE_HEAD, precise_only = TRUE) || user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH, simplified_probability = 50)) user.visible_message("[user] slaps [M] in the face!", "You slap [M] in the face!", "You hear a slap.") diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index fb4d5e1c3285e..719d3d625af9d 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -260,10 +260,7 @@ if(busy) to_chat(user, "Someone's already washing here.") return - var/selected_area = parse_zone(user.zone_selected) - var/washing_face = 0 - if(selected_area in list(BODY_ZONE_HEAD, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_EYES)) - washing_face = 1 + var/washing_face = user.is_zone_selected(BODY_ZONE_HEAD) user.visible_message("[user] starts washing [user.p_their()] [washing_face ? "face" : "hands"]...", \ "You start washing your [washing_face ? "face" : "hands"]...") busy = TRUE diff --git a/code/modules/antagonists/abductor/equipment/abduction_surgery.dm b/code/modules/antagonists/abductor/equipment/abduction_surgery.dm index 82c06c1524f23..6e7e39f53412d 100644 --- a/code/modules/antagonists/abductor/equipment/abduction_surgery.dm +++ b/code/modules/antagonists/abductor/equipment/abduction_surgery.dm @@ -4,7 +4,7 @@ possible_locs = list(BODY_ZONE_CHEST) ignore_clothes = 1 -/datum/surgery/organ_extraction/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/organ_extraction/can_start(mob/user, mob/living/carbon/target, target_zone) if(!ishuman(user)) return 0 var/mob/living/carbon/human/H = user @@ -22,21 +22,21 @@ var/obj/item/organ/IC = null var/list/organ_types = list(/obj/item/organ/heart) -/datum/surgery_step/extract_organ/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/extract_organ/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) for(var/atom/A in target.internal_organs) if(A.type in organ_types) IC = A break user.visible_message("[user] starts to remove [target]'s organs.", "You start to remove [target]'s organs...") -/datum/surgery_step/extract_organ/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/extract_organ/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(IC) - user.visible_message("[user] pulls [IC] out of [target]'s [target_zone]!", "You pull [IC] out of [target]'s [target_zone].") + user.visible_message("[user] pulls [IC] out of [target]'s [surgery.location]!", "You pull [IC] out of [target]'s [surgery.location].") user.put_in_hands(IC) IC.Remove(target) return 1 else - to_chat(user, "You don't find anything in [target]'s [target_zone]!") + to_chat(user, "You don't find anything in [target]'s [surgery.location]!") return 1 /datum/surgery_step/gland_insert @@ -44,10 +44,10 @@ implements = list(/obj/item/organ/heart/gland = 100) time = 32 -/datum/surgery_step/gland_insert/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/gland_insert/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) user.visible_message("[user] starts to insert [tool] into [target].", "You start to insert [tool] into [target]...") -/datum/surgery_step/gland_insert/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/gland_insert/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) user.visible_message("[user] inserts [tool] into [target].", "You insert [tool] into [target].") user.temporarilyRemoveItemFromInventory(tool, TRUE) var/obj/item/organ/heart/gland/gland = tool diff --git a/code/modules/antagonists/wizard/equipment/artefact.dm b/code/modules/antagonists/wizard/equipment/artefact.dm index cdb3511ea8235..22b5341c1ef41 100644 --- a/code/modules/antagonists/wizard/equipment/artefact.dm +++ b/code/modules/antagonists/wizard/equipment/artefact.dm @@ -331,7 +331,7 @@ target.adjust_bodytemperature(50) GiveHint(target) else if(is_pointed(I)) - to_chat(target, "You feel a stabbing pain in [parse_zone(user.zone_selected)]!") + to_chat(target, "You feel a stabbing pain in [parse_zone(user.get_combat_bodyzone(target))]!") target.Paralyze(40) GiveHint(target) else if(istype(I, /obj/item/bikehorn)) @@ -359,7 +359,15 @@ target = input(user, "Select your victim!", "Voodoo") as null|anything in sort_names(possible) return - if(user.zone_selected == BODY_ZONE_CHEST) + var/datum/task/select_zone_task = user.select_bodyzone(user, TRUE, BODYZONE_STYLE_DEFAULT) + select_zone_task.continue_with(CALLBACK(PROC_REF(perform_voodoo), user)) + +/obj/item/voodoo/proc/perform_voodoo(mob/user, zone_selected) + if (!can_interact(user)) + to_chat(user, "You are too far away!") + return + + if(zone_selected == BODY_ZONE_CHEST) if(voodoo_link) target = null voodoo_link.forceMove(drop_location()) @@ -369,7 +377,7 @@ return if(target && cooldown < world.time) - switch(user.zone_selected) + switch(zone_selected) if(BODY_ZONE_PRECISE_MOUTH) var/wgw = stripped_input(user, "What would you like the victim to say", "Voodoo") target.say(wgw, forced = "voodoo doll") diff --git a/code/modules/client/preferences/entries/player/zone_selection.dm b/code/modules/client/preferences/entries/player/zone_selection.dm new file mode 100644 index 0000000000000..d9b64e3c77650 --- /dev/null +++ b/code/modules/client/preferences/entries/player/zone_selection.dm @@ -0,0 +1,28 @@ +/// The preference for zone selection +/datum/preference/choiced/zone_select + db_key = "zone_select" + preference_type = PREFERENCE_PLAYER + category = PREFERENCE_CATEGORY_GAME_PREFERENCES + +/datum/preference/choiced/zone_select/init_possible_values() + return list( + PREFERENCE_BODYZONE_SIMPLIFIED, + PREFERENCE_BODYZONE_INTENT, + ) + +/datum/preference/choiced/zone_select/create_default_value() + // For the time being the default will be the standard intent system + // until we have had some time to play with the new simplified bodyzone + // system and determine if its good or not. If playing with it is acceptable + // and more intuative than bodyzones, switch the default to simplified. + return PREFERENCE_BODYZONE_INTENT + +/datum/preference/choiced/zone_select/apply_to_client(client/client, value) + var/atom/movable/screen/zone_sel/selector = client.mob?.hud_used?.zone_select + if (!selector) + return + // Reset zone selected to a sane value + if (value == PREFERENCE_BODYZONE_SIMPLIFIED) + selector.set_selected_zone(BODY_GROUP_CHEST_HEAD, client.mob) + else + selector.set_selected_zone(BODY_ZONE_CHEST, client.mob) diff --git a/code/modules/client/preferences/middleware/keybindings.dm b/code/modules/client/preferences/middleware/keybindings.dm index 4c06684595967..d3ee0f2ece72b 100644 --- a/code/modules/client/preferences/middleware/keybindings.dm +++ b/code/modules/client/preferences/middleware/keybindings.dm @@ -86,9 +86,12 @@ if (!(keybinding.category in keybindings)) keybindings[keybinding.category] = list() + var/datum/preference/required_type = keybinding.required_pref_type keybindings[keybinding.category][keybinding.name] = list( "name" = keybinding.full_name, "description" = keybinding.description, + "pref_key" = required_type && initial(required_type.db_key), + "pref_value" = keybinding.required_pref_value, ) return keybindings diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index f2480404a187b..31616d8295e27 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -63,8 +63,6 @@ /obj/item/clothing/neck/stethoscope/attack(mob/living/carbon/human/M, mob/living/user) if(ishuman(M) && isliving(user)) if(user.a_intent == INTENT_HELP) - var/body_part = parse_zone(user.zone_selected) - var/heart_strength = "no" var/lung_strength = "no" @@ -84,8 +82,9 @@ if(M.stat == DEAD && heart && world.time - M.timeofdeath < DEFIB_TIME_LIMIT * 10) heart_strength = "a faint, fluttery" - var/diagnosis = (body_part == BODY_ZONE_CHEST ? "You hear [heart_strength] pulse and [lung_strength] respiration." : "You faintly hear [heart_strength] pulse.") - user.visible_message("[user] places [src] against [M]'s [body_part] and listens attentively.", "You place [src] against [M]'s [body_part]. [diagnosis]") + var/diagnosis = (user.is_zone_selected(BODY_ZONE_CHEST) ? "You hear [heart_strength] pulse and [lung_strength] respiration." : "You faintly hear [heart_strength] pulse.") + var/bodypart = parse_zone(user.is_zone_selected(BODY_ZONE_CHEST) ? BODY_ZONE_CHEST : user.get_combat_bodyzone(M)) + user.visible_message("[user] places [src] against [M]'s [bodypart] and listens attentively.", "You place [src] against [M]'s [bodypart]. [diagnosis]") return return ..(M,user) diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index fd17c0fd9bb0a..200d71a99f30d 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -34,7 +34,7 @@ return 0 var/gulp_amount = gulp_size if(M == user) - if(user.zone_selected == BODY_ZONE_PRECISE_MOUTH && !beingChugged) + if(user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH, precise_only = TRUE) && !beingChugged) beingChugged = TRUE user.visible_message("[user] starts chugging [src].", \ "You start chugging [src].") @@ -500,7 +500,7 @@ return TOXLOSS /obj/item/reagent_containers/food/drinks/soda_cans/attack(mob/M, mob/user) - if(M == user && !src.reagents.total_volume && user.a_intent == INTENT_HARM && user.zone_selected == BODY_ZONE_HEAD) + if(M == user && !src.reagents.total_volume && user.a_intent == INTENT_HARM && user.is_zone_selected(BODY_ZONE_HEAD)) user.visible_message("[user] crushes the can of [src] on [user.p_their()] forehead!", "You crush the can of [src] on your forehead.") playsound(user.loc,'sound/weapons/pierce.ogg', rand(10,50), 1) var/obj/item/trash/can/crushed_can = new /obj/item/trash/can(user.loc) diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm index ee7e4f3ee1c36..6cd70bf1f8356 100644 --- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm +++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm @@ -60,20 +60,21 @@ force = 15 //Smashing bottles over someoen's head hurts. - var/obj/item/bodypart/affecting = user.zone_selected //Find what the player is aiming at - var/armor_block = 0 //Get the target's armor values for normal attack damage. var/armor_duration = 0 //The more force the bottle has, the longer the duration. + // Preference for smashing on the head with this item due to it dealing a stun effect on top + var/target_zone = user.is_zone_selected(BODY_ZONE_HEAD) ? BODY_ZONE_HEAD : user.get_combat_bodyzone(target) + //Calculating duration and calculating damage. if(ishuman(target)) var/mob/living/carbon/human/H = target var/headarmor = 0 // Target's head armor - armor_block = H.run_armor_check(affecting, MELEE,"","",armour_penetration) // For normal attack damage + armor_block = H.run_armor_check(target_zone, MELEE,"","",armour_penetration) // For normal attack damage //If they have a hat/helmet and the user is targeting their head. - if(istype(H.head, /obj/item/clothing/head) && affecting == BODY_ZONE_HEAD) + if(istype(H.head, /obj/item/clothing/head) && target_zone == BODY_ZONE_HEAD) headarmor = H.head.armor.melee else headarmor = 0 @@ -83,17 +84,17 @@ else //Only humans can have armor, right? - armor_block = target.run_armor_check(affecting, MELEE) - if(affecting == BODY_ZONE_HEAD) + armor_block = target.run_armor_check(target_zone, MELEE) + if(target_zone == BODY_ZONE_HEAD) armor_duration = bottle_knockdown_duration + force //Apply the damage! armor_block = min(90,armor_block) - target.apply_damage(force, BRUTE, affecting, armor_block) + target.apply_damage(force, BRUTE, target_zone, armor_block) // You are going to knock someone down for longer if they are not wearing a helmet. var/head_attack_message = "" - if(affecting == BODY_ZONE_HEAD && istype(target, /mob/living/carbon/)) + if(target_zone == BODY_ZONE_HEAD && istype(target, /mob/living/carbon/)) head_attack_message = " on the head" //Knock down the target for the duration that we calculated and divide it by 5. if(armor_duration) diff --git a/code/modules/holoparasite/holoparasite_damage.dm b/code/modules/holoparasite/holoparasite_damage.dm index 6276c0d52ce88..f23b52f8e305a 100644 --- a/code/modules/holoparasite/holoparasite_damage.dm +++ b/code/modules/holoparasite/holoparasite_damage.dm @@ -143,7 +143,7 @@ /** * Holoparasites are NOT physically soft like flesh. */ -/mob/living/simple_animal/hostile/holoparasite/can_inject() +/mob/living/simple_animal/hostile/holoparasite/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE) return FALSE /mob/living/simple_animal/hostile/holoparasite/ex_act(severity, target) diff --git a/code/modules/keybindings/bindings_client.dm b/code/modules/keybindings/bindings_client.dm index 94f56f9fe0b24..a35332985088a 100644 --- a/code/modules/keybindings/bindings_client.dm +++ b/code/modules/keybindings/bindings_client.dm @@ -27,6 +27,8 @@ GLOBAL_LIST_INIT(valid_keys, list( // AZERTY support "&" = 1, "É" = 1, "\"" = 1, "(" = 1, "È" = 1, "_" = 1, "Ç" = 1, "À" = 1, ")" = 1, "*" = 1, "$" = 1, "!" = 1, ":" = 1, "²" = 1, "Ù" = 1, "é" = 1, "è" = 1, "ç" = 1, "à" = 1, "ù" = 1, + // Scrolling support + "ScrollUp" = 1, "ScrollDown" = 1, )) /proc/input_sanity_check(client/C, key) diff --git a/code/modules/mob/living/carbon/alien/alien_defense.dm b/code/modules/mob/living/carbon/alien/alien_defense.dm index a8c0b3f87cbe4..0196a8b2eeed1 100644 --- a/code/modules/mob/living/carbon/alien/alien_defense.dm +++ b/code/modules/mob/living/carbon/alien/alien_defense.dm @@ -53,7 +53,7 @@ In all, this is a lot like the monkey code. /N if(!..()) return if(stat != DEAD) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.get_combat_bodyzone(src))) apply_damage(rand(3), BRUTE, affecting) /mob/living/carbon/alien/attack_hand(mob/living/carbon/human/M) @@ -68,7 +68,7 @@ In all, this is a lot like the monkey code. /N playsound(loc, "punch", 25, 1, -1) visible_message("[M] punches [src]!", \ "[M] punches you!", null, COMBAT_MESSAGE_RANGE) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.get_combat_bodyzone(src))) apply_damage(M.dna.species.punchdamage, BRUTE, affecting) log_combat(M, src, "attacked") M.do_attack_animation(src, ATTACK_EFFECT_PUNCH) diff --git a/code/modules/mob/living/carbon/alien/humanoid/queen.dm b/code/modules/mob/living/carbon/alien/humanoid/queen.dm index cbb36665fc112..db3d5e6dc2cb3 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/queen.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/queen.dm @@ -15,7 +15,7 @@ var/alt_inhands_file = 'icons/mob/alienqueen.dmi' var/game_end_timer -/mob/living/carbon/alien/humanoid/royal/can_inject() +/mob/living/carbon/alien/humanoid/royal/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE) return FALSE /mob/living/carbon/alien/humanoid/royal/queen/proc/maidify() diff --git a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm index 425501773550f..52db20e63a1db 100644 --- a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm +++ b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm @@ -6,7 +6,7 @@ log_combat(M, src, "attacked") visible_message("[M] kicks [src]!", \ "[M] kicks you!", null, COMBAT_MESSAGE_RANGE) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.get_combat_bodyzone(src))) apply_damage(M.dna.species.punchdamage, BRUTE, affecting) /mob/living/carbon/alien/larva/attack_hulk(mob/living/carbon/human/user, does_attack_animation = 0) diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 0876340f737d9..e5a468199338b 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -72,7 +72,7 @@ /mob/living/carbon/attacked_by(obj/item/I, mob/living/user) var/obj/item/bodypart/affecting - affecting = get_bodypart(check_zone(user.zone_selected)) + affecting = get_bodypart(check_zone(user.get_combat_bodyzone(src))) if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest) affecting = bodyparts[1] SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting) @@ -274,7 +274,7 @@ return M.visible_message("[M] shakes [src] trying to get [p_them()] up!", \ "You shake [src] trying to get [p_them()] up!") - else if(M.zone_selected == BODY_ZONE_CHEST) + else if(M.is_zone_selected(BODY_ZONE_CHEST)) M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \ "You hug [src] to make [p_them()] feel better!") @@ -305,19 +305,19 @@ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M) for(var/datum/brain_trauma/trauma in M.get_traumas()) trauma.on_hug(M, src) - else if(M.zone_selected == BODY_ZONE_HEAD) + else if(M.is_zone_selected(BODY_ZONE_HEAD)) M.visible_message("[M] pats [src] on the head.", \ "You pat [src] on the head.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat, M) for(var/datum/brain_trauma/trauma in M.get_traumas()) trauma.on_hug(M, src) - else if((M.zone_selected == BODY_ZONE_L_ARM) || (M.zone_selected == BODY_ZONE_R_ARM)) - if(!get_bodypart(check_zone(M.zone_selected))) - to_chat(M, "[src] does not have a [M.zone_selected == BODY_ZONE_L_ARM ? "left" : "right"] arm!") + else if((M.is_zone_selected(BODY_ZONE_L_ARM)) || (M.is_zone_selected(BODY_ZONE_R_ARM))) + if(!get_bodypart(check_zone(M.get_combat_bodyzone(src)))) + to_chat(M, "[src] does not have a [M.get_combat_bodyzone(src) == BODY_ZONE_L_ARM ? "left" : "right"] arm!") else M.visible_message("[M] shakes [src]'s hand.", \ "You shake [src]'s hand.") - else if(M.zone_selected == BODY_ZONE_PRECISE_GROIN) + else if(M.is_zone_selected(BODY_ZONE_PRECISE_GROIN, precise_only = TRUE)) to_chat(M, "ERP is not allowed on this server!") AdjustStun(-60) AdjustKnockdown(-60) diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index b37fec36b4ed5..c6707b08b9166 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -409,7 +409,7 @@ if(!target_zone) if(user) - target_zone = user.zone_selected + target_zone = user.get_combat_bodyzone(src, FALSE, BODYZONE_CONTEXT_INJECTION) else target_zone = BODY_ZONE_CHEST // If targeting the head, see if the head item is thin enough. @@ -874,7 +874,7 @@ . = ..() if(ishuman(over)) var/mob/living/carbon/human/T = over // curbstomp, ported from PP with modifications - if(!src.is_busy && (src.zone_selected == BODY_ZONE_HEAD || src.zone_selected == BODY_ZONE_PRECISE_GROIN) && get_turf(src) == get_turf(T) && !(T.mobility_flags & MOBILITY_STAND) && src.a_intent != INTENT_HELP && !HAS_TRAIT(src, TRAIT_PACIFISM)) //all the stars align, time to curbstomp + if(!src.is_busy && (src.is_zone_selected(BODY_ZONE_HEAD) || src.is_zone_selected(BODY_ZONE_PRECISE_GROIN)) && get_turf(src) == get_turf(T) && !(T.mobility_flags & MOBILITY_STAND) && src.a_intent != INTENT_HELP && !HAS_TRAIT(src, TRAIT_PACIFISM)) //all the stars align, time to curbstomp src.is_busy = TRUE if (!do_after(src, 2.5 SECONDS, T) || get_turf(src) != get_turf(T) || (T.mobility_flags & MOBILITY_STAND) || src.a_intent == INTENT_HELP || src == T) //wait 30ds and make sure the stars still align (Body zone check removed after PR #958) @@ -883,7 +883,7 @@ T.Stun(6) - if(src.zone_selected == BODY_ZONE_HEAD) //curbstomp specific code + if(src.is_zone_selected(BODY_ZONE_HEAD)) //curbstomp specific code var/increment = (T.lying_angle/90)-2 setDir(increment > 0 ? WEST : EAST) @@ -907,7 +907,8 @@ log_combat(src, T, "curbstomped") - else if(src.zone_selected == BODY_ZONE_PRECISE_GROIN) //groinkick specific code + // Will be legs only on simplified mode since groin is legs + else if(src.is_zone_selected(BODY_ZONE_PRECISE_GROIN)) //groinkick specific code var/increment = (T.lying_angle/90)-2 setDir(increment > 0 ? WEST : EAST) diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 4359e07bd7794..f47e90a69db18 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -176,10 +176,10 @@ var/obj/item/bodypart/affecting if(user == src) - affecting = get_bodypart(check_zone(user.zone_selected)) //stabbing yourself always hits the right target + affecting = get_bodypart(check_zone(user.get_combat_bodyzone(src))) //stabbing yourself always hits the right target else - affecting = get_bodypart(ran_zone(user.zone_selected)) - var/target_area = parse_zone(check_zone(user.zone_selected)) //our intended target + affecting = get_bodypart(ran_zone(user.get_combat_bodyzone(src))) + var/target_area = parse_zone(check_zone(user.get_combat_bodyzone(src))) //our intended target if(affecting) if(I.force && I.damtype != STAMINA && (!IS_ORGANIC_LIMB(affecting))) // Bodpart_robotic sparks when hit, but only when it does real damage if(I.force >= 5) @@ -206,7 +206,7 @@ var/message = "[user] has [hulk_verb]ed [src]!" visible_message("[message]", \ "[message]") - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(user.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(user.get_combat_bodyzone(src))) if(!affecting) affecting = get_bodypart(BODY_ZONE_CHEST) var/armor_block = run_armor_check(affecting, MELEE,"","",10) @@ -257,7 +257,7 @@ if(M.a_intent == INTENT_HARM) if (w_uniform) w_uniform.add_fingerprint(M) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.get_combat_bodyzone(src))) if(!affecting) affecting = get_bodypart(BODY_ZONE_CHEST) var/armor_block = run_armor_check(affecting, MELEE,"","",10) @@ -266,7 +266,7 @@ visible_message("[M] slashes at [src]!", \ "[M] slashes at you!") log_combat(M, src, "attacked") - if(!dismembering_strike(M, M.zone_selected)) //Dismemberment successful + if(!dismembering_strike(M, M.get_combat_bodyzone(src))) //Dismemberment successful return 1 apply_damage(20, BRUTE, affecting, armor_block) @@ -274,7 +274,7 @@ playsound(loc, 'sound/weapons/pierce.ogg', 25, 1, -1) Knockdown(20) log_combat(M, src, "tackled") - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.get_combat_bodyzone(src))) if(!affecting) affecting = get_bodypart(BODY_ZONE_CHEST) var/armor_block = run_armor_check(affecting, MELEE,"","",10) @@ -291,7 +291,7 @@ return 0 if(stat != DEAD) L.amount_grown = min(L.amount_grown + damage, L.max_grown) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.get_combat_bodyzone(src))) if(!affecting) affecting = get_bodypart(BODY_ZONE_CHEST) var/armor_block = run_armor_check(affecting, MELEE) diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 8a08bf82c6f06..dda8929df62de 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -1526,7 +1526,7 @@ GLOBAL_LIST_EMPTY(features_by_species) return TRUE else //Steal them shoes - if(!(target.mobility_flags & MOBILITY_STAND) && (user.zone_selected == BODY_ZONE_L_LEG || user.zone_selected == BODY_ZONE_R_LEG) && user.a_intent == INTENT_GRAB && target.shoes) + if(!(target.mobility_flags & MOBILITY_STAND) && (user.is_zone_selected(BODY_ZONE_L_LEG) || user.is_zone_selected(BODY_ZONE_R_LEG)) && user.a_intent == INTENT_GRAB && target.shoes) if(HAS_TRAIT(target.shoes, TRAIT_NODROP)) target.grabbedby(user) return TRUE @@ -1569,7 +1569,7 @@ GLOBAL_LIST_EMPTY(features_by_species) var/damage = user.dna.species.punchdamage - var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.zone_selected)) + var/obj/item/bodypart/affecting = target.get_bodypart(ran_zone(user.get_combat_bodyzone(target))) if(!damage || !affecting)//future-proofing for species that have 0 damage/weird cases where no zone is targeted playsound(target.loc, user.dna.species.miss_sound, 25, 1, -1) @@ -1626,7 +1626,7 @@ GLOBAL_LIST_EMPTY(features_by_species) if(target.w_uniform) target.w_uniform.add_fingerprint(user) - SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.zone_selected) + SEND_SIGNAL(target, COMSIG_HUMAN_DISARM_HIT, user, user.get_combat_bodyzone(target)) var/turf/target_oldturf = target.loc var/shove_dir = get_dir(user.loc, target_oldturf) diff --git a/code/modules/mob/living/carbon/human/species_types/pumpkin_man.dm b/code/modules/mob/living/carbon/human/species_types/pumpkin_man.dm index 85a4357f7804d..ec390b8df420b 100644 --- a/code/modules/mob/living/carbon/human/species_types/pumpkin_man.dm +++ b/code/modules/mob/living/carbon/human/species_types/pumpkin_man.dm @@ -61,7 +61,7 @@ //Check if the item is sharp - give owner a random face if applicable var/mob/living/carbon/human/M = _source var/obj/item/bodypart/head/pumpkin_man/head = M.get_bodypart(BODY_ZONE_HEAD) - if(_item.is_sharp() && head?.item_flags & ISCARVABLE && _user.a_intent == INTENT_HELP && _user.zone_selected == BODY_ZONE_HEAD) + if(_item.is_sharp() && head?.item_flags & ISCARVABLE && _user.a_intent == INTENT_HELP && _user.is_zone_selected(BODY_ZONE_HEAD)) to_chat(_user, "You begin to carve a face into [_source]...") //Do after for *flourish* if(do_after(_user, 3 SECONDS)) diff --git a/code/modules/mob/living/carbon/monkey/monkey_defense.dm b/code/modules/mob/living/carbon/monkey/monkey_defense.dm index 1dd266a6ebb7b..9021281aaab82 100644 --- a/code/modules/mob/living/carbon/monkey/monkey_defense.dm +++ b/code/modules/mob/living/carbon/monkey/monkey_defense.dm @@ -22,7 +22,7 @@ var/damage = rand(1, 3) if(stat != DEAD) L.amount_grown = min(L.amount_grown + damage, L.max_grown) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(L.get_combat_bodyzone(src))) if(!affecting) affecting = get_bodypart(BODY_ZONE_CHEST) apply_damage(damage, BRUTE, affecting) @@ -42,7 +42,7 @@ "[M] punches you!", null, COMBAT_MESSAGE_RANGE) playsound(loc, "punch", 25, 1, -1) var/damage = M.dna.species.punchdamage - var/obj/item/bodypart/affecting = get_bodypart(check_zone(M.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(check_zone(M.get_combat_bodyzone(src))) if(!affecting) affecting = get_bodypart(BODY_ZONE_CHEST) apply_damage(damage, BRUTE, affecting) @@ -73,7 +73,7 @@ visible_message("[M] slashes [name]!", \ "[M] slashes you!", null, COMBAT_MESSAGE_RANGE) - var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.zone_selected)) + var/obj/item/bodypart/affecting = get_bodypart(ran_zone(M.get_combat_bodyzone(src))) log_combat(M, src, "attacked") if(!affecting) affecting = get_bodypart(BODY_ZONE_CHEST) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 3c1bf8db0dd3a..d331b0d850c97 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -318,14 +318,14 @@ log_combat(src, M, "grabbed", addition="passive grab") if(!supress_message && !(iscarbon(AM) && HAS_TRAIT(src, TRAIT_STRONG_GRABBER))) //Everything in this if statement handles chat messages for grabbing var/mob/living/L = M - if (L.getorgan(/obj/item/organ/tail) && zone_selected == BODY_ZONE_PRECISE_GROIN) //Does the target have a tail? + if (L.getorgan(/obj/item/organ/tail) && (is_zone_selected(BODY_ZONE_PRECISE_GROIN, precise_only = TRUE) || is_group_selected(BODY_GROUP_LEGS))) //Does the target have a tail? M.visible_message("[src] grabs [L] by [L.p_their()] tail!",\ " [src] grabs you by the tail!", null, null, src) //Message sent to area, Message sent to grabbee to_chat(src, "You grab [L] by [L.p_their()] tail!") //Message sent to grabber else - M.visible_message("[src] grabs [M] [(zone_selected == BODY_ZONE_L_ARM || zone_selected == BODY_ZONE_R_ARM)? "by their hands":"passively"]!", \ - "[src] grabs you [(zone_selected == BODY_ZONE_L_ARM || zone_selected == BODY_ZONE_R_ARM)? "by your hands":"passively"]!", null, null, src) //Message sent to area, Message sent to grabbee - to_chat(src, "You grab [M] [(zone_selected == BODY_ZONE_L_ARM|| zone_selected == BODY_ZONE_R_ARM)? "by their hands":"passively"]!") //Message sent to grabber + M.visible_message("[src] grabs [M] [(is_zone_selected(BODY_ZONE_L_ARM) || is_zone_selected(BODY_ZONE_R_ARM))? "by their hands":"passively"]!", \ + "[src] grabs you [(is_zone_selected(BODY_ZONE_L_ARM) || is_zone_selected(BODY_ZONE_R_ARM))? "by your hands":"passively"]!", null, null, src) //Message sent to area, Message sent to grabbee + to_chat(src, "You grab [M] [(is_zone_selected(BODY_ZONE_L_ARM) || is_zone_selected(BODY_ZONE_R_ARM))? "by their hands":"passively"]!") //Message sent to grabber if(!iscarbon(src)) M.LAssailant = null else @@ -543,7 +543,7 @@ return FALSE // Living mobs use can_inject() to make sure that the mob is not syringe-proof in general. -/mob/living/proc/can_inject() +/mob/living/proc/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE) return TRUE /mob/living/is_injectable(mob/user, allowmobs = TRUE) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 4ed9a04c30f0d..8c9f416283761 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -165,7 +165,7 @@ for(var/key in alarm_types_clear) alarm_types_clear[key] = 0 -/mob/living/silicon/can_inject(mob/user, error_msg) +/mob/living/silicon/can_inject(mob/user, error_msg, target_zone, penetrate_thick = FALSE) if(error_msg) to_chat(user, "[p_their(TRUE)] outer shell is too tough.") return FALSE diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index afdc1eab41c18..0b260b6a37af0 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -48,7 +48,8 @@ */ /// The zone this mob is currently targeting - var/zone_selected = BODY_ZONE_CHEST + /// Use select_bodyzone and get_combat_bodyzone to get this value + VAR_PRIVATE/zone_selected = BODY_ZONE_CHEST var/computer_id = null var/list/logging = list() diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index b2d9fdacf98fe..c542890c09a6a 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -608,3 +608,116 @@ return TRUE else if(HAS_TRAIT(src, TRAIT_BARMASTER)) return TRUE + +/** + * Zone selection helpers. + * + * There are 2 ways to get the zone selected, a combat mode + * which determines the zone to target based on what target was + * pressed and a non-combat mode which displays a wheel of options. + */ + +/mob/proc/select_bodyzone(atom/target, precise = FALSE, style = BODYZONE_STYLE_DEFAULT, override_zones = null) + DECLARE_ASYNC + // Get the selected bodyzone + if (client?.prefs.read_player_preference(/datum/preference/choiced/zone_select) == PREFERENCE_BODYZONE_SIMPLIFIED) + switch (style) + if (BODYZONE_STYLE_DEFAULT) + ASYNC_RETURN_TASK(select_bodyzone_from_wheel(target, precise, override_zones = override_zones)) + if (BODYZONE_STYLE_MEDICAL) + var/accurate_health = HAS_TRAIT(src, TRAIT_MEDICAL_HUD) || istype(get_inactive_held_item(), /obj/item/healthanalyzer) + if (!accurate_health && isliving(target)) + to_chat(src, "You could more easilly determine how injured [target] was if you had a medical hud or a health analyser!") + ASYNC_RETURN_TASK(select_bodyzone_from_wheel(target, precise, CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(select_bodyzone_limb_health), accurate_health), override_zones)) + // Return the value instantly + if (precise) + ASYNC_RETURN(zone_selected) + ASYNC_RETURN(check_zone(zone_selected)) + +/** + * Get the zone that we probably wanted to target. This depends on the context. + * If we are in an injection context (quick injects like the hyposray) then we will + * target the first part in the group that isn't protected from injections. + * If we are in a combat context, then we will randomly pick legs, head and chest and + * will pick the arm that the target currently has selected. + * Arm target: Disarm target + * Leg target: Reduce mobility of target + * Head/Chest target: Damage/kill target + */ +/mob/proc/get_combat_bodyzone(atom/target = null, precise = FALSE, zone_context = BODYZONE_CONTEXT_COMBAT) + // Just grab whatever bodyzone they were targetting + if (client?.prefs.read_player_preference(/datum/preference/choiced/zone_select) != PREFERENCE_BODYZONE_SIMPLIFIED) + if (!precise) + return check_zone(zone_selected) + return zone_selected || BODY_ZONE_CHEST + // Implicitly determine the bodypart we were trying to target + switch (zone_selected) + if (BODY_GROUP_CHEST_HEAD) + var/head_priority = is_priority_zone(target, BODY_ZONE_HEAD, zone_context) + var/chest_priority = is_priority_zone(target, BODY_ZONE_CHEST, zone_context) + return head_priority == chest_priority ? (prob(70) ? BODY_ZONE_CHEST : BODY_ZONE_HEAD) : (head_priority ? BODY_ZONE_HEAD : BODY_ZONE_CHEST) + if (BODY_GROUP_LEGS) + var/left_priority = is_priority_zone(target, BODY_ZONE_L_LEG, zone_context) + var/right_priority = is_priority_zone(target, BODY_ZONE_R_LEG, zone_context) + return left_priority == right_priority ? pick(BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) : (left_priority ? BODY_ZONE_R_LEG : BODY_ZONE_R_LEG) + if (BODY_GROUP_ARMS) + var/left_priority = is_priority_zone(target, BODY_ZONE_L_ARM, zone_context) + var/right_priority = is_priority_zone(target, BODY_ZONE_R_ARM, zone_context) + return left_priority == right_priority ? pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM) : (left_priority ? BODY_ZONE_L_ARM : BODY_ZONE_R_ARM) + +/mob/proc/is_priority_zone(atom/target, target_zone, context) + switch (context) + // Prioritise active hand + if (BODYZONE_CONTEXT_COMBAT) + if (isliving(target)) + var/mob/living/living_target = target + if (living_target.active_hand_index == 1) + return target_zone == BODY_ZONE_L_ARM + else + return target_zone == BODY_ZONE_R_ARM + return FALSE + // Prioritise things that aren't injection proof + if (BODYZONE_CONTEXT_INJECTION) + if (isliving(target)) + var/mob/living/living_target = target + return living_target.can_inject(target_zone = target_zone) + return FALSE + // Prioritise robotic limbs + if (BODYZONE_CONTEXT_ROBOTIC_LIMB_HEALING) + if (isliving(target)) + var/mob/living/living_target = target + var/obj/item/bodypart/limb = living_target.get_bodypart(target_zone) + if (!limb) + return FALSE + return !IS_ORGANIC_LIMB(limb) && (limb.get_damage() > 0) + return FALSE + +/// Does the mob have a specific bodyzone group selected? +/// This will only work if you are using the simplified system (I mean it will work +/// if the mob isn't, but this proc shouldn't be used for that) +/mob/proc/is_group_selected(requested_group) + return zone_selected == requested_group + +/mob/proc/is_zone_selected(requested_zone = BODY_ZONE_CHEST, simplified_probability = 100, precise_only = FALSE, precise = TRUE) + if (client?.prefs.read_player_preference(/datum/preference/choiced/zone_select) != PREFERENCE_BODYZONE_SIMPLIFIED) + return zone_selected == requested_zone || (!precise && check_zone(zone_selected) == requested_zone) + if (precise_only) + return FALSE + // Check if we randomly don't hit the selected zone + if (simplified_probability != 100 && !prob(simplified_probability)) + return FALSE + if (requested_zone == zone_selected) + return TRUE + switch (zone_selected) + if (BODY_GROUP_LEGS) + return requested_zone == BODY_ZONE_L_LEG || requested_zone == BODY_ZONE_R_LEG || requested_zone == BODY_ZONE_PRECISE_L_FOOT || requested_zone == BODY_ZONE_PRECISE_R_FOOT || requested_zone == BODY_ZONE_PRECISE_GROIN + if (BODY_GROUP_ARMS) + return requested_zone == BODY_ZONE_L_ARM || requested_zone == BODY_ZONE_R_ARM || requested_zone == BODY_ZONE_PRECISE_L_HAND || requested_zone == BODY_ZONE_PRECISE_R_HAND + if (BODY_GROUP_CHEST_HEAD) + return requested_zone == BODY_ZONE_CHEST || requested_zone == BODY_ZONE_HEAD || requested_zone == BODY_ZONE_PRECISE_EYES || requested_zone == BODY_ZONE_PRECISE_MOUTH + +/** + * Don't use this + */ +/mob/proc/_set_zone_selected(zone_selected) + src.zone_selected = zone_selected diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index fde8a758ef52d..d3085aee11e8d 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -391,8 +391,10 @@ if(!check_has_body_select()) return + var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + var/next_in_line - switch(mob.zone_selected) + switch(selector.selecting) if(BODY_ZONE_HEAD) next_in_line = BODY_ZONE_PRECISE_EYES if(BODY_ZONE_PRECISE_EYES) @@ -400,7 +402,6 @@ else next_in_line = BODY_ZONE_HEAD - var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select selector.set_selected_zone(next_in_line, mob) ///Hidden verb to target the right arm, bound to 4 @@ -469,6 +470,34 @@ var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select selector.set_selected_zone(BODY_ZONE_L_LEG, mob) +/client/verb/body_up() + set name = "body-up" + set hidden = 1 + + if(!check_has_body_select()) + return + + var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + switch (selector.selecting) + if (BODY_GROUP_LEGS, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG) + selector.set_selected_zone(BODY_GROUP_ARMS, mob) + if (BODY_GROUP_ARMS, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM) + selector.set_selected_zone(BODY_GROUP_CHEST_HEAD, mob) + +/client/verb/body_down() + set name = "body-down" + set hidden = 1 + + if(!check_has_body_select()) + return + + var/atom/movable/screen/zone_sel/selector = mob.hud_used.zone_select + switch (selector.selecting) + if (BODY_GROUP_CHEST_HEAD, BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH, BODY_ZONE_PRECISE_GROIN) + selector.set_selected_zone(BODY_GROUP_ARMS, mob) + if (BODY_GROUP_ARMS, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM) + selector.set_selected_zone(BODY_GROUP_LEGS, mob) + ///Verb to toggle the walk or run status /client/verb/toggle_walk_run() set name = "toggle-walk-run" diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm index 57362d7b7e01d..a32d674606df5 100644 --- a/code/modules/paperwork/pen.dm +++ b/code/modules/paperwork/pen.dm @@ -312,7 +312,7 @@ return ..() if(!istype(M)) return ..() - if(user.zone_selected != BODY_ZONE_PRECISE_EYES && user.zone_selected != BODY_ZONE_HEAD) + if(!user.is_zone_selected(BODY_ZONE_PRECISE_EYES) && !user.is_zone_selected(BODY_ZONE_HEAD)) return ..() if(HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You don't want to harm [M]!") diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm index 93082748f1d88..b3f6c491ccfcf 100644 --- a/code/modules/projectiles/ammunition/_firing.dm +++ b/code/modules/projectiles/ammunition/_firing.dm @@ -33,7 +33,7 @@ if (zone_override) BB.def_zone = zone_override else - BB.def_zone = user.zone_selected + BB.def_zone = user.get_combat_bodyzone(target) BB.suppressed = quiet if(reagents && BB.reagents) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 73f4eaf938a43..50a7378c30c68 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -303,7 +303,7 @@ return if(!ismob(target) || user.a_intent == INTENT_HARM) //melee attack return - if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected) + if(target == user && user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH)) //so we can't shoot ourselves (unless mouth selected) return if(istype(user))//Check if the user can use the gun, if the user isn't alive(turrets) assume it can. @@ -312,7 +312,15 @@ return if(flag) - if(user.zone_selected == BODY_ZONE_PRECISE_MOUTH) + var/simplified_mode = user.client?.prefs.read_player_preference(/datum/preference/choiced/zone_select) == PREFERENCE_BODYZONE_SIMPLIFIED + var/mob/living/living_target = target + if (!simplified_mode) + if(user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH)) + handle_suicide(user, target, params) + return + // On simplified mode, contextually determine if we want to suicide them + // If the target is ourselves, they are buckled, restrained or lying down then suicide them + else if(user.is_zone_selected(BODY_ZONE_HEAD) && istype(living_target) && (user == target || living_target.restrained() || living_target.buckled || living_target.IsUnconscious())) handle_suicide(user, target, params) return @@ -732,7 +740,7 @@ semicd = TRUE - if(!bypass_timer && (!do_after(user, 12 SECONDS, target) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH)) + if(!bypass_timer && (!do_after(user, 12 SECONDS, target) || !user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH))) if(user) if(user == target) user.visible_message("[user] decided not to shoot.") diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm index 727652d49ee27..5c7a0cdc89815 100644 --- a/code/modules/projectiles/guns/ballistic/revolver.dm +++ b/code/modules/projectiles/guns/ballistic/revolver.dm @@ -250,7 +250,7 @@ var/obj/item/ammo_casing/AC = chambered if(AC.fire_casing(user, user)) playsound(user, fire_sound, fire_sound_volume, vary_fire_sound) - var/zone = check_zone(user.zone_selected) + var/zone = check_zone(user.get_combat_bodyzone(target)) var/obj/item/bodypart/affecting = H.get_bodypart(zone) if(zone == BODY_ZONE_HEAD || zone == BODY_ZONE_PRECISE_EYES || zone == BODY_ZONE_PRECISE_MOUTH) shoot_self(user, affecting) diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm index d81f15dcb0cc2..a87cacd48d9c9 100644 --- a/code/modules/projectiles/guns/misc/beam_rifle.dm +++ b/code/modules/projectiles/guns/misc/beam_rifle.dm @@ -302,7 +302,7 @@ return if(!ismob(target) || user.a_intent == INTENT_HARM) //melee attack return - if(target == user && user.zone_selected != BODY_ZONE_PRECISE_MOUTH) //so we can't shoot ourselves (unless mouth selected) + if(target == user && !user.is_zone_selected(BODY_ZONE_PRECISE_MOUTH)) //so we can't shoot ourselves (unless mouth selected) return if(!passthrough && (aiming_time > aiming_time_fire_threshold)) return diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm index 939fb14f9738f..d6f0ca14de7ec 100644 --- a/code/modules/reagents/reagent_containers/borghydro.dm +++ b/code/modules/reagents/reagent_containers/borghydro.dm @@ -102,7 +102,7 @@ Borg Hypospray return if(!istype(M)) return - if(R.total_volume && M.can_inject(user, 1, user.zone_selected,bypass_protection)) + if(R.total_volume && M.can_inject(user, 1, user.get_combat_bodyzone(M, zone_context = BODYZONE_CONTEXT_INJECTION), bypass_protection)) to_chat(M, "You feel a tiny prick!") to_chat(user, "You inject [M] with the injector.") var/fraction = min(amount_per_transfer_from_this/R.total_volume, 1) diff --git a/code/modules/reagents/reagent_containers/medspray.dm b/code/modules/reagents/reagent_containers/medspray.dm index 7369017018af3..cd10521efbb0a 100644 --- a/code/modules/reagents/reagent_containers/medspray.dm +++ b/code/modules/reagents/reagent_containers/medspray.dm @@ -32,7 +32,7 @@ amount_per_transfer_from_this = initial(amount_per_transfer_from_this) to_chat(user, "You will now apply the medspray's contents in [squirt_mode ? "short bursts":"extended sprays"]. You'll now use [amount_per_transfer_from_this] units per use.") -/obj/item/reagent_containers/medspray/attack(mob/living/carbon/M, mob/user, def_zone) +/obj/item/reagent_containers/medspray/attack(mob/living/carbon/M, mob/user) if(!iscarbon(M)) return @@ -40,7 +40,19 @@ to_chat(user, "[src] is empty!") return - var/obj/item/bodypart/affecting = M.get_bodypart(check_zone(user.zone_selected)) + var/datum/task/target_zone_task = user.select_bodyzone(M, FALSE, BODYZONE_STYLE_MEDICAL) + target_zone_task.continue_with(CALLBACK(src, PROC_REF(do_spray), M, user)) + +/obj/item/reagent_containers/medspray/proc/do_spray(mob/living/carbon/M, mob/user, def_zone) + if (!def_zone) + return + if (!user.can_interact_with(M, TRUE)) + balloon_alert(user, "[M] is too far away!") + return + if (!user.can_interact_with(src, TRUE)) + balloon_alert(user, "[src] is too far away!") + return + var/obj/item/bodypart/affecting = M.get_bodypart(check_zone(def_zone)) if(!affecting) balloon_alert(user, "The limb is missing.") return diff --git a/code/modules/reagents/reagent_containers/patch.dm b/code/modules/reagents/reagent_containers/patch.dm index 75ebe0daa310d..384cd193c165a 100644 --- a/code/modules/reagents/reagent_containers/patch.dm +++ b/code/modules/reagents/reagent_containers/patch.dm @@ -10,17 +10,30 @@ self_delay = 3 SECONDS dissolvable = FALSE -/obj/item/reagent_containers/pill/patch/attack(mob/living/L, mob/user, obj/item/bodypart/affecting) +/obj/item/reagent_containers/pill/patch/attack(mob/living/L, mob/user) if(!ishuman(L)) return ..() - affecting = L.get_bodypart(check_zone(user.zone_selected)) + var/datum/task/select_bodyzone = user.select_bodyzone(L, FALSE, BODYZONE_STYLE_MEDICAL) + select_bodyzone.continue_with(CALLBACK(src, PROC_REF(apply_part), L, user)) + return TRUE + +/obj/item/reagent_containers/pill/patch/proc/apply_part(mob/living/L, mob/user, selected_target) + if (!selected_target) + return + if (!user.can_interact_with(L, TRUE)) + balloon_alert(user, "[L] is too far away!") + return + if (!user.can_interact_with(src, TRUE)) + balloon_alert(user, "[src] is too far away!") + return + var/obj/item/bodypart/affecting = L.get_bodypart(selected_target) if(!affecting) balloon_alert(user, "The limb is missing.") return if(!IS_ORGANIC_LIMB(affecting)) balloon_alert(user, "[src] doesn't work on robotic limbs.") return - return ..() + perform_application(L, user, affecting) /obj/item/reagent_containers/pill/patch/canconsume(mob/eater, mob/user) if(!iscarbon(eater)) diff --git a/code/modules/reagents/reagent_containers/pill.dm b/code/modules/reagents/reagent_containers/pill.dm index cbee1647f4e10..4efc4fbe5c21e 100644 --- a/code/modules/reagents/reagent_containers/pill.dm +++ b/code/modules/reagents/reagent_containers/pill.dm @@ -27,7 +27,10 @@ return -/obj/item/reagent_containers/pill/attack(mob/M, mob/user, obj/item/bodypart/affecting) +/obj/item/reagent_containers/pill/attack(mob/M, mob/user, def_zone) + perform_application(M, user, null) + +/obj/item/reagent_containers/pill/proc/perform_application(mob/M, mob/user, obj/item/bodypart/affecting) if(!canconsume(M, user)) return FALSE if(iscarbon(M)) @@ -59,7 +62,6 @@ qdel(src) return TRUE - /obj/item/reagent_containers/pill/afterattack(obj/target, mob/user , proximity) . = ..() if(!proximity) diff --git a/code/modules/religion/religion_sects.dm b/code/modules/religion/religion_sects.dm index b03a9fecfeb40..c773691fe9b8e 100644 --- a/code/modules/religion/religion_sects.dm +++ b/code/modules/religion/religion_sects.dm @@ -167,9 +167,9 @@ eth_stomach.adjust_charge(60) did_we_charge = TRUE - //if we're not targetting a robot part we stop early - var/obj/item/bodypart/bodypart = blessed.get_bodypart(chap.zone_selected) - if(!IS_ORGANIC_LIMB(bodypart)) + //if we're not targeting a robot part we stop early + var/obj/item/bodypart/bodypart = blessed.get_bodypart(chap.get_combat_bodyzone(target, zone_context = BODYZONE_CONTEXT_ROBOTIC_LIMB_HEALING)) + if(IS_ORGANIC_LIMB(bodypart)) if(!did_we_charge) to_chat(chap, "[GLOB.deity] scoffs at the idea of healing such fleshy matter!") else diff --git a/code/modules/surgery/advanced/bioware/cortex_folding.dm b/code/modules/surgery/advanced/bioware/cortex_folding.dm index fb6216c1ef760..ca11a23eee374 100644 --- a/code/modules/surgery/advanced/bioware/cortex_folding.dm +++ b/code/modules/surgery/advanced/bioware/cortex_folding.dm @@ -14,7 +14,7 @@ bioware_target = BIOWARE_CORTEX -/datum/surgery/advanced/bioware/cortex_folding/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/advanced/bioware/cortex_folding/can_start(mob/user, mob/living/carbon/target, target_zone) var/obj/item/organ/brain/target_brain = target.getorganslot(ORGAN_SLOT_BRAIN) if(!target_brain) return FALSE @@ -25,7 +25,7 @@ accept_hand = TRUE time = 125 -/datum/surgery_step/fold_cortex/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/fold_cortex/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results( user, target, @@ -34,7 +34,7 @@ "[user] begins to perform surgery on [target]'s brain.", ) -/datum/surgery_step/fold_cortex/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) +/datum/surgery_step/fold_cortex/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) display_results( user, target, @@ -45,7 +45,7 @@ new /datum/bioware/cortex_fold(target) return ..() -/datum/surgery_step/fold_cortex/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/fold_cortex/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(target.getorganslot(ORGAN_SLOT_BRAIN)) display_results( user, diff --git a/code/modules/surgery/advanced/bioware/cortex_imprint.dm b/code/modules/surgery/advanced/bioware/cortex_imprint.dm index bec0637b8e7db..7c376508bc0a9 100644 --- a/code/modules/surgery/advanced/bioware/cortex_imprint.dm +++ b/code/modules/surgery/advanced/bioware/cortex_imprint.dm @@ -14,7 +14,7 @@ bioware_target = BIOWARE_CORTEX -/datum/surgery/advanced/bioware/cortex_imprint/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/advanced/bioware/cortex_imprint/can_start(mob/user, mob/living/carbon/target, target_zone) var/obj/item/organ/brain/target_brain = target.getorganslot(ORGAN_SLOT_BRAIN) if(!target_brain) return FALSE @@ -25,7 +25,7 @@ accept_hand = TRUE time = 125 -/datum/surgery_step/imprint_cortex/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/imprint_cortex/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results( user, target, @@ -34,7 +34,7 @@ "[user] begins to perform surgery on [target]'s brain.", ) -/datum/surgery_step/imprint_cortex/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) +/datum/surgery_step/imprint_cortex/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) display_results( user, target, @@ -45,7 +45,7 @@ new /datum/bioware/cortex_imprint(target) return ..() -/datum/surgery_step/imprint_cortex/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/imprint_cortex/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(target.getorganslot(ORGAN_SLOT_BRAIN)) display_results( user, diff --git a/code/modules/surgery/advanced/bioware/experimental_dissection.dm b/code/modules/surgery/advanced/bioware/experimental_dissection.dm index 12de45aa7a2a6..741e4164e8e41 100644 --- a/code/modules/surgery/advanced/bioware/experimental_dissection.dm +++ b/code/modules/surgery/advanced/bioware/experimental_dissection.dm @@ -10,7 +10,7 @@ possible_locs = list(BODY_ZONE_CHEST) target_mobtypes = list(/mob/living/carbon) //Feel free to dissect devils but they're magic. -/datum/surgery/advanced/experimental_dissection/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/advanced/experimental_dissection/can_start(mob/user, mob/living/carbon/target, target_zone) . = ..() if(HAS_TRAIT(target, TRAIT_DISSECTED)) return FALSE @@ -25,7 +25,7 @@ implements = list(TOOL_SCALPEL = 60, /obj/item/knife = 30, /obj/item/shard = 15) time = 125 -/datum/surgery_step/dissection/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/dissection/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) user.visible_message("[user] starts dissecting [target].", "You start dissecting [target].") /datum/surgery_step/dissection/proc/check_value(mob/living/carbon/target) @@ -46,7 +46,7 @@ return 3000 return 2000 -/datum/surgery_step/dissection/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/dissection/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) user.visible_message("[user] dissects [target]!", "You dissect [target], and add your discoveries to the research database!") SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_DISCOVERY = check_value(target))) var/obj/item/bodypart/L = target.get_bodypart(BODY_ZONE_CHEST) @@ -54,7 +54,7 @@ ADD_TRAIT(target, TRAIT_DISSECTED, "surgery") return TRUE -/datum/surgery_step/dissection/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/dissection/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) user.visible_message("[user] dissects [target]!", "You dissect [target], but do not find anything particularly interesting.") SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_DISCOVERY = (check_value(target) * 0.2))) var/obj/item/bodypart/L = target.get_bodypart(BODY_ZONE_CHEST) diff --git a/code/modules/surgery/advanced/bioware/ligament_hook.dm b/code/modules/surgery/advanced/bioware/ligament_hook.dm index cf47e774cc5eb..0b05040622dee 100644 --- a/code/modules/surgery/advanced/bioware/ligament_hook.dm +++ b/code/modules/surgery/advanced/bioware/ligament_hook.dm @@ -17,12 +17,12 @@ accept_hand = TRUE time = 125 -/datum/surgery_step/reshape_ligaments/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/reshape_ligaments/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You start reshaping [target]'s ligaments into a hook-like shape.", "[user] starts reshaping [target]'s ligaments into a hook-like shape.", "[user] starts manipulating [target]'s ligaments.") -/datum/surgery_step/reshape_ligaments/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/reshape_ligaments/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You reshape [target]'s ligaments into a connective hook!", "[user] reshapes [target]'s ligaments into a connective hook!", "[user] finishes manipulating [target]'s ligaments.") diff --git a/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm b/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm index 7d65c9dd0d092..0c7350419fe91 100644 --- a/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm +++ b/code/modules/surgery/advanced/bioware/ligament_reinforcement.dm @@ -17,12 +17,12 @@ accept_hand = TRUE time = 125 -/datum/surgery_step/reinforce_ligaments/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/reinforce_ligaments/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You start reinforcing [target]'s ligaments.", "[user] starts reinforce [target]'s ligaments.", "[user] starts manipulating [target]'s ligaments.") -/datum/surgery_step/reinforce_ligaments/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/reinforce_ligaments/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You reinforce [target]'s ligaments!", "[user] reinforces [target]'s ligaments!", "[user] finishes manipulating [target]'s ligaments.") diff --git a/code/modules/surgery/advanced/bioware/muscled_veins.dm b/code/modules/surgery/advanced/bioware/muscled_veins.dm index c9771d8b295d8..f45d6035ab447 100644 --- a/code/modules/surgery/advanced/bioware/muscled_veins.dm +++ b/code/modules/surgery/advanced/bioware/muscled_veins.dm @@ -16,12 +16,12 @@ accept_hand = TRUE time = 125 -/datum/surgery_step/muscled_veins/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/muscled_veins/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You start wrapping muscles around [target]'s circulatory system.", "[user] starts wrapping muscles around [target]'s circulatory system.", "[user] starts manipulating [target]'s circulatory system.") -/datum/surgery_step/muscled_veins/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/muscled_veins/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You reshape [target]'s circulatory system, adding a muscled membrane!", "[user] reshapes [target]'s circulatory system, adding a muscled membrane!", "[user] finishes manipulating [target]'s circulatory system.") diff --git a/code/modules/surgery/advanced/bioware/nerve_grounding.dm b/code/modules/surgery/advanced/bioware/nerve_grounding.dm index eb70a838a4099..32cf2588433da 100644 --- a/code/modules/surgery/advanced/bioware/nerve_grounding.dm +++ b/code/modules/surgery/advanced/bioware/nerve_grounding.dm @@ -16,12 +16,12 @@ accept_hand = TRUE time = 155 -/datum/surgery_step/ground_nerves/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/ground_nerves/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You start rerouting [target]'s nerves.", "[user] starts rerouting [target]'s nerves.", "[user] starts manipulating [target]'s nervous system.") -/datum/surgery_step/ground_nerves/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/ground_nerves/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You successfully reroute [target]'s nervous system!", "[user] successfully reroutes [target]'s nervous system!", "[user] finishes manipulating [target]'s nervous system.") diff --git a/code/modules/surgery/advanced/bioware/nerve_splicing.dm b/code/modules/surgery/advanced/bioware/nerve_splicing.dm index 50872fa6c2a18..b408ac678b1f7 100644 --- a/code/modules/surgery/advanced/bioware/nerve_splicing.dm +++ b/code/modules/surgery/advanced/bioware/nerve_splicing.dm @@ -16,12 +16,12 @@ accept_hand = TRUE time = 155 -/datum/surgery_step/splice_nerves/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/splice_nerves/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You start splicing together [target]'s nerves.", "[user] starts splicing together [target]'s nerves.", "[user] starts manipulating [target]'s nervous system.") -/datum/surgery_step/splice_nerves/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/splice_nerves/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You successfully splice [target]'s nervous system!", "[user] successfully splices [target]'s nervous system!", "[user] finishes manipulating [target]'s nervous system.") diff --git a/code/modules/surgery/advanced/bioware/vein_threading.dm b/code/modules/surgery/advanced/bioware/vein_threading.dm index 92df47ab353b9..b3e9e634f5a78 100644 --- a/code/modules/surgery/advanced/bioware/vein_threading.dm +++ b/code/modules/surgery/advanced/bioware/vein_threading.dm @@ -17,12 +17,12 @@ accept_hand = TRUE time = 125 -/datum/surgery_step/thread_veins/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/thread_veins/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You start weaving [target]'s circulatory system.", "[user] starts weaving [target]'s circulatory system.", "[user] starts manipulating [target]'s circulatory system.") -/datum/surgery_step/thread_veins/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/thread_veins/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You weave [target]'s circulatory system into a resistant mesh!", "[user] weaves [target]'s circulatory system into a resistant mesh!", "[user] finishes manipulating [target]'s circulatory system.") diff --git a/code/modules/surgery/advanced/brainwashing.dm b/code/modules/surgery/advanced/brainwashing.dm index a16e93a09898d..64d324068564b 100644 --- a/code/modules/surgery/advanced/brainwashing.dm +++ b/code/modules/surgery/advanced/brainwashing.dm @@ -18,7 +18,7 @@ possible_locs = list(BODY_ZONE_HEAD) abductor_surgery_blacklist = TRUE -/datum/surgery/advanced/brainwashing/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/advanced/brainwashing/can_start(mob/user, mob/living/carbon/target, target_zone) if(!..()) return FALSE var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN) @@ -35,7 +35,7 @@ failure_sound = 'sound/surgery/organ2.ogg' var/objective -/datum/surgery_step/brainwash/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/brainwash/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) objective = stripped_input(user, "Choose the objective to imprint on your victim's brain.", "Brainwashing", null, MAX_MESSAGE_LEN) if(!objective) return -1 @@ -43,7 +43,7 @@ "[user] begins to fix [target]'s brain.", "[user] begins to perform surgery on [target]'s brain.") -/datum/surgery_step/brainwash/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/brainwash/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(!target.mind) to_chat(user, "[target] doesn't respond to the brainwashing, as if [target.p_they()] lacked a mind...") return FALSE @@ -59,7 +59,7 @@ log_game("[key_name(user)] surgically brainwashed [key_name(target)] with the objective '[objective]'.") return TRUE -/datum/surgery_step/brainwash/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/brainwash/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(target.getorganslot(ORGAN_SLOT_BRAIN)) display_results(user, target, "You screw up, bruising the brain tissue!", "[user] screws up, causing brain damage!", diff --git a/code/modules/surgery/advanced/lobotomy.dm b/code/modules/surgery/advanced/lobotomy.dm index 796c7e2f26d6e..cb041d55f3413 100644 --- a/code/modules/surgery/advanced/lobotomy.dm +++ b/code/modules/surgery/advanced/lobotomy.dm @@ -13,7 +13,7 @@ possible_locs = list(BODY_ZONE_HEAD) requires_bodypart_type = 0 -/datum/surgery/advanced/lobotomy/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/advanced/lobotomy/can_start(mob/user, mob/living/carbon/target, target_zone) if(!..()) return FALSE var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN) @@ -35,12 +35,12 @@ return FALSE return TRUE -/datum/surgery_step/lobotomize/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/lobotomize/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to perform a lobotomy on [target]'s brain...", "[user] begins to perform a lobotomy on [target]'s brain.", "[user] begins to perform surgery on [target]'s brain.") -/datum/surgery_step/lobotomize/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/lobotomize/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You succeed in lobotomizing [target].", "[user] successfully lobotomizes [target]!", "[user] completes the surgery on [target]'s brain.") @@ -61,7 +61,7 @@ SWITCH_EMPTY_STATEMENT return TRUE -/datum/surgery_step/lobotomize/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/lobotomize/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN) if(B) display_results(user, target, "You remove the wrong part, causing more damage!", diff --git a/code/modules/surgery/advanced/necrotic_revival.dm b/code/modules/surgery/advanced/necrotic_revival.dm index 87e7e8f8ff0e1..7b930841f968f 100644 --- a/code/modules/surgery/advanced/necrotic_revival.dm +++ b/code/modules/surgery/advanced/necrotic_revival.dm @@ -11,7 +11,7 @@ possible_locs = list(BODY_ZONE_HEAD) abductor_surgery_blacklist = TRUE -/datum/surgery/advanced/necrotic_revival/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/advanced/necrotic_revival/can_start(mob/user, mob/living/carbon/target, target_zone) . = ..() var/obj/item/organ/zombie_infection/ZI = target.getorganslot(ORGAN_SLOT_ZOMBIE) if(ZI) @@ -24,12 +24,12 @@ chems_needed = list(/datum/reagent/toxin/zombiepowder, /datum/reagent/medicine/rezadone) require_all_chems = FALSE -/datum/surgery_step/bionecrosis/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/bionecrosis/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to grow a romerol tumor on [target]'s brain...", "[user] begins to tinker with [target]'s brain...", "[user] begins to perform surgery on [target]'s brain.") -/datum/surgery_step/bionecrosis/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/bionecrosis/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You succeed in growing a romerol tumor on [target]'s brain.", "[user] successfully grows a romerol tumor on [target]'s brain!", "[user] completes the surgery on [target]'s brain.") diff --git a/code/modules/surgery/advanced/pacification.dm b/code/modules/surgery/advanced/pacification.dm index a20a4889bfbe6..5a98e32083430 100644 --- a/code/modules/surgery/advanced/pacification.dm +++ b/code/modules/surgery/advanced/pacification.dm @@ -12,7 +12,7 @@ possible_locs = list(BODY_ZONE_HEAD) requires_bodypart_type = 0 -/datum/surgery/advanced/pacify/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/advanced/pacify/can_start(mob/user, mob/living/carbon/target, target_zone) . = ..() var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN) if(!B) @@ -26,19 +26,19 @@ success_sound = 'sound/surgery/hemostat1.ogg' failure_sound = 'sound/surgery/organ2.ogg' -/datum/surgery_step/pacify/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/pacify/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to pacify [target]...", "[user] begins to fix [target]'s brain.", "[user] begins to perform surgery on [target]'s brain.") -/datum/surgery_step/pacify/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/pacify/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You succeed in neurologically pacifying [target].", "[user] successfully fixes [target]'s brain!", "[user] completes the surgery on [target]'s brain.") target.gain_trauma(/datum/brain_trauma/severe/pacifism, TRAUMA_RESILIENCE_LOBOTOMY) return TRUE -/datum/surgery_step/pacify/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/pacify/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You screw up, rewiring [target]'s brain the wrong way around...", "[user] screws up, causing brain damage!", "[user] completes the surgery on [target]'s brain.") diff --git a/code/modules/surgery/advanced/revival.dm b/code/modules/surgery/advanced/revival.dm index f18ed376e04f6..b5ae8bce78b33 100644 --- a/code/modules/surgery/advanced/revival.dm +++ b/code/modules/surgery/advanced/revival.dm @@ -13,7 +13,7 @@ possible_locs = list(BODY_ZONE_HEAD) requires_bodypart_type = 0 -/datum/surgery/advanced/revival/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/advanced/revival/can_start(mob/user, mob/living/carbon/target, target_zone) if(!..()) return FALSE if(target.stat != DEAD) @@ -53,13 +53,13 @@ to_chat(user, "You need an electrode for this!") return FALSE -/datum/surgery_step/revive/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/revive/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You prepare to give [target]'s brain the spark of life with [tool].", "[user] prepares to shock [target]'s brain with [tool].", "[user] prepares to shock [target]'s brain with [tool].") target.notify_ghost_cloning("Someone is trying to zap your brain!", source = target) -/datum/surgery_step/revive/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/revive/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You successfully shock [target]'s brain with [tool]...", "[user] send a powerful shock to [target]'s brain with [tool]...", "[user] send a powerful shock to [target]'s brain with [tool]...") @@ -76,7 +76,7 @@ target.visible_message("...[target.p_they()] convulses, then lies still.") return FALSE -/datum/surgery_step/revive/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/revive/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You shock [target]'s brain with [tool], but [target.p_they()] doesn't react.", "[user] send a powerful shock to [target]'s brain with [tool], but [target.p_they()] doesn't react.", "[user] send a powerful shock to [target]'s brain with [tool], but [target.p_they()] doesn't react.") diff --git a/code/modules/surgery/advanced/viral_bonding.dm b/code/modules/surgery/advanced/viral_bonding.dm index 72055c08da280..53017cf892618 100644 --- a/code/modules/surgery/advanced/viral_bonding.dm +++ b/code/modules/surgery/advanced/viral_bonding.dm @@ -12,7 +12,7 @@ possible_locs = list(BODY_ZONE_CHEST) self_operable = TRUE -/datum/surgery/advanced/viral_bonding/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/advanced/viral_bonding/can_start(mob/user, mob/living/carbon/target, target_zone) if(!..()) return FALSE if(!LAZYLEN(target.diseases)) @@ -31,12 +31,12 @@ return TRUE -/datum/surgery_step/viral_bond/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/viral_bond/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You start heating [target]'s bone marrow with [tool]...", "[user] starts heating [target]'s bone marrow with [tool]...", "[user] starts heating something in [target]'s chest with [tool]...") -/datum/surgery_step/viral_bond/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/viral_bond/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "[target]'s bone marrow begins pulsing slowly. The viral bonding is complete.", "[target]'s bone marrow begins pulsing slowly.", "[user] finishes the operation.") diff --git a/code/modules/surgery/amputation.dm b/code/modules/surgery/amputation.dm index 98e66b71e3103..62ba5d084f0d5 100644 --- a/code/modules/surgery/amputation.dm +++ b/code/modules/surgery/amputation.dm @@ -15,16 +15,16 @@ preop_sound = 'sound/surgery/scalpel1.ogg' success_sound = 'sound/surgery/organ2.ogg' -/datum/surgery_step/sever_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to sever [target]'s [parse_zone(target_zone)]...", - "[user] begins to sever [target]'s [parse_zone(target_zone)]!", - "[user] begins to sever [target]'s [parse_zone(target_zone)]!") +/datum/surgery_step/sever_limb/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to sever [target]'s [parse_zone(surgery.location)]...", + "[user] begins to sever [target]'s [parse_zone(surgery.location)]!", + "[user] begins to sever [target]'s [parse_zone(surgery.location)]!") -/datum/surgery_step/sever_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/sever_limb/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) var/mob/living/carbon/human/L = target - display_results(user, target, "You sever [L]'s [parse_zone(target_zone)].", - "[user] severs [L]'s [parse_zone(target_zone)]!", - "[user] severs [L]'s [parse_zone(target_zone)]!") + display_results(user, target, "You sever [L]'s [parse_zone(surgery.location)].", + "[user] severs [L]'s [parse_zone(surgery.location)]!", + "[user] severs [L]'s [parse_zone(surgery.location)]!") if(surgery.operated_bodypart) var/obj/item/bodypart/target_limb = surgery.operated_bodypart target_limb.drop_limb() diff --git a/code/modules/surgery/blood_filter.dm b/code/modules/surgery/blood_filter.dm index d1d28b9b42bf2..0027a851bfc1a 100644 --- a/code/modules/surgery/blood_filter.dm +++ b/code/modules/surgery/blood_filter.dm @@ -24,7 +24,7 @@ filtering_step_type, /datum/surgery_step/close) -/datum/surgery/blood_filter/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/blood_filter/can_start(mob/user, mob/living/carbon/target, target_zone) if(HAS_TRAIT(target, TRAIT_HUSK)) //Can't filter husk return FALSE var/datum/surgery_step/filter_blood/filtering_step = filtering_step_type @@ -42,7 +42,7 @@ var/chem_purge_factor = 0.2 var/tox_heal_factor = 0 -/datum/surgery_step/filter_blood/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/filter_blood/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(istype(surgery,/datum/surgery/blood_filter)) var/datum/surgery/blood_filter/the_surgery = surgery if(!the_surgery.antispam) @@ -50,13 +50,13 @@ "[user] uses [tool] to filtering your blood.", "[user] uses [tool] on [target]'s chest.") -/datum/surgery_step/filter_blood/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) +/datum/surgery_step/filter_blood/initiate(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) if(..()) while(target.reagents.total_volume || (tox_heal_factor > 0 && target.getToxLoss() > 0)) if(!..()) break -/datum/surgery_step/filter_blood/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) +/datum/surgery_step/filter_blood/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) var/tox_loss = target.getToxLoss() if(target.reagents.total_volume || (tox_heal_factor > 0 && tox_loss > 0)) for(var/blood_chem in target.reagents.reagent_list) @@ -86,7 +86,7 @@ the_surgery.antispam = TRUE return TRUE -/datum/surgery_step/filter_blood/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/filter_blood/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You screw up, brusing [target]'s chest!", "[user] screws up, brusing [target]'s chest!", "[user] screws up!") diff --git a/code/modules/surgery/brain_recalibration.dm b/code/modules/surgery/brain_recalibration.dm index 41a47baea9dd2..46cb89dc73c0d 100644 --- a/code/modules/surgery/brain_recalibration.dm +++ b/code/modules/surgery/brain_recalibration.dm @@ -21,18 +21,18 @@ success_sound = 'sound/surgery/hemostat1.ogg' failure_sound = 'sound/surgery/organ2.ogg' -/datum/surgery/brain_recalibration/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/brain_recalibration/can_start(mob/user, mob/living/carbon/target, target_zone) var/obj/item/organ/brain/B = target.getorganslot(ORGAN_SLOT_BRAIN) if(!B) return FALSE return TRUE -/datum/surgery_step/fix_brain/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/fix_brain/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to fix [target]'s brain...", "[user] begins to fix [target]'s brain.", "[user] begins to perform surgery on [target]'s brain.") -/datum/surgery_step/fix_brain/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/fix_brain/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You succeed in fixing [target]'s brain.", "[user] successfully fixes [target]'s brain!", "[user] completes the surgery on [target]'s brain.") @@ -44,7 +44,7 @@ to_chat(user, "It looks like [target]'s brain could be fixed further.") return TRUE -/datum/surgery_step/fix_brain/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/fix_brain/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(target.getorganslot(ORGAN_SLOT_BRAIN)) display_results(user, target, "You screw up, causing more damage!", "[user] screws up, causing brain damage!", diff --git a/code/modules/surgery/cavity_implant.dm b/code/modules/surgery/cavity_implant.dm index 48eb59d579fdf..4a9350a9061d8 100644 --- a/code/modules/surgery/cavity_implant.dm +++ b/code/modules/surgery/cavity_implant.dm @@ -22,31 +22,31 @@ return FALSE return !tool.is_hot() -/datum/surgery_step/handle_cavity/preop(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/handle_cavity/preop(mob/user, mob/living/carbon/human/target, obj/item/tool, datum/surgery/surgery) var/obj/item/bodypart/chest/CH = target.get_bodypart(BODY_ZONE_CHEST) IC = CH.cavity_item if(tool) - display_results(user, target, "You begin to insert [tool] into [target]'s [target_zone]...", - "[user] begins to insert [tool] into [target]'s [target_zone].", - "[user] begins to insert [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [target]'s [target_zone].") + display_results(user, target, "You begin to insert [tool] into [target]'s [surgery.location]...", + "[user] begins to insert [tool] into [target]'s [surgery.location].", + "[user] begins to insert [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [target]'s [surgery.location].") //Incase they are interupted mid-insert, log it; shows intent to implant log_combat(user, target, "tried to cavity implant [tool.name] into") else - display_results(user, target, "You check for items in [target]'s [target_zone]...", - "[user] checks for items in [target]'s [target_zone].", - "[user] looks for something in [target]'s [target_zone].") + display_results(user, target, "You check for items in [target]'s [surgery.location]...", + "[user] checks for items in [target]'s [surgery.location].", + "[user] looks for something in [target]'s [surgery.location].") log_combat(user, target, "searched for cavity item [IC ? "([IC.name])" : null] in") -/datum/surgery_step/handle_cavity/success(mob/user, mob/living/carbon/human/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/handle_cavity/success(mob/user, mob/living/carbon/human/target, obj/item/tool, datum/surgery/surgery) var/obj/item/bodypart/chest/CH = target.get_bodypart(BODY_ZONE_CHEST) if(tool) if(IC || tool.w_class > WEIGHT_CLASS_NORMAL || HAS_TRAIT(tool, TRAIT_NODROP) || istype(tool, /obj/item/organ)) - to_chat(user, "You can't seem to fit [tool] in [target]'s [target_zone]!") + to_chat(user, "You can't seem to fit [tool] in [target]'s [surgery.location]!") return 0 else - display_results(user, target, "You stuff [tool] into [target]'s [target_zone].", - "[user] stuffs [tool] into [target]'s [target_zone]!", - "[user] stuffs [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [target]'s [target_zone].") + display_results(user, target, "You stuff [tool] into [target]'s [surgery.location].", + "[user] stuffs [tool] into [target]'s [surgery.location]!", + "[user] stuffs [tool.w_class > WEIGHT_CLASS_SMALL ? tool : "something"] into [target]'s [surgery.location].") user.transferItemToLoc(tool, target, TRUE) CH.cavity_item = tool //Logs stowing items in a cavity, similar to organ manipulation @@ -54,14 +54,14 @@ return 1 else if(IC) - display_results(user, target, "You pull [IC] out of [target]'s [target_zone].", - "[user] pulls [IC] out of [target]'s [target_zone]!", - "[user] pulls [IC.w_class > WEIGHT_CLASS_SMALL ? IC : "something"] out of [target]'s [target_zone].") + display_results(user, target, "You pull [IC] out of [target]'s [surgery.location].", + "[user] pulls [IC] out of [target]'s [surgery.location]!", + "[user] pulls [IC.w_class > WEIGHT_CLASS_SMALL ? IC : "something"] out of [target]'s [surgery.location].") user.put_in_hands(IC) CH.cavity_item = null //Log when cavity items are surgically removed, we don't care about it popping out from gibbing log_combat(user, target, "extracted [IC.name] from cavity in") return 1 else - to_chat(user, "You don't find anything in [target]'s [target_zone].") + to_chat(user, "You don't find anything in [target]'s [surgery.location].") return 0 diff --git a/code/modules/surgery/core_removal.dm b/code/modules/surgery/core_removal.dm index 5c9b8f334d28b..cb1484209b1d5 100644 --- a/code/modules/surgery/core_removal.dm +++ b/code/modules/surgery/core_removal.dm @@ -17,12 +17,12 @@ implements = list(TOOL_HEMOSTAT = 100, TOOL_CROWBAR = 100) time = 16 -/datum/surgery_step/extract_core/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/extract_core/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to extract a core from [target]...", "[user] begins to extract a core from [target].", "[user] begins to extract a core from [target].") -/datum/surgery_step/extract_core/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/extract_core/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) var/mob/living/simple_animal/slime/slime = target if(slime.cores > 0) slime.cores-- diff --git a/code/modules/surgery/coronary_bypass.dm b/code/modules/surgery/coronary_bypass.dm index eb74be456b856..2e49b36ade5c5 100644 --- a/code/modules/surgery/coronary_bypass.dm +++ b/code/modules/surgery/coronary_bypass.dm @@ -4,7 +4,7 @@ /datum/surgery_step/incise_heart, /datum/surgery_step/coronary_bypass, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_CHEST) -/datum/surgery/coronary_bypass/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/coronary_bypass/can_start(mob/user, mob/living/carbon/target, target_zone) var/obj/item/organ/heart/H = target.getorganslot(ORGAN_SLOT_HEART) if(H) if(H.damage > 60 && !H.operated) @@ -22,12 +22,12 @@ success_sound = 'sound/surgery/scalpel2.ogg' failure_sound = 'sound/surgery/organ2.ogg' -/datum/surgery_step/incise_heart/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/incise_heart/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to make an incision in [target]'s heart...", "[user] begins to make an incision in [target]'s heart.", "[user] begins to make an incision in [target]'s heart.") -/datum/surgery_step/incise_heart/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/incise_heart/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(ishuman(target)) var/mob/living/carbon/human/H = target if (!(NOBLOOD in H.dna.species.species_traits)) @@ -38,7 +38,7 @@ H.adjustBruteLoss(10) return TRUE -/datum/surgery_step/incise_heart/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/incise_heart/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(ishuman(target)) var/mob/living/carbon/human/H = target display_results(user, target, "You screw up, cutting too deeply into the heart!", @@ -54,12 +54,12 @@ implements = list(TOOL_HEMOSTAT = 90, TOOL_WIRECUTTER = 35, /obj/item/stack/package_wrap = 15, /obj/item/stack/cable_coil = 5) time = 90 -/datum/surgery_step/coronary_bypass/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/coronary_bypass/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to graft a bypass onto [target]'s heart...", "[user] begins to graft something onto [target]'s heart!", "[user] begins to graft something onto [target]'s heart!") -/datum/surgery_step/coronary_bypass/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/coronary_bypass/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) target.setOrganLoss(ORGAN_SLOT_HEART, 60) var/obj/item/organ/heart/heart = target.getorganslot(ORGAN_SLOT_HEART) if(heart) //slightly worrying if we lost our heart mid-operation, but that's life @@ -69,7 +69,7 @@ "[user] finishes grafting something onto [target]'s heart.") return TRUE -/datum/surgery_step/coronary_bypass/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/coronary_bypass/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(ishuman(target)) var/mob/living/carbon/human/H = target display_results(user, target, "You screw up in attaching the graft, and it tears off, tearing part of the heart!", diff --git a/code/modules/surgery/dental_implant.dm b/code/modules/surgery/dental_implant.dm index 7a0d828299b8a..7d6dfe54e1165 100644 --- a/code/modules/surgery/dental_implant.dm +++ b/code/modules/surgery/dental_implant.dm @@ -9,12 +9,12 @@ implements = list(/obj/item/reagent_containers/pill = 100) time = 16 -/datum/surgery_step/insert_pill/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to wedge [tool] in [target]'s [parse_zone(target_zone)]...", - "[user] begins to wedge \the [tool] in [target]'s [parse_zone(target_zone)].", - "[user] begins to wedge something in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/insert_pill/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to wedge [tool] in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to wedge \the [tool] in [target]'s [parse_zone(surgery.location)].", + "[user] begins to wedge something in [target]'s [parse_zone(surgery.location)].") -/datum/surgery_step/insert_pill/success(mob/user, mob/living/carbon/target, target_zone, var/obj/item/reagent_containers/pill/tool, datum/surgery/surgery) +/datum/surgery_step/insert_pill/success(mob/user, mob/living/carbon/target, obj/item/reagent_containers/pill/tool, datum/surgery/surgery) if(!istype(tool)) return 0 @@ -25,9 +25,9 @@ P.target = tool P.Grant(target) //The pill never actually goes in an inventory slot, so the owner doesn't inherit actions from it - display_results(user, target, "You wedge [tool] into [target]'s [parse_zone(target_zone)].", - "[user] wedges \the [tool] into [target]'s [parse_zone(target_zone)]!", - "[user] wedges something into [target]'s [parse_zone(target_zone)]!") + display_results(user, target, "You wedge [tool] into [target]'s [parse_zone(surgery.location)].", + "[user] wedges \the [tool] into [target]'s [parse_zone(surgery.location)]!", + "[user] wedges something into [target]'s [parse_zone(surgery.location)]!") return 1 /datum/action/item_action/hands_free/activate_pill diff --git a/code/modules/surgery/eye_surgery.dm b/code/modules/surgery/eye_surgery.dm index e0d739df76a5b..3a29baf23acb1 100644 --- a/code/modules/surgery/eye_surgery.dm +++ b/code/modules/surgery/eye_surgery.dm @@ -11,19 +11,19 @@ implements = list(TOOL_HEMOSTAT = 100, TOOL_SCREWDRIVER = 45, /obj/item/pen = 25) time = 64 -/datum/surgery/eye_surgery/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/eye_surgery/can_start(mob/user, mob/living/carbon/target, target_zone) var/obj/item/organ/eyes/E = target.getorganslot(ORGAN_SLOT_EYES) if(!E) to_chat(user, "It's hard to do surgery on someone's eyes when [target.p_they()] [target.p_do()]n't have any.") return FALSE return TRUE -/datum/surgery_step/fix_eyes/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/fix_eyes/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to fix [target]'s eyes...", "[user] begins to fix [target]'s eyes.", "[user] begins to perform surgery on [target]'s eyes.") -/datum/surgery_step/fix_eyes/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/fix_eyes/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) var/obj/item/organ/eyes/E = target.getorganslot(ORGAN_SLOT_EYES) user.visible_message("[user] successfully fixes [target]'s eyes!", "You succeed in fixing [target]'s eyes.") display_results(user, target, "You succeed in fixing [target]'s eyes.", @@ -36,7 +36,7 @@ E.setOrganDamage(0) return TRUE -/datum/surgery_step/fix_eyes/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/fix_eyes/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(target.getorgan(/obj/item/organ/brain)) display_results(user, target, "You accidentally stab [target] right in the brain!", "[user] accidentally stabs [target] right in the brain!", diff --git a/code/modules/surgery/gastrectomy.dm b/code/modules/surgery/gastrectomy.dm index cbc56604a0597..e766b30cd1e81 100644 --- a/code/modules/surgery/gastrectomy.dm +++ b/code/modules/surgery/gastrectomy.dm @@ -13,7 +13,7 @@ /datum/surgery_step/close ) -/datum/surgery/gastrectomy/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/gastrectomy/can_start(mob/user, mob/living/carbon/target, target_zone) var/obj/item/organ/stomach/L = target.getorganslot(ORGAN_SLOT_STOMACH) if(L?.damage > 50 && !(L.organ_flags & ORGAN_FAILING)) return TRUE @@ -26,12 +26,12 @@ /obj/item/shard = 35) time = 52 -/datum/surgery_step/gastrectomy/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/gastrectomy/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to cut out a damaged piece of [target]'s stomach...", "[user] begins to make an incision in [target].", "[user] begins to make an incision in [target].") -/datum/surgery_step/gastrectomy/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) +/datum/surgery_step/gastrectomy/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE) var/mob/living/carbon/human/H = target H.setOrganLoss(ORGAN_SLOT_STOMACH, 20) // Stomachs have a threshold for being able to even digest food, so I might tweak this number display_results(user, target, "You successfully remove the damaged part of [target]'s stomach.", @@ -39,7 +39,7 @@ "[user] successfully removes the damaged part of [target]'s stomach.") return ..() -/datum/surgery_step/gastrectomy/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery) +/datum/surgery_step/gastrectomy/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery) var/mob/living/carbon/human/H = target H.adjustOrganLoss(ORGAN_SLOT_STOMACH, 15) display_results(user, target, "You cut the wrong part of [target]'s stomach!", diff --git a/code/modules/surgery/healing.dm b/code/modules/surgery/healing.dm index 4dc1ea5b7c368..d6cfaf7b0cb47 100644 --- a/code/modules/surgery/healing.dm +++ b/code/modules/surgery/healing.dm @@ -33,7 +33,7 @@ /datum/surgery_step/heal/proc/get_progress(mob/user, mob/living/carbon/target, brute_healed, burn_healed) return -/datum/surgery_step/heal/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/heal/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) var/woundtype if(brutehealing && burnhealing) woundtype = "wounds" @@ -49,13 +49,13 @@ "[user] attempts to patch some of [target]'s [woundtype].") -/datum/surgery_step/heal/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) +/datum/surgery_step/heal/initiate(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) if(..()) while((brutehealing && target.getBruteLoss()) || (burnhealing && target.getFireLoss())) if(!..()) break -/datum/surgery_step/heal/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/heal/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) var/umsg = "You succeed in fixing some of [target]'s wounds" //no period, add initial space to "addons" var/tmsg = "[user] fixes some of [target]'s wounds" //see above var/urhealedamt_brute = brutehealing @@ -67,7 +67,7 @@ else //less healing bonus for the dead since they're expected to have lots of damage to begin with (to make TW into defib not TOO simple) urhealedamt_brute += round((target.getBruteLoss()/ (missinghpbonus*5)),0.1) urhealedamt_burn += round((target.getFireLoss()/ (missinghpbonus*5)),0.1) - if(!get_location_accessible(target, target_zone)) + if(!get_location_accessible(target, surgery.location)) urhealedamt_brute *= 0.55 urhealedamt_burn *= 0.55 umsg += " as best as you can while [target.p_they()] [target.p_have()] clothing on" @@ -83,7 +83,7 @@ the_surgery.antispam = TRUE return TRUE -/datum/surgery_step/heal/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/heal/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You screwed up!", "[user] screws up!", "[user] fixes some of [target]'s wounds.", TRUE) @@ -325,7 +325,7 @@ success_sound = 'sound/surgery/retractor2.ogg' failure_sound = 'sound/surgery/organ1.ogg' -/datum/surgery_step/heal/combo/upgraded/femto/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/heal/combo/upgraded/femto/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You screwed up!", "[user] screws up!", "[user] fixes some of [target]'s wounds.", TRUE) diff --git a/code/modules/surgery/helpers.dm b/code/modules/surgery/helpers.dm index a48037fea3164..2e79428cf6731 100644 --- a/code/modules/surgery/helpers.dm +++ b/code/modules/surgery/helpers.dm @@ -2,95 +2,93 @@ if(!istype(M)) return - var/mob/living/carbon/C - var/obj/item/bodypart/affecting - var/selected_zone = user.zone_selected - - if(iscarbon(M)) - C = M - affecting = C.get_bodypart(check_zone(selected_zone)) - var/datum/surgery/current_surgery for(var/datum/surgery/S in M.surgeries) - if(S.location == selected_zone) - current_surgery = S + current_surgery = S if(!current_surgery) - var/list/all_surgeries = GLOB.surgeries_list.Copy() - var/list/available_surgeries = list() + var/datum/task/zone_selector = user.select_bodyzone(M, TRUE) + zone_selector.continue_with(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(initiate_surgery_at_zone), I, M, user)) - for(var/datum/surgery/S in all_surgeries) - if(!S.possible_locs.Find(selected_zone)) - continue - if(affecting) - if(!S.requires_bodypart) - continue - if(S.requires_bodypart_type && !(affecting.bodytype & S.requires_bodypart_type)) - continue - if(S.requires_real_bodypart && affecting.is_pseudopart) - continue - else if(C && S.requires_bodypart) //mob with no limb in surgery zone when we need a limb + else if(!current_surgery.step_in_progress) + attempt_cancel_surgery(current_surgery, I, M, user) + + return 1 + +/proc/initiate_surgery_at_zone(obj/item/I, mob/living/M, mob/user, target_zone) + var/list/all_surgeries = GLOB.surgeries_list.Copy() + var/list/available_surgeries = list() + + var/mob/living/carbon/C + if (iscarbon(M)) + C = M + + var/obj/item/bodypart/affecting = M.get_bodypart(check_zone(target_zone)) + + for(var/datum/surgery/S in all_surgeries) + if(!S.possible_locs.Find(target_zone)) + continue + if(affecting) + if(!S.requires_bodypart) continue - if(S.lying_required && (M.mobility_flags & MOBILITY_STAND)) + if(S.requires_bodypart_type && !(affecting.bodytype & S.requires_bodypart_type)) continue - if(!S.can_start(user, M)) + if(S.requires_real_bodypart && affecting.is_pseudopart) continue - for(var/path in S.target_mobtypes) - if(istype(M, path)) - available_surgeries[S.name] = S - break + else if(C && S.requires_bodypart) //mob with no limb in surgery zone when we need a limb + continue + if(S.lying_required && (M.mobility_flags & MOBILITY_STAND)) + continue + if(!S.can_start(user, M, target_zone)) + continue + for(var/path in S.target_mobtypes) + if(istype(M, path)) + available_surgeries[S.name] = S + break + + if(!available_surgeries.len) + return - if(!available_surgeries.len) - return + var/P = input("Begin which procedure?", "Surgery", null, null) as null|anything in sort_list(available_surgeries) + if(P && user && user.Adjacent(M) && (I in user)) + var/datum/surgery/S = available_surgeries[P] - var/P = input("Begin which procedure?", "Surgery", null, null) as null|anything in sort_list(available_surgeries) - if(P && user && user.Adjacent(M) && (I in user)) - var/datum/surgery/S = available_surgeries[P] - - for(var/datum/surgery/other in M.surgeries) - if(other.location == S.location) - return //during the input() another surgery was started at the same location. - - //we check that the surgery is still doable after the input() wait. - if(C) - affecting = C.get_bodypart(check_zone(selected_zone)) - if(affecting) - if(!S.requires_bodypart) - return - if(S.requires_bodypart_type && !(affecting.bodytype & S.requires_bodypart_type)) - return - else if(C && S.requires_bodypart) - return - if(S.lying_required && (M.mobility_flags & MOBILITY_STAND)) + for(var/datum/surgery/other in M.surgeries) + if(other.location == S.location) + return //during the input() another surgery was started at the same location. + + //we check that the surgery is still doable after the input() wait. + if(C) + affecting = C.get_bodypart(check_zone(target_zone)) + if(affecting) + if(!S.requires_bodypart) return - if(!S.can_start(user, M)) + if(S.requires_bodypart_type && !(affecting.bodytype & S.requires_bodypart_type)) return + else if(C && S.requires_bodypart) + return + if(S.lying_required && (M.mobility_flags & MOBILITY_STAND)) + return + if(!S.can_start(user, M, target_zone)) + return - 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.", - "You drape [I] over [M]'s [parse_zone(selected_zone)] to prepare for \an [procedure.name].") - I.balloon_alert(user, "You drape over [parse_zone(selected_zone)].") - - log_combat(user, M, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [selected_zone])") - else - I.balloon_alert(user, "[parse_zone(selected_zone)] is covered up!") - - - else if(!current_surgery.step_in_progress) - attempt_cancel_surgery(current_surgery, I, M, user) + if(S.ignore_clothes || get_location_accessible(M, target_zone)) + var/datum/surgery/procedure = new S.type(M, target_zone, affecting) + user.visible_message("[user] drapes [I] over [M]'s [parse_zone(target_zone)] to prepare for surgery.", + "You drape [I] over [M]'s [parse_zone(target_zone)] to prepare for \an [procedure.name].") + I.balloon_alert(user, "You drape over [parse_zone(target_zone)].") - return 1 + log_combat(user, M, "operated on", null, "(OPERATION TYPE: [procedure.name]) (TARGET AREA: [target_zone])") + else + I.balloon_alert(user, "[parse_zone(target_zone)] is covered up!") /proc/attempt_cancel_surgery(datum/surgery/S, obj/item/I, mob/living/M, mob/user) - var/selected_zone = user.zone_selected - if(S.status == 1) M.surgeries -= S - user.visible_message("[user] removes [I] from [M]'s [parse_zone(selected_zone)].", \ - "You remove [I] from [M]'s [parse_zone(selected_zone)].") - I.balloon_alert(user, "You remove [I] from [parse_zone(selected_zone)].") + user.visible_message("[user] removes [I] from [M]'s [parse_zone(S.location)].", \ + "You remove [I] from [M]'s [parse_zone(S.location)].") + I.balloon_alert(user, "You remove [I] from [parse_zone(S.location)].") qdel(S) return @@ -111,8 +109,8 @@ to_chat(user, "You need to hold a [is_robotic ? "screwdriver" : "cautery"] in your inactive hand to stop [M]'s surgery!") return M.surgeries -= S - user.visible_message("[user] closes [M]'s [parse_zone(selected_zone)] with [close_tool] and removes [I].", \ - "You close [M]'s [parse_zone(selected_zone)] with [close_tool] and remove [I].") + user.visible_message("[user] closes [M]'s [parse_zone(S.location)] with [close_tool] and removes [I].", \ + "You close [M]'s [parse_zone(S.location)] with [close_tool] and remove [I].") qdel(S) /proc/get_location_accessible(mob/M, location) diff --git a/code/modules/surgery/hepatectomy.dm b/code/modules/surgery/hepatectomy.dm index a2f7165c8e239..87ab3c1444246 100644 --- a/code/modules/surgery/hepatectomy.dm +++ b/code/modules/surgery/hepatectomy.dm @@ -12,7 +12,7 @@ /datum/surgery_step/close ) -/datum/surgery/hepatectomy/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/hepatectomy/can_start(mob/user, mob/living/carbon/target, target_zone) var/obj/item/organ/liver/L = target.getorganslot(ORGAN_SLOT_LIVER) if(L?.damage > 50 && !(L.organ_flags & ORGAN_FAILING)) return TRUE @@ -25,12 +25,12 @@ /obj/item/shard = 35) time = 52 -/datum/surgery_step/hepatectomy/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/hepatectomy/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to cut out a damaged piece of [target]'s liver...", "[user] begins to make an incision in [target].", "[user] begins to make an incision in [target].") -/datum/surgery_step/hepatectomy/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/hepatectomy/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) var/mob/living/carbon/human/H = target H.setOrganLoss(ORGAN_SLOT_LIVER, 10) //not bad, not great display_results(user, target, "You successfully remove the damaged part of [target]'s liver.", @@ -38,7 +38,7 @@ "[user] successfullly removes the damaged part of [target]'s liver.") return TRUE -/datum/surgery_step/hepatectomy/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery) +/datum/surgery_step/hepatectomy/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery) var/mob/living/carbon/human/H = target H.adjustOrganLoss(ORGAN_SLOT_LIVER, 15) display_results(user, target, "You cut the wrong part of [target]'s liver!", diff --git a/code/modules/surgery/implant_removal.dm b/code/modules/surgery/implant_removal.dm index 4929098adc550..8d72ceac92a01 100644 --- a/code/modules/surgery/implant_removal.dm +++ b/code/modules/surgery/implant_removal.dm @@ -12,28 +12,28 @@ var/obj/item/implant/I = null success_sound = 'sound/surgery/hemostat1.ogg' -/datum/surgery_step/extract_implant/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/extract_implant/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) for(var/obj/item/O in target.implants) I = O break if(I) - display_results(user, target, "You begin to extract [I] from [target]'s [target_zone]...", - "[user] begins to extract [I] from [target]'s [target_zone].", - "[user] begins to extract something from [target]'s [target_zone].") + display_results(user, target, "You begin to extract [I] from [target]'s [surgery.location]...", + "[user] begins to extract [I] from [target]'s [surgery.location].", + "[user] begins to extract something from [target]'s [surgery.location].") //Incase they are interupted mid-extraction, log it log_combat(user, target, "tried to extract [I.name] from") else - display_results(user, target, "You look for an implant in [target]'s [target_zone]...", - "[user] looks for an implant in [target]'s [target_zone].", - "[user] looks for something in [target]'s [target_zone].") + display_results(user, target, "You look for an implant in [target]'s [surgery.location]...", + "[user] looks for an implant in [target]'s [surgery.location].", + "[user] looks for something in [target]'s [surgery.location].") //Doesn't matter if they finish or not, defaults to this if there are no implants log_combat(user, target, "implant checked") -/datum/surgery_step/extract_implant/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/extract_implant/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(I) - display_results(user, target, "You successfully remove [I] from [target]'s [target_zone].", - "[user] successfully removes [I] from [target]'s [target_zone]!", - "[user] successfully removes something from [target]'s [target_zone]!") + display_results(user, target, "You successfully remove [I] from [target]'s [surgery.location].", + "[user] successfully removes [I] from [target]'s [surgery.location]!", + "[user] successfully removes something from [target]'s [surgery.location]!") I.removed(target) //Logs removal of implants, similar to removal of organs during organ manipulation @@ -56,7 +56,7 @@ qdel(I) else - to_chat(user, "You can't find anything in [target]'s [target_zone]!") + to_chat(user, "You can't find anything in [target]'s [surgery.location]!") return 1 /datum/surgery/implant_removal/mechanic diff --git a/code/modules/surgery/limb_augmentation.dm b/code/modules/surgery/limb_augmentation.dm index d9f660278417b..c9c2d9d1111cd 100644 --- a/code/modules/surgery/limb_augmentation.dm +++ b/code/modules/surgery/limb_augmentation.dm @@ -11,15 +11,15 @@ var/obj/item/bodypart/L = null // L because "limb" -/datum/surgery_step/replace_limb/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/replace_limb/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(istype(tool, /obj/item/organ_storage) && istype(tool.contents[1], /obj/item/bodypart)) tool = tool.contents[1] var/obj/item/bodypart/aug = tool if(IS_ORGANIC_LIMB(aug)) to_chat(user, "That's not an augment, silly!") return -1 - if(aug.body_zone != target_zone) - to_chat(user, "[tool] isn't the right type for [parse_zone(target_zone)].") + if(aug.body_zone != surgery.location) + to_chat(user, "[tool] isn't the right type for [parse_zone(surgery.location)].") return -1 L = surgery.operated_bodypart if(L) @@ -27,11 +27,11 @@ to_chat(user, "You can't augment a limb with paralysis!") return -1 else - display_results(user, target, "You begin to augment [target]'s [parse_zone(user.zone_selected)]...", - "[user] begins to augment [target]'s [parse_zone(user.zone_selected)] with [aug].", - "[user] begins to augment [target]'s [parse_zone(user.zone_selected)].") + display_results(user, target, "You begin to augment [target]'s [parse_zone(surgery.location)]...", + "[user] begins to augment [target]'s [parse_zone(surgery.location)] with [aug].", + "[user] begins to augment [target]'s [parse_zone(surgery.location)].") else - user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...") + user.visible_message("[user] looks for [target]'s [parse_zone(surgery.location)].", "You look for [target]'s [parse_zone(surgery.location)]...") //ACTUAL SURGERIES @@ -45,12 +45,12 @@ -/datum/surgery/augmentation/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/augmentation/can_start(mob/user, mob/living/carbon/target, target_zone) return ..() && !isoozeling(target) //SURGERY STEP SUCCESSES -/datum/surgery_step/replace_limb/success(mob/user, mob/living/carbon/target, target_zone, obj/item/bodypart/tool, datum/surgery/surgery) +/datum/surgery_step/replace_limb/success(mob/user, mob/living/carbon/target, obj/item/bodypart/tool, datum/surgery/surgery) if(L) if(istype(tool, /obj/item/organ_storage)) tool.icon_state = initial(tool.icon_state) @@ -59,10 +59,10 @@ tool = tool.contents[1] if(istype(tool) && user.temporarilyRemoveItemFromInventory(tool)) tool.replace_limb(target, TRUE) - display_results(user, target, "You successfully augment [target]'s [parse_zone(target_zone)].", - "[user] successfully augments [target]'s [parse_zone(target_zone)] with [tool]!", - "[user] successfully augments [target]'s [parse_zone(target_zone)]!") - log_combat(user, target, "augmented", addition="by giving him new [parse_zone(target_zone)] INTENT: [uppertext(user.a_intent)]") + display_results(user, target, "You successfully augment [target]'s [parse_zone(surgery.location)].", + "[user] successfully augments [target]'s [parse_zone(surgery.location)] with [tool]!", + "[user] successfully augments [target]'s [parse_zone(surgery.location)]!") + log_combat(user, target, "augmented", addition="by giving him new [parse_zone(surgery.location)] INTENT: [uppertext(user.a_intent)]") else - to_chat(user, "[target] has no organic [parse_zone(target_zone)] there!") + to_chat(user, "[target] has no organic [parse_zone(surgery.location)] there!") return TRUE diff --git a/code/modules/surgery/lipoplasty.dm b/code/modules/surgery/lipoplasty.dm index 8c7812ba5cdb4..5b93a881b2db5 100644 --- a/code/modules/surgery/lipoplasty.dm +++ b/code/modules/surgery/lipoplasty.dm @@ -3,7 +3,7 @@ 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) -/datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/lipoplasty/can_start(mob/user, mob/living/carbon/target, target_zone) if(HAS_TRAIT(target, TRAIT_FAT)) return 1 return 0 @@ -15,16 +15,16 @@ implements = list(TOOL_SAW = 100, /obj/item/hatchet = 35, /obj/item/knife/butcher = 25) time = 64 -/datum/surgery_step/cut_fat/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/cut_fat/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) user.visible_message("[user] begins to cut away [target]'s excess fat.", "You begin to cut away [target]'s excess fat...") display_results(user, target, "You begin to cut away [target]'s excess fat...", "[user] begins to cut away [target]'s excess fat.", - "[user] begins to cut [target]'s [target_zone] with [tool].") + "[user] begins to cut [target]'s [surgery.location] with [tool].") -/datum/surgery_step/cut_fat/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/cut_fat/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You cut [target]'s excess fat loose.", "[user] cuts [target]'s excess fat loose!", - "[user] finishes the cut on [target]'s [target_zone].") + "[user] finishes the cut on [target]'s [surgery.location].") return 1 //remove fat @@ -33,12 +33,12 @@ implements = list(TOOL_RETRACTOR = 100, TOOL_SCREWDRIVER = 45, TOOL_WIRECUTTER = 35) time = 32 -/datum/surgery_step/remove_fat/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/remove_fat/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to extract [target]'s loose fat...", "[user] begins to extract [target]'s loose fat!", - "[user] begins to extract something from [target]'s [target_zone].") + "[user] begins to extract something from [target]'s [surgery.location].") -/datum/surgery_step/remove_fat/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/remove_fat/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You extract [target]'s fat.", "[user] extracts [target]'s fat!", "[user] extracts [target]'s fat!") diff --git a/code/modules/surgery/lobectomy.dm b/code/modules/surgery/lobectomy.dm index 0bb0ab39a8122..c10051f71842e 100644 --- a/code/modules/surgery/lobectomy.dm +++ b/code/modules/surgery/lobectomy.dm @@ -4,7 +4,7 @@ /datum/surgery_step/lobectomy, /datum/surgery_step/close) possible_locs = list(BODY_ZONE_CHEST) -/datum/surgery/lobectomy/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/lobectomy/can_start(mob/user, mob/living/carbon/target, target_zone) var/obj/item/organ/lungs/L = target.getorganslot(ORGAN_SLOT_LUNGS) if(L) if(L.damage > 60 && !L.operated) @@ -22,12 +22,12 @@ success_sound = 'sound/surgery/organ1.ogg' failure_sound = 'sound/surgery/organ2.ogg' -/datum/surgery_step/lobectomy/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/lobectomy/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to make an incision in [target]'s lungs...", "[user] begins to make an incision in [target].", "[user] begins to make an incision in [target].") -/datum/surgery_step/lobectomy/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/lobectomy/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(ishuman(target)) var/mob/living/carbon/human/H = target var/obj/item/organ/lungs/L = H.getorganslot(ORGAN_SLOT_LUNGS) @@ -38,7 +38,7 @@ "") return TRUE -/datum/surgery_step/lobectomy/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/lobectomy/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(ishuman(target)) var/mob/living/carbon/human/H = target display_results(user, target, "You screw up, failing to excise [H]'s damaged lobe!", diff --git a/code/modules/surgery/mechanic_steps.dm b/code/modules/surgery/mechanic_steps.dm index 930c109c4667a..4d180a7014100 100644 --- a/code/modules/surgery/mechanic_steps.dm +++ b/code/modules/surgery/mechanic_steps.dm @@ -10,10 +10,10 @@ preop_sound = 'sound/items/screwdriver.ogg' success_sound = 'sound/items/screwdriver2.ogg' -/datum/surgery_step/mechanic_open/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to unscrew the shell of [target]'s [parse_zone(target_zone)]...", - "[user] begins to unscrew the shell of [target]'s [parse_zone(target_zone)].", - "[user] begins to unscrew the shell of [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/mechanic_open/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to unscrew the shell of [target]'s [parse_zone(surgery.location)]...", + "[user] begins to unscrew the shell of [target]'s [parse_zone(surgery.location)].", + "[user] begins to unscrew the shell of [target]'s [parse_zone(surgery.location)].") /datum/surgery_step/mechanic_incise/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !tool.is_sharp()) @@ -35,10 +35,10 @@ preop_sound = 'sound/items/screwdriver.ogg' success_sound = 'sound/items/screwdriver2.ogg' -/datum/surgery_step/mechanic_close/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to screw the shell of [target]'s [parse_zone(target_zone)]...", - "[user] begins to screw the shell of [target]'s [parse_zone(target_zone)].", - "[user] begins to screw the shell of [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/mechanic_close/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to screw the shell of [target]'s [parse_zone(surgery.location)]...", + "[user] begins to screw the shell of [target]'s [parse_zone(surgery.location)].", + "[user] begins to screw the shell of [target]'s [parse_zone(surgery.location)].") /datum/surgery_step/mechanic_close/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !tool.is_sharp()) @@ -58,10 +58,10 @@ preop_sound = 'sound/surgery/tape_flip.ogg' success_sound = 'sound/surgery/taperecorder_close.ogg' -/datum/surgery_step/prepare_electronics/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to prepare electronics in [target]'s [parse_zone(target_zone)]...", - "[user] begins to prepare electronics in [target]'s [parse_zone(target_zone)].", - "[user] begins to prepare electronics in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/prepare_electronics/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to prepare electronics in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to prepare electronics in [target]'s [parse_zone(surgery.location)].", + "[user] begins to prepare electronics in [target]'s [parse_zone(surgery.location)].") //unwrench /datum/surgery_step/mechanic_unwrench @@ -72,10 +72,10 @@ time = 24 preop_sound = 'sound/items/ratchet.ogg' -/datum/surgery_step/mechanic_unwrench/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to unwrench some bolts in [target]'s [parse_zone(target_zone)]...", - "[user] begins to unwrench some bolts in [target]'s [parse_zone(target_zone)].", - "[user] begins to unwrench some bolts in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/mechanic_unwrench/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to unwrench some bolts in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to unwrench some bolts in [target]'s [parse_zone(surgery.location)].", + "[user] begins to unwrench some bolts in [target]'s [parse_zone(surgery.location)].") //wrench /datum/surgery_step/mechanic_wrench @@ -86,10 +86,10 @@ time = 24 preop_sound = 'sound/items/ratchet.ogg' -/datum/surgery_step/mechanic_wrench/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to wrench some bolts in [target]'s [parse_zone(target_zone)]...", - "[user] begins to wrench some bolts in [target]'s [parse_zone(target_zone)].", - "[user] begins to wrench some bolts in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/mechanic_wrench/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to wrench some bolts in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to wrench some bolts in [target]'s [parse_zone(surgery.location)].", + "[user] begins to wrench some bolts in [target]'s [parse_zone(surgery.location)].") //open hatch /datum/surgery_step/open_hatch @@ -99,7 +99,7 @@ preop_sound = 'sound/items/ratchet.ogg' preop_sound = 'sound/machines/doorclick.ogg' -/datum/surgery_step/open_hatch/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to open the hatch holders in [target]'s [parse_zone(target_zone)]...", - "[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].", - "[user] begins to open the hatch holders in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/open_hatch/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to open the hatch holders in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to open the hatch holders in [target]'s [parse_zone(surgery.location)].", + "[user] begins to open the hatch holders in [target]'s [parse_zone(surgery.location)].") diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm index 704d94a0ab68b..f4ecca1455928 100644 --- a/code/modules/surgery/organ_manipulation.dm +++ b/code/modules/surgery/organ_manipulation.dm @@ -81,7 +81,7 @@ ..() implements = implements + implements_extract -/datum/surgery_step/manipulate_organs/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/manipulate_organs/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) I = null if(istype(tool, /obj/item/organ_storage)) if(!tool.contents.len) @@ -89,14 +89,14 @@ return -1 I = tool.contents[1] if(!isorgan(I)) - to_chat(user, "You cannot put [I] into [target]'s [parse_zone(target_zone)]!") + to_chat(user, "You cannot put [I] into [target]'s [parse_zone(surgery.location)]!") return -1 tool = I if(isorgan(tool)) current_type = "insert" I = tool - if(target_zone != I.zone || target.getorganslot(I.slot)) - to_chat(user, "There is no room for [I] in [target]'s [parse_zone(target_zone)]!") + if(surgery.location != I.zone || target.getorganslot(I.slot)) + to_chat(user, "There is no room for [I] in [target]'s [parse_zone(surgery.location)]!") return -1 if(istype(I, /obj/item/organ/brain/positron)) var/obj/item/bodypart/affected = target.get_bodypart(check_zone(I.zone)) @@ -112,16 +112,16 @@ if(!meatslab.useable) to_chat(user, "[I] seems to have been chewed on, you can't use this!") return -1 - display_results(user, target, "You begin to insert [tool] into [target]'s [parse_zone(target_zone)]...", - "[user] begins to insert [tool] into [target]'s [parse_zone(target_zone)].", - "[user] begins to insert something into [target]'s [parse_zone(target_zone)].") + display_results(user, target, "You begin to insert [tool] into [target]'s [parse_zone(surgery.location)]...", + "[user] begins to insert [tool] into [target]'s [parse_zone(surgery.location)].", + "[user] begins to insert something into [target]'s [parse_zone(surgery.location)].") log_combat(user, target, "tried to insert [I.name] into") else if(implement_type in implements_extract) current_type = "extract" - var/list/organs = target.getorganszone(target_zone) + var/list/organs = target.getorganszone(surgery.location) if(!organs.len) - to_chat(user, "There are no removable organs in [target]'s [parse_zone(target_zone)]!") + to_chat(user, "There are no removable organs in [target]'s [parse_zone(surgery.location)]!") return -1 else for(var/obj/item/organ/O in organs) @@ -134,14 +134,14 @@ I = organs[I] if(!I) return -1 - display_results(user, target, "You begin to extract [I] from [target]'s [parse_zone(target_zone)]...", - "[user] begins to extract [I] from [target]'s [parse_zone(target_zone)].", - "[user] begins to extract something from [target]'s [parse_zone(target_zone)].") + display_results(user, target, "You begin to extract [I] from [target]'s [parse_zone(surgery.location)]...", + "[user] begins to extract [I] from [target]'s [parse_zone(surgery.location)].", + "[user] begins to extract something from [target]'s [parse_zone(surgery.location)].") log_combat(user, target, "tried to extract [I.name] from") else return -1 -/datum/surgery_step/manipulate_organs/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/manipulate_organs/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(current_type == "insert") if(istype(tool, /obj/item/organ_storage)) I = tool.contents[1] @@ -153,21 +153,21 @@ I = tool user.temporarilyRemoveItemFromInventory(I, TRUE) I.Insert(target) - display_results(user, target, "You insert [tool] into [target]'s [parse_zone(target_zone)].", - "[user] inserts [tool] into [target]'s [parse_zone(target_zone)]!", - "[user] inserts something into [target]'s [parse_zone(target_zone)]!") + display_results(user, target, "You insert [tool] into [target]'s [parse_zone(surgery.location)].", + "[user] inserts [tool] into [target]'s [parse_zone(surgery.location)]!", + "[user] inserts something into [target]'s [parse_zone(surgery.location)]!") log_combat(user, target, "surgically installed [I.name] into") else if(current_type == "extract") if(I && I.owner == target) - display_results(user, target, "You successfully extract [I] from [target]'s [parse_zone(target_zone)].", - "[user] successfully extracts [I] from [target]'s [parse_zone(target_zone)]!", - "[user] successfully extracts something from [target]'s [parse_zone(target_zone)]!") + display_results(user, target, "You successfully extract [I] from [target]'s [parse_zone(surgery.location)].", + "[user] successfully extracts [I] from [target]'s [parse_zone(surgery.location)]!", + "[user] successfully extracts something from [target]'s [parse_zone(surgery.location)]!") log_combat(user, target, "surgically removed [I.name] from") I.Remove(target) I.forceMove(get_turf(target)) else - display_results(user, target, "You can't extract anything from [target]'s [parse_zone(target_zone)]!", - "[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!", - "[user] can't seem to extract anything from [target]'s [parse_zone(target_zone)]!") + display_results(user, target, "You can't extract anything from [target]'s [parse_zone(surgery.location)]!", + "[user] can't seem to extract anything from [target]'s [parse_zone(surgery.location)]!", + "[user] can't seem to extract anything from [target]'s [parse_zone(surgery.location)]!") return 0 diff --git a/code/modules/surgery/organic_steps.dm b/code/modules/surgery/organic_steps.dm index 4c56c9709197e..9243218101665 100644 --- a/code/modules/surgery/organic_steps.dm +++ b/code/modules/surgery/organic_steps.dm @@ -8,10 +8,10 @@ preop_sound = 'sound/surgery/scalpel1.ogg' success_sound = 'sound/surgery/scalpel2.ogg' -/datum/surgery_step/incise/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to make an incision in [target]'s [parse_zone(target_zone)]...", - "[user] begins to make an incision in [target]'s [parse_zone(target_zone)].", - "[user] begins to make an incision in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/incise/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to make an incision in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to make an incision in [target]'s [parse_zone(surgery.location)].", + "[user] begins to make an incision in [target]'s [parse_zone(surgery.location)].") /datum/surgery_step/incise/tool_check(mob/user, obj/item/tool) if(implement_type == /obj/item && !tool.is_sharp()) @@ -19,24 +19,24 @@ return TRUE -/datum/surgery_step/incise/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/incise/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if ishuman(target) var/mob/living/carbon/human/H = target if (!(NOBLOOD in H.dna.species.species_traits)) - display_results(user, target, "Blood pools around the incision in [H]'s [parse_zone(target_zone)].", - "Blood pools around the incision in [H]'s [parse_zone(target_zone)].", + display_results(user, target, "Blood pools around the incision in [H]'s [parse_zone(surgery.location)].", + "Blood pools around the incision in [H]'s [parse_zone(surgery.location)].", "") H.bleed_rate += 3 return TRUE /datum/surgery_step/incise/nobleed //silly friendly! -/datum/surgery_step/incise/nobleed/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to carefully make an incision in [target]'s [parse_zone(target_zone)]...", - "[user] begins to carefully make an incision in [target]'s [parse_zone(target_zone)].", - "[user] begins to carefully make an incision in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/incise/nobleed/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to carefully make an incision in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to carefully make an incision in [target]'s [parse_zone(surgery.location)].", + "[user] begins to carefully make an incision in [target]'s [parse_zone(surgery.location)].") -/datum/surgery_step/incise/nobleed/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/incise/nobleed/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) return TRUE //clamp bleeders @@ -46,12 +46,12 @@ time = 24 preop_sound = 'sound/surgery/hemostat1.ogg' -/datum/surgery_step/clamp_bleeders/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to clamp bleeders in [target]'s [parse_zone(target_zone)]...", - "[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)].", - "[user] begins to clamp bleeders in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/clamp_bleeders/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to clamp bleeders in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to clamp bleeders in [target]'s [parse_zone(surgery.location)].", + "[user] begins to clamp bleeders in [target]'s [parse_zone(surgery.location)].") -/datum/surgery_step/clamp_bleeders/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/clamp_bleeders/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(locate(/datum/surgery_step/saw) in surgery.steps) target.heal_bodypart_damage(20,0) return ..() @@ -65,10 +65,10 @@ preop_sound = 'sound/surgery/retractor1.ogg' success_sound = 'sound/surgery/retractor2.ogg' -/datum/surgery_step/retract_skin/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to retract the skin in [target]'s [parse_zone(target_zone)]...", - "[user] begins to retract the skin in [target]'s [parse_zone(target_zone)].", - "[user] begins to retract the skin in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/retract_skin/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to retract the skin in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to retract the skin in [target]'s [parse_zone(surgery.location)].", + "[user] begins to retract the skin in [target]'s [parse_zone(surgery.location)].") @@ -81,10 +81,10 @@ preop_sound = 'sound/surgery/cautery1.ogg' success_sound = 'sound/surgery/cautery2.ogg' -/datum/surgery_step/close/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to mend the incision in [target]'s [parse_zone(target_zone)]...", - "[user] begins to mend the incision in [target]'s [parse_zone(target_zone)].", - "[user] begins to mend the incision in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/close/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to mend the incision in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to mend the incision in [target]'s [parse_zone(surgery.location)].", + "[user] begins to mend the incision in [target]'s [parse_zone(surgery.location)].") /datum/surgery_step/close/tool_check(mob/user, obj/item/tool) if(implement_type == TOOL_WELDER || implement_type == /obj/item) @@ -92,7 +92,7 @@ return TRUE -/datum/surgery_step/close/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/close/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(locate(/datum/surgery_step/saw) in surgery.steps) target.heal_bodypart_damage(45,0) return ..() @@ -115,16 +115,16 @@ ) success_sound = 'sound/surgery/organ2.ogg' -/datum/surgery_step/saw/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to saw through the bone in [target]'s [parse_zone(target_zone)]...", - "[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].", - "[user] begins to saw through the bone in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/saw/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to saw through the bone in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to saw through the bone in [target]'s [parse_zone(surgery.location)].", + "[user] begins to saw through the bone in [target]'s [parse_zone(surgery.location)].") -/datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - target.apply_damage(50, BRUTE, "[target_zone]") - display_results(user, target, "You saw [target]'s [parse_zone(target_zone)] open.", - "[user] saws [target]'s [parse_zone(target_zone)] open!", - "[user] saws [target]'s [parse_zone(target_zone)] open!") +/datum/surgery_step/saw/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + target.apply_damage(50, BRUTE, "[surgery.location]") + display_results(user, target, "You saw [target]'s [parse_zone(surgery.location)] open.", + "[user] saws [target]'s [parse_zone(surgery.location)] open!", + "[user] saws [target]'s [parse_zone(surgery.location)] open!") return 1 //drill bone @@ -140,13 +140,13 @@ return FALSE return TRUE -/datum/surgery_step/drill/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You begin to drill into the bone in [target]'s [parse_zone(target_zone)]...", - "[user] begins to drill into the bone in [target]'s [parse_zone(target_zone)].", - "[user] begins to drill into the bone in [target]'s [parse_zone(target_zone)].") +/datum/surgery_step/drill/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You begin to drill into the bone in [target]'s [parse_zone(surgery.location)]...", + "[user] begins to drill into the bone in [target]'s [parse_zone(surgery.location)].", + "[user] begins to drill into the bone in [target]'s [parse_zone(surgery.location)].") -/datum/surgery_step/drill/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) - display_results(user, target, "You drill into [target]'s [parse_zone(target_zone)].", - "[user] drills into [target]'s [parse_zone(target_zone)]!", - "[user] drills into [target]'s [parse_zone(target_zone)]!") +/datum/surgery_step/drill/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) + display_results(user, target, "You drill into [target]'s [parse_zone(surgery.location)].", + "[user] drills into [target]'s [parse_zone(surgery.location)]!", + "[user] drills into [target]'s [parse_zone(surgery.location)]!") return 1 diff --git a/code/modules/surgery/organs/organ_internal.dm b/code/modules/surgery/organs/organ_internal.dm index 6d004190bca6d..e2ec41f9e6209 100644 --- a/code/modules/surgery/organs/organ_internal.dm +++ b/code/modules/surgery/organs/organ_internal.dm @@ -156,8 +156,7 @@ INITIALIZE_IMMEDIATE(/obj/item/organ) /obj/item/organ/proc/check_for_surgery(mob/living/carbon/human/H) for(var/datum/surgery/S in H.surgeries) - if(S.location == H.zone_selected) - return TRUE //no snacks mid surgery + return TRUE //no snacks mid surgery return FALSE /obj/item/organ/item_action_slot_check(slot,mob/user) diff --git a/code/modules/surgery/plastic_surgery.dm b/code/modules/surgery/plastic_surgery.dm index 48f3d69a72f05..0544d89250191 100644 --- a/code/modules/surgery/plastic_surgery.dm +++ b/code/modules/surgery/plastic_surgery.dm @@ -9,13 +9,13 @@ implements = list(TOOL_SCALPEL = 100, /obj/item/knife = 50, TOOL_WIRECUTTER = 35) time = 64 -/datum/surgery_step/reshape_face/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/reshape_face/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) user.visible_message("[user] begins to alter [target]'s appearance.", "You begin to alter [target]'s appearance...") display_results(user, target, "You begin to alter [target]'s appearance...", "[user] begins to alter [target]'s appearance.", "[user] begins to make an incision in [target]'s face.") -/datum/surgery_step/reshape_face/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/reshape_face/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(HAS_TRAIT_FROM(target, TRAIT_DISFIGURED, TRAIT_GENERIC)) REMOVE_TRAIT(target, TRAIT_DISFIGURED, TRAIT_GENERIC) display_results(user, target, "You successfully restore [target]'s appearance.", @@ -44,7 +44,7 @@ H.sec_hud_set_ID() return TRUE -/datum/surgery_step/reshape_face/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/reshape_face/failure(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You screw up, leaving [target]'s appearance disfigured!", "[user] screws up, disfiguring [target]'s appearance!", "[user] finishes the operation on [target]'s face.") diff --git a/code/modules/surgery/prosthetic_replacement.dm b/code/modules/surgery/prosthetic_replacement.dm index 9c95ee4963e6b..f74a63eaeec9e 100644 --- a/code/modules/surgery/prosthetic_replacement.dm +++ b/code/modules/surgery/prosthetic_replacement.dm @@ -7,12 +7,12 @@ requires_bodypart_type = 0 self_operable = TRUE -/datum/surgery/prosthetic_replacement/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/prosthetic_replacement/can_start(mob/user, mob/living/carbon/target, target_zone) if(!iscarbon(target)) return 0 var/mob/living/carbon/C = target if(!isoozeling(target)) - if(!C.get_bodypart(user.zone_selected)) //can only start if limb is missing + if(!C.get_bodypart(target_zone)) //can only start if limb is missing return 1 @@ -22,7 +22,7 @@ time = 32 var/organ_rejection_dam = 0 -/datum/surgery_step/add_prosthetic/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/add_prosthetic/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(istype(tool, /obj/item/organ_storage)) if(!tool.contents.len) to_chat(user, "There is nothing inside [tool]!") @@ -48,22 +48,22 @@ if(H.dna.species.id != BP.limb_id) organ_rejection_dam = 30 - if(target_zone == BP.body_zone) //so we can't replace a leg with an arm, or a human arm with a monkey arm. - display_results(user, target, "You begin to replace [target]'s [parse_zone(target_zone)] with [tool]...", - "[user] begins to replace [target]'s [parse_zone(target_zone)] with [tool].", - "[user] begins to replace [target]'s [parse_zone(target_zone)].") + if(surgery.location == BP.body_zone) //so we can't replace a leg with an arm, or a human arm with a monkey arm. + display_results(user, target, "You begin to replace [target]'s [parse_zone(surgery.location)] with [tool]...", + "[user] begins to replace [target]'s [parse_zone(surgery.location)] with [tool].", + "[user] begins to replace [target]'s [parse_zone(surgery.location)].") else - to_chat(user, "[tool] isn't the right type for [parse_zone(target_zone)].") + to_chat(user, "[tool] isn't the right type for [parse_zone(surgery.location)].") return -1 - else if(target_zone == BODY_ZONE_L_ARM || target_zone == BODY_ZONE_R_ARM) + else if(surgery.location == BODY_ZONE_L_ARM || surgery.location == BODY_ZONE_R_ARM) display_results(user, target, "You begin to attach [tool] onto [target]...", - "[user] begins to attach [tool] onto [target]'s [parse_zone(target_zone)].", - "[user] begins to attach something onto [target]'s [parse_zone(target_zone)].") + "[user] begins to attach [tool] onto [target]'s [parse_zone(surgery.location)].", + "[user] begins to attach something onto [target]'s [parse_zone(surgery.location)].") else to_chat(user, "[tool] must be installed onto an arm.") return -1 -/datum/surgery_step/add_prosthetic/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/add_prosthetic/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(istype(tool, /obj/item/organ_storage)) tool.icon_state = initial(tool.icon_state) tool.desc = initial(tool.desc) @@ -74,12 +74,12 @@ L.attach_limb(target) if(organ_rejection_dam) target.adjustToxLoss(organ_rejection_dam) - display_results(user, target, "You succeed in replacing [target]'s [parse_zone(target_zone)].", - "[user] successfully replaces [target]'s [parse_zone(target_zone)] with [tool]!", - "[user] successfully replaces [target]'s [parse_zone(target_zone)]!") + display_results(user, target, "You succeed in replacing [target]'s [parse_zone(surgery.location)].", + "[user] successfully replaces [target]'s [parse_zone(surgery.location)] with [tool]!", + "[user] successfully replaces [target]'s [parse_zone(surgery.location)]!") return 1 else - var/obj/item/bodypart/L = target.newBodyPart(target_zone, FALSE, FALSE) + var/obj/item/bodypart/L = target.newBodyPart(surgery.location, FALSE, FALSE) L.is_pseudopart = TRUE L.attach_limb(target) user.visible_message("[user] finishes attaching [tool]!", "You attach [tool].") @@ -89,17 +89,17 @@ qdel(tool) if(istype(tool, /obj/item/chainsaw/energy/doom)) var/obj/item/mounted_chainsaw/super/new_arm = new(target) - target_zone == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm) + surgery.location == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm) return 1 else if(istype(tool, /obj/item/chainsaw/energy)) var/obj/item/mounted_chainsaw/energy/new_arm = new(target) - target_zone == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm) + surgery.location == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm) return 1 else if(istype(tool, /obj/item/chainsaw)) var/obj/item/mounted_chainsaw/normal/new_arm = new(target) - target_zone == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm) + surgery.location == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm) return 1 else if(istype(tool, /obj/item/melee/synthetic_arm_blade)) var/obj/item/melee/arm_blade/new_arm = new(target,TRUE,TRUE) - target_zone == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm) + surgery.location == BODY_ZONE_R_ARM ? target.put_in_r_hand(new_arm) : target.put_in_l_hand(new_arm) return 1 diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm index 29c3ef30d208a..858946b3e9d92 100644 --- a/code/modules/surgery/remove_embedded_object.dm +++ b/code/modules/surgery/remove_embedded_object.dm @@ -12,18 +12,18 @@ 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) +/datum/surgery_step/remove_object/preop(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) L = surgery.operated_bodypart if(L) - user.visible_message("[user] looks for objects embedded in [target]'s [parse_zone(user.zone_selected)].", "You look for objects embedded in [target]'s [parse_zone(user.zone_selected)]...") - display_results(user, target, "You look for objects embedded in [target]'s [parse_zone(user.zone_selected)]...", - "[user] looks for objects embedded in [target]'s [parse_zone(user.zone_selected)].", - "[user] looks for something in [target]'s [parse_zone(user.zone_selected)].") + user.visible_message("[user] looks for objects embedded in [target]'s [parse_zone(surgery.location)].", "You look for objects embedded in [target]'s [parse_zone(surgery.location)]...") + display_results(user, target, "You look for objects embedded in [target]'s [parse_zone(surgery.location)]...", + "[user] looks for objects embedded in [target]'s [parse_zone(surgery.location)].", + "[user] looks for something in [target]'s [parse_zone(surgery.location)].") else - user.visible_message("[user] looks for [target]'s [parse_zone(user.zone_selected)].", "You look for [target]'s [parse_zone(user.zone_selected)]...") + user.visible_message("[user] looks for [target]'s [parse_zone(surgery.location)].", "You look for [target]'s [parse_zone(surgery.location)]...") -/datum/surgery_step/remove_object/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/remove_object/success(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(L) if(ishuman(target)) var/mob/living/carbon/human/H = target @@ -40,6 +40,6 @@ to_chat(user, "You find no objects embedded in [H]'s [L]!") else - to_chat(user, "You can't find [target]'s [parse_zone(user.zone_selected)], let alone any objects embedded in it!") + to_chat(user, "You can't find [target]'s [parse_zone(surgery.location)], let alone any objects embedded in it!") return 1 diff --git a/code/modules/surgery/surgery.dm b/code/modules/surgery/surgery.dm index d829cc8afff28..51256efd318fe 100644 --- a/code/modules/surgery/surgery.dm +++ b/code/modules/surgery/surgery.dm @@ -43,7 +43,7 @@ return ..() -/datum/surgery/proc/can_start(mob/user, mob/living/carbon/target) //FALSE to not show in list +/datum/surgery/proc/can_start(mob/user, mob/living/carbon/target, target_zone) //FALSE to not show in list . = TRUE if(replaced_by == /datum/surgery) return FALSE @@ -119,7 +119,7 @@ var/datum/surgery_step/S = get_surgery_step() if(S) - if(S.try_op(user, target, user.zone_selected, user.get_active_held_item(), src, try_to_fail)) + if(S.try_op(user, target, user.get_active_held_item(), src, try_to_fail)) return TRUE if(iscyborg(user) && user.a_intent != INTENT_HARM) //to save asimov borgs a LOT of heartache return TRUE @@ -145,7 +145,7 @@ name = "advanced surgery" requires_tech = TRUE -/datum/surgery/advanced/can_start(mob/user, mob/living/carbon/target) +/datum/surgery/advanced/can_start(mob/user, mob/living/carbon/target, target_zone) if(!..()) return FALSE // True surgeons (like abductor scientists) need no instructions diff --git a/code/modules/surgery/surgery_step.dm b/code/modules/surgery/surgery_step.dm index 3f471cbc32ee5..bd23bf935b0db 100644 --- a/code/modules/surgery/surgery_step.dm +++ b/code/modules/surgery/surgery_step.dm @@ -12,7 +12,7 @@ var/success_sound //Sound played if the step succeeded var/failure_sound //Sound played if the step fails -/datum/surgery_step/proc/try_op(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) +/datum/surgery_step/proc/try_op(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) var/success = FALSE if(accept_hand) if(!tool) @@ -40,18 +40,17 @@ break if(success) - if(target_zone == surgery.location) - if(get_location_accessible(target, target_zone) || surgery.ignore_clothes) - return initiate(user, target, target_zone, tool, surgery, try_to_fail) - else - to_chat(user, "You need to expose [target]'s [parse_zone(target_zone)] to perform surgery on it!") - return TRUE //returns TRUE so we don't stab the guy in the dick or wherever. + if(get_location_accessible(target, surgery.location) || surgery.ignore_clothes) + return initiate(user, target, tool, surgery, try_to_fail) + else + to_chat(user, "You need to expose [target]'s [parse_zone(surgery.location)] to perform surgery on it!") + return TRUE //returns TRUE so we don't stab the guy in the dick or wherever. if(repeatable) var/datum/surgery_step/next_step = surgery.get_surgery_next_step() if(next_step) surgery.status++ - if(next_step.try_op(user, target, user.zone_selected, user.get_active_held_item(), surgery)) + if(next_step.try_op(user, target, user.get_active_held_item(), surgery)) return TRUE else surgery.status-- @@ -83,17 +82,17 @@ return max(propability + sleepbonus - selfpenalty, 0.1) -/datum/surgery_step/proc/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) +/datum/surgery_step/proc/initiate(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE) surgery.step_in_progress = TRUE var/speed_mod = 1 var/fail_prob = 0//100 - fail_prob = success_prob var/advance = FALSE - if(preop(user, target, target_zone, tool, surgery) == -1) + if(preop(user, target, tool, surgery) == -1) surgery.step_in_progress = FALSE return FALSE - play_preop_sound(user, target, target_zone, tool, surgery) // Here because most steps overwrite preop + play_preop_sound(user, target, tool, surgery) // Here because most steps overwrite preop if(tool) speed_mod = tool.toolspeed @@ -114,10 +113,11 @@ if((prob(100 - fail_prob) || iscyborg(user)) && chem_check(target) && !try_to_fail) - if(success(user, target, target_zone, tool, surgery)) - play_success_sound(user, target, target_zone, tool, surgery) + if(success(user, target, tool, surgery)) + play_success_sound(user, target, tool, surgery) advance = TRUE - else if(failure(user, target, target_zone, tool, surgery, fail_prob)) + else if(failure(user, target, tool, surgery, fail_prob)) + play_failure_sound(user, target, tool, surgery) advance = TRUE if(advance && !repeatable) @@ -128,12 +128,12 @@ surgery.step_in_progress = FALSE return advance -/datum/surgery_step/proc/preop(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/proc/preop(mob/user, mob/living/target, obj/item/tool, datum/surgery/surgery) display_results(user, target, "You begin to perform surgery on [target]...", "[user] begins to perform surgery on [target].", "[user] begins to perform surgery on [target].") -/datum/surgery_step/proc/play_preop_sound(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/proc/play_preop_sound(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(!preop_sound) return var/sound_file_use @@ -146,18 +146,18 @@ sound_file_use = preop_sound playsound(get_turf(target), sound_file_use, 75, TRUE, falloff_exponent = 12, falloff_distance = 1) -/datum/surgery_step/proc/success(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = TRUE) +/datum/surgery_step/proc/success(mob/user, mob/living/target, obj/item/tool, datum/surgery/surgery, default_display_results = TRUE) display_results(user, target, "You succeed.", "[user] succeeds.", "[user] finishes.") return TRUE -/datum/surgery_step/proc/play_success_sound(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/proc/play_success_sound(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(!success_sound) return playsound(get_turf(target), success_sound, 75, TRUE, falloff_exponent = 12, falloff_distance = 1) -/datum/surgery_step/proc/failure(mob/user, mob/living/target, target_zone, obj/item/tool, datum/surgery/surgery, fail_prob = 0) +/datum/surgery_step/proc/failure(mob/user, mob/living/target, obj/item/tool, datum/surgery/surgery, fail_prob = 0) var/screwedmessage = "" switch(fail_prob) if(0 to 24) @@ -172,7 +172,7 @@ "[user] finishes.", TRUE) //By default the patient will notice if the wrong thing has been cut return FALSE -/datum/surgery_step/proc/play_failure_sound(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) +/datum/surgery_step/proc/play_failure_sound(mob/user, mob/living/carbon/target, obj/item/tool, datum/surgery/surgery) if(!failure_sound) return playsound(get_turf(target), failure_sound, 75, TRUE, falloff_exponent = 12, falloff_distance = 1) diff --git a/code/modules/surgery/tools.dm b/code/modules/surgery/tools.dm index a37abc9c01583..dd245beb64fa9 100644 --- a/code/modules/surgery/tools.dm +++ b/code/modules/surgery/tools.dm @@ -233,8 +233,7 @@ attack_verb = list("slapped") /obj/item/surgical_drapes/attack(mob/living/M, mob/user) - if(!attempt_initiate_surgery(src, M, user)) - ..() + attempt_initiate_surgery(src, M, user) /obj/item/organ_storage //allows medical cyborgs to manipulate organs without hands name = "organ storage bag" diff --git a/code/modules/zombie/items.dm b/code/modules/zombie/items.dm index 675ec355535d8..602755735e9f0 100644 --- a/code/modules/zombie/items.dm +++ b/code/modules/zombie/items.dm @@ -34,7 +34,7 @@ else if(isliving(target)) if(ishuman(target)) var/mob/living/carbon/human/H = target - var/flesh_wound = ran_zone(user.zone_selected) + var/flesh_wound = ran_zone(user.get_combat_bodyzone(target)) if(H.check_shields(src, 0)) return if(prob(100-H.getarmor(flesh_wound, MELEE, armour_penetration))) diff --git a/icons/mob/screen_gen.dmi b/icons/mob/screen_gen.dmi index 712c6d1b2c2b9..1ead9f6d2309d 100644 Binary files a/icons/mob/screen_gen.dmi and b/icons/mob/screen_gen.dmi differ diff --git a/icons/mob/zone_dam.dmi b/icons/mob/zone_dam.dmi new file mode 100644 index 0000000000000..265e9b1289ac1 Binary files /dev/null and b/icons/mob/zone_dam.dmi differ diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx index 0d24e6904e16e..256a27c464fcb 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx @@ -18,6 +18,8 @@ const CATEGORY_SCALES = { type Keybinding = { name: string; description?: string; + pref_key?: string; + pref_value?: string; }; type Keybindings = Record>; @@ -416,6 +418,7 @@ export class KeybindingsPage extends Component<{}, KeybindingsPageState> { ); } const { act } = useBackend(this.context); + const { data } = useBackend(this.context); const keybindings = this.state?.keybindings; if (!keybindings) { @@ -439,37 +442,44 @@ export class KeybindingsPage extends Component<{}, KeybindingsPageState> { return [ category, - {sortKeybindings(Object.entries(keybindings)).map(([keybindingId, keybinding]) => { - const keys = this.state.selectedKeybindings![keybindingId] || []; - - const name = ( - - - - ); - - return ( - - - {name} - - {range(0, 3).map((key) => ( - - + {sortKeybindings(Object.entries(keybindings)) + .filter(([keybindingId, keybinding]) => { + return ( + !keybinding.pref_key || + data.character_preferences.game_preferences[keybinding.pref_key] === keybinding.pref_value + ); + }) + .map(([keybindingId, keybinding]) => { + const keys = this.state.selectedKeybindings![keybindingId] || []; + + const name = ( + + + + ); + + return ( + + + {name} + + {range(0, 3).map((key) => ( + + + + ))} + + + - ))} - - - - - - - ); - })} + + + ); + })} , ]; })} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/hotkeys.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/hotkeys.tsx index 04ed6c04558f7..ce4546fef5144 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/hotkeys.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/game_preferences/hotkeys.tsx @@ -1,4 +1,4 @@ -import { CheckboxInputInverse, FeatureToggle } from '../base'; +import { CheckboxInputInverse, FeatureButtonedDropdownInput, FeatureToggle, Feature } from '../base'; export const hotkeys: FeatureToggle = { name: 'Classic hotkeys', @@ -6,3 +6,11 @@ export const hotkeys: FeatureToggle = { description: 'When enabled, will revert to the legacy hotkeys, using the input bar rather than popups.', component: CheckboxInputInverse, }; + +export const zone_select: Feature = { + name: 'Bodyzone Targeting Mode', + category: 'GAMEPLAY', + description: + 'When set to simplified, the bodyzone system will be replaced with a grouped system where the bodyparts are put into 3 groups: Arms, Legs and Body/Chest. This setting is recommended if you do not have a numpad or want a simpler experience', + component: FeatureButtonedDropdownInput, +};