diff --git a/code/__DEFINES/MC.dm b/code/__DEFINES/MC.dm
index eb148e7b596..05c447d47cb 100644
--- a/code/__DEFINES/MC.dm
+++ b/code/__DEFINES/MC.dm
@@ -20,8 +20,9 @@
//SubSystem flags (Please design any new flags so that the default is off, to make adding flags to subsystems easier)
+//deprecated, can be replaced
//subsystem should fire during pre-game lobby.
-#define SS_FIRE_IN_LOBBY 1
+//#define SS_FIRE_IN_LOBBY 1
//subsystem does not initialize.
#define SS_NO_INIT 2
@@ -40,7 +41,7 @@
//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
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 79617db7bf9..ac6f4e4e7d8 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -60,3 +60,14 @@
#define INIT_ORDER_LIGHTING -20
#define INIT_ORDER_SQUEAK -40
#define INIT_ORDER_PERSISTENCE -100
+
+// SS runlevels
+
+#define RUNLEVEL_INIT 0
+#define RUNLEVEL_LOBBY 1
+#define RUNLEVEL_SETUP 2
+#define RUNLEVEL_GAME 3
+#define RUNLEVEL_POSTGAME 4
+
+#define RUNLEVEL_MIN_DEFAULT RUNLEVEL_SETUP
+#define RUNLEVEL_MAX_DEFAULT RUNLEVEL_POSTGAME
diff --git a/code/controllers/master.dm b/code/controllers/master.dm
index 01d0ac34470..602671f2db8 100644
--- a/code/controllers/master.dm
+++ b/code/controllers/master.dm
@@ -47,8 +47,6 @@ GLOBAL_VAR_INIT(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/local_round_started = FALSE //Don't read this var, use SSticker.HasRoundStarted() instead
// The type of the last subsystem to be process()'d.
var/last_type_processed
@@ -59,6 +57,8 @@ GLOBAL_VAR_INIT(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
+
/datum/controller/master/New()
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
subsystems = list()
@@ -176,6 +176,8 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
to_chat(world, "[msg]")
log_world(msg)
+ SetRunLevel(1)
+
// Sort subsystems by display setting for easy access.
sortTim(subsystems, /proc/cmp_subsystem_display)
// Set world options.
@@ -187,16 +189,9 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
// Loop.
Master.StartProcessing(0)
-// Notify the MC that the round has started.
-/datum/controller/master/proc/RoundStart()
- local_round_started = TRUE
- 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(runlevel)
+ testing("MC: Runlevel changed from [isnull(current_runlevel) ? "NULL" : current_runlevel] to [runlevel]")
+ current_runlevel = runlevel
// Starts the mc, and sticks around to restart it if the loop ever ends.
/datum/controller/master/proc/StartProcessing(delay)
@@ -221,12 +216,9 @@ GLOBAL_VAR_INIT(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.
- local_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
@@ -241,25 +233,24 @@ GLOBAL_VAR_INIT(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 (local_round_started)
- timer += world.tick_lag * rand(1, 5)
- SS.next_fire = timer
- normalsubsystems += SS
+ var/ss_max_runlevel = SS.runlevel_max
+ while(runlevel_sorted_subsystems.len < ss_max_runlevel)
+ runlevel_sorted_subsystems += list(list())
+
+ for(var/I in SS.runlevel_min to ss_max_runlevel)
+ runlevel_sorted_subsystems[I] += SS
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)
-
- normalsubsystems += tickersubsystems
- lobbysubsystems += tickersubsystems
+ for(var/I in runlevel_sorted_subsystems)
+ sortTim(runlevel_sorted_subsystems, /proc/cmp_subsystem_priority)
+ I += tickersubsystems
+
+ var/cached_runlevel = current_runlevel
+ var/list/current_runlevel_subsystems = runlevel_sorted_subsystems[cached_runlevel]
init_timeofday = REALTIMEOFDAY
init_time = world.time
@@ -296,14 +287,23 @@ GLOBAL_VAR_INIT(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 (local_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)
@@ -315,7 +315,7 @@ GLOBAL_VAR_INIT(CURRENT_TICKLIMIT, TICK_LIMIT_RUNNING)
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)
@@ -486,13 +486,15 @@ GLOBAL_VAR_INIT(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
@@ -500,8 +502,8 @@ GLOBAL_VAR_INIT(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 f37a9159efd..dcc55a8cb0a 100644
--- a/code/controllers/subsystem.dm
+++ b/code/controllers/subsystem.dm
@@ -28,6 +28,9 @@
var/datum/controller/subsystem/queue_next
var/datum/controller/subsystem/queue_prev
+ var/runlevel_min = RUNLEVEL_MIN_DEFAULT //the minimum runlevel at which this subsystem will fire
+ var/runlevel_max = RUNLEVEL_MAX_DEFAULT //the maximum runlevel at which this subsystem will fire
+
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
diff --git a/code/controllers/subsystem/acid.dm b/code/controllers/subsystem/acid.dm
index a0a506499fd..765c8cd49d0 100644
--- a/code/controllers/subsystem/acid.dm
+++ b/code/controllers/subsystem/acid.dm
@@ -2,6 +2,7 @@ SUBSYSTEM_DEF(acid)
name = "Acid"
priority = 40
flags = SS_NO_INIT|SS_BACKGROUND
+ runlevel_min = RUNLEVEL_GAME
var/list/currentrun = list()
var/list/processing = list()
diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm
index 38245c5bccf..0b77bbdc06a 100644
--- a/code/controllers/subsystem/air.dm
+++ b/code/controllers/subsystem/air.dm
@@ -12,6 +12,7 @@ SUBSYSTEM_DEF(air)
priority = 20
wait = 5
flags = SS_BACKGROUND
+ runlevel_min = RUNLEVEL_GAME
var/cost_turfs = 0
var/cost_groups = 0
diff --git a/code/controllers/subsystem/augury.dm b/code/controllers/subsystem/augury.dm
index 851234fde57..2ac9e05356f 100644
--- a/code/controllers/subsystem/augury.dm
+++ b/code/controllers/subsystem/augury.dm
@@ -1,6 +1,7 @@
SUBSYSTEM_DEF(augury)
name = "Augury"
flags = SS_NO_INIT
+ runlevel_min = RUNLEVEL_GAME
var/list/watchers = list()
var/list/doombringers = list()
diff --git a/code/controllers/subsystem/disease.dm b/code/controllers/subsystem/disease.dm
index 8b867146a66..845238f497a 100644
--- a/code/controllers/subsystem/disease.dm
+++ b/code/controllers/subsystem/disease.dm
@@ -1,6 +1,7 @@
SUBSYSTEM_DEF(disease)
name = "Disease"
flags = SS_KEEP_TIMING|SS_NO_INIT
+ runlevel_min = RUNLEVEL_GAME
var/list/currentrun = list()
var/list/processing = list()
diff --git a/code/controllers/subsystem/events.dm b/code/controllers/subsystem/events.dm
index b99b71ed336..22e3485bb7e 100644
--- a/code/controllers/subsystem/events.dm
+++ b/code/controllers/subsystem/events.dm
@@ -1,6 +1,8 @@
SUBSYSTEM_DEF(events)
name = "Events"
init_order = INIT_ORDER_EVENTS
+ runlevel_min = RUNLEVEL_GAME
+ runlevel_max = RUNLEVEL_GAME
var/list/control = list() //list of all datum/round_event_control. Used for selecting events based on weight and occurrences.
var/list/running = list() //list of all existing /datum/round_event
diff --git a/code/controllers/subsystem/fire_burning.dm b/code/controllers/subsystem/fire_burning.dm
index af3cb3f6a1c..4cba46a0aa4 100644
--- a/code/controllers/subsystem/fire_burning.dm
+++ b/code/controllers/subsystem/fire_burning.dm
@@ -2,6 +2,7 @@ SUBSYSTEM_DEF(fire_burning)
name = "Fire Burning"
priority = 40
flags = SS_NO_INIT|SS_BACKGROUND
+ runlevel_min = RUNLEVEL_GAME
var/list/currentrun = list()
var/list/processing = list()
diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm
index 7d3682cf5f7..69a16215826 100644
--- a/code/controllers/subsystem/garbage.dm
+++ b/code/controllers/subsystem/garbage.dm
@@ -2,7 +2,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
+ runlevel_min = 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/controllers/subsystem/inbounds.dm b/code/controllers/subsystem/inbounds.dm
index 1ac9115982b..dccb6e45ebe 100644
--- a/code/controllers/subsystem/inbounds.dm
+++ b/code/controllers/subsystem/inbounds.dm
@@ -2,6 +2,8 @@ SUBSYSTEM_DEF(inbounds)
name = "Inbounds"
priority = 40
flags = SS_NO_INIT
+ runlevel_min = RUNLEVEL_GAME
+ runlevel_max = RUNLEVEL_GAME
var/list/processing = list()
var/list/currentrun = list()
diff --git a/code/controllers/subsystem/mobs.dm b/code/controllers/subsystem/mobs.dm
index f87b94bac48..c7a6fb883e0 100644
--- a/code/controllers/subsystem/mobs.dm
+++ b/code/controllers/subsystem/mobs.dm
@@ -2,6 +2,7 @@ SUBSYSTEM_DEF(mobs)
name = "Mobs"
priority = 100
flags = SS_KEEP_TIMING|SS_NO_INIT
+ runlevel_min = RUNLEVEL_GAME
var/list/currentrun = list()
diff --git a/code/controllers/subsystem/npcpool.dm b/code/controllers/subsystem/npcpool.dm
index 77838e6509f..5a7c263034a 100644
--- a/code/controllers/subsystem/npcpool.dm
+++ b/code/controllers/subsystem/npcpool.dm
@@ -7,6 +7,7 @@ SUBSYSTEM_DEF(npcpool)
name = "NPC Pool"
flags = SS_POST_FIRE_TIMING|SS_NO_INIT|SS_BACKGROUND
priority = 20
+ runlevel_min = RUNLEVEL_GAME
var/list/canBeUsed = list()
var/list/needsDelegate = list()
diff --git a/code/controllers/subsystem/parallax.dm b/code/controllers/subsystem/parallax.dm
index 6ce2928f895..37a398d5d86 100644
--- a/code/controllers/subsystem/parallax.dm
+++ b/code/controllers/subsystem/parallax.dm
@@ -1,8 +1,9 @@
SUBSYSTEM_DEF(parallax)
name = "Parallax"
wait = 2
- flags = SS_POST_FIRE_TIMING | SS_FIRE_IN_LOBBY | SS_BACKGROUND | SS_NO_INIT
+ flags = SS_POST_FIRE_TIMING | SS_BACKGROUND | SS_NO_INIT
priority = 65
+ runlevel_min = RUNLEVEL_LOBBY
var/list/currentrun
/datum/controller/subsystem/parallax/fire(resumed = 0)
diff --git a/code/controllers/subsystem/processing/overlays.dm b/code/controllers/subsystem/processing/overlays.dm
index 1aa76e6b3de..3484571c5f5 100644
--- a/code/controllers/subsystem/processing/overlays.dm
+++ b/code/controllers/subsystem/processing/overlays.dm
@@ -1,9 +1,10 @@
PROCESSING_SUBSYSTEM_DEF(overlays)
name = "Overlay"
- flags = SS_TICKER|SS_FIRE_IN_LOBBY
+ flags = SS_TICKER
wait = 1
priority = 500
init_order = INIT_ORDER_OVERLAY
+ runlevel_min = RUNLEVEL_LOBBY
stat_tag = "Ov"
currentrun = null
diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm
index c248ca0a98e..b69188d1477 100644
--- a/code/controllers/subsystem/server_maint.dm
+++ b/code/controllers/subsystem/server_maint.dm
@@ -3,8 +3,9 @@
SUBSYSTEM_DEF(server_maint)
name = "Server Tasks"
wait = 6
- flags = SS_POST_FIRE_TIMING|SS_FIRE_IN_LOBBY
+ flags = SS_POST_FIRE_TIMING
priority = 10
+ runlevel_min = RUNLEVEL_LOBBY
var/list/currentrun
/datum/controller/subsystem/server_maint/Initialize(timeofday)
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index dcddd37fbfe..d23d0a0111a 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -5,6 +5,7 @@ SUBSYSTEM_DEF(shuttle)
wait = 10
init_order = INIT_ORDER_SHUTTLE
flags = SS_KEEP_TIMING|SS_NO_TICK_CHECK
+ runlevel_max = RUNLEVEL_GAME
var/list/mobile = list()
var/list/stationary = list()
diff --git a/code/controllers/subsystem/spacedrift.dm b/code/controllers/subsystem/spacedrift.dm
index c6d12d2efbc..b3b530611a6 100644
--- a/code/controllers/subsystem/spacedrift.dm
+++ b/code/controllers/subsystem/spacedrift.dm
@@ -3,6 +3,7 @@ SUBSYSTEM_DEF(spacedrift)
priority = 30
wait = 5
flags = SS_NO_INIT|SS_KEEP_TIMING
+ runlevel_min = RUNLEVEL_GAME
var/list/currentrun = list()
var/list/processing = list()
diff --git a/code/controllers/subsystem/tgui.dm b/code/controllers/subsystem/tgui.dm
index 862dfb0f98d..2f2e80f16f3 100644
--- a/code/controllers/subsystem/tgui.dm
+++ b/code/controllers/subsystem/tgui.dm
@@ -1,8 +1,9 @@
SUBSYSTEM_DEF(tgui)
name = "tgui"
wait = 9
- flags = SS_NO_INIT|SS_FIRE_IN_LOBBY
+ flags = SS_NO_INIT
priority = 110
+ runlevel_min = RUNLEVEL_LOBBY
var/list/currentrun = list()
var/list/open_uis = list() // A list of open UIs, grouped by src_object and ui_key.
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index e1c751ce550..d3f0176dd8f 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -5,7 +5,9 @@ SUBSYSTEM_DEF(ticker)
init_order = INIT_ORDER_TICKER
priority = 200
- flags = SS_FIRE_IN_LOBBY|SS_KEEP_TIMING
+ flags = SS_KEEP_TIMING
+ runlevel_min = RUNLEVEL_LOBBY
+ runlevel_max = RUNLEVEL_GAME
var/current_state = GAME_STATE_STARTUP //state of current round (used by process()) Use the defines GAME_STATE_* !
var/force_ending = 0 //Round was ended by admin intervention
@@ -105,6 +107,7 @@ SUBSYSTEM_DEF(ticker)
if(timeLeft <= 0)
current_state = GAME_STATE_SETTING_UP
+ Master.SetRunLevel(RUNLEVEL_SETUP)
if(start_immediately)
fire()
@@ -112,6 +115,7 @@ SUBSYSTEM_DEF(ticker)
if(!setup())
//setup failed
current_state = GAME_STATE_STARTUP
+ Master.SetRunLevel(RUNLEVEL_LOBBY)
if(GAME_STATE_PLAYING)
mode.process(wait * 0.1)
@@ -123,6 +127,7 @@ SUBSYSTEM_DEF(ticker)
current_state = GAME_STATE_FINISHED
toggle_ooc(1) // Turn it on
declare_completion(force_ending)
+ Master.SetRunLevel(RUNLEVEL_POSTGAME)
/datum/controller/subsystem/ticker/proc/setup()
to_chat(world, "Starting game...")
@@ -198,8 +203,6 @@ SUBSYSTEM_DEF(ticker)
GLOB.data_core.manifest()
transfer_characters() //transfer keys to the new mobs
-
- Master.RoundStart() //let the party begin...
for(var/I in round_start_events)
var/datum/callback/cb = I
@@ -213,6 +216,7 @@ SUBSYSTEM_DEF(ticker)
world << sound('sound/AI/welcome.ogg')
current_state = GAME_STATE_PLAYING
+ Master.SetRunLevel(RUNLEVEL_GAME)
if(SSevents.holidays)
to_chat(world, "and...")
diff --git a/code/controllers/subsystem/time_track.dm b/code/controllers/subsystem/time_track.dm
index 20230037c2d..1e82057dbf9 100644
--- a/code/controllers/subsystem/time_track.dm
+++ b/code/controllers/subsystem/time_track.dm
@@ -1,7 +1,8 @@
SUBSYSTEM_DEF(time_track)
name = "Time Tracking"
wait = 600
- flags = SS_NO_INIT|SS_FIRE_IN_LOBBY|SS_NO_TICK_CHECK
+ flags = SS_NO_INIT|SS_NO_TICK_CHECK
+ runlevel_min = RUNLEVEL_LOBBY
var/time_dilation_current = 0
diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm
index 55ebbfa3524..2203e0f1f5c 100644
--- a/code/controllers/subsystem/timer.dm
+++ b/code/controllers/subsystem/timer.dm
@@ -6,7 +6,7 @@ SUBSYSTEM_DEF(timer)
wait = 1 //SS_TICKER subsystem, so wait is in ticks
init_order = INIT_ORDER_TIMER
- flags = SS_FIRE_IN_LOBBY|SS_TICKER|SS_NO_INIT
+ flags = SS_TICKER|SS_NO_INIT
var/list/datum/timedevent/processing = list()
var/list/hashes = list()
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index 5abea8281a1..77d4d07afbc 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -2,7 +2,9 @@ SUBSYSTEM_DEF(vote)
name = "Vote"
wait = 10
- flags = SS_FIRE_IN_LOBBY|SS_KEEP_TIMING|SS_NO_INIT
+ flags = SS_KEEP_TIMING|SS_NO_INIT
+
+ runlevel_min = RUNLEVEL_LOBBY
var/initiator = null
var/started_time = null
diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm
index 569eb4032c7..6245aa927f8 100644
--- a/code/controllers/subsystem/weather.dm
+++ b/code/controllers/subsystem/weather.dm
@@ -3,6 +3,8 @@ SUBSYSTEM_DEF(weather)
name = "Weather"
flags = SS_BACKGROUND
wait = 10
+ runlevel_min = RUNLEVEL_GAME
+ runlevel_max = RUNLEVEL_GAME
var/list/processing = list()
var/list/existing_weather = list()
var/list/eligible_zlevels = list(ZLEVEL_LAVALAND)
diff --git a/code/world.dm b/code/world.dm
index 353d8198183..89f2d9a0dc4 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -341,7 +341,3 @@
s += ": [jointext(features, ", ")]"
status = s
-
-
-/world/proc/has_round_started()
- return SSticker.HasRoundStarted()