Better meteors, smoother rod movement (#29797)

* Better meteors

* Update move loop flags file references in comments.

* Adds MOVEMENT_LOOP_FORCE_MOVE, adds support for it to all movement types.

* Standardize meteor and rod movement.

* move_towards fixes

* Faster movement, fixed rod directions.

* Fix and simplify move_towards movement type.

* Bad comment.

* Oops.

* Revert requirements.txt change, doesn't belong in this PR.

* Apply suggestions from code review

Co-authored-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
Signed-off-by: Charlie Nolan <funnyman3595@gmail.com>

---------

Signed-off-by: Charlie Nolan <funnyman3595@gmail.com>
Co-authored-by: PollardTheDragon <144391971+PollardTheDragon@users.noreply.github.com>
This commit is contained in:
Charlie Nolan
2025-07-24 19:51:58 +00:00
committed by GitHub
co-authored by PollardTheDragon
parent f8d5490731
commit 6511979ce4
9 changed files with 352 additions and 254 deletions
@@ -121,7 +121,7 @@
var/old_loc = moving.loc
owner?.processing_move_loop_flags = flags
var/result = move() //Result is an enum value. Enums defined in __DEFINES/movement.dm
var/result = move() // Result is an enum value. Enums defined in __DEFINES/movement_defines.dm
if(moving)
var/direction = get_dir(old_loc, moving.loc)
SEND_SIGNAL(moving, COMSIG_MOVABLE_MOVED_FROM_LOOP, src, old_dir, direction)
@@ -183,7 +183,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to infinity
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*
**/
/datum/move_manager/proc/move(moving, direction, delay, timeout, subsystem, priority, flags, datum/extra_info)
@@ -206,38 +206,14 @@
/datum/move_loop/move/move()
var/atom/old_loc = moving.loc
moving.Move(get_step(moving, direction), direction, FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE), !(flags & MOVEMENT_LOOP_NO_MOMENTUM_CHANGE))
if(flags & MOVEMENT_LOOP_FORCE_MOVE)
moving.forceMove(get_step(moving, direction))
else
moving.Move(get_step(moving, direction), direction, FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE), !(flags & MOVEMENT_LOOP_NO_MOMENTUM_CHANGE))
// We cannot rely on the return value of Move(), we care about teleports and it doesn't
// Moving also can be null on occasion, if the move deleted it and therefor us
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
/**
* Like move(), but we don't care about collision at all
*
* Returns TRUE if the loop sucessfully started, or FALSE if it failed
*
* Arguments:
* moving - The atom we want to move
* direction - The direction we want to move in
* delay - How many deci-seconds to wait between fires. Defaults to the lowest value, 0.1
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to infinity
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
*
**/
/datum/move_manager/proc/force_move_dir(moving, direction, delay, timeout, subsystem, priority, flags, datum/extra_info)
return add_to_loop(moving, subsystem, /datum/move_loop/move/force, priority, flags, extra_info, delay, timeout, direction)
/datum/move_loop/move/force
/datum/move_loop/move/force/move()
var/atom/old_loc = moving.loc
moving.forceMove(get_step(moving, direction))
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
/datum/move_loop/has_target
///The thing we're moving in relation to, either at or away from
var/atom/target
@@ -268,34 +244,6 @@
SIGNAL_HANDLER
qdel(src)
/**
* Used for force-move loops, similar to move_towards_legacy() but not quite the same
*
* Returns TRUE if the loop sucessfully started, or FALSE if it failed
*
* Arguments:
* moving - The atom we want to move
* chasing - The atom we want to move towards
* delay - How many deci-seconds to wait between fires. Defaults to the lowest value, 0.1
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to infinity
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
*
**/
/datum/move_manager/proc/force_move(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info)
return add_to_loop(moving, subsystem, /datum/move_loop/has_target/force_move, priority, flags, extra_info, delay, timeout, chasing)
///Used for force-move loops
/datum/move_loop/has_target/force_move
/datum/move_loop/has_target/force_move/move()
var/atom/old_loc = moving.loc
moving.forceMove(get_step(moving, get_dir(moving, target)))
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
/**
* Used for following jps defined paths. The proc signature here's a bit long, I'm sorry
*
@@ -315,7 +263,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to infinity
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*
**/
/datum/move_manager/proc/jps_move(moving,
@@ -442,7 +390,11 @@
var/turf/next_step = movement_path[1]
var/atom/old_loc = moving.loc
moving.Move(next_step, get_dir(moving, next_step), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
if(flags & MOVEMENT_LOOP_FORCE_MOVE)
moving.forceMove(next_step)
else
moving.Move(next_step, get_dir(moving, next_step), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
. = (old_loc != moving?.loc) ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
// this check if we're on exactly the next tile may be overly brittle for dense objects who may get bumped slightly
@@ -493,7 +445,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to infinity
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*
**/
/datum/move_manager/proc/move_to(moving, chasing, min_dist, delay, timeout, subsystem, priority, flags, datum/extra_info)
@@ -511,7 +463,10 @@
return
var/atom/old_loc = moving.loc
var/turf/next = get_step_to(moving, target)
moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
if(flags & MOVEMENT_LOOP_FORCE_MOVE)
moving.forceMove(next)
else
moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
/**
@@ -527,7 +482,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to infinity
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*
**/
/datum/move_manager/proc/move_away(moving, chasing, max_dist, delay, timeout, subsystem, priority, flags, datum/extra_info)
@@ -545,7 +500,10 @@
return
var/atom/old_loc = moving.loc
var/turf/next = get_step_away(moving, target)
moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
if(flags & MOVEMENT_LOOP_FORCE_MOVE)
moving.forceMove(next)
else
moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
@@ -562,7 +520,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to INFINITY
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*
**/
/datum/move_manager/proc/move_towards(moving, chasing, delay, home, timeout, subsystem, priority, flags, datum/extra_info)
@@ -581,7 +539,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to INFINITY
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*
**/
/datum/move_manager/proc/home_onto(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info)
@@ -589,32 +547,27 @@
///Used as a alternative to GLOB.move_manager.home_onto
/datum/move_loop/has_target/move_towards
///The turf we want to move into, used for course correction
var/turf/moving_towards
///Should we try and stay on the path, or is deviation alright
/// Should we track our target, so we won't end up in the wrong place if it moves or if something knocks us off course?
var/home = FALSE
///When this gets larger then 1 we move a turf
var/x_ticker = 0
var/y_ticker = 0
///The rate at which we move, between 0 and 1
var/x_rate = 1
var/y_rate = 1
//We store the signs of x and y seperately, because byond will round negative numbers down
//So doing all our operations with absolute values then multiplying them is easier
var/x_sign = 0
var/y_sign = 0
// This tracks our location with sub-tile precision, allowing us to move along a smooth line. We assume that we started at the center of the tile, so that our shifts along the shorter axis are centered in the movement path, rather than biased towards the start or end. It also makes floating point errors less problematic, because neither 0.4999 nor 0.5001 will cross a tile boundary.
var/precise_x
var/precise_y
/// The speed at which we move along each axis, between -1 and 1
var/x_speed
var/y_speed
/datum/move_loop/has_target/move_towards/setup(delay, timeout, atom/chasing, home = FALSE)
. = ..()
if(!.)
return FALSE
src.home = home
precise_x = moving.x + 0.5
precise_y = moving.y + 0.5
if(home)
if(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(update_slope)) //If it can move, update your slope when it does
RegisterSignal(moving, COMSIG_MOVABLE_MOVED, PROC_REF(handle_move))
update_slope()
if(home && ismovable(target))
// If we're following something that can move, make sure we keep moving towards it.
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(update_angle))
update_angle()
/datum/move_loop/has_target/move_towards/compare_loops(datum/move_loop/loop_type, priority, flags, extra_info, delay, timeout, atom/chasing, home = FALSE)
if(..() && home == src.home)
@@ -625,41 +578,63 @@
if(home)
if(ismovable(target))
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
if(moving)
UnregisterSignal(moving, COMSIG_MOVABLE_MOVED)
return ..()
/datum/move_loop/has_target/move_towards/move()
//Move our tickers forward a step, we're guaranteed at least one step forward because of how the code is written
if(x_rate) //Did you know that rounding by 0 throws a divide by 0 error?
x_ticker = FLOOR(x_ticker + x_rate, x_rate)
if(y_rate)
y_ticker = FLOOR(y_ticker + y_rate, y_rate)
var/x = moving.x
var/y = moving.y
var/z = moving.z
moving_towards = locate(x + round(x_ticker) * x_sign, y + round(y_ticker) * y_sign, z)
//The tickers serve as good methods of tracking remainder
if(x_ticker >= 1)
x_ticker = MODULUS(x_ticker, 1) //I swear to god if you somehow go up by one then one in a tick I'm gonna go mad
if(y_ticker >= 1)
y_ticker = MODULUS(x_ticker, 1)
var/atom/old_loc = moving.loc
moving.Move(moving_towards, get_dir(moving, moving_towards), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
//YOU FOUND THEM! GOOD JOB
if(home && get_turf(moving) == get_turf(target))
x_rate = 0
y_rate = 0
var/old_turf = get_turf(moving)
if(!old_turf)
// If we aren't anywhere, we should stop moving.
qdel(src)
return
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
/datum/move_loop/has_target/move_towards/proc/handle_move(source, atom/OldLoc, Dir, Forced = FALSE)
SIGNAL_HANDLER
if(moving.loc == moving_towards && home) //If we didn't go where we should have, update slope to account for the deviation
update_slope()
// If we're not where we expect to be along either axis, we re-center ourselves within the correct tile along that axis.
var/off_course = FALSE
if(floor(precise_x) != moving.x)
precise_x = moving.x + 0.5
off_course = TRUE
if(floor(precise_y) != moving.y)
precise_y = moving.y + 0.5
off_course = TRUE
// And if we're homing, get back on course.
if(home && off_course)
update_angle()
// Update our position based on our current speed.
// We will always move at least one tile, because one of these is always 1 or -1.
precise_x += x_speed
precise_y += y_speed
var/next_turf = locate(floor(precise_x), floor(precise_y), moving.z)
if(flags & MOVEMENT_LOOP_FORCE_MOVE)
moving.forceMove(next_turf)
else
moving.Move(next_turf, get_dir(old_turf, next_turf), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
var/turf/here = get_turf(moving)
if(!here)
// If we aren't anywhere, we should stop moving.
qdel(src)
return
// If we didn't move the way we expected, re-center ourselves along the relevant axis/axes.
off_course = FALSE
if(here.x != floor(precise_x))
precise_x = here.x + 0.5
off_course = TRUE
if(here.y != floor(precise_y))
precise_y = here.y + 0.5
off_course = TRUE
// If we're homing, get back on course.
if(home && off_course)
update_angle()
else if(get_turf(moving) == get_turf(target))
// YOU FOUND IT! GOOD JOB!
x_speed = 0
y_speed = 0
// If we moved at all, that's a win.
return old_turf != here ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
/datum/move_loop/has_target/move_towards/handle_no_target()
if(home)
@@ -667,46 +642,37 @@
target = null
/**
* Recalculates the slope between our object and the target, sets our rates to it
* Recalculates the angle we're moving at, so that we get a smooth movement line, rather than awkwardly bending from orthogonal to diagonal (or vice versa) at some point.
*
* The math below is reminiscent of something like y = mx + b
* Except we don't need to care about axis, since we do all our movement in steps of 1
* Because of that all that matters is we only move one tile at a time
* So we take the smaller delta, divide it by the larger one, and get smaller step per large step
* Then we set the large step to 1, and we're done. This way we're guaranteed to never move more then a tile at once
* And we can have nice lines
* The way we set the angle is by adjusting the speed we move in each direction.
* We always move at full speed along the longer axis towards our target.
* For the other axis, we calculate the right speed to reach our target at the same time we did on the longer axis.
* The net result is that every time we move, we approach the target along the longer axis, but we only move along the shorter axis at regular intervals, creating as smooth a line as possible.
**/
/datum/move_loop/has_target/move_towards/proc/update_slope()
SIGNAL_HANDLER
/datum/move_loop/has_target/move_towards/proc/update_angle()
SIGNAL_HANDLER // COMSIG_MOVABLE_MOVED
//You'll notice this is rise over run, except we flip the formula upside down depending on the larger number
//This is so we never move more then one tile at once
var/delta_y = target.y - moving.y
var/delta_x = target.x - moving.x
//It's more convienent to store delta x and y as absolute values
//and modify them right at the end then it is to deal with rounding errors
x_sign = (delta_x > 0) ? 1 : -1
y_sign = (delta_y > 0) ? 1 : -1
delta_x = abs(delta_x)
delta_y = abs(delta_y)
var/delta_y = target.y - moving.y
if(delta_x == 0 && delta_y == 0)
// We ain't goin nowhere.
x_speed = 0
y_speed = 0
return
if(delta_x >= delta_y)
if(delta_x == 0) //Just go up/down
x_rate = 0
y_rate = 1
return
x_rate = 1
y_rate = delta_y / delta_x //rise over run, you know the deal
if(abs(delta_x) >= abs(delta_y))
// We need to move farther in the X direction, so always move along X.
x_speed = sign(delta_x)
// Move along Y often enough to smoothly reach the target.
y_speed = delta_y / abs(delta_x)
else
if(delta_y == 0) //Just go right/left
x_rate = 1
y_rate = 0
return
x_rate = delta_x / delta_y //Keep the larger step size at 1
y_rate = 1
// We need to move farther in the Y direction, so always move along Y.
y_speed = sign(delta_y)
// Move along X often enough to smoothly reach the target.
x_speed = delta_x / abs(delta_y)
/**
* Wrapper for GLOB.move_manager.home_onto, not reccomended, as its movement ends up being a bit stilted
* Alternative to GLOB.move_manager.home_onto. Not reccomended, as it ends up putting a kink in the movement path if it's not directly along one of the 8 directions.
*
* Returns TRUE if the loop sucessfully started, or FALSE if it failed
*
@@ -717,7 +683,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to infinity
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*
**/
/datum/move_manager/proc/move_towards_legacy(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info)
@@ -729,7 +695,10 @@
/datum/move_loop/has_target/move_towards_budget/move()
var/turf/target_turf = get_step_towards(moving, target)
var/atom/old_loc = moving.loc
moving.Move(target_turf, get_dir(moving, target_turf), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
if(flags & MOVEMENT_LOOP_FORCE_MOVE)
moving.forceMove(target_turf)
else
moving.Move(target_turf, get_dir(moving, target_turf), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
/**
@@ -744,7 +713,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. This should be considered extremely non-optional as it will completely stun out the movement loop <i>forever</i> if unset.
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*/
/datum/move_manager/proc/freeze(moving, halted_turf, delay, timeout, subsystem, priority, flags, datum/extra_info)
return add_to_loop(moving, subsystem, /datum/move_loop/freeze, priority, flags, extra_info, delay, timeout, halted_turf)
@@ -767,7 +736,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to infinity
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*
**/
/datum/move_manager/proc/move_rand(moving, directions, delay, timeout, subsystem, priority, flags, datum/extra_info)
@@ -802,7 +771,10 @@
var/testdir = pick(potential_dirs)
var/turf/moving_towards = get_step(moving, testdir)
var/atom/old_loc = moving.loc
moving.Move(moving_towards, testdir, FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
if(flags & MOVEMENT_LOOP_FORCE_MOVE)
moving.forceMove(moving_towards)
else
moving.Move(moving_towards, testdir, FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
if(old_loc != moving?.loc) //If it worked, we're done
return MOVELOOP_SUCCESS
potential_dirs -= testdir
@@ -819,7 +791,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to infinity
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*
**/
/datum/move_manager/proc/move_to_rand(moving, delay, timeout, subsystem, priority, flags, datum/extra_info)
@@ -831,7 +803,10 @@
/datum/move_loop/move_to_rand/move()
var/atom/old_loc = moving.loc
var/turf/next = get_step_rand(moving)
moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
if(flags & MOVEMENT_LOOP_FORCE_MOVE)
moving.forceMove(next)
else
moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
/**
@@ -847,7 +822,7 @@
* timeout - Time in deci-seconds until the moveloop self expires. Defaults to infinity
* subsystem - The movement subsystem to use. Defaults to SSmovement. Only one loop can exist for any one subsystem
* priority - Defines how different move loops override each other. Lower numbers beat higher numbers, equal defaults to what currently exists. Defaults to MOVEMENT_DEFAULT_PRIORITY
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
* flags - Set of bitflags that effect move loop behavior in some way. Check __DEFINES/movement_defines.dm
*
**/
/datum/move_manager/proc/ventcrawl(moving, chasing, delay, timeout, subsystem, priority, flags, skip_first = TRUE, datum/extra_info)