mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-10 18:22:39 +00:00
Power channels start on when objects initialize, then are turned off and area machines notified in area initialization if an apc is not found.
374 lines
11 KiB
Plaintext
374 lines
11 KiB
Plaintext
//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/controller_iteration = 0
|
|
var/global/last_tick_timeofday = world.timeofday
|
|
var/global/last_tick_duration = 0
|
|
|
|
var/global/air_processing_killed = 0
|
|
var/global/pipe_processing_killed = 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/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/nano_cost = 0
|
|
var/events_cost = 0
|
|
var/alarms_cost = 0
|
|
var/ticker_cost = 0
|
|
var/total_cost = 0
|
|
|
|
var/last_thing_processed
|
|
var/mob/list/expensive_mobs = list()
|
|
|
|
var/list/shuttle_list // For debugging and VV
|
|
var/datum/random_map/ore/asteroid_ore_map // For debugging and VV.
|
|
|
|
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)
|
|
log_debug("Rebuilding Master Controller")
|
|
if(istype(master_controller))
|
|
Recover()
|
|
del(master_controller)
|
|
master_controller = src
|
|
|
|
if(!job_master)
|
|
job_master = new /datum/controller/occupations()
|
|
job_master.SetupOccupations()
|
|
job_master.LoadJobs("config/jobs.txt")
|
|
world << "\red \b Job setup complete"
|
|
|
|
if(!syndicate_code_phrase) syndicate_code_phrase = generate_code_phrase()
|
|
if(!syndicate_code_response) syndicate_code_response = generate_code_phrase()
|
|
if(!emergency_shuttle) emergency_shuttle = new /datum/emergency_shuttle_controller()
|
|
if(!shuttle_controller) shuttle_controller = new /datum/shuttle_controller()
|
|
|
|
datum/controller/game_controller/proc/setup()
|
|
world.tick_lag = config.Ticklag
|
|
|
|
//Create the asteroid Z-level.
|
|
new /datum/random_map(null,13,32,5,217,223)
|
|
|
|
spawn(20)
|
|
createRandomZlevel()
|
|
|
|
if(!air_master)
|
|
air_master = new /datum/controller/air_system()
|
|
air_master.Setup()
|
|
|
|
if(!ticker)
|
|
ticker = new /datum/controller/gameticker()
|
|
|
|
setup_objects()
|
|
setupgenetics()
|
|
setupfactions()
|
|
setup_economy()
|
|
SetupXenoarch()
|
|
|
|
transfer_controller = new
|
|
|
|
spawn(0)
|
|
if(ticker)
|
|
ticker.pregame()
|
|
|
|
lighting_controller.initializeLighting()
|
|
|
|
|
|
datum/controller/game_controller/proc/setup_objects()
|
|
world << "<span class='danger>Initializing objects</span>"
|
|
sleep(-1)
|
|
for(var/atom/movable/object in world)
|
|
object.initialize()
|
|
|
|
world << "<span class='danger>Initializing areas</span>"
|
|
sleep(-1)
|
|
for(var/area/area in all_areas)
|
|
area.initialize()
|
|
|
|
world << "<span class='danger>Initializing pipe networks</span>"
|
|
sleep(-1)
|
|
for(var/obj/machinery/atmospherics/machine in machines)
|
|
machine.build_network()
|
|
|
|
world << "<span class='danger>Initializing atmos machinery.</span>"
|
|
sleep(-1)
|
|
for(var/obj/machinery/atmospherics/unary/U in machines)
|
|
if(istype(U, /obj/machinery/atmospherics/unary/vent_pump))
|
|
var/obj/machinery/atmospherics/unary/vent_pump/T = U
|
|
T.broadcast_status()
|
|
else if(istype(U, /obj/machinery/atmospherics/unary/vent_scrubber))
|
|
var/obj/machinery/atmospherics/unary/vent_scrubber/T = U
|
|
T.broadcast_status()
|
|
|
|
// Create the mining ore distribution map.
|
|
// These values determine the specific area that the map is applied to.
|
|
// If you do not use the official Baycode asteroid map, you will need to change them.
|
|
asteroid_ore_map = new /datum/random_map/ore(null,13,32,5,217,223)
|
|
|
|
//Shitty hack to fix mining turf overlays, for some reason New() is not being called.
|
|
//for(var/turf/simulated/floor/plating/airless/asteroid/T in world)
|
|
// T.updateMineralOverlays()
|
|
// T.name = "asteroid"
|
|
|
|
//Set up spawn points.
|
|
populate_spawn_points()
|
|
|
|
// Sort the machinery list so it doesn't cause a lagspike at roundstart
|
|
process_machines_sort()
|
|
|
|
world << "\red \b Initializations complete."
|
|
sleep(-1)
|
|
|
|
|
|
datum/controller/game_controller/proc/process()
|
|
processing = 1
|
|
spawn(0)
|
|
set background = 1
|
|
while(1) //far more efficient than recursively calling ourself
|
|
if(!Failsafe) new /datum/controller/failsafe()
|
|
|
|
var/currenttime = world.timeofday
|
|
last_tick_duration = (currenttime - last_tick_timeofday) / 10
|
|
last_tick_timeofday = currenttime
|
|
|
|
if(processing)
|
|
var/timer
|
|
var/start_time = world.timeofday
|
|
controller_iteration++
|
|
|
|
vote.process()
|
|
transfer_controller.process()
|
|
shuttle_controller.process()
|
|
process_newscaster()
|
|
|
|
//AIR
|
|
|
|
if(!air_processing_killed)
|
|
timer = world.timeofday
|
|
last_thing_processed = air_master.type
|
|
|
|
if(!air_master.Tick()) //Runtimed.
|
|
air_master.failed_ticks++
|
|
if(air_master.failed_ticks > 5)
|
|
world << "<font color='red'><b>RUNTIMES IN ATMOS TICKER. Killing air simulation!</font></b>"
|
|
world.log << "### ZAS SHUTDOWN"
|
|
message_admins("ZASALERT: unable to run [air_master.tick_progress], shutting down!")
|
|
log_admin("ZASALERT: unable run zone/process() -- [air_master.tick_progress]")
|
|
air_processing_killed = 1
|
|
air_master.failed_ticks = 0
|
|
|
|
air_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//SUN
|
|
timer = world.timeofday
|
|
last_thing_processed = sun.type
|
|
sun.calc_position()
|
|
sun_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//MOBS
|
|
timer = world.timeofday
|
|
process_mobs()
|
|
mobs_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//DISEASES
|
|
timer = world.timeofday
|
|
process_diseases()
|
|
diseases_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//MACHINES
|
|
timer = world.timeofday
|
|
process_machines()
|
|
machines_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//OBJECTS
|
|
timer = world.timeofday
|
|
process_objects()
|
|
objects_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//PIPENETS
|
|
if(!pipe_processing_killed)
|
|
timer = world.timeofday
|
|
process_pipenets()
|
|
networks_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//POWERNETS
|
|
timer = world.timeofday
|
|
process_powernets()
|
|
powernets_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//NANO UIS
|
|
timer = world.timeofday
|
|
process_nano()
|
|
nano_cost = (world.timeofday - timer) / 10
|
|
|
|
sleep(breather_ticks)
|
|
|
|
//EVENTS
|
|
timer = world.timeofday
|
|
process_events()
|
|
events_cost = (world.timeofday - timer) / 10
|
|
|
|
//ALARMS
|
|
timer = world.timeofday
|
|
process_alarms()
|
|
alarms_cost = (world.timeofday - timer) / 10
|
|
|
|
//TICKER
|
|
timer = world.timeofday
|
|
last_thing_processed = ticker.type
|
|
ticker.process()
|
|
ticker_cost = (world.timeofday - timer) / 10
|
|
|
|
//TIMING
|
|
total_cost = air_cost + sun_cost + mobs_cost + diseases_cost + machines_cost + objects_cost + networks_cost + powernets_cost + nano_cost + events_cost + alarms_cost + ticker_cost
|
|
|
|
var/end_time = world.timeofday
|
|
if(end_time < start_time) //why not just use world.time instead?
|
|
start_time -= 864000 //deciseconds in a day
|
|
sleep( round(minimum_ticks - (end_time - start_time),1) )
|
|
else
|
|
sleep(10)
|
|
|
|
datum/controller/game_controller/proc/process_mobs()
|
|
var/i = 1
|
|
expensive_mobs.Cut()
|
|
while(i<=mob_list.len)
|
|
var/mob/M = mob_list[i]
|
|
if(M)
|
|
var/clock = world.timeofday
|
|
last_thing_processed = M.type
|
|
M.Life()
|
|
if((world.timeofday - clock) > 1)
|
|
expensive_mobs += M
|
|
i++
|
|
continue
|
|
mob_list.Cut(i,i+1)
|
|
|
|
datum/controller/game_controller/proc/process_diseases()
|
|
var/i = 1
|
|
while(i<=active_diseases.len)
|
|
var/datum/disease/Disease = active_diseases[i]
|
|
if(Disease)
|
|
last_thing_processed = Disease.type
|
|
Disease.process()
|
|
i++
|
|
continue
|
|
active_diseases.Cut(i,i+1)
|
|
|
|
datum/controller/game_controller/proc/process_machines()
|
|
process_machines_sort()
|
|
process_machines_process()
|
|
|
|
/var/global/machinery_sort_required = 0
|
|
datum/controller/game_controller/proc/process_machines_sort()
|
|
if(machinery_sort_required)
|
|
machinery_sort_required = 0
|
|
machines = dd_sortedObjectList(machines)
|
|
|
|
datum/controller/game_controller/proc/process_machines_process()
|
|
for(var/obj/machinery/Machine in machines)
|
|
last_thing_processed = Machine.type
|
|
if(Machine.process() != PROCESS_KILL)
|
|
if(Machine)
|
|
Machine.power_change()
|
|
if(Machine.use_power)
|
|
Machine.auto_use_power()
|
|
continue
|
|
machines -= Machine
|
|
|
|
|
|
datum/controller/game_controller/proc/process_objects()
|
|
var/i = 1
|
|
while(i<=processing_objects.len)
|
|
var/obj/Object = processing_objects[i]
|
|
if(Object)
|
|
last_thing_processed = Object.type
|
|
Object.process()
|
|
i++
|
|
continue
|
|
processing_objects.Cut(i,i+1)
|
|
|
|
datum/controller/game_controller/proc/process_pipenets()
|
|
last_thing_processed = /datum/pipe_network
|
|
var/i = 1
|
|
while(i<=pipe_networks.len)
|
|
var/datum/pipe_network/Network = pipe_networks[i]
|
|
if(Network)
|
|
Network.process()
|
|
i++
|
|
continue
|
|
pipe_networks.Cut(i,i+1)
|
|
|
|
/datum/controller/game_controller/proc/process_powernets()
|
|
last_thing_processed = /datum/powernet
|
|
for(var/datum/powernet/Powernet in powernets)
|
|
Powernet.reset()
|
|
|
|
// This is necessary to ensure powersinks are always the first devices that drain power from powernet.
|
|
// Otherwise APCs or other stuff go first, resulting in bad things happening.
|
|
for(var/obj/item/device/powersink/S in processing_objects)
|
|
S.drain()
|
|
|
|
datum/controller/game_controller/proc/process_nano()
|
|
last_thing_processed = /datum/nanoui
|
|
var/i = 1
|
|
while(i<=nanomanager.processing_uis.len)
|
|
var/datum/nanoui/ui = nanomanager.processing_uis[i]
|
|
if(ui)
|
|
ui.process()
|
|
i++
|
|
continue
|
|
nanomanager.processing_uis.Cut(i,i+1)
|
|
|
|
datum/controller/game_controller/proc/process_events()
|
|
last_thing_processed = /datum/event_manager
|
|
event_manager.process()
|
|
|
|
datum/controller/game_controller/proc/process_alarms()
|
|
last_thing_processed = /datum/subsystem/alarm
|
|
alarm_manager.fire()
|
|
|
|
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
|
|
msg += "\t [varname] = [varval]\n"
|
|
world.log << msg
|
|
|