Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplified bodyzone targeting preference #9845

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
09630f6
Zone selector for patches
PowerfulBacon Aug 30, 2023
d27e1f1
Preference
PowerfulBacon Sep 17, 2023
56c8f38
Merge remote-tracking branch 'upstream/master' into Patch-application…
PowerfulBacon Sep 17, 2023
4835b01
Adds in a generic bodyzone part getter
PowerfulBacon Sep 17, 2023
b919f8f
Combat zone targetting
PowerfulBacon Sep 17, 2023
93c678a
Update mob_helpers.dm
PowerfulBacon Sep 17, 2023
944ec8f
Fixes some mistakes
PowerfulBacon Sep 17, 2023
cd80d29
Bug fixes, makes the task not have a delay
PowerfulBacon Sep 17, 2023
4155f7f
Makes the bodyzone wheel represent the positions of the limb
PowerfulBacon Sep 17, 2023
7df3c03
Mechanical repair interaction
PowerfulBacon Sep 17, 2023
95ce577
Adds in the flashlight interaction
PowerfulBacon Sep 17, 2023
3470c60
Hotkeys can now be hidden based on the values of preferences
PowerfulBacon Sep 17, 2023
d9810c7
Scroll hotkey for cycling the selected area
PowerfulBacon Sep 17, 2023
050453d
Surgery, cleans up the priority code and spelling mistake correction
PowerfulBacon Sep 17, 2023
534a06d
Update mob_helpers.dm
PowerfulBacon Sep 17, 2023
96f3e98
Fixes the logic in the technophile cult
PowerfulBacon Sep 17, 2023
a2cdb69
Voodoo Doll
PowerfulBacon Sep 17, 2023
b1f9afe
Update code/__DEFINES/preferences.dm
PowerfulBacon Sep 17, 2023
7decb58
Review addresses
PowerfulBacon Sep 17, 2023
e1113ed
Adjacency checks
PowerfulBacon Sep 17, 2023
91a2bf6
Merge branch 'Patch-application-improvements' of https://github.com/P…
PowerfulBacon Sep 17, 2023
8f1fcc7
Changes the dropdown to buttons
PowerfulBacon Sep 17, 2023
75d0e1b
Fix
PowerfulBacon Sep 17, 2023
633a43f
Named parameter arguments
PowerfulBacon Sep 17, 2023
3b557dd
Changes the required preference to a typepath
PowerfulBacon Sep 17, 2023
f8c4f00
Update _basemap.dm
PowerfulBacon Sep 17, 2023
4dc5cef
Fixes wrong variable name
PowerfulBacon Sep 17, 2023
6e2c126
You now have to be adjacent to medical items to use them as well as t…
PowerfulBacon Sep 17, 2023
e3d1f1c
You can't select a bodyzone to heal while healing
PowerfulBacon Sep 17, 2023
0e04251
Removes the ERP message when using simplified zone targeting since it…
PowerfulBacon Sep 17, 2023
430b982
Merge remote-tracking branch 'upstream/master' into Patch-application…
PowerfulBacon Sep 18, 2023
477bd33
Fixes holoparasite missing parameters
PowerfulBacon Sep 18, 2023
8fcf8d0
Merge branch 'master' into Patch-application-improvements
PowerfulBacon Dec 16, 2023
c0785af
Makes it so that mechanical repairs repeat
PowerfulBacon Dec 16, 2023
bcacdae
Fixes some linter catches
PowerfulBacon Dec 16, 2023
d1ba39b
Fixes surgery on groin being impossible
PowerfulBacon Dec 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions beestation.dme
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -2335,6 +2336,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"
Expand Down
4 changes: 4 additions & 0 deletions code/__DEFINES/async.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
7 changes: 7 additions & 0 deletions code/__DEFINES/bodyparts.dm
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions code/__DEFINES/combat.dm
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,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"
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/keybinding.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 4 additions & 0 deletions code/__DEFINES/preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -186,3 +189,4 @@ GLOBAL_PROTECT(undatumized_preference_tags_character)
#define PREFERENCE_LOAD_NO_DATA 2
/// Normal behavior - success!
#define PREFERENCE_LOAD_SUCCESS 3

142 changes: 142 additions & 0 deletions code/__HELPERS/mob_bodyzone.dm
Original file line number Diff line number Diff line change
@@ -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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you define something only to immediately rgb2num it why not define it in the correct format

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well the VS code plugin I have doesn't handle the byond specific list() format of colours compared to RGB colours, so it makes it a lot easier to see what colours have been defined.
image
Compared to
image

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need it in list() format? BYOND supports hex colors

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am generating a colour matrix from it because the target icon is red instead of white

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change it to whiteee

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
11 changes: 10 additions & 1 deletion code/_onclick/click.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down Expand Up @@ -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
Expand Down
35 changes: 18 additions & 17 deletions code/_onclick/hud/screen_objects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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'
Expand All @@ -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'
Expand Down
2 changes: 1 addition & 1 deletion code/datums/components/butchering.dm
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
user.show_message("<span class='danger'>[H]'s neck has already been already cut, you can't make the bleeding any worse!", 1, \
"<span class='danger'>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

Expand Down
2 changes: 1 addition & 1 deletion code/datums/components/embedded.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion code/datums/components/jousting.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion code/datums/components/pellet_cloud.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading
Loading