mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-25 04:57:12 +01:00
Port /tg/ move manager, drift and jetpack components. (#27698)
* Port /tg/ move manager, drift and jetpack components. * don't add go through newtonian movement if not moved to a turf * various cleans for blood drifts and mob speed * fix slow meteors * why on fuck's earth aren't speedbikes vehicles * style lint * also wtf * okay i'm an idiot * fix meaty ore speed and blood decal double stepping * fix not unbuckling pulled object occupants * don't bother dealing with immovable rods just yet * exclude bubblegum and vetus from move manager for now * fix issues related to null weightless blood icons * reset blood icon state properly * fuck it, we'll deal with mobs when basic mobs happen * break infinite loop in decal splat
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
///Component that handles drifting
|
||||
///Manages a movement loop that actually does the legwork of moving someone
|
||||
///Alongside dealing with the post movement input blocking required to make things look nice
|
||||
/datum/component/drift
|
||||
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
|
||||
|
||||
/// Accepts three args. The direction to drift in, if the drift is instant or not, and if it's not instant, the delay on the start
|
||||
/datum/component/drift/Initialize(direction, instant = FALSE, start_delay = 0)
|
||||
if(!ismovable(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
. = ..()
|
||||
|
||||
var/flags = MOVEMENT_LOOP_OUTSIDE_CONTROL
|
||||
if(instant)
|
||||
flags |= MOVEMENT_LOOP_START_FAST
|
||||
var/atom/movable/movable_parent = parent
|
||||
drifting_loop = GLOB.move_manager.move(moving = parent, direction = direction, delay = movable_parent.inertia_move_delay, subsystem = SSspacedrift, priority = MOVEMENT_SPACE_PRIORITY, flags = flags)
|
||||
|
||||
if(!drifting_loop) //Really want to qdel here but can't
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
RegisterSignal(drifting_loop, COMSIG_MOVELOOP_START, PROC_REF(drifting_start))
|
||||
RegisterSignal(drifting_loop, COMSIG_MOVELOOP_STOP, PROC_REF(drifting_stop))
|
||||
RegisterSignal(drifting_loop, COMSIG_MOVELOOP_PREPROCESS_CHECK, PROC_REF(before_move))
|
||||
RegisterSignal(drifting_loop, COMSIG_MOVELOOP_POSTPROCESS, PROC_REF(after_move))
|
||||
RegisterSignal(drifting_loop, COMSIG_PARENT_QDELETING, PROC_REF(loop_death))
|
||||
RegisterSignal(movable_parent, COMSIG_MOVABLE_NEWTONIAN_MOVE, PROC_REF(newtonian_impulse))
|
||||
if(drifting_loop.status & MOVELOOP_STATUS_RUNNING)
|
||||
drifting_start(drifting_loop) // There's a good chance it'll autostart, gotta catch that
|
||||
|
||||
var/visual_delay = movable_parent.inertia_move_delay
|
||||
|
||||
// Start delay is essentially a more granular version of instant
|
||||
// Isn't used in the standard case, just for things that have odd wants
|
||||
if(!instant && start_delay)
|
||||
drifting_loop.pause_for(start_delay)
|
||||
visual_delay = start_delay
|
||||
|
||||
apply_initial_visuals(visual_delay)
|
||||
|
||||
/datum/component/drift/Destroy()
|
||||
inertia_last_loc = null
|
||||
if(!QDELETED(drifting_loop))
|
||||
qdel(drifting_loop)
|
||||
drifting_loop = null
|
||||
var/atom/movable/movable_parent = parent
|
||||
movable_parent.inertia_moving = FALSE
|
||||
return ..()
|
||||
|
||||
/datum/component/drift/proc/apply_initial_visuals(visual_delay)
|
||||
// If something "somewhere" doesn't want us to apply our glidesize delays, don't
|
||||
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))
|
||||
var/mob/mob_parent = parent
|
||||
//Ok this is slightly weird, but basically, we need to force the client to glide at our rate
|
||||
//Make sure moving into a space move looks like a space move essentially
|
||||
//There is an inbuilt assumption that gliding will be added as a part of a move call, but eh
|
||||
//It's ok if it's not, it's just important if it is.
|
||||
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
|
||||
var/atom/movable/movable_parent = parent
|
||||
inertia_last_loc = movable_parent.loc
|
||||
if(drifting_loop)
|
||||
drifting_loop.direction = inertia_direction
|
||||
if(!inertia_direction)
|
||||
qdel(src)
|
||||
return COMPONENT_MOVABLE_NEWTONIAN_BLOCK
|
||||
|
||||
/datum/component/drift/proc/drifting_start()
|
||||
SIGNAL_HANDLER
|
||||
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_UPDATE_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
|
||||
var/atom/movable/movable_parent = parent
|
||||
movable_parent.inertia_moving = FALSE
|
||||
ignore_next_glide = FALSE
|
||||
UnregisterSignal(movable_parent, list(COMSIG_MOVABLE_MOVED, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, COMSIG_ATOM_NO_LONGER_PULLING))
|
||||
|
||||
/datum/component/drift/proc/before_move(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
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
|
||||
if(result == MOVELOOP_FAILURE)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
var/atom/movable/movable_parent = parent
|
||||
movable_parent.setDir(old_dir)
|
||||
movable_parent.inertia_moving = FALSE
|
||||
if(movable_parent.Process_Spacemove(drifting_loop.direction, continuous_move = TRUE))
|
||||
glide_to_halt(visual_delay)
|
||||
return
|
||||
|
||||
inertia_last_loc = movable_parent.loc
|
||||
ignore_next_glide = TRUE
|
||||
|
||||
/datum/component/drift/proc/loop_death(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
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
|
||||
// This can happen, because signals once sent cannot be stopped
|
||||
if(QDELETED(src))
|
||||
return
|
||||
var/atom/movable/movable_parent = parent
|
||||
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)
|
||||
|
||||
/// 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, 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)
|
||||
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 / glide_size, 1) * world.tick_lag
|
||||
drifting_loop.pause_for(glide_delay)
|
||||
delayed = TRUE
|
||||
|
||||
/// 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
|
||||
// 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)
|
||||
|
||||
/datum/component/drift/proc/glide_to_halt(glide_for)
|
||||
if(!ismob(parent))
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
var/mob/mob_parent = parent
|
||||
var/client/our_client = mob_parent.client
|
||||
// If we're not active, don't do the glide because it'll look dumb as fuck
|
||||
if(!our_client || delayed)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
block_inputs_until = world.time + glide_for
|
||||
QDEL_IN(src, glide_for + 1)
|
||||
qdel(drifting_loop)
|
||||
RegisterSignal(parent, COMSIG_MOB_CLIENT_PRE_MOVE, PROC_REF(allow_final_movement))
|
||||
|
||||
/datum/component/drift/proc/allow_final_movement(datum/source)
|
||||
// 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
|
||||
if(world.time < block_inputs_until)
|
||||
return COMSIG_MOB_CLIENT_BLOCK_PRE_MOVE
|
||||
@@ -0,0 +1,152 @@
|
||||
// Welcome to the jetpack component
|
||||
// Apply this to something when you want it to be "like a jetpack"
|
||||
// So propulsion through space on move, that sort of thing
|
||||
/datum/component/jetpack
|
||||
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
|
||||
/// Checks to ensure if we can move & if we can activate
|
||||
var/datum/callback/check_on_move
|
||||
/// If we should stabilize ourselves when not drifting
|
||||
var/stabilize = FALSE
|
||||
/// The signal we listen for as an activation
|
||||
var/activation_signal
|
||||
/// The signal we listen for as a de-activation
|
||||
var/deactivation_signal
|
||||
/// The return flag our parent expects for a failed activation
|
||||
var/return_flag
|
||||
/// The effect system for the jet pack trail
|
||||
var/datum/effect_system/trail_follow/trail
|
||||
/// The typepath to instansiate our trail as, when we need it
|
||||
var/effect_type
|
||||
|
||||
/**
|
||||
* Arguments:
|
||||
* * stabilize - If we should drift when we finish moving, or sit stable in space]
|
||||
* * activation_signal - Signal we activate on
|
||||
* * deactivation_signal - Signal we deactivate on
|
||||
* * return_flag - Flag to return if activation fails
|
||||
* * check_on_move - Callback we call each time we attempt a move, we expect it to retun true if the move is ok, false otherwise. It expects an arg, TRUE if fuel should be consumed, FALSE othewise
|
||||
* * effect_type - Type of trail_follow to spawn
|
||||
*/
|
||||
/datum/component/jetpack/Initialize(stabilize, activation_signal, deactivation_signal, return_flag, datum/callback/check_on_move, datum/effect_system/trail_follow/effect_type)
|
||||
. = ..()
|
||||
if(!isatom(parent))
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
if(!activation_signal) // Can't activate? go away
|
||||
return COMPONENT_INCOMPATIBLE
|
||||
|
||||
RegisterSignal(parent, activation_signal, PROC_REF(activate))
|
||||
if(deactivation_signal)
|
||||
RegisterSignal(parent, deactivation_signal, PROC_REF(deactivate))
|
||||
|
||||
src.stabilize = stabilize
|
||||
src.check_on_move = check_on_move
|
||||
src.activation_signal = activation_signal
|
||||
src.deactivation_signal = deactivation_signal
|
||||
src.return_flag = return_flag
|
||||
src.effect_type = effect_type
|
||||
|
||||
/datum/component/jetpack/InheritComponent(datum/component/component, original, stabilize, activation_signal, deactivation_signal, return_flag, datum/callback/check_on_move, datum/effect_system/trail_follow/effect_type)
|
||||
UnregisterSignal(parent, src.activation_signal)
|
||||
if(src.deactivation_signal)
|
||||
UnregisterSignal(parent, src.deactivation_signal)
|
||||
RegisterSignal(parent, activation_signal, PROC_REF(activate))
|
||||
if(deactivation_signal)
|
||||
RegisterSignal(parent, deactivation_signal, PROC_REF(deactivate))
|
||||
|
||||
src.stabilize = stabilize
|
||||
src.check_on_move = check_on_move
|
||||
src.activation_signal = activation_signal
|
||||
src.deactivation_signal = deactivation_signal
|
||||
src.return_flag = return_flag
|
||||
src.effect_type = effect_type
|
||||
|
||||
if(trail && trail.effect_type != effect_type)
|
||||
setup_trail(trail.holder)
|
||||
|
||||
/datum/component/jetpack/Destroy(force)
|
||||
if(trail)
|
||||
QDEL_NULL(trail)
|
||||
check_on_move = null
|
||||
return ..()
|
||||
|
||||
/datum/component/jetpack/proc/setup_trail(mob/user)
|
||||
if(trail)
|
||||
QDEL_NULL(trail)
|
||||
|
||||
trail = new effect_type
|
||||
trail.auto_process = FALSE
|
||||
trail.set_up(user)
|
||||
trail.start()
|
||||
|
||||
/datum/component/jetpack/proc/activate(datum/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!check_on_move.Invoke(TRUE))
|
||||
return return_flag
|
||||
|
||||
RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(move_react))
|
||||
RegisterSignal(user, COMSIG_MOVABLE_PRE_MOVE, PROC_REF(pre_move_react))
|
||||
RegisterSignal(user, COMSIG_MOVABLE_SPACEMOVE, PROC_REF(spacemove_react))
|
||||
RegisterSignal(user, COMSIG_MOVABLE_DRIFT_VISUAL_ATTEMPT, PROC_REF(block_starting_visuals))
|
||||
RegisterSignal(user, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT, PROC_REF(ignore_ending_block))
|
||||
|
||||
setup_trail(user)
|
||||
|
||||
/datum/component/jetpack/proc/deactivate(datum/source, mob/user)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
|
||||
UnregisterSignal(user, COMSIG_MOVABLE_PRE_MOVE)
|
||||
UnregisterSignal(user, COMSIG_MOVABLE_SPACEMOVE)
|
||||
UnregisterSignal(user, COMSIG_MOVABLE_DRIFT_VISUAL_ATTEMPT)
|
||||
UnregisterSignal(user, COMSIG_MOVABLE_DRIFT_BLOCK_INPUT)
|
||||
|
||||
if(trail)
|
||||
QDEL_NULL(trail)
|
||||
|
||||
/datum/component/jetpack/proc/move_react(mob/user)
|
||||
SIGNAL_HANDLER
|
||||
if(!user || !user.client)//Don't allow jet self using
|
||||
return
|
||||
if(!isturf(user.loc))//You can't use jet in nowhere or from mecha/closet
|
||||
return
|
||||
if(user.mob_has_gravity() || user.buckled)//You don't want use jet in gravity or while buckled.
|
||||
return
|
||||
if(user.pulledby)//You can't use jet if someone pull you
|
||||
return
|
||||
if(user.throwing)//You can't use jet if you thrown
|
||||
return
|
||||
if(user.client.calculate_move_dir())//You use jet when press keys. yes.
|
||||
thrust()
|
||||
|
||||
/datum/component/jetpack/proc/pre_move_react(mob/user)
|
||||
SIGNAL_HANDLER
|
||||
if(!trail)
|
||||
return FALSE
|
||||
trail.oldposition = get_turf(user)
|
||||
|
||||
/datum/component/jetpack/proc/spacemove_react(mob/user, movement_dir, continuous_move)
|
||||
SIGNAL_HANDLER
|
||||
if(!continuous_move && movement_dir)
|
||||
return COMSIG_MOVABLE_STOP_SPACEMOVE
|
||||
// Check if we have the fuel to stop this. Do NOT cosume any fuel, just check
|
||||
// This is done because things other then us can use our fuel
|
||||
if(stabilize && check_on_move.Invoke(FALSE))
|
||||
return COMSIG_MOVABLE_STOP_SPACEMOVE
|
||||
|
||||
/// Returns true if the thrust went well, false otherwise
|
||||
/datum/component/jetpack/proc/thrust()
|
||||
if(!check_on_move.Invoke(TRUE))
|
||||
return FALSE
|
||||
trail.generate_effect()
|
||||
return TRUE
|
||||
|
||||
/// Basically, tell the drift component not to do its starting visuals, because they look dumb for us
|
||||
/datum/component/jetpack/proc/block_starting_visuals(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
return DRIFT_VISUAL_FAILED
|
||||
|
||||
/// If we're on, don't let the drift component block movements at the end since we can speed
|
||||
/datum/component/jetpack/proc/ignore_ending_block(datum/source)
|
||||
SIGNAL_HANDLER
|
||||
return DRIFT_ALLOW_INPUT
|
||||
@@ -70,7 +70,7 @@
|
||||
if(!turf_check(next, current))
|
||||
to_chat(user, "<span class='warning'>[movable_parent] cannot go onto [next]!</span>")
|
||||
return
|
||||
if(!Process_Spacemove(direction) || !isturf(movable_parent.loc))
|
||||
if(GLOB.move_manager.processing_on(user, SSspacedrift) || !isturf(movable_parent.loc))
|
||||
return
|
||||
|
||||
step(movable_parent, direction)
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Acts as a namespace for movement packet/type related procs
|
||||
*
|
||||
* Exists to provide an in code implementation of movement looping
|
||||
* Replaces things like walk() or walk_to(), among others
|
||||
*
|
||||
* Because we're doing things in engine, we have a lot more control over how different operations are performed
|
||||
* We also get more say in when things happen, so we can subject movements to the whims of the master controller
|
||||
* Rather then using a fuck ton of cpu just moving mobs or meteors
|
||||
*
|
||||
* The goal is to keep the loops themselves reasonably barebone, and implement more advanced behavior and control via the signals
|
||||
*
|
||||
* This may be bypassed in cases where snowflakes are nessesary, or where performance is important. S not a hard and fast thing
|
||||
*
|
||||
* Every atom can have a movement packet, which contains information and behavior about currently active loops, and queuing info
|
||||
* Loops control how movement actually happens. So there's a "move in this direction" loop, a "move randomly" loop
|
||||
*
|
||||
* You can find the logic for this control in this file
|
||||
*
|
||||
* Specifics of how different loops operate can be found in the movement_types.dm file, alongside the [add to loop][/datum/move_manager/proc/add_to_loop] helper procs that use them
|
||||
*
|
||||
**/
|
||||
/datum/move_manager
|
||||
|
||||
GLOBAL_DATUM_INIT(move_manager, /datum/move_manager, new)
|
||||
|
||||
///Adds a movable thing to a movement subsystem. Returns TRUE if it all worked, FALSE if it failed somehow
|
||||
/datum/move_manager/proc/add_to_loop(atom/movable/thing_to_add, datum/controller/subsystem/movement/subsystem = SSmovement, datum/move_loop/loop_type, priority = MOVEMENT_DEFAULT_PRIORITY, flags, datum/extra_info)
|
||||
var/datum/movement_packet/our_data = thing_to_add.move_packet
|
||||
if(!our_data)
|
||||
our_data = new(thing_to_add)
|
||||
|
||||
var/list/arguments = args.Copy(2) //Drop the atom, since the movement packet already knows about it
|
||||
return our_data.add_loop(arglist(arguments))
|
||||
|
||||
///Returns the subsystem's loop if we're processing on it, null otherwise
|
||||
/datum/move_manager/proc/processing_on(atom/movable/packet_owner, datum/controller/subsystem/movement/subsystem)
|
||||
var/datum/movement_packet/packet = packet_owner.move_packet
|
||||
if(!packet)
|
||||
return
|
||||
var/datum/move_loop/linked_loop = packet.existing_loops[subsystem]
|
||||
if(!linked_loop)
|
||||
return
|
||||
if(linked_loop.flags & MOVEMENT_LOOP_IGNORE_PRIORITY)
|
||||
return linked_loop
|
||||
if(linked_loop != packet.running_loop)
|
||||
return
|
||||
return linked_loop
|
||||
|
||||
///A packet of information that describes the current state of a moving object
|
||||
/datum/movement_packet
|
||||
///Our parent atom
|
||||
var/atom/movable/parent
|
||||
///The move loop that's currently running, excluding those that ignore priority.
|
||||
var/datum/move_loop/running_loop
|
||||
/**
|
||||
* Flags passed from the move loop before it calls move() and unset right after.
|
||||
* Allows for properties of a move loop to be easily checked by mechanics outside of it.
|
||||
* Having this a bitfield rather than a type var means we don't get screwed over
|
||||
* if the move loop gets deleted mid-move, FYI.
|
||||
*/
|
||||
var/processing_move_loop_flags = NONE
|
||||
///Assoc list of subsystems -> loop datum. Only one datum is allowed per subsystem
|
||||
var/list/existing_loops = list()
|
||||
|
||||
/datum/movement_packet/New(atom/movable/parent)
|
||||
src.parent = parent
|
||||
parent.move_packet = src
|
||||
|
||||
/datum/movement_packet/Destroy(force)
|
||||
parent.move_packet = null
|
||||
parent = null
|
||||
for(var/datum/controller/subsystem/processor as anything in existing_loops)
|
||||
var/datum/move_loop/loop = existing_loops[processor]
|
||||
if(QDELETED(loop))
|
||||
continue
|
||||
qdel(loop)
|
||||
existing_loops.Cut()
|
||||
existing_loops = null //Catch anyone modifying this post del
|
||||
return ..()
|
||||
|
||||
///Adds a loop to our parent. Returns the created loop if a success, null otherwise
|
||||
/datum/movement_packet/proc/add_loop(datum/controller/subsystem/movement/subsystem, datum/move_loop/loop_type, priority, flags, datum/extra_info)
|
||||
var/datum/move_loop/existing_loop = existing_loops[subsystem]
|
||||
|
||||
if(existing_loop && existing_loop.priority > priority)
|
||||
if(!(existing_loop.flags & MOVEMENT_LOOP_IGNORE_PRIORITY) && !(flags & MOVEMENT_LOOP_IGNORE_PRIORITY))
|
||||
return //Give up
|
||||
|
||||
if(existing_loop?.compare_loops(arglist(args.Copy(2))))
|
||||
return //it already exists stop trying to make the same moveloop
|
||||
|
||||
var/datum/move_loop/new_loop = new loop_type(src, subsystem, parent, priority, flags, extra_info) //Pass the mob to move and ourselves in via new
|
||||
var/list/arguments = args.Copy(6) //Just send the args we've not already dealt with
|
||||
|
||||
var/worked_out = new_loop.setup(arglist(arguments)) //Here goes the rest
|
||||
if(!worked_out)
|
||||
qdel(new_loop)
|
||||
return
|
||||
|
||||
existing_loops[subsystem] = new_loop
|
||||
if(existing_loop)
|
||||
qdel(existing_loop) //We need to do this here because otherwise the packet would think it was empty, and self destruct
|
||||
contest_running_loop(new_loop)
|
||||
return new_loop
|
||||
|
||||
///Attempts to contest the current running move loop. Returns TRUE if the loop is active, FALSE otherwise
|
||||
/datum/movement_packet/proc/contest_running_loop(datum/move_loop/contestant)
|
||||
var/datum/controller/subsystem/movement/contesting_subsystem = contestant.controller
|
||||
|
||||
if(contestant.flags & MOVEMENT_LOOP_IGNORE_PRIORITY)
|
||||
contesting_subsystem.add_loop(contestant)
|
||||
return TRUE
|
||||
if(!running_loop)
|
||||
running_loop = contestant
|
||||
contesting_subsystem.add_loop(running_loop)
|
||||
return TRUE
|
||||
if(running_loop.priority > contestant.priority)
|
||||
return FALSE
|
||||
|
||||
var/datum/controller/subsystem/movement/current_subsystem = running_loop.controller
|
||||
|
||||
var/current_running_loop = running_loop
|
||||
running_loop = contestant
|
||||
current_subsystem.remove_loop(current_running_loop)
|
||||
if(running_loop != contestant) // A signal registrant could have messed with things
|
||||
return FALSE
|
||||
contesting_subsystem.add_loop(contestant)
|
||||
return TRUE
|
||||
|
||||
///Tries to figure out the current favorite loop to run. More complex then just deciding between two different loops, assumes no running loop currently exists
|
||||
/datum/movement_packet/proc/decide_on_running_loop()
|
||||
if(running_loop)
|
||||
return
|
||||
if(!length(existing_loops)) //Die
|
||||
qdel(src)
|
||||
return
|
||||
var/datum/move_loop/favorite
|
||||
for(var/datum/controller/subsystem/movement/owner as anything in existing_loops)
|
||||
var/datum/move_loop/checking = existing_loops[owner]
|
||||
if(checking.flags & MOVEMENT_LOOP_IGNORE_PRIORITY)
|
||||
continue
|
||||
if(favorite && favorite.priority > checking.priority)
|
||||
continue
|
||||
favorite = checking
|
||||
|
||||
if(!favorite) //This isn't an error state, since some loops ignore the concept of a running loop
|
||||
return
|
||||
|
||||
var/datum/controller/subsystem/movement/favorite_subsystem = favorite.controller
|
||||
|
||||
running_loop = favorite
|
||||
favorite_subsystem.add_loop(running_loop)
|
||||
|
||||
/datum/movement_packet/proc/remove_loop(datum/controller/subsystem/movement/remove_from, datum/move_loop/loop_to_remove)
|
||||
if(loop_to_remove == running_loop)
|
||||
running_loop = null
|
||||
remove_from.remove_loop(loop_to_remove)
|
||||
if(loop_to_remove.flags & MOVEMENT_LOOP_IGNORE_PRIORITY)
|
||||
remove_from.remove_loop(loop_to_remove)
|
||||
if(QDELETED(src))
|
||||
return
|
||||
if(existing_loops[remove_from] == loop_to_remove)
|
||||
existing_loops -= remove_from
|
||||
decide_on_running_loop()
|
||||
return
|
||||
|
||||
/datum/movement_packet/proc/remove_subsystem(datum/controller/subsystem/movement/remove)
|
||||
var/datum/move_loop/our_loop = existing_loops[remove]
|
||||
if(!our_loop)
|
||||
return FALSE
|
||||
qdel(our_loop)
|
||||
return TRUE
|
||||
Reference in New Issue
Block a user