Skip to content

Commit

Permalink
Fixed some logical issues with Enter() and LinkBlocked() procs
Browse files Browse the repository at this point in the history
- LinkBlocked handles diagonal movement properly now

- Collisions with multitile vehicles will now prioritize border items when handling collisions

- Collisions with multitile vehicles will now destroy all blocking items instead of only the first one that is caught

- Set more can_block_movement values to optimize movement slightly
  • Loading branch information
boskoramen committed Sep 9, 2024
1 parent 2fc43d5 commit 9e8087a
Show file tree
Hide file tree
Showing 15 changed files with 457 additions and 300 deletions.
4 changes: 4 additions & 0 deletions code/__DEFINES/movement.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#define BLOCKED_MOVEMENT (NORTH|SOUTH|EAST|WEST)
#define NO_BLOCKED_MOVEMENT 0

/// Whether after Collide, movement is NOT blocked.
/// Mainly for vehicles at the moment
#define MOVABLE_COLLIDE_NOT_BLOCKED (1<<0)

#define LOW_LAUNCH 0
#define NORMAL_LAUNCH 1
#define HIGH_LAUNCH 2
Expand Down
166 changes: 89 additions & 77 deletions code/__HELPERS/unsorted.dm
Original file line number Diff line number Diff line change
Expand Up @@ -130,106 +130,118 @@
/proc/Get_Compass_Dir(atom/start, atom/end)//get_dir() only considers an object to be north/south/east/west if there is zero deviation. This uses rounding instead.
return angle_to_dir(Get_Angle(get_turf(start), get_turf(end)))

// Among other things, used by flamethrower and boiler spray to calculate if flame/spray can pass through.
// Returns an atom for specific effects (primarily flames and acid spray) that damage things upon contact
//
// This is a copy-and-paste of the Enter() proc for turfs with tweaks related to the applications
// of LinkBlocked
/**
* Among other things, used by flamethrower and boiler spray to calculate if flame/spray can pass through.
* Returns an atom for specific effects (primarily flames and acid spray) that damage things upon contact
*
* This is a copy-and-paste of the Enter() proc for turfs with tweaks related to the applications of LinkBlocked
*/
/proc/LinkBlocked(atom/movable/mover, turf/start_turf, turf/target_turf, list/atom/forget)
if (!mover)
return null

/// the actual dir between the start and target turf
var/fdir = get_dir(start_turf, target_turf)
if (!fdir)
var/target_dir = get_dir(start_turf, target_turf)
if (!target_dir)
return null

var/fd1 = fdir & (fdir-1)
var/fd2 = fdir - fd1
// NORTH or SOUTH component of target direction
var/longitudinal_dir = target_dir & (target_dir-1)
// EAST or WEST component of target direction
var/latitudinal_dir = target_dir - longitudinal_dir

/// The direction that mover's path is being blocked by
var/blocking_dir = 0

var/obstacle
var/turf/T
var/atom/A

blocking_dir |= start_turf.BlockedExitDirs(mover, fdir)
var/blocking_dir = NO_BLOCKED_MOVEMENT

var/turf/turf_to_check
var/atom/movable/obstacle

/**
* Check atoms in the current turf (including turf itself)
*
* For each atom, including the current turf, we check:
* 1. Whether that atom will allow us to exit in either the longitudinal
* or latitudinal directions
*/
blocking_dir |= start_turf.BlockedExitDirs(mover, target_dir)
if (blocking_dir == target_dir)
return start_turf
for (obstacle in start_turf) //First, check objects to block exit
if (mover == obstacle || (obstacle in forget))
continue
if (!isStructure(obstacle) && !ismob(obstacle) && !isVehicle(obstacle))
continue
A = obstacle
blocking_dir |= A.BlockedExitDirs(mover, fdir)
if ((!fd1 || blocking_dir & fd1) && (!fd2 || blocking_dir & fd2))
return A

// Check for atoms in adjacent turf EAST/WEST
if (fd1 && fd1 != fdir)
T = get_step(start_turf, fd1)
if (T.BlockedExitDirs(mover, fd2) || T.BlockedPassDirs(mover, fd1))
blocking_dir |= fd1
if ((!fd1 || blocking_dir & fd1) && (!fd2 || blocking_dir & fd2))
return T
for (obstacle in T)
if(obstacle in forget)
continue
if (mover == obstacle || (obstacle in forget))
continue
blocking_dir |= obstacle.BlockedExitDirs(mover, target_dir)
if ((blocking_dir & target_dir) == target_dir)
return obstacle

/**
* Check atoms in the adjacent turf (including turf itself) to the EAST or WEST when moving diagonally
*
* For each atom, including the turf to the EAST or WEST, we check:
* 1. Whether that atom will block us from exiting into the target turf from its turf (by NORTH or SOUTH depending on latitudinal_dir)
* 2. Whether that atom will block us from entering into its turf from the current turf (by EAST or WEST depending on longitudinal_dir)
*/
if (longitudinal_dir && longitudinal_dir != target_dir)
turf_to_check = get_step(start_turf, longitudinal_dir)
if (turf_to_check.BlockedExitDirs(mover, latitudinal_dir) || turf_to_check.BlockedPassDirs(mover, longitudinal_dir))
blocking_dir |= longitudinal_dir
if ((blocking_dir & target_dir) == target_dir)
return turf_to_check
for (obstacle in turf_to_check.movement_blockers)
if (!isStructure(obstacle) && !ismob(obstacle) && !isVehicle(obstacle))
continue
A = obstacle
if (A.BlockedExitDirs(mover, fd2) || A.BlockedPassDirs(mover, fd1))
blocking_dir |= fd1
if ((!fd1 || blocking_dir & fd1) && (!fd2 || blocking_dir & fd2))
return A
break

// Check for atoms in adjacent turf NORTH/SOUTH
if (fd2 && fd2 != fdir)
T = get_step(start_turf, fd2)
if (T.BlockedExitDirs(mover, fd1) || T.BlockedPassDirs(mover, fd2))
blocking_dir |= fd2
if ((!fd1 || blocking_dir & fd1) && (!fd2 || blocking_dir & fd2))
return T
for (obstacle in T)
if(obstacle in forget)
if (obstacle in forget)
continue
if (obstacle.BlockedExitDirs(mover, latitudinal_dir) || obstacle.BlockedPassDirs(mover, longitudinal_dir))
blocking_dir |= longitudinal_dir
if ((blocking_dir & target_dir) == target_dir)
return obstacle

/**
* Check atoms in the adjacent turf (including turf itself) to the NORTH or SOUTH when moving diagonally
*
* For each atom, including the turf to the NORTH or SOUTH, we check:
* 1. Whether that atom will block us from exiting into the target turf from its turf (by EAST or WEST depending on longitudinal_dir)
* 2. Whether that atom will block us from entering into its turf from the current turf (by NORTH or SOUTH depending on latitudinal_dir)
*/
if (latitudinal_dir && latitudinal_dir != target_dir)
turf_to_check = get_step(start_turf, latitudinal_dir)
if (turf_to_check.BlockedExitDirs(mover, longitudinal_dir) || turf_to_check.BlockedPassDirs(mover, latitudinal_dir))
blocking_dir |= latitudinal_dir
if ((blocking_dir & target_dir) == target_dir)
return turf_to_check
for (obstacle in turf_to_check.movement_blockers)
if (!isStructure(obstacle) && !ismob(obstacle) && !isVehicle(obstacle))
continue
A = obstacle
if (A.BlockedExitDirs(mover, fd1) || A.BlockedPassDirs(mover, fd2))
blocking_dir |= fd2
if ((!fd1 || blocking_dir & fd1) && (!fd2 || blocking_dir & fd2))
return A
break

// Check the turf itself
blocking_dir |= target_turf.BlockedPassDirs(mover, fdir)
if ((!fd1 || blocking_dir & fd1) && (!fd2 || blocking_dir & fd2))
if(obstacle in forget)
continue
if (obstacle.BlockedExitDirs(mover, longitudinal_dir) || obstacle.BlockedPassDirs(mover, latitudinal_dir))
blocking_dir |= latitudinal_dir
if ((blocking_dir & target_dir) == target_dir)
return obstacle

/**
* Check atoms in the target turf (including turf itself)
*
* For each atom, including the target turf, we check:
* 1. Whether that atom will allow us to enter in either the longitudinal or
* latitudinal directions
*/
blocking_dir |= target_turf.BlockedPassDirs(mover, target_dir)
if ((blocking_dir & target_dir) == target_dir)
return target_turf
for (obstacle in target_turf) // Finally, check atoms in the target turf
if(obstacle in forget)
continue
if (!isStructure(obstacle) && !ismob(obstacle) && !isVehicle(obstacle))
for (obstacle in target_turf.movement_blockers) // Finally, check atoms in the target turf
if (obstacle in forget)
continue
A = obstacle
blocking_dir |= A.BlockedPassDirs(mover, fdir)
if((fd1 && blocking_dir == fd1) || (fd2 && blocking_dir == fd2))
return A
if((!fd1 || blocking_dir & fd1) && (!fd2 || blocking_dir & fd2))
return A
obstacle = obstacle
blocking_dir |= obstacle.BlockedPassDirs(mover, target_dir)
if((blocking_dir & target_dir) == target_dir)
return obstacle

return null // Nothing found to block the link of mover from start_turf to target_turf


/proc/TurfBlockedNonWindow(turf/loc)
for(var/obj/O in loc)
if(O.density && !istype(O, /obj/structure/window))
return 1
return 0



//Returns whether or not a player is a guest using their ckey as an input
/proc/IsGuestKey(key)
if (findtext(key, "Guest-", 1, 7) != 1) //was findtextEx
Expand Down
10 changes: 5 additions & 5 deletions code/game/atoms.dm
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@
//Z-Level Transitions
var/atom/movable/clone/clone = null

// Bitflag of which test cases this atom is exempt from
// See #define/tests.dm
/**
* Bitflag of which test cases this atom is exempt from
*
* See #define/tests.dm
*/
var/test_exemptions = 0

// Whether the atom is an obstacle that should be considered for passing
var/can_block_movement = FALSE

var/datum/component/orbiter/orbiters

///Reference to atom being orbited
Expand Down
10 changes: 8 additions & 2 deletions code/game/atoms_movable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@
var/mob/pulledby = null
var/rebounds = FALSE
var/rebounding = FALSE // whether an object that was launched was rebounded (to prevent infinite recursive loops from wall bouncing)
/// Whether the atom is an obstacle that should be considered for passing
var/can_block_movement = FALSE

var/acid_damage = 0 //Counter for stomach acid damage. At ~60 ticks, dissolved
/// Counter for stomach acid damage. At ~60 ticks, dissolved
var/acid_damage = 0

var/move_intentionally = FALSE // this is for some deep stuff optimization. This means that it is regular movement that can only be NSWE and you don't need to perform checks on diagonals. ALWAYS reset it back to FALSE when done
// this is for some deep stuff optimization. This means that it is regular movement that can only be NSWE and you don't need to perform checks on diagonals. ALWAYS reset it back to FALSE when done
var/move_intentionally = FALSE

/// How much this mob|object is worth when lowered into the ASRS pit while the black market is unlocked.
var/black_market_value = 0
Expand Down Expand Up @@ -92,6 +96,8 @@
AddComponent(/datum/component/overlay_lighting)
if(light_system == DIRECTIONAL_LIGHT)
AddComponent(/datum/component/overlay_lighting, is_directional = TRUE)
if(!mapload && isturf(loc))
loc.Entered(src)

/atom/movable/proc/update_emissive_block()
if(emissive_overlay)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@
/obj/effect/particle_effect/water/Collide(atom/A)
if(reagents)
reagents.reaction(A)
return ..()
return
1 change: 1 addition & 0 deletions code/game/objects/structures/signs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
anchored = TRUE
opacity = FALSE
density = FALSE
can_block_movement = FALSE
layer = WALL_OBJ_LAYER

/obj/structure/sign/ex_act(severity)
Expand Down
6 changes: 6 additions & 0 deletions code/game/objects/structures/window.dm
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,12 @@
/obj/structure/window/proc/is_full_window()
return !(flags_atom & ON_BORDER)

/obj/structure/window/proc/destroy(play_sound = TRUE)
if (play_sound)
playsound(src, "windowshatter", 50, 1)
handle_debris()
qdel(src)

/obj/structure/window/deconstruct(disassembled = TRUE)
if(disassembled)
if(reinf)
Expand Down
2 changes: 1 addition & 1 deletion code/game/turfs/transit.dm
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
if(turf.density)
continue
var/found_dense = FALSE
for(var/atom/turf_atom in turf)
for(var/atom/movable/turf_atom in turf)
if(turf_atom.density && turf_atom.can_block_movement)
found_dense = TRUE
break
Expand Down
Loading

0 comments on commit 9e8087a

Please sign in to comment.