diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm index 49ed7f612c1..d87d46b86fe 100644 --- a/code/__DEFINES/preferences.dm +++ b/code/__DEFINES/preferences.dm @@ -84,6 +84,7 @@ #define RADIAL_STACKS (1<<2) #define AUTO_INTERACT_DEPLOYABLES (1<<3) #define RADIAL_LASERGUNS (1<<4) +#define DIRECTIONAL_ATTACKS (1<<5) #define PARALLAX_INSANE -1 //for show offs #define PARALLAX_HIGH 0 //default. @@ -105,7 +106,7 @@ #define SCALING_METHOD_DISTORT "distort" #define SCALING_METHOD_BLUR "blur" -#define TOGGLES_GAMEPLAY_DEFAULT (RADIAL_MEDICAL|MIDDLESHIFTCLICKING|RADIAL_STACKS|AUTO_INTERACT_DEPLOYABLES|RADIAL_LASERGUNS) +#define TOGGLES_GAMEPLAY_DEFAULT (RADIAL_MEDICAL|MIDDLESHIFTCLICKING|RADIAL_STACKS|AUTO_INTERACT_DEPLOYABLES|RADIAL_LASERGUNS|DIRECTIONAL_ATTACKS) #define CHARACTER_CUSTOMIZATION 1 #define PRED_CHARACTER_CUSTOMIZATION 2 diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 01168c7f697..1af2cdd2aef 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -524,6 +524,7 @@ GLOBAL_LIST_INIT(bitfields, list( "RADIAL_STACKS" = RADIAL_STACKS, "AUTO_INTERACT_DEPLOYABLES" = AUTO_INTERACT_DEPLOYABLES, "RADIAL_LASERGUNS" = RADIAL_LASERGUNS, + "DIRECTIONAL_ATTACKS" = DIRECTIONAL_ATTACKS, ), "toggles_deadchat" = list( "DISABLE_DEATHRATTLE" = DISABLE_DEATHRATTLE, diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 60736d84611..8412b50f860 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -151,7 +151,9 @@ else if(A.Adjacent(src)) A.attack_hand(src) - RangedAttack(A, params) + + if(!A.Adjacent(src)) + RangedAttack(A, params) /atom/movable/proc/CanReach(atom/ultimate_target, obj/item/tool, view_only = FALSE) diff --git a/code/datums/elements/directional_attack.dm b/code/datums/elements/directional_attack.dm new file mode 100644 index 00000000000..4b130aa2962 --- /dev/null +++ b/code/datums/elements/directional_attack.dm @@ -0,0 +1,43 @@ +/*! + * This element allows the mob its attached to the ability to click an adjacent mob by clicking a distant atom + * that is in the general direction relative to the parent. + */ +/datum/element/directional_attack/Attach(datum/target) + . = ..() + if(!ismob(target)) + return ELEMENT_INCOMPATIBLE + + RegisterSignal(target, COMSIG_MOB_ATTACK_RANGED, PROC_REF(on_ranged_attack)) + +/datum/element/directional_attack/Detach(datum/source, ...) + . = ..() + UnregisterSignal(source, COMSIG_MOB_ATTACK_RANGED) + +/** + * This proc handles clicks on tiles that aren't adjacent to the source mob + * In addition to clicking the distant tile, it checks the tile in the direction and clicks the mob in the tile if there is one + * Arguments: + * * source - The mob clicking + * * clicked_atom - The atom being clicked (should be a distant one) + * * click_params - Miscellaneous click parameters, passed from Click itself + */ +/datum/element/directional_attack/proc/on_ranged_attack(mob/source, atom/clicked_atom, click_params) + SIGNAL_HANDLER + + if(!(source?.client?.prefs?.toggles_gameplay & DIRECTIONAL_ATTACKS)) + return + + if(QDELETED(clicked_atom)) + return + + var/turf/turf_to_check = get_step(source, angle_to_dir(Get_Angle(source, clicked_atom))) + if(!turf_to_check || !source.Adjacent(turf_to_check)) + return + + var/mob/target_mob = locate() in turf_to_check + if(!target_mob || source.faction == target_mob.faction) + return + + //This is here to undo the +1 the click on the distant turf adds so we can click the mob near us + source.next_click = world.time - 1 + INVOKE_ASYNC(source, TYPE_PROC_REF(/mob, ClickOn), target_mob, turf_to_check, click_params) diff --git a/code/modules/client/preferences_ui.dm b/code/modules/client/preferences_ui.dm index d6d79fc57ce..e23464c70cd 100644 --- a/code/modules/client/preferences_ui.dm +++ b/code/modules/client/preferences_ui.dm @@ -152,6 +152,7 @@ data["radialstackspref"] = !!(toggles_gameplay & RADIAL_STACKS) data["radiallasersgunpref"] = !!(toggles_gameplay & RADIAL_LASERGUNS) data["autointeractdeployablespref"] = !!(toggles_gameplay & AUTO_INTERACT_DEPLOYABLES) + data["directional_attacks"] = !!(toggles_gameplay & DIRECTIONAL_ATTACKS) data["scaling_method"] = scaling_method data["pixel_size"] = pixel_size data["parallax"] = parallax @@ -974,6 +975,9 @@ if("autointeractdeployablespref") toggles_gameplay ^= AUTO_INTERACT_DEPLOYABLES + if("directional_attacks") + toggles_gameplay ^= DIRECTIONAL_ATTACKS + if("pixel_size") switch(pixel_size) if(PIXEL_SCALING_AUTO) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 3193e7d039e..7e357c31d82 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -98,6 +98,7 @@ set_armor_datum() AddElement(/datum/element/gesture) AddElement(/datum/element/keybinding_update) + AddElement(/datum/element/directional_attack) /mob/living/Destroy() for(var/datum/status_effect/effect AS in status_effects) diff --git a/tgmc.dme b/tgmc.dme index 1c93b62eab4..239e5050d72 100644 --- a/tgmc.dme +++ b/tgmc.dme @@ -432,6 +432,7 @@ #include "code\datums\elements\attachment.dm" #include "code\datums\elements\connect_loc.dm" #include "code\datums\elements\debris.dm" +#include "code\datums\elements\directional_attack.dm" #include "code\datums\elements\egrill_element.dm" #include "code\datums\elements\footstep.dm" #include "code\datums\elements\gestures.dm" diff --git a/tgui/packages/tgui/interfaces/PlayerPreferences/GameSettings.tsx b/tgui/packages/tgui/interfaces/PlayerPreferences/GameSettings.tsx index a08eecd84d7..f7685ef0f6c 100644 --- a/tgui/packages/tgui/interfaces/PlayerPreferences/GameSettings.tsx +++ b/tgui/packages/tgui/interfaces/PlayerPreferences/GameSettings.tsx @@ -132,6 +132,13 @@ export const GameSettings = (props, context) => { leftLabel={'Enabled'} rightLabel={'Disabled'} /> +