mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-12 15:45:25 +01:00
Assorted atmos performance improvements. (#27966)
This commit is contained in:
@@ -12,12 +12,20 @@ SUBSYSTEM_DEF(air)
|
||||
name = "Atmospherics"
|
||||
init_order = INIT_ORDER_AIR
|
||||
priority = FIRE_PRIORITY_AIR
|
||||
wait = 2
|
||||
flags = SS_BACKGROUND
|
||||
// The MC really doesn't like it if we sleep (even though it's supposed to), and ends up running us continuously. Instead, we ask it to run us every tick, and "sleep" by skipping the current tick.
|
||||
wait = 1
|
||||
flags = SS_BACKGROUND | SS_TICKER
|
||||
/// How long we actually wait between ticks. Will round up to the next server tick.
|
||||
var/self_wait = 0.15 SECONDS
|
||||
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
|
||||
offline_implications = "Turfs will no longer process atmos, and all atmospheric machines (including cryotubes) will no longer function. Shuttle call recommended."
|
||||
cpu_display = SS_CPUDISPLAY_HIGH
|
||||
|
||||
/// When did we last finish running a complete tick?
|
||||
var/last_complete_tick = 0
|
||||
/// When did we last start a tick?
|
||||
var/last_tick_start = 0
|
||||
|
||||
/// How long we took for a full pass through the subsystem. Custom-tracked version of `cost`.
|
||||
var/datum/resumable_cost_counter/cost_full = new()
|
||||
/// How long we spent sleeping while waiting for MILLA to finish the last tick, shown in SS Info's C block as ZZZ.
|
||||
@@ -178,26 +186,21 @@ SUBSYSTEM_DEF(air)
|
||||
currentpart = SSair.currentpart
|
||||
milla_idle = SSair.milla_idle
|
||||
|
||||
#define SLEEPABLE_TIMER (world.time + world.tick_usage * world.tick_lag / 100)
|
||||
/datum/controller/subsystem/air/fire(resumed = 0)
|
||||
// All atmos stuff assumes MILLA is synchronous. Ensure it actually is.
|
||||
if(!milla_idle || length(sleepers) > 0)
|
||||
var/timer = SLEEPABLE_TIMER
|
||||
var/now = world.timeofday + (world.tick_lag * world.tick_usage) / 100
|
||||
var/elapsed = now - last_complete_tick
|
||||
if(!milla_idle || (elapsed >= 0 && elapsed < self_wait))
|
||||
return
|
||||
|
||||
while(!milla_idle || length(sleepers) > 0)
|
||||
// Sleep for 1ms.
|
||||
sleep(0.01)
|
||||
var/new_timer = SLEEPABLE_TIMER
|
||||
time_slept.record_progress((new_timer - timer) * 100, FALSE)
|
||||
timer = new_timer
|
||||
|
||||
time_slept.record_progress((SLEEPABLE_TIMER - timer) * 100, TRUE)
|
||||
if(last_tick_start <= last_complete_tick)
|
||||
last_tick_start = now
|
||||
time_slept.record_progress(max(0, elapsed) * 100, TRUE)
|
||||
|
||||
// Run the sleepless callbacks again in case more showed up since on_milla_tick_finished()
|
||||
run_sleepless_callbacks()
|
||||
|
||||
fire_sleepless(resumed)
|
||||
#undef SLEEPABLE_TIMER
|
||||
|
||||
/datum/controller/subsystem/air/proc/fire_sleepless(resumed)
|
||||
// Any proc that wants MILLA to be synchronous should not sleep.
|
||||
@@ -317,13 +320,15 @@ SUBSYSTEM_DEF(air)
|
||||
milla_idle = FALSE
|
||||
|
||||
cost_milla_tick = MC_AVERAGE(cost_milla_tick, get_milla_tick_time())
|
||||
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING)
|
||||
cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE)
|
||||
if(state == SS_PAUSED || state == SS_PAUSING)
|
||||
in_milla_safe_code = FALSE
|
||||
return
|
||||
resumed = 0
|
||||
|
||||
currentpart = SSAIR_DEFERREDPIPENETS
|
||||
last_complete_tick = world.timeofday + (world.tick_lag * world.tick_usage) / 100
|
||||
cost_full.record_progress(0, TRUE)
|
||||
in_milla_safe_code = FALSE
|
||||
|
||||
/datum/controller/subsystem/air/proc/build_pipenets(resumed = 0)
|
||||
@@ -624,6 +629,9 @@ SUBSYSTEM_DEF(air)
|
||||
for(var/turf/T as anything in block(low_corner, high_corner))
|
||||
T.Initialize_Atmos(times_fired)
|
||||
milla_load_turfs(low_corner, high_corner)
|
||||
for(var/turf/T as anything in block(low_corner, high_corner))
|
||||
T.milla_data.len = 0
|
||||
T.milla_data = null
|
||||
|
||||
/datum/controller/subsystem/air/proc/setup_write_to_milla()
|
||||
var/watch = start_watch()
|
||||
|
||||
@@ -61,8 +61,8 @@
|
||||
var/list/firealarms
|
||||
var/firedoors_last_closed_on = 0
|
||||
|
||||
/// The air alarm to use for atmos_alert consoles
|
||||
var/obj/machinery/alarm/master_air_alarm
|
||||
/// The air alarms present in this area.
|
||||
var/list/air_alarms = list()
|
||||
/// The list of vents in our area.
|
||||
var/list/obj/machinery/atmospherics/unary/vent_pump/vents = list()
|
||||
/// The list of scrubbers in our area.
|
||||
|
||||
@@ -19,26 +19,29 @@
|
||||
parent_area_type = machine_area.get_top_parent_type()
|
||||
|
||||
/obj/machinery/computer/atmos_alert/process()
|
||||
// This is relatively cheap because the areas list is pretty small
|
||||
for(var/obj/machinery/alarm/air_alarm as anything in GLOB.air_alarms)
|
||||
if(!((get_area(air_alarm)).type in typesof(parent_area_type)) || air_alarm.z != z)
|
||||
continue // Not an area we monitor, or outside our z-level
|
||||
if(!air_alarm.report_danger_level)
|
||||
alarm_cache = list()
|
||||
alarm_cache["priority"] = list()
|
||||
alarm_cache["minor"] = list()
|
||||
alarm_cache["mode"] = list()
|
||||
for(var/area/A in GLOB.all_areas)
|
||||
if(!istype(A, parent_area_type))
|
||||
continue
|
||||
switch(air_alarm.alarm_area.atmosalm)
|
||||
if(ATMOS_ALARM_DANGER)
|
||||
alarm_cache["priority"] |= air_alarm.alarm_area.name
|
||||
alarm_cache["minor"] -= air_alarm.alarm_area.name
|
||||
if(ATMOS_ALARM_WARNING)
|
||||
alarm_cache["priority"] -= air_alarm.alarm_area.name
|
||||
alarm_cache["minor"] |= air_alarm.alarm_area.name
|
||||
else
|
||||
alarm_cache["priority"] -= air_alarm.alarm_area.name
|
||||
alarm_cache["minor"] -= air_alarm.alarm_area.name
|
||||
if(air_alarm.mode == AALARM_MODE_FILTERING)
|
||||
alarm_cache["mode"] -= air_alarm.alarm_area.name
|
||||
else
|
||||
alarm_cache["mode"][air_alarm.alarm_area.name] = GLOB.aalarm_modes["[air_alarm.mode]"]
|
||||
var/alarm_level = null
|
||||
for(var/obj/machinery/alarm/air_alarm in A.air_alarms)
|
||||
if(!istype(air_alarm))
|
||||
continue
|
||||
if(!air_alarm.report_danger_level)
|
||||
continue
|
||||
switch(air_alarm.alarm_area.atmosalm)
|
||||
if(ATMOS_ALARM_DANGER)
|
||||
alarm_level = "priority"
|
||||
if(ATMOS_ALARM_WARNING)
|
||||
if(isnull(alarm_level))
|
||||
alarm_level = "minor"
|
||||
if(!isnull(alarm_level))
|
||||
alarm_cache[alarm_level] += A.name
|
||||
if(air_alarm.mode != AALARM_MODE_FILTERING)
|
||||
alarm_cache["mode"][A.name] = GLOB.aalarm_modes["[air_alarm.mode]"]
|
||||
|
||||
update_icon()
|
||||
|
||||
|
||||
@@ -85,13 +85,7 @@
|
||||
/// The effect used to render a pressure overlay from this tile.
|
||||
var/obj/effect/pressure_overlay/pressure_overlay
|
||||
|
||||
var/list/milla_atmos_airtight = list(FALSE, FALSE, FALSE, FALSE)
|
||||
var/list/milla_superconductivity = list(
|
||||
OPEN_HEAT_TRANSFER_COEFFICIENT,
|
||||
OPEN_HEAT_TRANSFER_COEFFICIENT,
|
||||
OPEN_HEAT_TRANSFER_COEFFICIENT,
|
||||
OPEN_HEAT_TRANSFER_COEFFICIENT)
|
||||
var/list/milla_data = list()
|
||||
var/list/milla_data = null
|
||||
|
||||
new_attack_chain = TRUE
|
||||
|
||||
|
||||
@@ -173,9 +173,9 @@
|
||||
|
||||
/turf/proc/Initialize_Atmos(times_fired)
|
||||
// This is one of two places expected to call this otherwise-unsafe method.
|
||||
private_unsafe_recalculate_atmos_connectivity()
|
||||
var/list/connectivity = private_unsafe_recalculate_atmos_connectivity()
|
||||
var/list/air = list(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, temperature)
|
||||
milla_data = milla_atmos_airtight + list(atmos_mode, SSmapping.environments[atmos_environment]) + air + milla_superconductivity
|
||||
milla_data = connectivity[1] + list(atmos_mode, SSmapping.environments[atmos_environment]) + air + connectivity[2]
|
||||
|
||||
/turf/proc/recalculate_atmos_connectivity()
|
||||
var/datum/milla_safe/recalculate_atmos_connectivity/milla = new()
|
||||
@@ -188,26 +188,26 @@
|
||||
return
|
||||
|
||||
// This is one of two places expected to call this otherwise-unsafe method.
|
||||
T.private_unsafe_recalculate_atmos_connectivity()
|
||||
var/list/connectivity = T.private_unsafe_recalculate_atmos_connectivity()
|
||||
|
||||
set_tile_airtight(T, T.milla_atmos_airtight)
|
||||
set_tile_airtight(T, connectivity[1])
|
||||
reset_superconductivity(T)
|
||||
reduce_superconductivity(T, T.milla_superconductivity)
|
||||
reduce_superconductivity(T, connectivity[2])
|
||||
|
||||
/// This method is unsafe to use because it only updates milla_* properties, but does not write them to MILLA. Use recalculate_atmos_connectivity() instead.
|
||||
/turf/proc/private_unsafe_recalculate_atmos_connectivity()
|
||||
if(blocks_air)
|
||||
milla_atmos_airtight = list(TRUE, TRUE, TRUE, TRUE)
|
||||
milla_superconductivity = list(0, 0, 0, 0)
|
||||
return
|
||||
var/milla_atmos_airtight = list(TRUE, TRUE, TRUE, TRUE)
|
||||
var/milla_superconductivity = list(0, 0, 0, 0)
|
||||
return list(milla_atmos_airtight, milla_superconductivity)
|
||||
|
||||
milla_atmos_airtight = list(
|
||||
var/milla_atmos_airtight = list(
|
||||
!CanAtmosPass(NORTH, FALSE),
|
||||
!CanAtmosPass(EAST, FALSE),
|
||||
!CanAtmosPass(SOUTH, FALSE),
|
||||
!CanAtmosPass(WEST, FALSE))
|
||||
|
||||
milla_superconductivity = list(
|
||||
var/milla_superconductivity = list(
|
||||
OPEN_HEAT_TRANSFER_COEFFICIENT,
|
||||
OPEN_HEAT_TRANSFER_COEFFICIENT,
|
||||
OPEN_HEAT_TRANSFER_COEFFICIENT,
|
||||
@@ -230,6 +230,8 @@
|
||||
milla_superconductivity[INDEX_SOUTH] = min(milla_superconductivity[INDEX_SOUTH], O.get_superconductivity(SOUTH))
|
||||
milla_superconductivity[INDEX_WEST] = min(milla_superconductivity[INDEX_WEST], O.get_superconductivity(WEST))
|
||||
|
||||
return list(milla_atmos_airtight, milla_superconductivity)
|
||||
|
||||
/obj/effect/wind
|
||||
anchored = TRUE
|
||||
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
|
||||
|
||||
@@ -114,12 +114,10 @@ What are the archived variables for?
|
||||
|
||||
/// Calculate moles
|
||||
/datum/gas_mixture/proc/total_moles()
|
||||
var/moles = private_oxygen + private_carbon_dioxide + private_nitrogen + private_toxins + private_sleeping_agent + private_agent_b
|
||||
return moles
|
||||
return private_oxygen + private_carbon_dioxide + private_nitrogen + private_toxins + private_sleeping_agent + private_agent_b
|
||||
|
||||
/datum/gas_mixture/proc/total_trace_moles()
|
||||
var/moles = private_agent_b
|
||||
return moles
|
||||
return private_agent_b
|
||||
|
||||
/// Calculate pressure in kilopascals
|
||||
/datum/gas_mixture/proc/return_pressure()
|
||||
@@ -662,23 +660,26 @@ What are the archived variables for?
|
||||
|
||||
/proc/share_many_airs(list/mixtures)
|
||||
var/total_volume = 0
|
||||
var/total_thermal_energy = 0
|
||||
var/total_heat_capacity = 0
|
||||
var/total_oxygen = 0
|
||||
var/total_nitrogen = 0
|
||||
var/total_toxins = 0
|
||||
var/total_carbon_dioxide = 0
|
||||
var/total_sleeping_agent = 0
|
||||
var/total_agent_b = 0
|
||||
var/must_share = FALSE
|
||||
|
||||
// Collect all the cheap data and check if there's a significant temperature difference.
|
||||
var/temperature = null
|
||||
for(var/datum/gas_mixture/G as anything in mixtures)
|
||||
if(!istype(G))
|
||||
stack_trace("share_many_airs had [G] in mixtures ([json_encode(mixtures)])")
|
||||
continue
|
||||
total_volume += G.volume
|
||||
var/heat_capacity = G.heat_capacity()
|
||||
total_heat_capacity += heat_capacity
|
||||
total_thermal_energy += G.private_temperature * heat_capacity
|
||||
|
||||
if(isnull(temperature))
|
||||
temperature = G.private_temperature
|
||||
else if(abs(temperature - G.private_temperature) >= 1)
|
||||
must_share = TRUE
|
||||
|
||||
total_oxygen += G.private_oxygen
|
||||
total_nitrogen += G.private_nitrogen
|
||||
@@ -687,26 +688,65 @@ What are the archived variables for?
|
||||
total_sleeping_agent += G.private_sleeping_agent
|
||||
total_agent_b += G.private_agent_b
|
||||
|
||||
if(total_volume > 0)
|
||||
//Calculate temperature
|
||||
var/temperature = 0
|
||||
if(total_volume <= 0)
|
||||
return
|
||||
|
||||
if(total_heat_capacity > 0)
|
||||
temperature = total_thermal_energy/total_heat_capacity
|
||||
|
||||
//Update individual gas_mixtures by volume ratio
|
||||
// If we don't have a significant temperature difference, check for a significant gas amount difference.
|
||||
if(!must_share)
|
||||
for(var/datum/gas_mixture/G as anything in mixtures)
|
||||
if(!istype(G))
|
||||
continue
|
||||
G.private_oxygen = total_oxygen * G.volume / total_volume
|
||||
G.private_nitrogen = total_nitrogen * G.volume / total_volume
|
||||
G.private_toxins = total_toxins * G.volume / total_volume
|
||||
G.private_carbon_dioxide = total_carbon_dioxide * G.volume / total_volume
|
||||
G.private_sleeping_agent = total_sleeping_agent * G.volume / total_volume
|
||||
G.private_agent_b = total_agent_b * G.volume / total_volume
|
||||
if(abs(G.private_oxygen - total_oxygen * G.volume / total_volume) > 0.1)
|
||||
must_share = TRUE
|
||||
break
|
||||
if(abs(G.private_nitrogen - total_nitrogen * G.volume / total_volume) > 0.1)
|
||||
must_share = TRUE
|
||||
break
|
||||
if(abs(G.private_toxins - total_toxins * G.volume / total_volume) > 0.1)
|
||||
must_share = TRUE
|
||||
break
|
||||
if(abs(G.private_carbon_dioxide - total_carbon_dioxide * G.volume / total_volume) > 0.1)
|
||||
must_share = TRUE
|
||||
break
|
||||
if(abs(G.private_sleeping_agent - total_sleeping_agent * G.volume / total_volume) > 0.1)
|
||||
must_share = TRUE
|
||||
break
|
||||
if(abs(G.private_agent_b - total_agent_b * G.volume / total_volume) > 0.1)
|
||||
must_share = TRUE
|
||||
break
|
||||
|
||||
G.private_temperature = temperature
|
||||
G.set_dirty()
|
||||
if(!must_share)
|
||||
// Nothing significant, don't do any more work.
|
||||
return
|
||||
|
||||
// Collect the more expensive data.
|
||||
var/total_thermal_energy = 0
|
||||
var/total_heat_capacity = 0
|
||||
for(var/datum/gas_mixture/G as anything in mixtures)
|
||||
if(!istype(G))
|
||||
continue
|
||||
var/heat_capacity = G.heat_capacity()
|
||||
total_heat_capacity += heat_capacity
|
||||
total_thermal_energy += G.private_temperature * heat_capacity
|
||||
|
||||
// Calculate shared temperature.
|
||||
temperature = TCMB
|
||||
if(total_heat_capacity > 0)
|
||||
temperature = total_thermal_energy/total_heat_capacity
|
||||
|
||||
// Update individual gas_mixtures by volume ratio.
|
||||
for(var/datum/gas_mixture/G as anything in mixtures)
|
||||
if(!istype(G))
|
||||
continue
|
||||
G.private_oxygen = total_oxygen * G.volume / total_volume
|
||||
G.private_nitrogen = total_nitrogen * G.volume / total_volume
|
||||
G.private_toxins = total_toxins * G.volume / total_volume
|
||||
G.private_carbon_dioxide = total_carbon_dioxide * G.volume / total_volume
|
||||
G.private_sleeping_agent = total_sleeping_agent * G.volume / total_volume
|
||||
G.private_agent_b = total_agent_b * G.volume / total_volume
|
||||
|
||||
G.private_temperature = temperature
|
||||
// In theory, we should G.set_dirty() here, but that's only useful for bound mixtures, and these can't be.
|
||||
|
||||
/datum/gas_mixture/proc/hotspot_expose(temperature, volume)
|
||||
return
|
||||
|
||||
@@ -222,6 +222,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list(
|
||||
set_pixel_offsets_from_dir(24, -24, 24, -24)
|
||||
|
||||
GLOB.air_alarms += src
|
||||
alarm_area.air_alarms += src
|
||||
|
||||
if(!mapload)
|
||||
GLOB.air_alarms = sortAtom(GLOB.air_alarms)
|
||||
@@ -231,17 +232,12 @@ GLOBAL_LIST_INIT(aalarm_modes, list(
|
||||
if(!building)
|
||||
first_run()
|
||||
|
||||
if(!master_is_operating())
|
||||
elect_master()
|
||||
|
||||
/obj/machinery/alarm/Destroy()
|
||||
SStgui.close_uis(wires)
|
||||
GLOB.air_alarms -= src
|
||||
alarm_area.air_alarms -= src
|
||||
GLOB.air_alarm_repository.update_cache(src)
|
||||
QDEL_NULL(wires)
|
||||
if(alarm_area && alarm_area.master_air_alarm == src)
|
||||
alarm_area.master_air_alarm = null
|
||||
elect_master(exclude_self = 1)
|
||||
alarm_area = null
|
||||
return ..()
|
||||
|
||||
@@ -249,24 +245,6 @@ GLOBAL_LIST_INIT(aalarm_modes, list(
|
||||
apply_preset(AALARM_PRESET_HUMAN) // Don't cycle.
|
||||
GLOB.air_alarm_repository.update_cache(src)
|
||||
|
||||
/obj/machinery/alarm/proc/master_is_operating()
|
||||
if(!alarm_area)
|
||||
alarm_area = get_area(src)
|
||||
if(!alarm_area)
|
||||
. = FALSE
|
||||
CRASH("Air alarm /obj/machinery/alarm lacks alarm_area vars during proc/master_is_operating()")
|
||||
return alarm_area.master_air_alarm && !(alarm_area.master_air_alarm.stat & (NOPOWER|BROKEN))
|
||||
|
||||
|
||||
/obj/machinery/alarm/proc/elect_master(exclude_self = 0) //Why is this an alarm and not area proc?
|
||||
for(var/obj/machinery/alarm/AA in alarm_area)
|
||||
if(exclude_self && AA == src)
|
||||
continue
|
||||
if(!(AA.stat & (NOPOWER|BROKEN)))
|
||||
alarm_area.master_air_alarm = AA
|
||||
return 1
|
||||
return 0
|
||||
|
||||
/obj/machinery/alarm/process()
|
||||
if((stat & (NOPOWER|BROKEN)) || shorted || buildstage != 2)
|
||||
return
|
||||
@@ -275,8 +253,9 @@ GLOBAL_LIST_INIT(aalarm_modes, list(
|
||||
if(!istype(location))
|
||||
return 0
|
||||
|
||||
var/datum/milla_safe/airalarm_heat_cool/milla = new()
|
||||
milla.invoke_async(src)
|
||||
if(thermostat_state)
|
||||
var/datum/milla_safe/airalarm_heat_cool/milla = new()
|
||||
milla.invoke_async(src)
|
||||
|
||||
var/datum/gas_mixture/environment = location.get_readonly_air()
|
||||
var/GET_PP = R_IDEAL_GAS_EQUATION * environment.temperature() / environment.volume
|
||||
@@ -342,8 +321,6 @@ GLOBAL_LIST_INIT(aalarm_modes, list(
|
||||
var/turf/location = get_turf(alarm)
|
||||
var/datum/gas_mixture/environment = get_turf_air(location)
|
||||
|
||||
if(!alarm.thermostat_state)
|
||||
return
|
||||
var/datum/tlv/cur_tlv = alarm.TLV["temperature"]
|
||||
//Handle temperature adjustment here.
|
||||
if(environment.temperature() < alarm.target_temperature - 2 || environment.temperature() > alarm.target_temperature + 2 || alarm.regulating_temperature)
|
||||
|
||||
@@ -94,21 +94,14 @@
|
||||
if(Old == parent)
|
||||
parent = New
|
||||
|
||||
/obj/machinery/atmospherics/unary/unsafe_pressure_release(mob/user, pressures)
|
||||
/obj/machinery/atmospherics/unary/unsafe_pressure_release(mob/user, pressure)
|
||||
..()
|
||||
|
||||
var/turf/T = get_turf(src)
|
||||
if(T)
|
||||
var/datum/milla_safe/unary_unsafe_pressure_release/milla = new()
|
||||
milla.invoke_async(src, pressures)
|
||||
if(!T)
|
||||
return
|
||||
|
||||
/datum/milla_safe/unary_unsafe_pressure_release
|
||||
var/lost = pressure * CELL_VOLUME / (air_contents.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
/datum/milla_safe/unary_unsafe_pressure_release/on_run(obj/machinery/atmospherics/unary/device, pressures)
|
||||
//Remove the gas from air_contents and assume it
|
||||
var/turf/T = get_turf(device)
|
||||
var/datum/gas_mixture/environment = get_turf_air(T)
|
||||
var/lost = pressures * environment.volume / (device.air_contents.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
var/datum/gas_mixture/to_release = device.air_contents.remove(lost)
|
||||
environment.merge(to_release)
|
||||
var/datum/gas_mixture/to_release = air_contents.remove(lost)
|
||||
T.blind_release_air(to_release)
|
||||
|
||||
@@ -108,69 +108,71 @@
|
||||
update_underlays()
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_pump/process_atmos()
|
||||
var/datum/milla_safe/vent_pump_process/milla = new()
|
||||
milla.invoke_async(src)
|
||||
|
||||
/datum/milla_safe/vent_pump_process
|
||||
|
||||
/datum/milla_safe/vent_pump_process/on_run(obj/machinery/atmospherics/unary/vent_pump/vent_pump)
|
||||
if(vent_pump.stat & (NOPOWER|BROKEN))
|
||||
if(stat & (NOPOWER|BROKEN))
|
||||
return FALSE
|
||||
if(QDELETED(vent_pump.parent))
|
||||
if(QDELETED(parent))
|
||||
// We're orphaned!
|
||||
return FALSE
|
||||
var/turf/T = get_turf(vent_pump)
|
||||
var/turf/T = get_turf(src)
|
||||
if(T.density) //No, you should not be able to get free air from walls
|
||||
return
|
||||
if(!vent_pump.node)
|
||||
vent_pump.on = FALSE
|
||||
if(!vent_pump.on)
|
||||
if(!node)
|
||||
on = FALSE
|
||||
if(!on)
|
||||
return FALSE
|
||||
|
||||
if(vent_pump.welded)
|
||||
if(vent_pump.air_contents.return_pressure() >= vent_pump.weld_burst_pressure && prob(5)) //the weld is on but the cover is welded shut, can it withstand the internal pressure?
|
||||
vent_pump.visible_message("<span class='danger'>The welded cover of [vent_pump] bursts open!</span>")
|
||||
if(welded)
|
||||
if(air_contents.return_pressure() >= weld_burst_pressure && prob(5)) //the weld is on but the cover is welded shut, can it withstand the internal pressure?
|
||||
visible_message("<span class='danger'>The welded cover of [src] bursts open!</span>")
|
||||
for(var/mob/living/M in range(1))
|
||||
vent_pump.unsafe_pressure_release(M, vent_pump.air_contents.return_pressure()) //let's send everyone flying
|
||||
vent_pump.welded = FALSE
|
||||
vent_pump.update_icon()
|
||||
unsafe_pressure_release(M, air_contents.return_pressure()) //let's send everyone flying
|
||||
welded = FALSE
|
||||
update_icon()
|
||||
return FALSE
|
||||
|
||||
var/datum/gas_mixture/environment = get_turf_air(T)
|
||||
var/environment_pressure = environment.return_pressure()
|
||||
if(vent_pump.releasing) //internal -> external
|
||||
var/datum/gas_mixture/environment = T.get_readonly_air()
|
||||
if(releasing) //internal -> external
|
||||
var/pressure_delta = 10000
|
||||
if(vent_pump.pressure_checks == ONLY_CHECK_EXT_PRESSURE)
|
||||
if(pressure_checks == ONLY_CHECK_EXT_PRESSURE)
|
||||
// Only checks difference between set pressure and environment pressure
|
||||
pressure_delta = min(pressure_delta, (vent_pump.external_pressure_bound - environment_pressure))
|
||||
if(vent_pump.pressure_checks == ONLY_CHECK_INT_PRESSURE)
|
||||
pressure_delta = min(pressure_delta, (vent_pump.air_contents.return_pressure() - vent_pump.internal_pressure_bound))
|
||||
pressure_delta = min(pressure_delta, (external_pressure_bound - environment.return_pressure()))
|
||||
if(pressure_checks == ONLY_CHECK_INT_PRESSURE)
|
||||
pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound))
|
||||
|
||||
if(pressure_delta > 0.5 && vent_pump.air_contents.temperature() > 0)
|
||||
if(pressure_delta > 0.5 && air_contents.temperature() > 0)
|
||||
// 1kPa * 1L = 1J
|
||||
var/wanted_joules = pressure_delta * environment.volume
|
||||
var/transfer_moles = min(vent_pump.max_transfer_joules, wanted_joules) / (vent_pump.air_contents.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
var/datum/gas_mixture/removed = vent_pump.air_contents.remove(transfer_moles)
|
||||
environment.merge(removed)
|
||||
vent_pump.parent.update = TRUE
|
||||
var/transfer_moles = min(max_transfer_joules, wanted_joules) / (air_contents.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
|
||||
// This isn't exactly "blind", but using the data from last tick is good enough for a vent.
|
||||
T.blind_release_air(removed)
|
||||
parent.update = TRUE
|
||||
|
||||
else //external -> internal
|
||||
var/pressure_delta = 10000
|
||||
if(vent_pump.pressure_checks == ONLY_CHECK_EXT_PRESSURE)
|
||||
pressure_delta = min(pressure_delta, (environment_pressure - vent_pump.external_pressure_bound))
|
||||
if(vent_pump.pressure_checks == ONLY_CHECK_INT_PRESSURE)
|
||||
pressure_delta = min(pressure_delta, (vent_pump.internal_pressure_bound - vent_pump.air_contents.return_pressure()))
|
||||
|
||||
if(pressure_delta > 0.5 && environment.temperature() > 0)
|
||||
// 1kPa * 1L = 1J
|
||||
var/wanted_joules = pressure_delta * environment.volume
|
||||
var/transfer_moles = min(vent_pump.max_transfer_joules, wanted_joules) / (environment.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
var/datum/gas_mixture/removed = environment.remove(transfer_moles)
|
||||
vent_pump.air_contents.merge(removed)
|
||||
vent_pump.parent.update = TRUE
|
||||
var/datum/milla_safe/vent_pump_siphon/milla = new()
|
||||
milla.invoke_async(src)
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/milla_safe/vent_pump_siphon
|
||||
|
||||
/datum/milla_safe/vent_pump_siphon/on_run(obj/machinery/atmospherics/unary/vent_pump/vent_pump)
|
||||
var/turf/T = get_turf(vent_pump)
|
||||
var/datum/gas_mixture/environment = get_turf_air(T)
|
||||
var/pressure_delta = 10000
|
||||
if(vent_pump.pressure_checks == ONLY_CHECK_EXT_PRESSURE)
|
||||
pressure_delta = min(pressure_delta, (environment.return_pressure() - vent_pump.external_pressure_bound))
|
||||
if(vent_pump.pressure_checks == ONLY_CHECK_INT_PRESSURE)
|
||||
pressure_delta = min(pressure_delta, (vent_pump.internal_pressure_bound - vent_pump.air_contents.return_pressure()))
|
||||
|
||||
if(pressure_delta > 0.5 && environment.temperature() > 0)
|
||||
// 1kPa * 1L = 1J
|
||||
var/wanted_joules = pressure_delta * environment.volume
|
||||
var/transfer_moles = min(vent_pump.max_transfer_joules, wanted_joules) / (environment.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
var/datum/gas_mixture/removed = environment.remove(transfer_moles)
|
||||
vent_pump.air_contents.merge(removed)
|
||||
vent_pump.parent.update = TRUE
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_pump/can_crawl_through()
|
||||
return !welded
|
||||
|
||||
|
||||
@@ -140,9 +140,31 @@
|
||||
adjacent_turfs = T.GetAtmosAdjacentTurfs(alldir=1)
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_scrubber/proc/scrub(turf/simulated/tile)
|
||||
if(!tile || !istype(tile))
|
||||
return 0
|
||||
|
||||
if(scrubbing && !should_scrub(tile.get_readonly_air()))
|
||||
return 0
|
||||
|
||||
var/datum/milla_safe/vent_scrubber_process/milla = new()
|
||||
milla.invoke_async(src, tile)
|
||||
|
||||
/obj/machinery/atmospherics/unary/vent_scrubber/proc/should_scrub(datum/gas_mixture/environment)
|
||||
if(scrub_O2 && environment.oxygen() > 0.001)
|
||||
return TRUE
|
||||
if(scrub_N2 && environment.nitrogen() > 0.001)
|
||||
return TRUE
|
||||
if(scrub_CO2 && environment.carbon_dioxide() > 0.001)
|
||||
return TRUE
|
||||
if(scrub_Toxins && environment.toxins() > 0.001)
|
||||
return TRUE
|
||||
if(environment.sleeping_agent() > 0.001)
|
||||
return TRUE
|
||||
if(environment.agent_b() > 0.001)
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/milla_safe/vent_scrubber_process
|
||||
|
||||
/datum/milla_safe/vent_scrubber_process/on_run(obj/machinery/atmospherics/unary/vent_scrubber/scrubber, turf/simulated/tile)
|
||||
@@ -152,7 +174,7 @@
|
||||
var/datum/gas_mixture/environment = get_turf_air(tile)
|
||||
|
||||
if(scrubber.scrubbing)
|
||||
if((scrubber.scrub_O2 && environment.oxygen() > 0.001) || (scrubber.scrub_N2 && environment.nitrogen() > 0.001) || (scrubber.scrub_CO2 && environment.carbon_dioxide() > 0.001) || (scrubber.scrub_Toxins && environment.toxins() > 0.001) || (environment.sleeping_agent()) || (environment.agent_b()))
|
||||
if(scrubber.should_scrub(environment))
|
||||
var/transfer_moles = min(1, scrubber.volume_rate / environment.volume) * environment.total_moles()
|
||||
|
||||
//Take a gas sample
|
||||
|
||||
@@ -210,41 +210,41 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
|
||||
/obj/machinery/atmospherics/portable/canister/process_atmos()
|
||||
..()
|
||||
sync_pressure_appearance()
|
||||
var/datum/milla_safe/canister_process/milla = new()
|
||||
milla.invoke_async(src)
|
||||
|
||||
/datum/milla_safe/canister_process
|
||||
|
||||
/datum/milla_safe/canister_process/on_run(obj/machinery/atmospherics/portable/canister/canister)
|
||||
if(canister.stat & BROKEN)
|
||||
if(stat & BROKEN)
|
||||
return
|
||||
|
||||
if(canister.valve_open)
|
||||
var/datum/gas_mixture/environment
|
||||
if(canister.holding_tank)
|
||||
environment = canister.holding_tank.air_contents
|
||||
else
|
||||
var/turf/T = get_turf(canister)
|
||||
environment = get_turf_air(T)
|
||||
if(valve_open)
|
||||
var/datum/milla_safe/canister_release/milla = new()
|
||||
milla.invoke_async(src)
|
||||
|
||||
var/env_pressure = environment.return_pressure()
|
||||
var/pressure_delta = min(canister.release_pressure - env_pressure, (canister.air_contents.return_pressure() - env_pressure) / 2)
|
||||
//Can not have a pressure delta that would cause environment pressure > tank pressure
|
||||
|
||||
var/transfer_moles = 0
|
||||
if((canister.air_contents.temperature() > 0) && (pressure_delta > 0))
|
||||
transfer_moles = pressure_delta * environment.volume / (canister.air_contents.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed = canister.air_contents.remove(transfer_moles)
|
||||
|
||||
environment.merge(removed)
|
||||
canister.sync_pressure_appearance()
|
||||
|
||||
if(canister.air_contents.return_pressure() < 1)
|
||||
canister.can_label = TRUE
|
||||
if(air_contents.return_pressure() < 1)
|
||||
can_label = TRUE
|
||||
else
|
||||
canister.can_label = FALSE
|
||||
can_label = FALSE
|
||||
|
||||
/datum/milla_safe/canister_release
|
||||
|
||||
/datum/milla_safe/canister_release/on_run(obj/machinery/atmospherics/portable/canister/canister)
|
||||
var/datum/gas_mixture/environment
|
||||
if(canister.holding_tank)
|
||||
environment = canister.holding_tank.air_contents
|
||||
else
|
||||
var/turf/T = get_turf(canister)
|
||||
environment = get_turf_air(T)
|
||||
|
||||
var/env_pressure = environment.return_pressure()
|
||||
var/pressure_delta = min(canister.release_pressure - env_pressure, (canister.air_contents.return_pressure() - env_pressure) / 2)
|
||||
//Can not have a pressure delta that would cause environment pressure > tank pressure
|
||||
|
||||
var/transfer_moles = 0
|
||||
if((canister.air_contents.temperature() > 0) && (pressure_delta > 0))
|
||||
transfer_moles = pressure_delta * environment.volume / (canister.air_contents.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed = canister.air_contents.remove(transfer_moles)
|
||||
|
||||
environment.merge(removed)
|
||||
canister.sync_pressure_appearance()
|
||||
|
||||
/obj/machinery/atmospherics/portable/canister/return_obj_air()
|
||||
RETURN_TYPE(/datum/gas_mixture)
|
||||
|
||||
@@ -61,44 +61,44 @@
|
||||
|
||||
/obj/machinery/atmospherics/portable/pump/process_atmos()
|
||||
..()
|
||||
var/datum/milla_safe/portable_pump_process/milla = new()
|
||||
milla.invoke_async(src)
|
||||
if(on)
|
||||
var/datum/milla_safe/portable_pump_process/milla = new()
|
||||
milla.invoke_async(src)
|
||||
|
||||
/datum/milla_safe/portable_pump_process
|
||||
|
||||
/datum/milla_safe/portable_pump_process/on_run(obj/machinery/atmospherics/portable/pump/pump)
|
||||
if(pump.on)
|
||||
var/datum/gas_mixture/environment
|
||||
if(pump.holding_tank)
|
||||
environment = pump.holding_tank.air_contents
|
||||
else
|
||||
var/turf/T = get_turf(pump)
|
||||
environment = get_turf_air(T)
|
||||
if(pump.direction == DIRECTION_OUT)
|
||||
var/pressure_delta = pump.target_pressure - environment.return_pressure()
|
||||
//Can not have a pressure delta that would cause environment pressure > tank pressure
|
||||
var/datum/gas_mixture/environment
|
||||
if(pump.holding_tank)
|
||||
environment = pump.holding_tank.air_contents
|
||||
else
|
||||
var/turf/T = get_turf(pump)
|
||||
environment = get_turf_air(T)
|
||||
if(pump.direction == DIRECTION_OUT)
|
||||
var/pressure_delta = pump.target_pressure - environment.return_pressure()
|
||||
//Can not have a pressure delta that would cause environment pressure > tank pressure
|
||||
|
||||
var/transfer_moles = 0
|
||||
if(pump.air_contents.temperature() > 0)
|
||||
transfer_moles = pressure_delta*environment.volume/(pump.air_contents.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
var/transfer_moles = 0
|
||||
if(pump.air_contents.temperature() > 0)
|
||||
transfer_moles = pressure_delta*environment.volume/(pump.air_contents.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed = pump.air_contents.remove(transfer_moles)
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed = pump.air_contents.remove(transfer_moles)
|
||||
|
||||
environment.merge(removed)
|
||||
else
|
||||
var/pressure_delta = pump.target_pressure - pump.air_contents.return_pressure()
|
||||
//Can not have a pressure delta that would cause environment pressure > tank pressure
|
||||
environment.merge(removed)
|
||||
else
|
||||
var/pressure_delta = pump.target_pressure - pump.air_contents.return_pressure()
|
||||
//Can not have a pressure delta that would cause environment pressure > tank pressure
|
||||
|
||||
var/transfer_moles = 0
|
||||
if(environment.temperature() > 0)
|
||||
transfer_moles = pressure_delta*pump.air_contents.volume/(environment.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
var/transfer_moles = 0
|
||||
if(environment.temperature() > 0)
|
||||
transfer_moles = pressure_delta*pump.air_contents.volume/(environment.temperature() * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed
|
||||
removed = environment.remove(transfer_moles)
|
||||
//Actually transfer the gas
|
||||
var/datum/gas_mixture/removed
|
||||
removed = environment.remove(transfer_moles)
|
||||
|
||||
pump.air_contents.merge(removed)
|
||||
pump.air_contents.merge(removed)
|
||||
|
||||
/obj/machinery/atmospherics/portable/pump/return_obj_air()
|
||||
RETURN_TYPE(/datum/gas_mixture)
|
||||
|
||||
@@ -46,18 +46,18 @@
|
||||
|
||||
/obj/machinery/atmospherics/portable/scrubber/process_atmos()
|
||||
..()
|
||||
var/datum/milla_safe/portable_scrubber_process/milla = new()
|
||||
if(!on)
|
||||
return
|
||||
if(holding_tank)
|
||||
scrub(holding_tank.air_contents)
|
||||
return
|
||||
|
||||
var/datum/milla_safe/portable_scrubber_scrub/milla = new()
|
||||
milla.invoke_async(src)
|
||||
|
||||
/datum/milla_safe/portable_scrubber_process
|
||||
|
||||
/datum/milla_safe/portable_scrubber_process/on_run(obj/machinery/atmospherics/portable/scrubber/scrubber)
|
||||
if(!scrubber.on)
|
||||
return
|
||||
if(scrubber.holding_tank)
|
||||
scrubber.scrub(scrubber.holding_tank.air_contents)
|
||||
return
|
||||
/datum/milla_safe/portable_scrubber_scrub
|
||||
|
||||
/datum/milla_safe/portable_scrubber_scrub/on_run(obj/machinery/atmospherics/portable/scrubber/scrubber)
|
||||
var/turf/T = get_turf(scrubber)
|
||||
scrubber.scrub(get_turf_air(T))
|
||||
if(scrubber.widenet)
|
||||
|
||||
Reference in New Issue
Block a user