[MIRROR] Smooth Movement: Resurrection: Resurgence: Revengeance 4: The Return of Smooth Movement: Smooth Edition Director's Cut (#550)

* Smooth Movement: Resurrection: Resurgence: Revengeance 4: The Return of Smooth Movement: Smooth Edition Director's Cut (#52515)

Automatic glide size adjustment based on move delay.
Essentially a port of https://github.com/yogstation13/Yogstation/pull/8132 but that was mostly my code with some fixes.

Why again? well it turns out the recent byond fixes to glide size actually worked and solved the issues that were unsolvable.
https://file.house/0B3u.mp4
Glide size no longer incorrectly scales at fps, so it works as intended at any framerate with the only stuttering being normal byond suck stuttering.

* Smooth Movement: Resurrection: Resurgence: Revengeance 4: The Return of Smooth Movement: Smooth Edition Director's Cut

Co-authored-by: Rob Bailey <actioninja@gmail.com>
This commit is contained in:
SkyratBot
2020-08-29 20:27:18 +01:00
committed by GitHub
co-authored by Rob Bailey
parent f212762e84
commit 0a2d016002
23 changed files with 120 additions and 37 deletions
+2
View File
@@ -284,6 +284,8 @@
#define COMSIG_MOVABLE_LIGHT_OVERLAY_SET_COLOR "movable_light_overlay_set_range"
///Called when the movable tries to toggle its dynamic light LIGHTING_ON status, from base atom/movable/lighting_overlay_toggle_on(): (new_state)
#define COMSIG_MOVABLE_LIGHT_OVERLAY_TOGGLE_ON "movable_light_overlay_toggle_on"
///called when the movable's glide size is updated: (new_glide_size)
#define COMSIG_MOVABLE_UPDATE_GLIDE_SIZE "movable_glide_size"
// /mob signals
+16
View File
@@ -0,0 +1,16 @@
/// The minimum for glide_size to be clamped to.
#define MIN_GLIDE_SIZE 1
/// The maximum for glide_size to be clamped to.
/// This shouldn't be higher than the icon size, and generally you shouldn't be changing this, but it's here just in case.
#define MAX_GLIDE_SIZE 32
/// Compensating for time dialation
GLOBAL_VAR_INIT(glide_size_multiplier, 1.0)
///Broken down, here's what this does:
/// divides the world icon_size (32) by delay divided by ticklag to get the number of pixels something should be moving each tick.
/// The division result is given a min value of 1 to prevent obscenely slow glide sizes from being set
/// Then that's multiplied by the global glide size multiplier. 1.25 by default feels pretty close to spot on. This is just to try to get byond to behave.
/// The whole result is then clamped to within the range above.
/// Not very readable but it works
#define DELAY_TO_GLIDE_SIZE(delay) (clamp(((32 / max((delay) / world.tick_lag, 1)) * GLOB.glide_size_multiplier), MIN_GLIDE_SIZE, MAX_GLIDE_SIZE))
+1
View File
@@ -47,6 +47,7 @@ SUBSYSTEM_DEF(spacedrift)
var/old_dir = AM.dir
var/old_loc = AM.loc
AM.inertia_moving = TRUE
AM.set_glide_size(DELAY_TO_GLIDE_SIZE(AM.inertia_move_delay))
step(AM, AM.inertia_dir)
AM.inertia_moving = FALSE
AM.inertia_next_move = world.time + AM.inertia_move_delay
+1 -1
View File
@@ -140,7 +140,7 @@ SUBSYSTEM_DEF(throwing)
finalize()
return
AM.Move(step, get_dir(AM, step))
AM.Move(step, get_dir(AM, step), DELAY_TO_GLIDE_SIZE(1 / speed))
if (!AM.throwing) // we hit something during our move
finalize(hit = TRUE)
+2 -1
View File
@@ -1,6 +1,6 @@
SUBSYSTEM_DEF(time_track)
name = "Time Tracking"
wait = 600
wait = 100
flags = SS_NO_INIT|SS_NO_TICK_CHECK
runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT
@@ -30,6 +30,7 @@ SUBSYSTEM_DEF(time_track)
time_dilation_avg_fast = MC_AVERAGE_FAST(time_dilation_avg_fast, time_dilation_current)
time_dilation_avg = MC_AVERAGE(time_dilation_avg, time_dilation_avg_fast)
time_dilation_avg_slow = MC_AVERAGE_SLOW(time_dilation_avg_slow, time_dilation_avg)
GLOB.glide_size_multiplier = (current_byondtime - last_tick_byond_time) / (current_realtime - last_tick_realtime)
else
first_run = FALSE
last_tick_realtime = current_realtime
+21
View File
@@ -58,6 +58,8 @@
orbiters[orbiter] = TRUE
orbiter.orbiting = src
RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, .proc/orbiter_move_react)
RegisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, .proc/orbiter_glide_size_update)
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_BEGIN, orbiter)
var/matrix/initial_transform = matrix(orbiter.transform)
@@ -78,6 +80,13 @@
orbiter.SpinAnimation(rotation_speed, -1, clockwise, rotation_segments, parallel = FALSE)
if(ismob(orbiter))
var/mob/orbiter_mob = orbiter
orbiter_mob.updating_glide_size = FALSE
if(ismovable(parent))
var/atom/movable/movable_parent = parent
orbiter.glide_size = movable_parent.glide_size
orbiter.forceMove(get_turf(parent))
to_chat(orbiter, "<span class='notice'>Now orbiting [parent].</span>")
@@ -85,6 +94,7 @@
if(!orbiters[orbiter])
return
UnregisterSignal(orbiter, COMSIG_MOVABLE_MOVED)
UnregisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE)
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_STOP, orbiter)
orbiter.SpinAnimation(0, 0)
if(istype(orbiters[orbiter],/matrix)) //This is ugly.
@@ -92,6 +102,12 @@
orbiters -= orbiter
orbiter.stop_orbit(src)
orbiter.orbiting = null
if(ismob(orbiter))
var/mob/orbiter_mob = orbiter
orbiter_mob.updating_glide_size = TRUE
orbiter_mob.glide_size = 8
if(!refreshing && !length(orbiters) && !QDELING(src))
qdel(src)
@@ -124,6 +140,11 @@
return
end_orbit(orbiter)
/datum/component/orbiter/proc/orbiter_glide_size_update(datum/source, target)
for(var/orbiter in orbiters)
var/atom/movable/movable_orbiter = orbiter
movable_orbiter.glide_size = target
/////////////////////
/atom/movable/proc/orbit(atom/A, radius = 10, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, pre_rotation = TRUE)
+8 -2
View File
@@ -39,6 +39,7 @@
var/atom/movable/AM = parent
restore_position(M)
unequip_buckle_inhands(M)
M.updating_glide_size = TRUE
if(del_on_unbuckle_all && !AM.has_buckled_mobs())
qdel(src)
@@ -46,6 +47,8 @@
SIGNAL_HANDLER
var/atom/movable/movable_parent = parent
M.set_glide_size(movable_parent.glide_size)
M.updating_glide_size = FALSE
handle_vehicle_offsets(movable_parent.dir)
/datum/component/riding/proc/handle_vehicle_layer(dir)
@@ -67,8 +70,11 @@
var/atom/movable/movable_parent = parent
if (isnull(dir))
dir = movable_parent.dir
for (var/buckled_mob in movable_parent.buckled_mobs)
ride_check(buckled_mob)
movable_parent.set_glide_size(DELAY_TO_GLIDE_SIZE(vehicle_move_delay))
for (var/m in movable_parent.buckled_mobs)
ride_check(m)
var/mob/buckled_mob = m
buckled_mob.set_glide_size(movable_parent.glide_size)
handle_vehicle_offsets(dir)
handle_vehicle_layer(dir)
+34 -15
View File
@@ -261,20 +261,21 @@
/atom/movable/proc/Move_Pulled(atom/A)
if(!pulling)
return
return FALSE
if(pulling.anchored || pulling.move_resist > move_force || !pulling.Adjacent(src))
stop_pulling()
return
return FALSE
if(isliving(pulling))
var/mob/living/L = pulling
if(L.buckled && L.buckled.buckle_prevents_pull) //if they're buckled to something that disallows pulling, prevent it
stop_pulling()
return
return FALSE
if(A == loc && pulling.density)
return
if(!Process_Spacemove(get_dir(pulling.loc, A)))
return
step(pulling, get_dir(pulling.loc, A))
return FALSE
var/move_dir = get_dir(pulling.loc, A)
if(!Process_Spacemove(move_dir))
return FALSE
pulling.Move(get_step(pulling.loc, move_dir), move_dir, glide_size)
return TRUE
/mob/living/Move_Pulled(atom/A)
@@ -303,11 +304,20 @@
if(pulledby && moving_diagonally != FIRST_DIAG_STEP && get_dist(src, pulledby) > 1) //separated from our puller and not in the middle of a diagonal move.
pulledby.stop_pulling()
/atom/movable/proc/set_glide_size(target = 8)
SEND_SIGNAL(src, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, target)
glide_size = target
for(var/m in buckled_mobs)
var/mob/buckled_mob = m
buckled_mob.set_glide_size(target)
////////////////////////////////////////
// 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, direct=0)
/atom/movable/Move(atom/newloc, direct=0, glide_size_override = 0)
. = FALSE
if(!newloc || newloc == loc)
return
@@ -353,7 +363,7 @@
////////////////////////////////////////
/atom/movable/Move(atom/newloc, direct)
/atom/movable/Move(atom/newloc, direct, glide_size_override = 0)
var/atom/movable/pullee = pulling
var/turf/T = loc
if(!moving_from_pull)
@@ -361,6 +371,9 @@
if(!loc || !newloc)
return FALSE
var/atom/oldloc = loc
//Early override for some cases like diagonal movement
if(glide_size_override)
set_glide_size(glide_size_override)
if(loc != newloc)
if (!(direct & (direct - 1))) //Cardinal move
@@ -433,13 +446,19 @@
//puller and pullee more than one tile away or in diagonal position
if(get_dist(src, pulling) > 1 || (moving_diagonally != SECOND_DIAG_STEP && ((pull_dir - 1) & pull_dir)))
pulling.moving_from_pull = src
pulling.Move(T, get_dir(pulling, T)) //the pullee tries to reach our previous position
pulling.Move(T, get_dir(pulling, T), glide_size) //the pullee tries to reach our previous position
pulling.moving_from_pull = null
check_pulling()
//glide_size strangely enough can change mid movement animation and update correctly while the animation is playing
//This means that if you don't override it late like this, it will just be set back by the movement update that's called when you move turfs.
if(glide_size_override)
set_glide_size(glide_size_override)
last_move = direct
setDir(direct)
if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc,direct)) //movement failed due to buckled mob(s)
if(. && has_buckled_mobs() && !handle_buckled_mob_movement(loc, direct, glide_size_override)) //movement failed due to buckled mob(s)
return FALSE
//Called after a successful Move(). By this point, we've already moved
@@ -722,16 +741,16 @@
if (quickstart)
TT.tick()
/atom/movable/proc/handle_buckled_mob_movement(newloc,direct)
/atom/movable/proc/handle_buckled_mob_movement(newloc, direct, glide_size_override)
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
if(!buckled_mob.Move(newloc, direct))
if(!buckled_mob.Move(newloc, direct, glide_size_override))
forceMove(buckled_mob.loc)
last_move = buckled_mob.last_move
inertia_dir = last_move
buckled_mob.inertia_dir = last_move
return 0
return 1
return FALSE
return TRUE
/atom/movable/proc/force_pushed(atom/movable/pusher, force = MOVE_FORCE_DEFAULT, direction)
return FALSE
+2
View File
@@ -617,10 +617,12 @@
var/move_result = 0
var/oldloc = loc
if(internal_damage & MECHA_INT_CONTROL_LOST)
set_glide_size(DELAY_TO_GLIDE_SIZE(step_in))
move_result = mechsteprand()
else if(dir != direction && (!strafe || occupant.client.keys_held["Alt"]))
move_result = mechturn(direction)
else
set_glide_size(DELAY_TO_GLIDE_SIZE(step_in))
move_result = mechstep(direction)
if(move_result || loc != oldloc)// halfway done diagonal move still returns false
use_power(step_energy_drain)
+2
View File
@@ -99,6 +99,7 @@
buckled_mobs |= M
M.update_mobility()
M.throw_alert("buckled", /obj/screen/alert/restrained/buckled)
M.set_glide_size(glide_size)
post_buckle_mob(M)
SEND_SIGNAL(src, COMSIG_MOVABLE_BUCKLE, M, force)
@@ -118,6 +119,7 @@
buckled_mob.set_anchored(initial(buckled_mob.anchored))
buckled_mob.update_mobility()
buckled_mob.clear_alert("buckled")
buckled_mob.set_glide_size(DELAY_TO_GLIDE_SIZE(buckled_mob.total_multiplicative_slowdown()))
buckled_mobs -= buckled_mob
SEND_SIGNAL(src, COMSIG_MOVABLE_UNBUCKLE, buckled_mob, force)
@@ -136,12 +136,13 @@
if(current_tube == null)
setDir(next_dir)
Move(get_step(loc, dir), dir) // Allow collisions when leaving the tubes.
Move(get_step(loc, dir), dir, DELAY_TO_GLIDE_SIZE(exit_delay)) // Allow collisions when leaving the tubes.
break
last_delay = current_tube.enter_delay(src, next_dir)
sleep(last_delay)
setDir(next_dir)
set_glide_size(DELAY_TO_GLIDE_SIZE(last_delay + exit_delay))
forceMove(next_loc) // When moving from one tube to another, skip collision and such.
density = current_tube.density
+8 -5
View File
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
#define SAVEFILE_VERSION_MAX 36
#define SAVEFILE_VERSION_MAX 37
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -69,6 +69,9 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
if(key_bindings["ShiftQ"] == "quick_equip_suit_storage")
key_bindings["ShiftQ"] = list("quick_equip_suit_storage")
if(current_version < 37)
if(clientfps == 0)
clientfps = -1
/datum/preferences/proc/update_character(current_version, savefile/S)
return
@@ -153,8 +156,8 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
fdel(bacpath) //only keep 1 version of backup
fcopy(S, bacpath) //byond helpfully lets you use a savefile for the first arg.
update_preferences(needs_update, S) //needs_update = savefile_version if we need an update (positive integer)
//Sanitize
asaycolor = sanitize_ooccolor(sanitize_hexcolor(asaycolor, 6, 1, initial(asaycolor)))
@@ -188,11 +191,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
pda_style = sanitize_inlist(pda_style, GLOB.pda_styles, initial(pda_style))
pda_color = sanitize_hexcolor(pda_color, 6, 1, initial(pda_color))
key_bindings = sanitize_keybindings(key_bindings)
if(needs_update >= 0) //save the updated version
var/old_default_slot = default_slot
var/old_max_save_slots = max_save_slots
for (var/slot in S.dir) //but first, update all current character slots.
if (copytext(slot, 1, 10) != "character")
continue
+3 -1
View File
@@ -320,11 +320,13 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
return
ghostize(FALSE)
/mob/dead/observer/Move(NewLoc, direct)
/mob/dead/observer/Move(NewLoc, direct, glide_size_override = 32)
if(updatedir)
setDir(direct)//only update dir if we actually need it, so overlays won't spin on base sprites that don't have directions of their own
var/oldloc = loc
if(glide_size_override)
set_glide_size(glide_size_override)
if(NewLoc)
forceMove(NewLoc)
update_parallax_contents()
@@ -3,7 +3,7 @@
real_name = "Unknown"
icon = 'icons/mob/human.dmi'
icon_state = "human_basic"
appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE
appearance_flags = KEEP_TOGETHER|TILE_BOUND|PIXEL_SCALE|LONG_GLIDE
hud_possible = list(HEALTH_HUD,STATUS_HUD,ID_HUD,WANTED_HUD,IMPLOYAL_HUD,IMPCHEM_HUD,IMPTRACK_HUD, NANITE_HUD, DIAG_NANITE_FULL_HUD,ANTAG_HUD,GLAND_HUD,SENTIENT_DISEASE_HUD,FAN_HUD)
hud_type = /datum/hud/human
possible_a_intents = list(INTENT_HELP, INTENT_DISARM, INTENT_GRAB, INTENT_HARM)
+4 -4
View File
@@ -233,8 +233,8 @@
var/current_dir
if(isliving(AM))
current_dir = AM.dir
if(step(AM, t))
step(src, t)
if(AM.Move(get_step(AM.loc, t), t, glide_size))
Move(get_step(loc, t), t)
if(current_dir)
AM.setDir(current_dir)
now_pushing = FALSE
@@ -640,12 +640,12 @@
/mob/living/proc/update_damage_overlays()
return
/mob/living/Move(atom/newloc, direct)
/mob/living/Move(atom/newloc, direct, glide_size_override)
if(lying_angle != 0)
lying_angle_on_movement(direct)
if (buckled && buckled.loc != newloc) //not updating position
if (!buckled.anchored)
return buckled.Move(newloc, direct)
return buckled.Move(newloc, direct, glide_size)
else
return FALSE
@@ -24,7 +24,6 @@
health = 50
maxHealth = 50
speed = 10
glide_size = 2
held_state = "sloth"
pet_bonus = TRUE
pet_bonus_emote = "slowly smiles!"
@@ -48,7 +48,7 @@
vision_range = 13
wander = FALSE
elimination = TRUE
appearance_flags = 0
appearance_flags = LONG_GLIDE
mouse_opacity = MOUSE_OPACITY_ICON
attack_action_types = list(/datum/action/innate/megafauna_attack/create_skull,
/datum/action/innate/megafauna_attack/charge_target,
+5 -1
View File
@@ -18,6 +18,9 @@
throwforce = 10
blocks_emissive = EMISSIVE_BLOCK_GENERIC
///when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace.
vis_flags = VIS_INHERIT_PLANE
var/lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
var/datum/mind/mind
var/static/next_mob_id = 0
@@ -216,4 +219,5 @@
/// Used for tracking last uses of emotes for cooldown purposes
var/list/emotes_used
vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of mob in openspace.
///Whether the mob is updating glide size when movespeed updates or not
var/updating_glide_size = TRUE
+2
View File
@@ -118,6 +118,7 @@
return FALSE
//We are now going to move
var/add_delay = mob.cached_multiplicative_slowdown
mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay * ( (NSCOMPONENT(direct) && EWCOMPONENT(direct)) ? 2 : 1 ) )) // set it now in case of pulled objects
if(old_move_delay + (add_delay*MOVEMENT_DELAY_BUFFER_DELTA) + MOVEMENT_DELAY_BUFFER > world.time)
move_delay = old_move_delay
else
@@ -140,6 +141,7 @@
if((direct & (direct - 1)) && mob.loc == n) //moved diagonally successfully
add_delay *= 2
mob.set_glide_size(DELAY_TO_GLIDE_SIZE(add_delay))
move_delay += add_delay
if(.) // If mob is null here, we deserve the runtime
if(mob.throwing)
@@ -10,7 +10,7 @@
move_resist = INFINITY
layer = MASSIVE_OBJ_LAYER
light_range = 6
appearance_flags = 0
appearance_flags = LONG_GLIDE
var/current_size = 1
var/allowed_size = 1
var/contained = 1 //Are we going to move around?
+3 -1
View File
@@ -72,15 +72,17 @@
// movement process, persists while holder is moving through pipes
/obj/structure/disposalholder/proc/move()
set waitfor = FALSE
var/ticks = 1
var/obj/structure/disposalpipe/last
while(active)
var/obj/structure/disposalpipe/curr = loc
last = curr
set_glide_size(DELAY_TO_GLIDE_SIZE(ticks * world.tick_lag))
curr = curr.transfer(src)
if(!curr && active)
last.expel(src, loc, dir)
stoplag()
ticks = stoplag()
if(!(count--))
active = FALSE
@@ -1055,7 +1055,6 @@
throwforce = 10
throw_speed = 0.1
throw_range = 28
glide_size = 2
flags_1 = CONDUCT_1
max_amount = 60
turf_type = /turf/open/floor/sepia
+1
View File
@@ -78,6 +78,7 @@
#include "code\__DEFINES\mobs.dm"
#include "code\__DEFINES\monkeys.dm"
#include "code\__DEFINES\move_force.dm"
#include "code\__DEFINES\movement.dm"
#include "code\__DEFINES\movespeed_modification.dm"
#include "code\__DEFINES\nanites.dm"
#include "code\__DEFINES\networks.dm"