From d40d459d4230309581da2b10adadf27c3c8a01e9 Mon Sep 17 00:00:00 2001 From: Fluffy <65877598+FluffyGhoster@users.noreply.github.com> Date: Sat, 26 Oct 2024 17:53:07 +0200 Subject: [PATCH] Refactored movement observable away (#20083) Refactored movement observable away, use only the signal. Some tweaks to the signal. --- aurorastation.dme | 6 +- code/__DEFINES/_helpers.dm | 13 ++ code/__DEFINES/dcs/signals.dm | 1 - .../signals/signals_atom/signals_atom_main.dm | 8 + .../signals_atom/signals_atom_movable.dm | 3 +- code/__HELPERS/matrices.dm | 56 ++++-- code/_onclick/observer.dm | 3 +- code/controllers/subsystems/orbit.dm | 46 ----- code/datums/components/orbiter.dm | 186 ++++++++++++++++++ code/datums/movement_detector.dm | 55 ++++++ code/datums/observation/helpers.dm | 11 -- code/datums/observation/moved.dm | 45 ----- code/datums/sound_player.dm | 8 +- code/game/atom/_atom.dm | 8 +- code/game/atom/atom_orbit.dm | 33 ++++ code/game/atoms_movable.dm | 43 ++-- .../endgame/bluespace_jump/bluespace_jump.dm | 19 +- .../objects/items/devices/slide_projector.dm | 4 +- code/game/objects/items/easel.dm | 4 +- code/game/objects/structures/target_stake.dm | 4 - code/modules/admin/verbs/adminjump.dm | 2 +- .../mob/abstract/freelook/visualnet.dm | 8 +- .../modules/mob/abstract/observer/observer.dm | 101 +++------- code/modules/mob/mob_grab.dm | 4 +- code/modules/mob/mob_movement.dm | 6 +- code/modules/multiz/movement.dm | 4 +- code/modules/orbit/orbit.dm | 90 --------- code/modules/overmap/ships/computers/ship.dm | 8 +- code/modules/power/power_usage.dm | 8 +- code/modules/power/tesla/energy_ball.dm | 7 - .../targeting/targeting_overlay.dm | 8 +- code/modules/surgery/implant.dm | 9 - code/modules/telesci/gps.dm | 26 +-- code/unit_tests/observation_tests.dm | 69 ++----- ...fyghost-refactormovementobservableaway.yml | 60 ++++++ 35 files changed, 532 insertions(+), 434 deletions(-) delete mode 100644 code/controllers/subsystems/orbit.dm create mode 100644 code/datums/components/orbiter.dm create mode 100644 code/datums/movement_detector.dm delete mode 100644 code/datums/observation/moved.dm create mode 100644 code/game/atom/atom_orbit.dm delete mode 100644 code/modules/orbit/orbit.dm create mode 100644 html/changelogs/fluffyghost-refactormovementobservableaway.yml diff --git a/aurorastation.dme b/aurorastation.dme index d51f20d3113..db41d6fd02a 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -352,7 +352,6 @@ #include "code\controllers\subsystems\mob_fast_ai.dm" #include "code\controllers\subsystems\news.dm" #include "code\controllers\subsystems\night_lighting.dm" -#include "code\controllers\subsystems\orbit.dm" #include "code\controllers\subsystems\overlays.dm" #include "code\controllers\subsystems\pai.dm" #include "code\controllers\subsystems\pathfinder.dm" @@ -434,6 +433,7 @@ #include "code\datums\mixed.dm" #include "code\datums\modules.dm" #include "code\datums\move_manager.dm" +#include "code\datums\movement_detector.dm" #include "code\datums\position_point_vector.dm" #include "code\datums\progressbar.dm" #include "code\datums\records.dm" @@ -450,6 +450,7 @@ #include "code\datums\components\connect_mob_behalf.dm" #include "code\datums\components\drift.dm" #include "code\datums\components\local_network.dm" +#include "code\datums\components\orbiter.dm" #include "code\datums\components\armor\armor.dm" #include "code\datums\components\base_name\base_name.dm" #include "code\datums\components\eye\_eye.dm" @@ -486,7 +487,6 @@ #include "code\datums\observation\exited.dm" #include "code\datums\observation\helpers.dm" #include "code\datums\observation\instruments.dm" -#include "code\datums\observation\moved.dm" #include "code\datums\observation\observation.dm" #include "code\datums\observation\see_invisible_set.dm" #include "code\datums\observation\set_invisibility.dm" @@ -663,6 +663,7 @@ #include "code\game\atom\atom_act.dm" #include "code\game\atom\atom_defense.dm" #include "code\game\atom\atom_examine.dm" +#include "code\game\atom\atom_orbit.dm" #include "code\game\atom\atoms_initializing_EXPENSIVE.dm" #include "code\game\dna\dna2.dm" #include "code\game\dna\dna2_domutcheck.dm" @@ -2953,7 +2954,6 @@ #include "code\modules\ntsl2\guide.dm" #include "code\modules\ntsl2\ntsl2_program.dm" #include "code\modules\ntsl2\ntsl2_types.dm" -#include "code\modules\orbit\orbit.dm" #include "code\modules\organs\blood.dm" #include "code\modules\organs\misc.dm" #include "code\modules\organs\organ.dm" diff --git a/code/__DEFINES/_helpers.dm b/code/__DEFINES/_helpers.dm index 998075b6a03..08a2a626dc0 100644 --- a/code/__DEFINES/_helpers.dm +++ b/code/__DEFINES/_helpers.dm @@ -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) diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 1cccb694f9e..65269f46389 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -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 diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm index c467eab2a86..5eb6c328956 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm @@ -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" diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm index dc2f07e9db5..3cd2409a5ac 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm @@ -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) diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm index 1faa78aa816..1e87f46e70b 100644 --- a/code/__HELPERS/matrices.dm +++ b/code/__HELPERS/matrices.dm @@ -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. * diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm index 63246f1e2c9..ec882d5da9f 100644 --- a/code/_onclick/observer.dm +++ b/code/_onclick/observer.dm @@ -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) diff --git a/code/controllers/subsystems/orbit.dm b/code/controllers/subsystems/orbit.dm deleted file mode 100644 index 96693b3fecf..00000000000 --- a/code/controllers/subsystems/orbit.dm +++ /dev/null @@ -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 diff --git a/code/datums/components/orbiter.dm b/code/datums/components/orbiter.dm new file mode 100644 index 00000000000..e73d4da5631 --- /dev/null +++ b/code/datums/components/orbiter.dm @@ -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) diff --git a/code/datums/movement_detector.dm b/code/datums/movement_detector.dm new file mode 100644 index 00000000000..be36d62e660 --- /dev/null +++ b/code/datums/movement_detector.dm @@ -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) diff --git a/code/datums/observation/helpers.dm b/code/datums/observation/helpers.dm index f3218309638..47d63c36a39 100644 --- a/code/datums/observation/helpers.dm +++ b/code/datums/observation/helpers.dm @@ -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) diff --git a/code/datums/observation/moved.dm b/code/datums/observation/moved.dm deleted file mode 100644 index fc549bdda6a..00000000000 --- a/code/datums/observation/moved.dm +++ /dev/null @@ -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) diff --git a/code/datums/sound_player.dm b/code/datums/sound_player.dm index a90ab317cab..f3b6240e5e5 100644 --- a/code/datums/sound_player.dm +++ b/code/datums/sound_player.dm @@ -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) diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index c2880dec9c0..347602fe68c 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -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 diff --git a/code/game/atom/atom_orbit.dm b/code/game/atom/atom_orbit.dm new file mode 100644 index 00000000000..8eecddd952d --- /dev/null +++ b/code/game/atom/atom_orbit.dm @@ -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 ..() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 0ab9e42db4f..bc5772d50ed 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -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) diff --git a/code/game/gamemodes/endgame/bluespace_jump/bluespace_jump.dm b/code/game/gamemodes/endgame/bluespace_jump/bluespace_jump.dm index ecce42ce949..40066a5b14e 100644 --- a/code/game/gamemodes/endgame/bluespace_jump/bluespace_jump.dm +++ b/code/game/gamemodes/endgame/bluespace_jump/bluespace_jump.dm @@ -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...")) diff --git a/code/game/objects/items/devices/slide_projector.dm b/code/game/objects/items/devices/slide_projector.dm index ebf0d548ea6..1d02decfa66 100644 --- a/code/game/objects/items/devices/slide_projector.dm +++ b/code/game/objects/items/devices/slide_projector.dm @@ -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() diff --git a/code/game/objects/items/easel.dm b/code/game/objects/items/easel.dm index 5729f6016f4..3962b8f6626 100644 --- a/code/game/objects/items/easel.dm +++ b/code/game/objects/items/easel.dm @@ -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 ..() /* diff --git a/code/game/objects/structures/target_stake.dm b/code/game/objects/structures/target_stake.dm index 4a4a5f21b07..569fa63de0c 100644 --- a/code/game/objects/structures/target_stake.dm +++ b/code/game/objects/structures/target_stake.dm @@ -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 diff --git a/code/modules/admin/verbs/adminjump.dm b/code/modules/admin/verbs/adminjump.dm index 74f21a053b4..1e765a75f34 100644 --- a/code/modules/admin/verbs/adminjump.dm +++ b/code/modules/admin/verbs/adminjump.dm @@ -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" diff --git a/code/modules/mob/abstract/freelook/visualnet.dm b/code/modules/mob/abstract/freelook/visualnet.dm index 2a699845067..e6dcbec2bfb 100644 --- a/code/modules/mob/abstract/freelook/visualnet.dm +++ b/code/modules/mob/abstract/freelook/visualnet.dm @@ -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 diff --git a/code/modules/mob/abstract/observer/observer.dm b/code/modules/mob/abstract/observer/observer.dm index c6cd8f0ef5e..7e7226540a2 100644 --- a/code/modules/mob/abstract/observer/observer.dm +++ b/code/modules/mob/abstract/observer/observer.dm @@ -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 [following].")) - 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 [target].")) updateghostsight() -/mob/abstract/observer/proc/stop_following() - if(following) - to_chat(src, SPAN_NOTICE("No longer following \the [following].")) - 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" diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 9675a79461c..665a493e377 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -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 diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 98a544da6e6..630bc0b0afa 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -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 diff --git a/code/modules/multiz/movement.dm b/code/modules/multiz/movement.dm index 831548a5bd9..b247cb89eed 100644 --- a/code/modules/multiz/movement.dm +++ b/code/modules/multiz/movement.dm @@ -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 . = ..() diff --git a/code/modules/orbit/orbit.dm b/code/modules/orbit/orbit.dm deleted file mode 100644 index 1a151529119..00000000000 --- a/code/modules/orbit/orbit.dm +++ /dev/null @@ -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) diff --git a/code/modules/overmap/ships/computers/ship.dm b/code/modules/overmap/ships/computers/ship.dm index f07891e265e..f25dbbb16e3 100644 --- a/code/modules/overmap/ships/computers/ship.dm +++ b/code/modules/overmap/ships/computers/ship.dm @@ -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) diff --git a/code/modules/power/power_usage.dm b/code/modules/power/power_usage.dm index 645459a4283..3147f65d080 100644 --- a/code/modules/power/power_usage.dm +++ b/code/modules/power/power_usage.dm @@ -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) diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm index 4be449f4f73..9e1415b1630 100644 --- a/code/modules/power/tesla/energy_ball.dm +++ b/code/modules/power/tesla/energy_ball.dm @@ -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) diff --git a/code/modules/projectiles/targeting/targeting_overlay.dm b/code/modules/projectiles/targeting/targeting_overlay.dm index 810d39e642c..846b16a4ac8 100644 --- a/code/modules/projectiles/targeting/targeting_overlay.dm +++ b/code/modules/projectiles/targeting/targeting_overlay.dm @@ -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 diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm index 88919569e96..fcdc0b24b38 100644 --- a/code/modules/surgery/implant.dm +++ b/code/modules/surgery/implant.dm @@ -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("[user] could not find anything inside [target]'s [affected.name], and pulls \the [tool] out.", \ diff --git a/code/modules/telesci/gps.dm b/code/modules/telesci/gps.dm index e0a1efa5fce..d7b9f03be35 100644 --- a/code/modules/telesci/gps.dm +++ b/code/modules/telesci/gps.dm @@ -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"] diff --git a/code/unit_tests/observation_tests.dm b/code/unit_tests/observation_tests.dm index 44c44f44def..5ea7ed39237 100644 --- a/code/unit_tests/observation_tests.dm +++ b/code/unit_tests/observation_tests.dm @@ -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 diff --git a/html/changelogs/fluffyghost-refactormovementobservableaway.yml b/html/changelogs/fluffyghost-refactormovementobservableaway.yml new file mode 100644 index 00000000000..d322427edc7 --- /dev/null +++ b/html/changelogs/fluffyghost-refactormovementobservableaway.yml @@ -0,0 +1,60 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# - (fixes bugs) +# wip +# - (work in progress) +# qol +# - (quality of life) +# soundadd +# - (adds a sound) +# sounddel +# - (removes a sound) +# rscadd +# - (adds a feature) +# rscdel +# - (removes a feature) +# imageadd +# - (adds an image or sprite) +# imagedel +# - (removes an image or sprite) +# spellcheck +# - (fixes spelling or grammar) +# experiment +# - (experimental change) +# balance +# - (balance changes) +# code_imp +# - (misc internal code change) +# refactor +# - (refactors code) +# config +# - (makes a change to the config files) +# admin +# - (makes changes to administrator tools) +# server +# - (miscellaneous changes to server) +################################# + +# Your name. +author: FluffyGhost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit. +# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog. +changes: + - refactor: "Refactored movement observable away, use only the signal." + - refactor: "Refactored and fixed orbiter for ghosts." + - code_imp: "Some tweaks to the signal."