diff --git a/code/__defines/MC.dm b/code/__defines/MC.dm
index 08b8d223ec7..fb15a693bf2 100644
--- a/code/__defines/MC.dm
+++ b/code/__defines/MC.dm
@@ -1,4 +1,15 @@
-#define MC_TICK_CHECK ( ( world.tick_usage > CURRENT_TICKLIMIT || src.state != SS_RUNNING ) ? pause() : 0 )
+#define MC_TICK_CHECK ( ( world.tick_usage > Master.current_ticklimit || src.state != SS_RUNNING ) ? pause() : 0 )
+
+// Used for splitting up your remaining time into phases, if you want to evenly divide it.
+#define MC_SPLIT_TICK_INIT(phase_count) var/original_tick_limit = Master.current_ticklimit; var/split_tick_phases = ##phase_count
+#define MC_SPLIT_TICK \
+ if(split_tick_phases > 1){\
+ Master.current_ticklimit = ((original_tick_limit - world.tick_usage) / split_tick_phases) + world.tick_usage;\
+ --split_tick_phases;\
+ } else {\
+ Master.current_ticklimit = original_tick_limit;\
+ }
+
// Used to smooth out costs to try and avoid oscillation.
#define MC_AVERAGE_FAST(average, current) (0.7 * (average) + 0.3 * (current))
#define MC_AVERAGE(average, current) (0.8 * (average) + 0.2 * (current))
@@ -10,39 +21,36 @@
//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
-//subsystem should fire during pre-game lobby.
-#define SS_FIRE_IN_LOBBY 1
-
//subsystem does not initialize.
-#define SS_NO_INIT 2
+#define SS_NO_INIT 1
//subsystem does not fire.
// (like can_fire = 0, but keeps it from getting added to the processing subsystems list)
// (Requires a MC restart to change)
-#define SS_NO_FIRE 4
+#define SS_NO_FIRE 2
//subsystem only runs on spare cpu (after all non-background subsystems have ran that tick)
// SS_BACKGROUND has its own priority bracket
-#define SS_BACKGROUND 8
+#define SS_BACKGROUND 4
//subsystem does not tick check, and should not run unless there is enough time (or its running behind (unless background))
-#define SS_NO_TICK_CHECK 16
+#define SS_NO_TICK_CHECK 8
//Treat wait as a tick count, not DS, run every wait ticks.
// (also forces it to run first in the tick, above even SS_NO_TICK_CHECK subsystems)
-// (implies SS_FIRE_IN_LOBBY because of how it works)
+// (implies all runlevels because of how it works)
// (overrides SS_BACKGROUND)
// This is designed for basically anything that works as a mini-mc (like SStimer)
-#define SS_TICKER 32
+#define SS_TICKER 16
//keep the subsystem's timing on point by firing early if it fired late last fire because of lag
// ie: if a 20ds subsystem fires say 5 ds late due to lag or what not, its next fire would be in 15ds, not 20ds.
-#define SS_KEEP_TIMING 64
+#define SS_KEEP_TIMING 32
//Calculate its next fire after its fired.
// (IE: if a 5ds wait SS takes 2ds to run, its next fire should be 5ds away, not 3ds like it normally would be)
// This flag overrides SS_KEEP_TIMING
-#define SS_POST_FIRE_TIMING 128
+#define SS_POST_FIRE_TIMING 64
//SUBSYSTEM STATES
#define SS_IDLE 0 //aint doing shit.
diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm
new file mode 100644
index 00000000000..8c546c9135a
--- /dev/null
+++ b/code/__defines/subsystems.dm
@@ -0,0 +1,13 @@
+
+// SS runlevels
+
+#define RUNLEVEL_INIT 0 // "Initialize Only" - Used for subsystems that should never be fired (Should also have SS_NO_FIRE set)
+#define RUNLEVEL_LOBBY 1 // Initial runlevel before setup. Returns to here if setup fails.
+#define RUNLEVEL_SETUP 2 // While the gamemode setup is running. I.E gameticker.setup()
+#define RUNLEVEL_GAME 4 // After successful game ticker setup, while the round is running.
+#define RUNLEVEL_POSTGAME 8 // When round completes but before reboot
+
+#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME)
+
+var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_GAME, RUNLEVEL_POSTGAME)
+#define RUNLEVEL_FLAG_TO_INDEX(flag) (log(2, flag) + 1) // Convert from the runlevel bitfield constants to index in runlevel_flags list
diff --git a/code/__defines/tick.dm b/code/__defines/tick.dm
index 3fa6e21bf3c..4c88fd643ea 100644
--- a/code/__defines/tick.dm
+++ b/code/__defines/tick.dm
@@ -3,5 +3,5 @@
#define TICK_LIMIT_MC 70
#define TICK_LIMIT_MC_INIT_DEFAULT 98
-#define TICK_CHECK ( world.tick_usage > CURRENT_TICKLIMIT )
+#define TICK_CHECK ( world.tick_usage > Master.current_ticklimit )
#define CHECK_TICK if TICK_CHECK stoplag()
diff --git a/code/_helpers/time.dm b/code/_helpers/time.dm
index b3989a32a4e..3a6bcedcd11 100644
--- a/code/_helpers/time.dm
+++ b/code/_helpers/time.dm
@@ -120,4 +120,4 @@ var/round_start_time = 0
. += round(i*DELTA_CALC)
sleep(i*world.tick_lag*DELTA_CALC)
i *= 2
- while (world.tick_usage > min(TICK_LIMIT_TO_RUN, CURRENT_TICKLIMIT))
+ while (world.tick_usage > min(TICK_LIMIT_TO_RUN, Master.current_ticklimit))
diff --git a/code/controllers/Processes/ticker.dm b/code/controllers/Processes/ticker.dm
index 6fa6d43237d..a70bb74c5ff 100644
--- a/code/controllers/Processes/ticker.dm
+++ b/code/controllers/Processes/ticker.dm
@@ -34,5 +34,9 @@ var/global/datum/controller/process/ticker/tickerProcess
/datum/controller/process/ticker/proc/getLastTickerTimeDuration()
return lastTickerTimeDuration
-/world/proc/has_round_started()
+// Use these preferentially to directly examining ticker.current_state to help prepare for transition to ticker as subsystem!
+/datum/controller/process/ticker/proc/HasRoundStarted()
return (ticker && ticker.current_state >= GAME_STATE_PLAYING)
+
+/datum/controller/process/ticker/proc/IsRoundInProgress()
+ return (ticker && ticker.current_state == GAME_STATE_PLAYING)
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 360b739badf..7c2bc86a651 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -7,14 +7,6 @@
*
**/
var/datum/controller/master/Master = new()
-var/MC_restart_clear = 0
-var/MC_restart_timeout = 0
-var/MC_restart_count = 0
-
-
-//current tick limit, assigned by the queue controller before running a subsystem.
-//used by check_tick as well so that the procs subsystems call can obey that SS's tick limits
-var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
/datum/controller/master
name = "Master"
@@ -40,8 +32,6 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
var/make_runtime = 0
var/initializations_finished_with_no_players_logged_in //I wonder what this could be?
- // Has round started? (So we know what subsystems to run)
- var/round_started = 0
// The type of the last subsystem to be process()'d.
var/last_type_processed
@@ -52,6 +42,16 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
var/queue_priority_count_bg = 0 //Same, but for background subsystems
var/map_loading = FALSE //Are we loading in a new map?
+ var/current_runlevel //for scheduling different subsystems for different stages of the round
+
+ var/static/restart_clear = 0
+ var/static/restart_timeout = 0
+ var/static/restart_count = 0
+
+ //current tick limit, assigned before running a subsystem.
+ //used by CHECK_TICK as well so that the procs subsystems call can obey that SS's tick limits
+ var/static/current_ticklimit = TICK_LIMIT_RUNNING
+
/datum/controller/master/New()
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
subsystems = list()
@@ -70,6 +70,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
/datum/controller/master/Shutdown()
processing = FALSE
+ sortTim(subsystems, /proc/cmp_subsystem_init)
+ reverseRange(subsystems)
for(var/datum/controller/subsystem/ss in subsystems)
ss.Shutdown()
@@ -77,14 +79,14 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
// -1 if we encountered a runtime trying to recreate it
/proc/Recreate_MC()
. = -1 //so if we runtime, things know we failed
- if (world.time < MC_restart_timeout)
+ if (world.time < Master.restart_timeout)
return 0
- if (world.time < MC_restart_clear)
- MC_restart_count *= 0.5
+ if (world.time < Master.restart_clear)
+ Master.restart_count *= 0.5
- var/delay = 50 * ++MC_restart_count
- MC_restart_timeout = world.time + delay
- MC_restart_clear = world.time + (delay * 2)
+ var/delay = 50 * ++Master.restart_count
+ Master.restart_timeout = world.time + delay
+ Master.restart_clear = world.time + (delay * 2)
Master.processing = 0 //stop ticking this one
try
new/datum/controller/master()
@@ -107,8 +109,28 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
else
msg += "\t [varname] = [varval]\n"
log_world(msg)
+
+ var/datum/controller/subsystem/BadBoy = Master.last_type_processed
+ var/FireHim = FALSE
+ if(istype(BadBoy))
+ msg = null
+ switch(++BadBoy.failure_strikes)
+ if(2)
+ msg = "The [BadBoy.name] subsystem was the last to fire for 2 controller restarts. It will be recovered now and disabled if it happens again."
+ FireHim = TRUE
+ if(3)
+ msg = "The [BadBoy.name] subsystem seems to be destabilizing the MC and will be offlined."
+ BadBoy.flags |= SS_NO_FIRE
+ if(msg)
+ log_game(msg)
+ message_admins("[msg]")
+ log_world(msg)
+
if (istype(Master.subsystems))
+ if(FireHim)
+ Master.subsystems += new BadBoy.type //NEW_SS_GLOBAL will remove the old one
subsystems = Master.subsystems
+ current_runlevel = Master.current_runlevel
StartProcessing(10)
else
to_chat(world, "The Master Controller is having some issues, we will need to re-initialize EVERYTHING")
@@ -133,19 +155,22 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
var/start_timeofday = REALTIMEOFDAY
// Initialize subsystems.
- CURRENT_TICKLIMIT = config.tick_limit_mc_init
+ current_ticklimit = config.tick_limit_mc_init
for (var/datum/controller/subsystem/SS in subsystems)
if (SS.flags & SS_NO_INIT)
continue
SS.Initialize(REALTIMEOFDAY)
CHECK_TICK
- CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
+ current_ticklimit = TICK_LIMIT_RUNNING
var/time = (REALTIMEOFDAY - start_timeofday) / 10
var/msg = "Initializations complete within [time] second[time == 1 ? "" : "s"]!"
to_chat(world, "[msg]")
log_world(msg)
+ if (!current_runlevel)
+ SetRunLevel(RUNLEVEL_LOBBY)
+
// Sort subsystems by display setting for easy access.
sortTim(subsystems, /proc/cmp_subsystem_display)
// Set world options.
@@ -161,16 +186,12 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
// Loop.
Master.StartProcessing(0)
-// Notify the MC that the round has started.
-/datum/controller/master/proc/RoundStart()
- round_started = 1
- var/timer = world.time
- for (var/datum/controller/subsystem/SS in subsystems)
- if (SS.flags & SS_FIRE_IN_LOBBY || SS.flags & SS_TICKER)
- continue //already firing
- // Stagger subsystems.
- timer += world.tick_lag * rand(1, 5)
- SS.next_fire = timer
+/datum/controller/master/proc/SetRunLevel(new_runlevel)
+ var/old_runlevel = isnull(current_runlevel) ? "NULL" : runlevel_flags[current_runlevel]
+ testing("MC: Runlevel changed from [old_runlevel] to [new_runlevel]")
+ current_runlevel = RUNLEVEL_FLAG_TO_INDEX(new_runlevel)
+ if(current_runlevel < 1)
+ CRASH("Attempted to set invalid runlevel: [new_runlevel]")
// Starts the mc, and sticks around to restart it if the loop ever ends.
/datum/controller/master/proc/StartProcessing(delay)
@@ -195,12 +216,9 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
//Prep the loop (most of this is because we want MC restarts to reset as much state as we can, and because
// local vars rock
- // Schedule the first run of the Subsystems.
- round_started = world.has_round_started()
//all this shit is here so that flag edits can be refreshed by restarting the MC. (and for speed)
var/list/tickersubsystems = list()
- var/list/normalsubsystems = list()
- var/list/lobbysubsystems = list()
+ var/list/runlevel_sorted_subsystems = list(list()) //ensure we always have at least one runlevel
var/timer = world.time
for (var/thing in subsystems)
var/datum/controller/subsystem/SS = thing
@@ -215,25 +233,29 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
timer += world.tick_lag * rand(1, 5)
SS.next_fire = timer
continue
- if (SS.flags & SS_FIRE_IN_LOBBY)
- lobbysubsystems += SS
- timer += world.tick_lag * rand(1, 5)
- SS.next_fire = timer
- else if (round_started)
- timer += world.tick_lag * rand(1, 5)
- SS.next_fire = timer
- normalsubsystems += SS
+
+ var/ss_runlevels = SS.runlevels
+ var/added_to_any = FALSE
+ for(var/I in 1 to global.runlevel_flags.len)
+ if(ss_runlevels & global.runlevel_flags[I])
+ while(runlevel_sorted_subsystems.len < I)
+ runlevel_sorted_subsystems += list(list())
+ runlevel_sorted_subsystems[I] += SS
+ added_to_any = TRUE
+ if(!added_to_any)
+ WARNING("[SS.name] subsystem is not SS_NO_FIRE but also does not have any runlevels set!")
queue_head = null
queue_tail = null
//these sort by lower priorities first to reduce the number of loops needed to add subsequent SS's to the queue
//(higher subsystems will be sooner in the queue, adding them later in the loop means we don't have to loop thru them next queue add)
sortTim(tickersubsystems, /proc/cmp_subsystem_priority)
- sortTim(normalsubsystems, /proc/cmp_subsystem_priority)
- sortTim(lobbysubsystems, /proc/cmp_subsystem_priority)
+ for(var/I in runlevel_sorted_subsystems)
+ sortTim(runlevel_sorted_subsystems, /proc/cmp_subsystem_priority)
+ I += tickersubsystems
- normalsubsystems += tickersubsystems
- lobbysubsystems += tickersubsystems
+ var/cached_runlevel = current_runlevel
+ var/list/current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel]
init_timeofday = REALTIMEOFDAY
init_time = world.time
@@ -246,7 +268,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
while (1)
tickdrift = max(0, MC_AVERAGE_FAST(tickdrift, (((REALTIMEOFDAY - init_timeofday) - (world.time - init_time)) / world.tick_lag)))
if (processing <= 0)
- CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
+ current_ticklimit = TICK_LIMIT_RUNNING
sleep(10)
continue
@@ -254,7 +276,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
// because sleeps are processed in the order received, so longer sleeps are more likely to run first
if (world.tick_usage > TICK_LIMIT_MC)
sleep_delta += 2
- CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.5)
+ current_ticklimit = TICK_LIMIT_RUNNING * 0.5
sleep(world.tick_lag * (processing + sleep_delta))
continue
@@ -270,32 +292,41 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
if (!Failsafe || (Failsafe.processing_interval > 0 && (Failsafe.lasttick+(Failsafe.processing_interval*5)) < world.time))
new/datum/controller/failsafe() // (re)Start the failsafe.
if (!queue_head || !(iteration % 3))
- if (round_started)
- subsystems_to_check = normalsubsystems
- else
- subsystems_to_check = lobbysubsystems
+ var/checking_runlevel = current_runlevel
+ if(cached_runlevel != checking_runlevel)
+ //resechedule subsystems
+ cached_runlevel = checking_runlevel
+ current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel]
+ var/stagger = world.time
+ for(var/I in current_runlevel_subsystems)
+ var/datum/controller/subsystem/SS = I
+ if(SS.next_fire <= world.time)
+ stagger += world.tick_lag * rand(1, 5)
+ SS.next_fire = stagger
+
+ subsystems_to_check = current_runlevel_subsystems
else
subsystems_to_check = tickersubsystems
if (CheckQueue(subsystems_to_check) <= 0)
- if (!SoftReset(tickersubsystems, normalsubsystems, lobbysubsystems))
+ if (!SoftReset(tickersubsystems, runlevel_sorted_subsystems))
log_world("MC: SoftReset() failed, crashing")
return
if (!error_level)
iteration++
error_level++
- CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
+ current_ticklimit = TICK_LIMIT_RUNNING
sleep(10)
continue
if (queue_head)
if (RunQueue() <= 0)
- if (!SoftReset(tickersubsystems, normalsubsystems, lobbysubsystems))
+ if (!SoftReset(tickersubsystems, runlevel_sorted_subsystems))
log_world("MC: SoftReset() failed, crashing")
return
if (!error_level)
iteration++
error_level++
- CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
+ current_ticklimit = TICK_LIMIT_RUNNING
sleep(10)
continue
error_level--
@@ -306,7 +337,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
iteration++
last_run = world.time
src.sleep_delta = MC_AVERAGE_FAST(src.sleep_delta, sleep_delta)
- CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc.
+ current_ticklimit = TICK_LIMIT_RUNNING - (TICK_LIMIT_RUNNING * 0.25) //reserve the tail 1/4 of the next tick for the mc.
sleep(world.tick_lag * (processing + sleep_delta))
@@ -395,7 +426,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
else
tick_precentage = tick_remaining
- CURRENT_TICKLIMIT = world.tick_usage + tick_precentage
+ current_ticklimit = world.tick_usage + tick_precentage
if (!(queue_node_flags & SS_TICKER))
ran_non_ticker = TRUE
@@ -460,13 +491,15 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
//resets the queue, and all subsystems, while filtering out the subsystem lists
// called if any mc's queue procs runtime or exit improperly.
-/datum/controller/master/proc/SoftReset(list/ticker_SS, list/normal_SS, list/lobby_SS)
+/datum/controller/master/proc/SoftReset(list/ticker_SS, list/runlevel_SS)
. = 0
log_world("MC: SoftReset called, resetting MC queue state.")
- if (!istype(subsystems) || !istype(ticker_SS) || !istype(normal_SS) || !istype(lobby_SS))
- log_world("MC: SoftReset: Bad list contents: '[subsystems]' '[ticker_SS]' '[normal_SS]' '[lobby_SS]' Crashing!")
+ if (!istype(subsystems) || !istype(ticker_SS) || !istype(runlevel_SS))
+ log_world("MC: SoftReset: Bad list contents: '[subsystems]' '[ticker_SS]' '[runlevel_SS]'")
return
- var/subsystemstocheck = subsystems + ticker_SS + normal_SS + lobby_SS
+ var/subsystemstocheck = subsystems + ticker_SS
+ for(var/I in runlevel_SS)
+ subsystemstocheck |= I
for (var/thing in subsystemstocheck)
var/datum/controller/subsystem/SS = thing
@@ -474,8 +507,8 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
//list(SS) is so if a list makes it in the subsystem list, we remove the list, not the contents
subsystems -= list(SS)
ticker_SS -= list(SS)
- normal_SS -= list(SS)
- lobby_SS -= list(SS)
+ for(var/I in runlevel_SS)
+ I -= list(SS)
log_world("MC: SoftReset: Found bad entry in subsystem list, '[SS]'")
continue
if (SS.queue_next && !istype(SS.queue_next))
diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm
index ff81fdc23e2..7dff609c76d 100644
--- a/code/controllers/subsystem.dm
+++ b/code/controllers/subsystem.dm
@@ -6,6 +6,7 @@
var/priority = 50 //When mutiple subsystems need to run in the same tick, higher priority subsystems will run first and be given a higher share of the tick before MC_TICK_CHECK triggers a sleep
var/flags = 0 //see MC.dm in __DEFINES Most flags must be set on world start to take full effect. (You can also restart the mc to force them to process again)
+ var/runlevels = RUNLEVELS_DEFAULT //points of the game at which the SS can fire
//set to 0 to prevent fire() calls, mostly for admin use or subsystems that may be resumed later
// use the SS_NO_FIRE flag instead for systems that never fire to keep it from even being added to the list
@@ -27,6 +28,8 @@
var/datum/controller/subsystem/queue_next
var/datum/controller/subsystem/queue_prev
+ var/static/failure_strikes = 0 //How many times we suspect this subsystem has crashed the MC, 3 strikes and you're out!
+
//Do not override
/datum/controller/subsystem/New()
return
diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm
index b07337e8035..d6db860d5de 100644
--- a/code/controllers/subsystems/garbage.dm
+++ b/code/controllers/subsystems/garbage.dm
@@ -5,7 +5,8 @@ SUBSYSTEM_DEF(garbage)
name = "Garbage"
priority = 15
wait = 5
- flags = SS_FIRE_IN_LOBBY|SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
+ flags = SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
+ runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
var/collection_timeout = 3000// deciseconds to wait to let running procs finish before we just say fuck it and force del() the object
var/delslasttick = 0 // number of del()'s we've done this tick
diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm
index 15e4eb48042..34a3e45877f 100644
--- a/code/game/gamemodes/gameticker.dm
+++ b/code/game/gamemodes/gameticker.dm
@@ -51,6 +51,7 @@ var/global/datum/controller/gameticker/ticker
vote.process()
if(pregame_timeleft <= 0)
current_state = GAME_STATE_SETTING_UP
+ Master.SetRunLevel(RUNLEVEL_SETUP)
while (!setup())
@@ -63,6 +64,7 @@ var/global/datum/controller/gameticker/ticker
if((master_mode=="random") || (master_mode=="secret"))
if(!runnable_modes.len)
current_state = GAME_STATE_PREGAME
+ Master.SetRunLevel(RUNLEVEL_LOBBY)
world << "Unable to choose playable game mode. Reverting to pre-game lobby."
return 0
if(secret_force_mode != "secret")
@@ -77,6 +79,7 @@ var/global/datum/controller/gameticker/ticker
if(!src.mode)
current_state = GAME_STATE_PREGAME
+ Master.SetRunLevel(RUNLEVEL_LOBBY)
world << "Serious error in mode setup! Reverting to pre-game lobby."
return 0
@@ -88,6 +91,7 @@ var/global/datum/controller/gameticker/ticker
if(!src.mode.can_start())
world << "Unable to start [mode.name]. Not enough players, [mode.required_players] players needed. Reverting to pre-game lobby."
current_state = GAME_STATE_PREGAME
+ Master.SetRunLevel(RUNLEVEL_LOBBY)
mode.fail_setup()
mode = null
job_master.ResetOccupations()
@@ -116,6 +120,7 @@ var/global/datum/controller/gameticker/ticker
shuttle_controller.setup_shuttle_docks()
+ // TODO - Leshana - Dear God Fix This. Fix all of this. Not just this line, this entire proc. This entire file!
spawn(0)//Forking here so we dont have to wait for this to finish
mode.post_setup()
//Cleanup some stuff
@@ -144,6 +149,7 @@ var/global/datum/controller/gameticker/ticker
*/
processScheduler.start()
+ Master.SetRunLevel(RUNLEVEL_GAME)
if(config.sql_enabled)
statistic_cycle() // Polls population totals regularly and stores them in an SQL DB -- TLE
@@ -308,6 +314,7 @@ var/global/datum/controller/gameticker/ticker
if(!mode.explosion_in_progress && game_finished && (mode_finished || post_game))
current_state = GAME_STATE_FINISHED
+ Master.SetRunLevel(RUNLEVEL_POSTGAME)
spawn
declare_completion()
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 7d333e2b660..98cb1613b7c 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -788,6 +788,7 @@ var/datum/announcement/minor/admin_min_announcer = new
return
if(ticker.current_state == GAME_STATE_PREGAME)
ticker.current_state = GAME_STATE_SETTING_UP
+ Master.SetRunLevel(RUNLEVEL_SETUP)
log_admin("[usr.key] has started the game.")
message_admins("[usr.key] has started the game.")
feedback_add_details("admin_verb","SN") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/unit_tests/unit_test.dm b/code/unit_tests/unit_test.dm
index f05514ce74e..605cf8fcac6 100644
--- a/code/unit_tests/unit_test.dm
+++ b/code/unit_tests/unit_test.dm
@@ -45,6 +45,7 @@ var/total_unit_tests = 0
sleep(1)
ticker.current_state = GAME_STATE_SETTING_UP
+ Master.SetRunLevel(RUNLEVEL_SETUP)
log_unit_test("Round has been started. Waiting 10 seconds to start tests.")
sleep(100)
diff --git a/code/world.dm b/code/world.dm
index fd38d66a818..41be4fc4671 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -436,6 +436,7 @@ var/world_topic_spam_protect_time = world.timeofday
*/
processScheduler.stop()
+ Master.Shutdown() //run SS shutdowns
for(var/client/C in clients)
if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
diff --git a/vorestation.dme b/vorestation.dme
index 9e5c46d5f59..e5f8a7b6817 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -49,6 +49,7 @@
#include "code\__defines\roguemining_vr.dm"
#include "code\__defines\species_languages.dm"
#include "code\__defines\species_languages_vr.dm"
+#include "code\__defines\subsystems.dm"
#include "code\__defines\targeting.dm"
#include "code\__defines\tick.dm"
#include "code\__defines\turfs.dm"