update orbiting (#7469)

<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may
not be viewable. -->
<!-- You can view Contributing.MD for a detailed description of the pull
request process. -->

## About The Pull Request

<!-- Describe The Pull Request. Please be sure every change is
documented or this can delay review and even discourage maintainers from
merging your PR! -->

## Why It's Good For The Game

<!-- Argue for the merits of your changes and how they benefit the game,
especially if they are controversial and/or far reaching. If you can't
actually explain WHY what you are doing will improve the game, then it
probably isn't good for the game in the first place. -->

## Changelog

<!-- If your PR modifies aspects of the game that can be concretely
observed by players or admins you should add a changelog. If your change
does NOT meet this description, remove this section. Please note that
maintainers freely reserve the right to remove and add tags should they
deem it appropriate. You can attempt to finagle the system all you want,
but it's best to shoot for clear communication right off the bat. -->

🆑
code: updated WrapAdminProcCall so it doesnt sleep (remove the waiting
feature)
tweak: you can now see how many people are orbiting something
/🆑

<!-- Both 🆑's are required for the changelog to work! You can put
your name to the right of the first 🆑 if you want to overwrite your
GitHub username as author ingame. -->
<!-- You can use multiple of the same prefix (they're only used for the
icon ingame) and delete the unneeded ones. Despite some of the tags,
changelogs should generally represent how a player might be affected by
the changes rather than a summary of the PR's contents. -->
This commit is contained in:
Letter N
2026-01-12 11:18:13 -05:00
committed by GitHub
parent f08f02e4c3
commit 05dc930edd
21 changed files with 432 additions and 135 deletions
+104 -53
View File
@@ -1,7 +1,12 @@
/datum/component/orbiter
can_transfer = TRUE
dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
var/list/orbiters
/// Assoc list of all orbiters -> their initial matrix
var/list/orbiter_list
/// Assoc list of orbiters -> their orbiting parameters
var/list/orbiter_params
/// Movement tracker used to check when our owner moves
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
@@ -12,33 +17,34 @@
if(!istype(orbiter) || !isatom(parent) || isarea(parent))
return COMPONENT_INCOMPATIBLE
orbiters = list()
var/atom/master = parent
master.orbiters = src
orbiter_list = list()
orbiter_params = list()
begin_orbit(orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
/datum/component/orbiter/RegisterWithParent()
. = ..()
var/atom/target = parent
while(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(move_react))
target = target.loc
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))
/datum/component/orbiter/UnregisterFromParent()
. = ..()
UnregisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE)
var/atom/target = parent
while(ismovable(target))
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
target = target.loc
target.orbiters = null
QDEL_NULL(tracker)
/datum/component/orbiter/Destroy()
var/atom/master = parent
master.orbiters = null
for(var/i in orbiters)
if(master.orbiters == src)
master.orbiters = null
for(var/i in orbiter_list)
end_orbit(i)
orbiters = null
orbiter_list = null
orbiter_params = null
return ..()
/datum/component/orbiter/InheritComponent(datum/component/orbiter/newcomp, original, atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
@@ -46,26 +52,43 @@
begin_orbit(arglist(args.Copy(3)))
return
// The following only happens on component transfers
orbiters += newcomp.orbiters
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, list(COMSIG_MOVABLE_MOVED /*, COMSIG_ATOM_BEFORE_SHUTTLE_MOVE, COMSIG_ATOM_AFTER_SHUTTLE_MOVE */))
RegisterSignal(incoming_orbiter, COMSIG_MOVABLE_MOVED, PROC_REF(orbiter_move_react))
// RegisterSignal(incoming_orbiter, COMSIG_ATOM_BEFORE_SHUTTLE_MOVE, PROC_REF(orbiter_before_shuttle_move))
/datum/component/orbiter/PostTransfer()
if(!isatom(parent) || isarea(parent) || !get_turf(parent))
orbiter_list += newcomp.orbiter_list
orbiter_params += newcomp.orbiter_params
newcomp.orbiter_list = null
newcomp.orbiter_params = null
/datum/component/orbiter/PostTransfer(datum/new_parent)
if(!isatom(new_parent) || isarea(new_parent) || !get_turf(new_parent))
return COMPONENT_INCOMPATIBLE
move_react()
move_react(new_parent)
/datum/component/orbiter/proc/begin_orbit(atom/movable/orbiter, radius, clockwise, rotation_speed, rotation_segments, pre_rotation)
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_BEGIN, 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_params[orbiter] = args.Copy(2)
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))
// RegisterSignal(orbiter, COMSIG_ATOM_BEFORE_SHUTTLE_MOVE, PROC_REF(orbiter_before_shuttle_move))
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_BEGIN, orbiter)
var/matrix/initial_transform = matrix(orbiter.transform)
orbiters[orbiter] = initial_transform
orbiter_list[orbiter] = initial_transform
// Head first!
if(pre_rotation)
@@ -82,28 +105,59 @@
orbiter.SpinAnimation(rotation_speed, -1, clockwise, rotation_segments, parallel = FALSE)
orbiter.forceMove(get_turf(parent))
to_chat(orbiter, "<span class='notice'>Now orbiting [parent].</span>")
// 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/orbiter_before_shuttle_move(atom/source)
SIGNAL_HANDLER
// We need to detach ourselves before the shuttle moves and reattach afterwards
end_orbit(source, TRUE)
// RegisterSignal(source, COMSIG_ATOM_AFTER_SHUTTLE_MOVE, PROC_REF(orbiter_after_shuttle_move))
/datum/component/orbiter/proc/orbiter_after_shuttle_move(atom/source)
SIGNAL_HANDLER
// UnregisterSignal(source, COMSIG_ATOM_AFTER_SHUTTLE_MOVE)
begin_orbit(arglist(list(source) + orbiter_params[source]))
/datum/component/orbiter/proc/end_orbit(atom/movable/orbiter, refreshing=FALSE)
if(!orbiters[orbiter])
if(!orbiter_list[orbiter])
return
SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_END, orbiter, refreshing)
UnregisterSignal(orbiter, COMSIG_MOVABLE_MOVED)
orbiter.SpinAnimation(0, 0, parallel = FALSE)
if(istype(orbiters[orbiter],/matrix)) //This is ugly.
orbiter.transform = orbiters[orbiter]
orbiters -= orbiter
UnregisterSignal(orbiter, list(COMSIG_MOVABLE_MOVED /*, COMSIG_ATOM_BEFORE_SHUTTLE_MOVE, COMSIG_ATOM_AFTER_SHUTTLE_MOVE */))
// SEND_SIGNAL(parent, COMSIG_ATOM_ORBIT_STOP, orbiter) // on tg used by ghost player plays
orbiter.SpinAnimation(0, 0)
if(istype(orbiter_list[orbiter],/matrix)) //This is ugly.
orbiter.transform = orbiter_list[orbiter]
orbiter_list -= orbiter
if(!refreshing)
orbiter_params -= orbiter
orbiter.stop_orbit(src)
orbiter.orbiting = null
if(!refreshing && !length(orbiters) && !QDELING(src))
if(ismob(orbiter))
var/mob/orbiter_mob = orbiter
// orbiter_mob.updating_glide_size = TRUE
orbiter_mob.glide_size = 8
if(isobserver(orbiter))
var/mob/observer/dead/ghostie = orbiter
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/orbited, atom/oldloc, direction)
/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
var/atom/movable/master = parent
if(master.loc == oldloc)
return
@@ -111,41 +165,38 @@
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(ismovable(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(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(move_react), 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)
for(var/atom/movable/movable_orbiter as anything in orbiter_list)
if(QDELETED(movable_orbiter) || movable_orbiter.loc == newturf)
continue
thing.forceMove(newturf)
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)