From 0204ab8fdd91c04b90b43b3b819087055b1ba5f6 Mon Sep 17 00:00:00 2001 From: die <96586172+grungussuss@users.noreply.github.com> Date: Tue, 7 Oct 2025 21:28:59 +0300 Subject: [PATCH] Canreach refactor (#93165) ## About The Pull Request ports https://github.com/DaedalusDock/daedalusdock/pull/1144 ports https://github.com/DaedalusDock/daedalusdock/pull/1147 full credit to @Kapu1178 for the juice instead of `reacher.CanReach(target)` we now do `target.CanBeReachedBy(reacher)`, this allows us to give special behavior to atoms which we want to reach, which is exactly what I need for a feature I'm working on. ## Why It's Good For The Game allows us to be more flexible with reachability ## Changelog :cl: refactor: refactored how reaching items works, report any oddities with being unable to reach something you should be able to! /:cl: --- code/__DEFINES/_flags.dm | 20 ++-- .../signals/signals_atom/signals_atom_main.dm | 3 - code/__DEFINES/inventory.dm | 5 +- code/__DEFINES/traits/declarations.dm | 2 + code/_globalvars/bitfields.dm | 1 - code/_globalvars/traits/_traits.dm | 1 + code/_onclick/click.dm | 103 ++++++++++++------ code/_onclick/cyborg.dm | 2 +- code/_onclick/drag_drop.dm | 2 +- code/datums/ai/_ai_controller.dm | 2 +- .../basic_ai_behaviors/basic_attacking.dm | 2 +- .../basic_subtrees/attack_adjacent_target.dm | 3 +- .../basic_subtrees/escape_captivity.dm | 2 +- .../ai/hunting_behavior/hunting_mouse.dm | 2 +- code/datums/ai/monkey/monkey_behaviors.dm | 4 +- code/datums/brain_damage/severe.dm | 2 +- code/datums/components/happiness.dm | 2 +- code/datums/components/profound_fisher.dm | 2 +- code/datums/components/riding/riding_mob.dm | 2 +- code/datums/components/tether.dm | 2 +- code/datums/elements/climbable.dm | 2 +- .../elements/openspace_item_click_handler.dm | 2 +- code/datums/embedding.dm | 2 +- code/datums/mutations/reach.dm | 32 +----- code/datums/status_effects/neutral.dm | 6 +- code/datums/storage/storage.dm | 10 +- code/datums/wires/_wires.dm | 2 +- code/game/machinery/computer/telescreen.dm | 2 +- code/game/machinery/doors/airlock.dm | 2 +- code/game/machinery/doors/firedoor.dm | 2 +- code/game/objects/buckling.dm | 2 +- code/game/objects/effects/misc.dm | 5 + code/game/objects/items/cards_ids.dm | 4 +- code/game/objects/items/dyespray.dm | 2 +- code/game/objects/items/food/misc.dm | 2 +- code/game/objects/items/stacks/medical.dm | 2 +- .../items/storage/toolboxes/_toolbox.dm | 2 +- code/game/objects/structures/bedsheet_bin.dm | 2 +- code/game/objects/structures/mystery_box.dm | 4 +- code/game/objects/structures/tables_racks.dm | 8 +- .../structures/water_structures/toilet.dm | 2 +- .../heretic/magic/flesh_surgery.dm | 4 +- .../antagonists/ninja/energy_katana.dm | 2 +- .../antagonists/wizard/equipment/soulstone.dm | 4 +- code/modules/art/paintings.dm | 4 +- code/modules/fishing/fish_mount.dm | 5 +- code/modules/fishing/fishing_minigame.dm | 2 +- .../food_and_drinks/machinery/griddle.dm | 5 +- .../modules/food_and_drinks/machinery/oven.dm | 5 +- .../food_and_drinks/machinery/processor.dm | 2 +- .../machinery/stove_component.dm | 4 +- code/modules/food_and_drinks/plate.dm | 5 +- .../ruins/spaceruin_code/hilbertshotel.dm | 2 +- code/modules/mining/equipment/grapple_gun.dm | 2 +- code/modules/mob/living/basic/bots/dedbot.dm | 2 +- .../mob/living/basic/bots/medbot/medbot.dm | 2 +- code/modules/mob/living/basic/clown/clown.dm | 6 +- .../basic/lavaland/goliath/goliath_ai.dm | 2 +- .../basic/lavaland/mook/mook_abilities.dm | 6 +- .../mob/living/basic/pets/dog/corgi.dm | 2 +- .../mob/living/basic/ruin_defender/flesh.dm | 2 +- code/modules/mob/living/living.dm | 4 +- code/modules/mob/living/living_defines.dm | 3 + .../mob/living/living_item_handling.dm | 2 +- .../mod/modules/modules_engineering.dm | 6 +- code/modules/point/point.dm | 2 +- .../mobile_port/variants/custom/blueprints.dm | 2 +- .../variants/emergency/emergency_console.dm | 2 +- code/modules/vending/vendor/inventory.dm | 2 +- 69 files changed, 190 insertions(+), 162 deletions(-) diff --git a/code/__DEFINES/_flags.dm b/code/__DEFINES/_flags.dm index 323785844ee..ca65bcaf9dd 100644 --- a/code/__DEFINES/_flags.dm +++ b/code/__DEFINES/_flags.dm @@ -37,29 +37,27 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204 #define ALLOW_DARK_PAINTS_1 (1<<8) /// Should this object be unpaintable? #define UNPAINTABLE_1 (1<<9) -/// Is this atom on top of another atom, and as such has click priority? -#define IS_ONTOP_1 (1<<10) /// Is this atom immune to being dusted by the supermatter? -#define SUPERMATTER_IGNORES_1 (1<<11) +#define SUPERMATTER_IGNORES_1 (1<<10) /// If a turf can be made dirty at roundstart. This is also used in areas. -#define CAN_BE_DIRTY_1 (1<<12) +#define CAN_BE_DIRTY_1 (1<<11) /// Should we use the initial icon for display? Mostly used by overlay only objects -#define HTML_USE_INITAL_ICON_1 (1<<13) +#define HTML_USE_INITAL_ICON_1 (1<<12) /// Can players recolor this in-game via vendors (and maybe more if support is added)? -#define IS_PLAYER_COLORABLE_1 (1<<14) +#define IS_PLAYER_COLORABLE_1 (1<<13) /// Whether or not this atom has contextual screentips when hovered OVER -#define HAS_CONTEXTUAL_SCREENTIPS_1 (1<<15) +#define HAS_CONTEXTUAL_SCREENTIPS_1 (1<<14) /// Whether or not this atom is storing contents for a disassociated storage object -#define HAS_DISASSOCIATED_STORAGE_1 (1<<16) +#define HAS_DISASSOCIATED_STORAGE_1 (1<<15) /// If this atom has experienced a decal element "init finished" sourced appearance update /// We use this to ensure stacked decals don't double up appearance updates for no reason /// Flag as an optimization, don't make this a trait without profiling /// Yes I know this is a stupid flag, no you can't take him from me -#define DECAL_INIT_UPDATE_EXPERIENCED_1 (1<<17) +#define DECAL_INIT_UPDATE_EXPERIENCED_1 (1<<16) /// This atom always returns its turf in get_turf_pixel instead of the turf from its offsets -#define IGNORE_TURF_PIXEL_OFFSET_1 (1<<18) +#define IGNORE_TURF_PIXEL_OFFSET_1 (1<<17) /// This atom does not need to generate its own preview icon for GAGS -#define NO_NEW_GAGS_PREVIEW_1 (1<<19) +#define NO_NEW_GAGS_PREVIEW_1 (1<<18) // Update flags for [/atom/proc/update_appearance] /// Update the atom's name diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm index 522a5b72f55..3ca26908e24 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm @@ -76,9 +76,6 @@ #define COMSIG_ATOM_BUMPED "atom_bumped" ///from base of atom/has_gravity(): (turf/location, list/forced_gravities) #define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity" -///from internal loop in atom/movable/proc/CanReach(): (list/next) -#define COMSIG_ATOM_CANREACH "atom_can_reach" - #define COMPONENT_ALLOW_REACH (1<<0) ///for when an atom has been created through processing (atom/original_atom, list/chosen_processing_option) #define COMSIG_ATOM_CREATEDBY_PROCESSING "atom_createdby_processing" ///when an atom is processed (mob/living/user, obj/item/process_item, list/atom/results) diff --git a/code/__DEFINES/inventory.dm b/code/__DEFINES/inventory.dm index 1c7b6a41f84..4b524bcc5d6 100644 --- a/code/__DEFINES/inventory.dm +++ b/code/__DEFINES/inventory.dm @@ -19,8 +19,9 @@ //Inventory depth: limits how many nested storage items you can access directly. //1: stuff in mob, 2: stuff in backpack, 3: stuff in box in backpack, etc -#define INVENTORY_DEPTH 3 -#define STORAGE_VIEW_DEPTH 2 +#define REACH_DEPTH_SELF 1 +/// A storage depth ontop of SELF. REACH_DEPTH_STORAGE(1) would allow an item inside of a backpack you are carrying. +#define REACH_DEPTH_STORAGE(level) (level + REACH_DEPTH_SELF) //ITEM INVENTORY SLOT BITMASKS /// Suit slot (armors, costumes, space suits, etc.) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 67d38d4e7db..96642ba3b4c 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -959,6 +959,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_EXAMINE_SKIP "examine_skip" /// Objects with this trait cannot be repaired with duct tape #define TRAIT_DUCT_TAPE_UNREPAIRABLE "duct_tape_unrepairable" +/// An item is ALWAYS considered baseline reachable and will pipe into CanBeReached(). +#define TRAIT_SKIP_BASIC_REACH_CHECK "skip_basic_reach_check" //quirk traits #define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance" diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index f8f1b2cc917..f2a923d0d58 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -138,7 +138,6 @@ DEFINE_BITFIELD(flags_1, list( "HTML_USE_INITAL_ICON_1" = HTML_USE_INITAL_ICON_1, "IGNORE_TURF_PIXEL_OFFSET_1" = IGNORE_TURF_PIXEL_OFFSET_1, "INITIALIZED_1" = INITIALIZED_1, - "IS_ONTOP_1" = IS_ONTOP_1, "IS_PLAYER_COLORABLE_1" = IS_PLAYER_COLORABLE_1, "NO_NEW_GAGS_PREVIEW_1" = NO_NEW_GAGS_PREVIEW_1, "NO_SCREENTIPS_1" = NO_SCREENTIPS_1, diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index b445f25381a..d7d8a36a459 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -685,6 +685,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_UNCOMPOSTABLE" = TRAIT_UNCOMPOSTABLE, "TRAIT_UNIQUE_AQUARIUM_CONTENT" = TRAIT_UNIQUE_AQUARIUM_CONTENT, "TRAIT_WIELDED" = TRAIT_WIELDED, + "TRAIT_SKIP_BASIC_REACH_CHECK" = TRAIT_SKIP_BASIC_REACH_CHECK, ), /obj/item/ammo_casing = list( "TRAIT_DART_HAS_INSERT" = TRAIT_DART_HAS_INSERT, diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 4e4b491b672..042d95b9a88 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -163,7 +163,7 @@ UnarmedAttack(item_atom, TRUE, modifiers) //Standard reach turf to turf or reaching inside storage - if(CanReach(A,W)) + if(A.IsReachableBy(src, W?.reach)) if(W) W.melee_attack_chain(src, A, modifiers) else @@ -200,42 +200,79 @@ return FALSE /** - * A backwards depth-limited breadth-first-search to see if the target is - * logically "in" anything adjacent to us. + * Returns TRUE if a movable can "Reach" this atom. This is defined as adjacency + * + * Args: + * * user: The movable trying to reach us. + * * reacher_range: How far the reacher can reach. + * * depth: How deep nested inside of an atom contents stack an object can be. + * * direct_access: Do not override. Used for recursion. */ -/atom/proc/CanReach(atom/ultimate_target, obj/item/tool, view_only = FALSE) - var/list/direct_access = DirectAccess() - var/depth = 1 + (view_only ? STORAGE_VIEW_DEPTH : INVENTORY_DEPTH) +/atom/proc/IsReachableBy(atom/movable/user, reacher_range = 1, depth = INFINITY, direct_access = user.DirectAccess()) + SHOULD_NOT_OVERRIDE(TRUE) - var/list/closed = list() - var/list/checking = list(ultimate_target) + if(isnull(user)) + return FALSE - while (checking.len && depth > 0) - var/list/next = list() - --depth - - for(var/atom/target in checking) // will filter out nulls - if(closed[target] || isarea(target)) // avoid infinity situations - continue - - if(isturf(target) || isturf(target.loc) || (target in direct_access) || (ismovable(target) && target.flags_1 & IS_ONTOP_1) || target.loc?.atom_storage) //Directly accessible atoms - if(Adjacent(target) || (tool && CheckToolReach(src, target, tool.reach))) //Adjacent or reaching attacks - return TRUE - - closed[target] = TRUE - - if (!target.loc) - continue - - if(target.loc.atom_storage) - next += target.loc - - checking = next - - if(SEND_SIGNAL(src, COMSIG_ATOM_CANREACH, ultimate_target) & COMPONENT_ALLOW_REACH) + if(src in direct_access) return TRUE - return FALSE + // This is a micro-opt, if any turf ever returns false from IsContainedAtomAccessible, change this. + if(isturf(loc) || isturf(src)) + if(CheckReachableAdjacency(user, reacher_range)) + return TRUE + + depth-- + + if(depth <= 0) + return FALSE + + if(isnull(loc) || isarea(loc) || !loc.IsContainedAtomAccessible(src, user)) + return FALSE + + return loc.IsReachableBy(user, reacher_range, depth, direct_access) + +/atom/proc/CheckReachableAdjacency(atom/movable/reacher, reacher_range) + if(reacher.Adjacent(src)) + return TRUE + + if(isliving(reacher)) + var/mob/living/living_reacher = reacher + if(living_reacher.reach_length > reacher_range) + reacher_range = living_reacher.reach_length + + return (reacher_range > 1) && RangedReachCheck(reacher, src, reacher_range) + +/// Called by IsReachableBy() to check for ranged reaches. +/proc/RangedReachCheck(atom/movable/here, atom/movable/there, reach) + if(!here || !there) + return FALSE + + if(reach <= 1) + return FALSE + + // Prevent infinite loop. + if(istype(here, /obj/effect/abstract/reach_checker)) + return FALSE + + var/obj/effect/abstract/reach_checker/dummy = new(get_turf(here)) + for(var/i in 1 to reach) //Limit it to that many tries + var/turf/T = get_step(dummy, get_dir(dummy, there)) + if(there.IsReachableBy(dummy)) + . = TRUE + break + + if(!dummy.Move(T)) //we're blocked! + break + + qdel(dummy) + +/// Returns TRUE if an atom contained within our contents is reachable. +/atom/proc/IsContainedAtomAccessible(atom/contained, atom/movable/user) + return TRUE + +/atom/movable/IsContainedAtomAccessible(atom/contained, atom/movable/user) + return !!atom_storage /atom/proc/DirectAccess() return list(src, loc) @@ -269,7 +306,7 @@ dummy.SetInvisibility(INVISIBILITY_ABSTRACT) for(var/i in 1 to reach) //Limit it to that many tries var/turf/T = get_step(dummy, get_dir(dummy, there)) - if(dummy.CanReach(there)) + if(there.IsReachableBy(dummy)) qdel(dummy) return TRUE if(!dummy.Move(T)) //we're blocked! diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm index 8ec29c8af14..d90ffb54507 100644 --- a/code/_onclick/cyborg.dm +++ b/code/_onclick/cyborg.dm @@ -85,7 +85,7 @@ return // cyborg rightclick code, allowing borgos to use weapons at range - if(CanReach(A,W)) + if(A.IsReachableBy(src, W?.reach)) W.melee_attack_chain(src, A, modifiers) return else if(isturf(A) || isturf(A.loc)) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index aa23d5a57ea..4fe49eb2862 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -38,7 +38,7 @@ var/combined_atom_flags = interaction_flags_atom | over.interaction_flags_atom if(!(combined_atom_flags & INTERACT_ATOM_MOUSEDROP_IGNORE_CHECKS)) //Check for adjacency - if(!(combined_atom_flags & INTERACT_ATOM_MOUSEDROP_IGNORE_ADJACENT) && (!CanReach(user) || !over.CanReach(user))) + if(!(combined_atom_flags & INTERACT_ATOM_MOUSEDROP_IGNORE_ADJACENT) && (!user.IsReachableBy(src) || user.IsReachableBy(src) || !user.IsReachableBy(over))) return // should stop you from dragging through windows if(!(combined_atom_flags & INTERACT_ATOM_MOUSEDROP_IGNORE_USABILITY)) diff --git a/code/datums/ai/_ai_controller.dm b/code/datums/ai/_ai_controller.dm index 7fb76efcc62..6c2e3d942d3 100644 --- a/code/datums/ai/_ai_controller.dm +++ b/code/datums/ai/_ai_controller.dm @@ -387,7 +387,7 @@ multiple modular subtrees with behaviors ///Stops pawns from performing such actions that should require the target to be adjacent. var/atom/movable/moving_pawn = pawn - var/can_reach = !(current_behavior.behavior_flags & AI_BEHAVIOR_REQUIRE_REACH) || moving_pawn.CanReach(current_movement_target) + var/can_reach = !(current_behavior.behavior_flags & AI_BEHAVIOR_REQUIRE_REACH) || current_movement_target.IsReachableBy(moving_pawn) if(can_reach && current_behavior.required_distance >= get_dist(moving_pawn, current_movement_target)) ///Are we close enough to engage? if(ai_movement.moving_controllers[src] == current_movement_target) //We are close enough, if we're moving stop. ai_movement.stop_moving_towards(src) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm index b75fc1ef38e..2e145c31ec4 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/basic_attacking.dm @@ -22,7 +22,7 @@ var/atom/target = controller.blackboard[target_key] if (isnull(target)) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_FAILED - if (!controller.pawn.CanReach(target)) + if (!target.IsReachableBy(controller.pawn)) controller.clear_blackboard_key(BB_BASIC_MOB_MELEE_COOLDOWN_TIMER) return AI_BEHAVIOR_INSTANT diff --git a/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm b/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm index 8effc7a0fa7..7dd626b1dc4 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/attack_adjacent_target.dm @@ -26,7 +26,8 @@ /datum/ai_behavior/basic_melee_attack/opportunistic/perform(seconds_per_tick, datum/ai_controller/controller, target_key, targeting_strategy_key, hiding_location_key) var/atom/movable/atom_pawn = controller.pawn - if(!atom_pawn.CanReach(controller.blackboard[target_key])) + var/atom/atom_target = controller.blackboard[target_key] + if(!atom_target.IsReachableBy(atom_pawn)) return AI_BEHAVIOR_INSTANT | AI_BEHAVIOR_SUCCEEDED . = ..() return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/datums/ai/basic_mobs/basic_subtrees/escape_captivity.dm b/code/datums/ai/basic_mobs/basic_subtrees/escape_captivity.dm index 9dfbfce94de..2c0a198c768 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/escape_captivity.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/escape_captivity.dm @@ -60,7 +60,7 @@ if (QDELETED(target)) return FALSE var/mob/living/pawn = controller.pawn - if (!pawn.CanReach(target)) + if (!target.IsReachableBy(pawn)) return FALSE return pawn.loc == target || pawn.buckled == target diff --git a/code/datums/ai/hunting_behavior/hunting_mouse.dm b/code/datums/ai/hunting_behavior/hunting_mouse.dm index b5c9a7743a4..ca849274f6d 100644 --- a/code/datums/ai/hunting_behavior/hunting_mouse.dm +++ b/code/datums/ai/hunting_behavior/hunting_mouse.dm @@ -40,7 +40,7 @@ if (!isturf(instrument.loc) || !can_see(pawn, instrument)) controller.clear_blackboard_key(BB_SONG_INSTRUMENT) return - if (pawn.CanReach(instrument)) + if (instrument.IsReachableBy(pawn)) return controller.queue_behavior(/datum/ai_behavior/travel_towards/adjacent, BB_SONG_INSTRUMENT) return SUBTREE_RETURN_FINISH_PLANNING diff --git a/code/datums/ai/monkey/monkey_behaviors.dm b/code/datums/ai/monkey/monkey_behaviors.dm index ef49de98823..01dd0b61449 100644 --- a/code/datums/ai/monkey/monkey_behaviors.dm +++ b/code/datums/ai/monkey/monkey_behaviors.dm @@ -87,7 +87,7 @@ var/success = FALSE - if(do_after(living_pawn, MONKEY_ITEM_SNATCH_DELAY, victim) && target && living_pawn.CanReach(victim)) + if(do_after(living_pawn, MONKEY_ITEM_SNATCH_DELAY, victim) && target && victim.IsReachableBy(living_pawn)) for(var/obj/item/I in victim.held_items) if(I == target) @@ -195,7 +195,7 @@ //look for any potential weapons we're holding var/obj/item/potential_weapon = locate() in living_pawn.held_items - if(!living_pawn.CanReach(target, potential_weapon)) + if(!target.IsReachableBy(living_pawn, potential_weapon?.reach)) return FALSE if(isnull(potential_weapon)) diff --git a/code/datums/brain_damage/severe.dm b/code/datums/brain_damage/severe.dm index 57cfae25cf5..b2b50cbe707 100644 --- a/code/datums/brain_damage/severe.dm +++ b/code/datums/brain_damage/severe.dm @@ -356,7 +356,7 @@ stealables += potential_stealable for(var/obj/item/stealable as anything in shuffle(stealables)) - if(!owner.CanReach(stealable, view_only = TRUE) || stealable.IsObscured()) + if(!stealable.IsReachableBy(owner) || stealable.IsObscured()) continue // Try to do a raw click on the item with one of our empty hands, to pick it up (duh) owner.log_message("attempted to pick up (kleptomania)", LOG_ATTACK, color = "orange") diff --git a/code/datums/components/happiness.dm b/code/datums/components/happiness.dm index 75aecee3561..95d3b0d1f42 100644 --- a/code/datums/components/happiness.dm +++ b/code/datums/components/happiness.dm @@ -104,7 +104,7 @@ START_PROCESSING(SSprocessing, src) /datum/component/happiness/proc/view_happiness(mob/living/source, mob/living/clicker) - if(HAS_TRAIT(source, TRAIT_MOB_HIDE_HAPPINESS) || !istype(clicker) || !COOLDOWN_FINISHED(src, happiness_inspect) || !clicker.CanReach(source)) + if(HAS_TRAIT(source, TRAIT_MOB_HIDE_HAPPINESS) || !istype(clicker) || !COOLDOWN_FINISHED(src, happiness_inspect) || !source.IsReachableBy(clicker)) return var/y_position = source.get_cached_height() + 1 var/obj/effect/overlay/happiness_overlay/hearts = new diff --git a/code/datums/components/profound_fisher.dm b/code/datums/components/profound_fisher.dm index 836fc7e2167..3c2ddbef1a8 100644 --- a/code/datums/components/profound_fisher.dm +++ b/code/datums/components/profound_fisher.dm @@ -105,7 +105,7 @@ /datum/component/profound_fisher/proc/should_fish_on(mob/living/user, atom/target) if(!HAS_TRAIT(target, TRAIT_FISHING_SPOT) || GLOB.fishing_challenges_by_user[user]) return FALSE - if(user.combat_mode || !user.CanReach(target)) + if(user.combat_mode || !target.IsReachableBy(user)) return FALSE return TRUE diff --git a/code/datums/components/riding/riding_mob.dm b/code/datums/components/riding/riding_mob.dm index e966012bdae..7a108574b9d 100644 --- a/code/datums/components/riding/riding_mob.dm +++ b/code/datums/components/riding/riding_mob.dm @@ -616,7 +616,7 @@ if(!isclosedturf(pointed)) return var/mob/living/basic/basic_parent = parent - if(!basic_parent.CanReach(pointed)) + if(!pointed.IsReachableBy(basic_parent)) return basic_parent.melee_attack(pointed) diff --git a/code/datums/components/tether.dm b/code/datums/components/tether.dm index b2aedaeb9ff..e156640682f 100644 --- a/code/datums/components/tether.dm +++ b/code/datums/components/tether.dm @@ -286,7 +286,7 @@ /datum/component/tether/proc/process_beam_click(atom/source, atom/location, params, mob/user) var/turf/nearest_turf for (var/turf/line_turf in get_line(get_turf(parent), get_turf(tether_target))) - if (user.CanReach(line_turf)) + if (line_turf.IsReachableBy(user)) nearest_turf = line_turf break diff --git a/code/datums/elements/climbable.dm b/code/datums/elements/climbable.dm index 8eaf86e2a3f..c2865f36258 100644 --- a/code/datums/elements/climbable.dm +++ b/code/datums/elements/climbable.dm @@ -37,7 +37,7 @@ examine_list["climbable"] = "It looks like it can be climbed on." /datum/element/climbable/proc/can_climb(atom/source, mob/user) - if (!user.CanReach(source)) + if (!source.IsReachableBy(user)) return FALSE var/dir_step = get_dir(user, source.loc) //To jump over a railing you have to be standing next to it, not far behind it. diff --git a/code/datums/elements/openspace_item_click_handler.dm b/code/datums/elements/openspace_item_click_handler.dm index 9059223fb0c..b43ec92a2bc 100644 --- a/code/datums/elements/openspace_item_click_handler.dm +++ b/code/datums/elements/openspace_item_click_handler.dm @@ -20,7 +20,7 @@ if((target.z == 0) || (user.z == 0) || target.z == user.z) return NONE var/turf/target_turf = parse_caught_click_modifiers(modifiers, get_turf(user.client?.eye || user), user.client) - if(target_turf?.z == user.z && user.CanReach(target_turf, source)) + if(target_turf?.z == user.z && target_turf.IsReachableBy(user, source?.reach)) INVOKE_ASYNC(source, TYPE_PROC_REF(/obj/item, handle_openspace_click), target_turf, user, modifiers) return ITEM_INTERACT_BLOCKING return NONE diff --git a/code/datums/embedding.dm b/code/datums/embedding.dm index dd6c044f79c..1c876468350 100644 --- a/code/datums/embedding.dm +++ b/code/datums/embedding.dm @@ -313,7 +313,7 @@ /// Someone attempted to pull us out! Either the owner by inspecting themselves, or someone else by examining the owner and clicking the link. /datum/embedding/proc/rip_out(mob/living/jack_the_ripper) - if (!jack_the_ripper.CanReach(owner)) + if (!owner.IsReachableBy(jack_the_ripper)) return if (!jack_the_ripper.can_perform_action(owner, FORBID_TELEKINESIS_REACH | NEED_HANDS | ALLOW_RESTING)) diff --git a/code/datums/mutations/reach.dm b/code/datums/mutations/reach.dm index e5757346f9b..24f2d5d37e8 100644 --- a/code/datums/mutations/reach.dm +++ b/code/datums/mutations/reach.dm @@ -53,15 +53,16 @@ . = ..() if(!.) return - RegisterSignal(homan, COMSIG_ATOM_CANREACH, PROC_REF(on_canreach)) RegisterSignal(homan, COMSIG_LIVING_TRY_PUT_IN_HAND, PROC_REF(on_owner_equipping_item)) RegisterSignal(homan, COMSIG_LIVING_TRY_PULL, PROC_REF(on_owner_try_pull)) + homan.reach_length++ /datum/mutation/elastic_arms/on_losing(mob/living/carbon/human/homan) . = ..() if(.) return - UnregisterSignal(homan, list(COMSIG_ATOM_CANREACH, COMSIG_LIVING_TRY_PUT_IN_HAND, COMSIG_LIVING_TRY_PULL)) + UnregisterSignal(homan, list(COMSIG_LIVING_TRY_PUT_IN_HAND, COMSIG_LIVING_TRY_PULL)) + homan.reach_length = min(1, homan.reach_length - 1) /// signal sent when prompting if an item can be equipped /datum/mutation/elastic_arms/proc/on_owner_equipping_item(mob/living/carbon/human/owner, obj/item/pick_item) @@ -83,30 +84,3 @@ if(item_target.w_class > WEIGHT_CLASS_BULKY) item_target.balloon_alert(owner, "arms too floppy to pull this!") return COMSIG_LIVING_CANCEL_PULL - -// probably buggy. let's enlist our players as bug testers -/datum/mutation/elastic_arms/proc/on_canreach(mob/source, atom/target) - SIGNAL_HANDLER - - var/distance = get_dist(target, source) - - // We only care about handling the reach distance, anything closer or further is handled normally. - // Also, no z-level shenanigans. Yet. - if((distance != 2) || source.z != target.z) - return - - var/direction = get_dir(source, target) - if(!direction) - return - var/turf/open/adjacent_turf = get_step(source, direction) - - // Make sure it's an open turf we're trying to pass over. - if(!istype(adjacent_turf)) - return - - // Check if there's something dense inbetween, then allow it. - for(var/atom/thing in adjacent_turf) - if(thing.density) - return - - return COMPONENT_ALLOW_REACH diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm index 162ccb6770e..8f2c168706d 100644 --- a/code/datums/status_effects/neutral.dm +++ b/code/datums/status_effects/neutral.dm @@ -265,7 +265,7 @@ /// One of our possible takers moved, see if they left us hanging /datum/status_effect/offering/proc/check_taker_in_range(mob/living/taker) SIGNAL_HANDLER - if(owner.CanReach(taker) && !IS_DEAD_OR_INCAP(taker)) + if(taker.IsReachableBy(owner) && !IS_DEAD_OR_INCAP(taker)) return to_chat(taker, span_warning("You moved out of range of [owner]!")) @@ -276,7 +276,7 @@ SIGNAL_HANDLER for(var/mob/living/checking_taker as anything in possible_takers) - if(!istype(checking_taker) || !owner.CanReach(checking_taker) || IS_DEAD_OR_INCAP(checking_taker)) + if(!istype(checking_taker) || !checking_taker.IsReachableBy(owner) || IS_DEAD_OR_INCAP(checking_taker)) remove_candidate(checking_taker) /// We lost the item, give it up @@ -291,7 +291,7 @@ * Returns `TRUE` if the taker is valid as a target for the offering. */ /datum/status_effect/offering/proc/is_taker_elligible(mob/living/taker) - return owner.CanReach(taker) && !IS_DEAD_OR_INCAP(taker) && additional_taker_check(taker) + return taker.IsReachableBy(owner) && !IS_DEAD_OR_INCAP(taker) && additional_taker_check(taker) /** * Additional checks added to `CanReach()` and `IS_DEAD_OR_INCAP()` in `is_taker_elligible()`. diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index ef525effb3d..4c5d6b8efbe 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -650,7 +650,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) */ /datum/storage/proc/remove_type(type, atom/destination, amount = INFINITY, check_adjacent = FALSE, force = FALSE, mob/user, list/inserted) if(!force && check_adjacent) - if(isnull(user) || !user.CanReach(destination) || !user.CanReach(parent)) + if(isnull(user) || !destination.IsReachableBy(user) || !parent.IsReachableBy(user)) return FALSE var/list/taking = typecache_filter_list(real_location.contents, typecacheof(type)) @@ -823,7 +823,7 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) if(locked) user.balloon_alert(user, "closed!") return - if(!user.CanReach(parent) || !user.CanReach(dest_object)) + if(!parent.IsReachableBy(user) || !dest_object.IsReachableBy(user)) return if(SEND_SIGNAL(dest_object, COMSIG_STORAGE_DUMP_CONTENT, src, user) & STORAGE_DUMP_HANDLED) @@ -985,9 +985,13 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) SIGNAL_HANDLER for(var/mob/user in can_see_contents()) - if (!user.CanReach(parent)) + if (!can_be_reached_by(user)) hide_contents(user) +/// Relay for parent.IsReachableBy +/datum/storage/proc/can_be_reached_by(mob/user) + return parent.IsReachableBy(user) + /// Close the storage UI for everyone viewing us. /datum/storage/proc/close_all() for(var/mob/user as anything in is_using) diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index b53bb64183b..d255d9d0f26 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -24,7 +24,7 @@ /atom/proc/attempt_wire_interaction(mob/user) if(!wires) return WIRE_INTERACTION_FAIL - if(!user.CanReach(src)) + if(!IsReachableBy(user)) return WIRE_INTERACTION_FAIL INVOKE_ASYNC(wires, TYPE_PROC_REF(/datum/wires, interact), user) return WIRE_INTERACTION_BLOCK diff --git a/code/game/machinery/computer/telescreen.dm b/code/game/machinery/computer/telescreen.dm index 12bafc3f73e..51f00c7f1b2 100644 --- a/code/game/machinery/computer/telescreen.dm +++ b/code/game/machinery/computer/telescreen.dm @@ -106,7 +106,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai if(HAS_SILICON_ACCESS(user) || (user.interaction_range && user.interaction_range >= get_dist(user, src))) can_range = TRUE - if((can_range || user.CanReach(src)) && ISADVANCEDTOOLUSER(user)) + if((can_range || IsReachableBy(user)) && ISADVANCEDTOOLUSER(user)) if(user.incapacitated) return UI_UPDATE if(!can_range && user.can_hold_items() && (user.usable_hands <= 0 || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED))) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 5f67b791e90..1c8e701685d 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -943,7 +943,7 @@ security_level = AIRLOCK_SECURITY_PLASTEEL_O return . if(note) - if(user.CanReach(src)) + if(IsReachableBy(user)) user.visible_message(span_notice("[user] cuts down [note] from [src]."), span_notice("You remove [note] from [src].")) else //telekinesis visible_message(span_notice("[tool] cuts down [note] from [src].")) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 8b3f9f6e5fc..c3b1c0dd2a0 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -586,7 +586,7 @@ SIGNAL_HANDLER - if(!QDELETED(crowbar_owner) && crowbar_owner.CanReach(src)) + if(!QDELETED(crowbar_owner) && IsReachableBy(crowbar_owner)) if(!ismob(crowbar_owner)) return var/mob/living/mob_user = crowbar_owner diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index 3babf33eb9e..2b1fdbf7389 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -351,7 +351,7 @@ * user - The mob unbuckling buckled_mob */ /atom/movable/proc/user_unbuckle_mob(mob/living/buckled_mob, mob/user) - if(!(buckled_mob in buckled_mobs) || !user.CanReach(buckled_mob)) + if(!(buckled_mob in buckled_mobs) || !buckled_mob.IsReachableBy(user)) return var/mob/living/M = unbuckle_mob(buckled_mob) if(M) diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index 84b1e5ad125..cdae1ecbe19 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -99,3 +99,8 @@ /obj/effect/abstract/marker/powernet name = "powernet run marker" var/powernet_owner + +/// Used by RangedReachCheck +/obj/effect/abstract/reach_checker + pass_flags = PASSTABLE + invisibility = INVISIBILITY_ABSTRACT diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index 93baa1d37fc..d98506dff51 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -848,7 +848,7 @@ if(HAS_TRAIT(user, TRAIT_ID_APPRAISER)) . += HAS_TRAIT(src, TRAIT_JOB_FIRST_ID_CARD) ? span_boldnotice("Hmm... yes, this ID was issued from Central Command!") : span_boldnotice("This ID was created in this sector, not by Central Command.") - if(HAS_TRAIT(src, TRAIT_TASTEFULLY_THICK_ID_CARD) && (user.is_holding(src) || (user.CanReach(src) && user.put_in_hands(src, ignore_animation = FALSE)))) + if(HAS_TRAIT(src, TRAIT_TASTEFULLY_THICK_ID_CARD) && (user.is_holding(src) || (IsReachableBy(user) && user.put_in_hands(src, ignore_animation = FALSE)))) ADD_TRAIT(src, TRAIT_NODROP, "psycho") . += span_hypnophrase("Look at that subtle coloring... The tasteful thickness of it. Oh my God, it even has a watermark...") var/sound/slowbeat = sound('sound/effects/health/slowbeat.ogg', repeat = TRUE) @@ -2131,7 +2131,7 @@ /obj/item/card/cardboard/proc/after_input_check(mob/living/user, obj/item/item, input, value) if(!input || (value && input == value)) return FALSE - if(QDELETED(user) || QDELETED(item) || QDELETED(src) || user.incapacitated || !user.is_holding(item) || !user.CanReach(src) || !user.can_write(item)) + if(QDELETED(user) || QDELETED(item) || QDELETED(src) || user.incapacitated || !user.is_holding(item) || !IsReachableBy(user) || !user.can_write(item)) return FALSE return TRUE diff --git a/code/game/objects/items/dyespray.dm b/code/game/objects/items/dyespray.dm index c0c3f8bf614..ceb292a20ad 100644 --- a/code/game/objects/items/dyespray.dm +++ b/code/game/objects/items/dyespray.dm @@ -58,7 +58,7 @@ return var/new_grad_color = input(user, "Choose a secondary hair color:", "Character Preference",human_target.grad_color) as color|null - if(!new_grad_color || !user.can_perform_action(src, NEED_DEXTERITY) || !user.CanReach(target)) + if(!new_grad_color || !user.can_perform_action(src, NEED_DEXTERITY) || !target.IsReachableBy(user)) return to_chat(user, span_notice("You start applying the hair dye...")) diff --git a/code/game/objects/items/food/misc.dm b/code/game/objects/items/food/misc.dm index 97b59fa0475..23e9c5952d4 100644 --- a/code/game/objects/items/food/misc.dm +++ b/code/game/objects/items/food/misc.dm @@ -390,7 +390,7 @@ to_chat(user, span_notice("You stick the rod into the stick of butter.")) user.temporarilyRemoveItemFromInventory(src) var/obj/item/food/butter/on_a_stick/new_item = new(drop_location()) - if (user.CanReach(new_item)) + if (new_item.IsReachableBy(user)) user.put_in_hands(new_item) qdel(src) return TRUE diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index b9a907f8b32..ba18ab8e06d 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -501,7 +501,7 @@ balloon_alert(user, "not enough gauze!") return new /obj/item/stack/sheet/cloth(I.drop_location()) - if(user.CanReach(src)) + if(IsReachableBy(user)) user.visible_message(span_notice("[user] cuts [src] into pieces of cloth with [I]."), \ span_notice("You cut [src] into pieces of cloth with [I]."), \ span_hear("You hear cutting.")) diff --git a/code/game/objects/items/storage/toolboxes/_toolbox.dm b/code/game/objects/items/storage/toolboxes/_toolbox.dm index e0986a941a6..538dc79f373 100644 --- a/code/game/objects/items/storage/toolboxes/_toolbox.dm +++ b/code/game/objects/items/storage/toolboxes/_toolbox.dm @@ -100,7 +100,7 @@ picked_tool.melee_attack_chain(user, interacting_with, modifiers) current_interactions -= 1 - if (QDELETED(picked_tool) || picked_tool.loc != user || !user.CanReach(picked_tool)) + if (QDELETED(picked_tool) || picked_tool.loc != user || !picked_tool.IsReachableBy(user)) current_interactions = 0 return diff --git a/code/game/objects/structures/bedsheet_bin.dm b/code/game/objects/structures/bedsheet_bin.dm index 01536a2518a..6e5a1528d2a 100644 --- a/code/game/objects/structures/bedsheet_bin.dm +++ b/code/game/objects/structures/bedsheet_bin.dm @@ -92,7 +92,7 @@ LINEN BINS return ITEM_INTERACT_SUCCESS /obj/item/bedsheet/attack_self(mob/living/user) - if(!user.CanReach(src)) //No telekinetic grabbing. + if(!IsReachableBy(user)) //No telekinetic grabbing. return if(user.body_position != LYING_DOWN) return diff --git a/code/game/objects/structures/mystery_box.dm b/code/game/objects/structures/mystery_box.dm index f01c2f3911a..3b3a4d9a9d9 100644 --- a/code/game/objects/structures/mystery_box.dm +++ b/code/game/objects/structures/mystery_box.dm @@ -174,13 +174,15 @@ GLOBAL_LIST_INIT(mystery_fishing, list( /obj/structure/mystery_box/proc/generate_valid_types() valid_types = get_sane_item_types(selectable_base_type) +/obj/structure/mystery_box/IsContainedAtomAccessible(atom/contained, atom/movable/user) + return TRUE + /// The box has been activated, play the sound and spawn the prop item /obj/structure/mystery_box/proc/activate(mob/living/user) box_state = MYSTERY_BOX_CHOOSING update_icon_state() presented_item = new(src) presented_item.vis_flags = VIS_INHERIT_PLANE - presented_item.flags_1 |= IS_ONTOP_1 vis_contents += presented_item presented_item.start_animation(src) current_sound_channel = SSsounds.reserve_sound_channel(src) diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index eff18ba1fff..6c14103cd73 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -1145,7 +1145,7 @@ tool.play_tool_sound(src, 50) balloon_alert(user, "mask detached") UnregisterSignal(breath_mask, list(COMSIG_MOVABLE_MOVED, COMSIG_ITEM_DROPPED)) - if (user.CanReach(breath_mask)) + if (breath_mask.IsReachableBy(user)) user.put_in_hands(breath_mask) breath_mask = null update_appearance() @@ -1160,7 +1160,7 @@ air_tank.forceMove(drop_location()) tool.play_tool_sound(src, 50) balloon_alert(user, "tank detached") - if (user.CanReach(air_tank)) + if (air_tank.IsReachableBy(user)) user.put_in_hands(air_tank) if (patient?.external && patient.external == air_tank) patient.close_externals() @@ -1192,7 +1192,7 @@ . += span_notice("There's a port for a breathing mask tube on its side.") /obj/structure/table/optable/proc/detach_mask(mob/living/user) - if (!istype(user) || !user.CanReach(src) || !user.can_interact_with(src)) + if (!istype(user) || !IsReachableBy(user) || !user.can_interact_with(src)) return FALSE if (!breath_mask) @@ -1208,7 +1208,7 @@ return TRUE /obj/structure/table/optable/mouse_drop_dragged(atom/over, mob/living/user, src_location, over_location, params) - if (over != patient || !istype(user) || !user.CanReach(src) || !user.can_interact_with(src)) + if (over != patient || !istype(user) || !IsReachableBy(user) || !user.can_interact_with(src)) return if (!air_tank) diff --git a/code/game/objects/structures/water_structures/toilet.dm b/code/game/objects/structures/water_structures/toilet.dm index 7738a0f6473..67d24d4007a 100644 --- a/code/game/objects/structures/water_structures/toilet.dm +++ b/code/game/objects/structures/water_structures/toilet.dm @@ -165,7 +165,7 @@ grabbed_mob.adjustBruteLoss(5) return - if(cistern_open && !cover_open && user.CanReach(src)) + if(cistern_open && !cover_open && IsReachableBy(user)) if(!LAZYLEN(cistern_items)) to_chat(user, span_notice("The cistern is empty.")) return diff --git a/code/modules/antagonists/heretic/magic/flesh_surgery.dm b/code/modules/antagonists/heretic/magic/flesh_surgery.dm index 26e21f54ae4..4b0aa96fbc7 100644 --- a/code/modules/antagonists/heretic/magic/flesh_surgery.dm +++ b/code/modules/antagonists/heretic/magic/flesh_surgery.dm @@ -126,7 +126,7 @@ /datum/action/cooldown/spell/touch/flesh_surgery/proc/register_held_organ(obj/item/organ/new_held_organ, obj/item/melee/touch_attack/hand) hand.vis_contents += new_held_organ held_organ = new_held_organ - new_held_organ.flags_1 |= IS_ONTOP_1 + ADD_TRAIT(new_held_organ, TRAIT_SKIP_BASIC_REACH_CHECK, ref(src)) new_held_organ.vis_flags |= VIS_INHERIT_PLANE RegisterSignal(new_held_organ, COMSIG_MOVABLE_MOVED, PROC_REF(unregister_held_organ)) RegisterSignal(new_held_organ, COMSIG_QDELETING, PROC_REF(unregister_held_organ)) @@ -139,7 +139,7 @@ /datum/action/cooldown/spell/touch/flesh_surgery/proc/unregister_held_organ(obj/item/organ/removed_organ) LAZYREMOVE(attached_hand.vis_contents, removed_organ) held_organ = null - removed_organ.flags_1 &= ~IS_ONTOP_1 + REMOVE_TRAIT(removed_organ, TRAIT_SKIP_BASIC_REACH_CHECK, ref(src)) removed_organ.vis_flags &= ~VIS_INHERIT_PLANE UnregisterSignal(removed_organ, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING)) // Reset item offsets diff --git a/code/modules/antagonists/ninja/energy_katana.dm b/code/modules/antagonists/ninja/energy_katana.dm index 1182bd56873..a03dfa66fd9 100644 --- a/code/modules/antagonists/ninja/energy_katana.dm +++ b/code/modules/antagonists/ninja/energy_katana.dm @@ -88,7 +88,7 @@ var/obj/item/sword = target if(length(line) <= 1 || !teleport(user, line[length(line) - 1])) // teleports to the second last turf, should be adjacent to the target return - if(!user.CanReach(stabbing, target)) + if(!stabbing.IsReachableBy(user, sword?.reach)) return sword.melee_attack_chain(user, stabbing) if(prob(5) && check_holidays(APRIL_FOOLS)) diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm index 79798ec1f5e..84b65dbd888 100644 --- a/code/modules/antagonists/wizard/equipment/soulstone.dm +++ b/code/modules/antagonists/wizard/equipment/soulstone.dm @@ -417,7 +417,7 @@ /obj/item/soulstone/proc/check_menu(mob/user, obj/structure/constructshell/shell) if(!istype(user)) return FALSE - if(user.incapacitated || !user.is_holding(src) || !user.CanReach(shell, src)) + if(user.incapacitated || !user.is_holding(src) || !shell.IsReachableBy(user, reach)) return FALSE return TRUE @@ -489,7 +489,7 @@ /// Called when a ghost is chosen to become a shade. /obj/item/soulstone/proc/on_poll_concluded(mob/living/master, mob/living/victim, mob/dead/observer/ghost) - if(isnull(victim) || master.incapacitated || !master.is_holding(src) || !master.CanReach(victim, src)) + if(isnull(victim) || master.incapacitated || !master.is_holding(src) || !victim.IsReachableBy(master, reach)) return FALSE if(isnull(ghost?.client)) to_chat(master, span_danger("There were no spirits willing to become a shade.")) diff --git a/code/modules/art/paintings.dm b/code/modules/art/paintings.dm index f94f0011f0b..c0e1bb5b964 100644 --- a/code/modules/art/paintings.dm +++ b/code/modules/art/paintings.dm @@ -360,7 +360,7 @@ /obj/item/canvas/proc/can_select_frame(mob/user) if(!istype(loc, /obj/structure/sign/painting)) return FALSE - if(!user?.CanReach(loc) || IS_DEAD_OR_INCAP(user)) + if(!loc.IsReachableBy(user) || IS_DEAD_OR_INCAP(user)) return FALSE if(!last_patron || !IS_WEAKREF_OF(user?.mind, last_patron)) return FALSE @@ -930,7 +930,7 @@ var/our_dir = get_dir(user, on_wall) var/check_dir = our_dir & (EAST|WEST) ? NORTH : EAST var/turf/closed/wall/second_wall = get_step(on_wall, check_dir) - if(!istype(second_wall) || !user.CanReach(second_wall)) + if(!istype(second_wall) || !second_wall.IsReachableBy(user)) to_chat(user, span_warning("You need a reachable wall to the [check_dir == EAST ? "right" : "left"] of this one to mount this frame!")) return FALSE if(check_wall_item(second_wall, our_dir, wall_external)) diff --git a/code/modules/fishing/fish_mount.dm b/code/modules/fishing/fish_mount.dm index 903a08801f4..fd9876c57a3 100644 --- a/code/modules/fishing/fish_mount.dm +++ b/code/modules/fishing/fish_mount.dm @@ -103,6 +103,9 @@ playsound(loc, 'sound/machines/click.ogg', 30, TRUE) return ITEM_INTERACT_SUCCESS +/obj/structure/fish_mount/IsContainedAtomAccessible(atom/contained, atom/movable/user) + return TRUE + /obj/structure/fish_mount/proc/add_fish(obj/item/fish/fish, from_persistence = FALSE, catcher) if(QDELETED(src)) // don't ever try to add a fish to one of these that's already been deleted - and get rid of the one that was created qdel(fish) @@ -113,7 +116,6 @@ mounted_fish.forceMove(loc) fish.forceMove(src) vis_contents += fish - fish.flags_1 |= IS_ONTOP_1 fish.vis_flags |= (VIS_INHERIT_PLANE|VIS_INHERIT_LAYER) fish.interaction_flags_item &= ~INTERACT_ITEM_ATTACK_HAND_PICKUP fish.obj_flags &= ~UNIQUE_RENAME @@ -195,7 +197,6 @@ if(!QDELETED(mounted_fish) && (!persistence_loaded_fish || roll_for_safe_removal())) rotate_fish(0, dir) UnregisterSignal(mounted_fish, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_ATOM_ATTACK_PAW)) - mounted_fish.flags_1 &= ~IS_ONTOP_1 mounted_fish.vis_flags &= ~(VIS_INHERIT_PLANE|VIS_INHERIT_LAYER) mounted_fish.interaction_flags_item |= INTERACT_ITEM_ATTACK_HAND_PICKUP mounted_fish.obj_flags |= UNIQUE_RENAME diff --git a/code/modules/fishing/fishing_minigame.dm b/code/modules/fishing/fishing_minigame.dm index 923c496371a..5d465b6e7ef 100644 --- a/code/modules/fishing/fishing_minigame.dm +++ b/code/modules/fishing/fishing_minigame.dm @@ -284,7 +284,7 @@ GLOBAL_LIST_EMPTY(fishing_challenges_by_user) /datum/fishing_challenge/proc/on_float_or_user_move(datum/source) SIGNAL_HANDLER - if(!user.CanReach(location)) + if(!location.IsReachableBy(user)) user.balloon_alert(user, "too far!") interrupt() diff --git a/code/modules/food_and_drinks/machinery/griddle.dm b/code/modules/food_and_drinks/machinery/griddle.dm index 5d0beed7ee0..83dcb2ae873 100644 --- a/code/modules/food_and_drinks/machinery/griddle.dm +++ b/code/modules/food_and_drinks/machinery/griddle.dm @@ -41,6 +41,9 @@ return variant = rand(1,3) +/obj/machinery/griddle/IsContainedAtomAccessible(atom/contained, atom/movable/user) + return ..() || (contained in griddled_objects) + /obj/machinery/griddle/proc/on_expose_reagent(atom/parent_atom, datum/reagent/exposing_reagent, reac_volume, methods) SIGNAL_HANDLER @@ -141,7 +144,6 @@ /obj/machinery/griddle/proc/AddToGrill(obj/item/item_to_grill, mob/user) vis_contents += item_to_grill griddled_objects += item_to_grill - item_to_grill.flags_1 |= IS_ONTOP_1 item_to_grill.vis_flags |= VIS_INHERIT_PLANE SEND_SIGNAL(item_to_grill, COMSIG_ITEM_GRILL_PLACED, user) @@ -155,7 +157,6 @@ /obj/machinery/griddle/proc/ItemRemovedFromGrill(obj/item/ungrill) SIGNAL_HANDLER - ungrill.flags_1 &= ~IS_ONTOP_1 ungrill.vis_flags &= ~VIS_INHERIT_PLANE griddled_objects -= ungrill vis_contents -= ungrill diff --git a/code/modules/food_and_drinks/machinery/oven.dm b/code/modules/food_and_drinks/machinery/oven.dm index a0d0ebad417..a94ca674038 100644 --- a/code/modules/food_and_drinks/machinery/oven.dm +++ b/code/modules/food_and_drinks/machinery/oven.dm @@ -46,6 +46,9 @@ remove_shared_particles(particle_type) return ..() +/obj/machinery/oven/IsContainedAtomAccessible(atom/contained, atom/movable/user) + return ..() || istype(contained, /obj/item/plate/oven_tray) + /// Used to determine if the oven appears active and cooking, or offline. /obj/machinery/oven/proc/appears_active() return !open && length(used_tray?.contents) && !(machine_stat & (BROKEN|NOPOWER)) @@ -127,7 +130,6 @@ if(!open) oven_tray.vis_flags |= VIS_HIDE vis_contents += oven_tray - oven_tray.flags_1 |= IS_ONTOP_1 oven_tray.vis_flags |= VIS_INHERIT_PLANE oven_tray.pixel_y = OVEN_TRAY_Y_OFFSET oven_tray.pixel_x = OVEN_TRAY_X_OFFSET @@ -144,7 +146,6 @@ /obj/machinery/oven/proc/tray_removed_from_oven(obj/item/oven_tray) SIGNAL_HANDLER - oven_tray.flags_1 &= ~IS_ONTOP_1 oven_tray.vis_flags &= ~VIS_INHERIT_PLANE vis_contents -= oven_tray used_tray = null diff --git a/code/modules/food_and_drinks/machinery/processor.dm b/code/modules/food_and_drinks/machinery/processor.dm index 859628abc98..eda53ab1777 100644 --- a/code/modules/food_and_drinks/machinery/processor.dm +++ b/code/modules/food_and_drinks/machinery/processor.dm @@ -232,7 +232,7 @@ /// We pick up a number of slimes equal to the rating of the matter bin var/slimes_picked = 0 for(var/mob/living/basic/slime/slime in range(1,src)) - if(!CanReach(slime)) //don't take slimes behind glass panes or somesuch; also makes it ignore slimes inside the processor + if(!slime.IsReachableBy(src)) //don't take slimes behind glass panes or somesuch; also makes it ignore slimes inside the processor continue if(slime.stat) var/datum/food_processor_process/recipe = PROCESSOR_SELECT_RECIPE(slime) diff --git a/code/modules/food_and_drinks/machinery/stove_component.dm b/code/modules/food_and_drinks/machinery/stove_component.dm index 8db59dc2739..71e80474c63 100644 --- a/code/modules/food_and_drinks/machinery/stove_component.dm +++ b/code/modules/food_and_drinks/machinery/stove_component.dm @@ -217,7 +217,7 @@ /datum/component/stove/proc/add_container(obj/item/new_container, mob/user) var/obj/real_parent = parent real_parent.vis_contents += new_container - new_container.flags_1 |= IS_ONTOP_1 + ADD_TRAIT(new_container, TRAIT_SKIP_BASIC_REACH_CHECK, ref(src)) new_container.vis_flags |= VIS_INHERIT_PLANE container = new_container @@ -230,7 +230,7 @@ /datum/component/stove/proc/remove_container() var/obj/real_parent = parent - container.flags_1 &= ~IS_ONTOP_1 + REMOVE_TRAIT(container, TRAIT_SKIP_BASIC_REACH_CHECK, ref(src)) container.vis_flags &= ~VIS_INHERIT_PLANE real_parent.vis_contents -= container diff --git a/code/modules/food_and_drinks/plate.dm b/code/modules/food_and_drinks/plate.dm index 225e8d86865..ff210436cc1 100644 --- a/code/modules/food_and_drinks/plate.dm +++ b/code/modules/food_and_drinks/plate.dm @@ -53,10 +53,12 @@ target.attackby(object_to_eat, user) return TRUE //No normal attack +/obj/item/plate/IsContainedAtomAccessible(atom/contained, atom/movable/user) + return TRUE + ///This proc adds the food to viscontents and makes sure it can deregister if this changes. /obj/item/plate/proc/AddToPlate(obj/item/item_to_plate) vis_contents += item_to_plate - item_to_plate.flags_1 |= IS_ONTOP_1 item_to_plate.vis_flags |= VIS_INHERIT_PLANE RegisterSignal(item_to_plate, COMSIG_MOVABLE_MOVED, PROC_REF(ItemMoved)) RegisterSignal(item_to_plate, COMSIG_QDELETING, PROC_REF(ItemMoved)) @@ -72,7 +74,6 @@ ///This proc cleans up any signals on the item when it is removed from a plate, and ensures it has the correct state again. /obj/item/plate/proc/ItemRemovedFromPlate(obj/item/removed_item) - removed_item.flags_1 &= ~IS_ONTOP_1 removed_item.vis_flags &= ~VIS_INHERIT_PLANE vis_contents -= removed_item UnregisterSignal(removed_item, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING)) diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm index 71a14d8a97d..980ebc4ab27 100644 --- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm +++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm @@ -527,7 +527,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999)) /obj/item/analyzer/hilbertsanalyzer/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) if(!istype(interacting_with, /obj/item/hilbertshotel)) return ..() - if(!user.CanReach(interacting_with)) + if(!interacting_with.IsReachableBy(user)) to_chat(user, span_warning("It's to far away to scan!")) return ITEM_INTERACT_BLOCKING var/obj/item/hilbertshotel/sphere = interacting_with diff --git a/code/modules/mining/equipment/grapple_gun.dm b/code/modules/mining/equipment/grapple_gun.dm index 99144d84867..5355fe6bbb6 100644 --- a/code/modules/mining/equipment/grapple_gun.dm +++ b/code/modules/mining/equipment/grapple_gun.dm @@ -61,7 +61,7 @@ attacked_atom = singular_turf break - if(user.CanReach(attacked_atom)) + if(attacked_atom.IsReachableBy(user)) return ITEM_INTERACT_BLOCKING var/atom/bullet = fire_projectile(/obj/projectile/grapple_hook, attacked_atom, 'sound/items/weapons/zipline_fire.ogg') diff --git a/code/modules/mob/living/basic/bots/dedbot.dm b/code/modules/mob/living/basic/bots/dedbot.dm index 07d81bcda83..607d788b430 100644 --- a/code/modules/mob/living/basic/bots/dedbot.dm +++ b/code/modules/mob/living/basic/bots/dedbot.dm @@ -109,7 +109,7 @@ /datum/action/cooldown/mob_cooldown/exenterate/proc/slash_em(atom/caster) for(var/mob/living/victim in range(ability_range, caster)) - if(faction_check(victim.faction, immune_factions) && owner.CanReach(victim)) + if(faction_check(victim.faction, immune_factions) && victim.IsReachableBy(owner)) continue to_chat(caster, span_warning("You slice [victim]!")) to_chat(victim, span_warning("You are cut by [caster]'s blades!")) diff --git a/code/modules/mob/living/basic/bots/medbot/medbot.dm b/code/modules/mob/living/basic/bots/medbot/medbot.dm index 7b5bf6c5869..e6b814b476d 100644 --- a/code/modules/mob/living/basic/bots/medbot/medbot.dm +++ b/code/modules/mob/living/basic/bots/medbot/medbot.dm @@ -366,7 +366,7 @@ update_bot_mode(new_mode = BOT_IDLE) return - if(CanReach(patient)) + if(patient.IsReachableBy(src)) melee_attack(patient) /datum/id_trim/medibot diff --git a/code/modules/mob/living/basic/clown/clown.dm b/code/modules/mob/living/basic/clown/clown.dm index 601d82495ae..c4544b8724c 100644 --- a/code/modules/mob/living/basic/clown/clown.dm +++ b/code/modules/mob/living/basic/clown/clown.dm @@ -597,7 +597,7 @@ . = ..() var/list/reachable_turfs = list() for(var/turf/adjacent_turf in RANGE_TURFS(1, owner.loc)) - if(adjacent_turf == owner.loc || !owner.CanReach(adjacent_turf) || !isopenturf(adjacent_turf)) + if(adjacent_turf == owner.loc || !adjacent_turf.IsReachableBy(owner) || !isopenturf(adjacent_turf)) continue reachable_turfs += adjacent_turf @@ -625,10 +625,10 @@ /datum/action/cooldown/exquisite_bunch/Trigger(mob/clicker, trigger_flags, atom/target) if(activating) return - var/bunch_turf = get_step(owner.loc, owner.dir) + var/atom/bunch_turf = get_step(owner.loc, owner.dir) if(!bunch_turf) return - if(!owner.CanReach(bunch_turf) || !isopenturf(bunch_turf)) + if(!bunch_turf.IsReachableBy(owner) || !isopenturf(bunch_turf)) owner.balloon_alert(owner, "can't do that here!") return activating = TRUE diff --git a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm index 68a31816fd4..63842f05ef5 100644 --- a/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm +++ b/code/modules/mob/living/basic/lavaland/goliath/goliath_ai.dm @@ -112,7 +112,7 @@ /datum/ai_behavior/goliath_dig/perform(seconds_per_tick, datum/ai_controller/controller, target_key) var/turf/target_turf = controller.blackboard[target_key] var/mob/living/basic/basic_mob = controller.pawn - if(!basic_mob.CanReach(target_turf)) + if(!target_turf.IsReachableBy(basic_mob)) return AI_BEHAVIOR_DELAY basic_mob.melee_attack(target_turf) return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm b/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm index 44f84da8fa7..ae9fd3d3de2 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook_abilities.dm @@ -37,7 +37,7 @@ var/times_to_attack = 4 /datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/Activate(atom/target) - if(owner.CanReach(target)) + if(target.IsReachableBy(owner)) attack_combo(target) StartCooldown() return TRUE @@ -74,14 +74,14 @@ owner.throw_at(target = final_turf, range = 7, speed = 1, spin = FALSE, callback = CALLBACK(src, PROC_REF(attack_combo), target)) /datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/proc/attack_combo(atom/target) - if(!owner.CanReach(target)) + if(!target.IsReachableBy(owner)) return FALSE for(var/i in 0 to (times_to_attack - 1)) addtimer(CALLBACK(src, PROC_REF(attack_target), target), i * attack_interval) /datum/action/cooldown/mob_cooldown/mook_ability/mook_leap/proc/attack_target(atom/target) - if(!owner.CanReach(target) || owner.stat == DEAD) + if(!target.IsReachableBy(owner) || owner.stat == DEAD) return var/mob/living/basic/basic_owner = owner basic_owner.melee_attack(target, ignore_cooldown = TRUE) diff --git a/code/modules/mob/living/basic/pets/dog/corgi.dm b/code/modules/mob/living/basic/pets/dog/corgi.dm index b2bd8e47976..f0c7a1d5f54 100644 --- a/code/modules/mob/living/basic/pets/dog/corgi.dm +++ b/code/modules/mob/living/basic/pets/dog/corgi.dm @@ -292,7 +292,7 @@ possible_headwear += item if(!length(possible_headwear)) for(var/obj/item/item in orange(1)) - if(ispath(item.dog_fashion, /datum/dog_fashion/head) && CanReach(item)) + if(ispath(item.dog_fashion, /datum/dog_fashion/head) && item.IsReachableBy(src)) possible_headwear += item if(!length(possible_headwear)) return diff --git a/code/modules/mob/living/basic/ruin_defender/flesh.dm b/code/modules/mob/living/basic/ruin_defender/flesh.dm index 610db57f1c0..918ea15206a 100644 --- a/code/modules/mob/living/basic/ruin_defender/flesh.dm +++ b/code/modules/mob/living/basic/ruin_defender/flesh.dm @@ -85,7 +85,7 @@ for(var/atom/movable/movable in orange(victim, 1)) if(movable == victim) continue - if(!victim.CanReach(movable) || movable.invisibility > victim.see_invisible) + if(!movable.IsReachableBy(victim) || movable.invisibility > victim.see_invisible) continue candidates += movable if(!length(candidates)) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 01662d6287d..463652877f4 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1055,7 +1055,7 @@ if(active_storage) var/storage_is_important_recurisve = (active_storage.parent in important_recursive_contents?[RECURSIVE_CONTENTS_ACTIVE_STORAGE]) - var/can_reach_active_storage = CanReach(active_storage.parent, view_only = TRUE) + var/can_reach_active_storage = active_storage.parent.IsReachableBy(src) if(!storage_is_important_recurisve && !can_reach_active_storage) active_storage.hide_contents(src) @@ -1375,7 +1375,7 @@ to_chat(src, span_warning("Your holochasis does not allow you to do this!")) return FALSE - if(!(action_bitflags & BYPASS_ADJACENCY) && ((action_bitflags & NOT_INSIDE_TARGET) || !recursive_loc_check(src, target)) && !CanReach(target)) + if(!(action_bitflags & BYPASS_ADJACENCY) && ((action_bitflags & NOT_INSIDE_TARGET) || !recursive_loc_check(src, target)) && !target.IsReachableBy(src)) if(HAS_SILICON_ACCESS(src) && !ispAI(src)) if(!(action_bitflags & ALLOW_SILICON_REACH)) // silicons can ignore range checks (except pAIs) if(!(action_bitflags & SILENT_ADJACENCY)) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index e4dc601bc90..cc8934a755a 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -248,3 +248,6 @@ /// First element is the current martial art - any other elements are "saved" for if they unlearn the first one /// Reference handling is done by the martial arts themselves var/list/datum/martial_art/martial_arts + + /// how many tiles can this mob reach with their hands? 1 tile is adjacent. + var/reach_length = 1 diff --git a/code/modules/mob/living/living_item_handling.dm b/code/modules/mob/living/living_item_handling.dm index 755f5d54466..6363fa53bed 100644 --- a/code/modules/mob/living/living_item_handling.dm +++ b/code/modules/mob/living/living_item_handling.dm @@ -158,7 +158,7 @@ to_chat(src, span_warning("[offered.p_Theyre()] unable to take anything in [offered.p_their()] current state!")) return - if(!CanReach(offered)) + if(!offered.IsReachableBy(src)) to_chat(src, span_warning("You have to be beside [offered.p_them()]!")) return diff --git a/code/modules/mod/modules/modules_engineering.dm b/code/modules/mod/modules/modules_engineering.dm index 5838e2391cd..12395591694 100644 --- a/code/modules/mod/modules/modules_engineering.dm +++ b/code/modules/mod/modules/modules_engineering.dm @@ -266,7 +266,7 @@ return ITEM_INTERACT_BLOCKING /obj/item/tether_anchor/attack_hand_secondary(mob/user, list/modifiers) - if (!can_interact(user) || !user.CanReach(src) || !isturf(loc)) + if (!can_interact(user) || !IsReachableBy(user) || !isturf(loc)) return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN if(HAS_TRAIT_FROM(user, TRAIT_TETHER_ATTACHED, REF(src))) @@ -289,10 +289,10 @@ reset_pixel_pos = FALSE /obj/item/tether_anchor/mouse_drop_receive(atom/target, mob/user, params) - if (!can_interact(user) || !user.CanReach(src) || !isturf(loc)) + if (!can_interact(user) || !IsReachableBy(user) || !isturf(loc)) return - if (!isliving(target) || !target.CanReach(src)) + if (!isliving(target) || !IsReachableBy(target)) return if(HAS_TRAIT_FROM(target, TRAIT_TETHER_ATTACHED, REF(src))) diff --git a/code/modules/point/point.dm b/code/modules/point/point.dm index adb539ad3b9..e3ef14d2db9 100644 --- a/code/modules/point/point.dm +++ b/code/modules/point/point.dm @@ -114,7 +114,7 @@ if(client) //Clientless mobs can just go ahead and point if(ismovable(pointing_at)) var/atom/movable/pointed_movable = pointing_at - if(pointed_movable.flags_1 & IS_ONTOP_1) + if(HAS_TRAIT(pointed_movable, TRAIT_SKIP_BASIC_REACH_CHECK) || pointing_at.loc.IsContainedAtomAccessible(pointing_at, src)) pointing_at = pointed_movable.loc if(!(pointing_at in view(client.view, src))) diff --git a/code/modules/shuttle/mobile_port/variants/custom/blueprints.dm b/code/modules/shuttle/mobile_port/variants/custom/blueprints.dm index 2f3320792bf..a3af891a65e 100644 --- a/code/modules/shuttle/mobile_port/variants/custom/blueprints.dm +++ b/code/modules/shuttle/mobile_port/variants/custom/blueprints.dm @@ -203,7 +203,7 @@ return new_name = apply_text_macros(new_name) var/obj/item/hitting_implement = (locate(/obj/item/reagent_containers/cup/glass/bottle) in user.held_items) || user.get_item_for_held_index(hand) - if(!user.CanReach(attacked, hitting_implement)) + if(!attacked.IsReachableBy(user, hitting_implement.reach)) user.balloon_alert(user, "out of range!") return var/obj/item/reagent_containers/cup/glass/bottle/bottle = hitting_implement diff --git a/code/modules/shuttle/mobile_port/variants/emergency/emergency_console.dm b/code/modules/shuttle/mobile_port/variants/emergency/emergency_console.dm index ed88724c6fe..ff070188da6 100644 --- a/code/modules/shuttle/mobile_port/variants/emergency/emergency_console.dm +++ b/code/modules/shuttle/mobile_port/variants/emergency/emergency_console.dm @@ -212,7 +212,7 @@ return CLICK_ACTION_SUCCESS /obj/machinery/computer/emergency_shuttle/proc/attempt_hijack_stage(mob/living/user) - if(!user.CanReach(src)) + if(!IsReachableBy(user)) return if(HAS_TRAIT(user, TRAIT_HANDS_BLOCKED)) to_chat(user, span_warning("You need your hands free before you can manipulate [src].")) diff --git a/code/modules/vending/vendor/inventory.dm b/code/modules/vending/vendor/inventory.dm index 8955e1002ab..ded975a2430 100644 --- a/code/modules/vending/vendor/inventory.dm +++ b/code/modules/vending/vendor/inventory.dm @@ -204,7 +204,7 @@ if(greyscale_colors) vended_item.set_greyscale(colors=greyscale_colors) - if(user.CanReach(src) && user.put_in_hands(vended_item)) + if(IsReachableBy(user) && user.put_in_hands(vended_item)) to_chat(user, span_notice("You take [item_record.name] out of the slot.")) vended_item.do_pickup_animation(user, src) else