Merge pull request #13437 from neersighted/clickable_stats

Refactor MC/Failsafe/add Subsystems
This commit is contained in:
duncathan salt
2015-12-07 19:58:46 -06:00
68 changed files with 751 additions and 620 deletions
@@ -33,8 +33,8 @@ Acts like a normal vent, but has an input AND output.
//OUTPUT_MAX: Do not pass output_pressure_max
/obj/machinery/atmospherics/components/binary/dp_vent_pump/Destroy()
if(radio_controller)
radio_controller.remove_object(src, frequency)
if(SSradio)
SSradio.remove_object(src, frequency)
return ..()
/obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume
@@ -117,10 +117,10 @@ Acts like a normal vent, but has an input AND output.
//Radio remote control
/obj/machinery/atmospherics/components/binary/dp_vent_pump/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA)
radio_connection = SSradio.add_object(src, frequency, filter = RADIO_ATMOSIA)
/obj/machinery/atmospherics/components/binary/dp_vent_pump/proc/broadcast_status()
if(!radio_connection)
@@ -23,8 +23,8 @@ Passive gate is similar to the regular pump except:
var/datum/radio_frequency/radio_connection
/obj/machinery/atmospherics/components/binary/passive_gate/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
return ..()
/obj/machinery/atmospherics/components/binary/passive_gate/update_icon_nopipes()
@@ -68,10 +68,10 @@ Passive gate is similar to the regular pump except:
//Radio remote control
/obj/machinery/atmospherics/components/binary/passive_gate/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA)
radio_connection = SSradio.add_object(src, frequency, filter = RADIO_ATMOSIA)
/obj/machinery/atmospherics/components/binary/passive_gate/proc/broadcast_status()
if(!radio_connection)
@@ -27,8 +27,8 @@ Thus, the two variables affect pump operation are set in New():
var/datum/radio_frequency/radio_connection
/obj/machinery/atmospherics/components/binary/pump/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
if(radio_connection)
radio_connection = null
return ..()
@@ -73,10 +73,10 @@ Thus, the two variables affect pump operation are set in New():
//Radio remote control
/obj/machinery/atmospherics/components/binary/pump/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA)
radio_connection = SSradio.add_object(src, frequency, filter = RADIO_ATMOSIA)
/obj/machinery/atmospherics/components/binary/pump/proc/broadcast_status()
if(!radio_connection)
@@ -27,8 +27,8 @@ Thus, the two variables affect pump operation are set in New():
var/datum/radio_frequency/radio_connection
/obj/machinery/atmospherics/components/binary/volume_pump/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
return ..()
/obj/machinery/atmospherics/components/binary/volume_pump/on
@@ -70,10 +70,10 @@ Thus, the two variables affect pump operation are set in New():
return 1
/obj/machinery/atmospherics/components/binary/volume_pump/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency)
radio_connection = SSradio.add_object(src, frequency)
/obj/machinery/atmospherics/components/binary/volume_pump/proc/broadcast_status()
if(!radio_connection)
@@ -39,14 +39,14 @@ Filter types:
flipped = 1
/obj/machinery/atmospherics/components/trinary/filter/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/components/trinary/filter/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
return ..()
/obj/machinery/atmospherics/components/trinary/filter/update_icon()
@@ -17,8 +17,8 @@
level = 1
/obj/machinery/atmospherics/components/unary/outlet_injector/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
return ..()
/obj/machinery/atmospherics/components/unary/outlet_injector/on
@@ -79,10 +79,10 @@
flick("inje_inject", src)
/obj/machinery/atmospherics/components/unary/outlet_injector/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency)
radio_connection = SSradio.add_object(src, frequency)
/obj/machinery/atmospherics/components/unary/outlet_injector/proc/broadcast_status()
if(!radio_connection)
@@ -60,8 +60,8 @@
id_tag = num2text(uid)
/obj/machinery/atmospherics/components/unary/vent_pump/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
radio_connection = null
if(initial_loc)
initial_loc.air_vent_info -= id_tag
@@ -154,10 +154,10 @@
//Radio remote control
/obj/machinery/atmospherics/components/unary/vent_pump/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency,radio_filter_in)
radio_connection = SSradio.add_object(src, frequency,radio_filter_in)
/obj/machinery/atmospherics/components/unary/vent_pump/proc/broadcast_status()
if(!radio_connection)
@@ -49,8 +49,8 @@
id_tag = num2text(uid)
/obj/machinery/atmospherics/components/unary/vent_scrubber/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
radio_connection = null
if(initial_loc)
initial_loc.air_scrub_info -= id_tag
@@ -103,9 +103,9 @@
icon_state = "scrub_purge"
/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency, radio_filter_in)
radio_connection = SSradio.add_object(src, frequency, radio_filter_in)
/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/broadcast_status()
if(!radio_connection)
+5
View File
@@ -31,3 +31,8 @@ var/cmp_field = "name"
/proc/cmp_subsystem_priority(datum/subsystem/a, datum/subsystem/b)
return b.priority - a.priority
/proc/cmp_subsystem_display(datum/subsystem/a, datum/subsystem/b)
if(a.display == b.display)
return sorttext(b.name, a.name)
return a.display - b.display
+50
View File
@@ -0,0 +1,50 @@
// Clickable stat() button.
/obj/effect/statclick
var/target
/obj/effect/statclick/New(text, target)
name = text
src.target = target
/obj/effect/statclick/proc/update(text)
name = text
return src
/obj/effect/statclick/debug
var/class
/obj/effect/statclick/debug/Click()
if(!usr.client.holder)
return
if(!class)
if(istype(target, /datum/subsystem))
class = "subsystem"
else if(istype(target, /datum/controller))
class = "controller"
else if(istype(target, /datum))
class = "datum"
else
class = "unknown"
usr.client.debug_variables(target)
message_admins("Admin [key_name_admin(usr)] is debugging the [target] [class].")
// Debug verbs.
/client/proc/restart_controller(controller in list("Master", "Failsafe"))
set category = "Debug"
set name = "Restart Controller"
set desc = "Restart one of the various periodic loop controllers for the game (be careful!)"
if(!holder)
return
switch(controller)
if("Master")
new/datum/controller/master()
Master.process()
feedback_add_details("admin_verb","RMC")
if("Failsafe")
new /datum/controller/failsafe()
feedback_add_details("admin_verb","RFailsafe")
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
+10
View File
@@ -11,6 +11,8 @@
var/autoadmin_rank = "Game Admin"
/datum/configuration
var/name = "Configuration" // datum name
var/server_name = null // server name (the name of the game window)
var/station_name = null // station name (the name of the station in-game)
var/server_suffix = 0 // generate numeric suffix based on server port
@@ -183,6 +185,8 @@
var/maprotation = 1
var/maprotatechancedelta = 0.75
// The object used for the clickable stat() button.
var/obj/effect/statclick/statclick
/datum/configuration/New()
@@ -699,3 +703,9 @@
if(M.required_players <= crew)
runnable_modes[M] = probabilities[M.config_tag]
return runnable_modes
/datum/configuration/proc/stat_entry()
if(!statclick)
statclick = new/obj/effect/statclick/debug("Edit", src)
stat("[name]:", statclick)
+4
View File
@@ -0,0 +1,4 @@
/datum/controller
var/name
// The object used for the clickable stat() button.
var/obj/effect/statclick/statclick
+49 -24
View File
@@ -1,43 +1,68 @@
/**
* Failsafe
*
* Pretty much pokes the MC to make sure it's still alive.
**/
var/datum/controller/failsafe/Failsafe
/datum/controller/failsafe // This thing pretty much just keeps poking the master controller
var/processing_interval = 100 //poke the MC every 10 seconds - set to 0 to disable
name = "Failsafe"
var/MC_iteration = 0
var/MC_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)
// The length of time to check on the MC (in deciseconds).
// Set to 0 to disable.
var/processing_interval = 100
// The alert level. For every failed poke, we drop a DEFCON level. Once we hit DEFCON 1, restart the MC.
var/defcon = 0
// Track the MC iteration to make sure its still on track.
var/master_iteration = 0
/datum/controller/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)
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
if(Failsafe != src)
if(istype(Failsafe))
qdel(Failsafe)
Failsafe = src
Failsafe.process()
/datum/controller/failsafe/process()
spawn(0)
while(1) //more efficient than recursivly calling ourself over and over. background = 1 ensures we do not trigger an infinite loop
if(!master_controller) new /datum/controller/game_controller() //replace the missing master_controller! This should never happen.
while(1) // More efficient than recursion, 1 to avoid an infinite loop.
if(!Master)
// Replace the missing Master! This should never, ever happen.
new /datum/controller/master()
// Only poke it if overrides are not in effect.
if(processing_interval > 0)
if(master_controller.processing_interval > 0) //only poke if these overrides aren't in effect
if(MC_iteration == master_controller.iteration) //master_controller hasn't finished processing in the defined interval
switch(MC_defcon)
if(0 to 3)
++MC_defcon
if(Master.processing_interval > 0)
// Check if processing is done yet.
if(Master.iteration == master_iteration)
switch(defcon)
if(1 to 2)
++defcon
if(3)
admins << "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has not fired in the last [defcon * processing_interval] ticks. Automatic restart in [processing_interval] ticks.</span>"
defcon = 4
if(4)
admins << "<font color='red' size='2'><b>Warning. The Master Controller has not fired in the last [MC_defcon*processing_interval] ticks. Automatic restart in [processing_interval] ticks.</b></font>"
MC_defcon = 5
if(5)
admins << "<font color='red' size='2'><b>Warning. The Master Controller has still not fired within the last [MC_defcon*processing_interval] ticks. Killing and restarting...</b></font>"
new /datum/controller/game_controller() //replace the old master_controller (hence killing the old one's process)
master_controller.process() //Start it rolling again
MC_defcon = 0
admins << "<span class='boldannounce'>Warning: DEFCON [defcon_pretty()]. The Master Controller has still not fired within the last [defcon * processing_interval] ticks. Killing and restarting...</span>"
// Replace the old master controller by creating a new one.
new/datum/controller/master()
// Get it rolling again.
Master.process()
defcon = 0
else
MC_defcon = 0
MC_iteration = master_controller.iteration
defcon = 0
master_iteration = Master.iteration
sleep(processing_interval)
else
MC_defcon = 0
sleep(100)
defcon = 0
sleep(initial(processing_interval))
/datum/controller/failsafe/proc/defcon_pretty()
return 5 - Failsafe.defcon
/datum/controller/failsafe/proc/stat_entry()
if(!statclick)
statclick = new/obj/effect/statclick/debug("Initializing...", src)
stat("Failsafe Controller:", statclick.update("Defcon: [Failsafe.defcon_pretty()] (Interval: [Failsafe.processing_interval] | Iteration: [Failsafe.master_iteration])"))
+198
View File
@@ -0,0 +1,198 @@
/**
* CarnMC
*
* Simplified MC; designed to fail fast and respawn.
* This ensures Master.process() never doubles up.
* It will kill itself and any sleeping procs if needed.
*
* All core systems are subsystems.
* They are process()'d by this Master Controller.
**/
var/global/datum/controller/master/Master = new()
/datum/controller/master
name = "Master"
// The minimum length of time between MC ticks (in deciseconds).
// The highest this can be without affecting schedules is the GCD of all subsystem waits.
// Set to 0 to disable all processing.
var/processing_interval = 1
// The iteration of the MC.
var/iteration = 0
// The cost (in deciseconds) of the MC loop.
var/cost = 0
// A list of subsystems to process().
var/list/subsystems = list()
// The cost of running the subsystems (in deciseconds).
var/subsystem_cost = 0
// The type of the last subsystem to be process()'d.
var/last_type_processed
/datum/controller/master/New()
// Highlander-style: there can only be one! Kill off the old and replace it with the new.
if(Master != src)
if(istype(Master))
Recover()
qdel(Master)
else
init_subtypes(/datum/subsystem, subsystems)
Master = src
processing_interval = calculate_gcd()
/datum/controller/master/Destroy()
..()
// Tell qdel() to Del() this object.
return QDEL_HINT_HARDDEL_NOW
/datum/controller/master/proc/Recover()
var/msg = "## DEBUG: [time2text(world.timeofday)] MC restarted. Reports:\n"
for(var/varname in Master.vars)
switch(varname)
if("name", "tag", "bestF", "type", "parent_type", "vars", "statclick") // Built-in junk.
continue
else
var/varval = Master.vars[varname]
if(istype(varval, /datum)) // Check if it has a type var.
var/datum/D = varval
msg += "\t [varname] = [D.type]\n"
else
msg += "\t [varname] = [varval]\n"
world.log << msg
subsystems = Master.subsystems
/datum/controller/master/proc/Setup(zlevel)
// Per-Z-level subsystems.
if (zlevel && zlevel > 0 && zlevel <= world.maxz)
for(var/datum/subsystem/SS in subsystems)
SS.Initialize(world.timeofday, zlevel)
sleep(-1)
return
world << "<span class='boldannounce'>Initializing subsystems...</span>"
// Pick a random away mission.
createRandomZlevel()
// Generate asteroid.
make_mining_asteroid_secrets()
// Set up Z-level transistions.
setup_map_transitions()
// Sort subsystems by priority, so they initialize in the correct order.
sortTim(subsystems, /proc/cmp_subsystem_priority)
// Initialize subsystems.
for(var/datum/subsystem/SS in subsystems)
SS.Initialize(world.timeofday, zlevel)
sleep(-1)
world << "<span class='boldannounce'>Initializations complete!</span>"
// Sort subsystems by display setting for easy access.
sortTim(subsystems, /proc/cmp_subsystem_display)
// Set world options.
world.sleep_offline = 1
world.fps = config.fps
sleep(-1)
// Loop.
Master.process()
// Notify the MC that the round has started.
/datum/controller/master/proc/RoundStart()
for(var/datum/subsystem/SS in subsystems)
SS.can_fire = 1
SS.next_fire = world.time + rand(0, SS.wait) // Stagger subsystems.
// Used to smooth out costs to try and avoid oscillation.
#define MC_AVERAGE(average, current) (0.8 * (average) + 0.2 * (current))
/datum/controller/master/process()
if(!Failsafe)
new/datum/controller/failsafe() // (re)Start the failsafe.
spawn(0)
// Schedule the first run of the Subsystems.
var/timer = world.time
for(var/datum/subsystem/SS in subsystems)
timer += processing_interval
SS.next_fire = timer
var/start_time
while(1) // More efficient than recursion, 1 to avoid an infinite loop.
if(processing_interval > 0)
++iteration
var/startingtick = world.time // Store when we started this iteration.
start_time = world.timeofday
var/ran_subsystems = 0
for(var/datum/subsystem/SS in subsystems)
if(SS.can_fire > 0)
if(SS.next_fire <= world.time && SS.last_fire + (SS.wait * 0.5) <= world.time) // Check if it's time.
ran_subsystems = 1
timer = world.timeofday
last_type_processed = SS.type
SS.last_fire = world.time
SS.fire() // Fire the subsystem and record the cost.
SS.cost = MC_AVERAGE(SS.cost, world.timeofday - timer)
if(SS.dynamic_wait) // Adjust wait depending on lag.
var/oldwait = SS.wait
var/global_delta = (subsystem_cost - (SS.cost / (SS.wait / 10))) - 1
var/newwait = (SS.cost - SS.dwait_buffer + global_delta) * SS.dwait_delta
newwait = newwait * (world.cpu / 100 + 1)
newwait = MC_AVERAGE(oldwait, newwait)
SS.wait = Clamp(newwait, SS.dwait_lower, SS.dwait_upper)
if(oldwait != SS.wait)
processing_interval = calculate_gcd()
SS.next_fire += SS.wait
++SS.times_fired
// If we caused BYOND to miss a tick, stop processing for a bit...
if(startingtick < world.time || start_time + 1 < world.timeofday)
break
sleep(-1)
cost = MC_AVERAGE(cost, world.timeofday - start_time)
if(ran_subsystems)
var/oldcost = subsystem_cost
var/newcost = 0
for(var/datum/subsystem/SS in subsystems)
if (!SS.can_fire)
continue
newcost += SS.cost / (SS.wait / 10)
subsystem_cost = MC_AVERAGE(oldcost, newcost)
var/extrasleep = 0
// If we caused BYOND to miss a tick, sleep a bit extra...
if(startingtick < world.time || start_time + 1 < world.timeofday)
extrasleep += world.tick_lag * 2
// If we are loading the server too much, sleep a bit extra...
if(world.cpu > 80)
extrasleep += extrasleep + processing_interval
sleep(processing_interval + extrasleep)
else
sleep(50)
#undef MC_AVERAGE
// Determine the GCD of subsystem waits: the longest the MC can wait while still staying on schedule.
/datum/controller/master/proc/calculate_gcd()
var/GCD
// The shortest possible fire rate is the lowest of two ticks or 1 decisecond.
var/minimumInterval = min(world.tick_lag * 2, 1)
// Loop over each subsystem and determine the GCD based on its wait value.
for(var/datum/subsystem/SS in subsystems)
if(SS.wait)
GCD = Gcd(round(SS.wait * 10), GCD)
GCD = round(GCD)
// If the GCD is less than the minimum, just use the minimum.
if(GCD < minimumInterval * 10)
GCD = minimumInterval * 10
// Return GCD.
return GCD / 10
/datum/controller/master/proc/stat_entry()
if(!statclick)
statclick = new/obj/effect/statclick/debug("Initializing...", src)
stat("Master Controller:", statclick.update("[round(Master.cost, 0.001)]ds (Interval: [Master.processing_interval] | Iteration:[Master.iteration])"))
-169
View File
@@ -1,169 +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)
//Update: all core-systems are now placed inside subsystem datums. This makes them highly configurable and easy to work with.
var/global/datum/controller/game_controller/master_controller = new()
/datum/controller/game_controller
var/processing_interval = 1 //The minimum length of time between MC ticks (in deciseconds). The highest this can be without affecting schedules, is the GCD of all subsystem var/wait. Set to 0 to disable all processing.
var/iteration = 0
var/cost = 0
var/SSCostPerSecond = 0
var/last_thing_processed
var/list/subsystems = list()
/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))
Recover()
qdel(master_controller)
else
init_subtypes(/datum/subsystem, subsystems)
master_controller = src
calculateGCD()
/datum/controller/game_controller/Destroy()
..()
return QDEL_HINT_HARDDEL_NOW
/*
calculate the longest number of ticks the MC can wait between each cycle without causing subsystems to not fire on schedule
*/
/datum/controller/game_controller/proc/calculateGCD()
var/GCD
//shortest fire rate is the lower of two ticks or 1ds
var/minimumInterval = min(world.tick_lag*2,1)
for(var/datum/subsystem/SS in subsystems)
if(SS.wait)
GCD = Gcd(round(SS.wait*10), GCD)
GCD = round(GCD)
if(GCD < minimumInterval*10)
GCD = minimumInterval*10
processing_interval = GCD/10
/datum/controller/game_controller/proc/setup(zlevel)
if (zlevel && zlevel > 0 && zlevel <= world.maxz)
for(var/datum/subsystem/S in subsystems)
S.Initialize(world.timeofday, zlevel)
sleep(-1)
return
world << "<span class='boldannounce'>Initializing Subsystems...</span>"
//sort subsystems by priority, so they initialize in the correct order
sortTim(subsystems, /proc/cmp_subsystem_priority)
createRandomZlevel() //gate system
setup_map_transitions()
for(var/i=0, i<max_secret_rooms, i++)
make_mining_asteroid_secret()
//Eventually all this other setup stuff should be contained in subsystems and done in subsystem.Initialize()
for(var/datum/subsystem/S in subsystems)
S.Initialize(world.timeofday, zlevel)
sleep(-1)
crewmonitor.generateMiniMaps()
populate_asset_cache()
world << "<span class='boldannounce'>Initializations complete</span>"
world.sleep_offline = 1
world.fps = config.fps
sleep(-1)
process()
//used for smoothing out the cost values so they don't fluctuate wildly
#define MC_AVERAGE(average, current) (0.8*(average) + 0.2*(current))
/datum/controller/game_controller/process()
if(!Failsafe) new /datum/controller/failsafe()
spawn(0)
var/timer = world.time
for(var/datum/subsystem/SS in subsystems)
timer += processing_interval
SS.next_fire = timer
var/start_time
while(1) //far more efficient than recursively calling ourself
if(processing_interval > 0)
++iteration
var/startingtick = world.time
start_time = world.timeofday
var/SubSystemRan = 0
for(var/datum/subsystem/SS in subsystems)
if(SS.can_fire > 0)
if(SS.next_fire <= world.time && SS.last_fire+(SS.wait*0.5) <= world.time)
SubSystemRan = 1
timer = world.timeofday
last_thing_processed = SS.type
SS.last_fire = world.time
SS.fire()
SS.cost = MC_AVERAGE(SS.cost, world.timeofday - timer)
if (SS.dynamic_wait)
var/oldwait = SS.wait
var/GlobalCostDelta = (SSCostPerSecond-(SS.cost/(SS.wait/10)))-1
var/NewWait = (SS.cost-SS.dwait_buffer+GlobalCostDelta)*SS.dwait_delta
NewWait = NewWait*(world.cpu/100+1)
NewWait = MC_AVERAGE(oldwait,NewWait)
SS.wait = Clamp(NewWait,SS.dwait_lower,SS.dwait_upper)
if (oldwait != SS.wait)
calculateGCD()
SS.next_fire += SS.wait
++SS.times_fired
//we caused byond to miss a tick, stop processing for a bit
if (startingtick < world.time || start_time+1 < world.timeofday)
break
sleep(-1)
cost = MC_AVERAGE(cost, world.timeofday - start_time)
if (SubSystemRan)
calculateSScost()
var/extrasleep = 0
if (startingtick < world.time || start_time+1 < world.timeofday)
//we caused byond to miss a tick, sleep a bit extra
extrasleep += world.tick_lag*2
if (world.cpu > 80)
extrasleep += extrasleep+processing_interval
sleep(processing_interval+extrasleep)
else
sleep(50)
/datum/controller/game_controller/proc/calculateSScost()
var/newcost = 0
for(var/datum/subsystem/SS in subsystems)
if (!SS.can_fire)
continue
newcost += SS.cost/(SS.wait/10)
SSCostPerSecond = MC_AVERAGE(SSCostPerSecond,newcost)
#undef MC_AVERAGE
/datum/controller/game_controller/proc/roundHasStarted()
for(var/datum/subsystem/SS in subsystems)
SS.can_fire = 1
SS.next_fire = world.time + rand(0,SS.wait)
/datum/controller/game_controller/proc/Recover()
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
msg += "\t [varname] = [varval]\n"
world.log << msg
subsystems = master_controller.subsystems
@@ -1,30 +1,35 @@
#define NEW_SS_GLOBAL(varname) if(varname != src){if(istype(varname)){Recover();qdel(varname);}varname = src;}
/datum/subsystem
//things you will want to define
// Metadata; you should define these.
var/name //name of the subsystem
var/priority = 0 //priority affects order of initialization. Higher priorities are initialized first, lower priorities later. Can be decimal and negative values.
var/wait = 20 //time to wait (in deciseconds) between each call to fire(). Must be a positive integer.
var/display = 100 //display affects order the subsystem is displayed in the MC tab
//Dynamic Wait - A system for scaling a subsystem's fire rate based on lag
//The algorithm is: (cost-dwait_buffer+AvgCostOfAllOtherSSPerSecond)*dwait_delta
//defaults are pretty sane for most use cases.
//you can change how quickly it starts scaling back with dwait_buffer,
//and you can change how much it scales back with dwait_delta
// Dynamic Wait
// A system for scaling a subsystem's fire rate based on lag.
// The algorithm is: (cost - dwait_buffer + subsystem_cost) * dwait_delta
// Defaults are pretty sane for most use cases.
// You can change how quickly it starts scaling back with dwait_buffer,
// and you can change how much it scales back with dwait_delta.
var/dynamic_wait = 0 //changes the wait based on the amount of time it took to process
var/dwait_upper = 20 //longest wait can be under dynamic_wait
var/dwait_lower = 5 //shortest wait can be under dynamic_wait
var/dwait_delta = 7 //How much should processing time effect dwait. or basically: wait = cost*dwait_delta
var/dwait_buffer = 0.7 //This number is subtracted from the processing time before calculating its new wait
//things you will probably want to leave alone
// Bookkeeping variables; probably shouldn't mess with these.
var/can_fire = 0 //prevent fire() calls
var/last_fire = 0 //last world.time we called fire()
var/next_fire = 0 //scheduled world.time for next fire()
var/cost = 0 //average time to execute
var/times_fired = 0 //number of times we have called fire()
//used to initialize the subsystem BEFORE the map has loaded
// The object used for the clickable stat() button.
var/obj/effect/statclick/statclick
// Used to initialize the subsystem BEFORE the map has loaded
/datum/subsystem/New()
//previously, this would have been named 'process()' but that name is used everywhere for different things!
@@ -37,19 +42,28 @@
//used to initialize the subsystem AFTER the map has loaded
/datum/subsystem/proc/Initialize(start_timeofday, zlevel)
var/time = (world.timeofday - start_timeofday) / 10
var/msg = "Initialized [name] SubSystem within [time] seconds"
if (zlevel)
var/msg = "Initialized [name] subsystem within [time] seconds!"
if(zlevel) // If only initialized for one Z-level.
testing(msg)
return
return time
world << "<span class='boldannounce'>[msg]</span>"
return time
//hook for printing stats to the "MC" statuspanel for admins to see performance and related stats etc.
/datum/subsystem/proc/stat_entry(msg)
if(!statclick)
statclick = new/obj/effect/statclick/debug("Initializing...", src)
var/dwait = ""
if (dynamic_wait)
if(dynamic_wait)
dwait = "DWait:[round(wait,0.1)]ds "
stat(name, "[round(cost,0.001)]ds\t[dwait][msg]")
if(can_fire)
msg = "[round(cost,0.001)]ds\t[dwait][msg]"
else
msg = "OFFLINE"
stat(name, statclick.update(msg))
//could be used to postpone a costly subsystem for (default one) var/cycles, cycles
//for instance, during cpu intensive operations like explosions
@@ -59,4 +73,4 @@
//usually called via datum/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash)
//should attempt to salvage what it can from the old instance of subsystem
/datum/subsystem/proc/Recover()
/datum/subsystem/proc/Recover()
+1
View File
@@ -6,6 +6,7 @@ var/datum/subsystem/air/SSair
wait = 5
dynamic_wait = 1
dwait_upper = 50
display = 1
var/cost_turfs = 0
var/cost_groups = 0
+23
View File
@@ -0,0 +1,23 @@
var/datum/subsystem/assets/SSasset
/datum/subsystem/assets
name = "Assets"
priority = -3
var/list/cache = list()
/datum/subsystem/assets/New()
NEW_SS_GLOBAL(SSasset)
/datum/subsystem/assets/Initialize(timeofday, zlevel)
if (zlevel)
return ..()
for(var/type in typesof(/datum/asset) - list(/datum/asset, /datum/asset/simple))
var/datum/asset/A = new type()
A.register()
for(var/client/C in clients)
// Doing this to a client too soon after they've connected can cause issues, also the proc we call sleeps.
spawn(10)
getFilesSlow(C, cache, FALSE)
..()
+4 -2
View File
@@ -2,13 +2,15 @@ var/datum/subsystem/garbage_collector/SSgarbage
/datum/subsystem/garbage_collector
name = "Garbage"
can_fire = 1
wait = 5
priority = -1
wait = 5
dynamic_wait = 1
dwait_upper = 50
dwait_delta = 10
dwait_buffer = 0
display = 2
can_fire = 1 // This needs to fire before round start.
var/collection_timeout = 300// deciseconds to wait to let running procs finish before we just say fuck it and force del() the object
var/max_run_time = 1 // how long, in deciseconds, can we run before waiting for the next tick
+2 -1
View File
@@ -4,10 +4,11 @@ var/datum/subsystem/lighting/SSlighting
/datum/subsystem/lighting
name = "Lighting"
wait = 5
priority = 1
wait = 5
dynamic_wait = 1
dwait_delta = 3
display = 5
var/list/changed_lights = list() //list of all datum/light_source that need updating
var/changed_lights_workload = 0 //stats on the largest number of lights (max changed_lights.len)
+1
View File
@@ -3,6 +3,7 @@ var/datum/subsystem/machines/SSmachine
/datum/subsystem/machines
name = "Machines"
priority = 9
display = 3
var/list/processing = list()
var/list/powernets = list()
+181
View File
@@ -0,0 +1,181 @@
// Activate this to debug tile mismatches in the minimap.
// This will store the full information on each tile and compare it the next time you run the minimap.
// It can be used to find out what's changed since the last iteration.
// Only activate this when you need it - this should never be active on a live server!
// #define MINIMAP_DEBUG
var/datum/subsystem/minimap/SSminimap
/datum/subsystem/minimap
name = "Minimap"
priority = -2
var/const/MAX_ICON_DIMENSION = 1024
var/const/ICON_SIZE = 4
/datum/subsystem/minimap/New()
NEW_SS_GLOBAL(SSminimap)
/datum/subsystem/minimap/Initialize(timeofday, zlevel)
if (zlevel)
return ..()
for(var/z = 1 to world.maxz)
generate(z)
for (var/z = 1 to world.maxz)
register_asset("minimap_[z].png", file("[getMinimapFile(z)].png"))
..()
/datum/subsystem/minimap/proc/generate(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy)
var/result_path = "[src.getMinimapFile(z)].png"
var/hash_path = "[src.getMinimapFile(z)].md5"
var/list/tiles = block(locate(x1, y1, z), locate(x2, y2, z))
var/hash = ""
var/temp
var/obj/obj
#ifdef MINIMAP_DEBUG
var/tiledata_path = "data/minimaps/debug_tiledata_[z].sav"
var/savefile/F = new/savefile(tiledata_path)
#endif
// Note for future developer: If you have tiles on the map with random or dynamic icons this hash check will fail
// every time. You'll have to modify this code to generate a unique hash for your object.
// Don't forget to modify the minimap generation code to use a default icon (or skip generation altogether).
for (var/turf/tile in tiles)
if (istype(tile.loc, /area/asteroid) || istype(tile.loc, /area/mine/unexplored) || istype(tile, /turf/simulated/mineral) || (istype(tile.loc, /area/space) && istype(tile, /turf/simulated/floor/plating/asteroid)))
temp = "/area/asteroid"
else if (istype(tile.loc, /area/mine) && istype(tile, /turf/simulated/floor/plating/asteroid))
temp = "/area/mine/explored"
else if (tile.loc.type == /area/start || (tile.type == /turf/space && !(locate(/obj/structure/lattice) in tile)) || istype(tile, /turf/space/transit))
temp = "/turf/space"
if (locate(/obj/structure/lattice/catwalk) in tile)
else
else if (tile.type == /turf/space)
if (locate(/obj/structure/lattice/catwalk) in tile)
temp = "/obj/structure/lattice/catwalk"
else
temp = "/obj/structure/lattice"
else if (tile.type == /turf/simulated/floor/plating/abductor)
temp = "/turf/simulated/floor/plating/abductor"
else if (tile.type == /turf/simulated/floor/plating && (locate(/obj/structure/window/shuttle) in tile))
temp = "/obj/structure/window/shuttle"
else
temp = "[tile.icon][tile.icon_state][tile.dir]"
obj = locate(/obj/structure/transit_tube) in tile
if (obj) temp = "[temp]/obj/structure/transit_tube[obj.icon_state][obj.dir]"
#ifdef MINIMAP_DEBUG
if (F["/[tile.y]/[tile.x]"] && F["/[tile.y]/[tile.x]"] != temp)
CRASH("Mismatch: [tile.type] at [tile.x],[tile.y],[tile.z] ([tile.icon], [tile.icon_state], [tile.dir])")
else
F["/[tile.y]/[tile.x]"] << temp
#endif
hash = md5("[hash][temp]")
if (fexists(result_path))
if (!fexists(hash_path) || trim(file2text(hash_path)) != hash)
fdel(result_path)
fdel(hash_path)
if (!fexists(result_path))
ASSERT(x1 > 0)
ASSERT(y1 > 0)
ASSERT(x2 <= world.maxx)
ASSERT(y2 <= world.maxy)
var/icon/map_icon = new/icon('html/mapbase1024.png')
// map_icon is fine and contains only 1 direction at this point.
ASSERT(map_icon.Width() == MAX_ICON_DIMENSION && map_icon.Height() == MAX_ICON_DIMENSION)
var/i = 0
var/icon/turf_icon
var/icon/obj_icon
var/old_icon
var/old_icon_state
var/old_dir
var/new_icon
var/new_icon_state
var/new_dir
for (var/turf/tile in tiles)
if (tile.loc.type != /area/start && (tile.type != /turf/space || (locate(/obj/structure/lattice) in tile) || (locate(/obj/structure/transit_tube) in tile)) && !istype(tile, /turf/space/transit))
if (istype(tile.loc, /area/asteroid) || istype(tile.loc, /area/mine/unexplored) || istype(tile, /turf/simulated/mineral) || (istype(tile.loc, /area/space) && istype(tile, /turf/simulated/floor/plating/asteroid)))
new_icon = 'icons/turf/mining.dmi'
new_icon_state = "rock"
new_dir = 2
else if (istype(tile.loc, /area/mine) && istype(tile, /turf/simulated/floor/plating/asteroid))
new_icon = 'icons/turf/floors.dmi'
new_icon_state = "asteroid"
new_dir = 2
else if (tile.type == /turf/simulated/floor/plating/abductor)
new_icon = 'icons/turf/floors.dmi'
new_icon_state = "alienpod1"
new_dir = 2
else if (tile.type == /turf/space)
obj = locate(/obj/structure/lattice) in tile
if (!obj) obj = locate(/obj/structure/transit_tube) in tile
ASSERT(obj != null)
if (obj)
new_icon = obj.icon
new_dir = obj.dir
new_icon_state = obj.icon_state
else if (tile.type == /turf/simulated/floor/plating && (locate(/obj/structure/window/shuttle) in tile))
new_icon = 'icons/obj/structures.dmi'
new_dir = 2
new_icon_state = "swindow"
else
new_icon = tile.icon
new_icon_state = tile.icon_state
new_dir = tile.dir
if (new_icon != old_icon || new_icon_state != old_icon_state || new_dir != old_dir)
old_icon = new_icon
old_icon_state = new_icon_state
old_dir = new_dir
turf_icon = new/icon(new_icon, new_icon_state, new_dir, 1, 0)
turf_icon.Scale(ICON_SIZE, ICON_SIZE)
if (tile.type != /turf/space || (locate(/obj/structure/lattice) in tile))
obj = locate(/obj/structure/transit_tube) in tile
if (obj)
obj_icon = new/icon(obj.icon, obj.icon_state, obj.dir, 1, 0)
obj_icon.Scale(ICON_SIZE, ICON_SIZE)
turf_icon.Blend(obj_icon, ICON_OVERLAY)
map_icon.Blend(turf_icon, ICON_OVERLAY, ((tile.x - 1) * ICON_SIZE), ((tile.y - 1) * ICON_SIZE))
if ((++i) % 512 == 0) sleep(1) // deliberate delay to avoid lag spikes
else
sleep(-1) // avoid sleeping if possible: prioritize pending procs
// BYOND BUG: map_icon now contains 4 directions? Create a new icon with only a single state.
var/icon/result_icon = new/icon()
result_icon.Insert(map_icon, "", SOUTH, 1, 0)
fcopy(result_icon, result_path)
text2file(hash, hash_path)
/datum/subsystem/minimap/proc/getMinimapFile(zlevel)
return "data/minimaps/map_[zlevel]"
/datum/subsystem/minimap/proc/sendMinimaps(client/client)
for (var/z = 1 to world.maxz)
send_asset(client, "minimap_[z].png")
#ifdef MINIMAP_DEBUG
#undef MINIMAP_DEBUG
#endif
+1
View File
@@ -3,6 +3,7 @@ var/datum/subsystem/mobs/SSmob
/datum/subsystem/mobs
name = "Mobs"
priority = 4
display = 4
/datum/subsystem/mobs/New()
+4 -4
View File
@@ -2,22 +2,22 @@ var/datum/subsystem/nano/SSnano
/datum/subsystem/nano
name = "NanoUI"
can_fire = 1
wait = 10
priority = 16
display = 6
can_fire = 1 // This needs to fire before round start.
var/list/open_uis = list() // A list of open NanoUIs, grouped by src_object and ui_key.
var/list/processing_uis = list() // A list of processing NanoUIs, not grouped.
/datum/subsystem/nano/New()
NEW_SS_GLOBAL(SSnano) // Register the subsystem.
NEW_SS_GLOBAL(SSnano)
/datum/subsystem/nano/stat_entry()
..("O:[open_uis.len]|P:[processing_uis.len]") // Show how many interfaces we have open/are processing.
/datum/subsystem/nano/fire() // Process UIs.
for(var/thing in processing_uis)
var/datum/nanoui/ui = thing
+5 -4
View File
@@ -1,8 +1,9 @@
var/datum/subsystem/npcpool/SSbp
var/datum/subsystem/npcpool/SSnpc
/datum/subsystem/npcpool
name = "NPCPool"
priority = 100
name = "NPC Pool"
priority = 17
display = 6
var/list/canBeUsed = list()
var/list/canBeUsed_non = list()
@@ -17,7 +18,7 @@ var/datum/subsystem/npcpool/SSbp
botPool_l |= toInsert
/datum/subsystem/npcpool/New()
NEW_SS_GLOBAL(SSbp)
NEW_SS_GLOBAL(SSnpc)
/datum/subsystem/npcpool/stat_entry()
..("T:[botPool_l.len + botPool_l_non.len]|D:[needsDelegate.len]|A:[needsAssistant.len + needsHelp_non.len]|U:[canBeUsed.len + canBeUsed_non.len]")
+1 -1
View File
@@ -2,7 +2,7 @@ var/datum/subsystem/pai/SSpai
/datum/subsystem/pai
name = "pAI"
wait = 20
priority = 20
var/askDelay = 600
+2 -2
View File
@@ -1,4 +1,4 @@
var/datum/subsystem/radio/radio_controller
var/datum/subsystem/radio/SSradio
/datum/subsystem/radio
name = "Radio"
@@ -7,7 +7,7 @@ var/datum/subsystem/radio/radio_controller
var/list/datum/radio_frequency/frequencies = list()
/datum/subsystem/radio/New()
NEW_SS_GLOBAL(radio_controller)
NEW_SS_GLOBAL(SSradio)
/datum/subsystem/radio/proc/add_object(obj/device, new_frequency as num, filter = null as text|null)
var/f_text = num2text(new_frequency)
@@ -1,8 +1,13 @@
var/datum/subsystem/server_maint/SSserver
/datum/subsystem/server_maint
name = "Server Tasks"
wait = 6000
priority = 19
/datum/subsystem/server_maint/New()
NEW_SS_GLOBAL(SSserver)
/datum/subsystem/server_maint/fire()
//handle kicking inactive players
if(config.kick_inactive > 0)
@@ -547,7 +547,7 @@
/obj/machinery/computer/supplycomp/proc/post_signal(command)
var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
var/datum/radio_frequency/frequency = SSradio.return_frequency(1435)
if(!frequency) return
+6 -8
View File
@@ -4,9 +4,10 @@ var/datum/subsystem/ticker/ticker
/datum/subsystem/ticker
name = "Ticker"
can_fire = 1
priority = 0
can_fire = 1 // This needs to fire before round start.
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
@@ -20,7 +21,7 @@ var/datum/subsystem/ticker/ticker
var/list/datum/mind/minds = list() //The characters in the game. Used for objective tracking.
//These bible variables should be a preference
//These bible variables should be a preference
var/Bible_icon_state //icon_state the chaplain has chosen for his bible
var/Bible_item_state //item_state the chaplain has chosen for his bible
var/Bible_name //name of the bible
@@ -67,7 +68,7 @@ var/datum/subsystem/ticker/ticker
switch(current_state)
if(GAME_STATE_STARTUP)
timeLeft = config.lobby_countdown * 10
world << "<B><FONT color='blue'>Welcome to the pre-game lobby!</FONT></B>"
world << "<b><font color='blue'>Welcome to the pre-game lobby!</font></b>"
world << "Please, setup your character and select ready. Game will start in [config.lobby_countdown] seconds"
current_state = GAME_STATE_PREGAME
@@ -178,8 +179,7 @@ var/datum/subsystem/ticker/ticker
equip_characters()
data_core.manifest()
master_controller.roundHasStarted()
Master.RoundStart()
world << "<FONT color='blue'><B>Welcome to [station_name()], enjoy your stay!</B></FONT>"
world << sound('sound/AI/welcome.ogg')
@@ -205,7 +205,7 @@ var/datum/subsystem/ticker/ticker
return 1
//Plus it provides an easy way to make cinematics for other events. Just use this as a template
//Plus it provides an easy way to make cinematics for other events. Just use this as a template
/datum/subsystem/ticker/proc/station_explosion_cinematic(station_missed=0, override = null)
if( cinematic ) return //already a cinematic in progress!
@@ -261,8 +261,6 @@ var/datum/subsystem/ticker/ticker
if(2) //nuke was nowhere nearby //TODO: a really distant explosion animation
sleep(50)
world << sound('sound/effects/explosionfar.ogg')
else //station was destroyed
if( mode && !override )
override = mode.name
-54
View File
@@ -1,54 +0,0 @@
//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) - MC done - lighting done
/client/proc/restart_controller(controller in list("Master","Failsafe"))
set category = "Debug"
set name = "Restart Controller"
set desc = "Restart one of the various periodic loop controllers for the game (be careful!)"
if(!holder) return
usr = null
src = null
switch(controller)
if("Master")
new /datum/controller/game_controller()
master_controller.process()
feedback_add_details("admin_verb","RMC")
if("Failsafe")
new /datum/controller/failsafe()
feedback_add_details("admin_verb","RFailsafe")
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
return
/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Jobs","Radio","Configuration", "Cameras"))
set category = "Debug"
set name = "Debug Controller"
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
if(!holder) return
switch(controller)
if("Master")
debug_variables(master_controller)
if("Failsafe")
debug_variables(Failsafe)
if("Ticker")
debug_variables(ticker)
if("Jobs")
debug_variables(SSjob)
if("Radio")
debug_variables(radio_controller)
if("Configuration")
debug_variables(config)
if("Cameras")
debug_variables(cameranet)
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
return
+4
View File
@@ -36,6 +36,10 @@ var/global/max_secret_rooms = 6
//////////////
/proc/make_mining_asteroid_secrets()
for(1 to max_secret_rooms)
make_mining_asteroid_secret()
/proc/make_mining_asteroid_secret()
var/valid = 0
var/turf/T = null
+1 -1
View File
@@ -1,7 +1,7 @@
/*
HOW IT WORKS
The radio_controller is a global object maintaining all radio transmissions, think about it as about "ether".
The SSradio is a global object maintaining all radio transmissions, think about it as about "ether".
Note that walkie-talkie, intercoms and headsets handle transmission using nonstandard way.
procs:
+10 -10
View File
@@ -73,10 +73,10 @@
/obj/machinery/door/airlock/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
if(new_frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK)
radio_connection = SSradio.add_object(src, frequency, RADIO_AIRLOCK)
/obj/machinery/door/airlock/initialize()
@@ -89,12 +89,12 @@
/obj/machinery/door/airlock/New()
..()
if(radio_controller)
if(SSradio)
set_frequency(frequency)
/obj/machinery/door/airlock/Destroy()
if(frequency && radio_controller)
radio_controller.remove_object(src,frequency)
if(frequency && SSradio)
SSradio.remove_object(src,frequency)
return ..()
/obj/machinery/airlock_sensor
@@ -152,9 +152,9 @@
update_icon()
/obj/machinery/airlock_sensor/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency, RADIO_AIRLOCK)
radio_connection = SSradio.add_object(src, frequency, RADIO_AIRLOCK)
/obj/machinery/airlock_sensor/initialize()
set_frequency(frequency)
@@ -162,10 +162,10 @@
/obj/machinery/airlock_sensor/New()
..()
if(radio_controller)
if(SSradio)
set_frequency(frequency)
/obj/machinery/airlock_sensor/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
return ..()
+5 -5
View File
@@ -146,8 +146,8 @@
src.initialize()
/obj/machinery/alarm/Destroy()
if(radio_controller)
radio_controller.remove_object(src, frequency)
if(SSradio)
SSradio.remove_object(src, frequency)
qdel(wires)
wires = null
return ..()
@@ -227,9 +227,9 @@
send_signal(id_tag, list("status") )
/obj/machinery/alarm/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency, RADIO_TO_AIRALARM)
radio_connection = SSradio.add_object(src, frequency, RADIO_TO_AIRALARM)
/obj/machinery/alarm/proc/send_signal(target, list/command)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise
if(!radio_connection)
@@ -652,7 +652,7 @@
/obj/machinery/alarm/proc/post_alert(alert_level)
var/datum/radio_frequency/frequency = radio_controller.return_frequency(alarm_frequency)
var/datum/radio_frequency/frequency = SSradio.return_frequency(alarm_frequency)
if(!frequency) return
+12 -12
View File
@@ -64,9 +64,9 @@
/obj/machinery/air_sensor/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/air_sensor/initialize()
set_frequency(frequency)
@@ -74,13 +74,13 @@
/obj/machinery/air_sensor/New()
..()
SSair.atmos_machinery += src
if(radio_controller)
if(SSradio)
set_frequency(frequency)
/obj/machinery/air_sensor/Destroy()
SSair.atmos_machinery -= src
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
return ..()
/////////////////////////////////////////////////////////////
@@ -102,7 +102,7 @@
/obj/machinery/computer/general_air_control/New()
..()
if(radio_controller)
if(SSradio)
set_frequency(frequency)
/obj/machinery/computer/general_air_control/attack_hand(mob/user)
@@ -178,14 +178,14 @@
return output
/obj/machinery/computer/general_air_control/Destroy()
if(radio_controller)
radio_controller.remove_object(src, frequency)
if(SSradio)
SSradio.remove_object(src, frequency)
return ..()
/obj/machinery/computer/general_air_control/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/computer/general_air_control/initialize()
set_frequency(frequency)
@@ -222,8 +222,8 @@
/obj/machinery/computer/general_air_control/large_tank_control/proc/reconnect(mob/user) //This hacky madness is the evidence of the fact that a lot of machines were never meant to be constructable, im so sorry you had to see this
var/list/IO = list()
var/datum/radio_frequency/air_freq = radio_controller.return_frequency(1443)
var/datum/radio_frequency/gas_freq = radio_controller.return_frequency(1441)
var/datum/radio_frequency/air_freq = SSradio.return_frequency(1443)
var/datum/radio_frequency/gas_freq = SSradio.return_frequency(1441)
var/list/devices = air_freq.devices["_default"]
devices |= gas_freq.devices["_default"]
for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in devices)
+1 -1
View File
@@ -59,7 +59,7 @@
icon_state = "meter4"
if(frequency)
var/datum/radio_frequency/radio_connection = radio_controller.return_frequency(frequency)
var/datum/radio_frequency/radio_connection = SSradio.return_frequency(frequency)
if(!radio_connection) return
+4 -4
View File
@@ -18,8 +18,8 @@
set_frequency(receive_frequency)
/obj/machinery/computer/atmos_alert/Destroy()
if(radio_controller)
radio_controller.remove_object(src, receive_frequency)
if(SSradio)
SSradio.remove_object(src, receive_frequency)
return ..()
/obj/machinery/computer/atmos_alert/receive_signal(datum/signal/signal)
@@ -41,9 +41,9 @@
/obj/machinery/computer/atmos_alert/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, receive_frequency)
SSradio.remove_object(src, receive_frequency)
receive_frequency = new_frequency
radio_connection = radio_controller.add_object(src, receive_frequency, RADIO_ATMOSIA)
radio_connection = SSradio.add_object(src, receive_frequency, RADIO_ATMOSIA)
/obj/machinery/computer/atmos_alert/attack_hand(mob/user)
@@ -588,7 +588,7 @@ var/const/CALL_SHUTTLE_REASON_LENGTH = 12
/obj/machinery/computer/communications/proc/post_status(command, data1, data2)
var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
var/datum/radio_frequency/frequency = SSradio.return_frequency(1435)
if(!frequency) return
+1 -174
View File
@@ -26,10 +26,6 @@ var/global/datum/crewmonitor/crewmonitor = new
var/list/jobs
var/list/interfaces
var/list/data
var/const/MAX_ICON_DIMENSION = 1024
var/const/ICON_SIZE = 4
var/initialized = FALSE
var/max_initialized_zlevel = 0
/datum/crewmonitor/New()
. = ..()
@@ -257,176 +253,7 @@ var/global/datum/crewmonitor/crewmonitor = new
/datum/crewmonitor/proc/queueUpdate(z)
addtimer(crewmonitor, "update", 5, TRUE, z)
/datum/crewmonitor/proc/generateMiniMaps()
for(var/z = 1 to world.maxz)
generateMiniMap(z)
for (var/z = 1 to world.maxz)
register_asset("minimap_[z].png", file("[getMinimapFile(z)].png"))
max_initialized_zlevel = world.maxz
world << "<span class='boldannounce'>All minimaps have been generated."
initialized = TRUE
/datum/crewmonitor/proc/sendResources(var/client/client)
send_asset(client, "crewmonitor.js")
send_asset(client, "crewmonitor.css")
for (var/z = 1 to max_initialized_zlevel)
send_asset(client, "minimap_[z].png")
/datum/crewmonitor/proc/getMinimapFile(z)
return "data/minimaps/map_[z]"
// Activate this to debug tile mismatches in the minimap.
// This will store the full information on each tile and compare it the next time you run the minimap.
// It can be used to find out what's changed since the last iteration.
// Only activate this when you need it - this should never be active on a live server!
// #define MINIMAP_DEBUG
/datum/crewmonitor/proc/generateMiniMap(z, x1 = 1, y1 = 1, x2 = world.maxx, y2 = world.maxy)
var/result_path = "[src.getMinimapFile(z)].png"
var/hash_path = "[src.getMinimapFile(z)].md5"
var/list/tiles = block(locate(x1, y1, z), locate(x2, y2, z))
var/hash = ""
var/temp
var/obj/obj
#ifdef MINIMAP_DEBUG
var/tiledata_path = "data/minimaps/debug_tiledata_[z].sav"
var/savefile/F = new/savefile(tiledata_path)
#endif
// Note for future developer: If you have tiles on the map with random or dynamic icons this hash check will fail
// every time. You'll have to modify this code to generate a unique hash for your object.
// Don't forget to modify the minimap generation code to use a default icon (or skip generation altogether).
for (var/turf/tile in tiles)
if (istype(tile.loc, /area/asteroid) || istype(tile.loc, /area/mine/unexplored) || istype(tile, /turf/simulated/mineral) || (istype(tile.loc, /area/space) && istype(tile, /turf/simulated/floor/plating/asteroid)))
temp = "/area/asteroid"
else if (istype(tile.loc, /area/mine) && istype(tile, /turf/simulated/floor/plating/asteroid))
temp = "/area/mine/explored"
else if (tile.loc.type == /area/start || (tile.type == /turf/space && !(locate(/obj/structure/lattice) in tile)) || istype(tile, /turf/space/transit))
temp = "/turf/space"
if (locate(/obj/structure/lattice/catwalk) in tile)
else
else if (tile.type == /turf/space)
if (locate(/obj/structure/lattice/catwalk) in tile)
temp = "/obj/structure/lattice/catwalk"
else
temp = "/obj/structure/lattice"
else if (tile.type == /turf/simulated/floor/plating/abductor)
temp = "/turf/simulated/floor/plating/abductor"
else if (tile.type == /turf/simulated/floor/plating && (locate(/obj/structure/window/shuttle) in tile))
temp = "/obj/structure/window/shuttle"
else
temp = "[tile.icon][tile.icon_state][tile.dir]"
obj = locate(/obj/structure/transit_tube) in tile
if (obj) temp = "[temp]/obj/structure/transit_tube[obj.icon_state][obj.dir]"
#ifdef MINIMAP_DEBUG
if (F["/[tile.y]/[tile.x]"] && F["/[tile.y]/[tile.x]"] != temp)
CRASH("Mismatch: [tile.type] at [tile.x],[tile.y],[tile.z] ([tile.icon], [tile.icon_state], [tile.dir])")
else
F["/[tile.y]/[tile.x]"] << temp
#endif
hash = md5("[hash][temp]")
if (fexists(result_path))
if (!fexists(hash_path) || trim(file2text(hash_path)) != hash)
fdel(result_path)
fdel(hash_path)
if (!fexists(result_path))
ASSERT(x1 > 0)
ASSERT(y1 > 0)
ASSERT(x2 <= world.maxx)
ASSERT(y2 <= world.maxy)
var/icon/map_icon = new/icon('html/mapbase1024.png')
// map_icon is fine and contains only 1 direction at this point.
ASSERT(map_icon.Width() == MAX_ICON_DIMENSION && map_icon.Height() == MAX_ICON_DIMENSION)
var/i = 0
var/icon/turf_icon
var/icon/obj_icon
var/old_icon
var/old_icon_state
var/old_dir
var/new_icon
var/new_icon_state
var/new_dir
for (var/turf/tile in tiles)
if (tile.loc.type != /area/start && (tile.type != /turf/space || (locate(/obj/structure/lattice) in tile) || (locate(/obj/structure/transit_tube) in tile)) && !istype(tile, /turf/space/transit))
if (istype(tile.loc, /area/asteroid) || istype(tile.loc, /area/mine/unexplored) || istype(tile, /turf/simulated/mineral) || (istype(tile.loc, /area/space) && istype(tile, /turf/simulated/floor/plating/asteroid)))
new_icon = 'icons/turf/mining.dmi'
new_icon_state = "rock"
new_dir = 2
else if (istype(tile.loc, /area/mine) && istype(tile, /turf/simulated/floor/plating/asteroid))
new_icon = 'icons/turf/floors.dmi'
new_icon_state = "asteroid"
new_dir = 2
else if (tile.type == /turf/simulated/floor/plating/abductor)
new_icon = 'icons/turf/floors.dmi'
new_icon_state = "alienpod1"
new_dir = 2
else if (tile.type == /turf/space)
obj = locate(/obj/structure/lattice) in tile
if (!obj) obj = locate(/obj/structure/transit_tube) in tile
ASSERT(obj != null)
if (obj)
new_icon = obj.icon
new_dir = obj.dir
new_icon_state = obj.icon_state
else if (tile.type == /turf/simulated/floor/plating && (locate(/obj/structure/window/shuttle) in tile))
new_icon = 'icons/obj/structures.dmi'
new_dir = 2
new_icon_state = "swindow"
else
new_icon = tile.icon
new_icon_state = tile.icon_state
new_dir = tile.dir
if (new_icon != old_icon || new_icon_state != old_icon_state || new_dir != old_dir)
old_icon = new_icon
old_icon_state = new_icon_state
old_dir = new_dir
turf_icon = new/icon(new_icon, new_icon_state, new_dir, 1, 0)
turf_icon.Scale(ICON_SIZE, ICON_SIZE)
if (tile.type != /turf/space || (locate(/obj/structure/lattice) in tile))
obj = locate(/obj/structure/transit_tube) in tile
if (obj)
obj_icon = new/icon(obj.icon, obj.icon_state, obj.dir, 1, 0)
obj_icon.Scale(ICON_SIZE, ICON_SIZE)
turf_icon.Blend(obj_icon, ICON_OVERLAY)
map_icon.Blend(turf_icon, ICON_OVERLAY, ((tile.x - 1) * ICON_SIZE), ((tile.y - 1) * ICON_SIZE))
if ((++i) % 512 == 0) sleep(1) // deliberate delay to avoid lag spikes
else
sleep(-1) // avoid sleeping if possible: prioritize pending procs
// BYOND BUG: map_icon now contains 4 directions? Create a new icon with only a single state.
var/icon/result_icon = new/icon()
result_icon.Insert(map_icon, "", SOUTH, 1, 0)
fcopy(result_icon, result_path)
text2file(hash, hash_path)
#ifdef MINIMAP_DEBUG
#undef MINIMAP_DEBUG
#endif
SSminimap.sendMinimaps(client)
+4 -4
View File
@@ -16,15 +16,15 @@
air_connection = new
/obj/machinery/door/airlock/alarmlock/Destroy()
if(radio_controller)
radio_controller.remove_object(src,air_frequency)
if(SSradio)
SSradio.remove_object(src,air_frequency)
air_connection = null
return ..()
/obj/machinery/door/airlock/alarmlock/initialize()
..()
radio_controller.remove_object(src, air_frequency)
air_connection = radio_controller.add_object(src, air_frequency, RADIO_TO_AIRALARM)
SSradio.remove_object(src, air_frequency)
air_connection = SSradio.add_object(src, air_frequency, RADIO_TO_AIRALARM)
open()
/obj/machinery/door/airlock/alarmlock/receive_signal(datum/signal/signal)
@@ -75,8 +75,8 @@
var/datum/radio_frequency/radio_connection
/obj/machinery/embedded_controller/radio/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
return ..()
/obj/machinery/embedded_controller/radio/initialize()
@@ -90,6 +90,6 @@
signal = null
/obj/machinery/embedded_controller/radio/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency)
radio_connection = SSradio.add_object(src, frequency)
+8 -8
View File
@@ -36,15 +36,15 @@
center = T
spawn(10) // must wait for map loading to finish
if(radio_controller)
radio_controller.add_object(src, freq, RADIO_MAGNETS)
if(SSradio)
SSradio.add_object(src, freq, RADIO_MAGNETS)
spawn()
magnetic_process()
/obj/machinery/magnetic_module/Destroy()
if(radio_controller)
radio_controller.remove_object(src, freq)
if(SSradio)
SSradio.remove_object(src, freq)
. = ..()
center = null
@@ -234,16 +234,16 @@
spawn(45) // must wait for map loading to finish
if(radio_controller)
radio_connection = radio_controller.add_object(src, frequency, RADIO_MAGNETS)
if(SSradio)
radio_connection = SSradio.add_object(src, frequency, RADIO_MAGNETS)
if(path) // check for default path
filter_path() // renders rpath
/obj/machinery/magnetic_controller/Destroy()
if(radio_controller)
radio_controller.remove_object(src, frequency)
if(SSradio)
SSradio.remove_object(src, frequency)
. = ..()
magnets = null
rpath = null
+4 -4
View File
@@ -45,12 +45,12 @@
/obj/machinery/status_display/New()
..()
spawn(5) // must wait for map loading to finish
if(radio_controller)
radio_controller.add_object(src, frequency)
if(SSradio)
SSradio.add_object(src, frequency)
/obj/machinery/status_display/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
return ..()
// timed process
@@ -179,7 +179,7 @@
var/mob/living/carbon/human/H = new
M = H
var/datum/radio_frequency/connection = radio_controller.return_frequency(frequency)
var/datum/radio_frequency/connection = SSradio.return_frequency(frequency)
var/display_freq = connection.frequency
@@ -209,7 +209,7 @@
// --- Broadcast to syndicate radio! ---
else if(data == 3)
var/datum/radio_frequency/syndicateconnection = radio_controller.return_frequency(SYND_FREQ)
var/datum/radio_frequency/syndicateconnection = SSradio.return_frequency(SYND_FREQ)
for (var/obj/item/device/radio/R in syndicateconnection.devices["[RADIO_CHAT]"])
var/turf/position = get_turf(R)
+1 -1
View File
@@ -251,7 +251,7 @@
/obj/item/weapon/cartridge/proc/post_status(command, data1, data2)
var/datum/radio_frequency/frequency = radio_controller.return_frequency(1435)
var/datum/radio_frequency/frequency = SSradio.return_frequency(1435)
if(!frequency) return
+5 -5
View File
@@ -26,12 +26,12 @@
/obj/item/radio/integrated/signal/New()
..()
if(radio_controller)
if(SSradio)
initialize()
/obj/item/radio/integrated/signal/Destroy()
if(radio_controller)
radio_controller.remove_object(src, frequency)
if(SSradio)
SSradio.remove_object(src, frequency)
return ..()
/obj/item/radio/integrated/signal/initialize()
@@ -41,9 +41,9 @@
set_frequency(frequency)
/obj/item/radio/integrated/signal/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency)
radio_connection = SSradio.add_object(src, frequency)
/obj/item/radio/integrated/signal/proc/send_signal(message="ACTIVATE")
@@ -18,12 +18,12 @@
return (FIRELOSS)
/obj/item/device/electropack/initialize()
if(radio_controller)
radio_controller.add_object(src, frequency, RADIO_CHAT)
if(SSradio)
SSradio.add_object(src, frequency, RADIO_CHAT)
/obj/item/device/electropack/Destroy()
if(radio_controller)
radio_controller.remove_object(src, frequency)
if(SSradio)
SSradio.remove_object(src, frequency)
return ..()
/obj/item/device/electropack/attack_hand(mob/user)
@@ -65,9 +65,9 @@
if(((istype(usr, /mob/living/carbon/human) && ((!( ticker ) || (ticker && ticker.mode != "monkey")) && usr.contents.Find(src))) || (usr.contents.Find(master) || (in_range(src, usr) && istype(loc, /turf)))))
usr.set_machine(src)
if(href_list["freq"])
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = sanitize_frequency(frequency + text2num(href_list["freq"]))
radio_controller.add_object(src, frequency, RADIO_CHAT)
SSradio.add_object(src, frequency, RADIO_CHAT)
else
if(href_list["code"])
code += text2num(href_list["code"])
@@ -222,7 +222,7 @@
for(var/ch_name in channels)
radio_controller.remove_object(src, radiochannels[ch_name])
SSradio.remove_object(src, radiochannels[ch_name])
secure_radio_connections[ch_name] = null
@@ -50,7 +50,7 @@
wires.CutWireIndex(WIRE_TRANSMIT)
secure_radio_connections = new
..()
if(radio_controller)
if(SSradio)
initialize()
@@ -248,7 +248,7 @@
be prepared to disregard any comments in all of tcomms code. i tried my best to keep them somewhat up-to-date, but eh
*/
//get the frequency you buttface. radios no longer use the radio_controller. confusing for future generations, convenient for me.
//get the frequency you buttface. radios no longer use the SSradio. confusing for future generations, convenient for me.
var/freq
if(channel && channels && channels.len > 0)
if (channel == "department")
@@ -587,7 +587,7 @@
for(var/ch_name in channels)
radio_controller.remove_object(src, radiochannels[ch_name])
SSradio.remove_object(src, radiochannels[ch_name])
secure_radio_connections[ch_name] = null
@@ -104,4 +104,4 @@
/obj/item/weapon/storage/toolbox/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] robusts \himself with the toolbox! It looks like \he's trying to commit suicide..</span>")
return (BRUTELOSS)
return (BRUTELOSS)
-2
View File
@@ -118,7 +118,6 @@ var/list/admin_verbs_debug = list(
/client/proc/cmd_admin_list_open_jobs,
/client/proc/Debug2,
/client/proc/cmd_debug_make_powernets,
/client/proc/debug_controller,
/client/proc/cmd_debug_mob_lists,
/client/proc/cmd_admin_delete,
/client/proc/cmd_debug_del_all,
@@ -203,7 +202,6 @@ var/list/admin_verbs_hideable = list(
/client/proc/Debug2,
/client/proc/reload_admins,
/client/proc/cmd_debug_make_powernets,
/client/proc/debug_controller,
/client/proc/startSinglo,
/client/proc/cmd_debug_mob_lists,
/client/proc/cmd_debug_del_all,
+2 -2
View File
@@ -64,9 +64,9 @@
"_default" = "NO_FILTER"
)
var/output = "<b>Radio Report</b><hr>"
for (var/fq in radio_controller.frequencies)
for (var/fq in SSradio.frequencies)
output += "<b>Freq: [fq]</b><br>"
var/list/datum/radio_frequency/fqs = radio_controller.frequencies[fq]
var/list/datum/radio_frequency/fqs = SSradio.frequencies[fq]
if (!fqs)
output += "&nbsp;&nbsp;<b>ERROR</b><br>"
continue
+1 -1
View File
@@ -58,7 +58,7 @@ var/intercom_range_display_status = 0
set category = "Mapping"
set name = "Camera Report"
if(!master_controller)
if(!Master)
alert(usr,"Master_controller not found.","Sec Camera Report")
return 0
+6 -6
View File
@@ -20,8 +20,8 @@
return
/obj/item/device/assembly/signaler/Destroy()
if(radio_controller)
radio_controller.remove_object(src,frequency)
if(SSradio)
SSradio.remove_object(src,frequency)
return ..()
/obj/item/device/assembly/signaler/activate()
@@ -135,13 +135,13 @@ Code:
/obj/item/device/assembly/signaler/proc/set_frequency(new_frequency)
if(!radio_controller)
if(!SSradio)
sleep(20)
if(!radio_controller)
if(!SSradio)
return
radio_controller.remove_object(src, frequency)
SSradio.remove_object(src, frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency, RADIO_CHAT)
radio_connection = SSradio.add_object(src, frequency, RADIO_CHAT)
return
// Embedded signaller used in grenade construction.
+5 -19
View File
@@ -17,9 +17,6 @@ You can set verify to TRUE if you want send() to sleep until the client has the
//When sending mutiple assets, how many before we give the client a quaint little sending resources message
#define ASSET_CACHE_TELL_CLIENT_AMOUNT 8
//List of ALL assets for the above, format is list(filename = asset).
/var/global/list/asset_cache = list()
/client
var/list/cache = list() // List of all assets sent to this client by the asset cache.
var/list/completed_asset_jobs = list() // List of all completed jobs, awaiting acknowledgement.
@@ -44,7 +41,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the
if(client.cache.Find(asset_name) || client.sending.Find(asset_name))
return 0
client << browse_rsc(asset_cache[asset_name], asset_name)
client << browse_rsc(SSasset.cache[asset_name], asset_name)
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
if (client)
client.cache += asset_name
@@ -94,8 +91,8 @@ You can set verify to TRUE if you want send() to sleep until the client has the
if (unreceived.len >= ASSET_CACHE_TELL_CLIENT_AMOUNT)
client << "Sending Resources..."
for(var/asset in unreceived)
if (asset in asset_cache)
client << browse_rsc(asset_cache[asset], asset)
if (asset in SSasset.cache)
client << browse_rsc(SSasset.cache[asset], asset)
if(!verify || !winexists(client, "asset_cache_browser")) // Can't access the asset cache browser, rip.
if (client)
@@ -127,7 +124,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
//The proc calls procs that sleep for long times.
proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
/proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
for(var/file in files)
if (!client)
break
@@ -139,18 +136,7 @@ proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
//if it's an icon or something be careful, you'll have to copy it before further use.
/proc/register_asset(var/asset_name, var/asset)
asset_cache[asset_name] = asset
//From here on out it's populating the asset cache.
/proc/populate_asset_cache()
for(var/type in typesof(/datum/asset) - list(/datum/asset, /datum/asset/simple))
var/datum/asset/A = new type()
A.register()
for(var/client/C in clients)
//doing this to a client too soon after they've connected can cause issues, also the proc we call sleeps
spawn(10)
getFilesSlow(C, asset_cache, FALSE)
SSasset.cache[asset_name] = asset
//These datums are used to populate the asset cache, the proc "register()" does this.
+2 -2
View File
@@ -179,7 +179,7 @@ var/next_external_rsc = 0
else if (isnum(player_age) && player_age < config.notify_new_player_age)
message_admins("New user: [key_name_admin(src)] just connected with an age of [player_age] day[(player_age==1?"":"s")]")
sync_client_with_db()
send_resources()
@@ -328,4 +328,4 @@ var/next_external_rsc = 0
)
spawn (10)
//Precache the client with all other assets slowly, so as to not block other browse() calls
getFilesSlow(src, asset_cache, register_asset = FALSE)
getFilesSlow(src, SSasset.cache, register_asset = FALSE)
+1 -1
View File
@@ -236,4 +236,4 @@ var/list/ghost_forms = list("ghost","ghostking","ghostian2","skeleghost","ghost_
set category = "Preferences"
set desc = "Allows you to access the Setup Character screen. Changes to your character won't take effect until next round, but other changes will."
prefs.current_tab = 1
prefs.ShowChoices(usr)
prefs.ShowChoices(usr)
+1 -1
View File
@@ -68,4 +68,4 @@
message_admins("Situation has been resolved")
return 0
message_admins("Unfortunately, no candidates were available for becoming an alien. Shutting down.")
return kill()
return kill()
+1 -1
View File
@@ -182,7 +182,7 @@
if(TRAITS & TRAIT_THIEVING)
slyness = 75
SSbp.insertBot(src)
SSnpc.insertBot(src)
/mob/living/carbon/human/interactive/attack_hand(mob/living/carbon/human/M)
@@ -858,4 +858,4 @@
return
if(!isturf(M.loc) && M.loc != src)
return
return 1
return 1
@@ -1,8 +1,8 @@
/mob/living/carbon/human/whisper(message as text)
if(!IsVocal())
return
if(!message)
return
if(!message)
return
if(say_disabled) //This is here to try to identify lag problems
usr << "<span class='danger'>Speech is currently admin-disabled.</span>"
@@ -7,12 +7,17 @@ var/const/CHUNK_SIZE = 16 // Only chunk sizes that are to the power of 2. E.g: 2
var/datum/cameranet/cameranet = new()
/datum/cameranet
var/name = "Camera Net" // Name to show for VV and stat()
// The cameras on the map, no matter if they work or not. Updated in obj/machinery/camera.dm by New() and Del().
var/list/cameras = list()
// The chunks of the map, mapping the areas that the cameras can see.
var/list/chunks = list()
var/ready = 0
// The object used for the clickable stat() button.
var/obj/effect/statclick/statclick
// Checks if a chunk has been Generated in x, y, z.
/datum/cameranet/proc/chunkGenerated(x, y, z)
x &= ~(CHUNK_SIZE - 1)
@@ -142,6 +147,11 @@ var/datum/cameranet/cameranet = new()
return 1
return 0
/datum/cameranet/proc/stat_entry()
if(!statclick)
statclick = new/obj/effect/statclick/debug("Initializing...", src)
stat(name, statclick.update("Cameras: [cameranet.cameras.len] | Chunks: [cameranet.chunks.len]"))
// Debug verb for VVing the chunk that the turf is in.
/*
@@ -151,4 +161,4 @@ var/datum/cameranet/cameranet = new()
if(cameranet.chunkGenerated(x, y, z))
var/datum/camerachunk/chunk = cameranet.getCameraChunk(x, y, z)
usr.client.debug_variables(chunk)
*/
*/
+18 -11
View File
@@ -651,18 +651,25 @@ var/list/slot_equipment_priority = list( \
if(client && client.holder)
if(statpanel("MC"))
stat("Location:","([x], [y], [z])")
stat("CPU:","[world.cpu]")
stat("Instances:","[world.contents.len]")
if(master_controller)
stat("MasterController:","[round(master_controller.cost,0.001)]ds (Interval:[master_controller.processing_interval] | Iteration:[master_controller.iteration])")
stat("Subsystem cost per second:","[round(master_controller.SSCostPerSecond,0.001)]ds")
for(var/datum/subsystem/SS in master_controller.subsystems)
if(SS.can_fire)
SS.stat_entry()
stat("Location:", "([x], [y], [z])")
stat("CPU:", "[world.cpu]")
stat("Instances:", "[world.contents.len]")
config.stat_entry()
stat(null)
if(Master)
Master.stat_entry()
else
stat("MasterController:","ERROR")
stat("Master Controller:", "ERROR")
if(Failsafe)
Failsafe.stat_entry()
else
stat("Failsafe Controller:", "ERROR")
if(Master)
stat("Subsystems:", "[round(Master.subsystem_cost, 0.001)]ds")
stat(null)
for(var/datum/subsystem/SS in Master.subsystems)
SS.stat_entry()
cameranet.stat_entry()
if(listed_turf && client)
if(!TurfAdjacent(listed_turf))
+1 -1
View File
@@ -155,7 +155,7 @@ eventually results in broadcast_message() being called.
Broadcast_message() does NOT call say() on radios, but rather calls Hear() on everyone in range of a radio.
This is because the system does not like repeating says.
Furthermore, I changed radios to not be in the radio_controller. Instead, they are in a global list called all_radios.
Furthermore, I changed radios to not be in the SSradio. Instead, they are in a global list called all_radios.
This is an associative list, and the numbers as strings are the keys. The values are lists of radios that can hear said frequency.
To add a radio, simply use add_radio(radio, frequency). To remove a radio, use remove_radio(radio, frequency).
+1 -1
View File
@@ -631,7 +631,7 @@
/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, force_open = 0)
ui = SSnano.try_update_ui(user, src, ui_key, ui, force_open = force_open)
if (!ui)
ui = new(user, src, ui_key, "apc.tmpl", name, 515, 550)
ui = new(user, src, ui_key, "apc.tmpl", name, 550, 550)
ui.open()
/obj/machinery/power/apc/get_ui_data(mob/user)
+1 -2
View File
@@ -54,9 +54,8 @@ var/global/list/map_transition_config = MAP_TRANSITION_CONFIG
data_core = new /datum/datacore()
spawn(-1)
master_controller.setup()
Master.Setup()
process_teleport_locs() //Sets up the wizard teleport locations
SortAreas() //Build the list of all existing areas and sort it alphabetically
+6 -3
View File
@@ -139,18 +139,21 @@
#include "code\ATMOSPHERICS\pipes\heat_exchange\junction.dm"
#include "code\ATMOSPHERICS\pipes\heat_exchange\manifold.dm"
#include "code\ATMOSPHERICS\pipes\heat_exchange\simple.dm"
#include "code\controllers\admin.dm"
#include "code\controllers\configuration.dm"
#include "code\controllers\controller.dm"
#include "code\controllers\failsafe.dm"
#include "code\controllers\master_controller.dm"
#include "code\controllers\subsystems.dm"
#include "code\controllers\verbs.dm"
#include "code\controllers\master.dm"
#include "code\controllers\subsystem.dm"
#include "code\controllers\subsystem\air.dm"
#include "code\controllers\subsystem\assets.dm"
#include "code\controllers\subsystem\diseases.dm"
#include "code\controllers\subsystem\events.dm"
#include "code\controllers\subsystem\garbage.dm"
#include "code\controllers\subsystem\jobs.dm"
#include "code\controllers\subsystem\lighting.dm"
#include "code\controllers\subsystem\machines.dm"
#include "code\controllers\subsystem\minimap.dm"
#include "code\controllers\subsystem\mobs.dm"
#include "code\controllers\subsystem\nano.dm"
#include "code\controllers\subsystem\npcpool.dm"