Skip to content

Commit 3f40954

Browse files
committed
CanReach rewrite
1 parent 20d5ab5 commit 3f40954

File tree

29 files changed

+95
-93
lines changed

29 files changed

+95
-93
lines changed

code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@
6060
#define COMSIG_ATOM_CONTENTS_DEL "atom_contents_del"
6161
///from base of atom/has_gravity(): (turf/location, list/forced_gravities)
6262
#define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity"
63-
///from internal loop in atom/movable/proc/CanReach(): (list/next)
64-
#define COMSIG_ATOM_CANREACH "atom_can_reach"
65-
#define COMPONENT_ALLOW_REACH (1<<0)
6663
///for when an atom has been created through processing (atom/original_atom, list/chosen_processing_option)
6764
#define COMSIG_ATOM_CREATEDBY_PROCESSING "atom_createdby_processing"
6865
///when an atom is processed (mob/living/user, obj/item/I, list/atom/results)

code/__DEFINES/inventory.dm

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616

1717
//Inventory depth: limits how many nested storage items you can access directly.
1818
//1: stuff in mob, 2: stuff in backpack, 3: stuff in box in backpack, etc
19-
#define INVENTORY_DEPTH 3
20-
#define STORAGE_VIEW_DEPTH 2
19+
///
20+
#define REACH_DEPTH_SELF 1
21+
/// A storage depth ontop of SELF. REACH_DEPTH_STORAGE(1) would allow an item inside of a backpack you are carrying.
22+
#define REACH_DEPTH_STORAGE(level) (level + REACH_DEPTH_SELF)
23+
/// An arbitrary depth value for keeping storage UIs open on Move().
24+
#define REACH_DEPTH_STORAGE_SANITY 5
2125

2226
//ITEM INVENTORY SLOT BITMASKS
2327
/// Suit slot (armors, costumes, space suits, etc.)

code/_onclick/click.dm

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@
169169
UnarmedAttack(item_atom, TRUE, modifiers)
170170

171171
//Standard reach turf to turf or reaching inside storage
172-
if(CanReach(A,W))
172+
if(A.IsReachableBy(src, W))
173173
if(W)
174174
W.melee_attack_chain(src, A, params)
175175
else
@@ -212,49 +212,49 @@
212212
return FALSE
213213

214214
/**
215-
* A backwards depth-limited breadth-first-search to see if the target is
216-
* logically "in" anything adjacent to us.
215+
* Returns TRUE if a movable can "Reach" this atom. This is defined as adjacency
216+
*
217+
* This is used for crafting by hitting the floor with items.
218+
* The inital use case is glass sheets breaking in to shards when the floor is hit.
219+
* Args:
220+
* * user: The movable trying to reach us.
221+
* * tool: An optional item being used.
222+
* * depth: How deep nested inside of an atom contents stack an object can be.
223+
* * direct_access: Do not override. Used for recursion.
217224
*/
218-
/atom/movable/proc/CanReach(atom/ultimate_target, obj/item/tool, view_only = FALSE)
219-
var/list/direct_access = DirectAccess()
220-
var/depth = 1 + (view_only ? STORAGE_VIEW_DEPTH : INVENTORY_DEPTH)
221-
222-
var/list/closed = list()
223-
var/list/checking = list(ultimate_target)
224-
225-
while (checking.len && depth > 0)
226-
var/list/next = list()
227-
--depth
228-
229-
for(var/atom/target in checking) // will filter out nulls
230-
if(closed[target] || isarea(target)) // avoid infinity situations
231-
continue
232-
233-
// Before we check CanBeReached() (adjacency), let's do some less expensive checks to see if we need to bother.
234-
// A target that is not a turf or on a turf is unclickable, exceptions:
235-
// * The object is directly accessible to the user (DirectAccess())
236-
// * The object has the ALWAYS_CLICKABLE trait.
237-
// * The object is inside of an atom with an associated atom_storage datum.
238-
// If any of the above are true, we THEN check adjacency.
239-
if(isturf(target) || isturf(target.loc) || (target in direct_access) || (HAS_TRAIT(target, TRAIT_SKIP_BASIC_REACH_CHECK)) || target.loc?.atom_storage)
240-
if(target.CanBeReached(src, tool))
241-
return TRUE
225+
/atom/proc/IsReachableBy(atom/movable/user, obj/item/tool, depth = INFINITY, direct_access = user.DirectAccess())
226+
SHOULD_NOT_OVERRIDE(TRUE)
242227

243-
closed[target] = TRUE
228+
if(isnull(user))
229+
return FALSE
244230

245-
if (!target.loc)
246-
continue
231+
if(src in direct_access)
232+
return TRUE
247233

248-
if(target.loc.atom_storage)
249-
next += target.loc
234+
if(isturf(loc) || isturf(src) || HAS_TRAIT(src, TRAIT_SKIP_BASIC_REACH_CHECK))
235+
if(CheckReachableAdjacency(user, tool))
236+
return TRUE
250237

251-
checking = next
252-
return FALSE
238+
depth--
239+
if(depth <= 0)
240+
return FALSE
253241

254-
/// Reciprocal function for CanReach().
255-
/atom/proc/CanBeReached(atom/movable/reacher, obj/item/tool)
242+
if(isnull(loc) || isarea(loc) || !loc.IsContainedAtomAccessible(src))
243+
return FALSE
244+
245+
return loc.IsReachableBy(user, tool, depth, direct_access)
246+
247+
/// Checks if a reacher is adjacent to us.
248+
/atom/proc/CheckReachableAdjacency(atom/movable/reacher, obj/item/tool)
256249
return reacher.Adjacent(src) || (tool && CheckToolReach(reacher, src, tool.reach))
257250

251+
/// Returns TRUE if an atom contained within our contents is reachable.
252+
/atom/proc/IsContainedAtomAccessible(atom/contained)
253+
return TRUE
254+
255+
/atom/movable/IsContainedAtomAccessible(atom/contained)
256+
return !!atom_storage
257+
258258
/atom/movable/proc/DirectAccess()
259259
return list(src, loc)
260260

@@ -284,7 +284,7 @@
284284
dummy.invisibility = INVISIBILITY_ABSTRACT
285285
for(var/i in 1 to reach) //Limit it to that many tries
286286
var/turf/T = get_step(dummy, get_dir(dummy, there))
287-
if(dummy.CanReach(there))
287+
if(there.IsReachableBy(dummy))
288288
qdel(dummy)
289289
return TRUE
290290
if(!dummy.Move(T)) //we're blocked!
@@ -388,7 +388,7 @@
388388
return FALSE
389389

390390
/mob/living/CtrlClick(mob/user, list/params)
391-
if(!isliving(user) || !user.CanReach(src) || user.incapacitated())
391+
if(!isliving(user) || !IsReachableBy(user) || user.incapacitated())
392392
return ..()
393393

394394
if(world.time < user.next_move)
@@ -404,7 +404,7 @@
404404

405405
/mob/living/carbon/human/CtrlClick(mob/user, list/params)
406406

407-
if(!ishuman(user) || !user.CanReach(src) || user.incapacitated())
407+
if(!ishuman(user) || !IsReachableBy(user) || user.incapacitated())
408408
return ..()
409409

410410
if(world.time < user.next_move)

code/_onclick/hud/screen_objects.dm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@
340340
if(ismecha(user.loc)) // stops inventory actions in a mech
341341
return TRUE
342342

343-
if(!user.CanReach(dropping))
343+
if(!dropping.IsReachableBy(user))
344344
return TRUE
345345

346346
var/obj/item/I = dropping
@@ -588,7 +588,7 @@
588588
if(ismecha(user.loc)) // stops inventory actions in a mech
589589
return TRUE
590590

591-
if(!user.CanReach(dropping))
591+
if(!dropping.IsReachableBy(user))
592592
return TRUE
593593

594594
var/obj/item/I = dropping

code/datums/ai/_ai_behavior.dm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
if(atom_basic_score < best_score)
4343
continue
4444

45-
if(pawn.CanReach(A))
45+
if(A.IsReachableBy(pawn))
4646
best_score = atom_basic_score
4747
ideal_atom = A
4848
continue

code/datums/ai/_ai_controller.dm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ multiple modular subtrees with behaviors
180180

181181
///Stops pawns from performing such actions that should require the target to be adjacent.
182182
var/atom/movable/moving_pawn = pawn
183-
var/can_reach = !(current_behavior.behavior_flags & AI_BEHAVIOR_REQUIRE_REACH) || moving_pawn.CanReach(current_movement_target)
183+
var/can_reach = !(current_behavior.behavior_flags & AI_BEHAVIOR_REQUIRE_REACH) || current_movement_target.IsReachableBy(moving_pawn)
184184
if(can_reach && current_behavior.required_distance >= get_dist(moving_pawn, current_movement_target)) ///Are we close enough to engage?
185185
if(ai_movement.moving_controllers[src] == current_movement_target) //We are close enough, if we're moving stop.
186186
ai_movement.stop_moving_towards(src)

code/datums/ai/dog/dog_behaviors.dm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
var/obj/item/fetch_thing = controller.blackboard[BB_FETCH_TARGET]
1212

1313
//either we can't pick it up, or we'd rather eat it, so stop trying.
14-
if(fetch_thing.anchored || !isturf(fetch_thing.loc) || IS_EDIBLE(fetch_thing) || !living_pawn.CanReach(fetch_thing))
14+
if(fetch_thing.anchored || !isturf(fetch_thing.loc) || IS_EDIBLE(fetch_thing) || !fetch_thing.IsReachableBy(living_pawn))
1515
return BEHAVIOR_PERFORM_FAILURE
1616

1717
return BEHAVIOR_PERFORM_SUCCESS

code/datums/ai/generic/generic_behaviors.dm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
var/obj/item/held_item = pawn.get_item_by_slot(pawn.get_active_hand())
9393
var/atom/target = controller.blackboard[target_key]
9494

95-
if(!target || !pawn.CanReach(target))
95+
if(!target || !target.IsReachableBy(pawn))
9696
return BEHAVIOR_PERFORM_COOLDOWN | BEHAVIOR_PERFORM_FAILURE
9797

9898
pawn.set_combat_mode(FALSE)
@@ -118,7 +118,7 @@
118118
var/obj/item/held_item = pawn.get_item_by_slot(pawn.get_active_hand())
119119
var/atom/target = controller.blackboard[target_key]
120120

121-
if(!target || !pawn.CanReach(target) || !isliving(target))
121+
if(!target || !target.IsReachableBy(pawn) || !isliving(target))
122122
return BEHAVIOR_PERFORM_COOLDOWN | BEHAVIOR_PERFORM_FAILURE
123123

124124
var/mob/living/living_target = target

code/datums/ai/monkey/monkey_behaviors.dm

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
var/mob/living/victim = target.loc
7171
var/mob/living/living_pawn = controller.pawn
7272

73-
if(!istype(victim) || !living_pawn.CanReach(victim))
73+
if(!istype(victim) || !victim.IsReachableBy(living_pawn))
7474
finish_action(controller, FALSE)
7575
return
7676

@@ -82,7 +82,7 @@
8282

8383
var/success = FALSE
8484

85-
if(do_after(living_pawn, victim, MONKEY_ITEM_SNATCH_DELAY, DO_PUBLIC, display = image('icons/hud/do_after.dmi', "pickpocket")) && target && living_pawn.CanReach(victim))
85+
if(do_after(living_pawn, victim, MONKEY_ITEM_SNATCH_DELAY, DO_PUBLIC, display = image('icons/hud/do_after.dmi', "pickpocket")) && target && victim.IsReachableBy(living_pawn))
8686

8787
for(var/obj/item/I in victim.held_items)
8888
if(I == target)
@@ -188,7 +188,7 @@
188188
controller.set_blackboard_key(BB_MONKEY_GUN_WORKED, TRUE)
189189

190190
// attack with weapon if we have one
191-
if(living_pawn.CanReach(target, weapon))
191+
if(target.IsReachableBy(living_pawn, weapon))
192192
if(weapon)
193193
weapon.melee_attack_chain(living_pawn, target)
194194
else

code/datums/elements/openspace_item_click_handler.dm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121
return
2222
var/turf/turf_above = GetAbove(target)
2323
if(turf_above?.z == user.z)
24-
INVOKE_ASYNC(source, TYPE_PROC_REF(/obj/item, handle_openspace_click), turf_above, user, user.CanReach(turf_above, source), click_parameters)
24+
INVOKE_ASYNC(source, TYPE_PROC_REF(/obj/item, handle_openspace_click), turf_above, user, turf_above.IsReachableBy(user, source), click_parameters)

0 commit comments

Comments
 (0)