mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-26 06:22:26 +01:00
SSthrowing (#19421)
Ported SSThrowing from TG, to handle throwings. Updated movement system to the latest iteration, made it a datum as per latest iteration. Updated pass/hit handling of atoms, introduced pass_flag_self to determine what atoms allow to pass. Moved procs and defines around to make them more organized.
This commit is contained in:
@@ -79,7 +79,7 @@ SUBSYSTEM_DEF(mob_ai)
|
||||
|
||||
/mob/proc/on_think_disabled()
|
||||
walk_to(src, 0)
|
||||
SSmove_manager.stop_looping(src)
|
||||
QDEL_NULL(move_packet)
|
||||
|
||||
/mob/proc/on_think_enabled()
|
||||
return
|
||||
|
||||
@@ -1,174 +0,0 @@
|
||||
/**
|
||||
* 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/controller/subsystem/move_manager/proc/add_to_loop] helper procs that use them
|
||||
*
|
||||
**/
|
||||
SUBSYSTEM_DEF(move_manager)
|
||||
name = "Movement Handler"
|
||||
flags = SS_NO_INIT | SS_NO_FIRE
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
///Adds a movable thing to a movement subsystem. Returns TRUE if it all worked, FALSE if it failed somehow
|
||||
/datum/controller/subsystem/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/controller/subsystem/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
|
||||
@@ -135,9 +135,6 @@
|
||||
if(flags & MOVEMENT_LOOP_IGNORE_GLIDE)
|
||||
return
|
||||
|
||||
//No gliding adjustment, for now
|
||||
//moving.set_glide_size(MOVEMENT_ADJUSTED_GLIDE_SIZE(delay, visual_delay))
|
||||
|
||||
///Handles the actual move, overriden by children
|
||||
///Returns FALSE if nothing happen, TRUE otherwise
|
||||
/datum/move_loop/proc/move()
|
||||
@@ -163,7 +160,7 @@
|
||||
status &= ~MOVELOOP_STATUS_PAUSED
|
||||
|
||||
///Removes the atom from some movement subsystem. Defaults to SSmovement
|
||||
/datum/controller/subsystem/move_manager/proc/stop_looping(atom/movable/moving, datum/controller/subsystem/movement/subsystem = SSmovement)
|
||||
/datum/move_manager/proc/stop_looping(atom/movable/moving, datum/controller/subsystem/movement/subsystem = SSmovement)
|
||||
var/datum/movement_packet/our_info = moving.move_packet
|
||||
if(!our_info)
|
||||
return FALSE
|
||||
@@ -184,7 +181,7 @@
|
||||
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
|
||||
*
|
||||
**/
|
||||
/datum/controller/subsystem/move_manager/proc/move(moving, direction, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
/datum/move_manager/proc/move(moving, direction, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
return add_to_loop(moving, subsystem, /datum/move_loop/move, priority, flags, extra_info, delay, timeout, direction)
|
||||
|
||||
///Replacement for walk()
|
||||
@@ -204,8 +201,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)
|
||||
moving.Move(get_step(moving, direction), direction, FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
|
||||
// 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
|
||||
@@ -226,7 +222,7 @@
|
||||
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
|
||||
*
|
||||
**/
|
||||
/datum/controller/subsystem/move_manager/proc/force_move_dir(moving, direction, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
/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
|
||||
@@ -283,7 +279,7 @@
|
||||
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
|
||||
*
|
||||
**/
|
||||
/datum/controller/subsystem/move_manager/proc/force_move(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
/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
|
||||
@@ -301,23 +297,23 @@
|
||||
* 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
|
||||
* * repath_delay - How often we're allowed to recalculate our path
|
||||
* * max_path_length - The maximum number of steps we can take in a given path to search (default: 30, 0 = infinite)
|
||||
* * miminum_distance - Minimum distance to the target before path returns, could be used to get near a target, but not right to it - for an AI mob with a gun, for example
|
||||
* * access - A list representing what access we have and what doors we can open
|
||||
* * simulated_only - Whether we consider turfs without atmos simulation (AKA do we want to ignore space)
|
||||
* * avoid - If we want to avoid a specific turf, like if we're a mulebot who already got blocked by some turf
|
||||
* * skip_first - Whether or not to delete the first item in the path. This would be done because the first item is the starting tile, which can break things
|
||||
* * 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
|
||||
* 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
|
||||
* repath_delay - How often we're allowed to recalculate our path
|
||||
* max_path_length - The maximum number of steps we can take in a given path to search (default: 30, 0 = infinite)
|
||||
* miminum_distance - Minimum distance to the target before path returns, could be used to get near a target, but not right to it - for an AI mob with a gun, for example
|
||||
* access - A list representing what access we have and what doors we can open
|
||||
* simulated_only - Whether we consider turfs without atmos simulation (AKA do we want to ignore space)
|
||||
* avoid - If we want to avoid a specific turf, like if we're a mulebot who already got blocked by some turf
|
||||
* skip_first - Whether or not to delete the first item in the path. This would be done because the first item is the starting tile, which can break things
|
||||
* 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/controller/subsystem/move_manager/proc/jps_move(moving,
|
||||
/datum/move_manager/proc/jps_move(moving,
|
||||
chasing,
|
||||
delay,
|
||||
timeout,
|
||||
@@ -441,8 +437,7 @@
|
||||
|
||||
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))
|
||||
moving.Move(next_step, get_dir(moving, next_step))
|
||||
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
|
||||
@@ -486,17 +481,17 @@
|
||||
* 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
|
||||
* * min_dist - the closest we're allower to get to the target
|
||||
* * 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
|
||||
* moving - The atom we want to move
|
||||
* chasing - The atom we want to move towards
|
||||
* min_dist - the closest we're allower to get to the target
|
||||
* 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/controller/subsystem/move_manager/proc/move_to(moving, chasing, min_dist, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
/datum/move_manager/proc/move_to(moving, chasing, min_dist, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
return add_to_loop(moving, subsystem, /datum/move_loop/has_target/dist_bound/move_to, priority, flags, extra_info, delay, timeout, chasing, min_dist)
|
||||
|
||||
///Wrapper around walk_to()
|
||||
@@ -511,9 +506,7 @@
|
||||
return
|
||||
var/atom/old_loc = moving.loc
|
||||
var/turf/next = get_step_to(moving, target)
|
||||
//This used to be `moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))` but our system is different and
|
||||
//putting a 4th or more parameters causes the gliding to catch fire, hence...
|
||||
moving.Move(next, get_dir(moving, next))
|
||||
moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
|
||||
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
|
||||
|
||||
/**
|
||||
@@ -522,17 +515,17 @@
|
||||
* 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
|
||||
* * max_dist - the furthest away from the target we're allowed to get
|
||||
* * 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
|
||||
* moving - The atom we want to move
|
||||
* chasing - The atom we want to move towards
|
||||
* max_dist - the furthest away from the target we're allowed to get
|
||||
* 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/controller/subsystem/move_manager/proc/move_away(moving, chasing, max_dist, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
/datum/move_manager/proc/move_away(moving, chasing, max_dist, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
return add_to_loop(moving, subsystem, /datum/move_loop/has_target/dist_bound/move_away, priority, flags, extra_info, delay, timeout, chasing, max_dist)
|
||||
|
||||
///Wrapper around walk_away()
|
||||
@@ -547,8 +540,7 @@
|
||||
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))
|
||||
moving.Move(next, get_dir(moving, next))
|
||||
moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
|
||||
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
|
||||
|
||||
|
||||
@@ -558,17 +550,17 @@
|
||||
* 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
|
||||
* * home - Should we move towards the object at all times? Or launch towards them, but allow walls and such to take us off track. Defaults to FALSE
|
||||
* * 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
|
||||
* 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
|
||||
* home - Should we move towards the object at all times? Or launch towards them, but allow walls and such to take us off track. Defaults to FALSE
|
||||
* 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/controller/subsystem/move_manager/proc/move_towards(atom/movable/moving, atom/chasing, delay, home, timeout, datum/controller/subsystem/movement/subsystem, priority, flags, datum/extra_info)
|
||||
/datum/move_manager/proc/move_towards(moving, chasing, delay, home, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
return add_to_loop(moving, subsystem, /datum/move_loop/has_target/move_towards, priority, flags, extra_info, delay, timeout, chasing, home)
|
||||
|
||||
/**
|
||||
@@ -587,7 +579,7 @@
|
||||
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
|
||||
*
|
||||
**/
|
||||
/datum/controller/subsystem/move_manager/proc/home_onto(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
/datum/move_manager/proc/home_onto(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
return move_towards(moving, chasing, delay, TRUE, timeout, subsystem, priority, flags, extra_info)
|
||||
|
||||
///Used as a alternative to walk_towards
|
||||
@@ -650,8 +642,7 @@
|
||||
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))
|
||||
moving.Move(moving_towards, get_dir(moving, moving_towards))
|
||||
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))
|
||||
@@ -724,7 +715,7 @@
|
||||
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
|
||||
*
|
||||
**/
|
||||
/datum/controller/subsystem/move_manager/proc/move_towards_legacy(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
/datum/move_manager/proc/move_towards_legacy(moving, chasing, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
return add_to_loop(moving, subsystem, /datum/move_loop/has_target/move_towards_budget, priority, flags, extra_info, delay, timeout, chasing)
|
||||
|
||||
///The actual implementation of walk_towards()
|
||||
@@ -733,8 +724,7 @@
|
||||
/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))
|
||||
moving.Move(target_turf, get_dir(moving, target_turf))
|
||||
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
|
||||
|
||||
/**
|
||||
@@ -751,7 +741,7 @@
|
||||
* 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/controller/subsystem/move_manager/proc/freeze(moving, halted_turf, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
/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)
|
||||
|
||||
/// As close as you can get to a "do-nothing" move loop, the pure intention of this is to absolutely resist all and any automated movement until the move loop times out.
|
||||
@@ -775,7 +765,7 @@
|
||||
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
|
||||
*
|
||||
**/
|
||||
/datum/controller/subsystem/move_manager/proc/move_rand(moving, directions, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
/datum/move_manager/proc/move_rand(moving, directions, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
if(!directions)
|
||||
directions = GLOB.alldirs
|
||||
return add_to_loop(moving, subsystem, /datum/move_loop/move_rand, priority, flags, extra_info, delay, timeout, directions)
|
||||
@@ -807,8 +797,7 @@
|
||||
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))
|
||||
moving.Move(moving_towards, testdir)
|
||||
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
|
||||
@@ -828,7 +817,7 @@
|
||||
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
|
||||
*
|
||||
**/
|
||||
/datum/controller/subsystem/move_manager/proc/move_to_rand(moving, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
/datum/move_manager/proc/move_to_rand(moving, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
return add_to_loop(moving, subsystem, /datum/move_loop/move_to_rand, priority, flags, extra_info, delay, timeout)
|
||||
|
||||
///Wrapper around step_rand
|
||||
@@ -837,8 +826,7 @@
|
||||
/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))
|
||||
moving.Move(next, get_dir(moving, next))
|
||||
moving.Move(next, get_dir(moving, next), FALSE, !(flags & MOVEMENT_LOOP_NO_DIR_UPDATE))
|
||||
return old_loc != moving?.loc ? MOVELOOP_SUCCESS : MOVELOOP_FAILURE
|
||||
|
||||
/**
|
||||
@@ -855,13 +843,13 @@
|
||||
* flags - Set of bitflags that effect move loop behavior in some way. Check _DEFINES/movement.dm
|
||||
*
|
||||
**/
|
||||
// /datum/controller/subsystem/move_manager/proc/move_disposals(moving, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
// /datum/move_manager/proc/move_disposals(moving, delay, timeout, subsystem, priority, flags, datum/extra_info)
|
||||
// return add_to_loop(moving, subsystem, /datum/move_loop/disposal_holder, priority, flags, extra_info, delay, timeout)
|
||||
|
||||
// /// Disposal holders need to move through a chain of pipes
|
||||
// /// Rather then through the world. This supports this
|
||||
// /// If this ever changes, get rid of this, add drift component like logic to the holder
|
||||
// /// And move them to move()
|
||||
/// Disposal holders need to move through a chain of pipes
|
||||
/// Rather then through the world. This supports this
|
||||
/// If this ever changes, get rid of this, add drift component like logic to the holder
|
||||
/// And move them to move()
|
||||
// /datum/move_loop/disposal_holder
|
||||
|
||||
// /datum/move_loop/disposal_holder/setup(delay = 1, timeout = INFINITY)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
MOVEMENT_SUBSYSTEM_DEF(spacedrift)
|
||||
name = "Space Drift"
|
||||
priority = FIRE_PRIORITY_SPACEDRIFT
|
||||
flags = SS_NO_INIT|SS_TICKER
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
@@ -0,0 +1,242 @@
|
||||
#define MAX_THROWING_DIST 1280 // 5 z-levels on default width
|
||||
#define MAX_TICKS_TO_MAKE_UP 3 //how many missed ticks will we attempt to make up for this run.
|
||||
|
||||
SUBSYSTEM_DEF(throwing)
|
||||
name = "Throwing"
|
||||
priority = FIRE_PRIORITY_THROWING
|
||||
wait = 1
|
||||
flags = SS_NO_INIT|SS_KEEP_TIMING|SS_TICKER
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
|
||||
var/list/currentrun
|
||||
var/list/processing = list()
|
||||
|
||||
/datum/controller/subsystem/throwing/stat_entry(msg)
|
||||
msg = "P:[length(processing)]"
|
||||
return ..()
|
||||
|
||||
|
||||
/datum/controller/subsystem/throwing/fire(resumed = 0)
|
||||
if (!resumed)
|
||||
src.currentrun = processing.Copy()
|
||||
|
||||
//cache for sanic speed (lists are references anyways)
|
||||
var/list/currentrun = src.currentrun
|
||||
|
||||
while(length(currentrun))
|
||||
var/atom/movable/AM = currentrun[currentrun.len]
|
||||
var/datum/thrownthing/TT = currentrun[AM]
|
||||
currentrun.len--
|
||||
if (QDELETED(AM) || QDELETED(TT))
|
||||
processing -= AM
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
continue
|
||||
|
||||
TT.tick()
|
||||
|
||||
if (MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
currentrun = null
|
||||
|
||||
/datum/thrownthing
|
||||
///Defines the atom that has been thrown (Objects and Mobs, mostly.)
|
||||
var/atom/movable/thrownthing
|
||||
///Weakref to the original intended target of the throw, to prevent hardDels
|
||||
var/datum/weakref/initial_target
|
||||
///The turf that the target was on, if it's not a turf itself.
|
||||
var/turf/target_turf
|
||||
///The turf that we were thrown from.
|
||||
var/turf/starting_turf
|
||||
///If the target happens to be a carbon and that carbon has a body zone aimed at, this is carried on here.
|
||||
var/target_zone
|
||||
///The initial direction of the thrower of the thrownthing for building the trajectory of the throw.
|
||||
var/init_dir
|
||||
///The maximum number of turfs that the thrownthing will travel to reach it's target.
|
||||
var/maxrange
|
||||
///Turfs to travel per tick
|
||||
var/speed
|
||||
///If a mob is the one who has thrown the object, then it's moved here. This can be null and must be null checked before trying to use it.
|
||||
var/datum/weakref/thrower
|
||||
///A variable that helps in describing objects thrown at an angle, if it should be moved diagonally first or last.
|
||||
var/diagonals_first
|
||||
///Set to TRUE if the throw is exclusively diagonal (45 Degree angle throws for example)
|
||||
var/pure_diagonal
|
||||
///Tracks how far a thrownthing has traveled mid-throw for the purposes of maxrange
|
||||
var/dist_travelled = 0
|
||||
///The start_time obtained via world.time for the purposes of tiles moved/tick.
|
||||
var/start_time
|
||||
///Distance to travel in the X axis/direction.
|
||||
var/dist_x
|
||||
///Distance to travel in the y axis/direction.
|
||||
var/dist_y
|
||||
///The Horizontal direction we're traveling (EAST or WEST)
|
||||
var/dx
|
||||
///The VERTICAL direction we're traveling (NORTH or SOUTH)
|
||||
var/dy
|
||||
///The movement force provided to a given object in transit. More info on these in move_force.dm
|
||||
var/force = MOVE_FORCE_DEFAULT
|
||||
///If the throw is gentle, then the thrownthing is harmless on impact.
|
||||
var/gentle = FALSE
|
||||
///How many tiles that need to be moved in order to travel to the target.
|
||||
var/diagonal_error
|
||||
///If a thrown thing has a callback, it can be invoked here within thrownthing.
|
||||
var/datum/callback/callback
|
||||
///Mainly exists for things that would freeze a thrown object in place, like a timestop'd tile. Or a Tractor Beam.
|
||||
var/paused = FALSE
|
||||
///How long an object has been paused for, to be added to the travel time.
|
||||
var/delayed_time = 0
|
||||
///The last world.time value stored when the thrownthing was moving.
|
||||
var/last_move = 0
|
||||
|
||||
/datum/thrownthing/New(thrownthing, target, init_dir, maxrange, speed, thrower, diagonals_first, force, gentle, callback, target_zone)
|
||||
. = ..()
|
||||
src.thrownthing = thrownthing
|
||||
RegisterSignal(thrownthing, COMSIG_QDELETING, PROC_REF(on_thrownthing_qdel))
|
||||
src.starting_turf = get_turf(thrownthing)
|
||||
src.target_turf = get_turf(target)
|
||||
if(target_turf != target)
|
||||
src.initial_target = WEAKREF(target)
|
||||
src.init_dir = init_dir
|
||||
src.maxrange = maxrange
|
||||
src.speed = speed
|
||||
if(thrower)
|
||||
src.thrower = WEAKREF(thrower)
|
||||
src.diagonals_first = diagonals_first
|
||||
src.force = force
|
||||
src.gentle = gentle
|
||||
src.callback = callback
|
||||
src.target_zone = target_zone
|
||||
|
||||
/datum/thrownthing/Destroy()
|
||||
SSthrowing.processing -= thrownthing
|
||||
SSthrowing.currentrun -= thrownthing
|
||||
thrownthing.throwing = null
|
||||
thrownthing = null
|
||||
thrower = null
|
||||
initial_target = null
|
||||
callback = null
|
||||
return ..()
|
||||
|
||||
///Defines the datum behavior on the thrownthing's qdeletion event.
|
||||
/datum/thrownthing/proc/on_thrownthing_qdel(atom/movable/source, force)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
qdel(src)
|
||||
|
||||
/// Returns the mob thrower, or null
|
||||
/datum/thrownthing/proc/get_thrower()
|
||||
. = thrower?.resolve()
|
||||
if(isnull(.))
|
||||
thrower = null
|
||||
|
||||
/datum/thrownthing/proc/tick()
|
||||
var/atom/movable/AM = thrownthing
|
||||
if (!isturf(AM.loc) || !AM.throwing)
|
||||
finalize()
|
||||
return
|
||||
|
||||
if(paused)
|
||||
delayed_time += world.time - last_move
|
||||
return
|
||||
|
||||
var/atom/movable/actual_target = initial_target?.resolve()
|
||||
var/mob/mob_thrower = get_thrower()
|
||||
|
||||
if(dist_travelled) //to catch sneaky things moving on our tile while we slept
|
||||
for(var/atom/movable/obstacle as anything in get_turf(thrownthing))
|
||||
if (obstacle == thrownthing || (obstacle == mob_thrower && !ismob(thrownthing)))
|
||||
continue
|
||||
if(ismob(obstacle) && thrownthing.pass_flags & PASSMOB && (obstacle != actual_target))
|
||||
continue
|
||||
if(obstacle.pass_flags_self & LETPASSTHROW)
|
||||
continue
|
||||
if (obstacle == actual_target || (obstacle.density)) //Different from TG
|
||||
finalize(TRUE, obstacle)
|
||||
return
|
||||
|
||||
var/atom/step
|
||||
|
||||
last_move = world.time
|
||||
|
||||
//calculate how many tiles to move, making up for any missed ticks.
|
||||
var/tilestomove = CEILING(min(((((world.time+world.tick_lag) - start_time + delayed_time) * speed) - (dist_travelled ? dist_travelled : -1)), speed*MAX_TICKS_TO_MAKE_UP) * (world.tick_lag * SSthrowing.wait), 1)
|
||||
while (tilestomove-- > 0)
|
||||
if ((dist_travelled >= maxrange || AM.loc == target_turf) && AM.has_gravity(AM.loc))
|
||||
finalize()
|
||||
return
|
||||
|
||||
if (dist_travelled <= max(dist_x, dist_y)) //if we haven't reached the target yet we home in on it, otherwise we use the initial direction
|
||||
step = get_step(AM, get_dir(AM, target_turf))
|
||||
else
|
||||
step = get_step(AM, init_dir)
|
||||
|
||||
if (!pure_diagonal && !diagonals_first) // not a purely diagonal trajectory and we don't want all diagonal moves to be done first
|
||||
if (diagonal_error >= 0 && max(dist_x,dist_y) - dist_travelled != 1) //we do a step forward unless we're right before the target
|
||||
step = get_step(AM, dx)
|
||||
diagonal_error += (diagonal_error < 0) ? dist_x/2 : -dist_y
|
||||
|
||||
if (!step) // going off the edge of the map makes get_step return null, don't let things go off the edge
|
||||
finalize()
|
||||
return
|
||||
|
||||
if(!AM.Move(step, get_dir(AM, step))) // we hit something during our move... //Different from TG
|
||||
if(AM.throwing) // ...but finalize() wasn't called on Bump() because of a higher level definition that doesn't always call parent.
|
||||
finalize()
|
||||
return
|
||||
|
||||
dist_travelled++
|
||||
|
||||
if(actual_target && !(actual_target.pass_flags_self & LETPASSTHROW) && actual_target.loc == AM.loc) // we crossed a movable with no density (e.g. a mouse or APC) we intend to hit anyway.
|
||||
finalize(TRUE, actual_target)
|
||||
return
|
||||
|
||||
if (dist_travelled > MAX_THROWING_DIST)
|
||||
finalize()
|
||||
return
|
||||
|
||||
/datum/thrownthing/proc/finalize(hit = FALSE, target=null)
|
||||
set waitfor = FALSE
|
||||
//done throwing, either because it hit something or it finished moving
|
||||
if(!thrownthing)
|
||||
return
|
||||
thrownthing.throwing = null
|
||||
if (!hit)
|
||||
for (var/atom/movable/obstacle as anything in get_turf(thrownthing)) //looking for our target on the turf we land on.
|
||||
if (obstacle == target)
|
||||
hit = TRUE
|
||||
thrownthing.throw_impact(obstacle, src)
|
||||
if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing
|
||||
return //deletion should already be handled by on_thrownthing_qdel()
|
||||
break
|
||||
if (!hit)
|
||||
thrownthing.throw_impact(get_turf(thrownthing), src) // we haven't hit something yet and we still must, let's hit the ground.
|
||||
if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing
|
||||
return //deletion should already be handled by on_thrownthing_qdel()
|
||||
thrownthing.newtonian_move(init_dir)
|
||||
else
|
||||
thrownthing.newtonian_move(init_dir)
|
||||
|
||||
if(target)
|
||||
thrownthing.throw_impact(target, src)
|
||||
if(QDELETED(thrownthing)) //throw_impact can delete things, such as glasses smashing
|
||||
return //deletion should already be handled by on_thrownthing_qdel()
|
||||
|
||||
if (callback)
|
||||
callback.Invoke()
|
||||
|
||||
// if(!thrownthing.currently_z_moving) // I don't think you can zfall while thrown but hey, just in case.
|
||||
// var/turf/T = get_turf(thrownthing)
|
||||
// T?.zFall(thrownthing)
|
||||
|
||||
if(thrownthing)
|
||||
SEND_SIGNAL(thrownthing, COMSIG_MOVABLE_THROW_LANDED, src)
|
||||
var/turf/landed_turf = get_turf(thrownthing)
|
||||
if(landed_turf)
|
||||
SEND_SIGNAL(landed_turf, COMSIG_TURF_MOVABLE_THROW_LANDED, thrownthing)
|
||||
|
||||
qdel(src)
|
||||
|
||||
#undef MAX_THROWING_DIST
|
||||
#undef MAX_TICKS_TO_MAKE_UP
|
||||
Reference in New Issue
Block a user