Fix jetpacks and speedbikes (#28222)

* Fix jetpacks

* All mobs LONG_GLIDE

* Don't disturb the drift loop on Z level changes.

* Fix speedbikes
This commit is contained in:
Charlie Nolan
2025-02-13 02:08:43 +00:00
committed by GitHub
parent 444000c165
commit cb7c6586c9
7 changed files with 54 additions and 78 deletions
+4 -3
View File
@@ -22,8 +22,8 @@
#define MOVEMENT_LOOP_IGNORE_GLIDE (1<<2)
///Should we not update our movables dir on move?
#define MOVEMENT_LOOP_NO_DIR_UPDATE (1<<3)
///Is the loop moving the movable outside its control, like it's an external force? e.g. footsteps won't play if enabled.
#define MOVEMENT_LOOP_OUTSIDE_CONTROL (1<<4)
///Controls how the loop will set momentum_change in its Move call.
#define MOVEMENT_LOOP_NO_MOMENTUM_CHANGE (1<<4)
// Movement loop status flags
/// Has the loop been paused, soon to be resumed?
@@ -54,12 +54,13 @@
#define ACTIVE_MOVEMENT_OLDLOCS 4
/// The arguments of this macro correspond directly to the argument order of /atom/movable/proc/Moved
#define SET_ACTIVE_MOVEMENT(_old_loc, _direction, _forced, _oldlocs) \
#define SET_ACTIVE_MOVEMENT(_old_loc, _direction, _forced, _oldlocs, _momentum_change) \
active_movement = list( \
_old_loc, \
_direction, \
_forced, \
_oldlocs, \
_momentum_change, \
)
/// Finish any active movements
@@ -206,7 +206,7 @@
/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))
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
+18 -42
View File
@@ -5,10 +5,6 @@
var/atom/inertia_last_loc
var/old_dir
var/datum/move_loop/move/drifting_loop
///Should we ignore the next glide rate input we get?
///This is to some extent a hack around the order of operations
///Around COMSIG_MOVELOOP_POSTPROCESS. I'm sorry lad
var/ignore_next_glide = FALSE
///Have we been delayed? IE: active, but not working right this second?
var/delayed = FALSE
var/block_inputs_until
@@ -19,7 +15,7 @@
return COMPONENT_INCOMPATIBLE
. = ..()
var/flags = MOVEMENT_LOOP_OUTSIDE_CONTROL
var/flags = MOVEMENT_LOOP_NO_MOMENTUM_CHANGE
if(instant)
flags |= MOVEMENT_LOOP_START_FAST
var/atom/movable/movable_parent = parent
@@ -61,8 +57,6 @@
if(SEND_SIGNAL(parent, COMSIG_MOVABLE_DRIFT_VISUAL_ATTEMPT) & DRIFT_VISUAL_FAILED)
return
// Ignore the next glide because it's literally just us
ignore_next_glide = TRUE
var/atom/movable/movable_parent = parent
movable_parent.set_glide_size(MOVEMENT_ADJUSTED_GLIDE_SIZE(visual_delay, SSspacedrift.visual_delay))
if(ismob(parent))
@@ -74,7 +68,7 @@
mob_parent.client?.visual_delay = MOVEMENT_ADJUSTED_GLIDE_SIZE(visual_delay, SSspacedrift.visual_delay)
/datum/component/drift/proc/newtonian_impulse(datum/source, inertia_direction)
SIGNAL_HANDLER
SIGNAL_HANDLER // COMSIG_MOVABLE_NEWTONIAN_MOVE
var/atom/movable/movable_parent = parent
inertia_last_loc = movable_parent.loc
if(drifting_loop)
@@ -84,32 +78,28 @@
return COMPONENT_MOVABLE_NEWTONIAN_BLOCK
/datum/component/drift/proc/drifting_start()
SIGNAL_HANDLER
SIGNAL_HANDLER // COMSIG_MOVELOOP_START
var/atom/movable/movable_parent = parent
inertia_last_loc = movable_parent.loc
RegisterSignal(movable_parent, COMSIG_MOVABLE_MOVED, PROC_REF(handle_move))
// We will use glide size to intuit how long to delay our loop's next move for
// This way you can't ride two movements at once while drifting, since that'd be dumb as fuck
RegisterSignal(movable_parent, COMSIG_MOVABLE_UPDATED_GLIDE_SIZE, PROC_REF(handle_glidesize_update))
// If you stop pulling something mid drift, I want it to retain that momentum
RegisterSignal(movable_parent, COMSIG_ATOM_NO_LONGER_PULLING, PROC_REF(stopped_pulling))
/datum/component/drift/proc/drifting_stop()
SIGNAL_HANDLER
SIGNAL_HANDLER // COMSIG_MOVELOOP_STOP
var/atom/movable/movable_parent = parent
movable_parent.inertia_moving = FALSE
ignore_next_glide = FALSE
UnregisterSignal(movable_parent, list(COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_UPDATED_GLIDE_SIZE, COMSIG_ATOM_NO_LONGER_PULLING))
/datum/component/drift/proc/before_move(datum/source)
SIGNAL_HANDLER
SIGNAL_HANDLER // COMSIG_MOVELOOP_PREPROCESS_CHECK
var/atom/movable/movable_parent = parent
movable_parent.inertia_moving = TRUE
old_dir = movable_parent.dir
delayed = FALSE
/datum/component/drift/proc/after_move(datum/source, result, visual_delay)
SIGNAL_HANDLER
SIGNAL_HANDLER // COMSIG_MOVELOOP_POSTPROCESS
if(result == MOVELOOP_FAILURE)
qdel(src)
return
@@ -122,15 +112,14 @@
return
inertia_last_loc = movable_parent.loc
ignore_next_glide = TRUE
/datum/component/drift/proc/loop_death(datum/source)
SIGNAL_HANDLER
SIGNAL_HANDLER // COMSIG_PARENT_QDELETING
drifting_loop = null
UnregisterSignal(parent, COMSIG_MOVABLE_NEWTONIAN_MOVE) // We won't block a component from replacing us anymore
/datum/component/drift/proc/handle_move(datum/source, old_loc)
SIGNAL_HANDLER
/datum/component/drift/proc/handle_move(datum/source, old_loc, movement_dir, forced, list/old_locs, momentum_change)
SIGNAL_HANDLER // COMSIG_MOVABLE_MOVED
// This can happen, because signals once sent cannot be stopped
if(QDELETED(src))
return
@@ -138,33 +127,19 @@
if(!isturf(movable_parent.loc))
qdel(src)
return
if(movable_parent.inertia_moving)
return
if(!movable_parent.Process_Spacemove(drifting_loop.direction, continuous_move = TRUE))
return
qdel(src)
// If we experience a momentum change that's not a result of changing Z levels, delay the drifting loop so we don't double-move.
if(momentum_change && !HAS_TRAIT(movable_parent, TRAIT_CURRENTLY_Z_MOVING))
drifting_loop.pause_for(movable_parent.inertia_move_delay)
/// We're going to take the passed in glide size
/// and use it to manually delay our loop for that period
/// to allow the other movement to complete
/datum/component/drift/proc/handle_glidesize_update(datum/source, old_glide_size)
SIGNAL_HANDLER
// If we aren't drifting, or this is us, fuck off
var/atom/movable/movable_parent = parent
if(!drifting_loop || movable_parent.inertia_moving)
if(!movable_parent.inertia_moving)
qdel(src)
return
// If we are drifting, but this set came from the moveloop itself, drop the input
// I'm sorry man
if(ignore_next_glide)
ignore_next_glide = FALSE
return
var/glide_delay = round(world.icon_size / movable_parent.glide_size, 1) * world.tick_lag
drifting_loop.pause_for(glide_delay)
delayed = TRUE
if(movable_parent.Process_Spacemove(drifting_loop.direction, continuous_move = TRUE))
qdel(src)
/// If we're pulling something and stop, we want it to continue at our rate and such
/datum/component/drift/proc/stopped_pulling(datum/source, atom/movable/was_pulling)
SIGNAL_HANDLER
SIGNAL_HANDLER // COMSIG_ATOM_NO_LONGER_PULLING
// This does mean it falls very slightly behind, but otherwise they'll potentially run into us
var/next_move_in = drifting_loop.timer - world.time + world.tick_lag
was_pulling.newtonian_move(drifting_loop.direction, start_delay = next_move_in)
@@ -187,6 +162,7 @@
RegisterSignal(parent, COMSIG_MOB_CLIENT_PRE_MOVE, PROC_REF(allow_final_movement))
/datum/component/drift/proc/allow_final_movement(datum/source)
SIGNAL_HANDLER // COMSIG_MOB_CLIENT_PRE_MOVE
// Some things want to allow movement out of spacedrift, we should let them
if(SEND_SIGNAL(parent, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT) & DRIFT_ALLOW_INPUT)
return
@@ -73,7 +73,9 @@
if(!turf_check(next, current))
to_chat(user, "<span class='warning'>[movable_parent] cannot go onto [next]!</span>")
return
if(GLOB.move_manager.processing_on(user, SSspacedrift) || !isturf(movable_parent.loc))
if(GLOB.move_manager.processing_on(user, SSspacedrift) && !override_allow_spacemove)
return
if(!isturf(movable_parent.loc))
return
step(movable_parent, direction)
+17 -10
View File
@@ -235,7 +235,7 @@
/// Here's where we rewrite how byond handles movement except slightly different.
/// To be removed on step_ conversion.
/// All this work to prevent a second bump.
/atom/movable/Move(atom/newloc, direction, glide_size_override = 0, update_dir = TRUE)
/atom/movable/Move(atom/newloc, direction, glide_size_override = 0, update_dir = TRUE, momentum_change = TRUE)
. = FALSE
if(!newloc || newloc == loc)
return
@@ -287,7 +287,7 @@
var/area/oldarea = get_area(oldloc)
var/area/newarea = get_area(newloc)
SET_ACTIVE_MOVEMENT(oldloc, direction, FALSE, old_locs)
SET_ACTIVE_MOVEMENT(oldloc, direction, FALSE, old_locs, momentum_change)
loc = newloc
. = TRUE
@@ -310,7 +310,7 @@
RESOLVE_ACTIVE_MOVEMENT
/atom/movable/Move(atom/newloc, direct = 0, glide_size_override = 0, update_dir = TRUE)
/atom/movable/Move(atom/newloc, direct = 0, glide_size_override = 0, update_dir = TRUE, momentum_change = TRUE)
var/atom/movable/pullee = pulling
var/turf/current_turf = loc
if(!loc || !newloc)
@@ -325,7 +325,7 @@
if(loc != newloc)
if(!IS_DIR_DIAGONAL(direct)) //Cardinal move
. = ..(newloc, direct)
. = ..(newloc, direct, momentum_change = momentum_change)
else //Diagonal move, split it into cardinal moves
moving_diagonally = FIRST_DIAG_STEP
var/first_step_dir = 0
@@ -334,22 +334,24 @@
var/direct_NS = direct & (NORTH | SOUTH)
var/direct_EW = direct & (EAST | WEST)
var/first_step_target = get_step(src, direct_NS)
step(src, direct_NS)
// .() is rarely seen (for good reason), but it calls the same proc we're in.
// We cant' avoid it here, because oour overloading of Move() makes it call the wrong one.
. = .(first_step_target, direct_NS, glide_size_override, FALSE, momentum_change)
if(loc == first_step_target)
first_step_dir = direct_NS
moving_diagonally = SECOND_DIAG_STEP
. = step(src, direct_EW)
. = .(newloc, direct_EW, glide_size_override, FALSE, momentum_change)
else if(loc == oldloc)
first_step_target = get_step(src, direct_EW)
step(src, direct_EW)
. = .(first_step_target, direct_EW, glide_size_override, FALSE, momentum_change)
if(loc == first_step_target)
first_step_dir = direct_EW
moving_diagonally = SECOND_DIAG_STEP
. = step(src, direct_NS)
. = .(newloc, direct_NS, glide_size_override, FALSE, momentum_change)
if(first_step_dir != 0)
if(!. && set_dir_on_move && update_dir)
setDir(first_step_dir)
Moved(oldloc, first_step_dir)
Moved(oldloc, first_step_dir, FALSE, null, TRUE)
else if(!inertia_moving)
newtonian_move(direct)
if(client_mobs_in_contents)
@@ -520,7 +522,7 @@
var/atom/oldloc = loc
var/is_multi_tile = bound_width > world.icon_size || bound_height > world.icon_size
SET_ACTIVE_MOVEMENT(oldloc, NONE, TRUE, null)
SET_ACTIVE_MOVEMENT(oldloc, NONE, TRUE, null, TRUE)
if(destination)
if(pulledby && !HAS_TRAIT(src, TRAIT_CURRENTLY_Z_MOVING))
@@ -658,6 +660,11 @@
return TRUE
/mob/newtonian_move(direction, instant = FALSE, start_delay = 0)
if(buckled)
return FALSE
return ..()
//called when src is thrown into hit_atom
/atom/movable/proc/throw_impact(atom/hit_atom, throwingdatum)
set waitfor = FALSE
+8 -21
View File
@@ -144,13 +144,7 @@
var/diagonal_factor = 1
if(IS_DIR_DIAGONAL(direct))
// For some reason, LONG_GLIDE mobs need to slow down here, but other mobs need to speed up.
// I'd expect one or the other to change, not both.
// If you can figure out why, please update this comment.
if(mob.appearance_flags & LONG_GLIDE)
diagonal_factor = sqrt(2)
else
diagonal_factor = 1 / sqrt(2)
diagonal_factor = sqrt(2)
mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay * diagonal_factor)) // set it now in case of pulled objects
//If the move was recent, count using old_move_delay
@@ -187,28 +181,21 @@
. = ..()
var/new_glide_size = 0
// Only adjust for diagonal movement if the move was *actually* diagonal
if(mob.loc == new_loc)
// Similar to the glide size calculation above, LONG_GLIDE mobs need to slow down and other mobs speed up.
// Unline before, we also want to calculate the new movement delay, which is increased for LONG_GLIDE mobs, and unchanged for other mobs.
mob.last_movement = world.time
if(IS_DIR_DIAGONAL(direct) && (mob.appearance_flags & LONG_GLIDE))
if(IS_DIR_DIAGONAL(direct))
add_delay *= sqrt(2)
if(visual_delay)
new_glide_size = visual_delay
else
new_glide_size = DELAY_TO_GLIDE_SIZE(add_delay)
if(IS_DIR_DIAGONAL(direct) && !(mob.appearance_flags & LONG_GLIDE))
new_glide_size *= sqrt(2)
mob.set_glide_size(new_glide_size)
else if(visual_delay)
mob.set_glide_size(visual_delay)
var/new_glide_size = 0
if(visual_delay)
new_glide_size = visual_delay
else
mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay))
new_glide_size = DELAY_TO_GLIDE_SIZE(add_delay)
mob.set_glide_size(new_glide_size)
move_delay += add_delay
+3
View File
@@ -2,6 +2,9 @@
density = TRUE
layer = MOB_LAYER
animate_movement = SLIDE_STEPS
// We probably shouldn't ever be setting this. LONG_GLIDE makes diagonal movement faster, because you move at full speed on both axes. However, we have manual changes scatterd around that undo this, and re-establish euclidian movement. Yes, that's exactly as silly as it sounds.
// Still, for the moment, we should at least make all mobs behave the same way that carbons do.
appearance_flags = LONG_GLIDE
pressure_resistance = 8
throwforce = 10
var/datum/mind/mind