"
+ ui_dat += ""
+ // Now generate the other list
+ for(var/x in zlevel_turf_indexes["[z_to_view]"])
+ var/turf/T = x
+ turf_markers += "s([T.x],[T.y]);"
+ CHECK_TICK
+
+ ui_dat += ""
+
+ vis.set_content(ui_dat.Join(""))
+ vis.open(FALSE)
+
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 63395600f6b..9d6c3c18bf4 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -2091,7 +2091,9 @@
if("Fire Death")
to_chat(M,"You feel hotter than usual. Maybe you should lowe-wait, is that your hand melting?")
var/turf/simulated/T = get_turf(M)
- new /obj/effect/hotspot(T)
+ var/obj/effect/hotspot/hotspot = new /obj/effect/hotspot/fake(T)
+ hotspot.temperature = 1000
+ hotspot.recolor()
M.adjustFireLoss(150)
logmsg = "a firey death."
if("Gib")
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index f3ae480e707..fadea2b8892 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -262,13 +262,13 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
if(!isturf(T))
return
- var/datum/gas_mixture/env = T.return_air()
+ var/datum/gas_mixture/env = T.get_readonly_air()
var/t = ""
- t+= "Nitrogen : [env.nitrogen]\n"
- t+= "Oxygen : [env.oxygen]\n"
- t+= "Plasma : [env.toxins]\n"
- t+= "CO2: [env.carbon_dioxide]\n"
+ t+= "Nitrogen : [env.nitrogen()]\n"
+ t+= "Oxygen : [env.oxygen()]\n"
+ t+= "Plasma : [env.toxins()]\n"
+ t+= "CO2: [env.carbon_dioxide()]\n"
usr.show_message(t, 1)
SSblackbox.record_feedback("tally", "admin_verb", 1, "Air Status (Location)") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
@@ -736,7 +736,7 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
if(Rad.anchored)
if(!Rad.loaded_tank)
var/obj/item/tank/internals/plasma/Plasma = new/obj/item/tank/internals/plasma(Rad)
- Plasma.air_contents.toxins = 70
+ Plasma.air_contents.set_toxins(70)
Rad.drainratio = 0
Rad.loaded_tank = Plasma
Plasma.loc = Rad
@@ -930,66 +930,6 @@ GLOBAL_PROTECT(AdminProcCallSpamPrevention)
to_chat(src, "You can now right click to use inspect on browsers.")
winset(src, "", "browser-options=byondstorage,find,devtools")
-/client/proc/visualise_active_turfs()
- set category = "Debug"
- set name = "Visualise Active Turfs"
-
- if(!check_rights(R_DEBUG | R_VIEWRUNTIMES))
- return
-
- // This can potentially iterate through a list thats 20k things long. Give ample warning to the user
- var/confirm = alert(usr, "WARNING: This process is lag intensive and should only be used if the atmos controller is screaming bloody murder. Are you sure you with to continue", "WARNING", "Im sure", "Nope")
- if(confirm != "Im sure")
- return
-
- var/display_turfs_overlay = FALSE
- var/do_display_turf_overlay = alert(usr, "Would you like to have all active turfs have a client side overlay applied as well?", "Optional", "Yep", "Nope")
- if(do_display_turf_overlay == "Yep")
- display_turfs_overlay = TRUE
-
- message_admins("[key_name_admin(usr)] is visualising active atmos turfs. Server may lag.")
-
- var/list/zlevel_turf_indexes = list()
-
- for(var/i in SSair.active_turfs)
- var/turf/T = i
- // ENSURE YOU USE STRING NUMBERS HERE, THIS IS A DICTIONARY KEY NOT AN INDEX!!!
- if(!zlevel_turf_indexes["[T.z]"])
- zlevel_turf_indexes["[T.z]"] = list()
- zlevel_turf_indexes["[T.z]"] |= T
- if(display_turfs_overlay)
- usr.client.images += image('icons/effects/alphacolors.dmi', T, "red")
- CHECK_TICK
-
- // Sort the keys
- zlevel_turf_indexes = sortAssoc(zlevel_turf_indexes)
-
- for(var/key in zlevel_turf_indexes)
- to_chat(usr, "Z[key]: [length(zlevel_turf_indexes["[key]"])] ATs")
-
- var/z_to_view = input(usr, "A list of z-levels their ATs has appeared in chat. Please enter a Z to visualise. Enter 0 to cancel.", "Selection", 0) as num
-
- if(!z_to_view)
- return
-
- // Do not combine these
- var/list/ui_dat = list()
- var/list/turf_markers = list()
-
- var/datum/browser/vis = new(usr, "atvis", "Active Turfs (Z[z_to_view])", 300, 315)
- ui_dat += "
"
- ui_dat += ""
- // Now generate the other list
- for(var/x in zlevel_turf_indexes["[z_to_view]"])
- var/turf/T = x
- turf_markers += "s([T.x],[T.y]);"
- CHECK_TICK
-
- ui_dat += ""
-
- vis.set_content(ui_dat.Join(""))
- vis.open(FALSE)
-
/client/proc/cmd_clean_radiation()
set name = "Remove All Radiation"
set desc = "Remove all radiation in the world."
diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm
index 3d672ab6ef3..ddcadec0550 100644
--- a/code/modules/admin/verbs/diagnostics.dm
+++ b/code/modules/admin/verbs/diagnostics.dm
@@ -8,14 +8,14 @@
if(!isturf(target))
return
- var/datum/gas_mixture/GM = target.return_air()
+ var/datum/gas_mixture/GM = target.get_readonly_air()
var/burning = 0
if(issimulatedturf(target))
var/turf/simulated/T = target
if(T.active_hotspot)
burning = 1
- to_chat(usr, "@[target.x],[target.y]: O:[GM.oxygen] T:[GM.toxins] N:[GM.nitrogen] C:[GM.carbon_dioxide] N2O: [GM.sleeping_agent] Agent B: [GM.agent_b] w [GM.temperature] Kelvin, [GM.return_pressure()] kPa [(burning)?("BURNING"):(null)]")
+ to_chat(usr, "@[target.x],[target.y]: O:[GM.oxygen()] T:[GM.toxins()] N:[GM.nitrogen()] C:[GM.carbon_dioxide()] N2O: [GM.sleeping_agent()] Agent B: [GM.agent_b()] w [GM.temperature()] Kelvin, [GM.return_pressure()] kPa [(burning)?("BURNING"):(null)]")
message_admins("[key_name_admin(usr)] has checked the air status of [target]")
log_admin("[key_name(usr)] has checked the air status of [target]")
diff --git a/code/modules/assembly/bomb.dm b/code/modules/assembly/bomb.dm
index 316bf9142f6..6cd315d4ded 100644
--- a/code/modules/assembly/bomb.dm
+++ b/code/modules/assembly/bomb.dm
@@ -54,14 +54,14 @@
return
if(!status)
status = TRUE
- investigate_log("[key_name(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", INVESTIGATE_BOMB)
- log_game("[key_name(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature - T0C]")
+ investigate_log("[key_name(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature() - T0C]", INVESTIGATE_BOMB)
+ log_game("[key_name(user)] welded a single tank bomb. Temperature: [bombtank.air_contents.temperature() - T0C]")
to_chat(user, "A pressure hole has been bored to [bombtank] valve. [bombtank] can now be ignited.")
- add_attack_logs(user, src, "welded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", ATKLOG_FEW)
+ add_attack_logs(user, src, "welded a single tank bomb. Temperature: [bombtank.air_contents.temperature() - T0C]", ATKLOG_FEW)
else
status = FALSE
- investigate_log("[key_name(user)] unwelded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", INVESTIGATE_BOMB)
- add_attack_logs(user, src, "unwelded a single tank bomb. Temperature: [bombtank.air_contents.temperature-T0C]", ATKLOG_ALMOSTALL)
+ investigate_log("[key_name(user)] unwelded a single tank bomb. Temperature: [bombtank.air_contents.temperature() - T0C]", INVESTIGATE_BOMB)
+ add_attack_logs(user, src, "unwelded a single tank bomb. Temperature: [bombtank.air_contents.temperature() - T0C]", ATKLOG_ALMOSTALL)
to_chat(user, "The hole has been closed.")
@@ -117,14 +117,14 @@
return
/obj/item/tank/proc/detonate() //This happens when a bomb is told to explode
- var/fuel_moles = air_contents.toxins + air_contents.oxygen / 6
+ var/fuel_moles = air_contents.toxins() + air_contents.oxygen() / 6
var/strength = 1
var/turf/ground_zero = get_turf(loc)
loc = null
- if(air_contents.temperature > (T0C + 400))
- strength = (fuel_moles/15)
+ if(air_contents.temperature() > (T0C + 400))
+ strength = (fuel_moles / 15)
if(strength >=1)
explosion(ground_zero, round(strength,1), round(strength*2,1), round(strength*3,1), round(strength*4,1))
@@ -133,34 +133,33 @@
else if(strength >=0.2)
explosion(ground_zero, -1, 0, 1, 2)
else
- ground_zero.assume_air(air_contents)
+ ground_zero.blind_release_air(air_contents)
ground_zero.hotspot_expose(1000, 125)
- else if(air_contents.temperature > (T0C + 250))
+ else if(air_contents.temperature() > (T0C + 250))
strength = (fuel_moles/20)
if(strength >=1)
- explosion(ground_zero, 0, round(strength,1), round(strength*2,1), round(strength*3,1))
+ explosion(ground_zero, 0, round(strength, 1), round(strength * 2, 1), round(strength * 3, 1))
else if(strength >=0.5)
explosion(ground_zero, -1, 0, 1, 2)
else
- ground_zero.assume_air(air_contents)
+ ground_zero.blind_release_air(air_contents)
ground_zero.hotspot_expose(1000, 125)
- else if(air_contents.temperature > (T0C + 100))
- strength = (fuel_moles/25)
+ else if(air_contents.temperature() > (T0C + 100))
+ strength = (fuel_moles / 25)
- if(strength >=1)
- explosion(ground_zero, -1, 0, round(strength,1), round(strength*3,1))
+ if(strength >= 1)
+ explosion(ground_zero, -1, 0, round(strength, 1), round(strength * 3, 1))
else
- ground_zero.assume_air(air_contents)
+ ground_zero.blind_release_air(air_contents)
ground_zero.hotspot_expose(1000, 125)
else
- ground_zero.assume_air(air_contents)
+ ground_zero.blind_release_air(air_contents)
ground_zero.hotspot_expose(1000, 125)
- air_update_turf()
if(master)
qdel(master)
qdel(src)
@@ -170,5 +169,4 @@
var/turf/simulated/T = get_turf(src)
if(!T)
return
- T.assume_air(removed)
- air_update_turf()
+ T.blind_release_air(removed)
diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm
index aae9e9ba296..8369f439e8c 100644
--- a/code/modules/atmospherics/environmental/LINDA_fire.dm
+++ b/code/modules/atmospherics/environmental/LINDA_fire.dm
@@ -4,44 +4,37 @@
reagents.temperature_reagents(exposed_temperature)
return null
-
-
/turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
- return
-
+ return FALSE
/turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
- var/datum/gas_mixture/air_contents = return_air()
if(reagents)
reagents.temperature_reagents(exposed_temperature, 10, 300)
- if(!air_contents)
- return 0
+ if(!issimulatedturf(src))
+ return FALSE
+ var/datum/gas_mixture/air = get_readonly_air()
+ if(!air)
+ return FALSE
if(active_hotspot)
if(soh)
- if(air_contents.toxins > 0.5 && air_contents.oxygen > 0.5)
+ if(air.toxins() > 0.5 && air.oxygen() > 0.5)
if(active_hotspot.temperature < exposed_temperature)
active_hotspot.temperature = exposed_temperature
if(active_hotspot.volume < exposed_volume)
active_hotspot.volume = exposed_volume
- return 1
-
- var/igniting = 0
-
- if((exposed_temperature > PLASMA_MINIMUM_BURN_TEMPERATURE) && air_contents.toxins > 0.5)
- igniting = 1
-
- if(igniting)
- if(air_contents.oxygen < 0.5 || air_contents.toxins < 0.5)
- return 0
+ return TRUE
+ if(exposed_temperature > PLASMA_MINIMUM_BURN_TEMPERATURE && air.oxygen() > 0.5 && air.toxins() > 0.5)
+ var/total = air.total_moles()
+ if(air.toxins() < 0.01 * total || air.oxygen() < 0.01 * total)
+ // The rest of the gas is snuffing out the reaction.
+ return FALSE
active_hotspot = new /obj/effect/hotspot(src)
active_hotspot.temperature = exposed_temperature
active_hotspot.volume = exposed_volume
+ return TRUE
- active_hotspot.just_spawned = (current_cycle < SSair.times_fired)
- //remove just_spawned protection if no longer processing this cell
- SSair.add_to_active(src, 0)
- return igniting
+ return FALSE
//This is the icon for fire on turfs, also helps for nurturing small fires until they are full tile
/obj/effect/hotspot
@@ -56,8 +49,6 @@
var/volume = 125
var/temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
- var/just_spawned = 1
- var/bypassing = 0
var/fake = FALSE
var/burn_time = 0
@@ -65,76 +56,119 @@
..()
if(!fake)
SSair.hotspots += src
- perform_exposure()
+ var/datum/milla_safe/hotspot_burn_plasma/milla = new()
+ milla.invoke_async(src)
dir = pick(GLOB.cardinal)
- air_update_turf()
-/obj/effect/hotspot/proc/perform_exposure()
+/datum/milla_safe/hotspot_burn_plasma
+
+/// Burns the air affected by this hotspot. A hotspot is effectively a gas fire that might not cover the entire tile yet. This proc makes that "partial fire" burn, altering the tile as a whole, and potentially setting the entire tile on fire.
+/datum/milla_safe/hotspot_burn_plasma/on_run(obj/effect/hotspot/hotspot)
+ var/turf/simulated/location = get_turf(hotspot)
+ if(!istype(location) || location.blocks_air)
+ // We're in the wrong neighborhood.
+ qdel(hotspot)
+ return
+
+ var/datum/gas_mixture/location_air = get_turf_air(location)
+ if(location_air.temperature() >= min(hotspot.temperature, PLASMA_UPPER_TEMPERATURE))
+ // The cell is already hot enough, no need to do more.
+ hotspot.temperature = location_air.temperature()
+ hotspot.volume = CELL_VOLUME
+ hotspot.recolor()
+ return
+
+ if(location_air.toxins() < 0.5 || location_air.oxygen() < 0.5)
+ // Burn what, exactly?
+ qdel(hotspot)
+ return
+
+ var/total = location_air.total_moles()
+ if(location_air.toxins() < 0.01 * total || location_air.oxygen() < 0.01 * total)
+ // The rest of the gas is snuffing out the reaction.
+ qdel(hotspot)
+ return
+
+ // Get some of the surrounding air for the hotspot to burn.
+ var/datum/gas_mixture/burning = location_air.remove_ratio(hotspot.volume / location_air.volume)
+
+ // Temporarily boost the temperature of this air to the hotspot temperature.
+ var/old_temperature = burning.temperature()
+ burning.set_temperature(hotspot.temperature)
+
+ // Record how much plasma we had initially.
+ var/old_toxins = burning.toxins()
+
+ // Burn it.
+ burning.react()
+
+ // Calculate how much thermal energy was produced.
+ // (Yes, gas_mixture has its own .fuel_burnt, but I dont' trust that code.)
+ var/fuel_burnt = old_toxins - burning.toxins()
+ var/thermal_energy = FIRE_PLASMA_ENERGY_RELEASED * fuel_burnt
+
+ // Update the hotspot based on the reaction.
+ hotspot.temperature = burning.temperature()
+ hotspot.volume = min(CELL_VOLUME, fuel_burnt * FIRE_GROWTH_RATE)
+ hotspot.recolor()
+
+ // Revert the air's temperature to where it started.
+ burning.set_temperature(old_temperature)
+
+ var/heat_capacity = burning.heat_capacity()
+ if(heat_capacity)
+ // Add in the produced thermal energy.
+ burning.set_temperature(burning.temperature() + thermal_energy / burning.heat_capacity())
+
+ // And add it back to the tile.
+ location_air.merge(burning)
+
+/obj/effect/hotspot/process()
var/turf/simulated/location = loc
- if(!istype(location) || !(location.air))
- return FALSE
+ if(!istype(location))
+ qdel(src)
+ return
- if(volume > CELL_VOLUME * 0.95)
- bypassing = TRUE
- else
- bypassing = FALSE
+ if((temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) || (volume <= 1))
+ qdel(src)
+ return
- if(bypassing)
- if(!just_spawned)
- volume = location.air.fuel_burnt * FIRE_GROWTH_RATE
- temperature = location.air.temperature
- else
- var/datum/gas_mixture/affected = location.air.remove_ratio(volume / location.air.volume)
- affected.temperature = temperature
- affected.react()
- temperature = affected.temperature
- volume = affected.fuel_burnt * FIRE_GROWTH_RATE
- location.assume_air(affected)
+ var/datum/gas_mixture/location_air = location.get_readonly_air()
+ if(location.blocks_air || location_air.toxins() < 0.5 || location_air.oxygen() < 0.5)
+ qdel(src)
+ return
+
+ var/datum/milla_safe/hotspot_burn_plasma/milla = new()
+ milla.invoke_async(src)
+ if(QDELETED(src))
+ return
for(var/A in loc)
var/atom/item = A
if(!QDELETED(item) && item != src) // It's possible that the item is deleted in temperature_expose
item.fire_act(null, temperature, volume)
- color = heat2color(temperature)
- set_light(l_color = color)
- return FALSE
-
-
-/obj/effect/hotspot/process()
- if(just_spawned)
- just_spawned = 0
- return 0
-
- var/turf/simulated/location = loc
if(!istype(location))
- qdel(src)
+ // We are now space. No need to do anything else.
return
- if(location.excited_group)
- location.excited_group.reset_cooldowns()
+ if(location.wet)
+ location.wet = TURF_DRY
- if((temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) || (volume <= 1))
- qdel(src)
- return
-
- if(!(location.air) || location.air.toxins < 0.5 || location.air.oxygen < 0.5)
- qdel(src)
- return
-
- perform_exposure()
-
- if(location.wet) location.wet = TURF_DRY
-
- if(bypassing)
+ if(volume >= CELL_VOLUME * 0.95)
icon_state = "3"
location.burn_tile()
//Possible spread due to radiated heat
- if(location.air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_SPREAD)
- var/radiated_temperature = location.air.temperature*FIRE_SPREAD_RADIOSITY_SCALE
- for(var/turf/simulated/T in location.atmos_adjacent_turfs)
- if(!T.active_hotspot)
+ if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_SPREAD)
+ var/radiated_temperature = temperature * FIRE_SPREAD_RADIOSITY_SCALE
+ for(var/direction in GLOB.cardinal)
+ var/turf/simulated/T = get_step(location, direction)
+ if(!istype(T))
+ continue
+ if(T.active_hotspot)
+ continue
+ if(src.CanAtmosPass(direction) && T.CanAtmosPass(turn(direction, 180)))
T.hotspot_expose(radiated_temperature, CELL_VOLUME / 4)
else
@@ -147,7 +181,7 @@
location.max_fire_temperature_sustained = temperature
if(location.heat_capacity && temperature > location.heat_capacity)
- location.to_be_destroyed = 1
+ location.to_be_destroyed = TRUE
/*if(prob(25))
location.ReplaceWithSpace()
return 0*/
@@ -165,6 +199,10 @@
DestroyTurf()
return ..()
+/obj/effect/hotspot/proc/recolor()
+ color = heat2color(temperature)
+ set_light(l_color = color)
+
/obj/effect/hotspot/proc/DestroyTurf()
if(issimulatedturf(loc))
var/turf/simulated/T = loc
@@ -212,8 +250,7 @@
var/obj/effect/hotspot/fake/H = new(T)
H.temperature = temp
H.volume = 400
- H.color = heat2color(H.temperature)
- H.set_light(l_color = H.color)
+ H.recolor()
T.hotspot_expose(H.temperature, H.volume)
for(var/atom/A in T)
@@ -270,8 +307,7 @@
H.temperature = temp - dist * falloff
expose_temp = H.temperature
H.volume = 400
- H.color = heat2color(H.temperature)
- H.set_light(l_color = H.color)
+ H.recolor()
existing_hotspot = H
else if(existing_hotspot.temperature < temp - dist * falloff)
@@ -280,8 +316,7 @@
if(expose_temp > prev_temp * 3)
need_expose = TRUE
existing_hotspot.temperature = temp - dist * falloff
- existing_hotspot.color = heat2color(existing_hotspot.temperature)
- existing_hotspot.set_light(l_color = existing_hotspot.color)
+ existing_hotspot.recolor()
affected[T] = existing_hotspot.temperature
if(need_expose && expose_temp)
@@ -310,12 +345,12 @@
if(dist == max_dist)
continue
- for(var/dir in GLOB.cardinal)
- var/turf/link = get_step(T, dir)
+ for(var/direction in GLOB.cardinal)
+ var/turf/link = get_step(T, direction)
if(!link)
continue
// Check if it wasn't already visited and if you can get to that turf
- if(!closed[link] && T.CanAtmosPass(link))
+ if(!closed[link] && T.CanAtmosPass(direction) && link.CanAtmosPass(turn(direction, 180)))
var/dx = link.x - Ce.x
var/dy = link.y - Ce.y
var/target_dist = max((dist + 1 + sqrt(dx * dx + dy * dy)) / 2, dist)
diff --git a/code/modules/atmospherics/environmental/LINDA_system.dm b/code/modules/atmospherics/environmental/LINDA_system.dm
index d8f0c27dccb..69975f0b658 100644
--- a/code/modules/atmospherics/environmental/LINDA_system.dm
+++ b/code/modules/atmospherics/environmental/LINDA_system.dm
@@ -1,39 +1,22 @@
-/turf/proc/CanAtmosPass(turf/T)
- if(!istype(T)) return 0
- var/R
- if(blocks_air || T.blocks_air)
- R = 1
+/turf/proc/CanAtmosPass(direction, consider_objects = TRUE)
+ if(blocks_air)
+ return FALSE
+
+ if(!consider_objects)
+ return TRUE
for(var/obj/O in contents)
- if(!O.CanAtmosPass(T))
- R = 1
- if(O.BlockSuperconductivity()) //the direction and open/closed are already checked on CanAtmosPass() so there are no arguments
- var/D = get_dir(src, T)
- atmos_superconductivity |= D
- D = get_dir(T, src)
- T.atmos_superconductivity |= D
- return 0 //no need to keep going, we got all we asked
+ if(istype(O, /obj/item))
+ // Items can't block atmos.
+ continue
- for(var/obj/O in T.contents)
- if(!O.CanAtmosPass(src))
- R = 1
- if(O.BlockSuperconductivity())
- var/D = get_dir(src, T)
- atmos_superconductivity |= D
- D = get_dir(T, src)
- T.atmos_superconductivity |= D
- return 0
+ if(!O.CanAtmosPass(direction))
+ return FALSE
- var/D = get_dir(src, T)
- atmos_superconductivity &= ~D
- D = get_dir(T, src)
- T.atmos_superconductivity &= ~D
-
- if(!R)
- return 1
+ return TRUE
/atom/movable/proc/CanAtmosPass()
- return 1
+ return TRUE
/atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5)
return (!density || !height)
@@ -57,20 +40,17 @@
return 1
-/atom/movable/proc/BlockSuperconductivity() // objects that block air and don't let superconductivity act. Only firelocks atm.
- return 0
+/atom/movable/proc/get_superconductivity(direction)
+ return OPEN_HEAT_TRANSFER_COEFFICIENT
-/turf/proc/CalculateAdjacentTurfs()
- for(var/direction in GLOB.cardinal)
- var/turf/T = get_step(src, direction)
- if(!istype(T))
- continue
- if(CanAtmosPass(T))
- atmos_adjacent_turfs |= T
- T.atmos_adjacent_turfs |= src
- else
- atmos_adjacent_turfs -= T
- T.atmos_adjacent_turfs -= src
+/atom/movable/proc/recalculate_atmos_connectivity()
+ for(var/turf/T in locs) // used by double wide doors and other nonexistant multitile structures
+ T.recalculate_atmos_connectivity()
+
+/atom/movable/proc/move_update_air(turf/T)
+ if(isturf(T))
+ T.recalculate_atmos_connectivity()
+ recalculate_atmos_connectivity()
//returns a list of adjacent turfs that can share air with this one.
//alldir includes adjacent diagonal tiles that can share
@@ -79,89 +59,87 @@
if(!issimulatedturf(src))
return list()
- var/adjacent_turfs = atmos_adjacent_turfs.Copy()
+ var/adjacent_turfs = list()
+ for(var/turf/T in RANGE_EDGE_TURFS(1, src))
+ var/direction = get_dir(src, T)
+ if(!CanAtmosPass(direction))
+ continue
+ if(!T.CanAtmosPass(turn(direction, 180)))
+ continue
+ adjacent_turfs += T
+
if(!alldir)
return adjacent_turfs
- var/turf/simulated/curloc = src
- for(var/direction in GLOB.diagonals)
- var/matchingDirections = 0
- var/turf/simulated/S = get_step(curloc, direction)
- for(var/checkDirection in GLOB.cardinal)
- var/turf/simulated/checkTurf = get_step(S, checkDirection)
- if(!(checkTurf in S.atmos_adjacent_turfs))
+ for(var/turf/T in RANGE_TURFS(1, src))
+ var/direction = get_dir(src, T)
+ if(IS_DIR_CARDINAL(direction))
+ continue
+ // check_direction is the first way we move, from src
+ for(var/check_direction in GLOB.cardinal)
+ if(!(check_direction & direction))
+ // Wrong way.
continue
- if(checkTurf in adjacent_turfs)
- matchingDirections++
+ var/turf/intermediate = get_step(src, check_direction)
+ if(!(intermediate in adjacent_turfs))
+ continue
- if(matchingDirections >= 2)
- adjacent_turfs += S
- break
+ // other_direction is the second way we move, from intermediate.
+ var/other_direction = direction & ~check_direction
+
+ // We already know we can reach intermediate, so now we just need to check the second step.
+ if(!intermediate.CanAtmosPass(other_direction))
+ continue
+ if(!T.CanAtmosPass(turn(other_direction, 180)))
+ continue
+
+ adjacent_turfs += T
+ break
return adjacent_turfs
-/atom/movable/proc/air_update_turf(command = 0)
- if(!isturf(loc) && command)
- return
- for(var/turf/T in locs) // used by double wide doors and other nonexistant multitile structures
- T.air_update_turf(command)
-
-/turf/proc/air_update_turf(command = 0)
- if(command)
- CalculateAdjacentTurfs()
- if(SSair)
- SSair.add_to_active(src,command)
-
-/atom/movable/proc/move_update_air(turf/T)
- if(isturf(T))
- T.air_update_turf(1)
- air_update_turf(1)
-
-
-
-/atom/movable/proc/atmos_spawn_air(text, amount) //because a lot of people loves to copy paste awful code lets just make a easy proc to spawn your plasma fires
+/atom/movable/proc/atmos_spawn_air(flag, amount) //because a lot of people loves to copy paste awful code lets just make a easy proc to spawn your plasma fires
var/turf/simulated/T = get_turf(src)
if(!istype(T))
return
- T.atmos_spawn_air(text, amount)
+ T.atmos_spawn_air(flag, amount)
/turf/simulated/proc/atmos_spawn_air(flag, amount)
- if(!text || !amount || !air)
+ if(!flag || !amount || blocks_air)
return
- var/datum/gas_mixture/G = new
+ var/datum/gas_mixture/G = new()
if(flag & LINDA_SPAWN_20C)
- G.temperature = T20C
+ G.set_temperature(T20C)
if(flag & LINDA_SPAWN_HEAT)
- G.temperature += 1000
+ G.set_temperature(G.temperature() + 1000)
if(flag & LINDA_SPAWN_COLD)
- G.temperature = TCMB
+ G.set_temperature(TCMB)
if(flag & LINDA_SPAWN_TOXINS)
- G.toxins += amount
+ G.set_toxins(G.toxins() + amount)
if(flag & LINDA_SPAWN_OXYGEN)
- G.oxygen += amount
+ G.set_oxygen(G.oxygen() + amount)
if(flag & LINDA_SPAWN_CO2)
- G.carbon_dioxide += amount
+ G.set_carbon_dioxide(G.carbon_dioxide() + amount)
if(flag & LINDA_SPAWN_NITROGEN)
- G.nitrogen += amount
+ G.set_nitrogen(G.nitrogen() + amount)
if(flag & LINDA_SPAWN_N2O)
- G.sleeping_agent += amount
+ G.set_sleeping_agent(G.sleeping_agent() + amount)
if(flag & LINDA_SPAWN_AGENT_B)
- G.agent_b += amount
+ G.set_agent_b(G.agent_b() + amount)
if(flag & LINDA_SPAWN_AIR)
- G.oxygen += MOLES_O2STANDARD * amount
- G.nitrogen += MOLES_N2STANDARD * amount
+ G.set_oxygen(G.oxygen() + MOLES_O2STANDARD * amount)
+ G.set_nitrogen(G.nitrogen() + MOLES_N2STANDARD * amount)
- air.merge(G)
- SSair.add_to_active(src, 0)
+ blind_release_air(G)
diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
index 82cd7383c15..a629c4dec32 100644
--- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
+++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
@@ -1,103 +1,33 @@
-/turf/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air
- qdel(giver)
- return 0
-
-/turf/return_air()
- RETURN_TYPE(/datum/gas_mixture)
- //Create gas mixture to hold data for passing
- var/datum/gas_mixture/GM = new
-
- GM.oxygen = oxygen
- GM.carbon_dioxide = carbon_dioxide
- GM.nitrogen = nitrogen
- GM.toxins = toxins
- GM.sleeping_agent = sleeping_agent
- GM.agent_b = agent_b
-
- GM.temperature = temperature
-
- return GM
-
-/turf/return_analyzable_air()
- return return_air()
-
-/turf/remove_air(amount)
- var/datum/gas_mixture/GM = new
-
- var/sum = oxygen + carbon_dioxide + nitrogen + toxins + sleeping_agent + agent_b
- if(sum > 0)
- GM.oxygen = (oxygen / sum) * amount
- GM.carbon_dioxide = (carbon_dioxide / sum) * amount
- GM.nitrogen = (nitrogen / sum) * amount
- GM.toxins = (toxins / sum) * amount
- GM.sleeping_agent = (sleeping_agent / sum) * amount
- GM.agent_b = (agent_b / sum) * amount
-
- GM.temperature = temperature
-
- return GM
-
/turf/simulated/Initialize(mapload)
. = ..()
if(!blocks_air)
- air = new
+ blind_set_air(get_initial_air())
- air.oxygen = oxygen
- air.carbon_dioxide = carbon_dioxide
- air.nitrogen = nitrogen
- air.toxins = toxins
- air.sleeping_agent = sleeping_agent
- air.agent_b = agent_b
-
- air.temperature = temperature
+/turf/simulated/proc/get_initial_air()
+ var/datum/gas_mixture/air = new()
+ if(!blocks_air)
+ air.set_oxygen(oxygen)
+ air.set_carbon_dioxide(carbon_dioxide)
+ air.set_nitrogen(nitrogen)
+ air.set_toxins(toxins)
+ air.set_sleeping_agent(sleeping_agent)
+ air.set_agent_b(agent_b)
+ air.set_temperature(temperature)
+ else
+ air.set_oxygen(0)
+ air.set_carbon_dioxide(0)
+ air.set_nitrogen(0)
+ air.set_toxins(0)
+ air.set_sleeping_agent(0)
+ air.set_agent_b(0)
+ air.set_temperature(0)
+ return air
/turf/simulated/Destroy()
QDEL_NULL(active_hotspot)
QDEL_NULL(wet_overlay)
return ..()
-/turf/simulated/assume_air(datum/gas_mixture/giver)
- if(!giver) return 0
- var/datum/gas_mixture/receiver = air
- if(istype(receiver))
-
- air.merge(giver)
-
- update_visuals()
-
- return 1
-
- else return ..()
-
-/turf/simulated/proc/copy_air_with_tile(turf/simulated/T)
- if(istype(T) && T.air && air)
- air.copy_from(T.air)
-
-/turf/simulated/proc/copy_air(datum/gas_mixture/copy)
- if(air && copy)
- air.copy_from(copy)
-
-/turf/simulated/return_air()
- RETURN_TYPE(/datum/gas_mixture)
- if(air)
- return air
-
- else
- return ..()
-
-/turf/simulated/remove_air(amount)
- if(air)
- var/datum/gas_mixture/removed = null
-
- removed = air.remove(amount)
-
- update_visuals()
-
- return removed
-
- else
- return ..()
-
/turf/simulated/proc/mimic_temperature_solid(turf/model, conduction_coefficient)
var/delta_temperature = (temperature_archived - model.temperature)
if((heat_capacity > 0) && (abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER))
@@ -116,131 +46,9 @@
temperature -= heat/heat_capacity
sharer.temperature += heat/sharer.heat_capacity
-/turf/proc/process_cell(fire_count)
- SSair.remove_from_active(src)
-
-/turf/simulated/process_cell(fire_count)
- if(archived_cycle < fire_count) //archive self if not already done
- archive()
- current_cycle = fire_count
-
- var/remove = 1 //set by non simulated turfs who are sharing with this turf
-
- //cache for sanic speed
- var/list/adjacent_turfs = atmos_adjacent_turfs
- var/datum/excited_group/our_excited_group = excited_group
- var/adjacent_turfs_length = length(adjacent_turfs)
-
- if(planetary_atmos)
- adjacent_turfs_length++
-
- for(var/t in adjacent_turfs)
- var/turf/enemy_tile = t
-
- if(issimulatedturf(enemy_tile))
- var/turf/simulated/enemy_simulated = enemy_tile
-
- if(fire_count > enemy_simulated.current_cycle)
- enemy_simulated.archive()
-
- /******************* GROUP HANDLING START *****************************************************************/
-
- if(enemy_simulated.excited)
- //cache for sanic speed
- var/datum/excited_group/enemy_excited_group = enemy_simulated.excited_group
- if(our_excited_group)
- if(enemy_excited_group)
- if(our_excited_group != enemy_excited_group)
- //combine groups (this also handles updating the excited_group var of all involved turfs)
- our_excited_group.merge_groups(enemy_excited_group)
- our_excited_group = excited_group //update our cache
- share_air(enemy_simulated, fire_count, adjacent_turfs_length) //share
- else
- if((recently_active == 1 && enemy_simulated.recently_active == 1) || !air.compare(enemy_simulated.air))
- our_excited_group.add_turf(enemy_simulated) //add enemy to our group
- share_air(enemy_simulated, fire_count, adjacent_turfs_length) //share
- else
- if(enemy_excited_group)
- if((recently_active == 1 && enemy_simulated.recently_active == 1) || !air.compare(enemy_simulated.air))
- enemy_excited_group.add_turf(src) //join self to enemy group
- our_excited_group = excited_group //update our cache
- share_air(enemy_simulated, fire_count, adjacent_turfs_length) //share
- else
- if((recently_active == 1 && enemy_simulated.recently_active == 1) || !air.compare(enemy_simulated.air))
- var/datum/excited_group/EG = new //generate new group
- EG.add_turf(src)
- EG.add_turf(enemy_simulated)
- our_excited_group = excited_group //update our cache
- share_air(enemy_simulated, fire_count, adjacent_turfs_length) //share
- else
- if(!air.compare(enemy_simulated.air)) //compare if
- SSair.add_to_active(enemy_simulated) //excite enemy
- if(our_excited_group)
- excited_group.add_turf(enemy_simulated) //add enemy to group
- else
- var/datum/excited_group/EG = new //generate new group
- EG.add_turf(src)
- EG.add_turf(enemy_simulated)
- our_excited_group = excited_group //update our cache
- share_air(enemy_simulated, fire_count, adjacent_turfs_length) //share
-
- /******************* GROUP HANDLING FINISH *********************************************************************/
-
- else
- if(!air.check_turf(enemy_tile, adjacent_turfs_length))
- var/difference = air.mimic(enemy_tile, adjacent_turfs_length)
- if(difference)
- if(difference > 0)
- consider_pressure_difference(enemy_tile, difference)
- else
- enemy_tile.consider_pressure_difference(src, difference)
- remove = 0
- if(our_excited_group)
- last_share_check()
-
- if(planetary_atmos) //share our air with the "atmosphere" "above" the turf
- var/datum/gas_mixture/G = new
- G.oxygen = oxygen
- G.carbon_dioxide = carbon_dioxide
- G.nitrogen = nitrogen
- G.toxins = toxins
- G.sleeping_agent = sleeping_agent
- G.agent_b = agent_b
- G.temperature = initial(temperature) // Temperature is modified at runtime; we only care about the turf's initial temperature
- G.archive()
- if(!air.compare(G))
- if(!our_excited_group)
- var/datum/excited_group/EG = new
- EG.add_turf(src)
- our_excited_group = excited_group
- air.share(G, adjacent_turfs_length)
- last_share_check()
-
- air.react()
-
- update_visuals()
-
- if(air.temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
- hotspot_expose(air.temperature, CELL_VOLUME)
- for(var/atom/movable/item in src)
- item.temperature_expose(air, air.temperature, CELL_VOLUME)
- temperature_expose(air, air.temperature, CELL_VOLUME)
-
- if(air.temperature > MINIMUM_TEMPERATURE_START_SUPERCONDUCTION)
- if(consider_superconductivity(starting = 1))
- remove = 0
-
- if(!our_excited_group && remove == 1)
- SSair.remove_from_active(src)
-
-/turf/simulated/proc/archive()
- if(air) //For open space like floors
- air.archive()
- temperature_archived = temperature
- archived_cycle = SSair.times_fired
-
/turf/simulated/proc/update_visuals()
- var/new_overlay_type = tile_graphic()
+ var/datum/gas_mixture/air = get_readonly_air()
+ var/new_overlay_type = tile_graphic(air)
if(new_overlay_type == atmos_overlay_type)
return
var/atmos_overlay = get_atmos_overlay_by_name(atmos_overlay_type)
@@ -261,38 +69,19 @@
return GLOB.slmaster
return null
-/turf/simulated/proc/tile_graphic()
- if(!air)
+/turf/simulated/proc/tile_graphic(datum/gas_mixture/air)
+ if(blocks_air)
return
- if(air.toxins > MOLES_PLASMA_VISIBLE)
+ if(!istype(air))
+ air = get_readonly_air()
+ if(air.toxins() > MOLES_PLASMA_VISIBLE)
return "plasma"
- if(air.sleeping_agent > 1)
+ if(air.sleeping_agent() > 1)
return "sleeping_agent"
return null
-/turf/simulated/proc/share_air(turf/simulated/T, fire_count, adjacent_turfs_length)
- if(T.current_cycle < fire_count)
- var/difference
- difference = air.share(T.air, adjacent_turfs_length)
- if(difference)
- if(difference > 0)
- consider_pressure_difference(T, difference)
- else
- T.consider_pressure_difference(src, difference)
- last_share_check()
-
-/turf/proc/consider_pressure_difference(turf/simulated/T, difference)
- SSair.high_pressure_delta |= src
- if(difference > pressure_difference)
- pressure_direction = get_dir(src, T)
- pressure_difference = difference
-
-/turf/simulated/proc/last_share_check()
- if(air.last_share > MINIMUM_AIR_TO_SUSPEND)
- excited_group.reset_cooldowns()
-
-/turf/proc/high_pressure_movements()
+/turf/proc/high_pressure_movements(flow_x, flow_y)
var/atom/movable/M
for(var/thing in src)
M = thing
@@ -303,11 +92,13 @@
if(M.pulledby)
continue
if(M.last_high_pressure_movement_air_cycle < SSair.times_fired)
- M.experience_pressure_difference(pressure_difference, pressure_direction)
+ M.experience_pressure_difference(flow_x, flow_y)
-/atom/movable/proc/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0)
+/atom/movable/proc/experience_pressure_difference(flow_x, flow_y, pressure_resistance_prob_delta = 0)
var/const/PROBABILITY_OFFSET = 25
var/const/PROBABILITY_BASE_PRECENT = 75
+
+ var/pressure_difference = sqrt(flow_x ** 2 + flow_y ** 2)
var/max_force = sqrt(pressure_difference) * (MOVE_FORCE_DEFAULT / 5)
set waitfor = 0
var/move_prob = 100
@@ -315,165 +106,19 @@
move_prob = (pressure_difference / pressure_resistance * PROBABILITY_BASE_PRECENT) - PROBABILITY_OFFSET
move_prob += pressure_resistance_prob_delta
if(move_prob > PROBABILITY_OFFSET && prob(move_prob) && (move_resist != INFINITY) && (!anchored && (max_force >= (move_resist * MOVE_FORCE_PUSH_RATIO))) || (anchored && (max_force >= (move_resist * MOVE_FORCE_FORCEPUSH_RATIO))))
+ var/direction = 0
+ if(flow_x > 0.5)
+ direction |= EAST
+ if(flow_x < -0.5)
+ direction |= WEST
+ if(flow_y > 0.5)
+ direction |= NORTH
+ if(flow_y < -0.5)
+ direction |= SOUTH
step(src, direction)
last_high_pressure_movement_air_cycle = SSair.times_fired
-
-
-/datum/excited_group
- var/list/turf_list = list()
- var/breakdown_cooldown = 0
-
-/datum/excited_group/New()
- if(SSair)
- SSair.excited_groups += src
-
-/datum/excited_group/proc/add_turf(turf/simulated/T)
- turf_list += T
- T.excited_group = src
- T.recently_active = 1
- reset_cooldowns()
-
-/datum/excited_group/proc/merge_groups(datum/excited_group/E)
- if(length(turf_list) > length(E.turf_list))
- SSair.excited_groups -= E
- for(var/turf/simulated/T in E.turf_list)
- T.excited_group = src
- turf_list += T
- reset_cooldowns()
- else
- SSair.excited_groups -= src
- for(var/turf/simulated/T in turf_list)
- T.excited_group = E
- E.turf_list += T
- E.reset_cooldowns()
-
-/datum/excited_group/proc/reset_cooldowns()
- breakdown_cooldown = 0
-
-/datum/excited_group/proc/self_breakdown()
- var/datum/gas_mixture/A = new
-
- var/list/cached_turf_list = turf_list // cache for super speed
-
- for(var/turf/simulated/T in cached_turf_list)
- A.oxygen += T.air.oxygen
- A.carbon_dioxide += T.air.carbon_dioxide
- A.nitrogen += T.air.nitrogen
- A.toxins += T.air.toxins
- A.sleeping_agent += T.air.sleeping_agent
- A.agent_b += T.air.agent_b
-
- var/turflen = length(cached_turf_list)
-
- for(var/turf/simulated/T in cached_turf_list)
- T.air.oxygen = A.oxygen / turflen
- T.air.carbon_dioxide = A.carbon_dioxide / turflen
- T.air.nitrogen = A.nitrogen / turflen
- T.air.toxins = A.toxins / turflen
- T.air.sleeping_agent = A.sleeping_agent / turflen
- T.air.agent_b = A.agent_b / turflen
-
- T.update_visuals()
-
-
-/datum/excited_group/proc/dismantle()
- for(var/turf/simulated/T in turf_list)
- T.excited = 0
- T.recently_active = 0
- T.excited_group = null
- SSair.active_turfs -= T
- garbage_collect()
-
-/datum/excited_group/proc/garbage_collect()
- for(var/turf/simulated/T in turf_list)
- T.excited_group = null
- turf_list.Cut()
- SSair.excited_groups -= src
-
-/turf/simulated/proc/super_conduct()
- var/conductivity_directions = 0
- if(blocks_air)
- //Does not participate in air exchange, so will conduct heat across all four borders at this time
- conductivity_directions = NORTH|SOUTH|EAST|WEST
-
- if(archived_cycle < SSair.times_fired)
- archive()
- else
- //Does particate in air exchange so only consider directions not considered during process_cell()
- for(var/direction in GLOB.cardinal)
- var/turf/T = get_step(src, direction)
- if(!(T in atmos_adjacent_turfs) && !(atmos_superconductivity & direction))
- conductivity_directions += direction
-
- if(conductivity_directions > 0)
- //Conduct with tiles around me
- for(var/direction in GLOB.cardinal)
- if(conductivity_directions & direction)
- var/turf/neighbor = get_step(src,direction)
-
- if(!neighbor?.thermal_conductivity)
- continue
-
- if(issimulatedturf(neighbor)) //anything under this subtype will share in the exchange
- var/turf/simulated/T = neighbor
-
- if(T.archived_cycle < SSair.times_fired)
- T.archive()
-
- if(T.air)
- if(air) //Both tiles are open
- air.temperature_share(T.air, WINDOW_HEAT_TRANSFER_COEFFICIENT)
- else //Solid but neighbor is open
- T.air.temperature_turf_share(src, T.thermal_conductivity)
- SSair.add_to_active(T, 0)
- else
- if(air) //Open but neighbor is solid
- air.temperature_turf_share(T, T.thermal_conductivity)
- else //Both tiles are solid
- share_temperature_mutual_solid(T, T.thermal_conductivity)
- T.temperature_expose(null, T.temperature, null)
-
- T.consider_superconductivity()
-
- else
- if(air) //Open
- air.temperature_mimic(neighbor, neighbor.thermal_conductivity)
- else
- mimic_temperature_solid(neighbor, neighbor.thermal_conductivity)
-
- if(!planetary_atmos)
- radiate_to_spess()
-
- //Conduct with air on my tile if I have it
- if(air)
- air.temperature_turf_share(src, thermal_conductivity)
-
- //Make sure still hot enough to continue conducting heat
- if(air.temperature < MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION)
- SSair.active_super_conductivity -= src
- return 0
-
- else
- if(temperature < MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION)
- SSair.active_super_conductivity -= src
- return 0
-
-/turf/simulated/proc/consider_superconductivity(starting)
- if(!thermal_conductivity)
- return 0
-
- if(air)
- if(air.temperature < (starting?MINIMUM_TEMPERATURE_START_SUPERCONDUCTION:MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION))
- return 0
- if(air.heat_capacity() < M_CELL_WITH_RATIO) // Was: MOLES_CELLSTANDARD*0.1*0.05 Since there are no variables here we can make this a constant.
- return 0
- else
- if(temperature < (starting?MINIMUM_TEMPERATURE_START_SUPERCONDUCTION:MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION))
- return 0
-
- SSair.active_super_conductivity |= src
- return 1
+ return pressure_difference
/turf/simulated/proc/radiate_to_spess() //Radiate excess tile heat to space
if(temperature > T0C) //Considering 0 degC as te break even point for radiation in and out
@@ -484,21 +129,76 @@
(heat_capacity*HEAT_CAPACITY_VACUUM/(heat_capacity+HEAT_CAPACITY_VACUUM)) //700000 is the heat_capacity from a space turf, hardcoded here
temperature -= heat/heat_capacity
-/turf/proc/Initialize_Atmos(times_fired)
- CalculateAdjacentTurfs()
+#define INDEX_NORTH 1
+#define INDEX_EAST 2
+#define INDEX_SOUTH 3
+#define INDEX_WEST 4
-/turf/simulated/Initialize_Atmos(times_fired)
- ..()
- update_visuals()
- for(var/tile in atmos_adjacent_turfs)
- var/turf/enemy_tile = tile
- if(issimulatedturf(enemy_tile))
- var/turf/simulated/enemy_simulated = enemy_tile
- if(!air.compare(enemy_simulated.air))
- excited = 1
- SSair.active_turfs |= src
- break
- else
- if(!air.check_turf_total(enemy_tile))
- excited = 1
- SSair.active_turfs |= src
+/turf/proc/Initialize_Atmos(times_fired)
+ recalculate_atmos_connectivity()
+
+ if(!blocks_air)
+ var/datum/gas_mixture/air = new()
+ air.set_oxygen(oxygen)
+ air.set_carbon_dioxide(carbon_dioxide)
+ air.set_nitrogen(nitrogen)
+ air.set_toxins(toxins)
+ air.set_sleeping_agent(sleeping_agent)
+ air.set_agent_b(agent_b)
+ air.set_temperature(temperature)
+ blind_set_air(air)
+
+/turf/proc/recalculate_atmos_connectivity()
+ var/datum/milla_safe/recalculate_atmos_connectivity/milla = new()
+ milla.invoke_async(src)
+
+/datum/milla_safe/recalculate_atmos_connectivity
+
+/datum/milla_safe/recalculate_atmos_connectivity/on_run(turf/T)
+ if(isnull(T))
+ return
+
+ if(T.blocks_air)
+ set_tile_airtight(T, list(TRUE, TRUE, TRUE, TRUE))
+ // Will be needed when we go back to having solid tile conductivity.
+ //reset_superconductivity(src)
+ reduce_superconductivity(T, list(0, 0, 0, 0))
+ return
+
+ var/list/atmos_airtight = list(
+ !T.CanAtmosPass(NORTH, FALSE),
+ !T.CanAtmosPass(EAST, FALSE),
+ !T.CanAtmosPass(SOUTH, FALSE),
+ !T.CanAtmosPass(WEST, FALSE))
+
+ var/list/superconductivity = list(
+ OPEN_HEAT_TRANSFER_COEFFICIENT,
+ OPEN_HEAT_TRANSFER_COEFFICIENT,
+ OPEN_HEAT_TRANSFER_COEFFICIENT,
+ OPEN_HEAT_TRANSFER_COEFFICIENT)
+
+ for(var/obj/O in T)
+ if(istype(O, /obj/item))
+ // Items can't block atmos.
+ continue
+ if(!O.CanAtmosPass(NORTH))
+ atmos_airtight[INDEX_NORTH] = TRUE
+ if(!O.CanAtmosPass(EAST))
+ atmos_airtight[INDEX_EAST] = TRUE
+ if(!O.CanAtmosPass(SOUTH))
+ atmos_airtight[INDEX_SOUTH] = TRUE
+ if(!O.CanAtmosPass(WEST))
+ atmos_airtight[INDEX_WEST] = TRUE
+ superconductivity[INDEX_NORTH] = min(superconductivity[INDEX_NORTH], O.get_superconductivity(NORTH))
+ superconductivity[INDEX_EAST] = min(superconductivity[INDEX_EAST], O.get_superconductivity(EAST))
+ superconductivity[INDEX_SOUTH] = min(superconductivity[INDEX_SOUTH], O.get_superconductivity(SOUTH))
+ superconductivity[INDEX_WEST] = min(superconductivity[INDEX_WEST], O.get_superconductivity(WEST))
+
+ set_tile_airtight(T, atmos_airtight)
+ reset_superconductivity(T)
+ reduce_superconductivity(T, superconductivity)
+
+#undef INDEX_NORTH
+#undef INDEX_EAST
+#undef INDEX_SOUTH
+#undef INDEX_WEST
diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
index 80ab27960ae..86cd73ec61b 100644
--- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
@@ -9,84 +9,137 @@ What are the archived variables for?
#define SPECIFIC_HEAT_N2O 40
#define SPECIFIC_HEAT_AGENT_B 300
-#define HEAT_CAPACITY_CALCULATION(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b) \
- (carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + toxins * SPECIFIC_HEAT_TOXIN + sleeping_agent * SPECIFIC_HEAT_N2O + agent_b * SPECIFIC_HEAT_AGENT_B)
+#define HEAT_CAPACITY_CALCULATION(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, innate_heat_capacity) \
+ (carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + toxins * SPECIFIC_HEAT_TOXIN + sleeping_agent * SPECIFIC_HEAT_N2O + agent_b * SPECIFIC_HEAT_AGENT_B + innate_heat_capacity)
#define MINIMUM_HEAT_CAPACITY 0.0003
#define MINIMUM_MOLE_COUNT 0.01
#define QUANTIZE(variable) (round(variable, 0.0001))
/datum/gas_mixture
- var/oxygen = 0
- var/carbon_dioxide = 0
- var/nitrogen = 0
- var/toxins = 0
- var/sleeping_agent = 0
- var/agent_b = 0
-
+ /// The volume this gas mixture fills.
var/volume = CELL_VOLUME
+ /// Heat capacity intrinsic to the container of this gas mixture.
+ var/innate_heat_capacity = 0
+ /// How much fuel this gas mixture burnt last reaction.
+ var/fuel_burnt = 0
- var/temperature = 0 //in Kelvin
+ // Private fields. Use the matching procs to get and set them.
+ // e.g. GM.oxygen(), GM.set_oxygen()
+ var/private_oxygen = 0
+ var/private_carbon_dioxide = 0
+ var/private_nitrogen = 0
+ var/private_toxins = 0
+ var/private_sleeping_agent = 0
+ var/private_agent_b = 0
+ var/private_temperature = 0 //in Kelvin
- var/last_share
+ // Archived versions of the private fields.
+ // Only gas_mixture should use these.
+ var/private_oxygen_archived = 0
+ var/private_carbon_dioxide_archived = 0
+ var/private_nitrogen_archived = 0
+ var/private_toxins_archived = 0
+ var/private_sleeping_agent_archived = 0
+ var/private_agent_b_archived = 0
+ var/private_temperature_archived = 0
- var/tmp/oxygen_archived
- var/tmp/carbon_dioxide_archived
- var/tmp/nitrogen_archived
- var/tmp/toxins_archived
- var/tmp/sleeping_agent_archived
- var/tmp/agent_b_archived
+ /// Is this mixture currently synchronized with MILLA? Always true for non-bound mixtures.
+ var/synchronized = TRUE
- var/tmp/temperature_archived
+ /// Tracks the callbacks from synchronize() that haven't run yet.
+ var/list/waiting_for_sync = list()
- var/tmp/fuel_burnt = 0
+/datum/gas_mixture/Destroy()
+ waiting_for_sync.Cut()
+ return ..()
- //PV = nRT
+/// Marks this gas mixture as changed from MILLA. Does nothing on non-bound mixtures.
+/datum/gas_mixture/proc/set_dirty()
+ return
+
+/datum/gas_mixture/proc/oxygen()
+ return private_oxygen
+
+/datum/gas_mixture/proc/set_oxygen(value)
+ private_oxygen = value
+
+/datum/gas_mixture/proc/carbon_dioxide()
+ return private_carbon_dioxide
+
+/datum/gas_mixture/proc/set_carbon_dioxide(value)
+ private_carbon_dioxide = value
+
+/datum/gas_mixture/proc/nitrogen()
+ return private_nitrogen
+
+/datum/gas_mixture/proc/set_nitrogen(value)
+ private_nitrogen = value
+
+/datum/gas_mixture/proc/toxins()
+ return private_toxins
+
+/datum/gas_mixture/proc/set_toxins(value)
+ private_toxins = value
+
+/datum/gas_mixture/proc/sleeping_agent()
+ return private_sleeping_agent
+
+/datum/gas_mixture/proc/set_sleeping_agent(value)
+ private_sleeping_agent = value
+
+/datum/gas_mixture/proc/agent_b()
+ return private_agent_b
+
+/datum/gas_mixture/proc/set_agent_b(value)
+ private_agent_b = value
+
+/datum/gas_mixture/proc/temperature()
+ return private_temperature
+
+/datum/gas_mixture/proc/set_temperature(value)
+ private_temperature = value
///joules per kelvin
/datum/gas_mixture/proc/heat_capacity()
- return HEAT_CAPACITY_CALCULATION(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b)
+ return HEAT_CAPACITY_CALCULATION(private_oxygen, private_carbon_dioxide, private_nitrogen, private_toxins, private_sleeping_agent, private_agent_b, innate_heat_capacity)
/datum/gas_mixture/proc/heat_capacity_archived()
- return HEAT_CAPACITY_CALCULATION(oxygen_archived, carbon_dioxide_archived, nitrogen_archived, toxins_archived, sleeping_agent_archived, agent_b_archived)
+ return HEAT_CAPACITY_CALCULATION(private_oxygen_archived, private_carbon_dioxide_archived, private_nitrogen_archived, private_toxins_archived, private_sleeping_agent_archived, private_agent_b_archived, innate_heat_capacity)
/// Calculate moles
/datum/gas_mixture/proc/total_moles()
- var/moles = oxygen + carbon_dioxide + nitrogen + toxins + sleeping_agent + agent_b
+ var/moles = private_oxygen + private_carbon_dioxide + private_nitrogen + private_toxins + private_sleeping_agent + private_agent_b
return moles
/datum/gas_mixture/proc/total_trace_moles()
- var/moles = agent_b
+ var/moles = private_agent_b
return moles
/// Calculate pressure in kilopascals
/datum/gas_mixture/proc/return_pressure()
if(volume > 0)
- return total_moles() * R_IDEAL_GAS_EQUATION * temperature / volume
+ return total_moles() * R_IDEAL_GAS_EQUATION * private_temperature / volume
return 0
- /// Calculate temperature in kelvins
-/datum/gas_mixture/proc/return_temperature()
- return temperature
-
/// Calculate volume in liters
/datum/gas_mixture/proc/return_volume()
return max(0, volume)
/// Calculate thermal energy in joules
/datum/gas_mixture/proc/thermal_energy()
- return temperature * heat_capacity()
+ return private_temperature * heat_capacity()
///Update archived versions of variables. Returns: TRUE in all cases
/datum/gas_mixture/proc/archive()
- oxygen_archived = oxygen
- carbon_dioxide_archived = carbon_dioxide
- nitrogen_archived = nitrogen
- toxins_archived = toxins
- sleeping_agent_archived = sleeping_agent
- agent_b_archived = agent_b
+ private_oxygen_archived = private_oxygen
+ private_carbon_dioxide_archived = private_carbon_dioxide
+ private_nitrogen_archived = private_nitrogen
+ private_toxins_archived = private_toxins
+ private_sleeping_agent_archived = private_sleeping_agent
+ private_agent_b_archived = private_agent_b
- temperature_archived = temperature
+ private_temperature_archived = private_temperature
return TRUE
@@ -95,20 +148,22 @@ What are the archived variables for?
if(!giver)
return FALSE
- if(abs(temperature - giver.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+
+ if(abs(private_temperature - giver.private_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity()
var/giver_heat_capacity = giver.heat_capacity()
var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity
if(combined_heat_capacity != 0)
- temperature = (giver.temperature * giver_heat_capacity + temperature * self_heat_capacity) / combined_heat_capacity
+ private_temperature = (giver.private_temperature * giver_heat_capacity + private_temperature * self_heat_capacity) / combined_heat_capacity
- oxygen += giver.oxygen
- carbon_dioxide += giver.carbon_dioxide
- nitrogen += giver.nitrogen
- toxins += giver.toxins
- sleeping_agent += giver.sleeping_agent
- agent_b += giver.agent_b
+ private_oxygen += giver.private_oxygen
+ private_carbon_dioxide += giver.private_carbon_dioxide
+ private_nitrogen += giver.private_nitrogen
+ private_toxins += giver.private_toxins
+ private_sleeping_agent += giver.private_sleeping_agent
+ private_agent_b += giver.private_agent_b
+ set_dirty()
return TRUE
/// Only removes the gas if we have more than the amount
@@ -129,22 +184,23 @@ What are the archived variables for?
var/datum/gas_mixture/removed = new
- removed.oxygen = QUANTIZE((oxygen / sum) * amount)
- removed.nitrogen = QUANTIZE((nitrogen/ sum) * amount)
- removed.carbon_dioxide = QUANTIZE((carbon_dioxide / sum) * amount)
- removed.toxins = QUANTIZE((toxins / sum) * amount)
- removed.sleeping_agent = QUANTIZE((sleeping_agent / sum) * amount)
- removed.agent_b = QUANTIZE((agent_b / sum) * amount)
+ removed.private_oxygen = QUANTIZE((private_oxygen / sum) * amount)
+ removed.private_nitrogen = QUANTIZE((private_nitrogen/ sum) * amount)
+ removed.private_carbon_dioxide = QUANTIZE((private_carbon_dioxide / sum) * amount)
+ removed.private_toxins = QUANTIZE((private_toxins / sum) * amount)
+ removed.private_sleeping_agent = QUANTIZE((private_sleeping_agent / sum) * amount)
+ removed.private_agent_b = QUANTIZE((private_agent_b / sum) * amount)
- oxygen = max(oxygen - removed.oxygen, 0)
- nitrogen = max(nitrogen - removed.nitrogen, 0)
- carbon_dioxide = max(carbon_dioxide - removed.carbon_dioxide, 0)
- toxins = max(toxins - removed.toxins, 0)
- sleeping_agent = max(sleeping_agent - removed.sleeping_agent, 0)
- agent_b = max(agent_b - removed.agent_b, 0)
+ private_oxygen = max(private_oxygen - removed.private_oxygen, 0)
+ private_nitrogen = max(private_nitrogen - removed.private_nitrogen, 0)
+ private_carbon_dioxide = max(private_carbon_dioxide - removed.private_carbon_dioxide, 0)
+ private_toxins = max(private_toxins - removed.private_toxins, 0)
+ private_sleeping_agent = max(private_sleeping_agent - removed.private_sleeping_agent, 0)
+ private_agent_b = max(private_agent_b - removed.private_agent_b, 0)
- removed.temperature = temperature
+ removed.private_temperature = private_temperature
+ set_dirty()
return removed
///Proportionally removes amount of gas from the gas_mixture.
@@ -158,51 +214,54 @@ What are the archived variables for?
var/datum/gas_mixture/removed = new
- removed.oxygen = QUANTIZE(oxygen * ratio)
- removed.nitrogen = QUANTIZE(nitrogen * ratio)
- removed.carbon_dioxide = QUANTIZE(carbon_dioxide * ratio)
- removed.toxins = QUANTIZE(toxins * ratio)
- removed.sleeping_agent = QUANTIZE(sleeping_agent * ratio)
- removed.agent_b = QUANTIZE(agent_b * ratio)
+ removed.private_oxygen = QUANTIZE(private_oxygen * ratio)
+ removed.private_nitrogen = QUANTIZE(private_nitrogen * ratio)
+ removed.private_carbon_dioxide = QUANTIZE(private_carbon_dioxide * ratio)
+ removed.private_toxins = QUANTIZE(private_toxins * ratio)
+ removed.private_sleeping_agent = QUANTIZE(private_sleeping_agent * ratio)
+ removed.private_agent_b = QUANTIZE(private_agent_b * ratio)
- oxygen = max(oxygen - removed.oxygen, 0)
- nitrogen = max(nitrogen - removed.nitrogen, 0)
- carbon_dioxide = max(carbon_dioxide - removed.carbon_dioxide, 0)
- toxins = max(toxins - removed.toxins, 0)
- sleeping_agent = max(sleeping_agent - removed.sleeping_agent, 0)
- agent_b = max(agent_b - removed.agent_b, 0)
+ private_oxygen = max(private_oxygen - removed.private_oxygen, 0)
+ private_nitrogen = max(private_nitrogen - removed.private_nitrogen, 0)
+ private_carbon_dioxide = max(private_carbon_dioxide - removed.private_carbon_dioxide, 0)
+ private_toxins = max(private_toxins - removed.private_toxins, 0)
+ private_sleeping_agent = max(private_sleeping_agent - removed.private_sleeping_agent, 0)
+ private_agent_b = max(private_agent_b - removed.private_agent_b, 0)
- removed.temperature = temperature
+ removed.private_temperature = private_temperature
+ set_dirty()
return removed
//Copies variables from sample
/datum/gas_mixture/proc/copy_from(datum/gas_mixture/sample)
- oxygen = sample.oxygen
- carbon_dioxide = sample.carbon_dioxide
- nitrogen = sample.nitrogen
- toxins = sample.toxins
- sleeping_agent = sample.sleeping_agent
- agent_b = sample.agent_b
+ private_oxygen = sample.private_oxygen
+ private_carbon_dioxide = sample.private_carbon_dioxide
+ private_nitrogen = sample.private_nitrogen
+ private_toxins = sample.private_toxins
+ private_sleeping_agent = sample.private_sleeping_agent
+ private_agent_b = sample.private_agent_b
- temperature = sample.temperature
+ private_temperature = sample.private_temperature
+ set_dirty()
return TRUE
///Copies all gas info from the turf into the gas list along with temperature
///Returns: TRUE if we are mutable, FALSE otherwise
/datum/gas_mixture/proc/copy_from_turf(turf/model)
- oxygen = model.oxygen
- carbon_dioxide = model.carbon_dioxide
- nitrogen = model.nitrogen
- toxins = model.toxins
- sleeping_agent = model.sleeping_agent
- agent_b = model.agent_b
+ private_oxygen = model.oxygen
+ private_carbon_dioxide = model.carbon_dioxide
+ private_nitrogen = model.nitrogen
+ private_toxins = model.toxins
+ private_sleeping_agent = model.sleeping_agent
+ private_agent_b = model.agent_b
//acounts for changes in temperature
var/turf/model_parent = model.parent_type
if(model.temperature != initial(model.temperature) || model.temperature != initial(model_parent.temperature))
- temperature = model.temperature
+ private_temperature = model.temperature
+ set_dirty()
return TRUE
@@ -212,17 +271,17 @@ What are the archived variables for?
if(!sharer)
return 0
/// Don't make calculations if there is no difference.
- if(oxygen_archived == sharer.oxygen_archived && carbon_dioxide_archived == sharer.carbon_dioxide_archived && nitrogen_archived == sharer.nitrogen_archived &&\
- toxins_archived == sharer.toxins_archived && sleeping_agent_archived == sharer.sleeping_agent_archived && agent_b_archived == sharer.agent_b_archived && temperature_archived == sharer.temperature_archived)
+ if(private_oxygen_archived == sharer.private_oxygen_archived && private_carbon_dioxide_archived == sharer.private_carbon_dioxide_archived && private_nitrogen_archived == sharer.private_nitrogen_archived &&\
+ private_toxins_archived == sharer.private_toxins_archived && private_sleeping_agent_archived == sharer.private_sleeping_agent_archived && private_agent_b_archived == sharer.private_agent_b_archived && private_temperature_archived == sharer.private_temperature_archived)
return 0
- var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived) / (atmos_adjacent_turfs + 1)
- var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived) / (atmos_adjacent_turfs + 1)
- var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived) / (atmos_adjacent_turfs + 1)
- var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived) / (atmos_adjacent_turfs + 1)
- var/delta_sleeping_agent = QUANTIZE(sleeping_agent_archived - sharer.sleeping_agent_archived) / (atmos_adjacent_turfs + 1)
- var/delta_agent_b = QUANTIZE(agent_b_archived - sharer.agent_b_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_oxygen = QUANTIZE(private_oxygen_archived - sharer.private_oxygen_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_carbon_dioxide = QUANTIZE(private_carbon_dioxide_archived - sharer.private_carbon_dioxide_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_nitrogen = QUANTIZE(private_nitrogen_archived - sharer.private_nitrogen_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_toxins = QUANTIZE(private_toxins_archived - sharer.private_toxins_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_sleeping_agent = QUANTIZE(private_sleeping_agent_archived - sharer.private_sleeping_agent_archived) / (atmos_adjacent_turfs + 1)
+ var/delta_agent_b = QUANTIZE(private_agent_b_archived - sharer.private_agent_b_archived) / (atmos_adjacent_turfs + 1)
- var/delta_temperature = (temperature_archived - sharer.temperature_archived)
+ var/delta_temperature = (private_temperature_archived - sharer.private_temperature_archived)
var/old_self_heat_capacity = 0
var/old_sharer_heat_capacity = 0
@@ -271,56 +330,56 @@ What are the archived variables for?
old_self_heat_capacity = heat_capacity()
old_sharer_heat_capacity = sharer.heat_capacity()
- oxygen -= delta_oxygen
- sharer.oxygen += delta_oxygen
+ private_oxygen -= delta_oxygen
+ sharer.private_oxygen += delta_oxygen
- carbon_dioxide -= delta_carbon_dioxide
- sharer.carbon_dioxide += delta_carbon_dioxide
+ private_carbon_dioxide -= delta_carbon_dioxide
+ sharer.private_carbon_dioxide += delta_carbon_dioxide
- nitrogen -= delta_nitrogen
- sharer.nitrogen += delta_nitrogen
+ private_nitrogen -= delta_nitrogen
+ sharer.private_nitrogen += delta_nitrogen
- toxins -= delta_toxins
- sharer.toxins += delta_toxins
+ private_toxins -= delta_toxins
+ sharer.private_toxins += delta_toxins
- sleeping_agent -= delta_sleeping_agent
- sharer.sleeping_agent += delta_sleeping_agent
+ private_sleeping_agent -= delta_sleeping_agent
+ sharer.private_sleeping_agent += delta_sleeping_agent
- agent_b -= delta_agent_b
- sharer.agent_b += delta_agent_b
+ private_agent_b -= delta_agent_b
+ sharer.private_agent_b += delta_agent_b
var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins + delta_sleeping_agent + delta_agent_b)
- last_share = abs(delta_oxygen) + abs(delta_carbon_dioxide) + abs(delta_nitrogen) + abs(delta_toxins) + abs(delta_sleeping_agent) + abs(delta_agent_b)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/new_self_heat_capacity = old_self_heat_capacity + heat_capacity_sharer_to_self - heat_capacity_self_to_sharer
var/new_sharer_heat_capacity = old_sharer_heat_capacity + heat_capacity_self_to_sharer - heat_capacity_sharer_to_self
if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY)
- temperature = (old_self_heat_capacity * temperature - heat_capacity_self_to_sharer * temperature_archived + heat_capacity_sharer_to_self * sharer.temperature_archived) / new_self_heat_capacity
+ private_temperature = (old_self_heat_capacity * private_temperature - heat_capacity_self_to_sharer * private_temperature_archived + heat_capacity_sharer_to_self * sharer.private_temperature_archived) / new_self_heat_capacity
if(new_sharer_heat_capacity > MINIMUM_HEAT_CAPACITY)
- sharer.temperature = (old_sharer_heat_capacity * sharer.temperature - heat_capacity_sharer_to_self * sharer.temperature_archived + heat_capacity_self_to_sharer * temperature_archived) / new_sharer_heat_capacity
+ sharer.private_temperature = (old_sharer_heat_capacity * sharer.private_temperature - heat_capacity_sharer_to_self * sharer.private_temperature_archived + heat_capacity_self_to_sharer * private_temperature_archived) / new_sharer_heat_capacity
if(abs(old_sharer_heat_capacity) > MINIMUM_HEAT_CAPACITY)
if(abs(new_sharer_heat_capacity / old_sharer_heat_capacity - 1) < 0.10) // <10% change in sharer heat capacity
temperature_share(sharer, OPEN_HEAT_TRANSFER_COEFFICIENT)
+ set_dirty()
if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
- var/delta_pressure = temperature_archived * (total_moles() + moved_moles) - sharer.temperature_archived * (sharer.total_moles() - moved_moles)
+ var/delta_pressure = private_temperature_archived * (total_moles() + moved_moles) - sharer.private_temperature_archived * (sharer.total_moles() - moved_moles)
return delta_pressure * R_IDEAL_GAS_EQUATION / volume
//Similar to share(...), except the model is not modified
//Return: amount of gas exchanged
/datum/gas_mixture/proc/mimic(turf/model, atmos_adjacent_turfs = 4) //I want this proc to die a painful death
- var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen) / (atmos_adjacent_turfs + 1)
- var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide) / (atmos_adjacent_turfs + 1)
- var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen) / (atmos_adjacent_turfs + 1)
- var/delta_toxins = QUANTIZE(toxins_archived - model.toxins) / (atmos_adjacent_turfs + 1)
- var/delta_sleeping_agent = QUANTIZE(sleeping_agent_archived - model.sleeping_agent) / (atmos_adjacent_turfs + 1)
- var/delta_agent_b = QUANTIZE(agent_b_archived - model.agent_b) / (atmos_adjacent_turfs + 1)
+ var/delta_oxygen = QUANTIZE(private_oxygen_archived - model.oxygen) / (atmos_adjacent_turfs + 1)
+ var/delta_carbon_dioxide = QUANTIZE(private_carbon_dioxide_archived - model.carbon_dioxide) / (atmos_adjacent_turfs + 1)
+ var/delta_nitrogen = QUANTIZE(private_nitrogen_archived - model.nitrogen) / (atmos_adjacent_turfs + 1)
+ var/delta_toxins = QUANTIZE(private_toxins_archived - model.toxins) / (atmos_adjacent_turfs + 1)
+ var/delta_sleeping_agent = QUANTIZE(private_sleeping_agent_archived - model.sleeping_agent) / (atmos_adjacent_turfs + 1)
+ var/delta_agent_b = QUANTIZE(private_agent_b_archived - model.agent_b) / (atmos_adjacent_turfs + 1)
- var/delta_temperature = (temperature_archived - model.temperature)
+ var/delta_temperature = (private_temperature_archived - model.temperature)
var/heat_transferred = 0
var/old_self_heat_capacity = 0
@@ -356,46 +415,46 @@ What are the archived variables for?
old_self_heat_capacity = heat_capacity()
- oxygen -= delta_oxygen
- carbon_dioxide -= delta_carbon_dioxide
- nitrogen -= delta_nitrogen
- toxins -= delta_toxins
- sleeping_agent -= delta_sleeping_agent
- agent_b -= delta_agent_b
+ private_oxygen -= delta_oxygen
+ private_carbon_dioxide -= delta_carbon_dioxide
+ private_nitrogen -= delta_nitrogen
+ private_toxins -= delta_toxins
+ private_sleeping_agent -= delta_sleeping_agent
+ private_agent_b -= delta_agent_b
var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins + delta_sleeping_agent + delta_agent_b)
- last_share = abs(delta_oxygen) + abs(delta_carbon_dioxide) + abs(delta_nitrogen) + abs(delta_toxins) + abs(delta_sleeping_agent) + abs(delta_agent_b)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/new_self_heat_capacity = old_self_heat_capacity - heat_capacity_transferred
if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY)
- temperature = (old_self_heat_capacity * temperature - heat_capacity_transferred * temperature_archived) / new_self_heat_capacity
+ private_temperature = (old_self_heat_capacity * private_temperature - heat_capacity_transferred * private_temperature_archived) / new_self_heat_capacity
temperature_mimic(model, model.thermal_conductivity)
+ set_dirty()
if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
- var/delta_pressure = temperature_archived * (total_moles() + moved_moles) - model.temperature * (model.oxygen + model.carbon_dioxide + model.nitrogen + model.toxins + model.sleeping_agent + model.agent_b)
+ var/delta_pressure = private_temperature_archived * (total_moles() + moved_moles) - model.temperature * (model.oxygen + model.carbon_dioxide + model.nitrogen + model.toxins + model.sleeping_agent + model.agent_b)
return delta_pressure * R_IDEAL_GAS_EQUATION / volume
else
return 0
//Returns: FALSE if self-check failed or TRUE if check passes
/datum/gas_mixture/proc/check_turf(turf/model, atmos_adjacent_turfs = 4) //I want this proc to die a painful death
- var/delta_oxygen = (oxygen_archived - model.oxygen) / (atmos_adjacent_turfs + 1)
- var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide) / (atmos_adjacent_turfs + 1)
- var/delta_nitrogen = (nitrogen_archived - model.nitrogen) / (atmos_adjacent_turfs + 1)
- var/delta_toxins = (toxins_archived - model.toxins) / (atmos_adjacent_turfs + 1)
- var/delta_sleeping_agent = (sleeping_agent_archived - model.sleeping_agent) / (atmos_adjacent_turfs + 1)
- var/delta_agent_b = (agent_b_archived - model.agent_b) / (atmos_adjacent_turfs + 1)
+ var/delta_oxygen = (private_oxygen_archived - model.oxygen) / (atmos_adjacent_turfs + 1)
+ var/delta_carbon_dioxide = (private_carbon_dioxide_archived - model.carbon_dioxide) / (atmos_adjacent_turfs + 1)
+ var/delta_nitrogen = (private_nitrogen_archived - model.nitrogen) / (atmos_adjacent_turfs + 1)
+ var/delta_toxins = (private_toxins_archived - model.toxins) / (atmos_adjacent_turfs + 1)
+ var/delta_sleeping_agent = (private_sleeping_agent_archived - model.sleeping_agent) / (atmos_adjacent_turfs + 1)
+ var/delta_agent_b = (private_agent_b_archived - model.agent_b) / (atmos_adjacent_turfs + 1)
- var/delta_temperature = (temperature_archived - model.temperature)
+ var/delta_temperature = (private_temperature_archived - model.temperature)
- if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_sleeping_agent) >= sleeping_agent_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= agent_b_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)))
+ if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= private_oxygen_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= private_carbon_dioxide_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= private_nitrogen_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= private_toxins_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_sleeping_agent) >= private_sleeping_agent_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= private_agent_b_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)))
return FALSE
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
return FALSE
@@ -403,7 +462,8 @@ What are the archived variables for?
return TRUE
/datum/gas_mixture/proc/temperature_mimic(turf/model, conduction_coefficient) //I want this proc to die a painful death
- var/delta_temperature = (temperature - model.temperature)
+ set_dirty()
+ var/delta_temperature = (private_temperature - model.temperature)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity()
@@ -411,14 +471,15 @@ What are the archived variables for?
var/heat = conduction_coefficient * delta_temperature * \
(self_heat_capacity * model.heat_capacity / (self_heat_capacity + model.heat_capacity))
- temperature -= heat / self_heat_capacity
+ private_temperature -= heat / self_heat_capacity
///Performs temperature sharing calculations (via conduction) between two gas_mixtures assuming only 1 boundary length
///Returns: new temperature of the sharer
/datum/gas_mixture/proc/temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
- var/delta_temperature = (temperature_archived - sharer.temperature_archived)
+ var/delta_temperature = (private_temperature_archived - sharer.private_temperature_archived)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ set_dirty()
var/self_heat_capacity = heat_capacity_archived()
var/sharer_heat_capacity = sharer.heat_capacity_archived()
@@ -426,64 +487,65 @@ What are the archived variables for?
var/heat = conduction_coefficient*delta_temperature * \
(self_heat_capacity * sharer_heat_capacity / (self_heat_capacity + sharer_heat_capacity))
- temperature -= heat / self_heat_capacity
- sharer.temperature += heat / sharer_heat_capacity
+ private_temperature -= heat / self_heat_capacity
+ sharer.private_temperature += heat / sharer_heat_capacity
/datum/gas_mixture/proc/temperature_turf_share(turf/simulated/sharer, conduction_coefficient) //I want this proc to die a painful death
- var/delta_temperature = (temperature_archived - sharer.temperature)
+ var/delta_temperature = (private_temperature_archived - sharer.temperature)
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ set_dirty()
var/self_heat_capacity = heat_capacity()
if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
var/heat = conduction_coefficient * delta_temperature * \
(self_heat_capacity * sharer.heat_capacity / (self_heat_capacity + sharer.heat_capacity))
- temperature -= heat / self_heat_capacity
+ private_temperature -= heat / self_heat_capacity
sharer.temperature += heat / sharer.heat_capacity
//Compares sample to self to see if within acceptable ranges that group processing may be enabled
/datum/gas_mixture/proc/compare(datum/gas_mixture/sample)
- if((abs(oxygen - sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \
- ((oxygen < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.oxygen) || (oxygen > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.oxygen)))
+ if((abs(private_oxygen - sample.private_oxygen) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((private_oxygen < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_oxygen) || (private_oxygen > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_oxygen)))
return FALSE
- if((abs(nitrogen - sample.nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \
- ((nitrogen < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.nitrogen) || (nitrogen > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.nitrogen)))
+ if((abs(private_nitrogen - sample.private_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((private_nitrogen < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_nitrogen) || (private_nitrogen > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_nitrogen)))
return FALSE
- if((abs(carbon_dioxide - sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \
- ((carbon_dioxide < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.carbon_dioxide) || (carbon_dioxide > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.carbon_dioxide)))
+ if((abs(private_carbon_dioxide - sample.private_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((private_carbon_dioxide < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_carbon_dioxide) || (private_carbon_dioxide > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_carbon_dioxide)))
return FALSE
- if((abs(toxins - sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \
- ((toxins < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.toxins) || (toxins > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.toxins)))
+ if((abs(private_toxins - sample.private_toxins) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((private_toxins < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_toxins) || (private_toxins > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_toxins)))
return FALSE
- if((abs(sleeping_agent - sample.sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && \
- ((sleeping_agent < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.sleeping_agent) || (sleeping_agent > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.sleeping_agent)))
+ if((abs(private_sleeping_agent - sample.private_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((private_sleeping_agent < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_sleeping_agent) || (private_sleeping_agent > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_sleeping_agent)))
return FALSE
- if((abs(agent_b - sample.agent_b) > MINIMUM_AIR_TO_SUSPEND) && \
- ((agent_b < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.agent_b) || (agent_b > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.agent_b)))
+ if((abs(private_agent_b - sample.private_agent_b) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((private_agent_b < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_agent_b) || (private_agent_b > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_agent_b)))
return FALSE
if(total_moles() > MINIMUM_AIR_TO_SUSPEND)
- if((abs(temperature - sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \
- ((temperature < (1 - MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND) * sample.temperature) || (temperature > (1 + MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND) * sample.temperature)))
+ if((abs(private_temperature - sample.private_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \
+ ((private_temperature < (1 - MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND) * sample.private_temperature) || (private_temperature > (1 + MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND) * sample.private_temperature)))
return FALSE
return TRUE
/datum/gas_mixture/proc/check_turf_total(turf/model) //I want this proc to die a painful death
- var/delta_oxygen = (oxygen - model.oxygen)
- var/delta_carbon_dioxide = (carbon_dioxide - model.carbon_dioxide)
- var/delta_nitrogen = (nitrogen - model.nitrogen)
- var/delta_toxins = (toxins - model.toxins)
- var/delta_sleeping_agent = (sleeping_agent - model.sleeping_agent)
- var/delta_agent_b = (agent_b - model.agent_b)
+ var/delta_oxygen = (private_oxygen - model.oxygen)
+ var/delta_carbon_dioxide = (private_carbon_dioxide - model.carbon_dioxide)
+ var/delta_nitrogen = (private_nitrogen - model.nitrogen)
+ var/delta_toxins = (private_toxins - model.toxins)
+ var/delta_sleeping_agent = (private_sleeping_agent - model.sleeping_agent)
+ var/delta_agent_b = (private_agent_b - model.agent_b)
- var/delta_temperature = (temperature - model.temperature)
+ var/delta_temperature = (private_temperature - model.temperature)
- if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_sleeping_agent) >= sleeping_agent * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
- || ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= agent_b * MINIMUM_AIR_RATIO_TO_SUSPEND)))
+ if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= private_oxygen * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= private_carbon_dioxide * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= private_nitrogen * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= private_toxins * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_sleeping_agent) >= private_sleeping_agent * MINIMUM_AIR_RATIO_TO_SUSPEND)) \
+ || ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= private_agent_b * MINIMUM_AIR_RATIO_TO_SUSPEND)))
return FALSE
if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
return FALSE
@@ -495,77 +557,78 @@ What are the archived variables for?
/datum/gas_mixture/proc/react(atom/dump_location)
var/reacting = FALSE //set to TRUE if a notable reaction occured (used by pipe_network)
- if((agent_b > MINIMUM_MOLE_COUNT) && temperature > 900)
- if(toxins > MINIMUM_HEAT_CAPACITY && carbon_dioxide > MINIMUM_HEAT_CAPACITY)
- var/reaction_rate = min(carbon_dioxide * 0.75, toxins * 0.25, agent_b * 0.05)
+ if((private_agent_b > MINIMUM_MOLE_COUNT) && private_temperature > 900)
+ if(private_toxins > MINIMUM_HEAT_CAPACITY && private_carbon_dioxide > MINIMUM_HEAT_CAPACITY)
+ var/reaction_rate = min(private_carbon_dioxide * 0.75, private_toxins * 0.25, private_agent_b * 0.05)
- carbon_dioxide -= reaction_rate
- oxygen += reaction_rate
+ private_carbon_dioxide -= reaction_rate
+ private_oxygen += reaction_rate
- agent_b -= reaction_rate * 0.05
+ private_agent_b -= reaction_rate * 0.05
- temperature += (reaction_rate * 20000) / heat_capacity()
+ private_temperature += (reaction_rate * 20000) / heat_capacity()
reacting = TRUE
- if((sleeping_agent > MINIMUM_MOLE_COUNT) && temperature > N2O_DECOMPOSITION_MIN_ENERGY)
+ if((private_sleeping_agent > MINIMUM_MOLE_COUNT) && private_temperature > N2O_DECOMPOSITION_MIN_ENERGY)
var/energy_released = 0
var/old_heat_capacity = heat_capacity()
var/burned_fuel = 0
- burned_fuel = max(0, 0.00002 * (temperature - (0.00001 * (temperature ** 2)))) * sleeping_agent
- if(sleeping_agent - burned_fuel > 0)
- sleeping_agent -= burned_fuel
+ burned_fuel = max(0, 0.00002 * (private_temperature - (0.00001 * (private_temperature ** 2)))) * private_sleeping_agent
+ if(private_sleeping_agent - burned_fuel > 0)
+ private_sleeping_agent -= burned_fuel
if(burned_fuel)
energy_released += (N2O_DECOMPOSITION_ENERGY_RELEASED * burned_fuel)
- oxygen += burned_fuel * 0.5
- nitrogen += burned_fuel
+ private_oxygen += burned_fuel * 0.5
+ private_nitrogen += burned_fuel
var/new_heat_capacity = heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- temperature = (temperature * old_heat_capacity + energy_released) / new_heat_capacity
+ private_temperature = (private_temperature * old_heat_capacity + energy_released) / new_heat_capacity
reacting = TRUE
fuel_burnt = 0
//Handle plasma burning
- if((toxins > MINIMUM_MOLE_COUNT) && (oxygen > MINIMUM_MOLE_COUNT) && temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
+ if((private_toxins > MINIMUM_MOLE_COUNT) && (private_oxygen > MINIMUM_MOLE_COUNT) && private_temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
var/energy_released = 0
var/old_heat_capacity = heat_capacity()
var/plasma_burn_rate = 0
- var/oxygen_burn_rate = 0
+ var/private_oxygen_burn_rate = 0
//more plasma released at higher temperatures
- var/temperature_scale = 0
+ var/private_temperature_scale = 0
- if(temperature > PLASMA_UPPER_TEMPERATURE)
- temperature_scale = 1
+ if(private_temperature > PLASMA_UPPER_TEMPERATURE)
+ private_temperature_scale = 1
else
- temperature_scale = (temperature - PLASMA_MINIMUM_BURN_TEMPERATURE) / (PLASMA_UPPER_TEMPERATURE - PLASMA_MINIMUM_BURN_TEMPERATURE)
- if(temperature_scale > 0)
- oxygen_burn_rate = OXYGEN_BURN_RATE_BASE - temperature_scale
- if(oxygen > toxins * PLASMA_OXYGEN_FULLBURN)
- plasma_burn_rate = (toxins * temperature_scale) / PLASMA_BURN_RATE_DELTA
+ private_temperature_scale = (private_temperature - PLASMA_MINIMUM_BURN_TEMPERATURE) / (PLASMA_UPPER_TEMPERATURE - PLASMA_MINIMUM_BURN_TEMPERATURE)
+ if(private_temperature_scale > 0)
+ private_oxygen_burn_rate = OXYGEN_BURN_RATE_BASE - private_temperature_scale
+ if(private_oxygen > private_toxins * PLASMA_OXYGEN_FULLBURN)
+ plasma_burn_rate = (private_toxins * private_temperature_scale) / PLASMA_BURN_RATE_DELTA
else
- plasma_burn_rate = (temperature_scale * (oxygen / PLASMA_OXYGEN_FULLBURN)) / PLASMA_BURN_RATE_DELTA
+ plasma_burn_rate = (private_temperature_scale * (private_oxygen / PLASMA_OXYGEN_FULLBURN)) / PLASMA_BURN_RATE_DELTA
if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
- plasma_burn_rate = min(plasma_burn_rate, toxins, oxygen / oxygen_burn_rate) //Ensures matter is conserved properly
- toxins = QUANTIZE(toxins - plasma_burn_rate)
- oxygen = QUANTIZE(oxygen - (plasma_burn_rate * oxygen_burn_rate))
- carbon_dioxide += plasma_burn_rate
+ plasma_burn_rate = min(plasma_burn_rate, private_toxins, private_oxygen / private_oxygen_burn_rate) //Ensures matter is conserved properly
+ private_toxins = QUANTIZE(private_toxins - plasma_burn_rate)
+ private_oxygen = QUANTIZE(private_oxygen - (plasma_burn_rate * private_oxygen_burn_rate))
+ private_carbon_dioxide += plasma_burn_rate
energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
- fuel_burnt += (plasma_burn_rate) * (1 + oxygen_burn_rate)
+ fuel_burnt += (plasma_burn_rate) * (1 + private_oxygen_burn_rate)
if(energy_released > 0)
var/new_heat_capacity = heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- temperature = (temperature * old_heat_capacity + energy_released) / new_heat_capacity
+ private_temperature = (private_temperature * old_heat_capacity + energy_released) / new_heat_capacity
if(fuel_burnt)
reacting = TRUE
+ set_dirty()
return reacting
///Takes the amount of the gas you want to PP as an argument
@@ -575,11 +638,66 @@ What are the archived variables for?
///O2_PP = get_partial_pressure(gas_mixture.oxygen)
/datum/gas_mixture/proc/get_breath_partial_pressure(gas_pressure)
- return (gas_pressure * R_IDEAL_GAS_EQUATION * temperature) / BREATH_VOLUME
+ return (gas_pressure * R_IDEAL_GAS_EQUATION * private_temperature) / BREATH_VOLUME
///inverse
/datum/gas_mixture/proc/get_true_breath_pressure(partial_pressure)
- return (partial_pressure * BREATH_VOLUME) / (R_IDEAL_GAS_EQUATION * temperature)
+ return (partial_pressure * BREATH_VOLUME) / (R_IDEAL_GAS_EQUATION * private_temperature)
+
+/datum/gas_mixture/proc/copy_from_milla(list/milla)
+ private_oxygen = milla[MILLA_INDEX_OXYGEN]
+ private_carbon_dioxide = milla[MILLA_INDEX_CARBON_DIOXIDE]
+ private_nitrogen = milla[MILLA_INDEX_NITROGEN]
+ private_toxins = milla[MILLA_INDEX_TOXINS]
+ private_sleeping_agent = milla[MILLA_INDEX_SLEEPING_AGENT]
+ private_agent_b = milla[MILLA_INDEX_AGENT_B]
+ innate_heat_capacity = milla[MILLA_INDEX_INNATE_HEAT_CAPACITY]
+ private_temperature = milla[MILLA_INDEX_TEMPERATURE]
+
+/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
+
+ for(var/datum/gas_mixture/G as anything in mixtures)
+ total_volume += G.volume
+ var/heat_capacity = G.heat_capacity()
+ total_heat_capacity += heat_capacity
+ total_thermal_energy += G.private_temperature * heat_capacity
+
+ total_oxygen += G.private_oxygen
+ total_nitrogen += G.private_nitrogen
+ total_toxins += G.private_toxins
+ total_carbon_dioxide += G.private_carbon_dioxide
+ 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
+
+ //Update individual gas_mixtures by volume ratio
+ for(var/datum/gas_mixture/G as anything in mixtures)
+ 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()
+
+
///Mathematical proofs:
/**
@@ -599,3 +717,103 @@ get_true_breath_pressure(pp) --> gas_pp = pp/breath_pp*total_moles()
#undef MINIMUM_HEAT_CAPACITY
#undef MINIMUM_MOLE_COUNT
#undef QUANTIZE
+
+/datum/gas_mixture/bound_to_turf
+ var/dirty = FALSE
+ var/lastread = 0
+ var/turf/bound_turf = null
+ var/datum/gas_mixture/readonly/readonly = null
+
+/datum/gas_mixture/bound_to_turf/Destroy()
+ bound_turf = null
+ return ..()
+
+/datum/gas_mixture/bound_to_turf/set_dirty()
+ dirty = TRUE
+
+ if(!isnull(readonly))
+ readonly.private_oxygen = private_oxygen
+ readonly.private_carbon_dioxide = private_carbon_dioxide
+ readonly.private_nitrogen = private_nitrogen
+ readonly.private_toxins = private_toxins
+ readonly.private_sleeping_agent = private_sleeping_agent
+ readonly.private_agent_b = private_agent_b
+ readonly.private_temperature = private_temperature
+
+ if(istype(bound_turf, /turf/simulated))
+ var/turf/simulated/S = bound_turf
+ S.update_visuals()
+ ASSERT(SSair.is_in_milla_safe_code())
+
+/datum/gas_mixture/bound_to_turf/set_oxygen(value)
+ private_oxygen = value
+ set_dirty()
+
+/datum/gas_mixture/bound_to_turf/set_carbon_dioxide(value)
+ private_carbon_dioxide = value
+ set_dirty()
+
+/datum/gas_mixture/bound_to_turf/set_nitrogen(value)
+ private_nitrogen = value
+ set_dirty()
+
+/datum/gas_mixture/bound_to_turf/set_toxins(value)
+ private_toxins = value
+ set_dirty()
+
+/datum/gas_mixture/bound_to_turf/set_sleeping_agent(value)
+ private_sleeping_agent = value
+ set_dirty()
+
+/datum/gas_mixture/bound_to_turf/set_agent_b(value)
+ private_agent_b = value
+ set_dirty()
+
+/datum/gas_mixture/bound_to_turf/set_temperature(value)
+ private_temperature = value
+ set_dirty()
+
+/datum/gas_mixture/bound_to_turf/proc/private_unsafe_write()
+ set_tile_atmos(bound_turf, oxygen = private_oxygen, carbon_dioxide = private_carbon_dioxide, nitrogen = private_nitrogen, toxins = private_toxins, sleeping_agent = private_sleeping_agent, agent_b = private_agent_b, temperature = private_temperature)
+
+/datum/gas_mixture/bound_to_turf/proc/get_readonly()
+ if(isnull(readonly))
+ readonly = new(src)
+ return readonly
+
+/// A gas mixture that should not be modified after creation.
+/datum/gas_mixture/readonly
+
+/datum/gas_mixture/readonly/New(datum/gas_mixture/parent)
+ private_oxygen = parent.private_oxygen
+ private_carbon_dioxide = parent.private_carbon_dioxide
+ private_nitrogen = parent.private_nitrogen
+ private_toxins = parent.private_toxins
+ private_sleeping_agent = parent.private_sleeping_agent
+ private_agent_b = parent.private_agent_b
+
+ private_temperature = parent.private_temperature
+
+/datum/gas_mixture/readonly/set_dirty()
+ CRASH("Attempted to modify a readonly gas_mixture.")
+
+/datum/gas_mixture/readonly/set_oxygen(value)
+ CRASH("Attempted to modify a readonly gas_mixture.")
+
+/datum/gas_mixture/readonly/set_carbon_dioxide(value)
+ CRASH("Attempted to modify a readonly gas_mixture.")
+
+/datum/gas_mixture/readonly/set_nitrogen(value)
+ CRASH("Attempted to modify a readonly gas_mixture.")
+
+/datum/gas_mixture/readonly/set_toxins(value)
+ CRASH("Attempted to modify a readonly gas_mixture.")
+
+/datum/gas_mixture/readonly/set_sleeping_agent(value)
+ CRASH("Attempted to modify a readonly gas_mixture.")
+
+/datum/gas_mixture/readonly/set_agent_b(value)
+ CRASH("Attempted to modify a readonly gas_mixture.")
+
+/datum/gas_mixture/readonly/set_temperature(value)
+ CRASH("Attempted to modify a readonly gas_mixture.")
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index 2c438e38d20..ce0a1ed401e 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -262,37 +262,37 @@
if(!istype(location))
return 0
- var/datum/gas_mixture/environment = location.return_air()
+ 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
var/datum/tlv/cur_tlv
- handle_heating_cooling(environment, cur_tlv, location)
-
- var/GET_PP = R_IDEAL_GAS_EQUATION*environment.temperature/environment.volume
-
cur_tlv = TLV["pressure"]
var/environment_pressure = environment.return_pressure()
var/pressure_dangerlevel = cur_tlv.get_danger_level(environment_pressure)
cur_tlv = TLV["oxygen"]
- var/oxygen_dangerlevel = cur_tlv.get_danger_level(environment.oxygen*GET_PP)
+ var/oxygen_dangerlevel = cur_tlv.get_danger_level(environment.oxygen() * GET_PP)
cur_tlv = TLV["nitrogen"]
- var/nitrogen_dangerlevel = cur_tlv.get_danger_level(environment.nitrogen*GET_PP)
+ var/nitrogen_dangerlevel = cur_tlv.get_danger_level(environment.nitrogen() * GET_PP)
cur_tlv = TLV["carbon dioxide"]
- var/co2_dangerlevel = cur_tlv.get_danger_level(environment.carbon_dioxide*GET_PP)
+ var/co2_dangerlevel = cur_tlv.get_danger_level(environment.carbon_dioxide() * GET_PP)
cur_tlv = TLV["plasma"]
- var/plasma_dangerlevel = cur_tlv.get_danger_level(environment.toxins*GET_PP)
+ var/plasma_dangerlevel = cur_tlv.get_danger_level(environment.toxins() * GET_PP)
cur_tlv = TLV["nitrous oxide"]
- var/sleeping_agent_dangerlevel = cur_tlv.get_danger_level(environment.sleeping_agent*GET_PP)
+ var/sleeping_agent_dangerlevel = cur_tlv.get_danger_level(environment.sleeping_agent() * GET_PP)
cur_tlv = TLV["other"]
var/other_dangerlevel = cur_tlv.get_danger_level(environment.total_trace_moles() * GET_PP)
cur_tlv = TLV["temperature"]
- var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature)
+ var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature())
var/old_danger_level = danger_level
danger_level = max(
@@ -313,43 +313,48 @@
mode = AALARM_MODE_SCRUBBING
apply_mode()
+/datum/milla_safe/airalarm_heat_cool
-/obj/machinery/alarm/proc/handle_heating_cooling(datum/gas_mixture/environment, datum/tlv/cur_tlv, turf/simulated/location)
- cur_tlv = TLV["temperature"]
+/datum/milla_safe/airalarm_heat_cool/on_run(obj/machinery/alarm/alarm)
+ 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 < target_temperature - 2 || environment.temperature > target_temperature + 2 || regulating_temperature)
+ if(environment.temperature() < alarm.target_temperature - 2 || environment.temperature() > alarm.target_temperature + 2 || alarm.regulating_temperature)
//If it goes too far, we should adjust ourselves back before stopping.
- if(!cur_tlv.get_danger_level(target_temperature))
- var/datum/gas_mixture/gas = location.remove_air(0.25 * environment.total_moles())
+ if(!cur_tlv.get_danger_level(alarm.target_temperature))
+ var/datum/gas_mixture/gas = environment.remove(0.25 * environment.total_moles())
if(!gas)
return
- if(!regulating_temperature && thermostat_state)
- regulating_temperature = TRUE
- visible_message("\The [src] clicks as it starts [environment.temperature > target_temperature ? "cooling" : "heating"] the room.", "You hear a click and a faint electronic hum.")
+ if(!alarm.regulating_temperature && alarm.thermostat_state)
+ alarm.regulating_temperature = TRUE
+ alarm.visible_message("\The [alarm] clicks as it starts [environment.temperature() > alarm.target_temperature ? "cooling" : "heating"] the room.", "You hear a click and a faint electronic hum.")
- if(target_temperature > MAX_TEMPERATURE)
- target_temperature = MAX_TEMPERATURE
+ if(alarm.target_temperature > MAX_TEMPERATURE)
+ alarm.target_temperature = MAX_TEMPERATURE
- if(target_temperature < MIN_TEMPERATURE)
- target_temperature = MIN_TEMPERATURE
+ if(alarm.target_temperature < MIN_TEMPERATURE)
+ alarm.target_temperature = MIN_TEMPERATURE
- if(thermostat_state)
- var/heat_capacity = gas.heat_capacity()
- var/energy_used = max(abs(heat_capacity * (gas.temperature - target_temperature) ), MAX_ENERGY_CHANGE)
+ var/heat_capacity = gas.heat_capacity()
+ var/energy_used = max(abs(heat_capacity * (gas.temperature() - alarm.target_temperature) ), MAX_ENERGY_CHANGE)
- //Use power. Assuming that each power unit represents 1000 watts....
- use_power(energy_used / 1000, PW_CHANNEL_ENVIRONMENT)
+ //Use power. Assuming that each power unit represents 1000 watts....
+ alarm.use_power(energy_used / 1000, PW_CHANNEL_ENVIRONMENT)
- //We need to cool ourselves.
- if(heat_capacity)
- if(environment.temperature > target_temperature)
- gas.temperature -= energy_used / heat_capacity
- else
- gas.temperature += energy_used / heat_capacity
+ //We need to cool ourselves.
+ if(heat_capacity)
+ if(environment.temperature() > alarm.target_temperature)
+ gas.set_temperature(gas.temperature() - energy_used / heat_capacity)
+ else
+ gas.set_temperature(gas.temperature() + energy_used / heat_capacity)
- if(abs(environment.temperature - target_temperature) <= 0.5)
- regulating_temperature = FALSE
- visible_message("[src] clicks quietly as it stops [environment.temperature > target_temperature ? "cooling" : "heating"] the room.", "You hear a click as a faint electronic humming stops.")
+ if(abs(environment.temperature() - alarm.target_temperature) <= 0.5)
+ alarm.regulating_temperature = FALSE
+ alarm.visible_message("[alarm] clicks quietly as it stops [environment.temperature() > alarm.target_temperature ? "cooling" : "heating"] the room.", "You hear a click as a faint electronic humming stops.")
environment.merge(gas)
@@ -577,36 +582,36 @@
if(!istype(location))
return
- var/datum/gas_mixture/environment = location.return_air()
- var/known_total = environment.oxygen + environment.nitrogen + environment.carbon_dioxide + environment.toxins + environment.sleeping_agent
+ var/datum/gas_mixture/environment = location.get_readonly_air()
+ var/known_total = environment.oxygen() + environment.nitrogen() + environment.carbon_dioxide() + environment.toxins() + environment.sleeping_agent()
var/total = environment.total_moles()
var/datum/tlv/cur_tlv
- var/GET_PP = R_IDEAL_GAS_EQUATION*environment.temperature/environment.volume
+ var/GET_PP = R_IDEAL_GAS_EQUATION * environment.temperature() / environment.volume
cur_tlv = TLV["pressure"]
var/environment_pressure = environment.return_pressure()
var/pressure_dangerlevel = cur_tlv.get_danger_level(environment_pressure)
cur_tlv = TLV["oxygen"]
- var/oxygen_dangerlevel = cur_tlv.get_danger_level(environment.oxygen*GET_PP)
- var/oxygen_percent = total ? environment.oxygen / total * 100 : 0
+ var/oxygen_dangerlevel = cur_tlv.get_danger_level(environment.oxygen() * GET_PP)
+ var/oxygen_percent = total ? environment.oxygen() / total * 100 : 0
cur_tlv = TLV["nitrogen"]
- var/nitrogen_dangerlevel = cur_tlv.get_danger_level(environment.nitrogen*GET_PP)
- var/nitrogen_percent = total ? environment.nitrogen / total * 100 : 0
+ var/nitrogen_dangerlevel = cur_tlv.get_danger_level(environment.nitrogen() * GET_PP)
+ var/nitrogen_percent = total ? environment.nitrogen() / total * 100 : 0
cur_tlv = TLV["carbon dioxide"]
- var/co2_dangerlevel = cur_tlv.get_danger_level(environment.carbon_dioxide*GET_PP)
- var/co2_percent = total ? environment.carbon_dioxide / total * 100 : 0
+ var/co2_dangerlevel = cur_tlv.get_danger_level(environment.carbon_dioxide() * GET_PP)
+ var/co2_percent = total ? environment.carbon_dioxide() / total * 100 : 0
cur_tlv = TLV["plasma"]
- var/plasma_dangerlevel = cur_tlv.get_danger_level(environment.toxins*GET_PP)
- var/plasma_percent = total ? environment.toxins / total * 100 : 0
+ var/plasma_dangerlevel = cur_tlv.get_danger_level(environment.toxins() * GET_PP)
+ var/plasma_percent = total ? environment.toxins() / total * 100 : 0
cur_tlv = TLV["nitrous oxide"]
- var/sleeping_agent_dangerlevel = cur_tlv.get_danger_level(environment.sleeping_agent*GET_PP)
- var/sleeping_agent_percent = total ? environment.sleeping_agent / total * 100 : 0
+ var/sleeping_agent_dangerlevel = cur_tlv.get_danger_level(environment.sleeping_agent() * GET_PP)
+ var/sleeping_agent_percent = total ? environment.sleeping_agent() / total * 100 : 0
cur_tlv = TLV["other"]
var/other_moles = total - known_total
@@ -614,12 +619,12 @@
var/other_percent = total ? other_moles / total * 100 : 0
cur_tlv = TLV["temperature"]
- var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature)
+ var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature())
var/list/data = list()
data["pressure"] = environment_pressure
- data["temperature"] = environment.temperature
- data["temperature_c"] = round(environment.temperature - T0C, 0.1)
+ data["temperature"] = environment.temperature()
+ data["temperature_c"] = round(environment.temperature() - T0C, 0.1)
data["thermostat_state"] = thermostat_state
var/list/percentages = list()
diff --git a/code/modules/atmospherics/machinery/atmospherics.dm b/code/modules/atmospherics/machinery/atmospherics.dm
index d1b103b57c9..08cd2b0382b 100644
--- a/code/modules/atmospherics/machinery/atmospherics.dm
+++ b/code/modules/atmospherics/machinery/atmospherics.dm
@@ -65,6 +65,8 @@ Pipelines + Other Objects -> Pipe network
pipe_color = null
/obj/machinery/atmospherics/proc/process_atmos() //If you dont use process why are you here
+ // Any proc that wants MILLA to be synchronous should not sleep.
+ SHOULD_NOT_SLEEP(TRUE)
return PROCESS_KILL
/obj/machinery/atmospherics/proc/atmos_init()
@@ -73,7 +75,7 @@ Pipelines + Other Objects -> Pipe network
/obj/machinery/atmospherics/Destroy()
SSair.atmos_machinery -= src
- SSair.deferred_pipenet_rebuilds -= src
+ SSair.pipenets_to_build -= src
for(var/mob/living/L in src) //ventcrawling is serious business
L.remove_ventcrawl()
L.forceMove(get_turf(src))
@@ -175,10 +177,10 @@ Pipelines + Other Objects -> Pipe network
/obj/machinery/atmospherics/proc/build_network(remove_deferral = FALSE)
// Called to build a network from this node
if(remove_deferral)
- SSair.deferred_pipenet_rebuilds -= src
+ SSair.pipenets_to_build -= src
/obj/machinery/atmospherics/proc/defer_build_network()
- SSair.deferred_pipenet_rebuilds += src
+ SSair.pipenets_to_build += src
/obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference)
return
@@ -197,8 +199,8 @@ Pipelines + Other Objects -> Pipe network
if(level == 1 && isturf(T) && T.intact)
to_chat(user, "You must remove the plating first.")
return
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
+ var/datum/gas_mixture/int_air = return_obj_air()
+ var/datum/gas_mixture/env_air = T.get_readonly_air()
add_fingerprint(user)
var/unsafe_wrenching = FALSE
@@ -252,8 +254,9 @@ Pipelines + Other Objects -> Pipe network
return
if(!pressures)
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
+ var/datum/gas_mixture/int_air = return_obj_air()
+ var/turf/T = get_turf(src)
+ var/datum/gas_mixture/env_air = T.get_readonly_air()
pressures = int_air.return_pressure() - env_air.return_pressure()
var/fuck_you_dir = get_dir(src, user)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/binary_atmos_base.dm b/code/modules/atmospherics/machinery/components/binary_devices/binary_atmos_base.dm
index bff72287926..5120a43c0ab 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/binary_atmos_base.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/binary_atmos_base.dm
@@ -144,12 +144,10 @@
var/turf/T = get_turf(src)
if(T)
//Remove the gas from air1+air2 and assume it
- var/datum/gas_mixture/environment = T.return_air()
- var/lost = pressures*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
- lost += pressures*environment.volume/(air2.temperature * R_IDEAL_GAS_EQUATION)
- var/shared_loss = lost/2
+ var/lost = pressures * CELL_VOLUME / (air1.temperature() * R_IDEAL_GAS_EQUATION)
+ lost += pressures * CELL_VOLUME / (air2.temperature() * R_IDEAL_GAS_EQUATION)
+ var/shared_loss = lost / 2
var/datum/gas_mixture/to_release = air1.remove(shared_loss)
to_release.merge(air2.remove(shared_loss))
- T.assume_air(to_release)
- air_update_turf(1)
+ T.blind_release_air(to_release)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
index 0636ad44b33..5783ac6a522 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
@@ -53,9 +53,9 @@
return
//Calculate necessary moles to transfer using PV = nRT
- if(inlet.temperature > 0)
+ if(inlet.temperature() > 0)
var/pressure_delta = (input_starting_pressure - output_starting_pressure) / 2
- var/transfer_moles = pressure_delta * outlet.volume/(inlet.temperature * R_IDEAL_GAS_EQUATION)
+ var/transfer_moles = pressure_delta * outlet.volume/(inlet.temperature() * R_IDEAL_GAS_EQUATION)
if(last_pressure_delta != pressure_delta)
last_pressure_delta = pressure_delta
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
index 41f09473a33..8ec612546e9 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
@@ -55,11 +55,11 @@
return 1
//Calculate necessary moles to transfer using PV = nRT
- if((air1.total_moles() > 0) && (air1.temperature > 0))
+ if((air1.total_moles() > 0) && (air1.temperature() > 0))
var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure) / 2)
//Can not have a pressure delta that would cause output_pressure > input_pressure
- var/transfer_moles = pressure_delta * air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
+ var/transfer_moles = pressure_delta * air2.volume / (air1.temperature() * R_IDEAL_GAS_EQUATION)
//Actually transfer the gas
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
index 5d335eab813..86f63455d99 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
@@ -82,9 +82,9 @@ Thus, the two variables affect pump operation are set in New():
return 1
//Calculate necessary moles to transfer using PV=nRT
- if((air1.total_moles() > 0) && (air1.temperature>0))
+ if((air1.total_moles() > 0) && (air1.temperature() > 0))
var/pressure_delta = target_pressure - output_starting_pressure
- var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
+ var/transfer_moles = pressure_delta * air2.volume / (air1.temperature() * R_IDEAL_GAS_EQUATION)
//Actually transfer the gas
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
index 2588b232fd7..f4bac4ae388 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
@@ -108,8 +108,8 @@
var/pressure_delta = target_pressure - output_starting_pressure
var/transfer_moles
- if(air1.temperature > 0)
- transfer_moles = pressure_delta*air3.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
+ if(air1.temperature() > 0)
+ transfer_moles = pressure_delta * air3.volume / (air1.temperature() * R_IDEAL_GAS_EQUATION)
//Actually transfer the gas
@@ -119,31 +119,31 @@
if(!removed)
return
var/datum/gas_mixture/filtered_out = new
- filtered_out.temperature = removed.temperature
+ filtered_out.set_temperature(removed.temperature())
switch(filter_type)
if(FILTER_TOXINS)
- filtered_out.toxins = removed.toxins
- removed.toxins = 0
+ filtered_out.set_toxins(removed.toxins())
+ removed.set_toxins(0)
- filtered_out.agent_b = removed.agent_b
- removed.agent_b = 0
+ filtered_out.set_agent_b(removed.agent_b())
+ removed.set_agent_b(0)
if(FILTER_OXYGEN)
- filtered_out.oxygen = removed.oxygen
- removed.oxygen = 0
+ filtered_out.set_oxygen(removed.oxygen())
+ removed.set_oxygen(0)
if(FILTER_NITROGEN)
- filtered_out.nitrogen = removed.nitrogen
- removed.nitrogen = 0
+ filtered_out.set_nitrogen(removed.nitrogen())
+ removed.set_nitrogen(0)
if(FILTER_CO2)
- filtered_out.carbon_dioxide = removed.carbon_dioxide
- removed.carbon_dioxide = 0
+ filtered_out.set_carbon_dioxide(removed.carbon_dioxide())
+ removed.set_carbon_dioxide(0)
if(FILTER_N2O)
- filtered_out.sleeping_agent = removed.sleeping_agent
- removed.sleeping_agent = 0
+ filtered_out.set_sleeping_agent(removed.sleeping_agent())
+ removed.set_sleeping_agent(0)
else
filtered_out = null
@@ -151,11 +151,14 @@
air2.merge(filtered_out)
air3.merge(removed)
- parent2.update = 1
+ if(!QDELETED(parent1))
+ parent1.update = 1
- parent3.update = 1
+ if(!QDELETED(parent2))
+ parent2.update = 1
- parent1.update = 1
+ if(!QDELETED(parent3))
+ parent3.update = 1
return TRUE
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
index 6a714ae8262..677df08ea06 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
@@ -94,11 +94,11 @@
var/transfer_moles1 = 0
var/transfer_moles2 = 0
- if(air1.temperature > 0)
- transfer_moles1 = (node1_concentration*pressure_delta)*air3.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
+ if(air1.temperature() > 0)
+ transfer_moles1 = (node1_concentration*pressure_delta)*air3.volume/(air1.temperature() * R_IDEAL_GAS_EQUATION)
- if(air2.temperature > 0)
- transfer_moles2 = (node2_concentration*pressure_delta)*air3.volume/(air2.temperature * R_IDEAL_GAS_EQUATION)
+ if(air2.temperature() > 0)
+ transfer_moles2 = (node2_concentration*pressure_delta)*air3.volume/(air2.temperature() * R_IDEAL_GAS_EQUATION)
var/air1_moles = air1.total_moles()
var/air2_moles = air2.total_moles()
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm b/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm
index afb1c014e53..ce1b0dfd003 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/trinary_base.dm
@@ -199,14 +199,12 @@
var/turf/T = get_turf(src)
if(T)
//Remove the gas from air1+air2+air3 and assume it
- var/datum/gas_mixture/environment = T.return_air()
- var/lost = pressures*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
- lost += pressures*environment.volume/(air2.temperature * R_IDEAL_GAS_EQUATION)
- lost += pressures*environment.volume/(air3.temperature * R_IDEAL_GAS_EQUATION)
+ var/lost = pressures * CELL_VOLUME / (air1.temperature() * R_IDEAL_GAS_EQUATION)
+ lost += pressures * CELL_VOLUME / (air2.temperature() * R_IDEAL_GAS_EQUATION)
+ lost += pressures * CELL_VOLUME / (air3.temperature() * R_IDEAL_GAS_EQUATION)
var/shared_loss = lost/3
var/datum/gas_mixture/to_release = air1.remove(shared_loss)
to_release.merge(air2.remove(shared_loss))
to_release.merge(air3.remove(shared_loss))
- T.assume_air(to_release)
- air_update_turf(1)
+ T.blind_release_air(to_release)
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index a8e75f02e4a..1025b299100 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -182,10 +182,10 @@
return
if(air_contents)
- temperature_archived = air_contents.temperature
+ temperature_archived = air_contents.temperature()
heat_gas_contents()
- if(abs(temperature_archived-air_contents.temperature) > 1)
+ if(abs(temperature_archived-air_contents.temperature()) > 1)
parent.update = 1
@@ -240,11 +240,11 @@
occupantData["bodyTemperature"] = occupant.bodytemperature
data["occupant"] = occupantData
- data["cellTemperature"] = round(air_contents.temperature)
+ data["cellTemperature"] = round(air_contents.temperature())
data["cellTemperatureStatus"] = "good"
- if(air_contents.temperature > T0C) // if greater than 273.15 kelvin (0 celcius)
+ if(air_contents.temperature() > T0C) // if greater than 273.15 kelvin (0 celcius)
data["cellTemperatureStatus"] = "bad"
- else if(air_contents.temperature > TCRYO)
+ else if(air_contents.temperature() > TCRYO)
data["cellTemperatureStatus"] = "average"
data["isBeakerLoaded"] = beaker ? TRUE : FALSE
@@ -379,14 +379,14 @@
occupant.bodytemperature = T0C
return
- occupant.bodytemperature += 2 * (air_contents.temperature - occupant.bodytemperature) * current_heat_capacity / (current_heat_capacity + air_contents.heat_capacity())
- occupant.bodytemperature = max(occupant.bodytemperature, air_contents.temperature) // this is so ugly i'm sorry for doing it i'll fix it later i promise
+ occupant.bodytemperature += 2 * (air_contents.temperature() - occupant.bodytemperature) * current_heat_capacity / (current_heat_capacity + air_contents.heat_capacity())
+ occupant.bodytemperature = max(occupant.bodytemperature, air_contents.temperature()) // this is so ugly i'm sorry for doing it i'll fix it later i promise
if(occupant.bodytemperature < T0C)
var/stun_time = (max(5 / efficiency, (1 / occupant.bodytemperature) * 2000 / efficiency)) STATUS_EFFECT_CONSTANT
occupant.Sleeping(stun_time)
- var/heal_mod = air_contents.oxygen < 2 ? 0.2 : 1
+ var/heal_mod = air_contents.oxygen() < 2 ? 0.2 : 1
occupant.adjustOxyLoss(-6 * heal_mod)
if(beaker && world.time >= last_injection + injection_cooldown)
@@ -403,8 +403,8 @@
var/air_heat_capacity = air_contents.heat_capacity()
var/combined_heat_capacity = current_heat_capacity + air_heat_capacity
if(combined_heat_capacity > 0)
- var/combined_energy = T20C*current_heat_capacity + air_heat_capacity*air_contents.temperature
- air_contents.temperature = combined_energy/combined_heat_capacity
+ var/combined_energy = T20C * current_heat_capacity + air_heat_capacity * air_contents.temperature()
+ air_contents.set_temperature(combined_energy / combined_heat_capacity)
/obj/machinery/atmospherics/unary/cryo_cell/proc/go_out()
if(!occupant)
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm b/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm
index 865dfc0baea..60a7a1187a7 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm
@@ -42,20 +42,20 @@
var/other_air_heat_capacity = partner.air_contents.heat_capacity()
var/combined_heat_capacity = other_air_heat_capacity + air_heat_capacity
- var/old_temperature = air_contents.temperature
- var/other_old_temperature = partner.air_contents.temperature
+ var/old_temperature = air_contents.temperature()
+ var/other_old_temperature = partner.air_contents.temperature()
if(combined_heat_capacity > 0)
- var/combined_energy = partner.air_contents.temperature*other_air_heat_capacity + air_heat_capacity*air_contents.temperature
+ var/combined_energy = partner.air_contents.temperature() * other_air_heat_capacity + air_heat_capacity * air_contents.temperature()
var/new_temperature = combined_energy/combined_heat_capacity
- air_contents.temperature = new_temperature
- partner.air_contents.temperature = new_temperature
+ air_contents.set_temperature(new_temperature)
+ partner.air_contents.set_temperature(new_temperature)
- if(abs(old_temperature-air_contents.temperature) > 1)
+ if(abs(old_temperature-air_contents.temperature()) > 1)
parent.update = 1
- if(abs(other_old_temperature-partner.air_contents.temperature) > 1)
+ if(abs(other_old_temperature-partner.air_contents.temperature()) > 1)
partner.parent.update = 1
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
index e7c6b839bd6..d320f0fb4f5 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
@@ -59,13 +59,13 @@ GLOBAL_LIST_EMPTY(air_injectors)
if(!on || stat & NOPOWER)
return 0
- if(air_contents.temperature > 0)
- var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
+ if(air_contents.temperature() > 0)
+ var/transfer_moles = (air_contents.return_pressure()) * volume_rate / (air_contents.temperature() * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
- loc.assume_air(removed)
- air_update_turf()
+ var/turf/T = get_turf(src)
+ T.blind_release_air(removed)
parent.update = TRUE
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm b/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm
index 5b8b3e33ae8..7edb250a174 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/oxygen_generator.dm
@@ -35,8 +35,8 @@
var/added_oxygen = oxygen_content - total_moles
- air_contents.temperature = (current_heat_capacity*air_contents.temperature + 20*added_oxygen*T0C)/(current_heat_capacity+20*added_oxygen)
- air_contents.oxygen += added_oxygen
+ air_contents.set_temperature((current_heat_capacity * air_contents.temperature() + 20 * added_oxygen * T0C) / (current_heat_capacity + 20 * added_oxygen))
+ air_contents.set_oxygen(air_contents.oxygen() + added_oxygen)
parent.update = 1
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
index 1381b56d71e..da6175c64d8 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
@@ -20,16 +20,21 @@
air_contents.volume = volume
/obj/machinery/atmospherics/unary/passive_vent/process_atmos()
- if(!node)
- return 0
+ var/datum/milla_safe/passive_vent_processing/milla = new()
+ milla.invoke_async(src)
- var/turf/T = loc
+/datum/milla_safe/passive_vent_processing
+
+/datum/milla_safe/passive_vent_processing/on_run(obj/machinery/atmospherics/unary/passive_vent/vent)
+ if(!vent.node)
+ return FALSE
+
+ var/turf/T = get_turf(vent)
if(T.density) //No, you should not be able to get free air from walls
return
+ var/datum/gas_mixture/environment = get_turf_air(T)
- var/datum/gas_mixture/environment = loc.return_air()
-
- var/pressure_delta = air_contents.return_pressure() - environment.return_pressure()
+ var/pressure_delta = vent.air_contents.return_pressure() - environment.return_pressure()
// based on pressure_pump to equalize pressure
// already equalized
@@ -38,25 +43,23 @@
if(pressure_delta > 0)
// transfer from pipe air to environment
- if((air_contents.total_moles() > 0) && (air_contents.temperature > 0))
- var/transfer_moles = pressure_delta * environment.volume / (air_contents.temperature * R_IDEAL_GAS_EQUATION)
- transfer_moles = min(transfer_moles, volume)
+ if((vent.air_contents.total_moles() > 0) && (vent.air_contents.temperature() > 0))
+ var/transfer_moles = pressure_delta * environment.volume / (vent.air_contents.temperature() * R_IDEAL_GAS_EQUATION)
+ transfer_moles = min(transfer_moles, vent.volume)
- var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
- loc.assume_air(removed)
- air_update_turf()
+ var/datum/gas_mixture/removed = vent.air_contents.remove(transfer_moles)
+ environment.merge(removed)
else
// transfer from environment to pipe air
pressure_delta = -pressure_delta
- if((environment.total_moles() > 0) && (environment.temperature > 0))
- var/transfer_moles = pressure_delta * air_contents.volume / (environment.temperature * R_IDEAL_GAS_EQUATION)
- transfer_moles = min(transfer_moles, volume)
+ if((environment.total_moles() > 0) && (environment.temperature() > 0))
+ var/transfer_moles = pressure_delta * vent.air_contents.volume / (environment.temperature() * R_IDEAL_GAS_EQUATION)
+ transfer_moles = min(transfer_moles, vent.volume)
- var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
- air_contents.merge(removed)
- air_update_turf()
+ var/datum/gas_mixture/removed = environment.remove(transfer_moles)
+ vent.air_contents.merge(removed)
- parent.update = 1
+ vent.parent.update = 1
return 1
/obj/machinery/atmospherics/unary/passive_vent/update_underlays()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
index 79522616de3..2193b03cd1a 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
@@ -28,9 +28,9 @@
. = ..()
icon_state = "air"
air_contents.volume = volume
- air_contents.temperature = T20C
- air_contents.oxygen = (25*ONE_ATMOSPHERE*O2STANDARD)*(air_contents.volume)/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
- air_contents.nitrogen = (25*ONE_ATMOSPHERE*N2STANDARD)*(air_contents.volume)/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
+ air_contents.set_temperature(T20C)
+ air_contents.set_oxygen((25 * ONE_ATMOSPHERE * O2STANDARD) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
+ air_contents.set_nitrogen((25 * ONE_ATMOSPHERE * N2STANDARD) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
/obj/machinery/atmospherics/unary/tank/oxygen
name = "Pressure Tank (Oxygen)"
@@ -40,8 +40,8 @@
. = ..()
icon_state = "o2"
air_contents.volume = volume
- air_contents.temperature = T20C
- air_contents.oxygen = (25*ONE_ATMOSPHERE)*(air_contents.volume)/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
+ air_contents.set_temperature(T20C)
+ air_contents.set_oxygen((25 * ONE_ATMOSPHERE) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
/obj/machinery/atmospherics/unary/tank/nitrogen
name = "Pressure Tank (Nitrogen)"
@@ -51,8 +51,8 @@
. = ..()
icon_state = "n2"
air_contents.volume = volume
- air_contents.temperature = T20C
- air_contents.nitrogen = (25*ONE_ATMOSPHERE)*(air_contents.volume)/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
+ air_contents.set_temperature(T20C)
+ air_contents.set_nitrogen((25 * ONE_ATMOSPHERE) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
/obj/machinery/atmospherics/unary/tank/carbon_dioxide
name = "Pressure Tank (Carbon Dioxide)"
@@ -62,8 +62,8 @@
. = ..()
icon_state = "co2"
air_contents.volume = volume
- air_contents.temperature = T20C
- air_contents.carbon_dioxide = (25*ONE_ATMOSPHERE)*(air_contents.volume)/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
+ air_contents.set_temperature(T20C)
+ air_contents.set_carbon_dioxide((25 * ONE_ATMOSPHERE) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
/obj/machinery/atmospherics/unary/tank/toxins
name = "Pressure Tank (Toxins)"
@@ -73,8 +73,8 @@
. = ..()
icon_state = "toxins"
air_contents.volume = volume
- air_contents.temperature = T20C
- air_contents.toxins = (25*ONE_ATMOSPHERE)*(air_contents.volume)/(R_IDEAL_GAS_EQUATION*air_contents.temperature)
+ air_contents.set_temperature(T20C)
+ air_contents.set_toxins((25 * ONE_ATMOSPHERE) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
/obj/machinery/atmospherics/unary/tank/nitrous_oxide
name = "Pressure Tank (Nitrous Oxide)"
@@ -84,9 +84,9 @@
. = ..()
icon_state = "n2o"
air_contents.volume = volume
- air_contents.temperature = T20C
+ air_contents.set_temperature(T20C)
- air_contents.sleeping_agent = (25 * ONE_ATMOSPHERE) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ air_contents.set_sleeping_agent((25 * ONE_ATMOSPHERE) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
/obj/machinery/atmospherics/unary/tank/oxygen_agent_b
name = "Unidentified Gas Tank"
@@ -97,6 +97,6 @@
. = ..()
icon_state = "agent_b"
air_contents.volume = volume
- air_contents.temperature = T20C
+ air_contents.set_temperature(T20C)
- air_contents.agent_b = (50 * ONE_ATMOSPHERE) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ air_contents.set_agent_b((50 * ONE_ATMOSPHERE) * (air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm
index 633f40704ba..3fda9371020 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermal_plate.dm
@@ -18,7 +18,14 @@
icon_state = "[prefix]off"
/obj/machinery/atmospherics/unary/thermal_plate/process_atmos()
- var/datum/gas_mixture/environment = loc.return_air()
+ var/datum/milla_safe/thermal_plate_process/milla = new()
+ milla.invoke_async(src)
+
+/datum/milla_safe/thermal_plate_process
+
+/datum/milla_safe/thermal_plate_process/on_run(obj/machinery/atmospherics/unary/thermal_plate/plate)
+ var/turf/T = get_turf(plate)
+ var/datum/gas_mixture/environment = get_turf_air(T)
//Get processable air sample and thermal info from environment
@@ -26,33 +33,33 @@
var/datum/gas_mixture/external_removed = environment.remove(transfer_moles)
if(!external_removed)
- return radiate()
+ return plate.radiate()
if(external_removed.total_moles() < 10)
- return radiate()
+ return plate.radiate()
//Get same info from connected gas
- var/internal_transfer_moles = 0.25 * air_contents.total_moles()
- var/datum/gas_mixture/internal_removed = air_contents.remove(internal_transfer_moles)
+ var/internal_transfer_moles = 0.25 * plate.air_contents.total_moles()
+ var/datum/gas_mixture/internal_removed = plate.air_contents.remove(internal_transfer_moles)
if(!internal_removed)
environment.merge(external_removed)
return 1
var/combined_heat_capacity = internal_removed.heat_capacity() + external_removed.heat_capacity()
- var/combined_energy = internal_removed.temperature * internal_removed.heat_capacity() + external_removed.heat_capacity() * external_removed.temperature
+ var/combined_energy = internal_removed.temperature() * internal_removed.heat_capacity() + external_removed.heat_capacity() * external_removed.temperature()
if(!combined_heat_capacity) combined_heat_capacity = 1
var/final_temperature = combined_energy / combined_heat_capacity
- external_removed.temperature = final_temperature
+ external_removed.set_temperature(final_temperature)
environment.merge(external_removed)
- internal_removed.temperature = final_temperature
- air_contents.merge(internal_removed)
+ internal_removed.set_temperature(final_temperature)
+ plate.air_contents.merge(internal_removed)
- parent.update = 1
+ plate.parent.update = 1
return 1
@@ -64,11 +71,11 @@
return 1
var/combined_heat_capacity = internal_removed.heat_capacity() + RADIATION_CAPACITY
- var/combined_energy = internal_removed.temperature * internal_removed.heat_capacity() + (RADIATION_CAPACITY * 6.4)
+ var/combined_energy = internal_removed.temperature() * internal_removed.heat_capacity() + (RADIATION_CAPACITY * 6.4)
var/final_temperature = combined_energy / combined_heat_capacity
- internal_removed.temperature = final_temperature
+ internal_removed.set_temperature(final_temperature)
air_contents.merge(internal_removed)
parent.update = 1
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
index 03039a7212d..d9a48dce55a 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
@@ -97,25 +97,25 @@
return
// Coolers don't heat.
- if(air_contents.temperature <= target_temperature && cooling)
+ if(air_contents.temperature() <= target_temperature && cooling)
return
// Heaters don't cool.
- if(air_contents.temperature >= target_temperature && !cooling)
+ if(air_contents.temperature() >= target_temperature && !cooling)
return
var/air_heat_capacity = air_contents.heat_capacity()
var/combined_heat_capacity = heat_capacity + air_heat_capacity
- var/old_temperature = air_contents.temperature
+ var/old_temperature = air_contents.temperature()
if(combined_heat_capacity > 0)
- var/combined_energy = heat_capacity * target_temperature + air_heat_capacity * air_contents.temperature
- air_contents.temperature = combined_energy / combined_heat_capacity
+ var/combined_energy = heat_capacity * target_temperature + air_heat_capacity * air_contents.temperature()
+ air_contents.set_temperature(combined_energy / combined_heat_capacity)
//todo: have current temperature affected. require power to bring down current temperature again
- var/temperature_delta = abs(old_temperature - air_contents.temperature)
+ var/temperature_delta = abs(old_temperature - air_contents.temperature())
if(temperature_delta > 1)
- var/new_active_consumption = (temperature_delta * 25) * min(log(10, air_contents.temperature) - 1, 1)
+ var/new_active_consumption = (temperature_delta * 25) * min(log(10, air_contents.temperature()) - 1, 1)
update_active_power_consumption(power_channel, new_active_consumption + idle_power_consumption)
change_power_mode(ACTIVE_POWER_USE)
parent.update = TRUE
@@ -190,7 +190,7 @@
data["target"] = target_temperature
data["initial"] = initial(target_temperature)
- data["temperature"] = air_contents.temperature
+ data["temperature"] = air_contents.temperature()
data["pressure"] = air_contents.return_pressure()
return data
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 a6d766a3c47..293538e76e1 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/unary_base.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/unary_base.dm
@@ -92,10 +92,16 @@
var/turf/T = get_turf(src)
if(T)
- //Remove the gas from air_contents and assume it
- var/datum/gas_mixture/environment = T.return_air()
- var/lost = pressures*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
+ var/datum/milla_safe/unary_unsafe_pressure_release/milla = new()
+ milla.invoke_async(src, pressures)
- var/datum/gas_mixture/to_release = air_contents.remove(lost)
- T.assume_air(to_release)
- air_update_turf(1)
+/datum/milla_safe/unary_unsafe_pressure_release
+
+/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)
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 7ec85af2152..2050b13f581 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
@@ -110,57 +110,61 @@
update_underlays()
/obj/machinery/atmospherics/unary/vent_pump/process_atmos()
- if(stat & (NOPOWER|BROKEN))
+ 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))
return FALSE
- var/turf/T = loc
+ if(QDELETED(vent_pump.parent))
+ // We're orphaned!
+ return FALSE
+ var/turf/T = get_turf(vent_pump)
if(T.density) //No, you should not be able to get free air from walls
return
- if(!node)
- on = FALSE
- //broadcast_status() // from now air alarm/control computer should request update purposely --rastaf0
- if(!on)
+ if(!vent_pump.node)
+ vent_pump.on = FALSE
+ if(!vent_pump.on)
return FALSE
- 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!")
+ 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!")
for(var/mob/living/M in range(1))
- unsafe_pressure_release(M, air_contents.return_pressure()) //let's send everyone flying
- welded = FALSE
- update_icon()
+ 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()
return FALSE
- var/datum/gas_mixture/environment = loc.return_air()
+ var/datum/gas_mixture/environment = get_turf_air(T)
var/environment_pressure = environment.return_pressure()
- if(releasing) //internal -> external
+ if(vent_pump.releasing) //internal -> external
var/pressure_delta = 10000
- if(pressure_checks & 1)
- pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure))
- if(pressure_checks & 2)
- pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound))
+ if(vent_pump.pressure_checks & 1)
+ pressure_delta = min(pressure_delta, (vent_pump.external_pressure_bound - environment_pressure))
+ if(vent_pump.pressure_checks & 2)
+ pressure_delta = min(pressure_delta, (vent_pump.air_contents.return_pressure() - vent_pump.internal_pressure_bound))
- if(pressure_delta > 0.5 && air_contents.temperature > 0)
- var/transfer_moles = pressure_delta * environment.volume / (air_contents.temperature * R_IDEAL_GAS_EQUATION)
- var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
- loc.assume_air(removed)
- air_update_turf()
- parent.update = TRUE
+ if(pressure_delta > 0.5 && vent_pump.air_contents.temperature() > 0)
+ var/transfer_moles = pressure_delta * environment.volume / (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
else //external -> internal
var/pressure_delta = 10000
- if(pressure_checks & 1)
- pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound))
- if(pressure_checks & 2)
- pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure()))
+ if(vent_pump.pressure_checks & 1)
+ pressure_delta = min(pressure_delta, (environment_pressure - vent_pump.external_pressure_bound))
+ if(vent_pump.pressure_checks & 2)
+ pressure_delta = min(pressure_delta, (vent_pump.internal_pressure_bound - vent_pump.air_contents.return_pressure()))
- if(pressure_delta > 0.5 && environment.temperature > 0)
- var/transfer_moles = pressure_delta * air_contents.volume / (environment.temperature * R_IDEAL_GAS_EQUATION)
- var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
- if(isnull(removed)) //in space
- return
- air_contents.merge(removed)
- air_update_turf()
- parent.update = TRUE
+ if(pressure_delta > 0.5 && environment.temperature() > 0)
+ var/transfer_moles = pressure_delta * vent_pump.air_contents.volume / (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
return TRUE
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 bc283f68098..5d470e590a6 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
@@ -133,62 +133,67 @@
adjacent_turfs = T.GetAtmosAdjacentTurfs(alldir=1)
/obj/machinery/atmospherics/unary/vent_scrubber/proc/scrub(turf/simulated/tile)
+ var/datum/milla_safe/vent_scrubber_process/milla = new()
+ milla.invoke_async(src, tile)
+
+/datum/milla_safe/vent_scrubber_process
+
+/datum/milla_safe/vent_scrubber_process/on_run(obj/machinery/atmospherics/unary/vent_scrubber/scrubber, turf/simulated/tile)
if(!tile || !istype(tile))
return 0
- var/datum/gas_mixture/environment = tile.return_air()
+ var/datum/gas_mixture/environment = get_turf_air(tile)
- if(scrubbing)
- if((scrub_O2 && environment.oxygen>0.001) || (scrub_N2 && environment.nitrogen>0.001) || (scrub_CO2 && environment.carbon_dioxide>0.001) || (scrub_Toxins && environment.toxins>0.001) || (environment.sleeping_agent) || (environment.agent_b))
- var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles()
+ 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()))
+ var/transfer_moles = min(1, scrubber.volume_rate / environment.volume) * environment.total_moles()
//Take a gas sample
- var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
+ var/datum/gas_mixture/removed = environment.remove(transfer_moles)
if(isnull(removed)) //in space
return
//Filter it
var/datum/gas_mixture/filtered_out = new
- filtered_out.temperature = removed.temperature
- if(scrub_O2)
- filtered_out.oxygen = removed.oxygen
- removed.oxygen = 0
- if(scrub_N2)
- filtered_out.nitrogen = removed.nitrogen
- removed.nitrogen = 0
- if(scrub_Toxins)
- filtered_out.toxins = removed.toxins
- removed.toxins = 0
- if(scrub_CO2)
- filtered_out.carbon_dioxide = removed.carbon_dioxide
- removed.carbon_dioxide = 0
+ filtered_out.set_temperature(removed.temperature())
+ if(scrubber.scrub_O2)
+ filtered_out.set_oxygen(removed.oxygen())
+ removed.set_oxygen(0)
+ if(scrubber.scrub_N2)
+ filtered_out.set_nitrogen(removed.nitrogen())
+ removed.set_nitrogen(0)
+ if(scrubber.scrub_Toxins)
+ filtered_out.set_toxins(removed.toxins())
+ removed.set_toxins(0)
+ if(scrubber.scrub_CO2)
+ filtered_out.set_carbon_dioxide(removed.carbon_dioxide())
+ removed.set_carbon_dioxide(0)
- if(removed.agent_b)
- filtered_out.agent_b = removed.agent_b
- removed.agent_b = 0
+ if(removed.agent_b())
+ filtered_out.set_agent_b(removed.agent_b())
+ removed.set_agent_b(0)
- if(scrub_N2O)
- filtered_out.sleeping_agent = removed.sleeping_agent
- removed.sleeping_agent = 0
+ if(scrubber.scrub_N2O)
+ filtered_out.set_sleeping_agent(removed.sleeping_agent())
+ removed.set_sleeping_agent(0)
//Remix the resulting gases
- air_contents.merge(filtered_out)
+ scrubber.air_contents.merge(filtered_out)
- tile.assume_air(removed)
- tile.air_update_turf()
+ environment.merge(removed)
else //Just siphoning all air
- if(air_contents.return_pressure() >= (50 * ONE_ATMOSPHERE))
+ if(scrubber.air_contents.return_pressure() >= (50 * ONE_ATMOSPHERE))
return
- var/transfer_moles = environment.total_moles() * (volume_rate/environment.volume)
+ var/transfer_moles = environment.total_moles() * (scrubber.volume_rate / environment.volume)
- var/datum/gas_mixture/removed = tile.remove_air(transfer_moles)
+ var/datum/gas_mixture/removed = environment.remove(transfer_moles)
- air_contents.merge(removed)
- tile.air_update_turf()
+ scrubber.air_contents.merge(removed)
- parent.update = 1
+ if(!QDELETED(scrubber.parent))
+ scrubber.parent.update = 1
return 1
diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm
index 7a9fbf70f38..416e4556d7a 100644
--- a/code/modules/atmospherics/machinery/datum_pipeline.dm
+++ b/code/modules/atmospherics/machinery/datum_pipeline.dm
@@ -8,10 +8,10 @@
var/update = TRUE
/datum/pipeline/New()
- SSair.networks += src
+ SSair.pipenets += src
/datum/pipeline/Destroy()
- SSair.networks -= src
+ SSair.pipenets -= src
if(air && air.volume)
temporarily_store_air()
for(var/obj/machinery/atmospherics/pipe/P in members)
@@ -121,18 +121,26 @@
member.air_temporary = new
member.air_temporary.volume = member.volume
- member.air_temporary.oxygen = air.oxygen * member.volume / air.volume
- member.air_temporary.nitrogen = air.nitrogen * member.volume / air.volume
- member.air_temporary.toxins = air.toxins * member.volume / air.volume
- member.air_temporary.carbon_dioxide = air.carbon_dioxide * member.volume / air.volume
- member.air_temporary.sleeping_agent = air.sleeping_agent * member.volume / air.volume
- member.air_temporary.agent_b = air.agent_b * member.volume / air.volume
+ member.air_temporary.set_oxygen(air.oxygen() * member.volume / air.volume)
+ member.air_temporary.set_nitrogen(air.nitrogen() * member.volume / air.volume)
+ member.air_temporary.set_toxins(air.toxins() * member.volume / air.volume)
+ member.air_temporary.set_carbon_dioxide(air.carbon_dioxide() * member.volume / air.volume)
+ member.air_temporary.set_sleeping_agent(air.sleeping_agent() * member.volume / air.volume)
+ member.air_temporary.set_agent_b(air.agent_b() * member.volume / air.volume)
- member.air_temporary.temperature = air.temperature
+ member.air_temporary.set_temperature(air.temperature())
/datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity)
- var/total_heat_capacity = air.heat_capacity()
- var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
+ var/datum/milla_safe/pipeline_temperature_interact/milla = new()
+ milla.invoke_async(src, target, share_volume, thermal_conductivity)
+
+/datum/milla_safe/pipeline_temperature_interact
+
+/datum/milla_safe/pipeline_temperature_interact/on_run(datum/pipeline/pipeline, turf/target, share_volume, thermal_conductivity)
+ var/datum/gas_mixture/environment = get_turf_air(target)
+
+ var/total_heat_capacity = pipeline.air.heat_capacity()
+ var/partial_heat_capacity = total_heat_capacity*(share_volume/pipeline.air.volume)
if(issimulatedturf(target))
var/turf/simulated/modeled_location = target
@@ -140,20 +148,20 @@
if(modeled_location.blocks_air)
if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0))
- var/delta_temperature = air.temperature - modeled_location.temperature
+ var/delta_temperature = pipeline.air.temperature() - modeled_location.temperature
var/heat = thermal_conductivity*delta_temperature* \
(partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity))
- air.temperature -= heat/total_heat_capacity
+ pipeline.air.set_temperature(pipeline.air.temperature() - heat / total_heat_capacity)
modeled_location.temperature += heat/modeled_location.heat_capacity
else
var/delta_temperature = 0
var/sharer_heat_capacity = 0
- delta_temperature = (air.temperature - modeled_location.air.temperature)
- sharer_heat_capacity = modeled_location.air.heat_capacity()
+ delta_temperature = (pipeline.air.temperature() - environment.temperature())
+ sharer_heat_capacity = environment.heat_capacity()
var/self_temperature_delta = 0
var/sharer_temperature_delta = 0
@@ -167,20 +175,20 @@
else
return 1
- air.temperature += self_temperature_delta
+ pipeline.air.set_temperature(pipeline.air.temperature() + self_temperature_delta)
- modeled_location.air.temperature += sharer_temperature_delta
+ environment.set_temperature(environment.temperature() + sharer_temperature_delta)
else
if((target.heat_capacity>0) && (partial_heat_capacity>0))
- var/delta_temperature = air.temperature - target.temperature
+ var/delta_temperature = pipeline.air.temperature() - target.temperature
- var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
+ var/heat = thermal_conductivity * delta_temperature * \
+ (partial_heat_capacity * target.heat_capacity / (partial_heat_capacity + target.heat_capacity))
- air.temperature -= heat/total_heat_capacity
- update = TRUE
+ pipeline.air.set_temperature(pipeline.air.temperature() - heat / total_heat_capacity)
+ pipeline.update = TRUE
/datum/pipeline/proc/reconcile_air()
var/list/datum/gas_mixture/GL = list()
@@ -210,43 +218,4 @@
if(C.connected_device)
GL += C.portableConnectorReturnAir()
- 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
-
- for(var/datum/gas_mixture/G in GL)
- total_volume += G.volume
- total_thermal_energy += G.thermal_energy()
- total_heat_capacity += G.heat_capacity()
-
- total_oxygen += G.oxygen
- total_nitrogen += G.nitrogen
- total_toxins += G.toxins
- total_carbon_dioxide += G.carbon_dioxide
- total_sleeping_agent += G.sleeping_agent
- total_agent_b += G.agent_b
-
- if(total_volume > 0)
-
- //Calculate temperature
- var/temperature = 0
-
- 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 in GL)
- G.oxygen = total_oxygen * G.volume / total_volume
- G.nitrogen = total_nitrogen * G.volume / total_volume
- G.toxins = total_toxins * G.volume / total_volume
- G.carbon_dioxide = total_carbon_dioxide * G.volume / total_volume
- G.sleeping_agent = total_sleeping_agent * G.volume / total_volume
- G.agent_b = total_agent_b * G.volume / total_volume
-
- G.temperature = temperature
+ share_many_airs(GL)
diff --git a/code/modules/atmospherics/machinery/other/meter.dm b/code/modules/atmospherics/machinery/other/meter.dm
index 1d8b54b8111..032ffa60068 100644
--- a/code/modules/atmospherics/machinery/other/meter.dm
+++ b/code/modules/atmospherics/machinery/other/meter.dm
@@ -38,7 +38,7 @@ GLOBAL_LIST_EMPTY(gas_meters)
icon_state = "meter0"
return
- var/datum/gas_mixture/environment = target.return_air()
+ var/datum/gas_mixture/environment = target.return_obj_air()
if(!environment)
icon_state = "meterX"
return
@@ -68,9 +68,9 @@ GLOBAL_LIST_EMPTY(gas_meters)
. += "The display is off."
else if(target)
- var/datum/gas_mixture/environment = target.return_air()
+ var/datum/gas_mixture/environment = target.return_obj_air()
if(environment)
- . += "The pressure gauge reads [round(environment.return_pressure(), 0.01)] kPa; [round(environment.temperature,0.01)]K ([round(environment.temperature-T0C,0.01)]°C)"
+ . += "The pressure gauge reads [round(environment.return_pressure(), 0.01)] kPa; [round(environment.temperature(), 0.01)]K ([round(environment.temperature() - T0C, 0.01)]°C)"
else
. += "The sensor error light is blinking."
else
diff --git a/code/modules/atmospherics/machinery/pipes/pipe.dm b/code/modules/atmospherics/machinery/pipes/pipe.dm
index 04fb677ccc5..4df99320cf5 100644
--- a/code/modules/atmospherics/machinery/pipes/pipe.dm
+++ b/code/modules/atmospherics/machinery/pipes/pipe.dm
@@ -22,10 +22,9 @@
level = 1
/obj/machinery/atmospherics/pipe/Destroy()
- releaseAirToTurf()
- QDEL_NULL(air_temporary)
+ var/turf/T = get_turf(src)
+ T.blind_release_air(air_temporary)
- var/turf/T = loc
for(var/obj/machinery/atmospherics/meter/meter in T)
if(meter.target == src)
var/obj/item/pipe_meter/PM = new (T)
@@ -49,13 +48,7 @@
/obj/machinery/atmospherics/proc/pipeline_expansion()
return null
-/obj/machinery/atmospherics/pipe/proc/releaseAirToTurf()
- if(air_temporary)
- var/turf/T = loc
- T.assume_air(air_temporary)
- air_update_turf()
-
-/obj/machinery/atmospherics/pipe/return_air()
+/obj/machinery/atmospherics/pipe/return_obj_air()
RETURN_TYPE(/datum/gas_mixture)
if(!parent)
return 0
diff --git a/code/modules/atmospherics/machinery/pipes/simple/pipe_simple_he.dm b/code/modules/atmospherics/machinery/pipes/simple/pipe_simple_he.dm
index 4a796a5332d..3d1dd04dd86 100644
--- a/code/modules/atmospherics/machinery/pipes/simple/pipe_simple_he.dm
+++ b/code/modules/atmospherics/machinery/pipes/simple/pipe_simple_he.dm
@@ -22,27 +22,24 @@
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/process_atmos()
var/environment_temperature = 0
- var/datum/gas_mixture/pipe_air = return_air()
+ var/datum/gas_mixture/pipe_air = return_obj_air()
if(!pipe_air)
return
- var/turf/simulated/T = loc
- if(istype(T))
- if(T.blocks_air)
- environment_temperature = T.temperature
- else
- var/datum/gas_mixture/environment = T.return_air()
- environment_temperature = environment.temperature
- else
+ var/turf/T = get_turf(src)
+ if(T.blocks_air)
environment_temperature = T.temperature
+ else
+ var/datum/gas_mixture/environment = T.get_readonly_air()
+ environment_temperature = environment.temperature()
- if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
+ if(abs(environment_temperature-pipe_air.temperature()) > minimum_temperature_difference)
parent.temperature_interact(T, volume, thermal_conductivity)
//Heat causes pipe to glow
- if(pipe_air.temperature && (icon_temperature > 500 || pipe_air.temperature > 500)) //glow starts at 500K
- if(abs(pipe_air.temperature - icon_temperature) > 10)
- icon_temperature = pipe_air.temperature
+ if(pipe_air.temperature() && (icon_temperature > 500 || pipe_air.temperature() > 500)) //glow starts at 500K
+ if(abs(pipe_air.temperature() - icon_temperature) > 10)
+ icon_temperature = pipe_air.temperature()
var/h_r = heat2color_r(icon_temperature)
var/h_g = heat2color_g(icon_temperature)
@@ -59,10 +56,10 @@
//burn any mobs buckled based on temperature
if(has_buckled_mobs())
var/heat_limit = 1000
- if(pipe_air.temperature > heat_limit + 1)
+ if(pipe_air.temperature() > heat_limit + 1)
for(var/m in buckled_mobs)
var/mob/living/buckled_mob = m
- buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, "chest")
+ buckled_mob.apply_damage(4 * log(pipe_air.temperature() - heat_limit), BURN, "chest")
/obj/machinery/atmospherics/pipe/simple/heat_exchanging/New()
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index 6d690ef6b85..7826aed7640 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -219,68 +219,69 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
/obj/machinery/atmospherics/portable/canister/proc/canister_break()
disconnect()
var/datum/gas_mixture/expelled_gas = air_contents.remove(air_contents.total_moles())
- var/turf/T = get_turf(src)
- T.assume_air(expelled_gas)
- air_update_turf()
-
stat |= BROKEN
density = FALSE
playsound(loc, 'sound/effects/spray.ogg', 10, TRUE, -3)
update_icon()
+ var/turf/T = get_turf(src)
if(holding_tank)
holding_tank.forceMove(T)
holding_tank = null
+ T.blind_release_air(expelled_gas)
+
/obj/machinery/atmospherics/portable/canister/process_atmos()
- if(stat & BROKEN)
+ ..()
+ 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)
return
- ..()
-
- if(valve_open)
+ if(canister.valve_open)
var/datum/gas_mixture/environment
- if(holding_tank)
- environment = holding_tank.air_contents
+ if(canister.holding_tank)
+ environment = canister.holding_tank.air_contents
else
- environment = loc.return_air()
+ var/turf/T = get_turf(canister)
+ environment = get_turf_air(T)
var/env_pressure = environment.return_pressure()
- var/pressure_delta = min(release_pressure - env_pressure, (air_contents.return_pressure() - env_pressure)/2)
+ 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((air_contents.temperature > 0) && (pressure_delta > 0))
- transfer_moles = pressure_delta * environment.volume / (air_contents.temperature * R_IDEAL_GAS_EQUATION)
+ 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 = air_contents.remove(transfer_moles)
+ var/datum/gas_mixture/removed = canister.air_contents.remove(transfer_moles)
- if(holding_tank)
- environment.merge(removed)
- else
- loc.assume_air(removed)
- air_update_turf()
- update_icon()
+ environment.merge(removed)
+ canister.update_icon()
- if(air_contents.return_pressure() < 1)
- can_label = TRUE
+ if(canister.air_contents.return_pressure() < 1)
+ canister.can_label = TRUE
else
- can_label = FALSE
+ canister.can_label = FALSE
-/obj/machinery/atmospherics/portable/canister/return_air()
+/obj/machinery/atmospherics/portable/canister/return_obj_air()
RETURN_TYPE(/datum/gas_mixture)
return air_contents
/obj/machinery/atmospherics/portable/canister/proc/return_temperature()
- var/datum/gas_mixture/GM = return_air()
- if(GM && GM.volume>0)
- return GM.temperature
+ var/datum/gas_mixture/GM = return_obj_air()
+ if(GM && GM.volume > 0)
+ return GM.temperature()
return
/obj/machinery/atmospherics/portable/canister/proc/return_pressure()
- var/datum/gas_mixture/GM = return_air()
+ var/datum/gas_mixture/GM = return_obj_air()
if(GM && GM.volume>0)
return GM.return_pressure()
return
@@ -384,12 +385,12 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
if(!holding_tank)
logmsg = "Valve was opened by [key_name(ui.user)], starting a transfer into the air. "
- if(air_contents.toxins > 0)
+ if(air_contents.toxins() > 0)
message_admins("[key_name_admin(ui.user)] opened a canister that contains plasma in [get_area(src)]! (JMP)")
log_admin("[key_name(ui.user)] opened a canister that contains plasma at [get_area(src)]: [x], [y], [z]")
ui.user.create_log(MISC_LOG, "has opened a canister of plasma")
- if(air_contents.sleeping_agent > 0)
+ if(air_contents.sleeping_agent() > 0)
message_admins("[key_name_admin(ui.user)] opened a canister that contains N2O in [get_area(src)]! (JMP)")
log_admin("[key_name(ui.user)] opened a canister that contains N2O at [get_area(src)]: [x], [y], [z]")
ui.user.create_log(MISC_LOG, "has opened a canister of N2O")
@@ -462,7 +463,7 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
. = ..()
canister_color["prim"] = "orange"
- air_contents.toxins = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ air_contents.set_toxins((maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
update_icon()
@@ -470,7 +471,7 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
. = ..()
canister_color["prim"] = "blue"
- air_contents.oxygen = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ air_contents.set_oxygen((maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
update_icon()
@@ -478,7 +479,7 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
. = ..()
canister_color["prim"] = "redws"
- air_contents.sleeping_agent = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ air_contents.set_sleeping_agent((maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
update_icon()
@@ -486,7 +487,7 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
. = ..()
canister_color["prim"] = "red"
- air_contents.nitrogen = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ air_contents.set_nitrogen((maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
update_icon()
@@ -495,7 +496,7 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
. = ..()
canister_color["prim"] = "black"
- air_contents.carbon_dioxide = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ air_contents.set_carbon_dioxide((maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
update_icon()
@@ -503,8 +504,8 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new())
. = ..()
canister_color["prim"] = "grey"
- air_contents.oxygen = (O2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
- air_contents.nitrogen = (N2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ air_contents.set_oxygen((O2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
+ air_contents.set_nitrogen((N2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature()))
update_icon()
diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
index 673b139e2d2..c9ee9fd5c02 100644
--- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
+++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
@@ -19,7 +19,7 @@
SSair.atmos_machinery += src
air_contents.volume = volume
- air_contents.temperature = T20C
+ air_contents.set_temperature(T20C)
if(mapload)
return INITIALIZE_HINT_LATELOAD
diff --git a/code/modules/atmospherics/machinery/portable/portable_pump.dm b/code/modules/atmospherics/machinery/portable/portable_pump.dm
index 71093b327fd..5474bdf2bfa 100644
--- a/code/modules/atmospherics/machinery/portable/portable_pump.dm
+++ b/code/modules/atmospherics/machinery/portable/portable_pump.dm
@@ -53,49 +53,46 @@
/obj/machinery/atmospherics/portable/pump/process_atmos()
..()
- 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(holding_tank)
- environment = holding_tank.air_contents
+ if(pump.holding_tank)
+ environment = pump.holding_tank.air_contents
else
- environment = loc.return_air()
- if(direction == DIRECTION_OUT)
- var/pressure_delta = target_pressure - environment.return_pressure()
+ 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(air_contents.temperature > 0)
- transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
+ 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 = air_contents.remove(transfer_moles)
+ var/datum/gas_mixture/removed = pump.air_contents.remove(transfer_moles)
- if(holding_tank)
- environment.merge(removed)
- else
- loc.assume_air(removed)
- air_update_turf()
+ environment.merge(removed)
else
- var/pressure_delta = target_pressure - air_contents.return_pressure()
+ 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*air_contents.volume/(environment.temperature * R_IDEAL_GAS_EQUATION)
+ 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
- if(holding_tank)
- removed = environment.remove(transfer_moles)
- else
- removed = loc.remove_air(transfer_moles)
- air_update_turf()
+ removed = environment.remove(transfer_moles)
- air_contents.merge(removed)
+ pump.air_contents.merge(removed)
- return
-
-/obj/machinery/atmospherics/portable/pump/return_air()
+/obj/machinery/atmospherics/portable/pump/return_obj_air()
RETURN_TYPE(/datum/gas_mixture)
return air_contents
diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm
index 34c7cd59b46..f2526a70dbc 100644
--- a/code/modules/atmospherics/machinery/portable/scrubber.dm
+++ b/code/modules/atmospherics/machinery/portable/scrubber.dm
@@ -46,60 +46,56 @@
/obj/machinery/atmospherics/portable/scrubber/process_atmos()
..()
+ var/datum/milla_safe/portable_scrubber_process/milla = new()
+ milla.invoke_async(src)
- if(!on)
+/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
- scrub(loc)
- if(widenet)
- var/turf/T = loc
- if(istype(T))
- for(var/turf/simulated/tile in T.GetAtmosAdjacentTurfs(alldir=1))
- scrub(tile)
-/obj/machinery/atmospherics/portable/scrubber/proc/scrub(turf/simulated/tile)
- var/datum/gas_mixture/environment
- if(holding_tank)
- environment = holding_tank.air_contents
- else
- environment = tile.return_air()
- var/transfer_moles = min(1,volume_rate/environment.volume)*environment.total_moles()
+ var/turf/T = get_turf(scrubber)
+ scrubber.scrub(get_turf_air(T))
+ if(scrubber.widenet)
+ for(var/turf/simulated/tile in T.GetAtmosAdjacentTurfs(alldir=1))
+ scrubber.scrub(get_turf_air(tile))
+
+/obj/machinery/atmospherics/portable/scrubber/proc/scrub(datum/gas_mixture/environment)
+ var/transfer_moles = min(1, volume_rate / environment.volume) * environment.total_moles()
//Take a gas sample
var/datum/gas_mixture/removed
- if(holding_tank)
- removed = environment.remove(transfer_moles)
- else
- removed = loc.remove_air(transfer_moles)
+ removed = environment.remove(transfer_moles)
//Filter it
if(removed)
var/datum/gas_mixture/filtered_out = new
- filtered_out.temperature = removed.temperature
+ filtered_out.set_temperature(removed.temperature())
- filtered_out.toxins = removed.toxins
- removed.toxins = 0
+ filtered_out.set_toxins(removed.toxins())
+ removed.set_toxins(0)
- filtered_out.carbon_dioxide = removed.carbon_dioxide
- removed.carbon_dioxide = 0
+ filtered_out.set_carbon_dioxide(removed.carbon_dioxide())
+ removed.set_carbon_dioxide(0)
- filtered_out.sleeping_agent = removed.sleeping_agent
- removed.sleeping_agent = 0
+ filtered_out.set_sleeping_agent(removed.sleeping_agent())
+ removed.set_sleeping_agent(0)
- filtered_out.agent_b = removed.agent_b
- removed.agent_b = 0
+ filtered_out.set_agent_b(removed.agent_b())
+ removed.set_agent_b(0)
- //Remix the resulting gases
+ //Remix the resulting gases
air_contents.merge(filtered_out)
- if(holding_tank)
- environment.merge(removed)
- else
- tile.assume_air(removed)
- tile.air_update_turf()
+ environment.merge(removed)
-/obj/machinery/atmospherics/portable/scrubber/return_air()
+/obj/machinery/atmospherics/portable/scrubber/return_obj_air()
RETURN_TYPE(/datum/gas_mixture)
return air_contents
diff --git a/code/modules/awaymissions/mission_code/beach.dm b/code/modules/awaymissions/mission_code/beach.dm
index 980dd94765c..150a6cd304d 100644
--- a/code/modules/awaymissions/mission_code/beach.dm
+++ b/code/modules/awaymissions/mission_code/beach.dm
@@ -32,7 +32,8 @@
icon = 'icons/misc/beach.dmi'
var/water_overlay_image = null
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- planetary_atmos = TRUE
+ atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT
+ atmos_environment = ENVIRONMENT_TEMPERATE
/turf/simulated/floor/beach/away/Initialize(mapload)
. = ..()
@@ -114,10 +115,11 @@
linkedcontroller.decalinpool += A
/turf/simulated/floor/beach/away/water/lavaland_air
- nitrogen = LAVALAND_NITROGEN
oxygen = LAVALAND_OXYGEN
+ nitrogen = LAVALAND_NITROGEN
temperature = LAVALAND_TEMPERATURE
- planetary_atmos = TRUE
+ atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT
+ atmos_environment = ENVIRONMENT_LAVALAND
/// for boundary "walls"
/turf/simulated/floor/beach/away/water/dense
diff --git a/code/modules/awaymissions/zlevel_helpers.dm b/code/modules/awaymissions/zlevel_helpers.dm
index 1795ddf77e3..d31c5b571b6 100644
--- a/code/modules/awaymissions/zlevel_helpers.dm
+++ b/code/modules/awaymissions/zlevel_helpers.dm
@@ -1,6 +1,7 @@
-// Call this before you remove the last dirt on a z level - that way, all objects
-// will have proper atmos and other important enviro things
-/proc/late_setup_level(turfs, smoothTurfs)
+/datum/milla_safe/late_setup_level
+
+// Ensures that atmos and environment are set up.
+/datum/milla_safe/late_setup_level/on_run(turfs, smoothTurfs)
var/total_timer = start_watch()
var/subtimer = start_watch()
if(!smoothTurfs)
@@ -11,7 +12,7 @@
* air subsystem will call subsequently call setup_allturfs with _every_
* turf in the world */
if(SSair && SSair.initialized)
- SSair.setup_allturfs(turfs)
+ SSair.setup_allturfs_sleepless(turfs)
log_debug("\tTook [stop_watch(subtimer)]s")
subtimer = start_watch()
diff --git a/code/modules/buildmode/submodes/atmos.dm b/code/modules/buildmode/submodes/atmos.dm
index caa833a7b35..1fa0e2836b0 100644
--- a/code/modules/buildmode/submodes/atmos.dm
+++ b/code/modules/buildmode/submodes/atmos.dm
@@ -43,30 +43,29 @@
var/left_click = pa.Find("left")
var/ctrl_click = pa.Find("ctrl")
if(left_click) //rectangular
+ var/datum/gas_mixture/air = new()
+ air.set_temperature(temperature)
+ air.set_oxygen(ppratio_to_moles(oxygen))
+ air.set_nitrogen(ppratio_to_moles(nitrogen))
+ air.set_toxins(ppratio_to_moles(plasma))
+ air.set_carbon_dioxide(ppratio_to_moles(cdiox))
+ air.set_sleeping_agent(ppratio_to_moles(nitrox))
+ air.set_agent_b(ppratio_to_moles(agentbx))
+
for(var/turf/T in block(cornerA,cornerB))
if(issimulatedturf(T))
// fill the turf with the appropriate gasses
- // this feels slightly icky
var/turf/simulated/S = T
- if(S.air)
- S.air.temperature = temperature
- S.air.oxygen = ppratio_to_moles(oxygen)
- S.air.nitrogen = ppratio_to_moles(nitrogen)
- S.air.toxins = ppratio_to_moles(plasma)
- S.air.carbon_dioxide = ppratio_to_moles(cdiox)
- S.air.sleeping_agent = ppratio_to_moles(nitrox)
- S.air.agent_b = ppratio_to_moles(agentbx)
- S.update_visuals()
- S.air_update_turf()
+ if(!S.blocks_air)
+ T.blind_set_air(air)
else if(ctrl_click) // overwrite "default" space air
T.temperature = temperature
- T.oxygen = ppratio_to_moles(oxygen)
- T.nitrogen = ppratio_to_moles(nitrogen)
- T.toxins = ppratio_to_moles(plasma)
- T.carbon_dioxide = ppratio_to_moles(cdiox)
- T.sleeping_agent = ppratio_to_moles(nitrox)
- T.agent_b = ppratio_to_moles(agentbx)
- T.air_update_turf()
+ T.oxygen = air.oxygen()
+ T.nitrogen = air.nitrogen()
+ T.toxins = air.toxins()
+ T.carbon_dioxide = air.carbon_dioxide()
+ T.sleeping_agent = air.sleeping_agent()
+ T.agent_b = air.agent_b()
// admin log
log_admin("Build Mode: [key_name(user)] changed the atmos of region [COORD(cornerA)] to [COORD(cornerB)]. T: [temperature], P: [pressure], Ox: [oxygen]%, N2: [nitrogen]%, Plsma: [plasma]%, CO2: [cdiox]%, N2O: [nitrox]%. [ctrl_click ? "Overwrote base space turf gases." : ""]")
diff --git a/code/modules/events/blob/blob_structures/strong_blob.dm b/code/modules/events/blob/blob_structures/strong_blob.dm
index 3cf59067884..86ae0a984f3 100644
--- a/code/modules/events/blob/blob_structures/strong_blob.dm
+++ b/code/modules/events/blob/blob_structures/strong_blob.dm
@@ -27,7 +27,7 @@
atmosblock = FALSE
else
atmosblock = TRUE
- air_update_turf(1)
+ recalculate_atmos_connectivity()
/obj/structure/blob/shield/update_name()
. = ..()
diff --git a/code/modules/events/blob/theblob.dm b/code/modules/events/blob/theblob.dm
index 727eb3354ca..6c3b3b8bf60 100644
--- a/code/modules/events/blob/theblob.dm
+++ b/code/modules/events/blob/theblob.dm
@@ -31,21 +31,23 @@ GLOBAL_LIST_EMPTY(blob_minions)
setDir(pick(GLOB.cardinal))
check_integrity()
if(atmosblock)
- air_update_turf(TRUE)
+ recalculate_atmos_connectivity()
ConsumeTile()
/obj/structure/blob/Destroy()
if(atmosblock)
atmosblock = FALSE
- air_update_turf(1)
+ recalculate_atmos_connectivity()
GLOB.blobs -= src
overmind = null // let us not have gc issues
if(isturf(loc)) //Necessary because Expand() is screwed up and spawns a blob and then deletes it
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
return ..()
-/obj/structure/blob/BlockSuperconductivity()
- return atmosblock
+/obj/structure/blob/get_superconductivity(direction)
+ if(atmosblock)
+ return FALSE
+ return ..()
/obj/structure/blob/CanPass(atom/movable/mover, turf/target, height=0)
if(height==0)
@@ -54,7 +56,7 @@ GLOBAL_LIST_EMPTY(blob_minions)
return 1
return 0
-/obj/structure/blob/CanAtmosPass(turf/T)
+/obj/structure/blob/CanAtmosPass(direction)
return !atmosblock
/obj/structure/blob/CanPathfindPass(obj/item/card/id/ID, dir, caller, no_id = FALSE)
diff --git a/code/modules/fish/fishtank.dm b/code/modules/fish/fishtank.dm
index a14e0205e97..b3e541e6d31 100644
--- a/code/modules/fish/fishtank.dm
+++ b/code/modules/fish/fishtank.dm
@@ -161,7 +161,7 @@
//////////////////////////////
//Stops atmos from passing wall tanks, since they are effectively full-windows.
-/obj/machinery/fishtank/wall/CanAtmosPass(turf/T)
+/obj/machinery/fishtank/wall/CanAtmosPass(direction)
return FALSE
/obj/machinery/fishtank/process()
diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
index 2b5cbddde4a..1e1cb356676 100644
--- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
@@ -374,7 +374,9 @@
..()
if(firestarter && active)
target.fire_act()
- new /obj/effect/hotspot(get_turf(target))
+ var/obj/effect/hotspot/hotspot = new /obj/effect/hotspot/fake(target)
+ hotspot.temperature = 1000
+ hotspot.recolor()
/obj/item/reagent_containers/drinks/bottle/molotov/attackby(obj/item/I, mob/user, params)
if(I.get_heat() && !active)
diff --git a/code/modules/hallucinations/effects/moderate.dm b/code/modules/hallucinations/effects/moderate.dm
index b381a82d4a4..fcbf90c0574 100644
--- a/code/modules/hallucinations/effects/moderate.dm
+++ b/code/modules/hallucinations/effects/moderate.dm
@@ -284,9 +284,9 @@
var/turf/source_turf = t
expand_queue -= source_turf
// Expand to each dir
- for(var/dir in GLOB.cardinal)
- var/turf/target_turf = get_step(source_turf, dir)
- if(processed[target_turf] || !source_turf.CanAtmosPass(target_turf))
+ for(var/direction in GLOB.cardinal)
+ var/turf/target_turf = get_step(source_turf, direction)
+ if(processed[target_turf] || !source_turf.CanAtmosPass(direction) || !target_turf.CanAtmosPass(turn(direction, 180)))
continue
create_plasma(target_turf)
expand_queue += target_turf
diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm
index 98f22590080..0a8ead91aba 100644
--- a/code/modules/hydroponics/grown/towercap.dm
+++ b/code/modules/hydroponics/grown/towercap.dm
@@ -180,9 +180,11 @@
..()
+/// Check if we're standing in an oxygenless environment
/obj/structure/bonfire/proc/CheckOxygen()
- var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
- if(G.oxygen > 13)
+ var/turf/T = get_turf(src)
+ var/datum/gas_mixture/G = T.get_readonly_air()
+ if(G.oxygen() > 13)
return 1
return 0
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index 94afc18e880..be98330ea47 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -111,11 +111,25 @@
icon_regular_floor = "podfloor_light"
floor_tile = /obj/item/stack/tile/pod/light
+/turf/simulated/floor/pod/light/lavaland_air
+ oxygen = LAVALAND_OXYGEN
+ nitrogen = LAVALAND_NITROGEN
+ temperature = LAVALAND_TEMPERATURE
+ atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT
+ atmos_environment = ENVIRONMENT_LAVALAND
+
/turf/simulated/floor/pod/dark
icon_state = "podfloor_dark"
icon_regular_floor = "podfloor_dark"
floor_tile = /obj/item/stack/tile/pod/dark
+/turf/simulated/floor/pod/dark/lavaland_air
+ oxygen = LAVALAND_OXYGEN
+ nitrogen = LAVALAND_NITROGEN
+ temperature = LAVALAND_TEMPERATURE
+ atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT
+ atmos_environment = ENVIRONMENT_LAVALAND
+
//Door
/obj/machinery/door/airlock/survival_pod
icon = 'icons/obj/doors/airlocks/survival/survival.dmi'
@@ -264,14 +278,14 @@
/obj/structure/fans/Initialize(loc)
. = ..()
- air_update_turf(1)
+ recalculate_atmos_connectivity()
/obj/structure/fans/Destroy()
arbitraryatmosblockingvar = 0
- air_update_turf(1)
+ recalculate_atmos_connectivity()
return ..()
-/obj/structure/fans/CanAtmosPass(turf/T)
+/obj/structure/fans/CanAtmosPass(direction)
return !arbitraryatmosblockingvar
/obj/structure/fans/deconstruct()
@@ -297,6 +311,10 @@
icon_state = "fan_tiny"
buildstackamount = 2
+/obj/structure/fans/tiny/get_superconductivity(direction)
+ // Mostly for stuff on Lavaland.
+ return ZERO_HEAT_TRANSFER_COEFFICIENT
+
/obj/structure/fans/tiny/invisible
name = "air flow blocker"
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
diff --git a/code/modules/mining/lavaland/loot/colossus_loot.dm b/code/modules/mining/lavaland/loot/colossus_loot.dm
index f57453a9e30..c076592a854 100644
--- a/code/modules/mining/lavaland/loot/colossus_loot.dm
+++ b/code/modules/mining/lavaland/loot/colossus_loot.dm
@@ -136,9 +136,6 @@
var/turf/T = Stuff
if((isspaceturf(T) || isfloorturf(T)) && NewTerrainFloors)
var/turf/simulated/O = T.ChangeTurf(NewTerrainFloors)
- if(O.air)
- var/datum/gas_mixture/G = O.air
- G.copy_from(O.air)
if(prob(florachance) && length(NewFlora) && !is_blocked_turf(O))
var/atom/Picked = pick(NewFlora)
new Picked(O)
diff --git a/code/modules/mob/camera/camera_mob.dm b/code/modules/mob/camera/camera_mob.dm
index f9ec7ef37d6..6a67fd1a43b 100644
--- a/code/modules/mob/camera/camera_mob.dm
+++ b/code/modules/mob/camera/camera_mob.dm
@@ -13,8 +13,8 @@
move_on_shuttle = FALSE
flags_2 = IMMUNE_TO_SHUTTLECRUSH_2
-/mob/camera/experience_pressure_difference()
- return
+/mob/camera/experience_pressure_difference(flow_x, flow_y)
+ return // Immune to gas flow.
/mob/camera/forceMove(atom/destination)
var/oldloc = loc
diff --git a/code/modules/mob/hear_say.dm b/code/modules/mob/hear_say.dm
index f3bc2e39564..e5a281851a0 100644
--- a/code/modules/mob/hear_say.dm
+++ b/code/modules/mob/hear_say.dm
@@ -68,7 +68,7 @@
//make sure the air can transmit speech - hearer's side
var/turf/T = get_turf(src)
if(T && !isobserver(src))
- var/datum/gas_mixture/environment = T.return_air()
+ var/datum/gas_mixture/environment = T.get_readonly_air()
var/pressure = environment ? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE && get_dist(speaker, src) > 1)
return FALSE
diff --git a/code/modules/mob/living/carbon/alien/alien_base.dm b/code/modules/mob/living/carbon/alien/alien_base.dm
index 8392f8a09bf..93fe906c18a 100644
--- a/code/modules/mob/living/carbon/alien/alien_base.dm
+++ b/code/modules/mob/living/carbon/alien/alien_base.dm
@@ -72,11 +72,11 @@
/mob/living/carbon/alien/check_eye_prot()
return 2
-/mob/living/carbon/alien/handle_environment(datum/gas_mixture/environment)
- if(!environment)
+/mob/living/carbon/alien/handle_environment(datum/gas_mixture/readonly_environment)
+ if(!readonly_environment)
return
- var/loc_temp = get_temperature(environment)
+ var/loc_temp = get_temperature(readonly_environment)
if(!on_fire) // If you're on fire, ignore local air temperature
if(loc_temp > bodytemperature)
diff --git a/code/modules/mob/living/carbon/alien/alien_life.dm b/code/modules/mob/living/carbon/alien/alien_life.dm
index 962971a4b21..2f4a0836f77 100644
--- a/code/modules/mob/living/carbon/alien/alien_life.dm
+++ b/code/modules/mob/living/carbon/alien/alien_life.dm
@@ -8,23 +8,23 @@
var/toxins_used = 0
var/tox_detect_threshold = 0.02
- var/breath_pressure = (breath.total_moles() * R_IDEAL_GAS_EQUATION * breath.temperature) / BREATH_VOLUME
+ var/breath_pressure = (breath.total_moles() * R_IDEAL_GAS_EQUATION * breath.temperature()) / BREATH_VOLUME
//Partial pressure of the toxins in our breath
- var/Toxins_pp = (breath.toxins / breath.total_moles()) * breath_pressure
+ var/Toxins_pp = (breath.toxins() / breath.total_moles()) * breath_pressure
if(Toxins_pp > tox_detect_threshold) // Detect toxins in air
- add_plasma(breath.toxins * 250)
+ add_plasma(breath.toxins() * 250)
throw_alert("alien_tox", /atom/movable/screen/alert/alien_tox)
- toxins_used = breath.toxins
+ toxins_used = breath.toxins()
else
clear_alert("alien_tox")
//Breathe in toxins and out oxygen
- breath.toxins -= toxins_used
- breath.oxygen += toxins_used
+ breath.set_toxins(breath.toxins() - toxins_used)
+ breath.set_oxygen(breath.oxygen() + toxins_used)
/mob/living/carbon/alien/handle_status_effects()
..()
diff --git a/code/modules/mob/living/carbon/carbon_life.dm b/code/modules/mob/living/carbon/carbon_life.dm
index bcbe2114812..ce2504424bf 100644
--- a/code/modules/mob/living/carbon/carbon_life.dm
+++ b/code/modules/mob/living/carbon/carbon_life.dm
@@ -42,21 +42,24 @@
//Start of a breath chain, calls breathe()
/mob/living/carbon/handle_breathing(times_fired)
if(times_fired % 2 == 1)
- breathe() //Breathe every other tick, unless suffocating
+ var/datum/milla_safe/carbon_breathe/milla = new()
+ milla.invoke_async(src)
else
if(isobj(loc))
var/obj/location_as_object = loc
location_as_object.handle_internal_lifeform(src, 0)
+/datum/milla_safe/carbon_breathe
+
+/datum/milla_safe/carbon_breathe/on_run(mob/living/carbon/carbon)
+ var/turf/T = get_turf(carbon)
+ carbon.breathe(get_turf_air(T))
+
//Second link in a breath chain, calls check_breath()
-/mob/living/carbon/proc/breathe()
+/mob/living/carbon/proc/breathe(datum/gas_mixture/environment)
if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell))
return
- var/datum/gas_mixture/environment
- if(loc)
- environment = loc.return_air()
-
var/datum/gas_mixture/breath
if(health <= HEALTH_THRESHOLD_CRIT && check_death_method())
@@ -77,14 +80,14 @@
if(isobj(loc)) //Breathe from loc as object
var/obj/loc_as_obj = loc
- breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME)
+ breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME, environment)
else if(isturf(loc)) //Breathe from loc as turf
var/breath_moles = 0
if(environment)
breath_moles = environment.total_moles()*BREATH_PERCENTAGE
- breath = loc.remove_air(breath_moles)
+ breath = environment.remove(breath_moles)
else //Breathe from loc as obj again
if(isobj(loc))
var/obj/loc_as_obj = loc
@@ -93,9 +96,8 @@
check_breath(breath)
if(breath)
- loc.assume_air(breath)
- air_update_turf()
- if(ishuman(src) && !internal && environment.temperature < 273 && environment.return_pressure() > 20) //foggy breath :^)
+ environment.merge(breath)
+ if(ishuman(src) && !internal && environment.temperature() < 273 && environment.return_pressure() > 20) //foggy breath :^)
new /obj/effect/frosty_breath(loc, src)
//Third and last link in a breath chain
@@ -119,12 +121,12 @@
var/SA_para_min = 1
var/SA_sleep_min = 1
var/oxygen_used = 0
- var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
+ var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature())/BREATH_VOLUME
- var/O2_partialpressure = (breath.oxygen/breath.total_moles())*breath_pressure
- var/Toxins_partialpressure = (breath.toxins/breath.total_moles())*breath_pressure
- var/CO2_partialpressure = (breath.carbon_dioxide/breath.total_moles())*breath_pressure
- var/SA_partialpressure = (breath.sleeping_agent/breath.total_moles())*breath_pressure
+ var/O2_partialpressure = (breath.oxygen() / breath.total_moles()) * breath_pressure
+ var/Toxins_partialpressure = (breath.toxins() / breath.total_moles()) * breath_pressure
+ var/CO2_partialpressure = (breath.carbon_dioxide() / breath.total_moles()) * breath_pressure
+ var/SA_partialpressure = (breath.sleeping_agent() / breath.total_moles()) * breath_pressure
//OXYGEN
if(O2_partialpressure < safe_oxy_min) //Not enough oxygen
@@ -133,18 +135,18 @@
if(O2_partialpressure > 0)
var/ratio = 1 - O2_partialpressure/safe_oxy_min
adjustOxyLoss(min(5*ratio, 3))
- oxygen_used = breath.oxygen*ratio
+ oxygen_used = breath.oxygen() * ratio
else
adjustOxyLoss(3)
throw_alert("not_enough_oxy", /atom/movable/screen/alert/not_enough_oxy)
else //Enough oxygen
adjustOxyLoss(-5)
- oxygen_used = breath.oxygen
+ oxygen_used = breath.oxygen()
clear_alert("not_enough_oxy")
- breath.oxygen -= oxygen_used
- breath.carbon_dioxide += oxygen_used
+ breath.set_oxygen(breath.oxygen() - oxygen_used)
+ breath.set_carbon_dioxide(breath.carbon_dioxide() + oxygen_used)
//CARBON DIOXIDE
if(CO2_partialpressure > safe_co2_max)
@@ -163,14 +165,14 @@
//TOXINS/PLASMA
if(Toxins_partialpressure > safe_tox_max)
- var/ratio = (breath.toxins/safe_tox_max) * 10
+ var/ratio = (breath.toxins() / safe_tox_max) * 10
adjustToxLoss(clamp(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
throw_alert("too_much_tox", /atom/movable/screen/alert/too_much_tox)
else
clear_alert("too_much_tox")
//TRACE GASES
- if(breath.sleeping_agent)
+ if(breath.sleeping_agent())
if(SA_partialpressure > SA_para_min)
Paralyse(6 SECONDS)
if(SA_partialpressure > SA_sleep_min)
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index a6725551147..b0f6e783584 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -772,10 +772,10 @@ emp_act
else
..()
-/mob/living/carbon/human/experience_pressure_difference(pressure_difference, direction)
+/mob/living/carbon/human/experience_pressure_difference(flow_x, flow_y)
playsound(src, 'sound/effects/space_wind.ogg', 50, TRUE)
if(HAS_TRAIT(src, TRAIT_NOSLIP))
- return FALSE
+ return // Immune to gas flow.
return ..()
/mob/living/carbon/human/water_act(volume, temperature, source, method = REAGENT_TOUCH)
diff --git a/code/modules/mob/living/carbon/human/human_life.dm b/code/modules/mob/living/carbon/human/human_life.dm
index 67ac118cb07..0289d9c3365 100644
--- a/code/modules/mob/living/carbon/human/human_life.dm
+++ b/code/modules/mob/living/carbon/human/human_life.dm
@@ -185,12 +185,11 @@
return null
-/mob/living/carbon/human/handle_environment(datum/gas_mixture/environment)
- if(!environment)
+/mob/living/carbon/human/handle_environment(datum/gas_mixture/readonly_environment)
+ if(!readonly_environment)
return
- var/loc_temp = get_temperature(environment)
-// to_chat(world, "Loc temp: [loc_temp] - Body temp: [bodytemperature] - Fireloss: [getFireLoss()] - Thermal protection: [get_thermal_protection()] - Fire protection: [thermal_protection + add_fire_protection(loc_temp)] - Heat capacity: [environment_heat_capacity] - Location: [loc] - src: [src]")
+ var/loc_temp = get_temperature(readonly_environment)
//Body temperature is adjusted in two steps. Firstly your body tries to stabilize itself a bit.
if(stat != DEAD)
@@ -254,7 +253,7 @@
// Account for massive pressure differences. Done by Polymorph
// Made it possible to actually have something that can protect against high pressure... Done by Errorage. Polymorph now has an axe sticking from his head for his previous hardcoded nonsense!
- var/pressure = environment.return_pressure()
+ var/pressure = readonly_environment.return_pressure()
var/adjusted_pressure = calculate_affecting_pressure(pressure) //Returns how much pressure actually affects the mob.
if(status_flags & GODMODE) return 1 //godmode
diff --git a/code/modules/mob/living/carbon/human/species/moth.dm b/code/modules/mob/living/carbon/human/species/moth.dm
index 53818ddea79..535074cbc19 100644
--- a/code/modules/mob/living/carbon/human/species/moth.dm
+++ b/code/modules/mob/living/carbon/human/species/moth.dm
@@ -117,8 +117,12 @@
return FALSE
if(H.has_status_effect(STATUS_EFFECT_BURNT_WINGS))
return FALSE
- var/datum/gas_mixture/current = A.return_air()
- if(current && (current.return_pressure() >= ONE_ATMOSPHERE*0.85)) //as long as there's reasonable pressure and no gravity, flight is possible
+ if(isobj(H.loc))
+ // Can't fly if you're in a box/mech/whatever.
+ return FALSE
+ var/turf/T = get_turf(H)
+ var/datum/gas_mixture/current = T.get_readonly_air()
+ if(current && (current.return_pressure() >= ONE_ATMOSPHERE * 0.85)) //as long as there's reasonable pressure and no gravity, flight is possible
return TRUE
/datum/species/moth/spec_thunk(mob/living/carbon/human/H)
diff --git a/code/modules/mob/living/carbon/human/species/plasmaman.dm b/code/modules/mob/living/carbon/human/species/plasmaman.dm
index b9dcaa73e10..cf0d8070028 100644
--- a/code/modules/mob/living/carbon/human/species/plasmaman.dm
+++ b/code/modules/mob/living/carbon/human/species/plasmaman.dm
@@ -153,11 +153,17 @@
/datum/species/plasmaman/handle_life(mob/living/carbon/human/H)
var/atmos_sealed = !HAS_TRAIT(H, TRAIT_NOFIRE) && (isclothing(H.wear_suit) && H.wear_suit.flags & STOPSPRESSUREDMAGE) && (isclothing(H.head) && H.head.flags & STOPSPRESSUREDMAGE)
if(!atmos_sealed && (!istype(H.w_uniform, /obj/item/clothing/under/plasmaman) || !istype(H.head, /obj/item/clothing/head/helmet/space/plasmaman) && !HAS_TRAIT(H, TRAIT_NOSELFIGNITION_HEAD_ONLY)))
- var/datum/gas_mixture/environment = H.loc.return_air()
+ var/datum/gas_mixture/environment = null
+ if(isobj(H.loc))
+ var/obj/O = H.loc
+ environment = O.return_obj_air()
+ if(isnull(environment))
+ var/turf/T = get_turf(H)
+ environment = T.get_readonly_air()
if(environment)
if(environment.total_moles())
if(!HAS_TRAIT(H, TRAIT_NOFIRE))
- if(environment.oxygen && environment.oxygen >= OXYCONCEN_PLASMEN_IGNITION) //Same threshhold that extinguishes fire
+ if(environment.oxygen() && environment.oxygen() >= OXYCONCEN_PLASMEN_IGNITION) //Same threshhold that extinguishes fire
H.adjust_fire_stacks(0.5)
if(!H.on_fire && H.fire_stacks > 0)
H.visible_message("[H]'s body reacts with the atmosphere and bursts into flames!","Your body reacts with the atmosphere and bursts into flame!")
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index de4a5cb6b9f..139a1df084a 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -671,7 +671,7 @@
else
return pick("trails_1", "trails_2")
-/mob/living/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0)
+/mob/living/experience_pressure_difference(flow_x, flow_y, pressure_resistance_prob_delta = 0)
if(buckled)
return
if(client && client.move_delay >= world.time + world.tick_lag * 2)
@@ -680,6 +680,16 @@
var/list/turfs_to_check = list()
if(has_limbs)
+ var/direction = 0
+ if(flow_x > 100)
+ direction |= EAST
+ if(flow_x < -100)
+ direction |= WEST
+ if(flow_y > 100)
+ direction |= NORTH
+ if(flow_y < -100)
+ direction |= SOUTH
+
var/turf/T = get_step(src, angle2dir(dir2angle(direction) + 90))
if(T)
turfs_to_check += T
@@ -698,7 +708,7 @@
pressure_resistance_prob_delta -= 20
break
- ..(pressure_difference, direction, pressure_resistance_prob_delta)
+ ..(flow_x, flow_y, pressure_resistance_prob_delta)
/*//////////////////////
START RESIST PROCS
@@ -885,10 +895,14 @@
var/loc_temp = T0C
if(ismecha(loc))
var/obj/mecha/M = loc
- loc_temp = M.return_temperature()
+ var/datum/gas_mixture/cabin = M.return_obj_air()
+ if(cabin)
+ loc_temp = cabin.temperature()
+ else
+ loc_temp = environment.temperature()
else if(istype(loc, /obj/structure/transit_tube_pod))
- loc_temp = environment.temperature
+ loc_temp = environment.temperature()
else if(isspaceturf(get_turf(src)))
var/turf/heat_turf = get_turf(src)
@@ -898,12 +912,12 @@
var/obj/machinery/atmospherics/unary/cryo_cell/C = loc
if(C.air_contents.total_moles() < 10)
- loc_temp = environment.temperature
+ loc_temp = environment.temperature()
else
- loc_temp = C.air_contents.temperature
+ loc_temp = C.air_contents.temperature()
else
- loc_temp = environment.temperature
+ loc_temp = environment.temperature()
return loc_temp
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index ea10e8c8488..c005bea8bea 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -223,12 +223,12 @@
else
ExtinguishMob()
return FALSE
- var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
- if(G.oxygen < 1)
+ var/turf/T = get_turf(src)
+ var/datum/gas_mixture/G = T?.get_readonly_air() // Check if we're standing in an oxygenless environment
+ if(!G || G.oxygen() < 1)
ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
return FALSE
- var/turf/location = get_turf(src)
- location.hotspot_expose(700, 50, 1)
+ T.hotspot_expose(700, 50, 1)
SEND_SIGNAL(src, COMSIG_LIVING_FIRE_TICK)
return TRUE
diff --git a/code/modules/mob/living/living_life.dm b/code/modules/mob/living/living_life.dm
index fad7b238c42..55d40f5d536 100644
--- a/code/modules/mob/living/living_life.dm
+++ b/code/modules/mob/living/living_life.dm
@@ -51,9 +51,15 @@
handle_heartattack()
//Handle temperature/pressure differences between body and environment
- var/datum/gas_mixture/environment = loc.return_air()
- if(environment)
- handle_environment(environment)
+ var/datum/gas_mixture/readonly_environment = null
+ if(isobj(loc))
+ var/obj/O = loc
+ readonly_environment = O.return_obj_air()
+ if(isnull(readonly_environment))
+ var/turf/T = get_turf(src)
+ if(!isnull(T))
+ readonly_environment = T.get_readonly_air()
+ handle_environment(readonly_environment)
handle_fire()
diff --git a/code/modules/mob/living/living_say.dm b/code/modules/mob/living/living_say.dm
index 8ea0776852e..6bb553548cc 100644
--- a/code/modules/mob/living/living_say.dm
+++ b/code/modules/mob/living/living_say.dm
@@ -239,7 +239,7 @@ GLOBAL_LIST_EMPTY(channel_to_radio_key)
if(T)
//make sure the air can transmit speech - speaker's side
- var/datum/gas_mixture/environment = T.return_air()
+ var/datum/gas_mixture/environment = T.get_readonly_air()
var/pressure = environment ? environment.return_pressure() : 0
if(!ignore_atmospherics)
if(pressure < SOUND_MINIMUM_PRESSURE)
diff --git a/code/modules/mob/living/silicon/robot/robot_movement.dm b/code/modules/mob/living/silicon/robot/robot_movement.dm
index 8f933aec0b1..2c4eccf2b78 100644
--- a/code/modules/mob/living/silicon/robot/robot_movement.dm
+++ b/code/modules/mob/living/silicon/robot/robot_movement.dm
@@ -22,6 +22,6 @@
/mob/living/silicon/robot/mob_has_gravity()
return ..() || mob_negates_gravity()
-/mob/living/silicon/robot/experience_pressure_difference(pressure_difference, direction)
+/mob/living/silicon/robot/experience_pressure_difference(flow_x, flow_y)
if(!HAS_TRAIT(src, TRAIT_MAGPULSE))
return ..()
diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm
index 2825e01df96..81b11d5c50a 100644
--- a/code/modules/mob/living/simple_animal/bot/mulebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm
@@ -864,12 +864,6 @@
new /obj/effect/decal/cleanable/blood/oil(loc)
..()
-/mob/living/simple_animal/bot/mulebot/remove_air(amount) //To prevent riders suffocating
- if(loc)
- return loc.remove_air(amount)
- else
- return null
-
/mob/living/simple_animal/bot/mulebot/run_resist()
. = ..()
if(load)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm
index 676b64b2a2d..88e1daee67c 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm
@@ -593,7 +593,9 @@ Difficulty: Hard
var/turf/C = get_turf(src)
new /obj/effect/temp_visual/lava_warning(C, enraged ? 18 SECONDS : 6 SECONDS)
for(var/turf/T in range (1,src))
- new /obj/effect/hotspot(T)
+ var/obj/effect/hotspot/hotspot = new /obj/effect/hotspot/fake(T)
+ hotspot.temperature = 1000
+ hotspot.recolor()
T.hotspot_expose(700,50,1)
if(mode == VORTEX)
var/turf/T = get_turf(src)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index ec3eeb697b6..0e711aae967 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -279,7 +279,9 @@ Difficulty: Medium
for(var/turf/T in turfs)
if(T.density)
break
- new /obj/effect/hotspot(T)
+ var/obj/effect/hotspot/hotspot = new /obj/effect/hotspot/fake(T)
+ hotspot.temperature = 1000
+ hotspot.recolor()
T.hotspot_expose(700,50,1)
for(var/mob/living/L in T.contents)
if(L in hit_list || L == source)
@@ -473,7 +475,7 @@ Difficulty: Medium
duration = 82
color = COLOR_DARK_ORANGE
-/obj/effect/temp_visual/drakewall/CanAtmosPass()
+/obj/effect/temp_visual/drakewall/CanAtmosPass(direction)
return !density
/obj/effect/temp_visual/lava_safe
@@ -567,7 +569,9 @@ Difficulty: Medium
var/turf/simulated/mineral/M = T
M.gets_drilled()
playsound(T, "explosion", 80, TRUE)
- new /obj/effect/hotspot(T)
+ var/obj/effect/hotspot/hotspot = new /obj/effect/hotspot/fake(T)
+ hotspot.temperature = 1000
+ hotspot.recolor()
T.hotspot_expose(700, 50, 1)
for(var/mob/living/L in T.contents)
if(istype(L, /mob/living/simple_animal/hostile/megafauna/dragon))
diff --git a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen_terror.dm b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen_terror.dm
index 207ccf93263..2d359f0617f 100644
--- a/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen_terror.dm
+++ b/code/modules/mob/living/simple_animal/hostile/terror_spiders/queen_terror.dm
@@ -366,12 +366,12 @@
/obj/structure/spider/terrorweb/queen/Initialize(mapload)
. = ..()
- air_update_turf(TRUE)
+ recalculate_atmos_connectivity()
-/obj/structure/spider/terrorweb/queen/CanAtmosPass(turf/T)
+/obj/structure/spider/terrorweb/queen/CanAtmosPass(direction)
return FALSE
/obj/structure/spider/terrorweb/queen/Destroy()
var/turf/T = get_turf(src)
. = ..()
- T.air_update_turf(TRUE)
+ T.recalculate_atmos_connectivity()
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index ed9505e5c13..606c185ba64 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -289,20 +289,22 @@
custom_emote(EMOTE_AUDIBLE, pick(emote_hear))
-/mob/living/simple_animal/handle_environment(datum/gas_mixture/environment)
+/mob/living/simple_animal/handle_environment(datum/gas_mixture/readonly_environment)
+ if(!readonly_environment)
+ return
var/atmos_suitable = 1
- var/areatemp = get_temperature(environment)
+ var/areatemp = get_temperature(readonly_environment)
if(abs(areatemp - bodytemperature) > 5 && !HAS_TRAIT(src, TRAIT_NOBREATH))
var/diff = areatemp - bodytemperature
diff = diff / 5
bodytemperature += diff
- var/tox = environment.toxins
- var/oxy = environment.oxygen
- var/n2 = environment.nitrogen
- var/co2 = environment.carbon_dioxide
+ var/tox = readonly_environment.toxins()
+ var/oxy = readonly_environment.oxygen()
+ var/n2 = readonly_environment.nitrogen()
+ var/co2 = readonly_environment.carbon_dioxide()
if(atmos_requirements["min_oxy"] && oxy < atmos_requirements["min_oxy"])
atmos_suitable = 0
diff --git a/code/modules/mob/living/simple_animal/slime/slime_life.dm b/code/modules/mob/living/simple_animal/slime/slime_life.dm
index 79fc701bed0..8f8bbe9adfa 100644
--- a/code/modules/mob/living/simple_animal/slime/slime_life.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime_life.dm
@@ -101,11 +101,11 @@
AIproc = FALSE
-/mob/living/simple_animal/slime/handle_environment(datum/gas_mixture/environment)
- if(!environment)
+/mob/living/simple_animal/slime/handle_environment(datum/gas_mixture/readonly_environment)
+ if(!readonly_environment)
return
- var/loc_temp = get_temperature(environment)
+ var/loc_temp = get_temperature(readonly_environment)
adjust_bodytemperature(adjust_body_temperature(bodytemperature, loc_temp, 1))
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 4edd7f84929..ea8a6f21afe 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -95,18 +95,20 @@
set category = "Admin"
set hidden = 1
- if(!loc) return 0
+ var/turf/T = get_turf(src)
+ var/datum/gas_mixture/environment = T.get_readonly_air()
- var/datum/gas_mixture/environment = loc.return_air()
+ if(!environment)
+ return
var/t = "Coordinates: [x],[y] \n"
- t+= "Temperature: [environment.temperature] \n"
- t+= "Nitrogen: [environment.nitrogen] \n"
- t+= "Oxygen: [environment.oxygen] \n"
- t+= "Plasma : [environment.toxins] \n"
- t+= "Carbon Dioxide: [environment.carbon_dioxide] \n"
- t+= "N2O: [environment.sleeping_agent] \n"
- t+= "Agent B: [environment.agent_b] \n"
+ t+= "Temperature: [environment.temperature()] \n"
+ t+= "Nitrogen: [environment.nitrogen()] \n"
+ t+= "Oxygen: [environment.oxygen()] \n"
+ t+= "Plasma : [environment.toxins()] \n"
+ t+= "Carbon Dioxide: [environment.carbon_dioxide()] \n"
+ t+= "N2O: [environment.sleeping_agent()] \n"
+ t+= "Agent B: [environment.agent_b()] \n"
usr.show_message(t, EMOTE_VISIBLE)
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index f4a3f71687e..16dc1f526b5 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -832,7 +832,9 @@
else if(myeffect == "Death By Fire")
to_chat(target,"You feel hotter than usual. Maybe you should lowe-wait, is that your hand melting?")
var/turf/simulated/T = get_turf(target)
- new /obj/effect/hotspot(T)
+ var/obj/effect/hotspot/hotspot = new /obj/effect/hotspot/fake(T)
+ hotspot.temperature = 1000
+ hotspot.recolor()
target.adjustFireLoss(150) // hard crit, the burning takes care of the rest.
else if(myeffect == "Total Brain Death")
to_chat(target,"You see a message appear in front of you in bright red letters: YHWH-3 ACTIVATED. TERMINATION IN 3 SECONDS")
diff --git a/code/modules/pda/core_apps.dm b/code/modules/pda/core_apps.dm
index df18daf2fc7..a45c9653c45 100644
--- a/code/modules/pda/core_apps.dm
+++ b/code/modules/pda/core_apps.dm
@@ -103,21 +103,21 @@
var/list/results = list()
var/turf/T = get_turf(user.loc)
if(!isnull(T))
- var/datum/gas_mixture/environment = T.return_air()
+ var/datum/gas_mixture/environment = T.get_readonly_air()
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
if(total_moles)
- var/o2_level = environment.oxygen/total_moles
- var/n2_level = environment.nitrogen/total_moles
- var/co2_level = environment.carbon_dioxide/total_moles
- var/plasma_level = environment.toxins/total_moles
- var/n2o_level = environment.sleeping_agent/total_moles
- var/unknown_level = 1-(o2_level+n2_level+co2_level+plasma_level+n2o_level)
+ var/o2_level = environment.oxygen()/total_moles
+ var/n2_level = environment.nitrogen() / total_moles
+ var/co2_level = environment.carbon_dioxide() / total_moles
+ var/plasma_level = environment.toxins() / total_moles
+ var/n2o_level = environment.sleeping_agent() / total_moles
+ var/unknown_level = 1 - (o2_level + n2_level + co2_level + plasma_level + n2o_level)
results = list(
list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80),
- list("entry" = "Temperature", "units" = "C", "val" = "[round(environment.temperature-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
+ list("entry" = "Temperature", "units" = "C", "val" = "[round(environment.temperature()-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5),
list("entry" = "Oxygen", "units" = "%", "val" = "[round(o2_level*100,0.1)]", "bad_high" = 140, "poor_high" = 135, "poor_low" = 19, "bad_low" = 17),
list("entry" = "Nitrogen", "units" = "%", "val" = "[round(n2_level*100,0.1)]", "bad_high" = 105, "poor_high" = 85, "poor_low" = 50, "bad_low" = 40),
list("entry" = "Carbon Dioxide", "units" = "%", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0),
diff --git a/code/modules/power/engines/singularity/collector.dm b/code/modules/power/engines/singularity/collector.dm
index 9f6d13842cf..15561f2e4de 100644
--- a/code/modules/power/engines/singularity/collector.dm
+++ b/code/modules/power/engines/singularity/collector.dm
@@ -25,13 +25,13 @@
/obj/machinery/power/rad_collector/process()
if(!loaded_tank)
return
- if(!loaded_tank.air_contents.toxins)
+ if(!loaded_tank.air_contents.toxins())
investigate_log("out of fuel.", "singulo")
playsound(src, 'sound/machines/ding.ogg', 50, TRUE)
eject()
else
- var/gasdrained = min(powerproduction_drain * drainratio, loaded_tank.air_contents.toxins)
- loaded_tank.air_contents.toxins -= gasdrained
+ var/gasdrained = min(powerproduction_drain * drainratio, loaded_tank.air_contents.toxins())
+ loaded_tank.air_contents.set_toxins(loaded_tank.air_contents.toxins() - gasdrained)
var/power_produced = RAD_COLLECTOR_OUTPUT
produce_direct_power(power_produced)
@@ -43,7 +43,7 @@
if(!locked)
toggle_power()
user.visible_message("[user.name] turns the [name] [active ? "on" : "off"].", "You turn the [name] [active ? "on" : "off"].")
- investigate_log("turned [active ? "on" : "off"] by [user.key]. [loaded_tank ? "Fuel: [round(loaded_tank.air_contents.toxins / 0.29)]%" : "It is empty"].", "singulo")
+ investigate_log("turned [active ? "on" : "off"] by [user.key]. [loaded_tank ? "Fuel: [round(loaded_tank.air_contents.toxins() / 0.29)]%" : "It is empty"].", "singulo")
else
to_chat(user, "The controls are locked!")
diff --git a/code/modules/power/engines/supermatter/supermatter.dm b/code/modules/power/engines/supermatter/supermatter.dm
index bac8aceb3b2..036b39e1a2c 100644
--- a/code/modules/power/engines/supermatter/supermatter.dm
+++ b/code/modules/power/engines/supermatter/supermatter.dm
@@ -272,7 +272,7 @@
var/turf/T = get_turf(src)
if(!T)
return SUPERMATTER_ERROR
- var/datum/gas_mixture/air = T.return_air()
+ var/datum/gas_mixture/air = T.get_readonly_air()
if(!air)
return SUPERMATTER_ERROR
@@ -286,10 +286,10 @@
if(integrity < SUPERMATTER_DANGER_PERCENT)
return SUPERMATTER_DANGER
- if((integrity < SUPERMATTER_WARNING_PERCENT) || (air.temperature > CRITICAL_TEMPERATURE))
+ if((integrity < SUPERMATTER_WARNING_PERCENT) || (air.temperature() > CRITICAL_TEMPERATURE))
return SUPERMATTER_WARNING
- if(air.temperature > (CRITICAL_TEMPERATURE * 0.8))
+ if(air.temperature() > (CRITICAL_TEMPERATURE * 0.8))
return SUPERMATTER_NOTIFY
if(power > 5)
@@ -402,9 +402,19 @@
qdel(src)
/obj/machinery/atmospherics/supermatter_crystal/process_atmos()
+ var/datum/milla_safe/supermatter_process/milla = new()
+ milla.invoke_async(src)
+
+/datum/milla_safe/supermatter_process
+
+/datum/milla_safe/supermatter_process/on_run(obj/machinery/atmospherics/supermatter_crystal/supermatter)
+ var/turf/T = get_turf(supermatter)
+ var/datum/gas_mixture/env = get_turf_air(T)
+ supermatter.process_atmos_safely(T, env)
+
+/obj/machinery/atmospherics/supermatter_crystal/proc/process_atmos_safely(turf/T, datum/gas_mixture/env)
if(!processes) //Just fuck me up bro
return
- var/turf/T = loc
if(isnull(T)) // We have a null turf...something is wrong, stop processing this entity.
return PROCESS_KILL
@@ -440,9 +450,6 @@
var/next_sound = round((100 - aggression) * 5)
last_accent_sound = world.time + max(SUPERMATTER_ACCENT_SOUND_MIN_COOLDOWN, next_sound)
- //Ok, get the air from the turf
- var/datum/gas_mixture/env = T.return_air()
-
var/datum/gas_mixture/removed
if(produces_gas)
//Remove gas from surrounding area
@@ -462,7 +469,7 @@
//((((some value between 0.5 and 1 * temp - ((273.15 + 40) * some values between 1 and 10)) * some number between 0.25 and knock your socks off / 150) * 0.25
//Heat and mols account for each other, a lot of hot mols are more damaging then a few
//Mols start to have a positive effect on damage after 350
- damage = max(damage + (max(clamp(removed.total_moles() / 200, 0.5, 1) * removed.temperature - ((T0C + heat_penalty_threshold)*dynamic_heat_resistance), 0) * mole_heat_penalty / 150 ) * DAMAGE_INCREASE_MULTIPLIER, 0)
+ damage = max(damage + (max(clamp(removed.total_moles() / 200, 0.5, 1) * removed.temperature() - ((T0C + heat_penalty_threshold)*dynamic_heat_resistance), 0) * mole_heat_penalty / 150 ) * DAMAGE_INCREASE_MULTIPLIER, 0)
//Power only starts affecting damage when it is above 5000
damage = max(damage + (max(power - POWER_PENALTY_THRESHOLD, 0)/500) * DAMAGE_INCREASE_MULTIPLIER, 0)
//Molar count only starts affecting damage when it is above 1800
@@ -472,24 +479,23 @@
//healing damage
if(combined_gas < MOLE_PENALTY_THRESHOLD)
//Only has a net positive effect when the temp is below 313.15, heals up to 2 damage. Psycologists increase this temp min by up to 45
- damage = max(damage + (min(removed.temperature - (T0C + heat_penalty_threshold), 0) / 150 ), 0)
+ damage = max(damage + (min(removed.temperature() - (T0C + heat_penalty_threshold), 0) / 150 ), 0)
//Check for holes in the SM inner chamber
- for(var/t in RANGE_TURFS(1, loc))
- if(!isspaceturf(t))
+ var/turf/here = get_turf(src)
+ for(var/turf/neighbor in here.GetAtmosAdjacentTurfs(alldir = TRUE))
+ if(!isspaceturf(neighbor))
continue
- var/turf/turf_to_check = t
- if(length(turf_to_check.atmos_adjacent_turfs))
- var/integrity = get_integrity()
- if(integrity < 10)
- damage += clamp((power * 0.0005) * DAMAGE_INCREASE_MULTIPLIER, 0, MAX_SPACE_EXPOSURE_DAMAGE)
- else if(integrity < 25)
- damage += clamp((power * 0.0009) * DAMAGE_INCREASE_MULTIPLIER, 0, MAX_SPACE_EXPOSURE_DAMAGE)
- else if(integrity < 45)
- damage += clamp((power * 0.005) * DAMAGE_INCREASE_MULTIPLIER, 0, MAX_SPACE_EXPOSURE_DAMAGE)
- else if(integrity < 75)
- damage += clamp((power * 0.002) * DAMAGE_INCREASE_MULTIPLIER, 0, MAX_SPACE_EXPOSURE_DAMAGE)
- break
+ var/integrity = get_integrity()
+ if(integrity < 10)
+ damage += clamp((power * 0.0005) * DAMAGE_INCREASE_MULTIPLIER, 0, MAX_SPACE_EXPOSURE_DAMAGE)
+ else if(integrity < 25)
+ damage += clamp((power * 0.0009) * DAMAGE_INCREASE_MULTIPLIER, 0, MAX_SPACE_EXPOSURE_DAMAGE)
+ else if(integrity < 45)
+ damage += clamp((power * 0.005) * DAMAGE_INCREASE_MULTIPLIER, 0, MAX_SPACE_EXPOSURE_DAMAGE)
+ else if(integrity < 75)
+ damage += clamp((power * 0.002) * DAMAGE_INCREASE_MULTIPLIER, 0, MAX_SPACE_EXPOSURE_DAMAGE)
+ break
//caps damage rate
//Takes the lower number between archived damage + (1.8) and damage
@@ -499,11 +505,11 @@
//calculating gas related values
combined_gas = max(removed.total_moles(), 0)
- plasmacomp = max(removed.toxins / combined_gas, 0)
- o2comp = max(removed.oxygen / combined_gas, 0)
- co2comp = max(removed.carbon_dioxide / combined_gas, 0)
- n2ocomp = max(removed.sleeping_agent / combined_gas, 0)
- n2comp = max(removed.nitrogen / combined_gas, 0)
+ plasmacomp = max(removed.toxins() / combined_gas, 0)
+ o2comp = max(removed.oxygen() / combined_gas, 0)
+ co2comp = max(removed.carbon_dioxide() / combined_gas, 0)
+ n2ocomp = max(removed.sleeping_agent() / combined_gas, 0)
+ n2comp = max(removed.nitrogen() / combined_gas, 0)
gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp - n2comp, 0), 1)
@@ -544,7 +550,7 @@
if(power_changes)
- power = max((removed.temperature * temp_factor / T0C) * gasmix_power_ratio + power, 0)
+ power = max((removed.temperature() * temp_factor / T0C) * gasmix_power_ratio + power, 0)
if(prob(50))
var/mole_crunch_bonus = 0
@@ -563,19 +569,18 @@
//Also keep in mind we are only adding this temperature to (efficiency)% of the one tile the rock
//is on. An increase of 4*C @ 25% efficiency here results in an increase of 1*C / (#tilesincore) overall.
//Power * 0.55 * (some value between 1.5 and 23) / 5
- removed.temperature += (((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER) * heat_multiplier)
+ removed.set_temperature(removed.temperature() + (((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER) * heat_multiplier))
//We can only emit so much heat, that being 57500
- removed.temperature = max(0, min(removed.temperature, 2500 * dynamic_heat_modifier))
+ removed.set_temperature(max(0, min(removed.temperature(), 2500 * dynamic_heat_modifier)))
//Calculate how much gas to release
//Varies based on power and gas content
- removed.toxins += max(((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER) * gas_multiplier, 0)
+ removed.set_toxins(removed.toxins() + max(((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER) * gas_multiplier, 0))
//Varies based on power, gas content, and heat
- removed.oxygen += max((((device_energy + removed.temperature * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER) * gas_multiplier, 0)
+ removed.set_oxygen(removed.oxygen() + max((((device_energy + removed.temperature() * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER) * gas_multiplier, 0))
if(produces_gas)
env.merge(removed)
- air_update_turf()
//Makes em go mad and accumulate rads.
for(var/mob/living/carbon/human/l in view(src, HALLUCINATION_RANGE(power))) // If they can see it without mesons on. Bad on them.
@@ -597,9 +602,9 @@
if(power > POWER_PENALTY_THRESHOLD || damage > damage_penalty_point) //If the power is above 5000 or if the damage is above 550
var/range = 4
zap_cutoff = 1500
- if(removed && removed.return_pressure() > 0 && removed.return_temperature() > 0)
+ if(removed && removed.return_pressure() > 0 && removed.temperature() > 0)
//You may be able to freeze the zapstate of the engine with good planning, we'll see
- zap_cutoff = clamp(3000 - (power * (removed.total_moles()) / 10) / removed.return_temperature(), 350, 3000)//If the core is cold, it's easier to jump, ditto if there are a lot of mols
+ zap_cutoff = clamp(3000 - (power * (removed.total_moles()) / 10) / removed.temperature(), 350, 3000)//If the core is cold, it's easier to jump, ditto if there are a lot of mols
//We should always be able to zap our way out of the default enclosure
//See supermatter_zap() for more details
range = clamp(power / removed.return_pressure() * 10, 2, 7)
@@ -1182,8 +1187,8 @@
//This gotdamn variable is a boomer and keeps giving me problems
var/turf/T = get_turf(target)
var/pressure = 1
- if(T?.return_air())
- var/datum/gas_mixture/G = T.return_air()
+ var/datum/gas_mixture/G = T?.get_readonly_air()
+ if(G)
pressure = max(1, G.return_pressure())
//We get our range with the strength of the zap and the pressure, the higher the former and the lower the latter the better
var/new_range = clamp(zap_str / pressure * 10, 2, 7)
diff --git a/code/modules/power/engines/supermatter/supermatter_event.dm b/code/modules/power/engines/supermatter/supermatter_event.dm
index 1d7bae80edc..44befc60573 100644
--- a/code/modules/power/engines/supermatter/supermatter_event.dm
+++ b/code/modules/power/engines/supermatter/supermatter_event.dm
@@ -1,22 +1,21 @@
/datum/supermatter_event
var/name = "Unknown X-K (Report this to coders)"
var/obj/machinery/atmospherics/supermatter_crystal/supermatter
- var/datum/gas_mixture/environment
/// Probability of the event not running, higher tiers being rarer
var/threat_level
var/duration
+ var/turf/supermatter_turf
/datum/supermatter_event/New(obj/machinery/atmospherics/supermatter_crystal/_supermatter)
. = ..()
supermatter = _supermatter
+ supermatter_turf = get_turf(supermatter)
if(!supermatter)
stack_trace("a /datum/supermatter_event was called without an involved supermatter.")
return
if(!istype(supermatter))
stack_trace("a /datum/supermatter_event was called with (name: [supermatter], type: [supermatter.type]) instead of a supermatter!")
return
- var/turf/T = get_turf(supermatter)
- environment = T.return_air()
/datum/supermatter_event/proc/start_event()
supermatter.event_active = src
@@ -66,21 +65,27 @@
name = "D-1"
/datum/supermatter_event/delta_tier/sleeping_gas/on_start()
- environment.sleeping_agent += 200
+ var/datum/gas_mixture/air = new()
+ air.set_sleeping_agent(200)
+ supermatter_turf.blind_release_air(air)
// nitrogen
/datum/supermatter_event/delta_tier/nitrogen
name = "D-2"
/datum/supermatter_event/delta_tier/nitrogen/on_start()
- environment.nitrogen += 200
+ var/datum/gas_mixture/air = new()
+ air.set_nitrogen(200)
+ supermatter_turf.blind_release_air(air)
// carbon dioxide
/datum/supermatter_event/delta_tier/carbon_dioxide
name = "D-3"
/datum/supermatter_event/delta_tier/carbon_dioxide/on_start()
- environment.carbon_dioxide += 250
+ var/datum/gas_mixture/air = new()
+ air.set_carbon_dioxide(250)
+ supermatter_turf.blind_release_air(air)
// C class events
@@ -97,14 +102,18 @@
name = "C-1"
/datum/supermatter_event/charlie_tier/oxygen/on_start()
- environment.oxygen += 250
+ var/datum/gas_mixture/air = new()
+ air.set_oxygen(250)
+ supermatter_turf.blind_release_air(air)
// plasma
/datum/supermatter_event/charlie_tier/plasma
name = "C-2"
/datum/supermatter_event/charlie_tier/plasma/on_start()
- environment.toxins += 200
+ var/datum/gas_mixture/air = new()
+ air.set_toxins(200)
+ supermatter_turf.blind_release_air(air)
// lowers the temp required for the SM to take damage.
/datum/supermatter_event/charlie_tier/heat_penalty_threshold
diff --git a/code/modules/power/generators/portable generators/pacman.dm b/code/modules/power/generators/portable generators/pacman.dm
index 3fa64a39583..5e7b7102964 100644
--- a/code/modules/power/generators/portable generators/pacman.dm
+++ b/code/modules/power/generators/portable generators/pacman.dm
@@ -125,10 +125,11 @@
Gives traitors more opportunities to sabotage the generator or allows enterprising engineers to build additional
cooling in order to get more power out.
*/
- var/datum/gas_mixture/environment = loc.return_air()
+ var/turf/T = get_turf(src)
+ var/datum/gas_mixture/environment = T.get_readonly_air()
if(environment)
var/ratio = min(environment.return_pressure() / ONE_ATMOSPHERE, 1)
- var/ambient = environment.temperature - T20C
+ var/ambient = environment.temperature() - T20C
lower_limit += ambient * ratio
upper_limit += ambient * ratio
@@ -154,10 +155,11 @@
/obj/machinery/power/port_gen/pacman/handle_inactive()
var/cooling_temperature = 20
- var/datum/gas_mixture/environment = loc.return_air()
+ var/turf/T = get_turf(src)
+ var/datum/gas_mixture/environment = T.get_readonly_air()
if(environment)
var/ratio = min(environment.return_pressure()/ONE_ATMOSPHERE, 1)
- var/ambient = environment.temperature - T20C
+ var/ambient = environment.temperature() - T20C
cooling_temperature += ambient*ratio
if(temperature > cooling_temperature)
diff --git a/code/modules/power/generators/thermo_electric_generator.dm b/code/modules/power/generators/thermo_electric_generator.dm
index 7c4217a2dd2..222ea5d94c3 100644
--- a/code/modules/power/generators/thermo_electric_generator.dm
+++ b/code/modules/power/generators/thermo_electric_generator.dm
@@ -110,13 +110,13 @@
if(cold_air && hot_air)
- //log_debug("hot_air = [hot_air] temperature = [hot_air.temperature]; cold_air = [cold_air] temperature = [hot_air.temperature];")
+ //log_debug("hot_air = [hot_air] temperature = [hot_air.temperature()]; cold_air = [cold_air] temperature = [hot_air.temperature()];")
//log_debug("coldair and hotair pass")
var/cold_air_heat_capacity = cold_air.heat_capacity()
var/hot_air_heat_capacity = hot_air.heat_capacity()
- var/delta_temperature = hot_air.temperature - cold_air.temperature
+ var/delta_temperature = hot_air.temperature() - cold_air.temperature()
//log_debug("delta_temperature = [delta_temperature]; cold_air_heat_capacity = [cold_air_heat_capacity]; hot_air_heat_capacity = [hot_air_heat_capacity]")
@@ -130,8 +130,8 @@
//log_debug("lastgen = [lastgen]; heat = [heat]; delta_temperature = [delta_temperature]; hot_air_heat_capacity = [hot_air_heat_capacity]; cold_air_heat_capacity = [cold_air_heat_capacity];")
- hot_air.temperature = hot_air.temperature - energy_transfer / hot_air_heat_capacity
- cold_air.temperature = cold_air.temperature + heat / cold_air_heat_capacity
+ hot_air.set_temperature(hot_air.temperature() - energy_transfer / hot_air_heat_capacity)
+ cold_air.set_temperature(cold_air.temperature() + heat / cold_air_heat_capacity)
//log_debug("POWER: [lastgen] W generated at [efficiency * 100]% efficiency and sinks sizes [cold_air_heat_capacity], [hot_air_heat_capacity]")
@@ -221,10 +221,10 @@
data["hot_dir"] = dir2text(hot_dir)
data["output_power"] = round(lastgen)
// Temps are K, pressures are kPa, power is W
- data["cold_inlet_temp"] = round(cold_circ_air2.temperature, 0.1)
- data["hot_inlet_temp"] = round(hot_circ_air2.temperature, 0.1)
- data["cold_outlet_temp"] = round(cold_circ_air1.temperature, 0.1)
- data["hot_outlet_temp"] = round(hot_circ_air1.temperature, 0.1)
+ data["cold_inlet_temp"] = round(cold_circ_air2.temperature(), 0.1)
+ data["hot_inlet_temp"] = round(hot_circ_air2.temperature(), 0.1)
+ data["cold_outlet_temp"] = round(cold_circ_air1.temperature(), 0.1)
+ data["hot_outlet_temp"] = round(hot_circ_air1.temperature(), 0.1)
data["cold_delta_temp"] = data["cold_outlet_temp"] - data["cold_inlet_temp"]
data["cold_inlet_pressure"] = round(cold_circ_air2.return_pressure(), 0.1)
data["hot_inlet_pressure"] = round(hot_circ_air2.return_pressure(), 0.1)
diff --git a/code/modules/power/generators/turbine.dm b/code/modules/power/generators/turbine.dm
index e81f4337882..591cd54a04b 100644
--- a/code/modules/power/generators/turbine.dm
+++ b/code/modules/power/generators/turbine.dm
@@ -167,7 +167,7 @@
M.set_multitool_buffer(user, src)
-/obj/machinery/power/compressor/CanAtmosPass(turf/T)
+/obj/machinery/power/compressor/CanAtmosPass(direction)
return !density
/obj/machinery/power/compressor/proc/trigger_overheat()
@@ -181,46 +181,46 @@
return max(last_overheat + OVERHEAT_TIME - world.time, 0)
/obj/machinery/power/compressor/process()
- if(!turbine)
- stat = BROKEN
- if(stat & BROKEN || panel_open)
+ var/datum/milla_safe/compressor_process/milla = new()
+ milla.invoke_async(src)
+
+/datum/milla_safe/compressor_process
+
+/datum/milla_safe/compressor_process/on_run(obj/machinery/power/compressor/compressor)
+ if(!compressor.turbine)
+ compressor.stat = BROKEN
+ if(compressor.stat & BROKEN || compressor.panel_open)
return
- if(!starter)
+ if(!compressor.starter)
return
- if(rpm_threshold == OVERDRIVE)
- //UI update here
- overheat += 2
- if(overheat >= OVERHEAT_THRESHOLD)
- trigger_overheat()
- else if(overheat > 0)
- overheat -= 2
- rpm = 0.9* rpm + 0.1 * rpmtarget
- var/datum/gas_mixture/environment = inturf.return_air()
-
- // It's a simplified version taking only 1/10 of the moles from the turf nearby. It should be later changed into a better version
- //2023 note: It works, im not touc
+ if(compressor.rpm_threshold == OVERDRIVE)
+ compressor.overheat += 2
+ if(compressor.overheat >= OVERHEAT_THRESHOLD)
+ compressor.trigger_overheat()
+ else if(compressor.overheat > 0)
+ compressor.overheat -= 2
+ compressor.rpm = 0.9 * compressor.rpm + 0.1 * compressor.rpmtarget
+ var/datum/gas_mixture/environment = get_turf_air(compressor.inturf)
var/transfer_moles = environment.total_moles()/10
- //var/transfer_moles = rpm/10000*capacity
- var/datum/gas_mixture/removed = inturf.remove_air(transfer_moles)
- gas_contained.merge(removed)
+ var/datum/gas_mixture/removed = environment.remove(transfer_moles)
+ compressor.gas_contained.merge(removed)
// RPM function to include compression friction - be advised that too low/high of a compfriction value can make things screwy
-
- rpm = max(0, rpm - (rpm*rpm)/(COMPFRICTION*efficiency))
+ compressor.rpm = max(0, compressor.rpm - (compressor.rpm*compressor.rpm)/(COMPFRICTION*compressor.efficiency))
- if(starter && !(stat & NOPOWER))
- use_power(2800)
- if(rpm<1000)
- rpmtarget = 1000
+ if(!(compressor.stat & NOPOWER))
+ compressor.use_power(2800)
+ if(compressor.rpm < 1000)
+ compressor.rpmtarget = 1000
else
- if(rpm<1000)
- rpmtarget = 0
+ if(compressor.rpm < 1000)
+ compressor.rpmtarget = 0
var/new_rpm_threshold
- switch(rpm)
+ switch(compressor.rpm)
if(50001 to INFINITY)
new_rpm_threshold = OVERDRIVE
if(10001 to 50000)
@@ -232,9 +232,9 @@
else
new_rpm_threshold = NONE
- if(rpm_threshold != new_rpm_threshold)
- rpm_threshold = new_rpm_threshold
- update_icon(UPDATE_OVERLAYS)
+ if(compressor.rpm_threshold != new_rpm_threshold)
+ compressor.rpm_threshold = new_rpm_threshold
+ compressor.update_icon(UPDATE_OVERLAYS)
/obj/machinery/power/compressor/update_overlays()
. = ..()
@@ -286,44 +286,49 @@
return !density
/obj/machinery/power/turbine/process()
+ var/datum/milla_safe/turbine_process/milla = new()
+ milla.invoke_async(src)
- if(!compressor)
- stat = BROKEN
+/datum/milla_safe/turbine_process
- if((stat & BROKEN) || panel_open)
+/datum/milla_safe/turbine_process/on_run(obj/machinery/power/turbine/turbine)
+ if(!turbine.compressor)
+ turbine.stat = BROKEN
+
+ if((turbine.stat & BROKEN) || turbine.panel_open)
return
- if(!compressor.starter)
+ if(!turbine.compressor.starter)
return
// This is the power generation function. If anything is needed it's good to plot it in EXCEL before modifying
// the TURBPOWER and TURBCURVESHAPE values
- if(compressor.gas_contained.temperature < 500)
- lastgen = 0
+ if(turbine.compressor.gas_contained.temperature() < 500)
+ turbine.lastgen = 0
else
- lastgen = ((compressor.rpm / TURBPOWER) ** TURBCURVESHAPE) * TURBPOWER * productivity * POWER_CURVE_MOD
+ turbine.lastgen = ((turbine.compressor.rpm / TURBPOWER) ** TURBCURVESHAPE) * TURBPOWER * turbine.productivity * POWER_CURVE_MOD
- produce_direct_power(lastgen)
+ turbine.produce_direct_power(turbine.lastgen)
// Weird function but it works. Should be something else...
- var/newrpm = ((compressor.gas_contained.temperature) * compressor.gas_contained.total_moles())/4
+ var/newrpm = ((turbine.compressor.gas_contained.temperature()) * turbine.compressor.gas_contained.total_moles()) / 4
newrpm = max(0, newrpm)
- if(!compressor.starter || newrpm > 1000)
- compressor.rpmtarget = newrpm
+ if(!turbine.compressor.starter || newrpm > 1000)
+ turbine.compressor.rpmtarget = newrpm
- if(compressor.gas_contained.total_moles()>0)
- var/oamount = min(compressor.gas_contained.total_moles(), (compressor.rpm+100)/35000*compressor.capacity)
- var/datum/gas_mixture/removed = compressor.gas_contained.remove(oamount)
- outturf.assume_air(removed)
+ if(turbine.compressor.gas_contained.total_moles()>0)
+ var/oamount = min(turbine.compressor.gas_contained.total_moles(), (turbine.compressor.rpm + 100) / 35000 * turbine.compressor.capacity)
+ var/datum/gas_mixture/removed = turbine.compressor.gas_contained.remove(oamount)
+ turbine.outturf.blind_release_air(removed)
- if((lastgen > 100) != generator_threshold)
- generator_threshold = !generator_threshold
- update_icon(UPDATE_OVERLAYS)
+ if((turbine.lastgen > 100) != turbine.generator_threshold)
+ turbine.generator_threshold = !turbine.generator_threshold
+ turbine.update_icon(UPDATE_OVERLAYS)
- updateDialog()
+ turbine.updateDialog()
/obj/machinery/power/turbine/update_overlays()
. = ..()
@@ -378,7 +383,7 @@
data["online"] = compressor.starter
data["power"] = compressor.turbine.lastgen
data["rpm"] = compressor.rpm
- data["temperature"] = compressor.gas_contained.return_temperature()
+ data["temperature"] = compressor.gas_contained.temperature()
return data
/obj/machinery/power/turbine/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
@@ -446,7 +451,7 @@
data["online"] = compressor.starter
data["power"] = compressor.turbine.lastgen
data["rpm"] = compressor.rpm
- data["temperature"] = compressor.gas_contained.return_temperature()
+ data["temperature"] = compressor.gas_contained.temperature()
data["bearing_heat"] = clamp((compressor.overheat / OVERHEAT_THRESHOLD) * 100, 0, 100)
return data
diff --git a/code/modules/procedural_mapping/mapGeneratorModules/mapgen_helpers.dm b/code/modules/procedural_mapping/mapGeneratorModules/mapgen_helpers.dm
index bbf752fd6a1..1ca4fd14c0b 100644
--- a/code/modules/procedural_mapping/mapGeneratorModules/mapgen_helpers.dm
+++ b/code/modules/procedural_mapping/mapGeneratorModules/mapgen_helpers.dm
@@ -11,17 +11,15 @@
return
var/list/map = mother.map
for(var/turf/simulated/T in map)
- SSair.remove_from_active(T)
- for(var/turf/simulated/T in map)
- if(T.air)
- T.air.oxygen = T.oxygen
- T.air.nitrogen = T.nitrogen
- T.air.carbon_dioxide = T.carbon_dioxide
- T.air.toxins = T.toxins
- T.air.sleeping_agent = T.sleeping_agent
- T.air.agent_b = T.agent_b
- T.air.temperature = T.temperature
- SSair.add_to_active(T)
+ var/datum/gas_mixture/air = new()
+ air.set_oxygen(T.oxygen)
+ air.set_nitrogen(T.nitrogen)
+ air.set_carbon_dioxide(T.carbon_dioxide)
+ air.set_toxins(T.toxins)
+ air.set_sleeping_agent(T.sleeping_agent)
+ air.set_agent_b(T.agent_b)
+ air.set_temperature(T.temperature)
+ T.blind_set_air(air)
//Only places atoms/turfs on area borders
/datum/mapGeneratorModule/border
diff --git a/code/modules/projectiles/guns/energy/special_eguns.dm b/code/modules/projectiles/guns/energy/special_eguns.dm
index fcd8c34a368..6b204a39320 100644
--- a/code/modules/projectiles/guns/energy/special_eguns.dm
+++ b/code/modules/projectiles/guns/energy/special_eguns.dm
@@ -588,7 +588,11 @@
visible_message("[src] vents heated plasma!")
var/turf/simulated/T = get_turf(src)
if(istype(T))
- T.atmos_spawn_air(LINDA_SPAWN_HEAT | LINDA_SPAWN_TOXINS|LINDA_SPAWN_20C, 20)
+ var/datum/gas_mixture/air = new()
+ air.set_temperature(1000)
+ air.set_toxins(20)
+ air.set_oxygen(20)
+ T.blind_release_air(air)
#undef PLASMA_CHARGE_USE_PER_SECOND
#undef PLASMA_DISCHARGE_LIMIT
diff --git a/code/modules/projectiles/guns/projectile/saw.dm b/code/modules/projectiles/guns/projectile/saw.dm
index 91a9eb677bd..4c113421fde 100644
--- a/code/modules/projectiles/guns/projectile/saw.dm
+++ b/code/modules/projectiles/guns/projectile/saw.dm
@@ -98,7 +98,9 @@
..()
var/turf/location = get_turf(src)
if(location)
- new /obj/effect/hotspot(location)
+ var/obj/effect/hotspot/hotspot = new /obj/effect/hotspot/fake(location)
+ hotspot.temperature = 1000
+ hotspot.recolor()
location.hotspot_expose(700, 50, 1)
//magazines//
diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm
index 7fc85667347..d509a37b8f9 100644
--- a/code/modules/projectiles/projectile/bullets.dm
+++ b/code/modules/projectiles/projectile/bullets.dm
@@ -164,7 +164,9 @@
..()
var/turf/location = get_turf(src)
if(location)
- new /obj/effect/hotspot(location)
+ var/obj/effect/hotspot/hotspot = new /obj/effect/hotspot/fake(location)
+ hotspot.temperature = 1000
+ hotspot.recolor()
location.hotspot_expose(700, 50, 1)
/obj/item/projectile/bullet/incendiary/shell/dragonsbreath
diff --git a/code/modules/projectiles/projectile_base.dm b/code/modules/projectiles/projectile_base.dm
index 279516a9600..805f1aa785f 100644
--- a/code/modules/projectiles/projectile_base.dm
+++ b/code/modules/projectiles/projectile_base.dm
@@ -463,7 +463,7 @@
return TRUE
/obj/item/projectile/experience_pressure_difference()
- return
+ return // Immune to gas flow.
/obj/item/projectile/forceMove(atom/target)
. = ..()
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 3305c8632b7..293230dd83d 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -384,13 +384,7 @@
return
if(volume >= 3)
T.MakeSlippery()
- var/hotspot = (locate(/obj/effect/hotspot) in T)
- if(hotspot)
- var/datum/gas_mixture/lowertemp = T.remove_air( T.air.total_moles())
- lowertemp.temperature = max(min(lowertemp.temperature-2000, lowertemp.temperature / 2), 0)
- lowertemp.react()
- T.assume_air(lowertemp)
- qdel(hotspot)
+ T.quench(1000, 2)
/datum/reagent/consumable/enzyme
name = "Universal Enzyme"
diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
index fdfd4e3b9c9..63bd1d2ea9e 100644
--- a/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
+++ b/code/modules/reagents/chemistry/reagents/pyrotechnic.dm
@@ -424,15 +424,8 @@
/datum/reagent/firefighting_foam/reaction_turf(turf/simulated/T, volume)
if(!istype(T))
return
- var/CT = cooling_temperature
new /obj/effect/decal/cleanable/flour/foam(T) //foam mess; clears up quickly.
- var/hotspot = (locate(/obj/effect/hotspot) in T)
- if(hotspot)
- var/datum/gas_mixture/lowertemp = T.remove_air(T.air.total_moles())
- lowertemp.temperature = max(min(lowertemp.temperature-(CT*1000), lowertemp.temperature / CT), 0)
- lowertemp.react()
- T.assume_air(lowertemp)
- qdel(hotspot)
+ T.quench(1000, cooling_temperature)
/datum/reagent/plasma_dust
name = "Plasma Dust"
diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
index 10c8a080317..d308b3d9539 100644
--- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm
+++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
@@ -338,7 +338,10 @@
if(holder && holder.my_atom)
var/turf/simulated/T = get_turf(holder.my_atom)
if(istype(T))
- T.atmos_spawn_air(LINDA_SPAWN_HEAT | LINDA_SPAWN_TOXINS, 50)
+ var/datum/gas_mixture/air = new()
+ air.set_temperature(1000)
+ air.set_toxins(20)
+ T.blind_release_air(air)
//Yellow
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index 76740a9a988..e9ce7102fc0 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -77,15 +77,32 @@
/obj/machinery/disposal/Initialize(mapload)
// this will get a copy of the air turf and take a SEND PRESSURE amount of air from it
. = ..()
- var/atom/L = loc
- var/datum/gas_mixture/env = new
- env.copy_from(L.return_air())
- var/datum/gas_mixture/removed = env.remove(SEND_PRESSURE + 1)
- air_contents = new
- air_contents.merge(removed)
+ air_contents = new()
+ var/datum/milla_safe/disposal_suck_air/milla = new()
+ milla.invoke_async(src)
trunk_check()
update()
+/datum/milla_safe/disposal_suck_air
+
+/datum/milla_safe/disposal_suck_air/on_run(obj/machinery/disposal/disposal)
+ var/turf/T = get_turf(disposal)
+ var/datum/gas_mixture/env = get_turf_air(T)
+
+ var/pressure_delta = (SEND_PRESSURE + 1) - disposal.air_contents.return_pressure()
+
+ if(env.temperature() > 0)
+ var/transfer_moles = 0.1 * pressure_delta*disposal.air_contents.volume / (env.temperature() * R_IDEAL_GAS_EQUATION)
+
+ //Actually transfer the gas
+ var/datum/gas_mixture/removed = env.remove(transfer_moles)
+ disposal.air_contents.merge(removed)
+
+ // if full enough, switch to ready mode
+ if(disposal.air_contents.return_pressure() >= SEND_PRESSURE)
+ disposal.mode = 2
+ disposal.update()
+
// attack by item places it in to disposal
/obj/machinery/disposal/attackby(obj/item/I, mob/user, params)
if(stat & BROKEN || !user || I.flags & ABSTRACT)
@@ -425,25 +442,9 @@
// otherwise charge
change_power_mode(ACTIVE_POWER_USE)
- var/atom/L = loc // recharging from loc turf
+ var/datum/milla_safe/disposal_suck_air/milla = new()
+ milla.invoke_async(src)
- var/datum/gas_mixture/env = L.return_air()
- var/pressure_delta = (SEND_PRESSURE*1.01) - air_contents.return_pressure()
-
- if(env.temperature > 0)
- var/transfer_moles = 0.1 * pressure_delta*air_contents.volume/(env.temperature * R_IDEAL_GAS_EQUATION)
-
- //Actually transfer the gas
- var/datum/gas_mixture/removed = env.remove(transfer_moles)
- air_contents.merge(removed)
- air_update_turf()
-
-
- // if full enough, switch to ready mode
- if(air_contents.return_pressure() >= SEND_PRESSURE)
- mode = 2
- update()
- return
// perform a flush
/obj/machinery/disposal/proc/flush()
@@ -714,11 +715,9 @@
playsound(loc, 'sound/effects/clang.ogg', 50, 0, 0)
// called to vent all gas in holder to a location
-/obj/structure/disposalholder/proc/vent_gas(atom/location)
- if(location)
- location.assume_air(gas) // vent all gas to turf
- air_update_turf()
- return
+/obj/structure/disposalholder/proc/vent_gas(turf/location)
+ if(istype(location))
+ location.blind_release_air(gas)
// Disposal pipes
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 04d8ee6a358..946691db282 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -367,16 +367,8 @@
ejectItem(TRUE)
if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
visible_message("[src] malfunctions, melting [exp_on] and leaking hot air!")
- var/datum/gas_mixture/env = loc.return_air()
- var/transfer_moles = 0.25 * env.total_moles()
- var/datum/gas_mixture/removed = env.remove(transfer_moles)
- if(removed)
- var/heat_capacity = removed.heat_capacity()
- if(heat_capacity == 0 || heat_capacity == null)
- heat_capacity = 1
- removed.temperature = min((removed.temperature*heat_capacity + 100000)/heat_capacity, 1000)
- env.merge(removed)
- air_update_turf()
+ var/datum/milla_safe/experimentor_temperature/milla = new()
+ milla.invoke_async(src, 100000, 1000)
investigate_log("Experimentor has released hot air.", "experimentor")
ejectItem(TRUE)
if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
@@ -413,16 +405,8 @@
ejectItem(TRUE)
if(prob(EFFECT_PROB_LOW-badThingCoeff))
visible_message("[src] malfunctions, shattering [exp_on] and leaking cold air!")
- var/datum/gas_mixture/env = loc.return_air()
- var/transfer_moles = 0.25 * env.total_moles()
- var/datum/gas_mixture/removed = env.remove(transfer_moles)
- if(removed)
- var/heat_capacity = removed.heat_capacity()
- if(heat_capacity == 0 || heat_capacity == null)
- heat_capacity = 1
- removed.temperature = (removed.temperature*heat_capacity - 75000)/heat_capacity
- env.merge(removed)
- air_update_turf()
+ var/datum/milla_safe/experimentor_temperature/milla = new()
+ milla.invoke_async(src, -75000, 1000, TCMB)
investigate_log("Experimentor has released cold air.", "experimentor")
ejectItem(TRUE)
if(prob(EFFECT_PROB_MEDIUM-badThingCoeff))
@@ -529,6 +513,21 @@
icon_state = "h_lathe"
recentlyExperimented = 0
+/datum/milla_safe/experimentor_temperature
+
+/datum/milla_safe/experimentor_temperature/on_run(obj/machinery/r_n_d/experimentor/experimentor, delta, min_new_temp)
+ var/turf/T = get_turf(experimentor)
+ var/datum/gas_mixture/env = get_turf_air(T)
+
+ var/transfer_moles = 0.25 * env.total_moles()
+ var/datum/gas_mixture/removed = env.remove(transfer_moles)
+ if(removed)
+ var/heat_capacity = removed.heat_capacity()
+ if(heat_capacity == 0 || heat_capacity == null)
+ heat_capacity = 1
+ removed.set_temperature(max(min_new_temp, (removed.temperature() * heat_capacity + delta) / heat_capacity))
+ env.merge(removed)
+
/obj/machinery/r_n_d/experimentor/Topic(href, href_list)
if(..())
return
diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm
index 0eb7290c88d..bf5e7e72d11 100644
--- a/code/modules/research/server.dm
+++ b/code/modules/research/server.dm
@@ -74,8 +74,9 @@
if(prob(3) && plays_sound)
playsound(loc, "computer_ambience", 10, TRUE, ignore_walls = FALSE)
- var/datum/gas_mixture/environment = loc.return_air()
- switch(environment.temperature)
+ var/turf/T = get_turf(src)
+ var/datum/gas_mixture/environment = T.get_readonly_air()
+ switch(environment.temperature())
if(0 to T0C)
health = min(100, health + 1)
if(T0C to (T20C + 20))
@@ -88,11 +89,11 @@
var/updateRD = 0
files.known_designs = list()
for(var/v in files.known_tech)
- var/datum/tech/T = files.known_tech[v]
+ var/datum/tech/tech = files.known_tech[v]
// Slowly decrease research if health drops below 0
if(prob(1))
updateRD++
- T.level--
+ tech.level--
if(updateRD)
files.RefreshResearch()
if(delay)
@@ -120,25 +121,31 @@
files.push_data(C.files)
/obj/machinery/r_n_d/server/proc/produce_heat(heat_amt)
- if(!(stat & (NOPOWER|BROKEN))) // Blatantly stolen from space heater.
- var/turf/simulated/L = loc
- if(istype(L))
- var/datum/gas_mixture/env = L.return_air()
- if(env.temperature < (heat_amt+T0C))
+ var/datum/milla_safe/rnd_server_heat/milla = new()
+ milla.invoke_async(src, heat_amt)
- var/transfer_moles = 0.25 * env.total_moles()
+/datum/milla_safe/rnd_server_heat
- var/datum/gas_mixture/removed = env.remove(transfer_moles)
+/datum/milla_safe/rnd_server_heat/on_run(obj/machinery/r_n_d/server/server, heat)
+ var/turf/T = get_turf(server)
+ var/datum/gas_mixture/env = get_turf_air(T)
- if(removed)
+ if(server.stat & (NOPOWER|BROKEN))
+ return
+ if(env.temperature() >= (heat + T0C))
+ return
- var/heat_capacity = removed.heat_capacity()
- if(heat_capacity == 0 || heat_capacity == null)
- heat_capacity = 1
- removed.temperature = min((removed.temperature*heat_capacity + heating_power)/heat_capacity, 1000)
+ var/transfer_moles = 0.25 * env.total_moles()
- env.merge(removed)
- air_update_turf()
+ var/datum/gas_mixture/removed = env.remove(transfer_moles)
+ if(!removed)
+ return
+
+ var/heat_capacity = removed.heat_capacity()
+ if(heat_capacity == 0 || heat_capacity == null)
+ heat_capacity = 1
+ removed.set_temperature(min((removed.temperature() * heat_capacity + server.heating_power) / heat_capacity, 1000))
+ env.merge(removed)
/obj/machinery/r_n_d/server/attackby(obj/item/O as obj, mob/user as mob, params)
if(exchange_parts(user, O))
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index 7a54a505b89..81e0d51a247 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -448,7 +448,23 @@
if(!canMove())
return -1
- var/obj/docking_port/stationary/S0 = get_docked()
+ var/datum/milla_safe/docking_port_dock/milla = new()
+ milla.invoke_async(src, S1, force, transit)
+
+/datum/milla_safe/docking_port_dock
+
+/datum/milla_safe/docking_port_dock/on_run(obj/docking_port/mobile/mobile_port, obj/docking_port/stationary/S1, force, transit)
+ // Re-check that it's OK to dock.
+ if(S1.get_docked() == mobile_port)
+ mobile_port.remove_ripples()
+ return
+ if(!force)
+ if(!mobile_port.check_dock(S1))
+ return
+ if(!mobile_port.canMove())
+ return
+
+ var/obj/docking_port/stationary/S0 = mobile_port.get_docked()
var/turf_type = /turf/space
var/area_type = /area/space
if(S0)
@@ -458,18 +474,18 @@
area_type = S0.area_type
//close and lock the dock's airlocks
- closePortDoors(S0)
+ mobile_port.closePortDoors(S0)
- var/list/L0 = return_ordered_turfs(x, y, z, dir, areaInstance)
- var/list/L1 = return_ordered_turfs(S1.x, S1.y, S1.z, S1.dir)
+ var/list/L0 = mobile_port.return_ordered_turfs(mobile_port.x, mobile_port.y, mobile_port.z, mobile_port.dir, mobile_port.areaInstance)
+ var/list/L1 = mobile_port.return_ordered_turfs(S1.x, S1.y, S1.z, S1.dir)
- var/rotation = dir2angle(S1.dir)-dir2angle(dir)
+ var/rotation = dir2angle(S1.dir) - dir2angle(mobile_port.dir)
if((rotation % 90) != 0)
rotation += (rotation % 90) //diagonal rotations not allowed, round up
rotation = SIMPLIFY_DEGREES(rotation)
//remove area surrounding docking port
- if(length(areaInstance.contents))
+ if(length(mobile_port.areaInstance.contents))
var/area/A0 = locate("[area_type]")
if(!A0)
A0 = new area_type(null)
@@ -477,10 +493,10 @@
A0.contents += T0
// Removes ripples
- remove_ripples()
+ mobile_port.remove_ripples()
//move or squish anything in the way ship at destination
- if(lance_docking && is_station_level(S1.z))
+ if(mobile_port.lance_docking && is_station_level(S1.z))
var/list/L2 = list()
switch(S1.dir)
if(NORTH)
@@ -491,8 +507,8 @@
L2 = block(locate(S1.x+36, S1.y-9, S1.z), locate(255, S1.y+9, S1.z))
if(WEST)
L2 = block(locate(1, S1.y-9, S1.z), locate(S1.x-36, S1.y+9, S1.z))
- shuttle_smash(L2, S1)
- roadkill(L0, L1, S1.dir)
+ mobile_port.shuttle_smash(L2, S1)
+ mobile_port.roadkill(L0, L1, S1.dir)
for(var/i in 1 to length(L0))
var/turf/T0 = L0[i]
@@ -502,61 +518,54 @@
if(!T1)
continue
- areaInstance.contents += T1
+ mobile_port.areaInstance.contents += T1
- var/should_transit = !is_turf_blacklisted_for_transit(T0)
+ var/should_transit = !mobile_port.is_turf_blacklisted_for_transit(T0)
if(should_transit) // Only move over stuff if the transfer actually happened
T0.copyTurf(T1)
//copy over air
if(issimulatedturf(T1))
- var/turf/simulated/Ts1 = T1
- Ts1.copy_air_with_tile(T0)
+ get_turf_air(T1).copy_from(get_turf_air(T0))
//move mobile to new location
for(var/atom/movable/AM in T0)
if(AM.loc != T0) //fix for multi-tile objects
continue
- AM.onShuttleMove(T0, T1, rotation, last_caller)
+ AM.onShuttleMove(T0, T1, rotation, mobile_port.last_caller)
if(rotation)
T1.shuttleRotate(rotation)
// Always do this stuff as it ensures that the destination turfs still behave properly with the rest of the shuttle transit
- //atmos and lighting stuff
- SSair.remove_from_active(T1)
- T1.CalculateAdjacentTurfs()
- SSair.add_to_active(T1,1)
-
+ //lighting stuff
T1.lighting_build_overlay()
+ T1.recalculate_atmos_connectivity()
if(!should_transit)
continue // Don't want to actually change the skipped turf
T0.ChangeTurf(turf_type, keep_icon = FALSE)
+ T0.recalculate_atmos_connectivity()
- SSair.remove_from_active(T0)
- T0.CalculateAdjacentTurfs()
- SSair.add_to_active(T0,1)
-
- areaInstance.moving = transit
+ mobile_port.areaInstance.moving = transit
for(var/A1 in L1)
var/turf/T1 = A1
T1.postDock(S1)
for(var/atom/movable/M in T1)
M.postDock(S1)
- loc = S1.loc
- dir = S1.dir
+ mobile_port.loc = S1.loc
+ mobile_port.dir = S1.dir
//update mining and labor shuttle ash storm audio
- if(id in list("mining", "laborcamp"))
+ if(mobile_port.id in list("mining", "laborcamp"))
var/mining_zlevel = level_name_to_num(MINING)
var/datum/weather/ash_storm/W = SSweather.get_weather(mining_zlevel, /area/lavaland/surface/outdoors)
if(W)
W.update_eligible_areas()
W.update_audio()
- unlockPortDoors(S1)
+ mobile_port.unlockPortDoors(S1)
/obj/docking_port/mobile/proc/is_turf_blacklisted_for_transit(turf/T)
var/static/list/blacklisted_turf_types = typecacheof(list(/turf/space, /turf/simulated/floor/chasm, /turf/simulated/floor/lava, /turf/simulated/floor/plating/asteroid))
diff --git a/code/modules/space_management/zlevel_manager.dm b/code/modules/space_management/zlevel_manager.dm
index ab9cc4b92a9..d2364652ee6 100644
--- a/code/modules/space_management/zlevel_manager.dm
+++ b/code/modules/space_management/zlevel_manager.dm
@@ -29,6 +29,7 @@ GLOBAL_DATUM_INIT(space_manager, /datum/zlev_manager, new())
var/list/attributes = features["attributes"]
attributes = attributes.Copy() // Clone the list so it can't be changed on accident
+ milla_init_z(k)
var/datum/space_level/S = new /datum/space_level(k, name, transition_type = linking, traits = attributes)
z_list["[k]"] = S
levels_by_name[name] = S
@@ -37,6 +38,7 @@ GLOBAL_DATUM_INIT(space_manager, /datum/zlev_manager, new())
// Then, we take care of unmanaged z levels
// They get the default linkage of SELFLOOPING
for(var/i = k, i <= world.maxz, i++)
+ milla_init_z(k)
z_list["[i]"] = new /datum/space_level(i)
initialized = 1
@@ -112,6 +114,7 @@ GLOBAL_DATUM_INIT(space_manager, /datum/zlev_manager, new())
throw EXCEPTION("Name already in use: [name]")
world.maxz++
var/our_z = world.maxz
+ milla_init_z(our_z)
var/datum/space_level/S = new /datum/space_level(our_z, name, transition_type = linkage, traits = traits)
levels_by_name[name] = S
z_list["[our_z]"] = S
diff --git a/code/modules/surgery/organs/organ_datums/lung_datum.dm b/code/modules/surgery/organs/organ_datums/lung_datum.dm
index a07866eface..d02f8095904 100644
--- a/code/modules/surgery/organs/organ_datums/lung_datum.dm
+++ b/code/modules/surgery/organs/organ_datums/lung_datum.dm
@@ -81,11 +81,11 @@
var/gas_breathed = 0
//Partial pressures in our breath
- var/O2_pp = breath.get_breath_partial_pressure(breath.oxygen)
- var/N2_pp = breath.get_breath_partial_pressure(breath.nitrogen)
- var/Toxins_pp = breath.get_breath_partial_pressure(breath.toxins)
- var/CO2_pp = breath.get_breath_partial_pressure(breath.carbon_dioxide)
- var/SA_pp = breath.get_breath_partial_pressure(breath.sleeping_agent)
+ var/O2_pp = breath.get_breath_partial_pressure(breath.oxygen())
+ var/N2_pp = breath.get_breath_partial_pressure(breath.nitrogen())
+ var/Toxins_pp = breath.get_breath_partial_pressure(breath.toxins())
+ var/CO2_pp = breath.get_breath_partial_pressure(breath.carbon_dioxide())
+ var/SA_pp = breath.get_breath_partial_pressure(breath.sleeping_agent())
//-- OXY --//
@@ -93,7 +93,7 @@
//Too much oxygen! //Yes, some species may not like it.
if(safe_oxygen_max)
if(O2_pp > safe_oxygen_max)
- var/ratio = (breath.oxygen / safe_oxygen_max / safe_oxygen_max) * 10
+ var/ratio = (breath.oxygen() / safe_oxygen_max / safe_oxygen_max) * 10
H.apply_damage_type(clamp(ratio, oxy_breath_dam_min, oxy_breath_dam_max), oxy_damage_type)
H.throw_alert("too_much_oxy", /atom/movable/screen/alert/too_much_oxy)
else
@@ -102,16 +102,16 @@
//Too little oxygen!
if(safe_oxygen_min)
if(O2_pp < safe_oxygen_min)
- gas_breathed = handle_too_little_breath(H, O2_pp, safe_oxygen_min, breath.oxygen)
+ gas_breathed = handle_too_little_breath(H, O2_pp, safe_oxygen_min, breath.oxygen())
H.throw_alert("not_enough_oxy", /atom/movable/screen/alert/not_enough_oxy)
else
H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS)
- gas_breathed = breath.oxygen
+ gas_breathed = breath.oxygen()
H.clear_alert("not_enough_oxy")
//Exhale
- breath.oxygen -= gas_breathed
- breath.carbon_dioxide += gas_breathed
+ breath.set_oxygen(breath.oxygen() - gas_breathed)
+ breath.set_carbon_dioxide(breath.carbon_dioxide() + gas_breathed)
gas_breathed = 0
//-- Nitrogen --//
@@ -119,7 +119,7 @@
//Too much nitrogen!
if(safe_nitro_max)
if(N2_pp > safe_nitro_max)
- var/ratio = (breath.nitrogen / safe_nitro_max) * 10
+ var/ratio = (breath.nitrogen() / safe_nitro_max) * 10
H.apply_damage_type(clamp(ratio, nitro_breath_dam_min, nitro_breath_dam_max), nitro_damage_type)
H.throw_alert("too_much_nitro", /atom/movable/screen/alert/too_much_nitro)
else
@@ -128,16 +128,16 @@
//Too little nitrogen!
if(safe_nitro_min)
if(N2_pp < safe_nitro_min)
- gas_breathed = handle_too_little_breath(H, N2_pp, safe_nitro_min, breath.nitrogen)
+ gas_breathed = handle_too_little_breath(H, N2_pp, safe_nitro_min, breath.nitrogen())
H.throw_alert("not_enough_nitro", /atom/movable/screen/alert/not_enough_nitro)
else
H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS)
- gas_breathed = breath.nitrogen
+ gas_breathed = breath.nitrogen()
H.clear_alert("not_enough_nitro")
//Exhale
- breath.nitrogen -= gas_breathed
- breath.carbon_dioxide += gas_breathed
+ breath.set_nitrogen(breath.nitrogen() - gas_breathed)
+ breath.set_carbon_dioxide(breath.carbon_dioxide() + gas_breathed)
gas_breathed = 0
//-- CO2 --//
@@ -163,16 +163,16 @@
//Too little CO2!
if(safe_co2_min)
if(CO2_pp < safe_co2_min)
- gas_breathed = handle_too_little_breath(H, CO2_pp, safe_co2_min, breath.carbon_dioxide)
+ gas_breathed = handle_too_little_breath(H, CO2_pp, safe_co2_min, breath.carbon_dioxide())
H.throw_alert("not_enough_co2", /atom/movable/screen/alert/not_enough_co2)
else
H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS)
- gas_breathed = breath.carbon_dioxide
+ gas_breathed = breath.carbon_dioxide()
H.clear_alert("not_enough_co2")
//Exhale
- breath.carbon_dioxide -= gas_breathed
- breath.oxygen += gas_breathed
+ breath.set_carbon_dioxide(breath.carbon_dioxide() - gas_breathed)
+ breath.set_oxygen(breath.oxygen() + gas_breathed)
gas_breathed = 0
@@ -181,7 +181,7 @@
//Too much toxins!
if(safe_toxins_max)
if(Toxins_pp > safe_toxins_max)
- var/ratio = (breath.toxins / safe_toxins_max) * 10
+ var/ratio = (breath.toxins() / safe_toxins_max) * 10
H.apply_damage_type(clamp(ratio, tox_breath_dam_min, tox_breath_dam_max), tox_damage_type)
H.throw_alert("too_much_tox", /atom/movable/screen/alert/too_much_tox)
else
@@ -191,22 +191,22 @@
//Too little toxins!
if(safe_toxins_min)
if(Toxins_pp < safe_toxins_min)
- gas_breathed = handle_too_little_breath(H, Toxins_pp, safe_toxins_min, breath.toxins)
+ gas_breathed = handle_too_little_breath(H, Toxins_pp, safe_toxins_min, breath.toxins())
H.throw_alert("not_enough_tox", /atom/movable/screen/alert/not_enough_tox)
else
H.adjustOxyLoss(-HUMAN_MAX_OXYLOSS)
- gas_breathed = breath.toxins
+ gas_breathed = breath.toxins()
H.clear_alert("not_enough_tox")
//Exhale
- breath.toxins -= gas_breathed
- breath.carbon_dioxide += gas_breathed
+ breath.set_toxins(breath.toxins() - gas_breathed)
+ breath.set_carbon_dioxide(breath.carbon_dioxide() + gas_breathed)
gas_breathed = 0
//-- TRACES --//
- if(breath.sleeping_agent) // If there's some other shit in the air lets deal with it here.
+ if(breath.sleeping_agent()) // If there's some other shit in the air lets deal with it here.
if(SA_pp > SA_para_min)
H.Paralyse(6 SECONDS) // 6 seconds gives them one second to wake up and run away a bit!
if(SA_pp > SA_sleep_min) // Enough to make us sleep as well
@@ -236,7 +236,7 @@
/datum/organ/lungs/proc/handle_breath_temperature(datum/gas_mixture/breath, mob/living/carbon/human/H) // called by human/life, handles temperatures
- var/breath_temperature = breath.temperature
+ var/breath_temperature = breath.temperature()
if(!HAS_TRAIT(H, TRAIT_RESISTCOLD)) // COLD DAMAGE
var/CM = abs(H.dna.species.coldmod)
diff --git a/code/modules/unit_tests/atmos/test_ventcrawl.dm b/code/modules/unit_tests/atmos/test_ventcrawl.dm
index 7df0fd482e3..b4b153d1953 100644
--- a/code/modules/unit_tests/atmos/test_ventcrawl.dm
+++ b/code/modules/unit_tests/atmos/test_ventcrawl.dm
@@ -2,15 +2,20 @@
var/mob/living/simple_animal/slime = null
var/obj/machinery/vent = null
var/obj/structure/table/table = null
+ var/setup_complete = FALSE
-/datum/unit_test/ventcrawl/proc/setup_test_area()
+/datum/milla_safe/ventcrawl_test_setup
+
+/datum/milla_safe/ventcrawl_test_setup/on_run(datum/unit_test/ventcrawl/test)
+ // This setup creates turfs that initialize themselves in MILLA on creation, which is why we need to be MILLA-safe.
var/datum/map_template/template = GLOB.map_templates["test_ventcrawl.dmm"]
- if(!template.load(run_loc_bottom_left))
- Fail("Failed to load 'test_ventcrawl.dmm'")
+ if(!template.load(test.run_loc_bottom_left))
+ test.Fail("Failed to load 'test_ventcrawl.dmm'")
- slime = new /mob/living/simple_animal/slime/unit_test_dummy(run_loc_bottom_left)
- vent = find_spawned_test_object(run_loc_bottom_left, /obj/machinery/atmospherics/unary/vent_pump)
- table = find_spawned_test_object(get_step(run_loc_bottom_left, EAST), /obj/structure/table)
+ test.slime = new /mob/living/simple_animal/slime/unit_test_dummy(test.run_loc_bottom_left)
+ test.vent = test.find_spawned_test_object(test.run_loc_bottom_left, /obj/machinery/atmospherics/unary/vent_pump)
+ test.table = test.find_spawned_test_object(get_step(test.run_loc_bottom_left, EAST), /obj/structure/table)
+ test.setup_complete = TRUE
/datum/unit_test/ventcrawl/proc/find_spawned_test_object(turf/location as turf, test_object_type)
for(var/content in location.contents)
@@ -19,7 +24,10 @@
Fail("Couldn't find spawned test object of type: [test_object_type].")
/datum/unit_test/ventcrawl/Run()
- setup_test_area()
+ var/datum/milla_safe/ventcrawl_test_setup/milla = new()
+ milla.invoke_async(src)
+ while(!setup_complete)
+ sleep(world.tick_lag)
// Enter vent
vent.AltClick(slime)
diff --git a/milla.dll b/milla.dll
new file mode 100755
index 00000000000..956df9e5f22
Binary files /dev/null and b/milla.dll differ
diff --git a/milla/Cargo.lock b/milla/Cargo.lock
new file mode 100644
index 00000000000..eee0b6908eb
--- /dev/null
+++ b/milla/Cargo.lock
@@ -0,0 +1,724 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "atomic_float"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c4b08ed8a30ff7320117c190eb4d73d47f0ac0c930ab853b8224cef7cd9a5e7"
+
+[[package]]
+name = "bindgen"
+version = "0.69.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "clang-sys",
+ "itertools",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "prettyplease",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "syn",
+ "which",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+
+[[package]]
+name = "byondapi"
+version = "0.4.7"
+source = "git+https://github.com/spacestation13/byondapi-rs.git#aa4addd95c33b66652b3e35e7401a0ad82aa028e"
+dependencies = [
+ "byondapi-macros",
+ "byondapi-sys",
+ "inventory",
+ "lazy_static",
+ "libloading",
+ "num_enum",
+ "walkdir",
+]
+
+[[package]]
+name = "byondapi-macros"
+version = "0.1.2"
+source = "git+https://github.com/spacestation13/byondapi-rs.git#aa4addd95c33b66652b3e35e7401a0ad82aa028e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "byondapi-sys"
+version = "0.11.1"
+source = "git+https://github.com/spacestation13/byondapi-rs.git#aa4addd95c33b66652b3e35e7401a0ad82aa028e"
+dependencies = [
+ "bindgen",
+ "doxygen-rs",
+ "libloading",
+ "rustc_version",
+ "walkdir",
+]
+
+[[package]]
+name = "cexpr"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clang-sys"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "doxygen-rs"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "415b6ec780d34dcf624666747194393603d0373b7141eef01d12ee58881507d9"
+dependencies = [
+ "phf",
+]
+
+[[package]]
+name = "either"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "errno"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+dependencies = [
+ "libc",
+ "windows-sys",
+]
+
+[[package]]
+name = "eyre"
+version = "0.6.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
+dependencies = [
+ "indenter",
+ "once_cell",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "home"
+version = "0.5.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "indenter"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
+
+[[package]]
+name = "indexmap"
+version = "2.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "inventory"
+version = "0.3.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767"
+
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "libc"
+version = "0.2.154"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
+
+[[package]]
+name = "libloading"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
+dependencies = [
+ "cfg-if",
+ "windows-targets",
+]
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.4.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+
+[[package]]
+name = "log"
+version = "0.4.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+
+[[package]]
+name = "memchr"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
+
+[[package]]
+name = "milla"
+version = "1.0.0"
+dependencies = [
+ "atomic_float",
+ "bitflags",
+ "byondapi",
+ "eyre",
+ "rand",
+ "scc",
+ "thread-priority",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "nom"
+version = "7.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
+name = "phf"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc"
+dependencies = [
+ "phf_macros",
+ "phf_shared",
+]
+
+[[package]]
+name = "phf_generator"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0"
+dependencies = [
+ "phf_shared",
+ "rand",
+]
+
+[[package]]
+name = "phf_macros"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b"
+dependencies = [
+ "phf_generator",
+ "phf_shared",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "phf_shared"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b"
+dependencies = [
+ "siphasher",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "prettyplease"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ac2cf0f2e4f42b49f5ffd07dae8d746508ef7526c13940e5f524012ae6c6550"
+dependencies = [
+ "proc-macro2",
+ "syn",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
+dependencies = [
+ "toml_edit",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.81"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "0.38.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0"
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scc"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76ad2bbb0ae5100a07b7a6f2ed7ab5fd0045551a4c507989b7a620046ea3efdc"
+dependencies = [
+ "sdd",
+]
+
+[[package]]
+name = "sdd"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b84345e4c9bd703274a082fb80caaa99b7612be48dfaa1dd9266577ec412309d"
+
+[[package]]
+name = "semver"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+
+[[package]]
+name = "shlex"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
+[[package]]
+name = "syn"
+version = "2.0.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thread-priority"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d3b04d33c9633b8662b167b847c7ab521f83d1ae20f2321b65b5b925e532e36"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "libc",
+ "log",
+ "rustversion",
+ "winapi",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+
+[[package]]
+name = "toml_edit"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "walkdir"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
+dependencies = [
+ "same-file",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "which"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
+dependencies = [
+ "either",
+ "home",
+ "once_cell",
+ "rustix",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
diff --git a/milla/Cargo.toml b/milla/Cargo.toml
new file mode 100644
index 00000000000..268df469456
--- /dev/null
+++ b/milla/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "milla"
+version = "1.0.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+atomic_float = "1.0.0"
+bitflags = "2.5.0"
+byondapi = { git = "https://github.com/spacestation13/byondapi-rs.git", version = "0.4.7" }
+eyre = "0.6.12"
+rand = { version = "0.8.5", features = ["small_rng"] }
+scc = "2.1.1"
+thread-priority = "1.1.0"
diff --git a/milla/src/api.rs b/milla/src/api.rs
new file mode 100644
index 00000000000..db0bbe6206a
--- /dev/null
+++ b/milla/src/api.rs
@@ -0,0 +1,548 @@
+use crate::constants::*;
+use crate::conversion;
+use crate::logging;
+use crate::model::*;
+use crate::statics::*;
+use crate::tick;
+use byondapi::global_call::call_global;
+use byondapi::map::byond_xyz;
+use byondapi::prelude::*;
+use eyre::eyre;
+use eyre::Result;
+use std::thread;
+use std::time::Instant;
+
+/// BYOND API for ensuring the buffers are usable.
+#[byondapi::bind]
+fn initialize(byond_z: ByondValue) {
+ logging::setup_panic_handler();
+ let z = f32::try_from(byond_z)? as i32 - 1;
+ internal_initialize(z)?;
+ Ok(Default::default())
+}
+
+/// Ensure that buffers are available.
+pub(crate) fn internal_initialize(z: i32) -> Result<(), eyre::Error> {
+ if z >= MAX_Z_LEVELS {
+ return Err(eyre!(
+ "Suspiciously high Z level {} initialized, update MAX_Z_LEVELS if this is intentional.",
+ z
+ ));
+ }
+ let buffers = BUFFERS.get_or_init(Buffers::new);
+ buffers.init_to(z);
+ Ok(Default::default())
+}
+
+/// BYOND API for defining an environment that a tile can be exposed to.
+#[byondapi::bind]
+fn create_environment(
+ oxygen: ByondValue,
+ carbon_dioxide: ByondValue,
+ nitrogen: ByondValue,
+ toxins: ByondValue,
+ sleeping_agent: ByondValue,
+ agent_b: ByondValue,
+ temperature: ByondValue,
+) {
+ logging::setup_panic_handler();
+ Ok(ByondValue::from(internal_create_environment(
+ conversion::byond_to_option_f32(oxygen)?,
+ conversion::byond_to_option_f32(carbon_dioxide)?,
+ conversion::byond_to_option_f32(nitrogen)?,
+ conversion::byond_to_option_f32(toxins)?,
+ conversion::byond_to_option_f32(sleeping_agent)?,
+ conversion::byond_to_option_f32(agent_b)?,
+ conversion::byond_to_option_f32(temperature)?,
+ ) as f32))
+}
+
+/// Define an environment that a tile can be exposed to.
+pub(crate) fn internal_create_environment(
+ oxygen: Option,
+ carbon_dioxide: Option,
+ nitrogen: Option,
+ toxins: Option,
+ sleeping_agent: Option,
+ agent_b: Option,
+ temperature: Option,
+) -> u8 {
+ let mut tile = Tile::new();
+ if let Some(value) = oxygen {
+ tile.gases.set_oxygen(value);
+ }
+ if let Some(value) = carbon_dioxide {
+ tile.gases.set_carbon_dioxide(value);
+ }
+ if let Some(value) = nitrogen {
+ tile.gases.set_nitrogen(value);
+ }
+ if let Some(value) = toxins {
+ tile.gases.set_toxins(value);
+ }
+ if let Some(value) = sleeping_agent {
+ tile.gases.set_sleeping_agent(value);
+ }
+ if let Some(value) = agent_b {
+ tile.gases.set_agent_b(value);
+ }
+ if let Some(value) = temperature {
+ tile.thermal_energy = value * tile.heat_capacity();
+ }
+
+ let buffers = BUFFERS.get_or_init(Buffers::new);
+ buffers.create_environment(tile)
+}
+
+/// BYOND API for setting the atmos details of a tile.
+#[byondapi::bind]
+fn set_tile(
+ turf: ByondValue,
+ airtight_north: ByondValue,
+ airtight_east: ByondValue,
+ airtight_south: ByondValue,
+ airtight_west: ByondValue,
+ atmos_mode: ByondValue,
+ environment: ByondValue,
+ oxygen: ByondValue,
+ carbon_dioxide: ByondValue,
+ nitrogen: ByondValue,
+ toxins: ByondValue,
+ sleeping_agent: ByondValue,
+ agent_b: ByondValue,
+ temperature: ByondValue,
+ _innate_heat_capacity: ByondValue,
+) {
+ logging::setup_panic_handler();
+ let (x, y, z) = byond_xyz(&turf)?.coordinates();
+ internal_set_tile(
+ x as i32 - 1,
+ y as i32 - 1,
+ z as i32 - 1,
+ conversion::byond_to_option_f32(airtight_north)?,
+ conversion::byond_to_option_f32(airtight_east)?,
+ conversion::byond_to_option_f32(airtight_south)?,
+ conversion::byond_to_option_f32(airtight_west)?,
+ conversion::byond_to_option_f32(atmos_mode)?,
+ conversion::byond_to_option_f32(environment)?,
+ conversion::bounded_byond_to_option_f32(oxygen, 0.0, f32::INFINITY)?,
+ conversion::bounded_byond_to_option_f32(carbon_dioxide, 0.0, f32::INFINITY)?,
+ conversion::bounded_byond_to_option_f32(nitrogen, 0.0, f32::INFINITY)?,
+ conversion::bounded_byond_to_option_f32(toxins, 0.0, f32::INFINITY)?,
+ conversion::bounded_byond_to_option_f32(sleeping_agent, 0.0, f32::INFINITY)?,
+ conversion::bounded_byond_to_option_f32(agent_b, 0.0, f32::INFINITY)?,
+ conversion::bounded_byond_to_option_f32(temperature, 0.0, f32::INFINITY)?,
+ None,
+ // Temporarily disabled to better match the existing system.
+ //bounded_byond_to_option_f32(innate_heat_capacity, 0.0, f32::INFINITY)?,
+ Some(0.0),
+ )?;
+ Ok(Default::default())
+}
+
+/// BYOND API for setting the directions a tile is airtight in.
+/// Like set_tile, just with a smaller set of fields.
+#[byondapi::bind]
+fn set_tile_airtight(
+ turf: ByondValue,
+ airtight_north: ByondValue,
+ airtight_east: ByondValue,
+ airtight_south: ByondValue,
+ airtight_west: ByondValue,
+) {
+ logging::setup_panic_handler();
+ let (x, y, z) = byond_xyz(&turf)?.coordinates();
+ internal_set_tile(
+ x as i32 - 1,
+ y as i32 - 1,
+ z as i32 - 1,
+ conversion::byond_to_option_f32(airtight_north)?,
+ conversion::byond_to_option_f32(airtight_east)?,
+ conversion::byond_to_option_f32(airtight_south)?,
+ conversion::byond_to_option_f32(airtight_west)?,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ )?;
+ Ok(Default::default())
+}
+
+/// Rust version of setting the atmos details of a tile.
+#[allow(clippy::too_many_arguments)]
+pub(crate) fn internal_set_tile(
+ x: i32,
+ y: i32,
+ z: i32,
+ airtight_north: Option,
+ airtight_east: Option,
+ airtight_south: Option,
+ airtight_west: Option,
+ atmos_mode: Option,
+ environment: Option,
+ oxygen: Option,
+ carbon_dioxide: Option,
+ nitrogen: Option,
+ toxins: Option,
+ sleeping_agent: Option,
+ agent_b: Option,
+ temperature: Option,
+ thermal_energy: Option,
+ innate_heat_capacity: Option,
+) -> Result<()> {
+ let buffers = BUFFERS.get().ok_or(eyre!("BUFFERS not initialized."))?;
+ let active = buffers.get_active().read().unwrap();
+ let maybe_z_level = active.0[z as usize].try_write();
+ if maybe_z_level.is_err() {
+ return Err(eyre!(
+ "Tried to write during asynchronous, read-only atmos. Use a /datum/milla_safe/..."
+ ));
+ }
+ let mut z_level = maybe_z_level.unwrap();
+ let tile = z_level.get_tile_mut(ZLevel::maybe_get_index(x, y).ok_or(eyre!(
+ "Bad coordinates ({}, {}, {})",
+ x + 1,
+ y + 1,
+ z + 1
+ ))?);
+ if let Some(value) = airtight_north {
+ tile.airtight_directions
+ .set(AirtightDirections::NORTH, value > 0.0);
+ }
+ if let Some(value) = airtight_east {
+ tile.airtight_directions
+ .set(AirtightDirections::EAST, value > 0.0);
+ }
+ if let Some(value) = airtight_south {
+ tile.airtight_directions
+ .set(AirtightDirections::SOUTH, value > 0.0);
+ }
+ if let Some(value) = airtight_west {
+ tile.airtight_directions
+ .set(AirtightDirections::WEST, value > 0.0);
+ }
+ if let Some(value) = atmos_mode {
+ match value as i32 {
+ 0 => tile.mode = AtmosMode::Space,
+ 1 => tile.mode = AtmosMode::Sealed,
+ 2 => {
+ if let Some(env) = environment {
+ tile.mode = AtmosMode::ExposedTo {
+ environment_id: env as u8,
+ };
+ }
+ }
+ _ => return Err(eyre!("Invalid atmos_mode: {}", value)),
+ }
+ }
+ if let Some(value) = oxygen {
+ tile.gases.set_oxygen(value);
+ }
+ if let Some(value) = carbon_dioxide {
+ tile.gases.set_carbon_dioxide(value);
+ }
+ if let Some(value) = nitrogen {
+ tile.gases.set_nitrogen(value);
+ }
+ if let Some(value) = toxins {
+ tile.gases.set_toxins(value);
+ }
+ if let Some(value) = sleeping_agent {
+ tile.gases.set_sleeping_agent(value);
+ }
+ if let Some(value) = agent_b {
+ tile.gases.set_agent_b(value);
+ }
+ // Done sooner because we need innate heat capacity to calculate thermal energy from
+ // temperature.
+ if let Some(value) = innate_heat_capacity {
+ tile.innate_heat_capacity = value;
+ }
+ if let Some(value) = temperature {
+ tile.thermal_energy = value * tile.heat_capacity();
+ }
+ if let Some(value) = thermal_energy {
+ tile.thermal_energy = value;
+ }
+
+ Ok(())
+}
+
+/// BYOND API for fetching the atmos details of a tile.
+#[byondapi::bind]
+fn get_tile(turf: ByondValue, list: ByondValue) {
+ logging::setup_panic_handler();
+ let (x, y, z) = byond_xyz(&turf)?.coordinates();
+ let tile = internal_get_tile(x as i32 - 1, y as i32 - 1, z as i32 - 1)?;
+ let vec: Vec = (&tile).into();
+ list.write_list(vec.as_slice())?;
+ Ok(Default::default())
+}
+
+/// Rust version of fetching the atmos details of a tile.
+pub(crate) fn internal_get_tile(x: i32, y: i32, z: i32) -> Result {
+ let buffers = BUFFERS.get().ok_or(eyre!("BUFFERS not initialized."))?;
+ let active = buffers.get_active().read().unwrap();
+ let z_level = active.0[z as usize].read().unwrap();
+ Ok(z_level
+ .get_tile(ZLevel::maybe_get_index(x, y).ok_or(eyre!(
+ "Bad coordinates ({}, {}, {})",
+ x + 1,
+ y + 1,
+ z + 1
+ ))?)
+ .clone())
+}
+
+/// BYOND API for getting a list of interesting tiles this tick.
+/// There are three kinds:
+/// * Turfs that are hot eough to cause fires.
+/// * Turfs that just passed the threshold for showing plasma or sleeping gas.
+/// * Turfs with strong airflow out.
+#[byondapi::bind]
+fn get_interesting_tiles() {
+ logging::setup_panic_handler();
+ let interesting_tiles = INTERESTING_TILES.lock().unwrap();
+ let byond_interesting_tiles = interesting_tiles
+ .iter()
+ .flat_map(|v| Vec::from(v))
+ .collect::>();
+ Ok(byond_interesting_tiles.as_slice().try_into()?)
+}
+
+/// BYOND API for getting a single random interesting tile.
+#[byondapi::bind]
+fn get_random_interesting_tile() {
+ logging::setup_panic_handler();
+ let interesting_tiles = INTERESTING_TILES.lock().unwrap();
+ let length = interesting_tiles.len() as f32;
+ if length <= 0.0 {
+ return Err(eyre!("No interesting tiles."));
+ }
+ let random: f32 = rand::random();
+ let chosen = (random * length) as usize;
+ Ok(Vec::from(&interesting_tiles[chosen])
+ .as_slice()
+ .try_into()?)
+}
+
+/// BYOND API for capping the superconductivity of a tile.
+#[byondapi::bind]
+fn reduce_superconductivity(
+ turf: ByondValue,
+ north: ByondValue,
+ east: ByondValue,
+ south: ByondValue,
+ west: ByondValue,
+) {
+ let (x, y, z) = byond_xyz(&turf)?.coordinates();
+ let rust_north = conversion::bounded_byond_to_option_f32(north, 0.0, 1.0)?;
+ let rust_east = conversion::bounded_byond_to_option_f32(east, 0.0, 1.0)?;
+ let rust_south = conversion::bounded_byond_to_option_f32(south, 0.0, 1.0)?;
+ let rust_west = conversion::bounded_byond_to_option_f32(west, 0.0, 1.0)?;
+ internal_reduce_superconductivity(
+ x as i32 - 1,
+ y as i32 - 1,
+ z as i32 - 1,
+ rust_north,
+ rust_east,
+ rust_south,
+ rust_west,
+ )?;
+ Ok(Default::default())
+}
+
+/// Rust version of capping the superconductivity of a tile.
+/// We never increase superconductivity, only reduce it, because it represents how much heat flow has
+/// been restricted by the tiles and objects on them.
+pub(crate) fn internal_reduce_superconductivity(
+ x: i32,
+ y: i32,
+ z: i32,
+ north: Option,
+ east: Option,
+ south: Option,
+ west: Option,
+) -> Result<(), eyre::Error> {
+ let buffers = BUFFERS.get().ok_or(eyre!("BUFFERS not initialized."))?;
+ let active = buffers.get_active().read().unwrap();
+ let maybe_z_level = active.0[z as usize].try_write();
+ if maybe_z_level.is_err() {
+ return Err(eyre!(
+ "Tried to write during asynchronous, read-only atmos. Use a /datum/milla_safe/..."
+ ));
+ }
+ let mut z_level = maybe_z_level.unwrap();
+ let tile = z_level.get_tile_mut(ZLevel::maybe_get_index(x, y).ok_or(eyre!(
+ "Bad coordinates ({}, {}, {})",
+ x + 1,
+ y + 1,
+ z + 1
+ ))?);
+ if let Some(value) = north {
+ tile.superconductivity.north = tile.superconductivity.north.min(value);
+ }
+ if let Some(value) = east {
+ tile.superconductivity.east = tile.superconductivity.east.min(value);
+ }
+ if let Some(value) = south {
+ tile.superconductivity.south = tile.superconductivity.south.min(value);
+ }
+ if let Some(value) = west {
+ tile.superconductivity.west = tile.superconductivity.west.min(value);
+ }
+ Ok(())
+}
+
+/// BYOND API for resetting the superconductivity of a tile.
+#[byondapi::bind]
+fn reset_superconductivity(turf: ByondValue) {
+ let (x, y, z) = byond_xyz(&turf)?.coordinates();
+ internal_reset_superconductivity(x as i32 - 1, y as i32 - 1, z as i32 - 1)?;
+ Ok(Default::default())
+}
+
+/// Rust version of resetting the superconductivity of a tile.
+pub(crate) fn internal_reset_superconductivity(x: i32, y: i32, z: i32) -> Result<()> {
+ let buffers = BUFFERS.get().ok_or(eyre!("BUFFERS not initialized."))?;
+ let active = buffers.get_active().read().unwrap();
+ let maybe_z_level = active.0[z as usize].try_write();
+ if maybe_z_level.is_err() {
+ return Err(eyre!(
+ "Tried to write during asynchronous, read-only atmos. Use a /datum/milla_safe/..."
+ ));
+ }
+ let mut z_level = maybe_z_level.unwrap();
+ let tile = z_level.get_tile_mut(ZLevel::maybe_get_index(x, y).ok_or(eyre!(
+ "Bad coordinates ({}, {}, {})",
+ x + 1,
+ y + 1,
+ z + 1
+ ))?);
+ tile.superconductivity.north = OPEN_HEAT_TRANSFER_COEFFICIENT;
+ tile.superconductivity.east = OPEN_HEAT_TRANSFER_COEFFICIENT;
+ tile.superconductivity.south = OPEN_HEAT_TRANSFER_COEFFICIENT;
+ tile.superconductivity.west = OPEN_HEAT_TRANSFER_COEFFICIENT;
+ Ok(())
+}
+
+/// BYOND API for starting an atmos tick.
+#[byondapi::bind]
+fn spawn_tick_thread() {
+ logging::setup_panic_handler();
+ thread::spawn(|| -> Result<(), eyre::Error> {
+ let now = Instant::now();
+ let buffers = BUFFERS.get_or_init(Buffers::new);
+ tick::tick(buffers)?;
+ TICK_TIME.store(
+ now.elapsed().as_millis() as usize,
+ std::sync::atomic::Ordering::Relaxed,
+ );
+ call_global("milla_tick_finished", &[])?;
+ Ok(())
+ });
+ Ok(Default::default())
+}
+
+/// BYOND API for asking how long the prior tick took.
+#[byondapi::bind]
+fn get_tick_time() {
+ logging::setup_panic_handler();
+ Ok(ByondValue::from(
+ TICK_TIME.load(std::sync::atomic::Ordering::Relaxed) as f32,
+ ))
+}
+
+// Yay, tests!
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ // The data set by internal_set_tile() should be retrieved by internal_get_tile().
+ #[test]
+ fn set_get_loop() {
+ let test_z = 0;
+ internal_initialize(test_z).unwrap();
+
+ // Set some arbitrary data.
+ internal_set_tile(
+ 1,
+ 2,
+ test_z,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ Some(1.0),
+ None,
+ Some(1.0),
+ None,
+ Some(1.0),
+ None,
+ None,
+ Some(1.0),
+ )
+ .unwrap();
+
+ // Check that we got the same data back.
+ {
+ let tile = internal_get_tile(1, 2, test_z).unwrap();
+ for gas in 0..GAS_COUNT {
+ if gas % 2 == 0 {
+ assert_eq!(tile.gases.values[gas], 0.0, "{}", gas);
+ } else {
+ assert_eq!(tile.gases.values[gas], 1.0, "{}", gas);
+ }
+ }
+ assert_eq!(tile.thermal_energy, 0.0);
+ assert_eq!(tile.innate_heat_capacity, 1.0);
+ }
+
+ // Set a different set of arbitrary data.
+ internal_set_tile(
+ 1,
+ 1,
+ test_z,
+ None,
+ None,
+ None,
+ None,
+ None,
+ None,
+ Some(1.0),
+ None,
+ Some(1.0),
+ None,
+ Some(1.0),
+ None,
+ None,
+ Some(1.0),
+ None,
+ )
+ .unwrap();
+
+ // Check that we got the same data back.
+ {
+ let tile = internal_get_tile(1, 1, test_z).unwrap();
+ for gas in 0..GAS_COUNT {
+ if gas % 2 == 0 {
+ assert_eq!(tile.gases.values[gas], 1.0, "{}", gas);
+ } else {
+ assert_eq!(tile.gases.values[gas], 0.0, "{}", gas);
+ }
+ }
+ assert_eq!(tile.thermal_energy, 1.0);
+ assert_eq!(tile.innate_heat_capacity, 0.0);
+ }
+ }
+}
diff --git a/milla/src/constants.rs b/milla/src/constants.rs
new file mode 100644
index 00000000000..df6dc8138cb
--- /dev/null
+++ b/milla/src/constants.rs
@@ -0,0 +1,134 @@
+/// How many Z levels we allow before being suspicious that the wrong number was sent.
+pub(crate) const MAX_Z_LEVELS: i32 = 10;
+
+/// How big is the map? Assumed square.
+pub(crate) const MAP_SIZE: usize = 255;
+
+/// 0 degrees Celsius, in Kelvin
+pub(crate) const T0C: f32 = 273.15;
+
+/// 20 degrees Celsius, in Kelvin
+pub(crate) const T20C: f32 = T0C + 20.0;
+
+/// How well does heat transfer in ideal circumstances?
+pub(crate) const OPEN_HEAT_TRANSFER_COEFFICIENT: f32 = 0.4;
+
+/// The constant R from the ideal gas equation.
+pub(crate) const R_IDEAL_GAS_EQUATION: f32 = 8.31;
+
+/// How big a tile is, in liters.
+pub(crate) const TILE_VOLUME: f32 = 2500.0;
+
+/// How many moles are needed to make toxins visible.
+pub(crate) const TOXINS_VISIBILITY_MOLES: f32 = 0.5;
+
+/// How many moles are needed to make sleeping gas visible.
+pub(crate) const SLEEPING_GAS_VISIBILITY_MOLES: f32 = 1.0;
+
+/// How many moles of each gas are needed before a reaction should happen.
+pub(crate) const REACTION_SIGNIFICANCE_MOLES: f32 = 0.5;
+
+/// How much of the tile a reaction's gas needs to occupy to happen.
+pub(crate) const REACTION_SIGNIFICANCE_RATIO: f32 = 0.01;
+
+/// How hot does it need to be for Agent B to work?
+pub(crate) const AGENT_B_CONVERSION_TEMP: f32 = 900.0;
+
+/// How hot does it need to be for sleeping gass to break down?
+pub(crate) const SLEEPING_GAS_BREAKDOWN_TEMP: f32 = 1400.0;
+
+/// Index for oxygen in gas list.
+pub(crate) const GAS_OXYGEN: usize = 0;
+
+/// Index for carbon dioxide in gas list.
+pub(crate) const GAS_CARBON_DIOXIDE: usize = 1;
+
+/// Index for nitrogen in gas list.
+pub(crate) const GAS_NITROGEN: usize = 2;
+
+/// Index for toxins in gas list.
+pub(crate) const GAS_TOXINS: usize = 3;
+
+/// Index for sleeping agent in gas list.
+pub(crate) const GAS_SLEEPING_AGENT: usize = 4;
+
+/// Index for agent b in gas list.
+pub(crate) const GAS_AGENT_B: usize = 5;
+
+/// How many gases are there?
+pub(crate) const GAS_COUNT: usize = GAS_AGENT_B + 1;
+
+/// The two axes, Y and X. The order is arbitrary, but will break the copy from active to inactive
+/// if changed.
+pub(crate) const AXES: [(i32, i32); 2] = [(0, 1), (1, 0)];
+
+/// The four cardinal directions. The order is arbitrary, and doesn't matter.
+pub(crate) const DIRECTIONS: [(i32, i32); 4] = [(0, 1), (1, 0), (0, -1), (-1, 0)];
+
+// The numbers here are completely wrong for actual gases, but they're what LINDA used, so we'll
+// keep them for now.
+
+// The specific heat of oxygen, in joules per kelvin-mole.
+pub(crate) const SPECIFIC_HEAT_OXYGEN: f32 = 20.0;
+
+// The specific heat of carbon dioxide, in joules per kelvin-mole.
+pub(crate) const SPECIFIC_HEAT_CARBON_DIOXIDE: f32 = 30.0;
+
+// The specific heat of nitrogen, in joules per kelvin-mole.
+pub(crate) const SPECIFIC_HEAT_NITROGEN: f32 = 20.0;
+
+// The specific heat of toxins, in joules per kelvin-mole.
+pub(crate) const SPECIFIC_HEAT_TOXINS: f32 = 200.0;
+
+// The specific heat of sleeping agent, in joules per kelvin-mole.
+pub(crate) const SPECIFIC_HEAT_SLEEPING_AGENT: f32 = 40.0;
+
+// The specific heat of agent b, in joules per kelvin-mole.
+pub(crate) const SPECIFIC_HEAT_AGENT_B: f32 = 300.0;
+
+// Convenience array, so we can add loop through gases and calculate heat capacity.
+pub(crate) const SPECIFIC_HEATS: [f32; GAS_COUNT] = [
+ SPECIFIC_HEAT_OXYGEN,
+ SPECIFIC_HEAT_CARBON_DIOXIDE,
+ SPECIFIC_HEAT_NITROGEN,
+ SPECIFIC_HEAT_TOXINS,
+ SPECIFIC_HEAT_SLEEPING_AGENT,
+ SPECIFIC_HEAT_AGENT_B,
+];
+
+/// How hot does it need to be for a plasma fire to start?
+pub(crate) const PLASMA_BURN_MIN_TEMP: f32 = 100.0 + T0C;
+
+/// How hot does it need to be for a plasma fire to work as well as possible?
+pub(crate) const PLASMA_BURN_OPTIMAL_TEMP: f32 = 1370.0 + T0C;
+
+/// How much oxygen needs to be available per unit of plasma.
+pub(crate) const PLASMA_BURN_REQUIRED_OXYGEN_AVAILABILITY: f32 = 10.0;
+
+/// How much of the plasma are we willing to burn each tick?
+pub(crate) const PLASMA_BURN_MAX_RATIO: f32 = 0.25;
+
+/// How much oxygen do we use per plasma at min temp?
+pub(crate) const PLASMA_BURN_WORST_OXYGEN_PER_PLASMA: f32 = 1.4;
+
+/// How much oxygen do we use per plasma at optimal temp?
+pub(crate) const PLASMA_BURN_BEST_OXYGEN_PER_PLASMA: f32 = 0.4;
+
+/// How much thermal energy is produced, in joules per mole of agent b.
+pub(crate) const AGENT_B_CONVERSION_ENERGY: f32 = 20_000.0;
+
+/// How much thermal energy is produced, in joules per mole of sleeping agent.
+pub(crate) const NITROUS_BREAKDOWN_ENERGY: f32 = 200_000.0;
+
+/// How much thermal energy is produced, in joules per mole of sleeping toxins.
+pub(crate) const PLASMA_BURN_ENERGY: f32 = 3_000_000.0;
+
+/// We allow small deviations in tests, so that floating point precision doesn't cause problems.
+#[cfg(test)]
+pub(crate) const TEST_TOLERANCE: f32 = 0.00001;
+
+/// Lose this multiple of heat energy per tick if above T20C.
+pub(crate) const SPACE_COOLING_FACTOR: f32 = 0.005;
+
+/// Tiles with less than this much gas will become empty.
+pub(crate) const MINIMUM_NONZERO_MOLES: f32 = 0.1;
diff --git a/milla/src/conversion.rs b/milla/src/conversion.rs
new file mode 100644
index 00000000000..77e4a02481a
--- /dev/null
+++ b/milla/src/conversion.rs
@@ -0,0 +1,38 @@
+use byondapi::prelude::*;
+use byondapi::Error;
+use eyre::Result;
+
+/// Turns a BYOND number into an Option.
+/// The option will be None if the number was null or NaN.
+pub(crate) fn byond_to_option_f32(value: ByondValue) -> Result