mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-09 07:48:55 +00:00
469 lines
14 KiB
Plaintext
469 lines
14 KiB
Plaintext
SUBSYSTEM_DEF(air)
|
|
name = "Atmospherics"
|
|
init_order = INIT_ORDER_AIR
|
|
priority = FIRE_PRIORITY_AIR
|
|
wait = 5
|
|
flags = SS_BACKGROUND
|
|
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
|
|
|
var/cost_turfs = 0
|
|
var/cost_groups = 0
|
|
var/cost_highpressure = 0
|
|
var/cost_hotspots = 0
|
|
var/cost_superconductivity = 0
|
|
var/cost_pipenets = 0
|
|
var/cost_rebuilds = 0
|
|
var/cost_atmos_machinery = 0
|
|
var/cost_equalize = 0
|
|
|
|
var/list/hotspots = list()
|
|
var/list/networks = list()
|
|
var/list/pipenets_needing_rebuilt = list()
|
|
var/list/obj/machinery/atmos_machinery = list()
|
|
var/list/pipe_init_dirs_cache = list()
|
|
|
|
//atmos singletons
|
|
var/list/gas_reactions = list()
|
|
|
|
//Special functions lists
|
|
var/list/turf/active_super_conductivity = list()
|
|
var/list/turf/open/high_pressure_delta = list()
|
|
|
|
|
|
var/list/currentrun = list()
|
|
var/currentpart = SSAIR_REBUILD_PIPENETS
|
|
|
|
var/map_loading = TRUE
|
|
var/list/queued_for_activation
|
|
|
|
var/log_explosive_decompression = TRUE // If things get spammy, admemes can turn this off.
|
|
|
|
var/monstermos_turf_limit = 10
|
|
var/monstermos_hard_turf_limit = 2000
|
|
var/monstermos_enabled = TRUE
|
|
|
|
/datum/controller/subsystem/air/stat_entry(msg)
|
|
msg += "C:{"
|
|
msg += "EQ:[round(cost_equalize,1)]|"
|
|
msg += "AT:[round(cost_turfs,1)]|"
|
|
msg += "EG:[round(cost_groups,1)]|"
|
|
msg += "HP:[round(cost_highpressure,1)]|"
|
|
msg += "HS:[round(cost_hotspots,1)]|"
|
|
msg += "SC:[round(cost_superconductivity,1)]|"
|
|
msg += "PN:[round(cost_pipenets,1)]|"
|
|
msg += "AM:[round(cost_atmos_machinery,1)]"
|
|
msg += "} "
|
|
var/active_turfs_len = get_amt_active_turfs()
|
|
msg += "AT:[active_turfs_len]|"
|
|
msg += "EG:[get_amt_excited_groups()]|"
|
|
msg += "HS:[hotspots.len]|"
|
|
msg += "PN:[networks.len]|"
|
|
msg += "HP:[high_pressure_delta.len]|"
|
|
msg += "AS:[active_super_conductivity.len]|"
|
|
msg += "GA:[get_amt_gas_mixes()]|"
|
|
msg += "MG:[get_max_gas_mixes()]|"
|
|
msg += "AT/MS:[round((cost ? active_turfs_len/cost : 0),0.1)]"
|
|
return ..()
|
|
|
|
/datum/controller/subsystem/air/Initialize(timeofday)
|
|
extools_update_ssair()
|
|
map_loading = FALSE
|
|
setup_allturfs()
|
|
setup_atmos_machinery()
|
|
setup_pipenets()
|
|
gas_reactions = init_gas_reactions()
|
|
extools_update_reactions()
|
|
return ..()
|
|
|
|
/datum/controller/subsystem/air/proc/extools_update_ssair()
|
|
/datum/controller/subsystem/air/proc/extools_update_reactions()
|
|
|
|
/datum/controller/subsystem/air/fire(resumed = 0)
|
|
var/timer = TICK_USAGE_REAL
|
|
|
|
if(currentpart == SSAIR_REBUILD_PIPENETS)
|
|
var/list/pipenet_rebuilds = pipenets_needing_rebuilt
|
|
for(var/thing in pipenet_rebuilds)
|
|
var/obj/machinery/atmospherics/AT = thing
|
|
if(!istype(AT))
|
|
continue
|
|
AT.build_network()
|
|
cost_rebuilds = MC_AVERAGE(cost_rebuilds, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
|
pipenets_needing_rebuilt.Cut()
|
|
if(state != SS_RUNNING)
|
|
return
|
|
resumed = FALSE
|
|
currentpart = SSAIR_PIPENETS
|
|
|
|
if(currentpart == SSAIR_PIPENETS || !resumed)
|
|
process_pipenets(resumed)
|
|
cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
|
if(state != SS_RUNNING)
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_ATMOSMACHINERY
|
|
|
|
if(currentpart == SSAIR_ATMOSMACHINERY)
|
|
timer = TICK_USAGE_REAL
|
|
process_atmos_machinery(resumed)
|
|
cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
|
if(state != SS_RUNNING)
|
|
return
|
|
resumed = 0
|
|
currentpart = monstermos_enabled ? SSAIR_EQUALIZE : SSAIR_ACTIVETURFS
|
|
|
|
if(currentpart == SSAIR_EQUALIZE)
|
|
timer = TICK_USAGE_REAL
|
|
process_turf_equalize(resumed)
|
|
cost_equalize = MC_AVERAGE(cost_equalize, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
|
if(state != SS_RUNNING)
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_ACTIVETURFS
|
|
|
|
if(currentpart == SSAIR_ACTIVETURFS)
|
|
timer = TICK_USAGE_REAL
|
|
process_active_turfs(resumed)
|
|
cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
|
if(state != SS_RUNNING)
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_EXCITEDGROUPS
|
|
|
|
if(currentpart == SSAIR_EXCITEDGROUPS)
|
|
timer = TICK_USAGE_REAL
|
|
process_excited_groups(resumed)
|
|
cost_groups = MC_AVERAGE(cost_groups, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
|
if(state != SS_RUNNING)
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_HIGHPRESSURE
|
|
|
|
if(currentpart == SSAIR_HIGHPRESSURE)
|
|
timer = TICK_USAGE_REAL
|
|
process_high_pressure_delta(resumed)
|
|
cost_highpressure = MC_AVERAGE(cost_highpressure, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
|
if(state != SS_RUNNING)
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_HOTSPOTS
|
|
|
|
if(currentpart == SSAIR_HOTSPOTS)
|
|
timer = TICK_USAGE_REAL
|
|
process_hotspots(resumed)
|
|
cost_hotspots = MC_AVERAGE(cost_hotspots, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
|
if(state != SS_RUNNING)
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_SUPERCONDUCTIVITY
|
|
|
|
if(currentpart == SSAIR_SUPERCONDUCTIVITY)
|
|
timer = TICK_USAGE_REAL
|
|
process_super_conductivity(resumed)
|
|
cost_superconductivity = MC_AVERAGE(cost_superconductivity, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
|
|
if(state != SS_RUNNING)
|
|
return
|
|
resumed = 0
|
|
currentpart = SSAIR_REBUILD_PIPENETS
|
|
|
|
|
|
|
|
/datum/controller/subsystem/air/proc/process_pipenets(resumed = 0)
|
|
if (!resumed)
|
|
src.currentrun = networks.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(currentrun.len)
|
|
var/datum/thing = currentrun[currentrun.len]
|
|
currentrun.len--
|
|
if(thing)
|
|
thing.process()
|
|
else
|
|
networks.Remove(thing)
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
/datum/controller/subsystem/air/proc/add_to_rebuild_queue(atmos_machine)
|
|
if(istype(atmos_machine, /obj/machinery/atmospherics))
|
|
pipenets_needing_rebuilt += atmos_machine
|
|
|
|
/datum/controller/subsystem/air/proc/process_atmos_machinery(resumed = 0)
|
|
var/seconds = wait * 0.1
|
|
if (!resumed)
|
|
src.currentrun = atmos_machinery.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(currentrun.len)
|
|
var/obj/machinery/M = currentrun[currentrun.len]
|
|
currentrun.len--
|
|
if(!M || (M.process_atmos(seconds) == PROCESS_KILL))
|
|
atmos_machinery.Remove(M)
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
|
|
/datum/controller/subsystem/air/proc/process_super_conductivity(resumed = 0)
|
|
if (!resumed)
|
|
src.currentrun = active_super_conductivity.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(currentrun.len)
|
|
var/turf/T = currentrun[currentrun.len]
|
|
currentrun.len--
|
|
T.super_conduct()
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
/datum/controller/subsystem/air/proc/process_hotspots(resumed = 0)
|
|
if (!resumed)
|
|
src.currentrun = hotspots.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(currentrun.len)
|
|
var/obj/effect/hotspot/H = currentrun[currentrun.len]
|
|
currentrun.len--
|
|
if (H)
|
|
H.process()
|
|
else
|
|
hotspots -= H
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
|
|
/datum/controller/subsystem/air/proc/process_high_pressure_delta(resumed = 0)
|
|
while (high_pressure_delta.len)
|
|
var/turf/open/T = high_pressure_delta[high_pressure_delta.len]
|
|
high_pressure_delta.len--
|
|
T.high_pressure_movements()
|
|
T.pressure_difference = 0
|
|
T.pressure_specific_target = null
|
|
if(MC_TICK_CHECK)
|
|
return
|
|
|
|
/datum/controller/subsystem/air/proc/process_turf_equalize(resumed = 0)
|
|
return process_turf_equalize_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag)
|
|
/*
|
|
//cache for sanic speed
|
|
var/fire_count = times_fired
|
|
if (!resumed)
|
|
src.currentrun = active_turfs.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(currentrun.len)
|
|
var/turf/open/T = currentrun[currentrun.len]
|
|
currentrun.len--
|
|
if (T)
|
|
T.equalize_pressure_in_zone(fire_count)
|
|
//equalize_pressure_in_zone(T, fire_count)
|
|
if (MC_TICK_CHECK)
|
|
return
|
|
*/
|
|
|
|
/datum/controller/subsystem/air/proc/process_active_turfs(resumed = 0)
|
|
return process_active_turfs_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag)
|
|
/*
|
|
//cache for sanic speed
|
|
var/fire_count = times_fired
|
|
if (!resumed)
|
|
src.currentrun = active_turfs.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(currentrun.len)
|
|
var/turf/open/T = currentrun[currentrun.len]
|
|
currentrun.len--
|
|
if (T)
|
|
T.process_cell(fire_count)
|
|
if (MC_TICK_CHECK)
|
|
return
|
|
*/
|
|
|
|
/datum/controller/subsystem/air/proc/process_excited_groups(resumed = 0)
|
|
return process_excited_groups_extools(resumed, (Master.current_ticklimit - TICK_USAGE) * 0.01 * world.tick_lag)
|
|
/*
|
|
if (!resumed)
|
|
src.currentrun = excited_groups.Copy()
|
|
//cache for sanic speed (lists are references anyways)
|
|
var/list/currentrun = src.currentrun
|
|
while(currentrun.len)
|
|
var/datum/excited_group/EG = currentrun[currentrun.len]
|
|
currentrun.len--
|
|
EG.breakdown_cooldown++
|
|
EG.dismantle_cooldown++
|
|
if(EG.breakdown_cooldown >= EXCITED_GROUP_BREAKDOWN_CYCLES)
|
|
EG.self_breakdown()
|
|
else if(EG.dismantle_cooldown >= EXCITED_GROUP_DISMANTLE_CYCLES)
|
|
EG.dismantle()
|
|
if (MC_TICK_CHECK)
|
|
return
|
|
*/
|
|
|
|
/datum/controller/subsystem/air/proc/process_active_turfs_extools()
|
|
/datum/controller/subsystem/air/proc/process_turf_equalize_extools()
|
|
/datum/controller/subsystem/air/proc/process_excited_groups_extools()
|
|
/datum/controller/subsystem/air/proc/get_amt_excited_groups()
|
|
/datum/controller/subsystem/air/proc/get_amt_active_turfs()
|
|
/datum/controller/subsystem/air/proc/get_amt_gas_mixes()
|
|
/datum/controller/subsystem/air/proc/get_max_gas_mixes()
|
|
/datum/controller/subsystem/air/proc/add_to_active_extools()
|
|
/datum/controller/subsystem/air/proc/remove_from_active_extools()
|
|
/datum/controller/subsystem/air/proc/get_active_turfs()
|
|
/datum/controller/subsystem/air/proc/clear_active_turfs()
|
|
|
|
/datum/controller/subsystem/air/proc/remove_from_active(turf/open/T)
|
|
remove_from_active_extools(T)
|
|
#ifdef VISUALIZE_ACTIVE_TURFS
|
|
T.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, "#00ff00")
|
|
#endif
|
|
if(istype(T))
|
|
T.set_excited(FALSE)
|
|
T.eg_garbage_collect()
|
|
|
|
/datum/controller/subsystem/air/proc/add_to_active(turf/open/T, blockchanges = 1)
|
|
if(istype(T) && T.air)
|
|
#ifdef VISUALIZE_ACTIVE_TURFS
|
|
T.add_atom_colour("#00ff00", TEMPORARY_COLOUR_PRIORITY)
|
|
#endif
|
|
T.set_excited(TRUE)
|
|
add_to_active_extools(T)
|
|
if(blockchanges)
|
|
T.eg_garbage_collect()
|
|
else if(T.flags_1 & INITIALIZED_1)
|
|
for(var/turf/S in T.atmos_adjacent_turfs)
|
|
add_to_active(S)
|
|
else if(map_loading)
|
|
if(queued_for_activation)
|
|
queued_for_activation[T] = T
|
|
return
|
|
else
|
|
T.requires_activation = TRUE
|
|
|
|
/datum/controller/subsystem/air/StartLoadingMap()
|
|
LAZYINITLIST(queued_for_activation)
|
|
map_loading = TRUE
|
|
|
|
/datum/controller/subsystem/air/StopLoadingMap()
|
|
map_loading = FALSE
|
|
for(var/T in queued_for_activation)
|
|
add_to_active(T)
|
|
queued_for_activation.Cut()
|
|
|
|
/datum/controller/subsystem/air/proc/setup_allturfs()
|
|
var/list/turfs_to_init = block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz))
|
|
var/times_fired = ++src.times_fired
|
|
|
|
// Clear active turfs - faster than removing every single turf in the world
|
|
// one-by-one, and Initalize_Atmos only ever adds `src` back in.
|
|
clear_active_turfs()
|
|
|
|
for(var/thing in turfs_to_init)
|
|
var/turf/T = thing
|
|
if (T.blocks_air)
|
|
continue
|
|
T.Initalize_Atmos(times_fired)
|
|
CHECK_TICK
|
|
var/starting_ats = get_amt_active_turfs()
|
|
if(starting_ats)
|
|
sleep(world.tick_lag)
|
|
var/timer = world.timeofday
|
|
log_mapping("There are [starting_ats] active turfs at roundstart caused by a difference of the air between the adjacent turfs. You can see its coordinates using \"Mapping -> Show roundstart AT list\" verb (debug verbs required).")
|
|
var/list/turfs_to_check = get_amt_active_turfs()
|
|
for(var/T in turfs_to_check)
|
|
GLOB.active_turfs_startlist += T
|
|
|
|
//now lets clear out these active turfs
|
|
do
|
|
var/list/new_turfs_to_check = list()
|
|
for(var/turf/open/T in turfs_to_check)
|
|
new_turfs_to_check += T.resolve_active_graph()
|
|
CHECK_TICK
|
|
for(var/T in new_turfs_to_check)
|
|
add_to_active_extools(T)
|
|
turfs_to_check = new_turfs_to_check
|
|
|
|
while (turfs_to_check.len)
|
|
var/ending_ats = get_amt_active_turfs()
|
|
/*for(var/thing in excited_groups)
|
|
var/datum/excited_group/EG = thing
|
|
//EG.self_breakdown(space_is_all_consuming = 1)
|
|
//EG.dismantle()
|
|
CHECK_TICK*/
|
|
|
|
var/msg = "HEY! LISTEN! [DisplayTimeText(world.timeofday - timer)] were wasted processing [starting_ats] turf(s) (connected to [ending_ats] other turfs) with atmos differences at round start."
|
|
to_chat(world, "<span class='boldannounce'>[msg]</span>")
|
|
warning(msg)
|
|
|
|
/turf/open/proc/resolve_active_graph()
|
|
. = list()
|
|
/*
|
|
var/datum/excited_group/EG = excited_group
|
|
if (blocks_air || !air)
|
|
return
|
|
if (!EG)
|
|
EG = new
|
|
EG.add_turf(src)
|
|
|
|
for (var/turf/open/ET in atmos_adjacent_turfs)
|
|
if ( ET.blocks_air || !ET.air)
|
|
continue
|
|
|
|
var/ET_EG = ET.excited_group
|
|
if (ET_EG)
|
|
if (ET_EG != EG)
|
|
EG.merge_groups(ET_EG)
|
|
EG = excited_group //merge_groups() may decide to replace our current EG
|
|
else
|
|
EG.add_turf(ET)
|
|
if (!ET.excited)
|
|
ET.excited = 1
|
|
. += ET*/
|
|
|
|
/turf/open/space/resolve_active_graph()
|
|
return list()
|
|
|
|
/datum/controller/subsystem/air/proc/setup_atmos_machinery()
|
|
for (var/obj/machinery/atmospherics/AM in atmos_machinery)
|
|
AM.atmosinit()
|
|
CHECK_TICK
|
|
|
|
//this can't be done with setup_atmos_machinery() because
|
|
// all atmos machinery has to initalize before the first
|
|
// pipenet can be built.
|
|
/datum/controller/subsystem/air/proc/setup_pipenets()
|
|
for (var/obj/machinery/atmospherics/AM in atmos_machinery)
|
|
AM.build_network()
|
|
CHECK_TICK
|
|
|
|
/datum/controller/subsystem/air/proc/setup_template_machinery(list/atmos_machines)
|
|
if(!initialized) // yogs - fixes randomized bars
|
|
return // yogs
|
|
for(var/A in atmos_machines)
|
|
var/obj/machinery/atmospherics/AM = A
|
|
AM.atmosinit()
|
|
CHECK_TICK
|
|
|
|
for(var/A in atmos_machines)
|
|
var/obj/machinery/atmospherics/AM = A
|
|
AM.build_network()
|
|
CHECK_TICK
|
|
|
|
/datum/controller/subsystem/air/proc/get_init_dirs(type, dir)
|
|
if(!pipe_init_dirs_cache[type])
|
|
pipe_init_dirs_cache[type] = list()
|
|
|
|
if(!pipe_init_dirs_cache[type]["[dir]"])
|
|
var/obj/machinery/atmospherics/temp = new type(null, FALSE, dir)
|
|
pipe_init_dirs_cache[type]["[dir]"] = temp.GetInitDirections()
|
|
qdel(temp)
|
|
|
|
return pipe_init_dirs_cache[type]["[dir]"]
|
|
|
|
/proc/get_extools_benchmarks()
|
|
|
|
#undef SSAIR_PIPENETS
|
|
#undef SSAIR_ATMOSMACHINERY
|
|
#undef SSAIR_ACTIVETURFS
|
|
#undef SSAIR_EXCITEDGROUPS
|
|
#undef SSAIR_HIGHPRESSURE
|
|
#undef SSAIR_HOTSPOTS
|
|
#undef SSAIR_SUPERCONDUCTIVITY
|