Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tweak(following): ghosts can orbit now #11223

Merged
merged 3 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions baystation12.dme
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@
#include "code\controllers\subsystems\mapping.dm"
#include "code\controllers\subsystems\misc_late.dm"
#include "code\controllers\subsystems\open_space.dm"
#include "code\controllers\subsystems\orbit.dm"
#include "code\controllers\subsystems\overlays.dm"
#include "code\controllers\subsystems\plants.dm"
#include "code\controllers\subsystems\radiation.dm"
Expand Down Expand Up @@ -2490,6 +2491,7 @@
#include "code\modules\nano\modules\human_appearance.dm"
#include "code\modules\nano\modules\law_manager.dm"
#include "code\modules\nano\modules\nano_module.dm"
#include "code\modules\orbit\orbit.dm"
#include "code\modules\paperwork\adminpaper.dm"
#include "code\modules\paperwork\carbonpaper.dm"
#include "code\modules\paperwork\clipboard.dm"
Expand Down
4 changes: 4 additions & 0 deletions code/__defines/ces/signals_global.dm
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@

#define SIGNAL_MOB_RESIST "!mob_resist"
#define SIGNAL_MOB_GRAB_SET_STATE "!mob_grab_set_state"

#define SIGNAL_ORBIT_BEGIN "orbit_begin"

#define SIGNAL_ORBIT_STOP "orbit_stop"
1 change: 1 addition & 0 deletions code/__defines/subsystem-priority.dm
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define SS_PRIORITY_MACHINERY 95 // Machinery + powernet ticks.
#define SS_PRIORITY_PHYSICS 94
#define SS_PRIORITY_AIR 80 // ZAS processing.
#define SS_PRIORITY_ORBIT 35
#define SS_PRIORITY_ALARM 20 // Alarm processing.
#define SS_PRIORITY_EVENT 20 // Event processing and queue handling.
#define SS_PRIORITY_STORYTELLER 20
Expand Down
32 changes: 22 additions & 10 deletions code/_helpers/matrices.dm
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,28 @@
Multiply(others)
return src

/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)
speed /= 3 //Gives us 3 equal time segments for our three turns.
//Why not one turn? Because byond will see that the start and finish are the same place and do nothing
//Why not two turns? Because byond will do a flip instead of a turn
animate(src, transform = m120, time = speed, loops)
animate(transform = m240, time = speed)
animate(transform = m360, time = speed)
/atom/proc/SpinAnimation(speed = 10, loops = -1, clockwise = TRUE, segments = 3)
if(!segments)
return

var/segment = 360/segments
if(!clockwise)
segment = -segment

var/list/matrices = list()
for(var/i in 1 to segments-1)
var/matrix/M = matrix(transform)
M.Turn(segment*i)
matrices += M

var/matrix/last = matrix(transform)
matrices += last

speed /= segments

animate(src, transform = matrices[1], time = speed, loops)
for(var/i in 2 to segments)
animate(transform = matrices[i], time = speed)

/atom/proc/shake_animation(intensity = 8, stime = 6)
var/init_px = pixel_x
Expand Down
50 changes: 50 additions & 0 deletions code/controllers/subsystems/orbit.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
SUBSYSTEM_DEF(orbit)
name = "Orbit"

priority = SS_PRIORITY_ORBIT
wait = 2

flags = SS_NO_INIT | SS_TICKER

var/list/currentrun = list()
var/list/orbits = list()

/datum/controller/subsystem/orbit/stat_entry()
..("P:[orbits.len]")

/datum/controller/subsystem/orbit/fire(resumed = 0)
if(!resumed)
src.currentrun = orbits.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)
orbits -= 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
9 changes: 9 additions & 0 deletions code/modules/mob/mob_movement.dm
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@
if ((A != src.loc && A && A.z == src.z))
src.last_move = get_dir(A, src.loc)

if(orbiters)
for(var/thing in orbiters)
var/datum/orbit/O = thing
O.Check()

var/datum/orbit/orbit = orbiting?.resolve()
if(istype(orbit))
orbit.Check()

SEND_SIGNAL(src, SIGNAL_MOVED, src, old_loc, loc)

/proc/step_glide(atom/movable/am, dir, glide_size_override)
Expand Down
27 changes: 20 additions & 7 deletions code/modules/mob/observer/ghost/ghost.dm
Original file line number Diff line number Diff line change
Expand Up @@ -451,20 +451,33 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
register_signal(following, SIGNAL_DIR_SET, /atom/proc/recursive_dir_set)
register_signal(following, SIGNAL_QDELETING, /mob/observer/ghost/proc/stop_following)

to_chat(src, SPAN_NOTICE("Now following \the [following]."))
move_to_turf(following, loc, following.loc)
glide_before_follow = src.glide_size
src.glide_size = target.glide_size
var/orbitsize
if(target.icon)
var/icon/I = icon(target.icon, target.icon_state, target.dir)
orbitsize = (I.Width() + I.Height()) * 0.5
else
orbitsize = world.icon_size
orbitsize -= (orbitsize / world.icon_size) * (world.icon_size * 0.25)

var/datum/orbit/orbit = orbiting?.resolve()
if(istype(orbit) && orbit.orbiting != target)
to_chat(src, "<span class='notice'>Now following \the [target].</span>")

forceMove(target)
orbit(target, orbitsize, FALSE, 20, 36)

/mob/dead/observer/orbit()
set_dir(WEST) // Reset dir so the right directional sprites show up
..()

/mob/observer/ghost/proc/stop_following()
if(following)
if(orbiting)
stop_orbit()
to_chat(src, SPAN_NOTICE("No longer following \the [following]."))
unregister_signal(following, SIGNAL_MOVED)
unregister_signal(following, SIGNAL_DIR_SET)
unregister_signal(following, SIGNAL_QDELETING)
following = null
glide_size = glide_before_follow
glide_before_follow = 0

/mob/observer/ghost/move_to_turf(atom/movable/am, old_loc, new_loc)
var/turf/T = get_turf(new_loc)
Expand Down
121 changes: 121 additions & 0 deletions code/modules/orbit/orbit.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/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.orbits += src
if(!orbiting.orbiters)
orbiting.orbiters = list()
orbiting.orbiters += src

if(orbiter.orbiting)
orbiter.stop_orbit()
orbiter.orbiting = src

if(!Check())
return

lock = _lock

SEND_SIGNAL(orbiter, SIGNAL_ORBIT_BEGIN, orbiting)

//do not qdel directly, use stop_orbit on the orbiter. (This way the orbiter can bind to the orbit stopping)
/datum/orbit/Destroy()
SEND_SIGNAL(orbiter, SIGNAL_ORBIT_STOP, orbiting)
SSorbit.orbits -= 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_self()
return FALSE

if(!orbiting)
orbiter.stop_orbit()
return FALSE

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 FALSE

orbiter.loc = targetloc
lastloc = orbiter.loc
return TRUE

/atom/movable
var/weakref/orbiting = null
var/cached_transform = null

/atom
var/list/orbiters = null

/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)
cached_transform = initial_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)

/atom/movable/proc/stop_orbit()
SpinAnimation(0, 0)
qdel(orbiting)
transform = cached_transform

/atom/Destroy()
. = ..()
if(orbiters)
for(var/thing in orbiters)
var/datum/orbit/O = thing
if(O.orbiter)
O.orbiter.stop_orbit()

/atom/movable/Destroy()
. = ..()
if(orbiting)
stop_orbit()
Loading