diff --git a/code/WorkInProgress/carn/master_controller_old.dm b/code/WorkInProgress/carn/master_controller_old.dm
new file mode 100644
index 0000000000..80a7659035
--- /dev/null
+++ b/code/WorkInProgress/carn/master_controller_old.dm
@@ -0,0 +1,210 @@
+var/global/datum/controller/game_controller/master_controller //Set in world.New()
+var/global/datum/failsafe/Failsafe
+var/global/controller_iteration = 0
+
+
+var/global/last_tick_timeofday = world.timeofday
+var/global/last_tick_duration = 0
+
+datum/controller/game_controller
+ var/processing = 0
+
+ var/global/air_master_ready = 0
+ var/global/sun_ready = 0
+ var/global/mobs_ready = 0
+ var/global/diseases_ready = 0
+ var/global/machines_ready = 0
+ var/global/objects_ready = 0
+ var/global/networks_ready = 0
+ var/global/powernets_ready = 0
+ var/global/ticker_ready = 0
+
+ //Used for MC 'proc break' debugging
+ var/global/obj/last_obj_processed
+ var/global/datum/disease/last_disease_processed
+ var/global/obj/machinery/last_machine_processed
+ var/global/mob/last_mob_processed
+
+
+ proc/setup()
+ if(master_controller && (master_controller != src))
+ del(src)
+ return
+ //There can be only one master.
+
+ if(!air_master)
+ air_master = new /datum/controller/air_system()
+ air_master.setup()
+
+ if(!job_master)
+ job_master = new /datum/controller/occupations()
+ if(job_master.SetupOccupations())
+ world << "\red \b Job setup complete"
+ job_master.LoadJobs("config/jobs.txt")
+
+ world.tick_lag = config.Ticklag
+
+ createRandomZlevel()
+
+ setup_objects()
+
+ setupgenetics()
+
+
+ for(var/i = 0, i < max_secret_rooms, i++)
+ make_mining_asteroid_secret()
+
+ syndicate_code_phrase = generate_code_phrase()//Sets up code phrase for traitors, for the round.
+ syndicate_code_response = generate_code_phrase()
+
+ emergency_shuttle = new /datum/shuttle_controller/emergency_shuttle()
+
+ if(!ticker)
+ ticker = new /datum/controller/gameticker()
+
+ setupfactions()
+
+ spawn
+ ticker.pregame()
+
+ proc/setup_objects()
+ world << "\red \b Initializing objects"
+ sleep(-1)
+
+ for(var/obj/object in world)
+ object.initialize()
+
+ world << "\red \b Initializing pipe networks"
+ sleep(-1)
+
+ for(var/obj/machinery/atmospherics/machine in world)
+ machine.build_network()
+
+ world << "\red \b Initializing atmos machinery."
+ sleep(-1)
+ for(var/obj/machinery/atmospherics/unary/vent_pump/T in world)
+ T.broadcast_status()
+ for(var/obj/machinery/atmospherics/unary/vent_scrubber/T in world)
+ T.broadcast_status()
+
+ world << "\red \b Initializations complete."
+
+
+ proc/process()
+ processing = 1
+ spawn(0)
+ set background = 1
+ while(1)
+ var/currenttime = world.timeofday
+ var/diff = (currenttime - last_tick_timeofday) / 10
+ last_tick_timeofday = currenttime
+ last_tick_duration = diff
+
+ if(processing)
+
+ controller_iteration++
+
+ var/start_time = world.timeofday
+
+ air_master_ready = 0
+ sun_ready = 0
+ mobs_ready = 0
+ diseases_ready = 0
+ machines_ready = 0
+ objects_ready = 0
+ networks_ready = 0
+ powernets_ready = 0
+ ticker_ready = 0
+
+ spawn(0)
+ air_master.process()
+ air_master_ready = 1
+
+ sleep(1)
+
+ spawn(0)
+ sun.calc_position()
+ sun_ready = 1
+
+ sleep(-1)
+
+ spawn(0)
+ for(var/mob/M in world)
+ last_mob_processed = M
+ M.Life()
+ mobs_ready = 1
+
+ sleep(-1)
+
+ spawn(0)
+ for(var/datum/disease/D in active_diseases)
+ last_disease_processed = D
+ D.process()
+ diseases_ready = 1
+
+ spawn(0)
+ for(var/obj/machinery/machine in machines)
+ if(machine)
+ last_machine_processed = machine
+ machine.process()
+ if(machine && machine.use_power)
+ machine.auto_use_power()
+
+ machines_ready = 1
+
+ sleep(1)
+
+ spawn(-1)
+ for(var/obj/object in processing_objects)
+ last_obj_processed = object
+ object.process()
+ objects_ready = 1
+
+ sleep(-1)
+
+ spawn(-1)
+ for(var/datum/pipe_network/network in pipe_networks)
+ network.process()
+ networks_ready = 1
+
+ spawn(-1)
+ for(var/datum/powernet/P in powernets)
+ P.reset()
+ powernets_ready = 1
+
+ sleep(-1)
+
+ spawn(-1)
+ ticker.process()
+ ticker_ready = 1
+
+ var/IL_check = 0 //Infinite loop check (To report when the master controller breaks.)
+ while(!air_master_ready || !sun_ready || !mobs_ready || !diseases_ready || !machines_ready || !objects_ready || !networks_ready || !powernets_ready || !ticker_ready)
+ IL_check++
+ if(IL_check > 600)
+ var/MC_report = "air_master_ready = [air_master_ready]; sun_ready = [sun_ready]; mobs_ready = [mobs_ready]; diseases_ready = [diseases_ready]; machines_ready = [machines_ready]; objects_ready = [objects_ready]; networks_ready = [networks_ready]; powernets_ready = [powernets_ready]; ticker_ready = [ticker_ready];"
+ message_admins("PROC BREAKAGE WARNING: The game's master contorller appears to be stuck in one of it's cycles. It has looped through it's delaying loop [IL_check] times.")
+ message_admins("The master controller reports: [MC_report]")
+ if(!diseases_ready)
+ if(last_disease_processed)
+ message_admins("DISEASE PROCESSING stuck on [last_disease_processed]", 0, 1)
+ else
+ message_admins("DISEASE PROCESSING stuck on unknown")
+ if(!machines_ready)
+ if(last_machine_processed)
+ message_admins("MACHINE PROCESSING stuck on [last_machine_processed]", 0, 1)
+ else
+ message_admins("MACHINE PROCESSING stuck on unknown")
+ if(!objects_ready)
+ if(last_obj_processed)
+ message_admins("OBJ PROCESSING stuck on [last_obj_processed]", 0, 1)
+ else
+ message_admins("OBJ PROCESSING stuck on unknown")
+ log_admin("PROC BREAKAGE WARNING: infinite_loop_check = [IL_check]; [MC_report];")
+ message_admins("Master controller breaking out of delaying loop. Restarting the round is advised if problem persists. DO NOT manually restart the master controller.")
+ break;
+ sleep(1)
+
+ sleep(world.timeofday+12-start_time)
+ else
+ sleep(10)
\ No newline at end of file
diff --git a/code/WorkInProgress/carn/master_controller_sequential.dm b/code/WorkInProgress/carn/master_controller_sequential.dm
deleted file mode 100644
index 3c2978a6e8..0000000000
--- a/code/WorkInProgress/carn/master_controller_sequential.dm
+++ /dev/null
@@ -1,209 +0,0 @@
-//simplified MC that is designed to fail when procs 'break'. When it fails it's just replaced with a new one.
-//It ensures master_controller.process() is never doubled up by killing the MC (hence terminating any of its sleeping procs)
-//WIP, needs lots of work still
-
-var/global/datum/controller/game_controller/master_controller //Set in world.New()
-var/global/datum/failsafe/Failsafe
-var/global/controller_iteration = 0
-
-
-var/global/last_tick_timeofday = world.timeofday
-var/global/last_tick_duration = 0
-
-var/global/obj/machinery/last_obj_processed //Used for MC 'proc break' debugging
-var/global/datum/disease/last_disease_processed //Used for MC 'proc break' debugging
-var/global/obj/machinery/last_machine_processed //Used for MC 'proc break' debugging
-
-datum/controller/game_controller
- var/processing = 0
- var/breather_ticks = 2 //a somewhat crude attempt to iron over the 'bumps' caused by high-cpu use by letting the MC have a breather for this many ticks after every loop
- var/minimum_ticks = 20 //The minimum length of time between MC ticks
-
- var/global/air_master_ready = 0
- var/global/tension_master_ready = 0
- var/global/sun_ready = 0
- var/global/mobs_ready = 0
- var/global/diseases_ready = 0
- var/global/machines_ready = 0
- var/global/objects_ready = 0
- var/global/networks_ready = 0
- var/global/powernets_ready = 0
- var/global/ticker_ready = 0
-
-datum/controller/game_controller/New()
- //There can be only one master_controller. Out with the old and in with the new.
- if(master_controller)
- if(master_controller != src)
- del(master_controller)
- master_controller = src
-
- if(!air_master)
- air_master = new /datum/controller/air_system()
- air_master.setup()
-
- if(!job_master)
- job_master = new /datum/controller/occupations()
- if(job_master.SetupOccupations())
- world << "\red \b Job setup complete"
- job_master.LoadJobs("config/jobs.txt")
-
- if(!syndicate_code_phrase) syndicate_code_phrase = generate_code_phrase()
- if(!syndicate_code_response) syndicate_code_response = generate_code_phrase()
- if(!ticker) ticker = new /datum/controller/gameticker()
- if(!emergency_shuttle) emergency_shuttle = new /datum/shuttle_controller/emergency_shuttle()
-
-
-datum/controller/game_controller/proc/setup()
- world.tick_lag = config.Ticklag
-
- createRandomZlevel()
- setup_objects()
- setupgenetics()
- setupfactions()
-
- for(var/i = 0, i < max_secret_rooms, i++)
- make_mining_asteroid_secret()
-
- spawn(0)
- if(ticker)
- ticker.pregame()
-
-datum/controller/game_controller/proc/setup_objects()
- world << "\red \b Initializing objects"
- sleep(-1)
- for(var/obj/object in world)
- object.initialize()
-
- world << "\red \b Initializing pipe networks"
- sleep(-1)
- for(var/obj/machinery/atmospherics/machine in world)
- machine.build_network()
-
- world << "\red \b Initializing atmos machinery."
- sleep(-1)
- for(var/obj/machinery/atmospherics/unary/vent_pump/T in world)
- T.broadcast_status()
- for(var/obj/machinery/atmospherics/unary/vent_scrubber/T in world)
- T.broadcast_status()
-
- world << "\red \b Initializations complete."
- sleep(-1)
-
-
-datum/controller/game_controller/proc/process()
- set background = 1
- processing = 1
- while(1) //far more efficient than recursively calling ourself
- if(!Failsafe) new /datum/failsafe()
-
- var/currenttime = world.timeofday
- last_tick_duration = (currenttime - last_tick_timeofday) / 10
- last_tick_timeofday = currenttime
-
- if(processing)
- var/start_time = world.timeofday
- controller_iteration++
-
- air_master.process()
- sleep(breather_ticks)
-
- sun.calc_position()
- sleep(breather_ticks)
-
- for(var/mob/living/M in world) //only living mobs have life processes
- M.Life()
- sleep(breather_ticks)
-
- for(var/datum/disease/D in active_diseases)
- last_disease_processed = D
- D.process()
- sleep(breather_ticks)
-
- for(var/obj/machinery/machine in machines)
- if(machine)
- last_machine_processed = machine
- machine.process()
- if(machine && machine.use_power)
- machine.auto_use_power()
- sleep(breather_ticks)
-
- for(var/obj/object in processing_objects)
- last_obj_processed = object
- object.process()
- sleep(breather_ticks)
-
- for(var/datum/pipe_network/network in pipe_networks)
- network.process()
- sleep(breather_ticks)
-
-
- for(var/datum/powernet/P in powernets)
- P.reset()
- sleep(breather_ticks)
-
- ticker.process()
-
- sleep( minimum_ticks - max(world.timeofday-start_time,0) ) //to prevent long delays happening at midnight
-
- else
- sleep(10)
-
-
-
-/datum/failsafe // This thing pretty much just keeps poking the master controller
- var/spinning = 1
- var/current_iteration = 0
- var/ticks_per_spin = 100 //poke the MC every 10 seconds
- var/defcon = 0 //alert level. For every poke that fails this is raised by 1. When it reaches 5 the MC is replaced with a new one. (effectively killing any master_controller.process() and starting a new one)
-
-/datum/failsafe/New()
- //There can be only one failsafe. Out with the old in with the new (that way we can restart the Failsafe by spawning a new one)
- if(Failsafe && (Failsafe != src))
- del(Failsafe)
- Failsafe = src
-
- current_iteration = controller_iteration
- spawn(0)
- Failsafe.spin()
-
-
-/datum/failsafe/proc/spin()
- set background = 1
- while(1) //more efficient than recursivly calling ourself over and over. background = 1 ensures we do not trigger an infinite loop
- if(master_controller)
- if(spinning && master_controller.processing) //only poke if these overrides aren't in effect
- if(current_iteration == controller_iteration) //master_controller hasn't finished processing in the defined interval
- switch(defcon)
- if(0 to 3)
- defcon++
- if(4)
- defcon = 5
- for(var/client/C)
- if(C.holder)
- C << "Warning. The Master Controller has not fired in the last [defcon*ticks_per_spin] ticks. Automatic restart in [ticks_per_spin] ticks."
- if(5)
- for(var/client/C)
- if(C.holder)
- C << "Warning. The Master Controller has still not fired within the last [defcon*ticks_per_spin] ticks. Killing and restarting..."
- spawn(0)
- new /datum/controller/game_controller() //replace the old master_controller (hence killing the old one's process)
- master_controller.process() //Start it rolling again
- defcon = 0
- else
- defcon = 0
- current_iteration = controller_iteration
- else
- defcon = 0
- else
- new /datum/controller/game_controller() //replace the missing master_controller! This should never happen.
- sleep(ticks_per_spin)
-
-//DEBUG VERBS
-/*
-/client/verb/spawn_MC()
- new /datum/controller/game_controller()
-
-
-/client/verb/spawn_FS()
- new /datum/failsafe()
-*/
\ No newline at end of file
diff --git a/code/controllers/_DynamicAreaLighting_TG.dm b/code/controllers/_DynamicAreaLighting_TG.dm
index 8a00ca9e1f..519b580708 100644
--- a/code/controllers/_DynamicAreaLighting_TG.dm
+++ b/code/controllers/_DynamicAreaLighting_TG.dm
@@ -37,9 +37,6 @@
#define LIGHTING_LAYER 10 //Drawing layer for lighting overlays
#define LIGHTING_ICON 'icons/effects/ss13_dark_alpha7.dmi' //Icon used for lighting shading effects
-datum/controller/lighting/New() //moved here so its in the define. eek :S
- lighting_states = max( 0, length(icon_states(LIGHTING_ICON))-1 )
-
datum/light_source
var/atom/owner
var/changed = 1
@@ -302,4 +299,4 @@ area
#undef LIGHTING_MAX_LUMINOSITY
#undef LIGHTING_MAX_LUMINOSITY_MOB
#undef LIGHTING_LAYER
-#undef LIGHTING_ICON
\ No newline at end of file
+//#undef LIGHTING_ICON
\ No newline at end of file
diff --git a/code/controllers/lighting_controller.dm b/code/controllers/lighting_controller.dm
index b21b1cc637..3d4f859efa 100644
--- a/code/controllers/lighting_controller.dm
+++ b/code/controllers/lighting_controller.dm
@@ -16,6 +16,15 @@ datum/controller/lighting
var/list/changed_turfs = list()
var/changed_turfs_workload_max = 0
+datum/controller/lighting/New()
+ lighting_states = max( 0, length(icon_states(LIGHTING_ICON))-1 )
+ if(lighting_controller != src)
+ if(istype(lighting_controller,/datum/controller/lighting))
+ Recover() //if we are replacing an existing lighting_controller (due to a crash) we attempt to preserve as much as we can
+ del(lighting_controller)
+ lighting_controller = src
+
+
//Workhorse of lighting. It cycles through each light to see which ones need their effects updating. It updates their
//effects and then processes every turf in the queue, moving the turfs to the corresponing lighting sub-area.
//All queue lists prune themselves, which will cause lights with no luminosity to be garbage collected (cheaper and safer
@@ -33,9 +42,10 @@ datum/controller/lighting/proc/process()
lights_workload_max = max(lights_workload_max,lights.len)
for(var/i=1, i<=lights.len, i++)
var/datum/light_source/L = lights[i]
- if(L.check())
- lights.Cut(i,i+1)
- i--
+ if(L && !L.check())
+ continue
+ lights.Cut(i,i+1)
+ i--
sleep(-1)
@@ -78,4 +88,42 @@ datum/controller/lighting/proc/Initialize(var/z_level)
var/turf/T = locate(i,j,k)
if(T) T.shift_to_subarea()
- changed_turfs.Cut() // reset the changed list
\ No newline at end of file
+ changed_turfs.Cut() // reset the changed list
+
+
+//Used to strip valid information from an existing controller and transfer it to a replacement
+//It works by using spawn(-1) to transfer the data, if there is a runtime the data does not get transfered but the loop
+//does not crash
+datum/controller/lighting/proc/Recover()
+ if(!istype(lighting_controller.changed_turfs,/list))
+ lighting_controller.changed_turfs = list()
+ if(!istype(lighting_controller.lights,/list))
+ lighting_controller.lights = list()
+
+ for(var/i=1, i<=lighting_controller.lights.len, i++)
+ var/datum/light_source/L = lighting_controller.lights[i]
+ if(istype(L))
+ spawn(-1) //so we don't crash the loop (inefficient)
+ L.check()
+ lights += L //If we didn't runtime then this will get transferred over
+
+ for(var/i=1, i<=lighting_controller.changed_turfs.len, i++)
+ var/turf/T = lighting_controller.changed_turfs[i]
+ if(istype(T) && T.lighting_changed)
+ spawn(-1)
+ T.shift_to_subarea()
+
+ var/msg = "## DEBUG: [time2text(world.timeofday)] lighting_controller restarted. Reports:\n"
+ for(var/varname in lighting_controller.vars)
+ switch(varname)
+ if("tag","bestF","type","parent_type","vars") continue
+ else
+ var/varval1 = lighting_controller.vars[varname]
+ var/varval2 = vars[varname]
+ if(istype(varval1,/list))
+ varval1 = "/list([length(varval1)])"
+ varval2 = "/list([length(varval2)])"
+ msg += "\t [varname] = [varval1] -> [varval2]\n"
+ world.log << msg
+
+#undef LIGHTING_ICON
diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index 80a7659035..faa7dfd8cd 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -1,210 +1,286 @@
+//simplified MC that is designed to fail when procs 'break'. When it fails it's just replaced with a new one.
+//It ensures master_controller.process() is never doubled up by killing the MC (hence terminating any of its sleeping procs)
+//WIP, needs lots of work still
+
var/global/datum/controller/game_controller/master_controller //Set in world.New()
var/global/datum/failsafe/Failsafe
+
var/global/controller_iteration = 0
-
-
var/global/last_tick_timeofday = world.timeofday
var/global/last_tick_duration = 0
datum/controller/game_controller
var/processing = 0
+ var/breather_ticks = 2 //a somewhat crude attempt to iron over the 'bumps' caused by high-cpu use by letting the MC have a breather for this many ticks after every loop
+ var/minimum_ticks = 20 //The minimum length of time between MC ticks
- var/global/air_master_ready = 0
- var/global/sun_ready = 0
- var/global/mobs_ready = 0
- var/global/diseases_ready = 0
- var/global/machines_ready = 0
- var/global/objects_ready = 0
- var/global/networks_ready = 0
- var/global/powernets_ready = 0
- var/global/ticker_ready = 0
+ var/air_cost = 0
+ var/sun_cost = 0
+ var/mobs_cost = 0
+ var/diseases_cost = 0
+ var/machines_cost = 0
+ var/objects_cost = 0
+ var/networks_cost = 0
+ var/powernets_cost = 0
+ var/ticker_cost = 0
+ var/total_cost = 0
- //Used for MC 'proc break' debugging
- var/global/obj/last_obj_processed
- var/global/datum/disease/last_disease_processed
- var/global/obj/machinery/last_machine_processed
- var/global/mob/last_mob_processed
+ var/obj/machinery/last_obj_processed //Used for MC 'proc break' debugging
+ var/datum/disease/last_disease_processed //Used for MC 'proc break' debugging
+ var/obj/machinery/last_machine_processed //Used for MC 'proc break' debugging
+
+datum/controller/game_controller/New()
+ //There can be only one master_controller. Out with the old and in with the new.
+ if(master_controller != src)
+ if(istype(master_controller,/datum/controller/game_controller))
+ Recover()
+ del(master_controller)
+ master_controller = src
+
+ if(!air_master)
+ air_master = new /datum/controller/air_system()
+ air_master.setup()
+
+ if(!job_master)
+ job_master = new /datum/controller/occupations()
+ if(job_master.SetupOccupations())
+ world << "\red \b Job setup complete"
+ job_master.LoadJobs("config/jobs.txt")
+
+ if(!syndicate_code_phrase) syndicate_code_phrase = generate_code_phrase()
+ if(!syndicate_code_response) syndicate_code_response = generate_code_phrase()
+ if(!ticker) ticker = new /datum/controller/gameticker()
+ if(!emergency_shuttle) emergency_shuttle = new /datum/shuttle_controller/emergency_shuttle()
- proc/setup()
- if(master_controller && (master_controller != src))
- del(src)
- return
- //There can be only one master.
+datum/controller/game_controller/proc/setup()
+ world.tick_lag = config.Ticklag
- if(!air_master)
- air_master = new /datum/controller/air_system()
- air_master.setup()
+ createRandomZlevel()
+ setup_objects()
+ setupgenetics()
+ setupfactions()
- if(!job_master)
- job_master = new /datum/controller/occupations()
- if(job_master.SetupOccupations())
- world << "\red \b Job setup complete"
- job_master.LoadJobs("config/jobs.txt")
+ for(var/i=0, i 600)
- var/MC_report = "air_master_ready = [air_master_ready]; sun_ready = [sun_ready]; mobs_ready = [mobs_ready]; diseases_ready = [diseases_ready]; machines_ready = [machines_ready]; objects_ready = [objects_ready]; networks_ready = [networks_ready]; powernets_ready = [powernets_ready]; ticker_ready = [ticker_ready];"
- message_admins("PROC BREAKAGE WARNING: The game's master contorller appears to be stuck in one of it's cycles. It has looped through it's delaying loop [IL_check] times.")
- message_admins("The master controller reports: [MC_report]")
- if(!diseases_ready)
- if(last_disease_processed)
- message_admins("DISEASE PROCESSING stuck on [last_disease_processed]", 0, 1)
- else
- message_admins("DISEASE PROCESSING stuck on unknown")
- if(!machines_ready)
- if(last_machine_processed)
- message_admins("MACHINE PROCESSING stuck on [last_machine_processed]", 0, 1)
- else
- message_admins("MACHINE PROCESSING stuck on unknown")
- if(!objects_ready)
- if(last_obj_processed)
- message_admins("OBJ PROCESSING stuck on [last_obj_processed]", 0, 1)
- else
- message_admins("OBJ PROCESSING stuck on unknown")
- log_admin("PROC BREAKAGE WARNING: infinite_loop_check = [IL_check]; [MC_report];")
- message_admins("Master controller breaking out of delaying loop. Restarting the round is advised if problem persists. DO NOT manually restart the master controller.")
- break;
- sleep(1)
+ total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + objects_cost + networks_cost + powernets_cost + ticker_cost
- sleep(world.timeofday+12-start_time)
+ var/end_time = world.timeofday
+ if(end_time < start_time)
+ start_time -= 864000 //deciseconds in a day
+ sleep( round(minimum_ticks - (end_time - start_time),1) )
+
+ else
+ sleep(10)
+
+datum/controller/game_controller/proc/Recover() //Mostly a placeholder for now.
+ var/msg = "## DEBUG: [time2text(world.timeofday)] MC restarted. Reports:\n"
+ for(var/varname in master_controller.vars)
+ switch(varname)
+ if("tag","bestF","type","parent_type","vars") continue
+ else
+ var/varval = master_controller.vars[varname]
+ if(istype(varval,/datum))
+ var/datum/D = varval
+ msg += "\t [varname] = [D.type]\n"
else
- sleep(10)
\ No newline at end of file
+ msg += "\t [varname] = [varval]\n"
+ world.log << msg
+
+/datum/failsafe // This thing pretty much just keeps poking the master controller
+ var/spinning = 1
+ var/current_iteration = 0
+ var/ticks_per_spin = 100 //poke the MC every 10 seconds
+ var/defcon = 0 //alert level. For every poke that fails this is raised by 1. When it reaches 5 the MC is replaced with a new one. (effectively killing any master_controller.process() and starting a new one)
+
+/datum/failsafe/New()
+ //There can be only one failsafe. Out with the old in with the new (that way we can restart the Failsafe by spawning a new one)
+ if(Failsafe && (Failsafe != src))
+ del(Failsafe)
+ Failsafe = src
+
+ current_iteration = controller_iteration
+ Failsafe.spin()
+
+
+/datum/failsafe/proc/spin()
+ spawn(0)
+ set background = 1
+ while(1) //more efficient than recursivly calling ourself over and over. background = 1 ensures we do not trigger an infinite loop
+ if(master_controller)
+ if(spinning && master_controller.processing) //only poke if these overrides aren't in effect
+ if(current_iteration == controller_iteration) //master_controller hasn't finished processing in the defined interval
+ switch(defcon)
+ if(0 to 3)
+ defcon++
+ if(4)
+ defcon = 5
+ for(var/client/C in admin_list)
+ if(C.holder)
+ C << "Warning. The Master Controller has not fired in the last [defcon*ticks_per_spin] ticks. Automatic restart in [ticks_per_spin] ticks."
+ if(5)
+ for(var/client/C in admin_list)
+ if(C.holder)
+ C << "Warning. The Master Controller has still not fired within the last [defcon*ticks_per_spin] ticks. Killing and restarting..."
+ new /datum/controller/game_controller() //replace the old master_controller (hence killing the old one's process)
+ master_controller.process() //Start it rolling again
+ defcon = 0
+ else
+ defcon = 0
+ current_iteration = controller_iteration
+ else
+ defcon = 0
+ else
+ new /datum/controller/game_controller() //replace the missing master_controller! This should never happen.
+ sleep(ticks_per_spin)
+
+//DEBUG VERBS
+/*
+/client/verb/spawn_MC()
+ new /datum/controller/game_controller()
+
+
+/client/verb/spawn_FS()
+ new /datum/failsafe()
+*/
diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm
index 78e3bce9de..04a1a47fed 100644
--- a/code/controllers/verbs.dm
+++ b/code/controllers/verbs.dm
@@ -1,5 +1,5 @@
//TODO: rewrite and standardise all controller datums to the datum/controller type
-//TODO: allow all controllers to be deleted for clean restarts (see WIP master controller stuff)
+//TODO: allow all controllers to be deleted for clean restarts (see WIP master controller stuff) - MC done - lighting done
/client/proc/restart_controller(controller in list("Master","Lighting","Supply Shuttle"))
set category = "Debug"
@@ -11,9 +11,11 @@
src = null
switch(controller)
if("Master")
+ new /datum/controller/game_controller()
master_controller.process()
feedback_add_details("admin_verb","RMC")
if("Lighting")
+ new /datum/controller/lighting()
lighting_controller.process()
feedback_add_details("admin_verb","RLighting")
if("Supply Shuttle")
diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm
index 626953c33d..ce3c7c4940 100644
--- a/code/game/objects/explosion.dm
+++ b/code/game/objects/explosion.dm
@@ -8,7 +8,7 @@
proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impact_range, flash_range, adminlog = 1)
- src = null
+ src = null //so we don't abort once src is deleted
spawn(0)
var/start = world.timeofday
epicenter = get_turf(epicenter)
@@ -47,12 +47,12 @@ proc/explosion(turf/epicenter, devastation_range, heavy_impact_range, light_impa
T.ex_act(dist)
if(T)
- for(var/atom_movable in T.contents)
+ for(var/atom_movable in T.contents) //bypass type checking since only atom/movable can be contained by turfs anyway
var/atom/movable/AM = atom_movable
AM.ex_act(dist)
- //here util we get explosions to be less laggy, might help us identify issues after changes to splosions (because let's face it we've had a few)
- world.log << "## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [(world.timeofday-start)/10] seconds."
+ //You need to press the DebugGame verb to see these now....they were getting annoying and we've collected a fair bit of data. Just -test- changes to explosion code using this please so we can compare
+ if(Debug2) world.log << "## DEBUG: Explosion([x0],[y0],[z0])(d[devastation_range],h[heavy_impact_range],l[light_impact_range]): Took [(world.timeofday-start)/10] seconds."
sleep(8)
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index de1d25135c..78fc387fd3 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -510,7 +510,6 @@
if(1.0)
//SN src = null
src.ReplaceWithSpace()
- del(src)
return
if(2.0)
if (prob(50))
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index a8e83602fa..1517d53705 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -222,7 +222,6 @@
//verbs += /proc/togglebuildmode --Merged with view variables
//verbs += /client/proc/cmd_modify_object_variables --Merged with view variables
verbs += /client/proc/togglebuildmodeself
- verbs += /client/proc/debug_controller
else return
//Game Admin
@@ -243,9 +242,10 @@
verbs += /client/proc/make_sound
verbs += /client/proc/play_local_sound
verbs += /client/proc/send_space_ninja
- verbs += /client/proc/restart_controller //Can call via aproccall --I_hate_easy_things.jpg, Mport --Agouri
- verbs += /client/proc/Blobize //I need to remember to move/remove this later
- verbs += /client/proc/Blobcount //I need to remember to move/remove this later
+ verbs += /client/proc/restart_controller //Can call via aproccall --I_hate_easy_things.jpg, Mport --Agouri
+ verbs += /client/proc/debug_controller
+// verbs += /client/proc/Blobize //I need to remember to move/remove this later
+// verbs += /client/proc/Blobcount //I need to remember to move/remove this later
verbs += /client/proc/toggle_clickproc //TODO ERRORAGE (Temporary proc while the new clickproc is being tested)
verbs += /client/proc/toggle_gravity_on
verbs += /client/proc/toggle_gravity_off
@@ -392,8 +392,8 @@
verbs -= /client/proc/play_local_sound
verbs -= /client/proc/enable_debug_verbs
verbs -= /client/proc/toggleprayers
- verbs -= /client/proc/Blobize
- verbs -= /client/proc/Blobcount
+// verbs -= /client/proc/Blobize
+// verbs -= /client/proc/Blobcount
verbs -= /client/proc/toggle_clickproc //TODO ERRORAGE (Temporary proc while the enw clickproc is being tested)
verbs -= /client/proc/toggle_hear_deadcast
verbs -= /client/proc/toggle_hear_radio
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index eb22b05656..4de346b775 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -659,14 +659,22 @@ note dizziness decrements automatically in the mob's Life() proc.
/mob/Stat()
..()
- statpanel("Status")
+ if(!statpanel("Status")) //not looking at that panel
+ return
- if (client && client.holder)
- stat(null, "([x], [y], [z])")
- stat(null, "CPU: [world.cpu]")
- if (master_controller)
- stat(null, "Current Iteration: [controller_iteration]")
- stat(null, "Time between ticks: [last_tick_duration]")
+ if(client && client.holder)
+ stat(null,"Location: \t ([x], [y], [z])")
+ stat(null,"CPU: \t [world.cpu]")
+
+ if(master_controller)
+ stat(null,"MasterController-[last_tick_duration] ([master_controller.processing?"On":"Off"]-[controller_iteration])")
+ stat(null,"Air-[master_controller.air_cost]\t Sun-[master_controller.sun_cost]")
+ stat(null,"Mob-[master_controller.mobs_cost]\t Dis-[master_controller.diseases_cost]")
+ stat(null,"Mch-[master_controller.machines_cost]\t Obj-[master_controller.objects_cost]")
+ stat(null,"Net-[master_controller.networks_cost]\t Pnet-[master_controller.powernets_cost]")
+ stat(null,"Tick-[master_controller.ticker_cost]\t ALL-[master_controller.total_cost]")
+ else
+ stat(null,"MasterController-ERROR")
if (spell_list.len)