Refactored movement observable away (#20083)

Refactored movement observable away, use only the signal.
Some tweaks to the signal.
This commit is contained in:
Fluffy
2024-10-26 15:53:07 +00:00
committed by GitHub
parent 3de4911dc8
commit d40d459d42
35 changed files with 532 additions and 434 deletions
+13
View File
@@ -1,5 +1,18 @@
// Stuff that is relatively "core" and is used in other defines/helpers
/**
* The game's world.icon_size. \
* Ideally divisible by 16. \
* Ideally a number, but it
* can be a string ("32x32"), so more exotic coders
* will be sad if you use this in math.
*/
#define ICON_SIZE_ALL 32
/// The X/Width dimension of ICON_SIZE. This will more than likely be the bigger axis.
#define ICON_SIZE_X 32
/// The Y/Height dimension of ICON_SIZE. This will more than likely be the smaller axis.
#define ICON_SIZE_Y 32
//Returns the hex value of a decimal number
//len == length of returned string
#define num2hex(X, len) num2text(X, len, 16)
-1
View File
@@ -21,7 +21,6 @@
// /turf signals
// /atom/movable signals
#define COMSIG_MOVABLE_MOVED "movable_moved"
#define COMSIG_MOVABLE_HEAR "movable_hear"
#define HEARING_MESSAGE 1
@@ -23,8 +23,16 @@
///from base of atom/has_gravity(): (turf/location, list/forced_gravities)
#define COMSIG_ATOM_HAS_GRAVITY "atom_has_gravity"
///called when an atom starts orbiting another atom: (atom)
#define COMSIG_ATOM_ORBIT_BEGIN "atom_orbit_begin"
///called when an atom stops orbiting another atom: (atom)
#define COMSIG_ATOM_ORBIT_STOP "atom_orbit_stop"
///from base of atom/throw_impact, sent by the target hit by a thrown object. (hit_atom, thrown_atom, datum/thrownthing/throwingdatum)
#define COMSIG_ATOM_PREHITBY "atom_pre_hitby"
#define COMSIG_HIT_PREVENTED (1<<0)
///from base of atom/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
#define COMSIG_ATOM_HITBY "atom_hitby"
/// Called on [/atom/SpinAnimation()] : (speed, loops, segments, angle)
#define COMSIG_ATOM_SPIN_ANIMATION "atom_spin_animation"
@@ -5,7 +5,8 @@
///from base of atom/movable/Moved(): (/atom)
#define COMSIG_MOVABLE_PRE_MOVE "movable_pre_move"
#define COMPONENT_MOVABLE_BLOCK_PRE_MOVE (1<<0)
///from base of atom/movable/Moved(): (atom/old_loc, dir, forced, list/old_locs)
#define COMSIG_MOVABLE_MOVED "movable_moved"
///from base of atom/movable/Cross(): (/atom/movable)
#define COMSIG_MOVABLE_CROSS "movable_cross"
///from base of atom/movable/Move(): (/atom/movable)
+41 -15
View File
@@ -218,27 +218,53 @@ round(cos_inv_third+sqrt3_sin, 0.001), round(cos_inv_third-sqrt3_sin, 0.001), ro
return COLOR_MATRIX_IDENTITY
CRASH(message)
///Animates source spinning around itself. For docmentation on the args, check atom/proc/SpinAnimation()
/atom/proc/do_spin_animation(speed = 1 SECONDS, loops = -1, segments = 3, angle = 120, parallel = TRUE)
var/list/matrices = list()
for(var/i in 1 to segments-1)
var/matrix/segment_matrix = matrix(transform)
segment_matrix.Turn(angle*i)
matrices += segment_matrix
var/matrix/last = matrix(transform)
matrices += last
speed /= segments
if(parallel)
animate(src, transform = matrices[1], time = speed, loop = loops, flags = ANIMATION_PARALLEL)
else
animate(src, transform = matrices[1], time = speed, loop = loops)
for(var/i in 2 to segments) //2 because 1 is covered above
animate(transform = matrices[i], time = speed)
//doesn't have an object argument because this is "Stacking" with the animate call above
//3 billion% intentional
/**
* Proc called when you want the atom to spin around the center of its icon (or where it would be if its transform var is translated)
* By default, it makes the atom spin forever and ever at a speed of 60 rpm.
*
* Arguments:
* * speed: how much it takes for the atom to complete one 360° rotation
* * loops: how many times do we want the atom to rotate
* * clockwise: whether the atom ought to spin clockwise or counter-clockwise
* * segments: in how many animate calls the rotation is split. Probably unnecessary, but you shouldn't set it lower than 3 anyway.
* * parallel: whether the animation calls have the ANIMATION_PARALLEL flag, necessary for it to run alongside concurrent animations.
*/
/atom/proc/SpinAnimation(speed = 1 SECONDS, loops = -1, clockwise = TRUE, segments = 3, parallel = TRUE)
if(!segments)
return
var/segment = 360/segments
if(!clockwise)
segment = -segment
SEND_SIGNAL(src, COMSIG_ATOM_SPIN_ANIMATION, speed, loops, segments, segment)
do_spin_animation(speed, loops, segments, segment, parallel)
/*############################
AURORA SNOWFLAKE SECTION
(Most are from Bay)
############################*/
/**
* Performs a spin/rotation animation on the atom's sprite.
*
* **Parameters**:
* - `speed` (int) - How quickly the atom should rotate.
* - `loops` (int) - How many times the spin animation should occur. Set to `-1` for infinite looping.
*/
/atom/proc/SpinAnimation(speed = 10, loops = -1)
var/matrix/m120 = matrix(transform).Update(rotation = 120)
var/matrix/m240 = matrix(transform).Update(rotation = 240)
var/matrix/m360 = matrix(transform).Update(rotation = 360)
animate(src, transform = m120, time = speed / 3, loops)
animate(transform = m240, time = speed / 3)
animate(transform = m360, time = speed / 3)
/**
* Performs a shaking animation on the atom's sprite.
*
+2 -1
View File
@@ -16,13 +16,14 @@
reenter_corpse() // (cloning scanner, body bag, closet, mech, etc)
return // seems legit.
orbiting?.end_orbit(src) // stop orbiting
// Things you might plausibly want to follow
if((ismob(A) && A != src) || istype(A,/obj/machinery/bot) || istype(A,/obj/singularity))
ManualFollow(A)
// Otherwise jump
else
stop_following()
forceMove(get_turf(A))
/mob/abstract/observer/ClickOn(var/atom/A, var/params)
-46
View File
@@ -1,46 +0,0 @@
SUBSYSTEM_DEF(orbit)
name = "Orbits"
priority = SS_PRIORITY_ORBIT
wait = 2
flags = SS_NO_INIT|SS_TICKER
runlevels = RUNLEVELS_PLAYING
var/list/currentrun = list()
var/list/processing = list()
/datum/controller/subsystem/orbit/Recover()
src.processing = SSorbit.processing
/datum/controller/subsystem/orbit/stat_entry(msg)
msg = "P:[processing.len]"
return ..()
/datum/controller/subsystem/orbit/fire(resumed = 0)
if (!resumed)
src.currentrun = processing.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while (currentrun.len)
var/datum/orbit/O = currentrun[currentrun.len]
currentrun.len--
if (!O)
processing -= O
if (MC_TICK_CHECK)
return
continue
if (!O.orbiter)
qdel(O)
if (MC_TICK_CHECK)
return
continue
if (O.lastprocess >= world.time) //we already checked recently
if (MC_TICK_CHECK)
return
continue
var/targetloc = get_turf(O.orbiting)
if (targetloc != O.lastloc || O.orbiter.loc != targetloc)
O.Check(targetloc)
if (MC_TICK_CHECK)
return
+186
View File
@@ -0,0 +1,186 @@
/datum/component/orbiter
can_transfer = TRUE
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/list/orbiter_list
var/datum/movement_detector/tracker
//radius: range to orbit at, radius of the circle formed by orbiting (in pixels)
//clockwise: whether you orbit clockwise or anti clockwise
//rotation_speed: how fast to rotate (how many ds should it take for a rotation to complete)
//rotation_segments: the resolution of the orbit circle, less = a more block circle, this can be used to produce hexagons (6 segments) triangles (3 segments), and so on, 36 is the best default.
//pre_rotation: Chooses to rotate src 90 degress towards the orbit dir (clockwise/anticlockwise), useful for things to go "head first" like ghosts
/datum/component/orbiter/Initialize(atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
if(!istype(orbiter) || !isatom(parent) || isarea(parent))
return COMPONENT_INCOMPATIBLE
orbiter_list = list()
begin_orbit(orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
/datum/component/orbiter/RegisterWithParent()
var/atom/target = parent
target.orbiters = src
if(ismovable(target))
tracker = new(target, CALLBACK(src, PROC_REF(move_react)))
// RegisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE, PROC_REF(orbiter_glide_size_update)) //Aurora doesn't vary glides
/datum/component/orbiter/UnregisterFromParent()
// UnregisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE) //Aurora doesn't vary glides
var/atom/target = parent
target.orbiters = null
QDEL_NULL(tracker)
/datum/component/orbiter/Destroy()
var/atom/master = parent
if(master.orbiters == src)
master.orbiters = null
for(var/i in orbiter_list)
end_orbit(i)
orbiter_list = null
return ..()
/datum/component/orbiter/InheritComponent(datum/component/orbiter/newcomp, original, atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
if(!newcomp)
begin_orbit(arglist(args.Copy(3)))
return
// The following only happens on component transfers
for(var/o in newcomp.orbiter_list)
var/atom/movable/incoming_orbiter = o
incoming_orbiter.orbiting = src
// It is important to transfer the signals so we don't get locked to the new orbiter component for all time
newcomp.UnregisterSignal(incoming_orbiter, COMSIG_MOVABLE_MOVED)
RegisterSignal(incoming_orbiter, COMSIG_MOVABLE_MOVED, PROC_REF(orbiter_move_react))
orbiter_list += newcomp.orbiter_list
newcomp.orbiter_list = null
/datum/component/orbiter/PostTransfer()
if(!isatom(parent) || isarea(parent) || !get_turf(parent))
return COMPONENT_INCOMPATIBLE
move_react(parent)
/datum/component/orbiter/proc/begin_orbit(atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
if(orbiter.orbiting)
if(orbiter.orbiting == src)
orbiter.orbiting.end_orbit(orbiter, TRUE)
else
orbiter.orbiting.end_orbit(orbiter)
orbiter_list[orbiter] = TRUE
orbiter.orbiting = src
// ADD_TRAIT(orbiter, TRAIT_NO_FLOATING_ANIM, ORBITING_TRAIT)
RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, PROC_REF(orbiter_move_react))
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_BEGIN, orbiter)
var/matrix/initial_transform = matrix(orbiter.transform)
orbiter_list[orbiter] = initial_transform
// Head first!
if(pre_rotation)
var/matrix/M = matrix(orbiter.transform)
var/pre_rot = 90
if(!clockwise)
pre_rot = -90
M.Turn(pre_rot)
orbiter.transform = M
var/matrix/shift = matrix(orbiter.transform)
shift.Translate(0, radius)
orbiter.transform = shift
orbiter.SpinAnimation(rotation_speed, -1, clockwise, rotation_segments, parallel = FALSE)
//Aurora doesn't vary glides
// 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.abstract_move(get_turf(parent))
to_chat(orbiter, SPAN_NOTICE("Now orbiting [parent]."))
/datum/component/orbiter/proc/end_orbit(atom/movable/orbiter, refreshing=FALSE)
if(!orbiter_list[orbiter])
return
UnregisterSignal(orbiter, COMSIG_MOVABLE_MOVED)
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_STOP, orbiter)
orbiter.SpinAnimation(0, 0, parallel = FALSE) //TG has it with parallel = TRUE but it seems to not work here with that, for some reason
if(istype(orbiter_list[orbiter],/matrix)) //This is ugly.
orbiter.transform = orbiter_list[orbiter]
orbiter_list -= orbiter
orbiter.stop_orbit(src)
orbiter.orbiting = null
if(ismob(orbiter))
var/mob/orbiter_mob = orbiter
// orbiter_mob.updating_glide_size = TRUE //Aurora doesn't vary glides
orbiter_mob.glide_size = 8
if(isobserver(orbiter))
var/mob/abstract/observer/ghostie = orbiter //is var/mob/dead/observer/ghostie = orbiter in tg
ghostie.orbiting_ref = null
// REMOVE_TRAIT(orbiter, TRAIT_NO_FLOATING_ANIM, ORBITING_TRAIT)
if(!refreshing && !length(orbiter_list) && !QDELING(src))
qdel(src)
// This proc can receive signals by either the thing being directly orbited or anything holding it
/datum/component/orbiter/proc/move_react(atom/movable/master, atom/mover, atom/oldloc, direction)
set waitfor = FALSE // Transfer calls this directly and it doesnt care if the ghosts arent done moving
if(master.loc == oldloc)
return
var/turf/newturf = get_turf(master)
if(!newturf)
qdel(src)
var/atom/curloc = master.loc
for(var/atom/movable/movable_orbiter as anything in orbiter_list)
if(QDELETED(movable_orbiter) || movable_orbiter.loc == newturf)
continue
movable_orbiter.abstract_move(newturf)
if(CHECK_TICK && master.loc != curloc)
// We moved again during the checktick, cancel current operation
break
/datum/component/orbiter/proc/orbiter_move_react(atom/movable/orbiter, atom/oldloc, direction)
SIGNAL_HANDLER
if(orbiter.loc == get_turf(parent))
return
end_orbit(orbiter)
/datum/component/orbiter/proc/orbiter_glide_size_update(datum/source, target)
SIGNAL_HANDLER
for(var/orbiter in orbiter_list)
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)
if(!istype(A) || !get_turf(A) || A == src)
return
// if (HAS_TRAIT(A, TRAIT_ORBITING_FORBIDDEN))
// // Stealth-mins have an empty name, don't want "You cannot orbit at this time."
// to_chat(src, SPAN_NOTICE("You cannot orbit ["[A]" || "them"] at this time."))
// return
orbit_target = A
return A.AddComponent(/datum/component/orbiter, src, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
/atom/movable/proc/stop_orbit(datum/component/orbiter/orbits)
orbit_target = null
return // We're just a simple hook
/atom/proc/transfer_observers_to(atom/target)
if(!orbiters || !istype(target) || !get_turf(target) || target == src)
return
target.TakeComponent(orbiters)
+55
View File
@@ -0,0 +1,55 @@
/// A datum to handle the busywork of registering signals to handle in depth tracking of a movable
/datum/movement_detector
var/atom/movable/tracked
var/datum/callback/listener
/datum/movement_detector/New(atom/movable/target, datum/callback/listener)
if(target)
track(target, listener)
/datum/movement_detector/Destroy()
untrack()
tracked = null
listener = null
return ..()
/// Sets up tracking of the given movable atom
/datum/movement_detector/proc/track(atom/movable/target, datum/callback/listener)
untrack()
tracked = target
src.listener = listener
while(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(move_react))
target = target.loc
/// Stops tracking
/datum/movement_detector/proc/untrack()
if(!tracked)
return
var/atom/movable/target = tracked
while(ismovable(target))
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
target = target.loc
/**
* Reacts to any movement that would cause a change in coordinates of the tracked movable atom
* This works by detecting movement of either the tracked object, or anything it is inside, recursively
*/
/datum/movement_detector/proc/move_react(atom/movable/mover, atom/oldloc, direction)
SIGNAL_HANDLER
var/turf/newturf = get_turf(tracked)
if(oldloc && !isturf(oldloc))
var/atom/target = oldloc
while(ismovable(target))
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
target = target.loc
if(tracked.loc != newturf)
var/atom/target = mover.loc
while(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(move_react), TRUE)
target = target.loc
listener.Invoke(tracked, mover, oldloc, direction)
-11
View File
@@ -1,14 +1,3 @@
/atom/movable/proc/move_to_turf(var/atom/movable/am, var/old_loc, var/new_loc)
var/turf/T = get_turf(new_loc)
if(T && T != loc)
forceMove(T)
// Similar to above but we also follow into nullspace
/atom/movable/proc/move_to_turf_or_null(var/atom/movable/am, var/old_loc, var/new_loc)
var/turf/T = get_turf(new_loc)
if(T != loc)
forceMove(T)
/atom/movable/proc/move_to_loc_or_null(var/atom/movable/am, var/old_loc, var/new_loc)
if(new_loc != loc)
forceMove(new_loc)
-45
View File
@@ -1,45 +0,0 @@
GLOBAL_DATUM_INIT(moved_event, /singleton/observ/moved, new)
/singleton/observ/moved
name = "Moved"
expected_type = /atom/movable
/singleton/observ/moved/register(var/eventSource, var/datum/procOwner, var/proc_call)
. = ..()
var/atom/movable/child = eventSource
if(.)
var/atom/movable/parent = child.loc
while(istype(parent) && !GLOB.moved_event.is_listening(parent, child))
GLOB.moved_event.register(parent, child, TYPE_PROC_REF(/atom/movable, recursive_move))
child = parent
parent = child.loc
/singleton/observ/moved/unregister(event_source, datum/listener, proc_call)
. = ..()
var/atom/movable/child = event_source
if(.)
var/atom/movable/parent = child.loc
while(istype(parent) && GLOB.moved_event.is_listening(parent, child))
GLOB.moved_event.unregister(parent, child, TYPE_PROC_REF(/atom/movable, recursive_move))
child = parent
parent = child.loc
/singleton/observ/moved/proc/register_all_movement(var/event_source, var/listener)
GLOB.moved_event.register(event_source, listener, /atom/movable/proc/recursive_move)
GLOB.dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set)
/singleton/observ/moved/proc/unregister_all_movement(var/event_source, var/listener)
GLOB.moved_event.unregister(event_source, listener, /atom/movable/proc/recursive_move)
GLOB.dir_set_event.unregister(event_source, listener, /atom/proc/recursive_dir_set)
/********************
* Movement Handling *
********************/
/atom/movable/proc/move_to_destination(var/atom/movable/am, var/old_loc, var/new_loc)
var/turf/T = get_turf(new_loc)
if(T && T != loc)
forceMove(T)
/atom/movable/proc/recursive_move(var/atom/movable/am, var/old_loc, var/new_loc)
GLOB.moved_event.raise_event(src, old_loc, new_loc)
+4 -4
View File
@@ -197,19 +197,19 @@ GLOBAL_DATUM_INIT(sound_player, /singleton/sound_player, new)
listeners += listener
GLOB.moved_event.register(listener, src, PROC_REF(PrivUpdateListenerLoc))
RegisterSignal(listener, COMSIG_MOVABLE_MOVED, PROC_REF(PrivUpdateListenerLoc))
GLOB.destroyed_event.register(listener, src, PROC_REF(PrivRemoveListener))
PrivUpdateListenerLoc(listener, FALSE)
PrivUpdateListenerLoc(listener, update_sound = FALSE)
/datum/sound_token/proc/PrivRemoveListener(atom/listener, sound/null_sound)
null_sound = null_sound || new(channel = sound.channel)
sound_to(listener, null_sound)
GLOB.moved_event.unregister(listener, src, PROC_REF(PrivUpdateListenerLoc))
UnregisterSignal(listener, COMSIG_MOVABLE_MOVED)
GLOB.destroyed_event.unregister(listener, src, PROC_REF(PrivRemoveListener))
listeners -= listener
/datum/sound_token/proc/PrivUpdateListenerLoc(atom/listener, update_sound = TRUE)
/datum/sound_token/proc/PrivUpdateListenerLoc(atom/movable/listener, atom/old_loc, dir, forced, list/old_locs, update_sound = TRUE)
var/turf/source_turf = get_turf(source)
var/turf/listener_turf = get_turf(listener)
+1 -7
View File
@@ -107,12 +107,7 @@
if(length(atom_protected_overlay_cache))
LAZYCLEARLIST(atom_protected_overlay_cache)
if(orbiters)
for(var/thing in orbiters)
var/datum/orbit/O = thing
if(O.orbiter)
O.orbiter.stop_orbit()
orbiters = null
orbiters = null // The component is attached to us normaly and will be deleted elsewhere
. = ..()
@@ -173,7 +168,6 @@
//Observables event, Aurora snowflake code
GLOB.entered_event.raise_event(src, arrived, old_loc)
GLOB.moved_event.raise_event(arrived, old_loc, arrived.loc)
/**
* An atom is attempting to exit this atom's contents
+33
View File
@@ -0,0 +1,33 @@
/atom
///Reference to atom being orbited
var/atom/orbit_target
///The orbiter component, if there's anything orbiting this atom
var/datum/component/orbiter/orbiters
/**
* Recursive getter method to return a list of all ghosts orbitting this atom
*
* This will work fine without manually passing arguments.
* * processed - The list of atoms we've already convered
* * source - Is this the atom for who we're counting up all the orbiters?
* * ignored_stealthed_admins - If TRUE, don't count admins who are stealthmoded and orbiting this
*/
/atom/proc/get_all_orbiters(list/processed, source = TRUE, ignore_stealthed_admins = TRUE)
var/list/output = list()
if(!processed)
processed = list()
else if(src in processed)
return output
if(!source)
output += src
processed += src
for(var/atom/atom_orbiter as anything in orbiters?.orbiter_list)
output += atom_orbiter.get_all_orbiters(processed, source = FALSE)
return output
/mob/get_all_orbiters(list/processed, source = TRUE, ignore_stealthed_admins = TRUE)
if(!source && ignore_stealthed_admins && client?.holder?.fakekey)
return list()
return ..()
+30 -13
View File
@@ -64,6 +64,8 @@
*/
var/movement_type = GROUND
var/datum/component/orbiter/orbiting
/// Either [EMISSIVE_BLOCK_NONE], [EMISSIVE_BLOCK_GENERIC], or [EMISSIVE_BLOCK_UNIQUE]
var/blocks_emissive = EMISSIVE_BLOCK_NONE
///Internal holder for emissive blocker object, DO NOT USE DIRECTLY. Use blocks_emissive
@@ -78,7 +80,6 @@
/atom/movable/Destroy(force)
if(orbiting)
stop_orbit()
GLOB.moved_event.unregister_all_movement(loc, src)
//Recalculate opacity
var/turf/T = loc
@@ -147,7 +148,7 @@
if(old_area)
old_area.Exited(src, NONE)
Moved(oldloc, TRUE)
Moved(oldloc, NONE, TRUE, null)
// Make sure you know what you're doing if you call this
// You probably want CanPass()
@@ -492,7 +493,7 @@
var/old_loc = loc
loc = destination
loc.Entered(src, old_loc)
Moved(old_loc, TRUE)
Moved(old_loc, get_dir(old_loc, destination), TRUE)
//Zmimic
if(bound_overlay)
@@ -516,13 +517,20 @@
return TRUE
/atom/movable/proc/Moved(atom/old_loc, forced)
/**
* Called after a successful Move(). By this point, we've already moved.
* Arguments:
* * old_loc is the location prior to the move. Can be null to indicate nullspace.
* * movement_dir is the direction the movement took place. Can be NONE if it was some sort of teleport.
* * The forced flag indicates whether this was a forced move, which skips many checks of regular movement.
* * The old_locs is an optional argument, in case the moved movable was present in multiple locations before the movement.
**/
/atom/movable/proc/Moved(atom/old_loc, movement_dir, forced, list/old_locs)
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, forced)
update_grid_location(old_loc, src)
/atom/movable/proc/update_grid_location(atom/old_loc)
/* START Spatial grid stuffs */
if(!HAS_SPATIAL_GRID_CONTENTS(src) || !SSspatial_grid.initialized)
return
@@ -541,6 +549,7 @@
else if(new_turf && !old_turf)
SSspatial_grid.enter_cell(src, new_turf)
/* END Spatial grid stuffs */
/atom/movable/Exited(atom/movable/gone, direction)
. = ..()
@@ -565,9 +574,6 @@
if(LAZYLEN(gone.stored_chat_text))
return_floating_text(gone)
if(GLOB.moved_event.is_listening(src, gone, TYPE_PROC_REF(/atom/movable, recursive_move)))
GLOB.moved_event.unregister(src, gone)
GLOB.dir_set_event.unregister(src, gone, TYPE_PROC_REF(/atom, recursive_dir_set))
/atom/movable/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
@@ -589,9 +595,6 @@
if (LAZYLEN(arrived.stored_chat_text))
give_floating_text(arrived)
if(GLOB.moved_event.has_listeners(arrived) && !GLOB.moved_event.is_listening(src, arrived))
GLOB.moved_event.register(src, arrived, TYPE_PROC_REF(/atom/movable, recursive_move))
if(GLOB.dir_set_event.has_listeners(arrived))
GLOB.dir_set_event.register(src, arrived, TYPE_PROC_REF(/atom, recursive_dir_set))
@@ -847,3 +850,17 @@
AddComponent(/datum/component/drift, direction, instant, start_delay)
return TRUE
/**
* meant for movement with zero side effects. only use for objects that are supposed to move "invisibly" (like camera mobs or ghosts)
* if you want something to move onto a tile with a beartrap or recycler or tripmine or mouse without that object knowing about it at all, use this
* most of the time you want forceMove()
*/
/atom/movable/proc/abstract_move(atom/new_loc)
// RESOLVE_ACTIVE_MOVEMENT // This should NEVER happen, but, just in case...
var/atom/old_loc = loc
var/direction = get_dir(old_loc, new_loc)
loc = new_loc
//is Moved(old_loc, direction, TRUE, momentum_change = FALSE) in tg
Moved(old_loc, direction, TRUE)
@@ -72,24 +72,25 @@
daddy = ndaddy
set_dir(daddy.dir)
appearance = daddy.appearance
GLOB.moved_event.register(daddy, src, PROC_REF(mirror))
RegisterSignal(daddy, COMSIG_MOVABLE_MOVED, PROC_REF(mirror))
GLOB.dir_set_event.register(daddy, src, PROC_REF(mirror_dir))
GLOB.destroyed_event.register(daddy, src, TYPE_PROC_REF(/datum, qdel_self))
/obj/effect/bluegoast/Destroy()
GLOB.destroyed_event.unregister(daddy, src)
GLOB.dir_set_event.unregister(daddy, src)
GLOB.moved_event.unregister(daddy, src)
daddy = null
if(daddy)
GLOB.destroyed_event.unregister(daddy, src)
GLOB.dir_set_event.unregister(daddy, src)
UnregisterSignal(daddy, COMSIG_MOVABLE_MOVED)
daddy = null
. = ..()
/obj/effect/bluegoast/proc/mirror(var/atom/movable/am, var/old_loc, var/new_loc)
var/ndir = get_dir(new_loc,old_loc)
// /obj/effect/bluegoast/proc/mirror(var/atom/movable/am, var/old_loc, var/new_loc)
/obj/effect/bluegoast/proc/mirror(atom/movable/listener, atom/old_loc, dir, forced, list/old_locs)
appearance = daddy.appearance
var/nloc = get_step(src, ndir)
var/nloc = get_step(src, dir)
if(nloc)
forceMove(nloc)
if(nloc == new_loc)
if(nloc == daddy.loc)
reality++
if(reality > 5)
to_chat(daddy, SPAN_NOTICE("Yep, it's certainly the other one. Your existance was a glitch, and it's finally being mended..."))
@@ -68,7 +68,7 @@
/obj/item/storage/slide_projector/proc/stop_projecting()
if(projection)
QDEL_NULL(projection)
GLOB.moved_event.unregister(src, src, PROC_REF(check_projections))
UnregisterSignal(src, COMSIG_MOVABLE_MOVED)
set_light(0)
update_icon()
@@ -83,7 +83,7 @@
break
projection = new projection_type(target)
projection.set_source(current_slide)
GLOB.moved_event.register(src, src, PROC_REF(check_projections))
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(check_projections))
set_light(1.4, 0.1, COLOR_WHITE) //Bit of light
update_icon()
+2 -2
View File
@@ -9,12 +9,12 @@
/obj/structure/easel/Initialize(ml, _mat, _reinf_mat)
. = ..()
GLOB.moved_event.register(src, src, PROC_REF(move_painting))
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(move_painting))
material = SSmaterials.get_material_by_name(MATERIAL_WOOD)
/obj/structure/easel/Destroy()
painting = null
GLOB.moved_event.unregister(src, src, PROC_REF(move_painting))
UnregisterSignal(src, COMSIG_MOVABLE_MOVED)
return ..()
/*
@@ -43,8 +43,6 @@
T.pixel_x = 0
T.pixel_y = 0
T.layer = ABOVE_OBJ_LAYER
GLOB.moved_event.register(T, src, TYPE_PROC_REF(/atom/movable, move_to_turf))
GLOB.moved_event.register(src, T, TYPE_PROC_REF(/atom/movable, move_to_turf))
T.stake = src
pinned_target = T
else
@@ -52,8 +50,6 @@
if(pinned_target)
pinned_target.density = FALSE
pinned_target.layer = OBJ_LAYER
GLOB.moved_event.unregister(pinned_target, src)
GLOB.moved_event.unregister(src, pinned_target)
pinned_target.stake = null
pinned_target = null
+1 -1
View File
@@ -2,7 +2,7 @@
return
/mob/abstract/observer/on_mob_jump()
stop_following()
QDEL_NULL(orbiting)
/client/proc/Jump(var/area/A in GLOB.all_areas)
set name = "Jump to Area"
@@ -118,7 +118,7 @@
if(source in sources)
return FALSE
sources += source
GLOB.moved_event.register(source, src, PROC_REF(source_moved))
RegisterSignal(source, COMSIG_MOVABLE_MOVED, PROC_REF(source_moved))
GLOB.destroyed_event.register(source, src, PROC_REF(remove_source))
for_all_chunks_in_range(source, TYPE_PROC_REF(/datum/chunk, add_source), list(source))
if(update_visibility)
@@ -128,16 +128,16 @@
/datum/visualnet/proc/remove_source(var/atom/source, var/update_visibility = TRUE, var/opacity_check = FALSE)
if(!sources.Remove(source))
return FALSE
GLOB.moved_event.unregister(source, src)
UnregisterSignal(source, COMSIG_MOVABLE_MOVED)
GLOB.destroyed_event.unregister(source, src)
for_all_chunks_in_range(source, /datum/chunk/proc/remove_source, list(source))
if(update_visibility)
update_visibility(source, opacity_check)
return TRUE
/datum/visualnet/proc/source_moved(var/atom/movable/source, var/old_loc, var/new_loc)
/datum/visualnet/proc/source_moved(atom/movable/source, atom/old_loc, dir, forced, list/old_locs)
var/turf/old_turf = get_turf(old_loc)
var/turf/new_turf = get_turf(new_loc)
var/turf/new_turf = get_turf(source)
if(old_turf == new_turf)
return
+32 -69
View File
@@ -22,7 +22,7 @@
var/medHUD = 0
var/antagHUD = 0
universal_speak = 1
var/atom/movable/following = null
// var/atom/movable/following = null
var/admin_ghosted = 0
var/anonsay = 0
var/image/ghostimage = null //this mobs ghost image, for deleting and stuff
@@ -37,6 +37,9 @@
mob_thinks = FALSE
/// The POI we're orbiting (orbit menu)
var/orbiting_ref
/mob/abstract/observer/New(mob/body)
if (istype(body, /mob/abstract/observer))
return//A ghost can't become a ghost.
@@ -97,7 +100,6 @@
..()
/mob/abstract/observer/Destroy()
stop_following()
qdel(ghost_multitool)
ghost_multitool = null
@@ -162,8 +164,6 @@ Works together with spawning an observer, noted above.
if(medHUD)
process_medHUD(src)
teleport_if_needed()
/mob/abstract/observer/proc/on_restricted_level(var/check)
if(!check)
check = z
@@ -187,30 +187,6 @@ Works together with spawning an observer, noted above.
to_chat(src, SPAN_NOTICE("[message]"))
forceMove(O.loc)
//Teleports the observer away from z-levels they shouldnt be on, if needed.
/mob/abstract/observer/proc/teleport_if_needed()
//If we dont have a observe restriction we dont need to teleport
if(!GLOB.config.observe_restriction)
return
//If we are not on a restricted level we dont need to get rid of them
if(!on_restricted_level())
return
//If we have observe restriction 1 and they are following a living non-animal mob we dont need to do anything.
if(GLOB.config.observe_restriction == 1 && following && isliving(following) && !isliving(following))
return
//In case we have observe restriction 2 (or 1 and they are following something, then teleport them back.)
if(following)
stop_following()
teleport_to_spawn("You can not follow \the [following] on this level.")
else
teleport_to_spawn()
//And update their sight settings
updateghostsight()
/mob/abstract/observer/proc/process_medHUD(var/mob/M)
var/client/C = M.client
@@ -299,7 +275,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
if(!found_rune)
to_chat(usr, SPAN_CULT("The astral cord that ties your body and your spirit has been severed. You are likely to wander the realm beyond until your body is finally dead and thus reunited with you."))
return
stop_following()
QDEL_NULL(orbiting)
mind.current.ajourn=0
mind.current.key = key
mind.current.teleop = null
@@ -326,14 +302,14 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Medical Scan Target"
set desc = "Analyse the health of whatever you are following."
if(!following)
if(!orbiting)
to_chat(src, SPAN_WARNING("You aren't following anything!"))
return
if(isipc(following) || isrobot(following))
robotic_analyze_mob(following, usr, TRUE)
else if(ishuman(following))
health_scan_mob(following, usr, TRUE, TRUE)
if(isipc(orbit_target) || isrobot(orbit_target))
robotic_analyze_mob(orbit_target, usr, TRUE)
else if(ishuman(orbit_target))
health_scan_mob(orbit_target, usr, TRUE, TRUE)
else
to_chat(src, SPAN_WARNING("This isn't a scannable target."))
@@ -403,8 +379,7 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
to_chat(usr, "You can not teleport to this area")
return
stop_following()
usr.forceMove(pick(L))
usr.abstract_move(pick(L))
/mob/abstract/observer/verb/follow()
set category = "Ghost"
@@ -415,35 +390,28 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
GM.ui_interact(usr)
// This is the ghost's follow verb with an argument
/mob/abstract/observer/proc/ManualFollow(var/atom/movable/target)
if(!target || target == following || target == src)
/mob/abstract/observer/proc/ManualFollow(atom/movable/target)
if(!target)
return
stop_following()
following = target
GLOB.moved_event.register(following, src, TYPE_PROC_REF(/atom/movable, move_to_destination))
GLOB.destroyed_event.register(following, src, PROC_REF(stop_following))
//Stops orbit if there's any; TG doesn't do this, but if you don't it breaks the orbiting reference
//if you are jumping from one mob to another, hence why we're doing it here
orbiting?.end_orbit(src)
to_chat(src, SPAN_NOTICE("Now following \the <b>[following]</b>."))
move_to_destination(following, following.loc, following.loc)
var/list/icon_dimensions = get_icon_dimensions(target.icon)
var/orbitsize = (icon_dimensions["width"] + icon_dimensions["height"]) * 0.5
orbitsize -= (orbitsize/ICON_SIZE_ALL)*(ICON_SIZE_ALL*0.25)
var/rot_seg = 30 //Let's make it simple and it's just a circle
orbit(target,orbitsize, FALSE, 20, rot_seg)
to_chat(src, SPAN_NOTICE("Now following \the <b>[target]</b>."))
updateghostsight()
/mob/abstract/observer/proc/stop_following()
if(following)
to_chat(src, SPAN_NOTICE("No longer following \the <b>[following]</b>."))
GLOB.moved_event.unregister(following, src)
GLOB.destroyed_event.unregister(following, src)
following = null
/mob/abstract/observer/move_to_destination(var/atom/movable/am, var/old_loc, var/new_loc)
var/turf/T = get_turf(new_loc)
if(check_holy(T))
stop_following()
teleport_if_needed()
to_chat(usr, SPAN_WARNING("You cannot follow something standing on holy grounds!"))
return
..()
/mob/abstract/observer/orbit()
set_dir(2)//reset dir so the right directional sprites show up
return ..()
/mob/proc/check_holy(var/turf/T)
return 0
@@ -459,19 +427,18 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set name = "Jump to Mob"
set desc = "Teleport to a mob"
if(istype(usr, /mob/abstract/observer)) //Make sure they're an observer!
if(istype(src, /mob/abstract/observer)) //Make sure they're an observer!
var/mob/source_mob = src //Source mob
var/target = getmobs()[input]
if(!target) return
var/turf/T = get_turf(target) //Turf of the destination mob
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
stop_following()
forceMove(T)
source_mob.abstract_move(T)
else
to_chat(src, "This mob is not located in the game world.")
teleport_if_needed()
/mob/abstract/observer/memory()
set hidden = 1
to_chat(src, SPAN_WARNING("You are dead! You have no mind to store memory!"))
@@ -480,10 +447,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
set hidden = 1
to_chat(src, SPAN_WARNING("You are dead! You have no mind to store memory!"))
/mob/abstract/observer/Post_Incorpmove()
stop_following()
teleport_if_needed()
/mob/abstract/observer/verb/analyze_air()
set name = "Analyze Air"
set category = "Ghost"
+2 -2
View File
@@ -414,7 +414,7 @@
affecting.buckled_to = null
affecting.update_canmove()
affecting.anchored = FALSE
GLOB.moved_event.unregister(assailant, src, PROC_REF(move_affecting))
UnregisterSignal(assailant, COMSIG_MOVABLE_MOVED)
animate(affecting, pixel_x = affecting.get_standard_pixel_x(), pixel_y = affecting.get_standard_pixel_y(), 4, 1, LINEAR_EASING)
affecting.layer = initial(affecting.layer)
@@ -471,7 +471,7 @@
affecting.buckled_to = assailant
affecting.forceMove(H.loc)
adjust_position()
GLOB.moved_event.register(assailant, src, PROC_REF(move_affecting))
RegisterSignal(assailant, COMSIG_MOVABLE_MOVED, PROC_REF(move_affecting))
/obj/item/grab/proc/set_wielding()
wielded = TRUE
+1 -5
View File
@@ -185,10 +185,6 @@
. = ..(newloc, direction)
if(.)
// Events.
if(GLOB.moved_event.global_listeners[src])
GLOB.moved_event.raise_event(src, old_loc, loc)
// Lighting.
if(light_sources)
var/datum/light_source/L
@@ -213,7 +209,7 @@
if(bound_overlay.dir != dir)
bound_overlay.set_dir(dir)
Moved(old_loc, FALSE)
Moved(old_loc, direction, FALSE)
if(direction != olddir)
dir = olddir
+2 -2
View File
@@ -799,7 +799,7 @@
forceMove(T)
tile_shifted = TRUE
follow()
GLOB.moved_event.register(owner, src, PROC_REF(follow))
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(follow))
/atom/movable/z_observer/proc/follow()
@@ -826,7 +826,7 @@
qdel(src)
/atom/movable/z_observer/Destroy()
GLOB.moved_event.unregister(owner, src, PROC_REF(follow))
UnregisterSignal(owner, COMSIG_MOVABLE_MOVED)
owner = null
. = ..()
-90
View File
@@ -1,90 +0,0 @@
/datum/orbit
var/atom/movable/orbiter
var/atom/orbiting
var/lock = TRUE
var/turf/lastloc
var/lastprocess
/datum/orbit/New(_orbiter, _orbiting, _lock)
orbiter = _orbiter
orbiting = _orbiting
SSorbit.processing += src
if (!orbiting.orbiters)
orbiting.orbiters = list()
orbiting.orbiters += src
if (orbiter.orbiting)
orbiter.stop_orbit()
orbiter.orbiting = src
Check()
lock = _lock
//do not qdel directly, use stop_orbit on the orbiter. (This way the orbiter can bind to the orbit stopping)
/datum/orbit/Destroy(force = FALSE)
SSorbit.processing -= src
if (orbiter)
orbiter.orbiting = null
orbiter = null
if (orbiting)
if (orbiting.orbiters)
orbiting.orbiters -= src
if (!orbiting.orbiters.len)//we are the last orbit, delete the list
orbiting.orbiters = null
orbiting = null
return ..()
/datum/orbit/proc/Check(turf/targetloc)
if (!orbiter)
qdel(src)
return
if (!orbiting)
orbiter.stop_orbit()
return
if (!orbiter.orbiting) //admin wants to stop the orbit.
orbiter.orbiting = src //set it back to us first
orbiter.stop_orbit()
lastprocess = world.time
if (!targetloc)
targetloc = get_turf(orbiting)
if (!targetloc || (!lock && orbiter.loc != lastloc && orbiter.loc != targetloc))
orbiter.stop_orbit()
return
orbiter.forceMove(targetloc)
lastloc = orbiter.loc
/atom/movable/var/datum/orbit/orbiting = null
/atom/var/list/orbiters = null
//A: atom to orbit
//radius: range to orbit at, radius of the circle formed by orbiting (in pixels)
//rotation_speed: how fast to rotate (how many ds should it take for a rotation to complete)
//pre_rotation: Chooses to rotate src 90 degress towards the orbit dir, useful for things to go "head first" like ghosts
//lockinorbit: Forces src to always be on A's turf, otherwise the orbit cancels when src gets too far away (eg: ghosts)
/atom/movable/proc/orbit(atom/A, radius = 10, rotation_speed = 20, pre_rotation = TRUE, lockinorbit = FALSE)
if (!istype(A))
return
new/datum/orbit(src, A, lockinorbit)
if (!orbiting) //something failed, and our orbit datum deleted itself
return
var/matrix/initial_transform = matrix(transform)
//Head first!
if (pre_rotation)
var/matrix/M = matrix(transform)
M.Turn(90)
transform = M
var/matrix/shift = matrix(transform)
shift.Translate(0,radius)
transform = shift
SpinAnimation(rotation_speed, -1)
//we stack the orbits up client side, so we can assign this back to normal server side without it breaking the orbit
transform = initial_transform
/atom/movable/proc/stop_orbit()
SpinAnimation(0,0)
QDEL_NULL(orbiting)
+4 -4
View File
@@ -52,9 +52,9 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
user.reset_view(linked)
if(user.client)
user.client.view = world.view + extra_view
GLOB.moved_event.register(user, src, PROC_REF(unlook))
RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(unlook))
if(user.eyeobj)
GLOB.moved_event.register(user.eyeobj, src, PROC_REF(unlook))
RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(unlook))
LAZYDISTINCTADD(viewers, WEAKREF(user))
if(linked)
LAZYDISTINCTADD(linked.navigation_viewers, WEAKREF(user))
@@ -80,11 +80,11 @@ somewhere on that shuttle. Subtypes of these can be then used to perform ship ov
c.pixel_x = 0
c.pixel_y = 0
GLOB.moved_event.unregister(user, src, PROC_REF(unlook))
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
if(isEye(user)) // If we're an AI eye, the computer has our AI mob in its viewers list not the eye mob
var/mob/abstract/eye/E = user
GLOB.moved_event.unregister(E.owner, src, PROC_REF(unlook))
UnregisterSignal(E.owner, COMSIG_MOVABLE_MOVED)
LAZYREMOVE(viewers, WEAKREF(E.owner))
LAZYREMOVE(viewers, WEAKREF(user))
if(linked)
+4 -4
View File
@@ -78,18 +78,18 @@ This is /obj/machinery level code to properly manage power usage from the area.
/obj/machinery/Initialize(mapload, d = 0, populate_components = TRUE, is_internal = FALSE)
internal = is_internal
REPORT_POWER_CONSUMPTION_CHANGE(0, get_power_usage())
GLOB.moved_event.register(src, src, PROC_REF(update_power_on_move))
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(update_power_on_move))
power_init_complete = TRUE
. = ..()
// Or in Destroy at all, but especially after the ..().
/obj/machinery/Destroy()
GLOB.moved_event.unregister(src, src, PROC_REF(update_power_on_move))
UnregisterSignal(src, COMSIG_MOVABLE_MOVED)
REPORT_POWER_CONSUMPTION_CHANGE(get_power_usage(), 0)
. = ..()
/obj/machinery/proc/update_power_on_move(atom/movable/mover, atom/old_loc, atom/new_loc)
area_changed(get_area(old_loc), get_area(new_loc))
/obj/machinery/proc/update_power_on_move(atom/movable/mover, atom/old_loc, dir, forced, list/old_locs)
area_changed(get_area(old_loc), get_area(src))
/obj/machinery/proc/area_changed(area/old_area, area/new_area)
if(old_area == new_area)
-7
View File
@@ -31,9 +31,6 @@
/obj/singularity/energy_ball/Destroy()
walk(src, 0) // Stop walking
if(orbiting && istype(orbiting.orbiting, /obj/singularity/energy_ball))
var/obj/singularity/energy_ball/EB = orbiting.orbiting
EB.orbiting_balls -= src
for(var/ball in orbiting_balls)
var/obj/singularity/energy_ball/EB = ball
@@ -257,10 +254,6 @@
. = ..()
/obj/singularity/energy_ball/stop_orbit()
if (orbiting && istype(orbiting.orbiting, /obj/singularity/energy_ball))
var/obj/singularity/energy_ball/orbitingball = orbiting.orbiting
orbitingball.orbiting_balls -= src
orbitingball.dissipate_strength = orbitingball.orbiting_balls.len
. = ..()
if (!loc && !QDELETED(src))
qdel(src)
@@ -213,8 +213,8 @@
locked = 0
update_icon()
lock_time = world.time + 35
GLOB.moved_event.register(owner, src, PROC_REF(update_aiming))
GLOB.moved_event.register(aiming_at, src, PROC_REF(target_moved))
RegisterSignal(owner, COMSIG_MOVABLE_MOVED, PROC_REF(update_aiming))
RegisterSignal(aiming_at, COMSIG_MOVABLE_MOVED, PROC_REF(target_moved))
GLOB.destroyed_event.register(aiming_at, src, PROC_REF(cancel_aiming))
/obj/aiming_overlay/proc/aim_cooldown(seconds)
@@ -258,9 +258,9 @@
SPAN_NOTICE("You lower \the [aiming_with].")
)
GLOB.moved_event.unregister(owner, src)
UnregisterSignal(owner, COMSIG_MOVABLE_MOVED)
if(aiming_at)
GLOB.moved_event.unregister(aiming_at, src)
UnregisterSignal(aiming_at, COMSIG_MOVABLE_MOVED)
GLOB.destroyed_event.unregister(aiming_at, src)
LAZYREMOVE(aiming_at.aimed_at_by, src)
aiming_at = null
-9
View File
@@ -142,10 +142,6 @@
affected.owner.custom_pain("You feel something rip in your [affected.name]!", 1)
user.drop_item()
affected.implants += tool
if(istype(tool, /obj/item/device/gps))
var/obj/item/device/gps/gps = tool
GLOB.moved_event.register(target, gps, TYPE_PROC_REF(/obj/item/device/gps, update_position))
gps.implanted_into = target
tool.forceMove(affected)
affected.cavity = CAVITY_CLOSED
@@ -210,11 +206,6 @@
worm.detach()
worm.leave_host()
else if(istype(I, /obj/item/device/gps))
var/obj/item/device/gps/gps = I
GLOB.moved_event.unregister(target, gps)
gps.implanted_into = null
playsound(target.loc, 'sound/effects/squelch1.ogg', 50, 1)
else
user.visible_message("<b>[user]</b> could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.", \
+13 -13
View File
@@ -50,10 +50,10 @@ GLOBAL_LIST_EMPTY(gps_list)
update_icon()
if(held_by)
GLOB.moved_event.register(held_by, src, PROC_REF(update_position))
RegisterSignal(held_by, COMSIG_MOVABLE_MOVED, PROC_REF(update_position), TRUE)
if(implanted_into)
GLOB.moved_event.register(implanted_into, src, PROC_REF(update_position))
GLOB.moved_event.register(src, src, PROC_REF(update_position))
RegisterSignal(implanted_into, COMSIG_MOVABLE_MOVED, PROC_REF(update_position), TRUE)
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(update_position))
for(var/gps in GLOB.gps_list)
tracking += GLOB.gps_list[gps]["tag"]
@@ -62,12 +62,12 @@ GLOBAL_LIST_EMPTY(gps_list)
/obj/item/device/gps/Destroy()
GLOB.gps_list -= GLOB.gps_list[gpstag]
GLOB.moved_event.unregister(src, src)
UnregisterSignal(src, COMSIG_MOVABLE_MOVED)
if(held_by)
GLOB.moved_event.unregister(held_by, src)
UnregisterSignal(held_by, COMSIG_MOVABLE_MOVED)
held_by = null
if(implanted_into)
GLOB.moved_event.unregister(implanted_into, src)
UnregisterSignal(implanted_into, COMSIG_MOVABLE_MOVED)
implanted_into = null
STOP_PROCESSING(SSprocessing, src)
return ..()
@@ -84,16 +84,16 @@ GLOBAL_LIST_EMPTY(gps_list)
/obj/item/device/gps/pickup(var/mob/user)
..()
if(held_by)
GLOB.moved_event.unregister(held_by, src)
UnregisterSignal(held_by, COMSIG_MOVABLE_MOVED)
held_by = user
GLOB.moved_event.register(user, src, PROC_REF(update_position))
RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(update_position), TRUE)
update_icon()
/obj/item/device/gps/dropped(mob/user)
..()
if(isturf(loc))
held_by = null
GLOB.moved_event.unregister(user, src)
UnregisterSignal(user, COMSIG_MOVABLE_MOVED)
if(user.client)
user.client.screen -= compass
update_icon()
@@ -234,7 +234,7 @@ GLOBAL_LIST_EMPTY(gps_list)
/obj/item/device/gps/proc/update_position(var/check_held_by = TRUE)
var/turf/T = get_turf(src)
if(check_held_by && held_by && (held_by.x != T.x || held_by.y != T.y || held_by.z != T.z) && held_by != recursive_loc_turf_check(src, 3, held_by))
GLOB.moved_event.unregister(held_by, src)
UnregisterSignal(held_by, COMSIG_MOVABLE_MOVED)
held_by = null
update_icon()
return
@@ -342,10 +342,10 @@ GLOBAL_LIST_EMPTY(gps_list)
update_icon()
if(held_by)
GLOB.moved_event.register(held_by, src, PROC_REF(update_position))
RegisterSignal(held_by, COMSIG_MOVABLE_MOVED, PROC_REF(update_position), TRUE)
if(implanted_into)
GLOB.moved_event.register(implanted_into, src, PROC_REF(update_position))
GLOB.moved_event.register(src, src, PROC_REF(update_position))
RegisterSignal(implanted_into, COMSIG_MOVABLE_MOVED, PROC_REF(update_position), TRUE)
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(update_position))
for(var/gps in GLOB.gps_list)
tracking += GLOB.gps_list[gps]["tag"]
+13 -56
View File
@@ -1,5 +1,11 @@
/proc/is_listening_to_movement(var/atom/movable/listening_to, var/listener)
return GLOB.moved_event.is_listening(listening_to, listener)
/proc/is_listening_to_movement(var/atom/movable/listening_to, var/mob/abstract/observer/listener)
if(!listener.orbiting)
return FALSE
var/list/procs = (listener.orbiting.tracker._signal_procs ||= list())
var/list/target_procs = (procs[listening_to] ||= list())
var/exists = target_procs[COMSIG_MOVABLE_MOVED]
return exists
/datum/unit_test/observation
name = "OBSERVATION template"
@@ -22,8 +28,8 @@
else
TEST_FAIL("The observer is not following the mob.")
QDEL_IN(H, 10 SECONDS)
QDEL_IN(O, 10 SECONDS)
qdel(H)
qdel(O)
return 1
/datum/unit_test/observation/moved_observer_shall_unregister_on_nofollow
@@ -36,61 +42,12 @@
var/mob/abstract/observer/O = new(T)
O.ManualFollow(H)
O.stop_following()
QDEL_NULL(O.orbiting)
if(!is_listening_to_movement(H, O))
TEST_PASS("The observer is no longer following the mob.")
else
TEST_FAIL("The observer is still following the mob.")
QDEL_IN(H, 10 SECONDS)
QDEL_IN(O, 10 SECONDS)
return 1
/datum/unit_test/observation/moved_shall_registers_recursively_on_new_listener
name = "OBSERVATION: Moved - Shall Register Recursively on New Listener"
groups = list("generic")
/datum/unit_test/observation/moved_shall_registers_recursively_on_new_listener/start_test()
var/turf/T = locate(20,20,1)
var/mob/living/carbon/human/H = new(T)
var/obj/structure/closet/C = new(T)
var/mob/abstract/observer/O = new(T)
H.forceMove(C)
O.ManualFollow(H)
var/listening_to_closet = is_listening_to_movement(C, H)
var/listening_to_human = is_listening_to_movement(H, O)
if(listening_to_closet && listening_to_human)
TEST_PASS("Recursive moved registration succesful.")
else
TEST_FAIL("Recursive moved registration failed. Human listening to closet: [listening_to_closet] - Observer listening to human: [listening_to_human]")
QDEL_IN(C, 10 SECONDS)
QDEL_IN(H, 10 SECONDS)
QDEL_IN(O, 10 SECONDS)
return 1
/datum/unit_test/observation/moved_shall_registers_recursively_with_existing_listener
name = "OBSERVATION: Moved - Shall Register Recursively with Existing Listener"
groups = list("generic")
/datum/unit_test/observation/moved_shall_registers_recursively_with_existing_listener/start_test()
var/turf/T = locate(20,20,1)
var/mob/living/carbon/human/H = new(T)
var/obj/structure/closet/C = new(T)
var/mob/abstract/observer/O = new(T)
O.ManualFollow(H)
H.forceMove(C)
var/listening_to_closet = is_listening_to_movement(C, H)
var/listening_to_human = is_listening_to_movement(H, O)
if(listening_to_closet && listening_to_human)
TEST_PASS("Recursive moved registration succesful.")
else
TEST_FAIL("Recursive moved registration failed. Human listening to closet: [listening_to_closet] - Observer listening to human: [listening_to_human]")
QDEL_IN(C, 10 SECONDS)
QDEL_IN(H, 10 SECONDS)
QDEL_IN(O, 10 SECONDS)
qdel(H)
qdel(O)
return 1