diff --git a/code/controllers/subsystem/SSair.dm b/code/controllers/subsystem/SSair.dm index 5553f6d78d06..2701124ec466 100644 --- a/code/controllers/subsystem/SSair.dm +++ b/code/controllers/subsystem/SSair.dm @@ -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 - - 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 + 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 - 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() diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index 37f2b52023c9..de66376bff58 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -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. diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm index 9b3fee6c25ca..3d2fc2646d09 100644 --- a/code/game/machinery/computer/atmos_alert.dm +++ b/code/game/machinery/computer/atmos_alert.dm @@ -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() diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 55d448149759..765a74fed915 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -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 diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index 8a845f5994ad..882772719295 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -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 diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm index 7bfd1fa004ec..e14706d7b269 100644 --- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm +++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm @@ -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_heat_capacity > 0) - temperature = total_thermal_energy/total_heat_capacity + if(total_volume <= 0) + return - //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 - - G.private_temperature = temperature - G.set_dirty() + 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 + + 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 diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 9e86fa0c13eb..795772f5d1a6 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -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) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/unary_base.dm b/code/modules/atmospherics/machinery/components/unary_devices/unary_base.dm index a831588f4014..dbd529be80db 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/unary_base.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/unary_base.dm @@ -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) - -/datum/milla_safe/unary_unsafe_pressure_release + if(!T) + return -/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/lost = pressure * CELL_VOLUME / (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) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm index 2743bfdd7f92..412bf1b2e24a 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm @@ -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("The welded cover of [vent_pump] bursts open!") + 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("The welded cover of [src] bursts open!") 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 diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm index 3066b5308b01..70b00ea21618 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm @@ -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 diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index 0d31cf0572f0..e8023b2a3ba7 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -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) + if(stat & BROKEN) + return -/datum/milla_safe/canister_process + if(valve_open) + var/datum/milla_safe/canister_release/milla = new() + milla.invoke_async(src) -/datum/milla_safe/canister_process/on_run(obj/machinery/atmospherics/portable/canister/canister) - if(canister.stat & BROKEN) - return + if(air_contents.return_pressure() < 1) + can_label = TRUE + else + can_label = FALSE - 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) +/datum/milla_safe/canister_release - 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 +/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/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) + 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 - //Actually transfer the gas - var/datum/gas_mixture/removed = canister.air_contents.remove(transfer_moles) + 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) - environment.merge(removed) - canister.sync_pressure_appearance() + //Actually transfer the gas + var/datum/gas_mixture/removed = canister.air_contents.remove(transfer_moles) - if(canister.air_contents.return_pressure() < 1) - canister.can_label = TRUE - else - canister.can_label = FALSE + environment.merge(removed) + canister.sync_pressure_appearance() /obj/machinery/atmospherics/portable/canister/return_obj_air() RETURN_TYPE(/datum/gas_mixture) diff --git a/code/modules/atmospherics/machinery/portable/portable_pump.dm b/code/modules/atmospherics/machinery/portable/portable_pump.dm index 8821a9331033..9adab28c93cc 100644 --- a/code/modules/atmospherics/machinery/portable/portable_pump.dm +++ b/code/modules/atmospherics/machinery/portable/portable_pump.dm @@ -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/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) - - 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) - - //Actually transfer the gas - var/datum/gas_mixture/removed - removed = environment.remove(transfer_moles) - - pump.air_contents.merge(removed) + 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) + + //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 + + 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) + + pump.air_contents.merge(removed) /obj/machinery/atmospherics/portable/pump/return_obj_air() RETURN_TYPE(/datum/gas_mixture) diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm index df888f2dcceb..71e1af7f9b76 100644 --- a/code/modules/atmospherics/machinery/portable/scrubber.dm +++ b/code/modules/atmospherics/machinery/portable/scrubber.dm @@ -46,18 +46,18 @@ /obj/machinery/atmospherics/portable/scrubber/process_atmos() ..() - var/datum/milla_safe/portable_scrubber_process/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) + if(!on) return - if(scrubber.holding_tank) - scrubber.scrub(scrubber.holding_tank.air_contents) + 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_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)