diff --git a/code/__DEFINES/components.dm b/code/__DEFINES/components.dm
index dbe8cfbb62..210bdf57a6 100644
--- a/code/__DEFINES/components.dm
+++ b/code/__DEFINES/components.dm
@@ -130,6 +130,7 @@
#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack" //from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
#define COMSIG_MOB_ATTACK_RANGED "mob_attack_ranged" //from base of mob/RangedAttack(): (atom/A, params)
#define COMSIG_MOB_THROW "mob_throw" //from base of /mob/throw_item(): (atom/target)
+#define COMSIG_MOB_UPDATE_SIGHT "mob_update_sight" //from base of /mob/update_sight(): ()
// /mob/living signals
#define COMSIG_LIVING_RESIST "living_resist" //from base of mob/living/resist() (/mob/living)
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index f54a0542f4..ecd1ef1e21 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -102,7 +102,6 @@
#define FIRE_PRIORITY_SPACEDRIFT 30
#define FIRE_PRIORITY_FIELDS 30
#define FIRE_PRIOTITY_SMOOTHING 35
-#define FIRE_PRIORITY_ORBIT 35
#define FIRE_PRIORITY_NETWORKS 40
#define FIRE_PRIORITY_OBJ 40
#define FIRE_PRIORITY_ACID 40
diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm
index 8b77b170e0..d96ec76a7c 100644
--- a/code/__HELPERS/matrices.dm
+++ b/code/__HELPERS/matrices.dm
@@ -2,7 +2,7 @@
. = new_angle - old_angle
Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT
-/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3)
+/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = 1, segments = 3, parallel = TRUE)
if(!segments)
return
var/segment = 360/segments
@@ -18,7 +18,11 @@
speed /= segments
- animate(src, transform = matrices[1], time = speed, loops)
+ if(parallel)
+ animate(src, transform = matrices[1], time = speed, loops , flags = ANIMATION_PARALLEL)
+ else
+ animate(src, transform = matrices[1], time = speed, 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
diff --git a/code/controllers/subsystem/augury.dm b/code/controllers/subsystem/augury.dm
index 875f1ee7d3..1b1c7bc3b7 100644
--- a/code/controllers/subsystem/augury.dm
+++ b/code/controllers/subsystem/augury.dm
@@ -50,7 +50,7 @@ SUBSYSTEM_DEF(augury)
watchers -= w
continue
var/mob/dead/observer/O = w
- if(biggest_doom && (!O.orbiting || O.orbiting.orbiting != biggest_doom))
+ if(biggest_doom && (!O.orbiting || O.orbiting.parent != biggest_doom))
O.ManualFollow(biggest_doom)
/datum/action/innate/augury
diff --git a/code/controllers/subsystem/orbit.dm b/code/controllers/subsystem/orbit.dm
deleted file mode 100644
index 45d280b601..0000000000
--- a/code/controllers/subsystem/orbit.dm
+++ /dev/null
@@ -1,44 +0,0 @@
-SUBSYSTEM_DEF(orbit)
- name = "Orbits"
- priority = FIRE_PRIORITY_ORBIT
- wait = 2
- flags = SS_NO_INIT|SS_TICKER
-
- var/list/currentrun = list()
- var/list/processing = list()
-
-/datum/controller/subsystem/orbit/stat_entry()
- ..("P:[processing.len]")
-
-
-/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 0000000000..301e50dc42
--- /dev/null
+++ b/code/datums/components/orbiter.dm
@@ -0,0 +1,156 @@
+/datum/component/orbiter
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+ var/list/orbiters
+ var/datum/callback/orbiter_spy
+ var/datum/callback/orbited_spy
+
+//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
+
+ orbiters = list()
+ orbiter_spy = CALLBACK(src, .proc/orbiter_move_react)
+ orbited_spy = CALLBACK(src, .proc/move_react)
+
+ var/atom/master = parent
+ master.orbiters = src
+
+ begin_orbit(orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
+
+/datum/component/orbiter/RegisterWithParent()
+ var/atom/target = parent
+ while(ismovableatom(target))
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, orbited_spy)
+ target = target.loc
+
+/datum/component/orbiter/UnregisterFromParent()
+ var/atom/target = parent
+ while(ismovableatom(target))
+ UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
+ target = target.loc
+
+/datum/component/orbiter/Destroy()
+ var/atom/master = parent
+ master.orbiters = null
+ for(var/i in orbiters)
+ end_orbit(i)
+ orbiters = null
+ QDEL_NULL(orbiter_spy)
+ QDEL_NULL(orbited_spy)
+ return ..()
+
+/datum/component/orbiter/InheritComponent(datum/component/orbiter/newcomp, original, list/arguments)
+ if(arguments)
+ begin_orbit(arglist(arguments))
+ return
+ // The following only happens on component transfers
+ orbiters += newcomp.orbiters
+
+/datum/component/orbiter/PostTransfer()
+ if(!isatom(parent) || isarea(parent) || !get_turf(parent))
+ return COMPONENT_INCOMPATIBLE
+ move_react()
+
+/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)
+ orbiters[orbiter] = TRUE
+ orbiter.orbiting = src
+ RegisterSignal(orbiter, COMSIG_MOVABLE_MOVED, orbiter_spy)
+ var/matrix/initial_transform = matrix(orbiter.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)
+
+ //we stack the orbits up client side, so we can assign this back to normal server side without it breaking the orbit
+ orbiter.transform = initial_transform
+ orbiter.forceMove(get_turf(parent))
+ to_chat(orbiter, "Now orbiting [parent].")
+
+/datum/component/orbiter/proc/end_orbit(atom/movable/orbiter, refreshing=FALSE)
+ if(!orbiters[orbiter])
+ return
+ UnregisterSignal(orbiter, COMSIG_MOVABLE_MOVED)
+ orbiter.SpinAnimation(0, 0)
+ orbiters -= orbiter
+ orbiter.stop_orbit(src)
+ orbiter.orbiting = null
+ if(!refreshing && !length(orbiters) && !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/orbited, atom/oldloc, direction)
+ set waitfor = FALSE // Transfer calls this directly and it doesnt care if the ghosts arent done moving
+
+ var/atom/movable/master = parent
+ if(master.loc == oldloc)
+ return
+
+ var/turf/newturf = get_turf(master)
+ if(!newturf)
+ qdel(src)
+
+ // Handling the signals of stuff holding us (or not anymore)
+ // These are prety rarely activated, how often are you following something in a bag?
+ if(oldloc && !isturf(oldloc)) // We used to be registered to it, probably
+ var/atom/target = oldloc
+ while(ismovableatom(target))
+ UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
+ target = target.loc
+ if(orbited?.loc && orbited.loc != newturf) // We want to know when anything holding us moves too
+ var/atom/target = orbited.loc
+ while(ismovableatom(target))
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, orbited_spy, TRUE)
+ target = target.loc
+
+ var/atom/curloc = master.loc
+ for(var/i in orbiters)
+ var/atom/movable/thing = i
+ if(QDELETED(thing) || thing.loc == newturf)
+ continue
+ thing.forceMove(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)
+ if(orbiter.loc == get_turf(parent))
+ return
+ end_orbit(orbiter)
+
+/////////////////////
+
+/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
+
+ return A.AddComponent(/datum/component/orbiter, src, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
+
+/atom/movable/proc/stop_orbit(datum/component/orbiter/orbits)
+ 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/game/atoms.dm b/code/game/atoms.dm
index 81e2371f9a..f2eb23808e 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -31,6 +31,8 @@
var/list/filter_data //For handling persistent filters
+ var/datum/component/orbiter/orbiters
+
var/rad_flags = NONE // Will move to flags_1 when i can be arsed to
var/rad_insulation = RAD_NO_INSULATION
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index c37c120b93..f88f4f8e41 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -31,6 +31,7 @@
var/atom/movable/pulling
var/grab_state = 0
var/throwforce = 0
+ var/datum/component/orbiter/orbiting
var/can_be_z_moved = TRUE
/atom/movable/vv_edit_var(var_name, var_value)
@@ -296,14 +297,7 @@
if (length(client_mobs_in_contents))
update_parallax_contents()
- if (orbiters)
- for (var/thing in orbiters)
- var/datum/orbit/O = thing
- O.Check()
- if (orbiting)
- orbiting.Check()
-
- return 1
+ return TRUE
/atom/movable/Destroy(force)
QDEL_NULL(proximity_monitor)
@@ -325,6 +319,10 @@
if(pulledby)
pulledby.stop_pulling()
+ if(orbiting)
+ orbiting.end_orbit(src)
+ orbiting = null
+
// Make sure you know what you're doing if you call this, this is intended to only be called by byond directly.
// You probably want CanPass()
/atom/movable/Cross(atom/movable/AM)
diff --git a/code/game/machinery/dance_machine.dm b/code/game/machinery/dance_machine.dm
index 7beb32eebb..1c6d713437 100644
--- a/code/game/machinery/dance_machine.dm
+++ b/code/game/machinery/dance_machine.dm
@@ -214,11 +214,11 @@
sparkles += S
switch(i)
if(1 to 8)
- S.orbit(src, 30, TRUE, 60, 36, TRUE, FALSE)
+ S.orbit(src, 30, TRUE, 60, 36, TRUE)
if(9 to 16)
- S.orbit(src, 62, TRUE, 60, 36, TRUE, FALSE)
+ S.orbit(src, 62, TRUE, 60, 36, TRUE)
if(17 to 24)
- S.orbit(src, 95, TRUE, 60, 36, TRUE, FALSE)
+ S.orbit(src, 95, TRUE, 60, 36, TRUE)
if(25)
S.pixel_y = 7
S.forceMove(get_turf(src))
diff --git a/code/modules/antagonists/cult/cult_comms.dm b/code/modules/antagonists/cult/cult_comms.dm
index 8452f78ed3..761412e9f8 100644
--- a/code/modules/antagonists/cult/cult_comms.dm
+++ b/code/modules/antagonists/cult/cult_comms.dm
@@ -342,10 +342,7 @@
if(cooldown>world.time)
to_chat(owner, "You aren't ready to place another blood mark yet!")
return
- if(owner.orbiting && owner.orbiting.orbiting)
- target = owner.orbiting.orbiting
- else
- target = get_turf(owner)
+ target = owner.orbiting?.parent || get_turf(owner)
if(!target)
return
C.cult_team.blood_target = target
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 0990ca961a..eaac1984e3 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -273,23 +273,12 @@
to_chat(user, "You release the wisp. It begins to bob around your head.")
icon_state = "lantern"
wisp.orbit(user, 20)
- user.update_sight()
SSblackbox.record_feedback("tally", "wisp_lantern", 1, "Freed")
else
to_chat(user, "You return the wisp to the lantern.")
-
- var/mob/target
- if(wisp.orbiting)
- target = wisp.orbiting.orbiting
- wisp.stop_orbit()
- wisp.forceMove(src)
-
- if (istype(target))
- target.update_sight()
- to_chat(target, "Your vision returns to normal.")
-
icon_state = "lantern-blue"
+ wisp.forceMove(src)
SSblackbox.record_feedback("tally", "wisp_lantern", 1, "Returned")
/obj/item/wisp_lantern/Initialize()
@@ -302,7 +291,7 @@
qdel(wisp)
else
wisp.visible_message("[wisp] has a sad feeling for a moment, then it passes.")
- ..()
+ return ..()
/obj/effect/wisp
name = "friendly wisp"
@@ -314,6 +303,25 @@
var/sight_flags = SEE_MOBS
var/lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
+/obj/effect/wisp/orbit(atom/thing, radius, clockwise, rotation_speed, rotation_segments, pre_rotation, lockinorbit)
+ . = ..()
+ if(ismob(thing))
+ RegisterSignal(thing, COMSIG_MOB_UPDATE_SIGHT, .proc/update_user_sight)
+ var/mob/being = thing
+ being.update_sight()
+ to_chat(thing, "The wisp enhances your vision.")
+
+/obj/effect/wisp/stop_orbit(datum/component/orbiter/orbits)
+ . = ..()
+ if(ismob(orbits.parent))
+ UnregisterSignal(orbits.parent, COMSIG_MOB_UPDATE_SIGHT)
+ to_chat(orbits.parent, "Your vision returns to normal.")
+
+/obj/effect/wisp/proc/update_user_sight(mob/user)
+ user.sight |= sight_flags
+ if(!isnull(lighting_alpha))
+ user.lighting_alpha = min(user.lighting_alpha, lighting_alpha)
+
//Red/Blue Cubes
/obj/item/warp_cube
name = "blue cube"
@@ -781,19 +789,17 @@
var/turf/T = get_turf(src)
var/list/contents = T.GetAllContents()
var/mob/dead/observer/current_spirits = list()
- var/list/orbiters = list()
for(var/thing in contents)
var/atom/A = thing
- if (A.orbiters)
- orbiters += A.orbiters
+ A.transfer_observers_to(src)
- for(var/thing in orbiters)
- var/datum/orbit/O = thing
- if (isobserver(O.orbiter))
- var/mob/dead/observer/G = O.orbiter
- ghost_counter++
- G.invisibility = 0
- current_spirits |= G
+ for(var/i in orbiters?.orbiters)
+ if(!isobserver(i))
+ continue
+ var/mob/dead/observer/G = i
+ ghost_counter++
+ G.invisibility = 0
+ current_spirits |= G
for(var/mob/dead/observer/G in spirits - current_spirits)
G.invisibility = GLOB.observer_default_invisibility
diff --git a/code/modules/mob/camera/camera.dm b/code/modules/mob/camera/camera.dm
index 883f5a034f..c780d57810 100644
--- a/code/modules/mob/camera/camera.dm
+++ b/code/modules/mob/camera/camera.dm
@@ -26,7 +26,9 @@
return
/mob/camera/forceMove(atom/destination)
+ var/oldloc = loc
loc = destination
+ Moved(oldloc, NONE, TRUE)
/mob/camera/emote(act, m_type=1, message = null, intentional = FALSE)
return
diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm
index d886a41b0f..381dc131e7 100644
--- a/code/modules/mob/dead/dead.dm
+++ b/code/modules/mob/dead/dead.dm
@@ -34,7 +34,9 @@ INITIALIZE_IMMEDIATE(/mob/dead)
var/turf/new_turf = get_turf(destination)
if (old_turf?.z != new_turf?.z)
onTransitZ(old_turf?.z, new_turf?.z)
+ var/oldloc = loc
loc = destination
+ Moved(oldloc, NONE, TRUE)
/mob/dead/Stat()
..()
diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm
index 55b8891534..8bfba07fe4 100644
--- a/code/modules/mob/dead/observer/observer.dm
+++ b/code/modules/mob/dead/observer/observer.dm
@@ -429,9 +429,6 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
var/orbitsize = (I.Width()+I.Height())*0.5
orbitsize -= (orbitsize/world.icon_size)*(world.icon_size*0.25)
- if(orbiting && orbiting.orbiting != target)
- to_chat(src, "Now orbiting [target].")
-
var/rot_seg
switch(ghost_orbit)
@@ -450,10 +447,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
/mob/dead/observer/orbit()
setDir(2)//reset dir so the right directional sprites show up
- ..()
+ return ..()
-/mob/dead/observer/stop_orbit()
- ..()
+/mob/dead/observer/stop_orbit(datum/component/orbiter/orbits)
+ . = ..()
//restart our floating animation after orbit is done.
pixel_y = 0
animate(src, pixel_y = 2, time = 10, loop = -1)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 7ff8fbc0b1..641c80f188 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -871,13 +871,7 @@
return
/mob/proc/update_sight()
- for(var/O in orbiters)
- var/datum/orbit/orbit = O
- var/obj/effect/wisp/wisp = orbit.orbiter
- if (istype(wisp))
- sight |= wisp.sight_flags
- if(!isnull(wisp.lighting_alpha))
- lighting_alpha = min(lighting_alpha, wisp.lighting_alpha)
+ SEND_SIGNAL(src, COMSIG_MOB_UPDATE_SIGHT)
sync_lighting_plane_alpha()
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 33f1ec81c1..82e2b11f8e 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -148,7 +148,7 @@
if(INCORPOREAL_MOVE_BASIC)
var/T = get_step(L,direct)
if(T)
- L.loc = T
+ L.forceMove(T)
L.setDir(direct)
if(INCORPOREAL_MOVE_SHADOW)
if(prob(50))
@@ -190,7 +190,7 @@
new /obj/effect/temp_visual/dir_setting/ninja/shadow(mobloc, L.dir)
var/T = get_step(L,direct)
if(T)
- L.loc = T
+ L.forceMove(T)
L.setDir(direct)
if(INCORPOREAL_MOVE_JAUNT) //Incorporeal move, but blocked by holy-watered tiles and salt piles.
var/turf/open/floor/stepTurf = get_step(L, direct)
@@ -209,7 +209,7 @@
to_chat(L, "Holy energies block your path!")
return
- L.loc = get_step(L, direct)
+ L.forceMove(stepTurf)
L.setDir(direct)
return TRUE
diff --git a/code/modules/orbit/orbit.dm b/code/modules/orbit/orbit.dm
deleted file mode 100644
index 79685b9104..0000000000
--- a/code/modules/orbit/orbit.dm
+++ /dev/null
@@ -1,135 +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, list/checked_already = list())
- //Avoid infinite loops for people who end up orbiting themself through another orbiter
- checked_already[src] = TRUE
- 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()
- var/atom/movable/AM = orbiting
- if(istype(AM) && AM.orbiting && AM.orbiting.orbiting == orbiter)
- orbiter.stop_orbit()
- return
- lastprocess = world.time
- if (!targetloc)
- targetloc = get_turf(orbiting)
- if (!targetloc || (!lock && orbiter.loc != lastloc && orbiter.loc != targetloc))
- orbiter.stop_orbit()
- return
- var/turf/old_turf = get_turf(orbiter)
- var/turf/new_turf = get_turf(targetloc)
- if (old_turf?.z != new_turf?.z)
- orbiter.onTransitZ(old_turf?.z, new_turf?.z)
- // DO NOT PORT TO FORCEMOVE - MEMECODE WILL KILL MC
- orbiter.loc = targetloc
- orbiter.update_parallax_contents()
- orbiter.update_light()
- lastloc = orbiter.loc
- for(var/other_orbit in orbiter.orbiters)
- var/datum/orbit/OO = other_orbit
- //Skip if checked already
- if(checked_already[OO])
- continue
- OO.Check(targetloc, checked_already)
-
-/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)
-//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
-//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, clockwise = FALSE, rotation_speed = 20, rotation_segments = 36, 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)
- var/pre_rot = 90
- if(!clockwise)
- pre_rot = -90
- M.Turn(pre_rot)
- transform = M
-
- var/matrix/shift = matrix(transform)
- shift.Translate(0,radius)
- transform = shift
-
- SpinAnimation(rotation_speed, -1, clockwise, rotation_segments)
-
- //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(orbiting)
-
-/atom/Destroy(force = FALSE)
- . = ..()
- if (orbiters)
- for (var/thing in orbiters)
- var/datum/orbit/O = thing
- if (O.orbiter)
- O.orbiter.stop_orbit()
-
-/atom/movable/Destroy(force = FALSE)
- . = ..()
- if (orbiting)
- stop_orbit()
-
-/atom/movable/proc/transfer_observers_to(atom/movable/target)
- if(orbiters)
- for(var/thing in orbiters)
- var/datum/orbit/O = thing
- if(O.orbiter && isobserver(O.orbiter))
- var/mob/dead/observer/D = O.orbiter
- D.ManualFollow(target)
diff --git a/code/modules/power/tesla/energy_ball.dm b/code/modules/power/tesla/energy_ball.dm
index 0a54bcab33..bbad3e08b0 100644
--- a/code/modules/power/tesla/energy_ball.dm
+++ b/code/modules/power/tesla/energy_ball.dm
@@ -33,8 +33,8 @@
return
/obj/singularity/energy_ball/Destroy()
- if(orbiting && istype(orbiting.orbiting, /obj/singularity/energy_ball))
- var/obj/singularity/energy_ball/EB = orbiting.orbiting
+ if(orbiting && istype(orbiting.parent, /obj/singularity/energy_ball))
+ var/obj/singularity/energy_ball/EB = orbiting.parent
EB.orbiting_balls -= src
for(var/ball in orbiting_balls)
@@ -146,12 +146,12 @@
. = ..()
/obj/singularity/energy_ball/stop_orbit()
- if (orbiting && istype(orbiting.orbiting, /obj/singularity/energy_ball))
- var/obj/singularity/energy_ball/orbitingball = orbiting.orbiting
+ if (orbiting && istype(orbiting.parent, /obj/singularity/energy_ball))
+ var/obj/singularity/energy_ball/orbitingball = orbiting.parent
orbitingball.orbiting_balls -= src
orbitingball.dissipate_strength = orbitingball.orbiting_balls.len
- ..()
- if (!loc && !QDELETED(src))
+ . = ..()
+ if (!QDELETED(src))
qdel(src)
diff --git a/tgstation.dme b/tgstation.dme
index 988fc3c82c..1a8dd941ab 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -247,7 +247,6 @@
#include "code\controllers\subsystem\moods.dm"
#include "code\controllers\subsystem\nightshift.dm"
#include "code\controllers\subsystem\npcpool.dm"
-#include "code\controllers\subsystem\orbit.dm"
#include "code\controllers\subsystem\overlays.dm"
#include "code\controllers\subsystem\pai.dm"
#include "code\controllers\subsystem\parallax.dm"
@@ -360,6 +359,7 @@
#include "code\datums\components\mood.dm"
#include "code\datums\components\nanites.dm"
#include "code\datums\components\ntnet_interface.dm"
+#include "code\datums\components\orbiter.dm"
#include "code\datums\components\paintable.dm"
#include "code\datums\components\rad_insulation.dm"
#include "code\datums\components\radioactive.dm"
@@ -2265,7 +2265,6 @@
#include "code\modules\NTNet\network.dm"
#include "code\modules\NTNet\relays.dm"
#include "code\modules\NTNet\services\_service.dm"
-#include "code\modules\orbit\orbit.dm"
#include "code\modules\paperwork\clipboard.dm"
#include "code\modules\paperwork\contract.dm"
#include "code\modules\paperwork\filingcabinet.dm"