mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-14 11:42:27 +00:00
* Updates to orbit ui [READY] (#83186) ## About The Pull Request Pretty big orbit ui refactor. Check changelog for full list of features. <details> <summary>screenshots</summary> In game  Sort by department  Did you know ninjas had a hud icon that hasn't worked for four years?  Criticals  Orbit blade https://github.com/tgstation/tgstation/assets/42397676/99681548-bfb3-4895-9c95-3b650df71107 </details> ## Why It's Good For The Game Some QoL for the orbit menu, giving more info on where action is and isn't. Removes more of the uselocalstate hook which is deprecated anyways ## Changelog 🆑 fix: Fixed an issue preventing space ninjas from having a hud icon add: ORBIT UI CHANGES: add: AFK players are greyed out. add: Living NPCs now display health. add: Icons displayed are now based on hud icons, which includes icons for player-visible antagonists add: You can now sort by job department (click health icon) add: Round ending "critical" items will be listed at the top. add: Click the settings button to expand for more info add: Your current orbit target is highlighted. /🆑 * Updates to orbit ui [READY] --------- Co-authored-by: Jeremiah <42397676+jlsnow301@users.noreply.github.com>
186 lines
6.5 KiB
Plaintext
186 lines
6.5 KiB
Plaintext
/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))
|
|
|
|
/datum/component/orbiter/UnregisterFromParent()
|
|
UnregisterSignal(parent, COMSIG_MOVABLE_UPDATE_GLIDE_SIZE)
|
|
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)
|
|
|
|
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)
|
|
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
|
|
orbiter_mob.glide_size = 8
|
|
|
|
if(isobserver(orbiter))
|
|
var/mob/dead/observer/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/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)
|