diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ae777746daf..a628563525e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -77,6 +77,18 @@ actual development. /:cl: ``` +## Modifying MILLA + +Our atmos engine, MILLA, is in the `milla/` directory. It's written in Rust for performance reasons, which means it's not compiled the same way as the rest of the code. If you're on Windows, you get a pre-built copy by default. If you're on Linux, you built one already to run the server. + +If you make changes to MILLA, you'll want to rebuild. This will be very similar to RUSTG: +https://github.com/ParadiseSS13/rust-g +The only difference is that you run `cargo` from the `milla/` directory, and don't need to speify `--all-features` (though it doesn't hurt). + +The server will automatically detect that you have a local build, and use that over the default Windows one. + +When you're ready to make a PR, please DO NOT modify `milla.dll` or `tools/ci/libmilla_ci.so`. Leave "Allow edits and access to secrets by maintainers" enabled, and post a comment on your PR saying `!build_milla`. A bot will automatically build them for you and update your branch. + ## Specifications As mentioned before, you are expected to follow these specifications in order to make everyone's lives easier. It'll save both your time and ours, by making diff --git a/.github/DOWNLOADING.md b/.github/DOWNLOADING.md index db973ecb9d1..5787b807775 100644 --- a/.github/DOWNLOADING.md +++ b/.github/DOWNLOADING.md @@ -73,11 +73,13 @@ Then press GO and the server should start up and be ready to join. ## Installation (Linux) -The code is fully able to run on linux, however windows is still the recommended platform. The library we use for external functions (RUSTG) requires some extra dependencies. +The code is fully able to run on linux, however windows is still the recommended platform. The libraries we use for external functions (RUSTG and MILLA) require some extra dependencies. For debian, please download the latest RUSTG release from [https://github.com/ParadiseSS13/rust-g](https://github.com/ParadiseSS13/rust-g), run the following: `apt-get install libssl-dev:i386 pkg-config:i386 zlib1g-dev:i386`. -After installing these packages, RUSTG should function as intended. We assume that if you are hosting on linux, you know what you are doing. +After installing these packages, RUSTG should be able to build and function as intended. Build instructions are on the RUSTG page. We assume that if you are hosting on linux, you know what you are doing. + +Once you've built RUSTG, you can build MILLA similarly, just go into the `milla/` directory and run `cargo build --release --target=i686-unknown-linux-gnu`. ## UPDATING diff --git a/.gitignore b/.gitignore index 37f03500538..6f6c2dd9c36 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,6 @@ $RECYCLE.BIN # VIM swap files. *.swp + +# Rust output. +/milla/target/* diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm index d360977a55c..db896ab95c5 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_clown_planet.dmm @@ -18,13 +18,13 @@ /obj/structure/disposalpipe/segment/corner{ dir = 4 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "ae" = ( /obj/structure/disposalpipe/segment/corner{ dir = 2 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "af" = ( /obj/structure/disposalpipe/segment{ @@ -40,7 +40,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "ag" = ( /obj/effect/mob_spawn/human/corpse/damaged, @@ -58,7 +58,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "ah" = ( /obj/effect/turf_decal/tile/yellow, @@ -74,7 +74,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aj" = ( /obj/effect/decal/cleanable/pie_smudge, @@ -91,7 +91,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "ak" = ( /obj/structure/disposalpipe/segment{ @@ -110,7 +110,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "al" = ( /obj/effect/decal/cleanable/dirt, @@ -127,7 +127,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 1 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "am" = ( /obj/structure/disposalpipe/segment{ @@ -145,7 +145,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "an" = ( /obj/structure/disposalpipe/segment{ @@ -162,14 +162,14 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "ao" = ( /obj/structure/window/reinforced, /obj/structure/disposalpipe/segment/corner{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "ap" = ( /obj/effect/turf_decal/tile/yellow, @@ -185,14 +185,14 @@ /obj/structure/disposalpipe/segment/corner{ dir = 8 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aq" = ( /obj/structure/disposalpipe/trunk, /obj/structure/disposaloutlet{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "ar" = ( /obj/effect/turf_decal/tile/yellow, @@ -205,7 +205,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "as" = ( /obj/effect/decal/cleanable/dirt, @@ -219,7 +219,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "at" = ( /obj/structure/disposalpipe/segment{ @@ -237,13 +237,13 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "au" = ( /obj/structure/disposalpipe/segment{ invisibility = 101 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "aw" = ( /obj/machinery/light/small{ @@ -262,7 +262,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "ay" = ( /obj/effect/decal/cleanable/dirt, @@ -279,7 +279,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 8 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "az" = ( /obj/item/bikehorn, @@ -296,7 +296,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 1 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aB" = ( /obj/structure/disposalpipe/segment{ @@ -317,7 +317,7 @@ /obj/structure/disposalpipe/segment{ invisibility = 101 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aC" = ( /obj/effect/turf_decal/tile/yellow, @@ -333,7 +333,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 2 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aD" = ( /obj/item/bikehorn, @@ -351,13 +351,13 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aE" = ( /obj/structure/disposalpipe/segment/corner{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "aF" = ( /obj/effect/decal/cleanable/dirt, @@ -374,7 +374,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aG" = ( /obj/machinery/light/small{ @@ -393,7 +393,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 2 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aH" = ( /obj/effect/decal/cleanable/dirt, @@ -413,7 +413,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 2 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aI" = ( /obj/item/bikehorn, @@ -431,7 +431,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aJ" = ( /obj/item/bikehorn, @@ -448,7 +448,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aK" = ( /obj/structure/disposalpipe/segment{ @@ -465,7 +465,7 @@ /obj/effect/turf_decal/tile/red{ dir = 1 }, -/turf/simulated/floor/plasteel, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "aL" = ( /obj/structure/disposalpipe/segment{ @@ -486,17 +486,14 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aN" = ( /obj/structure/disposalpipe/segment{ dir = 4; invisibility = 101 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "aO" = ( /obj/effect/decal/cleanable/dirt, @@ -513,7 +510,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aP" = ( /obj/structure/disposalpipe/segment{ @@ -523,7 +520,7 @@ /obj/structure/disposalpipe/segment{ invisibility = 101 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "aQ" = ( /obj/structure/disposalpipe/segment{ @@ -536,10 +533,7 @@ /obj/structure/disposalpipe/segment{ invisibility = 101 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "aR" = ( /obj/structure/disposalpipe/segment{ @@ -551,10 +545,7 @@ /obj/structure/disposalpipe/segment{ invisibility = 101 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "aS" = ( /obj/effect/decal/cleanable/pie_smudge, @@ -571,7 +562,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 2 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "aT" = ( /obj/structure/disposalpipe/segment{ @@ -579,32 +570,23 @@ invisibility = 101 }, /obj/item/pickaxe, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "aU" = ( /obj/effect/spawner/window/reinforced, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "aV" = ( /obj/structure/disposalpipe/segment/corner{ dir = 4 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "aW" = ( /obj/structure/disposalpipe/segment/corner{ dir = 2 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "aX" = ( /obj/structure/disposalpipe/trunk{ @@ -613,7 +595,7 @@ /obj/structure/disposaloutlet{ dir = 8 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "aY" = ( /obj/structure/disposalpipe/segment{ @@ -623,17 +605,14 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "aZ" = ( /obj/structure/disposalpipe/segment{ dir = 4; invisibility = 101 }, -/turf/simulated/floor/light, +/turf/simulated/floor/light/lavaland_air, /area/ruin/powered/clownplanet) "ba" = ( /obj/structure/disposalpipe/segment{ @@ -643,10 +622,7 @@ /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bb" = ( /obj/structure/disposalpipe/segment{ @@ -659,22 +635,16 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bc" = ( -/turf/simulated/floor/light, +/turf/simulated/floor/light/lavaland_air, /area/ruin/powered/clownplanet) "bd" = ( /obj/structure/disposalpipe/segment/corner{ dir = 1 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "be" = ( /obj/machinery/light/small{ @@ -683,26 +653,17 @@ /obj/structure/disposalpipe/segment/corner{ dir = 8 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bf" = ( /turf/simulated/mineral/clown/volcanic, /area/ruin/powered/clownplanet) "bg" = ( /obj/item/pickaxe, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bh" = ( -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bi" = ( /obj/effect/turf_decal/tile/red, @@ -718,7 +679,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 4 }, -/turf/simulated/floor/plasteel, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bj" = ( /obj/effect/decal/cleanable/dirt, @@ -735,13 +696,13 @@ /obj/structure/disposalpipe/segment/corner{ dir = 2 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "bk" = ( /obj/structure/disposalpipe/segment/corner{ dir = 1 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "bl" = ( /obj/item/bikehorn, @@ -758,16 +719,13 @@ /obj/structure/disposalpipe/segment/corner{ dir = 2 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "bm" = ( /obj/structure/disposalpipe/segment/corner{ dir = 8 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bn" = ( /obj/effect/decal/cleanable/cobweb, @@ -781,7 +739,7 @@ /obj/effect/turf_decal/tile/red{ dir = 1 }, -/turf/simulated/floor/plasteel, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bo" = ( /obj/effect/turf_decal/tile/yellow, @@ -797,7 +755,7 @@ /obj/structure/disposalpipe/junction{ dir = 1 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "bp" = ( /obj/effect/decal/cleanable/pie_smudge, @@ -812,17 +770,14 @@ }, /obj/effect/turf_decal/tile/yellow, /obj/structure/disposalpipe/junction/y, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "bq" = ( /obj/machinery/disposal/deliveryChute{ dir = 1 }, /obj/structure/disposalpipe/trunk, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "br" = ( /obj/effect/turf_decal/tile/red, @@ -835,7 +790,7 @@ /obj/effect/turf_decal/tile/red{ dir = 1 }, -/turf/simulated/floor/plasteel, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bs" = ( /obj/machinery/light{ @@ -851,14 +806,14 @@ /obj/effect/turf_decal/tile/red{ dir = 1 }, -/turf/simulated/floor/plasteel, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bu" = ( /obj/effect/decal/cleanable/blood/oil, /obj/structure/disposalpipe/segment/corner{ dir = 2 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "bv" = ( /obj/effect/mob_spawn/human/corpse/damaged, @@ -873,7 +828,7 @@ /obj/effect/turf_decal/tile/yellow{ dir = 4 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "bw" = ( /obj/effect/turf_decal/tile/red, @@ -889,7 +844,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 8 }, -/turf/simulated/floor/plasteel, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "bx" = ( /obj/effect/decal/cleanable/dirt, @@ -904,15 +859,15 @@ dir = 4 }, /obj/effect/baseturf_helper/lava/mapping_lava, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "by" = ( /obj/structure/table/glass, /obj/item/gun/magic/wand/slipping, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "bB" = ( -/turf/simulated/floor/mineral/bananium/lubed, +/turf/simulated/floor/mineral/bananium/lubed/lavaland_air, /area/ruin/powered/clownplanet) "bD" = ( /obj/structure/mecha_wreckage/honker, @@ -920,44 +875,44 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "bH" = ( /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/mineral/bananium/lubed, +/turf/simulated/floor/mineral/bananium/lubed/lavaland_air, /area/ruin/powered/clownplanet) "bL" = ( /obj/item/reagent_containers/drinks/trophy/gold_cup, /obj/structure/table/glass, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "bM" = ( -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "bN" = ( /obj/machinery/disposal/deliveryChute, /obj/structure/disposalpipe/trunk{ dir = 1 }, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "bO" = ( /obj/effect/decal/cleanable/cobweb, -/turf/simulated/floor/mineral/bananium/lubed, +/turf/simulated/floor/mineral/bananium/lubed/lavaland_air, /area/ruin/powered/clownplanet) "bP" = ( /obj/structure/statue/bananium/clown, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "bQ" = ( /obj/structure/table/glass, /obj/item/grown/bananapeel/bluespace, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "bR" = ( /obj/structure/table/glass, /obj/item/clothing/shoes/magboots/clown, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "bS" = ( /obj/item/coin/clown, @@ -967,34 +922,34 @@ /obj/machinery/light/small{ dir = 8 }, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "bT" = ( /obj/item/slime_extract/rainbow, /obj/structure/table/glass, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "bU" = ( /obj/item/bikehorn/airhorn, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "bW" = ( /obj/item/bikehorn, -/turf/simulated/floor/mineral/bananium/lubed, +/turf/simulated/floor/mineral/bananium/lubed/lavaland_air, /area/ruin/powered/clownplanet) "bY" = ( /obj/effect/mob_spawn/human/corpse/damaged, /obj/effect/decal/cleanable/blood/old, -/turf/simulated/floor/mineral/bananium/lubed, +/turf/simulated/floor/mineral/bananium/lubed/lavaland_air, /area/ruin/powered/clownplanet) "bZ" = ( /obj/machinery/door/airlock/bananium, -/turf/simulated/floor/mineral/bananium/lubed, +/turf/simulated/floor/mineral/bananium/lubed/lavaland_air, /area/ruin/powered/clownplanet) "ca" = ( /obj/item/bikehorn, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/mineral/bananium/lubed, +/turf/simulated/floor/mineral/bananium/lubed/lavaland_air, /area/ruin/powered/clownplanet) "cc" = ( /turf/simulated/wall/r_wall, @@ -1006,13 +961,13 @@ /turf/simulated/wall/r_wall, /area/ruin/powered/clownplanet) "cu" = ( -/turf/simulated/floor/plating, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/powered/clownplanet) "dK" = ( /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "dL" = ( /obj/item/coin/clown, @@ -1022,17 +977,17 @@ /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/carpet, +/turf/simulated/floor/carpet/lavaland_air, /area/ruin/powered/clownplanet) "dM" = ( /obj/machinery/light{ dir = 1 }, -/turf/simulated/floor/mineral/bananium/lubed, +/turf/simulated/floor/mineral/bananium/lubed/lavaland_air, /area/ruin/powered/clownplanet) "dO" = ( /obj/machinery/light, -/turf/simulated/floor/mineral/bananium/lubed, +/turf/simulated/floor/mineral/bananium/lubed/lavaland_air, /area/ruin/powered/clownplanet) "eX" = ( /obj/effect/mapping_helpers/no_lava, @@ -1073,7 +1028,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 1 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "qS" = ( /obj/structure/disposalpipe/segment{ @@ -1094,16 +1049,16 @@ /obj/structure/disposalpipe/segment{ invisibility = 101 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "sL" = ( /obj/structure/disposalpipe/segment/corner{ dir = 4 }, -/turf/simulated/floor/light, +/turf/simulated/floor/light/lavaland_air, /area/ruin/powered/clownplanet) "ye" = ( -/turf/simulated/floor/lava, +/turf/simulated/floor/lava/lava_land_surface, /area/ruin/powered/clownplanet) "CB" = ( /obj/item/paper/crumpled/bloody/ruins/lavaland/clown_planet/hope, @@ -1121,7 +1076,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 8 }, -/turf/simulated/floor/light, +/turf/simulated/floor/light/lavaland_air, /area/ruin/powered/clownplanet) "HQ" = ( /obj/structure/disposalpipe/segment{ @@ -1145,7 +1100,7 @@ /obj/structure/disposalpipe/segment{ invisibility = 101 }, -/turf/simulated/floor/light, +/turf/simulated/floor/light/lavaland_air, /area/ruin/powered/clownplanet) "LH" = ( /obj/machinery/disposal/deliveryChute{ @@ -1177,10 +1132,7 @@ /obj/structure/disposalpipe/segment{ invisibility = 101 }, -/turf/simulated/floor/plasteel{ - dir = 4; - icon_state = "white" - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/powered/clownplanet) "TD" = ( /obj/structure/disposalpipe/trunk, @@ -1214,7 +1166,7 @@ /obj/structure/disposalpipe/segment{ invisibility = 101 }, -/turf/simulated/floor/lubed, +/turf/simulated/floor/lubed/lavaland_air, /area/ruin/powered/clownplanet) "Xm" = ( /obj/item/clothing/head/cone, diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_winter.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_winter.dmm index 473e7b3672e..f4083f3b563 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_winter.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_biodome_winter.dmm @@ -290,11 +290,7 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/dark{ - oxygen = 8; - nitrogen = 14; - temperature = 500 - }, +/turf/simulated/floor/pod/dark/lavaland_air, /area/ruin/powered/snow_biodome) "jE" = ( /obj/effect/decal/cleanable/blood/drip, diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_althland_excavation.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_althland_excavation.dmm index 1e3b9a3be13..03a9616e965 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_althland_excavation.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_althland_excavation.dmm @@ -7,10 +7,10 @@ "ac" = ( /obj/effect/decal/cleanable/glass, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "ad" = ( -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -22,7 +22,7 @@ /obj/effect/landmark/damageturf, /obj/effect/turf_decal/stripes/corner, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -42,7 +42,7 @@ /obj/structure/railing, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "ah" = ( /obj/effect/decal/cleanable/dirt, @@ -50,7 +50,7 @@ /obj/item/clothing/head/bomb_hood, /obj/item/clothing/suit/bomb_suit, /obj/effect/turf_decal/delivery/white/hollow, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -64,7 +64,7 @@ dir = 6 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "aj" = ( /obj/structure/railing{ @@ -75,7 +75,7 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -84,30 +84,30 @@ /obj/structure/marker_beacon/dock_marker/collision, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "am" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "an" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/bed/pod, /obj/item/bedsheet, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "ao" = ( /obj/structure/table, /obj/structure/bedsheetbin, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "ap" = ( /obj/structure/bed/pod, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -116,25 +116,25 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/closet/secure_closet/freezer/fridge/open, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "ar" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/table_frame, /obj/item/clothing/suit/hooded/explorer, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "as" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "at" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/washing_machine, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -142,7 +142,7 @@ "au" = ( /obj/structure/bed/pod, /obj/item/bedsheet, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -158,7 +158,7 @@ }, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "ax" = ( /obj/effect/decal/cleanable/dirt, @@ -169,14 +169,14 @@ desc = "A weathered payload core, its once vital center now shattered, rendering it indistinguishable from a mere stone." }, /obj/effect/turf_decal/delivery/white/hollow, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "ay" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/table_frame, /obj/item/clothing/mask/gas/explorer, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -185,7 +185,7 @@ /obj/effect/decal/cleanable/dirt, /obj/structure/table, /obj/item/clothing/mask/gas/explorer, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -212,13 +212,13 @@ "aE" = ( /obj/structure/mecha_wreckage/ripley/firefighter, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "aG" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/bed/pod, /obj/item/bedsheet, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -227,7 +227,7 @@ /obj/item/chair{ dir = 1 }, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "aJ" = ( /obj/structure/railing{ @@ -250,19 +250,19 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "aN" = ( /obj/structure/railing, /obj/effect/landmark/damageturf, /obj/effect/turf_decal/stripes/line, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "aQ" = ( /obj/structure/grille, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "aR" = ( /obj/structure/railing, @@ -270,38 +270,38 @@ /obj/effect/landmark/damageturf, /obj/effect/turf_decal/stripes/line, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, /area/lavaland/surface/outdoors) "aU" = ( /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "aV" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/item/deck/cards/black, /obj/structure/table_frame, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "aX" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/remains/human, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "aZ" = ( /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "bi" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/portable/canister/air, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -311,12 +311,12 @@ /obj/item/stack/ore/plasma, /obj/item/stack/ore/plasma, /obj/effect/turf_decal/delivery/white/hollow, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "bk" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/largecrate, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -324,7 +324,7 @@ "bl" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -338,7 +338,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -348,7 +348,7 @@ /obj/effect/decal/cleanable/glass, /obj/item/chair, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "bq" = ( /obj/structure/railing{ @@ -357,7 +357,7 @@ /obj/structure/marker_beacon/dock_marker/collision, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "br" = ( /obj/structure/lattice, @@ -374,18 +374,18 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "bz" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/closet/crate/miningcar, /obj/item/gibtonite, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "bA" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/portable/pump, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -393,7 +393,7 @@ "bB" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery/white, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -404,7 +404,7 @@ /obj/machinery/atmospherics/unary/tank/oxygen_agent_b{ dir = 8 }, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -414,7 +414,7 @@ /obj/structure/chair/office{ dir = 4 }, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "bF" = ( /obj/structure/railing{ @@ -425,7 +425,7 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "bG" = ( /obj/structure/railing{ @@ -435,13 +435,13 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "bH" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/bed/pod, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -450,13 +450,13 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/glass, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "bK" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/remains/human, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -464,7 +464,7 @@ "bL" = ( /obj/effect/decal/cleanable/dirt, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -472,7 +472,7 @@ "bM" = ( /obj/effect/decal/cleanable/dirt, /obj/item/shard, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -482,19 +482,19 @@ /obj/effect/decal/cleanable/dirt, /obj/structure/girder/reinforced, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "bO" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/item/chair, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "bP" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery/white/hollow, /obj/item/stack/sheet/wood, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "bQ" = ( /obj/structure/railing{ @@ -502,11 +502,11 @@ }, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "bR" = ( /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "bS" = ( /obj/structure/railing/corner, @@ -514,7 +514,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/corner, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -527,11 +527,11 @@ dir = 4 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "bU" = ( /obj/effect/decal/remains/human, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -548,7 +548,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 8 }, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -563,16 +563,16 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "cs" = ( /obj/machinery/door/airlock/maintenance_hatch, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "ct" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/remains/human, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -582,21 +582,21 @@ /obj/effect/decal/cleanable/dirt, /obj/structure/closet/crate/miningcar, /obj/item/stack/ore/plasma, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "dp" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/table, /obj/machinery/kitchen_machine/microwave, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "ej" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/remains/human, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "eC" = ( /obj/structure/railing/corner{ @@ -610,14 +610,14 @@ /area/lavaland/surface/outdoors) "eX" = ( /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "fc" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -628,24 +628,24 @@ /obj/effect/decal/remains/human, /obj/machinery/atmospherics/portable/scrubber, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "gg" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/girder/reinforced, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "gh" = ( /obj/effect/decal/cleanable/dirt, /obj/item/stack/sheet/metal, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "gF" = ( /obj/effect/landmark/damageturf, /obj/item/stack/sheet/metal, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "hn" = ( /obj/structure/railing, @@ -658,7 +658,7 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -666,7 +666,7 @@ "ie" = ( /obj/structure/table, /obj/item/food/snacks/badrecipe, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "iv" = ( /obj/structure/grille/broken, @@ -674,12 +674,12 @@ /obj/effect/decal/cleanable/glass, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "iA" = ( /obj/effect/decal/remains/human, /obj/item/clothing/suit/hooded/explorer, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -689,16 +689,16 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/chair/office, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "je" = ( /obj/structure/girder/reinforced, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "jj" = ( /obj/effect/decal/cleanable/dirt, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "js" = ( /obj/structure/railing{ @@ -712,7 +712,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/item/stack/sheet/metal, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -721,7 +721,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/item/stack/sheet/metal, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "jT" = ( /obj/effect/decal/cleanable/dirt, @@ -734,7 +734,7 @@ /obj/effect/decal/cleanable/dirt, /obj/structure/mecha_wreckage/ripley, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -744,7 +744,7 @@ /obj/effect/decal/cleanable/dirt, /obj/item/stack/sheet/wood, /obj/effect/turf_decal/delivery/white/hollow, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "lF" = ( /obj/structure/railing/corner, @@ -756,13 +756,13 @@ }, /obj/effect/decal/cleanable/dirt, /obj/structure/door_assembly/door_assembly_ext, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "lM" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/closet/crate/trashcart, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -771,19 +771,19 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "mK" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, /area/lavaland/surface/outdoors) "mW" = ( /obj/structure/door_assembly/door_assembly_mhatch, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "nw" = ( /obj/effect/decal/cleanable/dirt, @@ -795,7 +795,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/glass, /obj/effect/turf_decal/delivery/white, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "oh" = ( /turf/simulated/mineral/volcanic/lava_land_surface, @@ -813,7 +813,7 @@ pixel_y = 32 }, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "pE" = ( /obj/machinery/atmospherics/pipe/simple/hidden{ @@ -821,19 +821,19 @@ }, /obj/effect/decal/cleanable/dirt, /obj/machinery/power/apc/off_station/empty_charge/directional/north, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "pI" = ( /obj/item/stack/sheet/metal, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "qa" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/closet/crate/miningcar, /obj/effect/turf_decal/delivery/white/hollow, /obj/item/gibtonite, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -841,7 +841,7 @@ "qp" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/chair/office, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "qw" = ( /obj/effect/decal/cleanable/dirt, @@ -850,7 +850,7 @@ name = "degraded payload"; desc = "A weathered payload core, its once vital center now shattered, rendering it indistinguishable from a mere stone." }, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -863,7 +863,7 @@ desc = "A melted floodlight, despite being completely welded into the floor, it still somehow works."; name = "melted floodlight" }, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -883,13 +883,13 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "tj" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/grille/broken, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "tV" = ( /obj/effect/decal/remains/human, @@ -902,31 +902,31 @@ /obj/effect/landmark/damageturf, /obj/effect/turf_decal/stripes/line, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "ui" = ( /obj/item/storage/toolbox/syndicate, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "uA" = ( /obj/structure/grille, /obj/item/shard, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "uG" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "uP" = ( /obj/item/chair{ dir = 1 }, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -934,7 +934,7 @@ "vM" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/remains/human, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "wb" = ( /obj/structure/railing{ @@ -945,14 +945,14 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "wi" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/item/reagent_containers/drinks/oilcan, /obj/machinery/constructable_frame, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -967,7 +967,7 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -976,7 +976,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -985,7 +985,7 @@ /obj/effect/decal/cleanable/dirt, /obj/item/stack/sheet/metal, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -994,12 +994,12 @@ /obj/effect/decal/remains/human, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "yb" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "yc" = ( /obj/effect/decal/cleanable/dirt, @@ -1007,13 +1007,13 @@ /obj/structure/railing, /obj/effect/turf_decal/stripes/line, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "yn" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1023,7 +1023,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "zh" = ( /obj/effect/decal/cleanable/dirt, @@ -1031,7 +1031,7 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "zp" = ( /obj/structure/railing/corner, @@ -1043,7 +1043,7 @@ /obj/machinery/atmospherics/unary/tank/oxygen_agent_b{ dir = 8 }, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1053,7 +1053,7 @@ /obj/effect/decal/cleanable/dirt, /obj/item/stack/sheet/metal, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "AU" = ( /obj/structure/railing{ @@ -1066,12 +1066,12 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Bl" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/portable/canister/air, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "BW" = ( /obj/structure/lattice/lava, @@ -1083,7 +1083,7 @@ dir = 8 }, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "Cs" = ( /obj/effect/decal/cleanable/dirt, @@ -1093,7 +1093,7 @@ pixel_y = 14; pixel_x = 14 }, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1107,7 +1107,7 @@ /obj/structure/railing, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Du" = ( /obj/structure/door_assembly/door_assembly_mhatch, @@ -1117,14 +1117,14 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "Ec" = ( /obj/effect/decal/cleanable/dirt, /obj/item/chair{ dir = 1 }, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "Ei" = ( /obj/effect/mapping_helpers/no_lava, @@ -1141,19 +1141,19 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/structure/door_assembly/door_assembly_ext, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "EG" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, /area/ruin/unpowered/althland_excavation) "EL" = ( -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "Fe" = ( /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, @@ -1161,13 +1161,13 @@ "Fs" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/door_assembly/door_assembly_ext, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "FQ" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1176,13 +1176,13 @@ /obj/structure/marker_beacon/dock_marker, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Gp" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery/white/hollow, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1197,13 +1197,13 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "HC" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/chair/office, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "In" = ( /obj/structure/railing, @@ -1212,11 +1212,11 @@ /obj/effect/decal/remains/human, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "IZ" = ( /obj/effect/decal/cleanable/glass, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1224,7 +1224,7 @@ "Jp" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/manifold/hidden, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "JF" = ( /obj/structure/railing/corner, @@ -1234,18 +1234,18 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "JG" = ( /obj/structure/girder/reinforced, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "KU" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/remains/human, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1253,7 +1253,7 @@ "Lt" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/door/airlock/maintenance_hatch, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1262,14 +1262,14 @@ /obj/effect/decal/cleanable/glass, /obj/effect/decal/cleanable/dirt, /obj/structure/table_frame, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "LK" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/item/stack/sheet/metal, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1283,13 +1283,13 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Nv" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1309,12 +1309,12 @@ dir = 9 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "OX" = ( /obj/structure/table_frame, /obj/item/food/snacks/badrecipe, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "Pe" = ( /obj/effect/decal/cleanable/dirt, @@ -1322,7 +1322,7 @@ dir = 4 }, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "PC" = ( /obj/structure/railing{ @@ -1333,11 +1333,11 @@ dir = 8 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "PL" = ( /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1345,14 +1345,14 @@ "PM" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Qk" = ( /obj/effect/decal/cleanable/glass, /obj/structure/chair/office{ dir = 1 }, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "QM" = ( /obj/structure/railing{ @@ -1361,18 +1361,18 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "QS" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/item/stack/sheet/metal, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "Rf" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/baseturf_helper/lava/mapping_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1383,7 +1383,7 @@ /obj/machinery/atmospherics/unary/portables_connector{ dir = 4 }, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1394,21 +1394,21 @@ /obj/effect/decal/remains/human, /obj/structure/grille/broken, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "RW" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "SV" = ( /obj/structure/girder/reinforced, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "TD" = ( /obj/structure/girder/reinforced, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "TJ" = ( /obj/effect/decal/cleanable/dirt, @@ -1416,7 +1416,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "TN" = ( /obj/effect/spawner/random_spawners/wall_rusted_maybe, @@ -1428,7 +1428,7 @@ }, /obj/effect/landmark/damageturf, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "TW" = ( /obj/structure/railing/corner{ @@ -1440,7 +1440,7 @@ dir = 4 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "UR" = ( /obj/structure/railing{ @@ -1450,14 +1450,14 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "US" = ( /obj/structure/grille/broken, /obj/item/shard, /obj/effect/decal/cleanable/glass, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1465,7 +1465,7 @@ "Vg" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/door_assembly/door_assembly_mhatch, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "Vk" = ( /obj/effect/decal/cleanable/dirt, @@ -1476,7 +1476,7 @@ dir = 1 }, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Vw" = ( /obj/structure/grille/broken, @@ -1484,18 +1484,18 @@ /obj/effect/decal/cleanable/glass, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "VO" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Wt" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/grille, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "WH" = ( /obj/machinery/door/poddoor/multi_tile/three_tile_hor, @@ -1504,7 +1504,7 @@ "Xl" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1514,7 +1514,7 @@ pixel_y = 28 }, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_excavation) "XS" = ( /obj/effect/spawner/random_spawners/wall_rusted_maybe, @@ -1525,7 +1525,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/stripes/line, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1535,7 +1535,7 @@ /obj/structure/urinal{ pixel_y = 32 }, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1544,7 +1544,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/mecha_wreckage/ripley, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1554,7 +1554,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/mapping_helpers/no_lava, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, @@ -1563,7 +1563,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/door_assembly/door_assembly_ext, -/turf/simulated/floor/pod/light{ +/turf/simulated/floor/pod/light/lavaland_air{ oxygen = 0; nitrogen = 0 }, diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_althland_facility.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_althland_facility.dmm index 7aa7ddc15bc..32276f9dd3d 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_althland_facility.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_althland_facility.dmm @@ -1,11 +1,7 @@ //MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE "aa" = ( /obj/effect/landmark/burnturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "ab" = ( /obj/effect/mapping_helpers/no_lava, @@ -18,11 +14,7 @@ pixel_x = 5; pixel_y = 3 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "af" = ( /obj/structure/lattice/lava, @@ -38,11 +30,7 @@ "au" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/computer/nonfunctional, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "aJ" = ( /obj/effect/decal/cleanable/dirt, @@ -54,11 +42,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 1 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "aM" = ( /obj/effect/decal/cleanable/dirt, @@ -68,22 +52,14 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "bc" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/mecha_wreckage/ripley, /obj/effect/turf_decal/box/white, /obj/effect/turf_decal/caution/stand_clear/white, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "be" = ( /obj/effect/spawner/random_spawners/wall_rusted_always, @@ -97,22 +73,14 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/item/clothing/under/rank/cargo/miner, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "bP" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/door_assembly/door_assembly_ext{ name = "Broken External Airlock" }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "bT" = ( /turf/simulated/floor/lava/mapping_lava, @@ -133,31 +101,19 @@ "cc" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "cw" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/machinery/power/smes, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "cJ" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/mech_bay_recharge_port, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "dh" = ( /obj/effect/mapping_helpers/no_lava, @@ -173,43 +129,26 @@ }, /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) -"dM" = ( -/obj/effect/decal/cleanable/dirt, -/obj/structure/girder, -/turf/simulated/floor/plating/airless, -/area/ruin/unpowered/althland_processing) "eH" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/item/stack/ore/plasma, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "eV" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/machinery/computer/nonfunctional, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "fc" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "fd" = ( /obj/effect/decal/cleanable/dirt, @@ -218,11 +157,7 @@ /obj/structure/disposalpipe/trunk{ dir = 1 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "fm" = ( /obj/machinery/light_construct/small{ @@ -235,31 +170,19 @@ }, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "fs" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/closet/crate/secure/loot, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "fv" = ( /mob/living/simple_animal/hostile/asteroid/hivelord/legion, /obj/structure/disposalpipe/segment, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "fB" = ( /obj/effect/mapping_helpers/no_lava, @@ -274,11 +197,7 @@ /obj/machinery/atmospherics/unary/portables_connector{ dir = 4 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "fP" = ( /obj/effect/mapping_helpers/no_lava, @@ -290,11 +209,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "gb" = ( /obj/effect/landmark/damageturf, @@ -302,11 +217,7 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "gw" = ( /obj/effect/decal/cleanable/dirt, @@ -314,11 +225,7 @@ /obj/structure/disposalpipe/segment/corner{ dir = 8 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "gE" = ( /obj/effect/decal/cleanable/dirt, @@ -326,16 +233,12 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "gF" = ( /obj/structure/girder, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "hc" = ( /obj/structure/disposalpipe/segment, @@ -344,31 +247,19 @@ /area/ruin/unpowered/althland_processing) "hj" = ( /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "ho" = ( /obj/structure/door_assembly/door_assembly_ext{ name = "Broken External Airlock" }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "hx" = ( /obj/item/shard, /obj/structure/grille/broken, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "hE" = ( /obj/effect/decal/cleanable/dirt, @@ -377,11 +268,7 @@ dir = 8 }, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "hI" = ( /obj/effect/spawner/random_spawners/wall_rusted_maybe, @@ -392,11 +279,7 @@ /obj/effect/decal/cleanable/dirt, /obj/structure/window/reinforced, /obj/machinery/conveyor/west, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "hY" = ( /obj/effect/decal/cleanable/dirt, @@ -404,11 +287,7 @@ /obj/effect/decal/cleanable/dirt, /obj/structure/disposalpipe/segment, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "ia" = ( /obj/effect/mapping_helpers/no_lava, @@ -422,11 +301,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/machinery/door/airlock/maintenance_hatch, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "iq" = ( /obj/effect/decal/cleanable/dirt, @@ -434,11 +309,7 @@ /obj/structure/window/reinforced, /obj/machinery/conveyor/west, /obj/machinery/mineral/unloading_machine, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "jb" = ( /obj/structure/lattice/catwalk/mining, @@ -459,11 +330,7 @@ dir = 8 }, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "kn" = ( /obj/effect/decal/cleanable/dirt, @@ -474,11 +341,7 @@ }, /obj/item/clothing/under/rank/cargo/miner, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "kR" = ( /obj/effect/decal/cleanable/dirt, @@ -488,21 +351,13 @@ /obj/item/tank/internals/oxygen, /obj/item/storage/box/donkpockets/empty, /obj/item/storage/box/donkpockets/empty, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "lr" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "lZ" = ( /obj/effect/decal/cleanable/dirt, @@ -513,36 +368,24 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "mv" = ( /obj/structure/disposalpipe/segment/corner{ dir = 1 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "nm" = ( /obj/structure/disposalpipe/broken{ dir = 2 }, -/turf/simulated/floor/plasteel/airless, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "no" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "nK" = ( /obj/effect/decal/cleanable/dirt, @@ -550,11 +393,7 @@ /obj/structure/grille/broken, /obj/item/shard, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "nN" = ( /obj/structure/grille/broken, @@ -562,21 +401,13 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "nQ" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery/white/hollow, /obj/structure/ore_box, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "nX" = ( /obj/effect/decal/cleanable/dirt, @@ -585,19 +416,11 @@ /turf/simulated/wall/r_wall, /area/ruin/unpowered/althland_processing) "oj" = ( -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "oG" = ( /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "pn" = ( /obj/effect/decal/cleanable/dirt, @@ -608,11 +431,7 @@ }, /obj/item/clothing/under/rank/cargo/miner, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "pP" = ( /obj/effect/decal/cleanable/dirt, @@ -620,11 +439,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "qh" = ( /obj/effect/mapping_helpers/no_lava, @@ -642,11 +457,7 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "qQ" = ( /obj/effect/mapping_helpers/no_lava, @@ -661,21 +472,13 @@ }, /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "rf" = ( /obj/structure/door_assembly/door_assembly_ext{ name = "Broken External Airlock" }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "rw" = ( /obj/effect/decal/cleanable/dirt, @@ -684,21 +487,13 @@ /obj/effect/landmark/burnturf, /obj/effect/landmark/damageturf, /obj/structure/disposalpipe/segment, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "rY" = ( /obj/effect/decal/remains/human, /obj/item/clothing/under/rank/cargo/miner, /obj/item/paper/fluff/ruins/althland/journal, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "sa" = ( /obj/effect/decal/cleanable/dirt, @@ -706,19 +501,11 @@ /obj/machinery/conveyor/west, /obj/structure/window/reinforced, /obj/item/stack/sheet/mineral/silver, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "sg" = ( /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "su" = ( /obj/effect/decal/cleanable/dirt, @@ -728,11 +515,7 @@ amount = 5 }, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "sv" = ( /obj/effect/decal/cleanable/dirt, @@ -748,21 +531,13 @@ "sQ" = ( /obj/item/pickaxe, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "to" = ( /obj/structure/marker_beacon/dock_marker, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "tv" = ( /obj/effect/decal/cleanable/dirt, @@ -770,32 +545,20 @@ /obj/effect/decal/cleanable/dirt, /obj/machinery/constructable_frame/machine_frame, /obj/item/stack/cable_coil, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "tD" = ( /obj/effect/turf_decal/delivery/white/hollow, /obj/machinery/light_construct/small, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "tH" = ( /obj/structure/disposalpipe/segment/corner{ dir = 8 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "tS" = ( /obj/effect/mapping_helpers/no_lava, @@ -811,30 +574,18 @@ "ua" = ( /obj/effect/turf_decal/caution/stand_clear/white, /obj/effect/turf_decal/box/white, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "ub" = ( /obj/item/clothing/under/rank/cargo/miner, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "uf" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "ui" = ( /obj/effect/spawner/random_spawners/wall_rusted_maybe, @@ -848,11 +599,7 @@ /obj/effect/decal/cleanable/dirt, /obj/machinery/disposal, /obj/structure/disposalpipe/trunk, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "uM" = ( /obj/effect/decal/cleanable/dirt, @@ -860,11 +607,7 @@ /obj/effect/decal/cleanable/dirt, /obj/item/rack_parts, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "vf" = ( /obj/effect/decal/cleanable/dirt, @@ -875,22 +618,14 @@ /obj/machinery/atmospherics/portable/canister/air, /obj/effect/landmark/burnturf, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "vl" = ( /obj/structure/table, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/item/storage/belt/mining/alt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "vo" = ( /obj/machinery/light_construct/small{ @@ -900,32 +635,20 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/remains/human, /obj/item/clothing/under/rank/cargo/miner, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "vM" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "wZ" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "xK" = ( /obj/effect/decal/cleanable/dirt, @@ -933,11 +656,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/machinery/economy/vending/chinese, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "zd" = ( /obj/effect/decal/cleanable/dirt, @@ -947,11 +666,7 @@ /obj/machinery/light_construct/small{ dir = 1 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "zp" = ( /obj/effect/decal/cleanable/dirt, @@ -965,11 +680,7 @@ }, /obj/effect/landmark/burnturf, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "zv" = ( /obj/effect/decal/cleanable/dirt, @@ -977,11 +688,7 @@ /obj/structure/window/reinforced, /obj/machinery/conveyor/west, /obj/effect/baseturf_helper/lava/mapping_lava, -/turf/simulated/floor{ - temperature = 300; - oxygen = 14; - nitrogen = 23 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "zE" = ( /obj/effect/decal/cleanable/dirt, @@ -991,11 +698,7 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "zG" = ( /obj/effect/decal/cleanable/dirt, @@ -1006,41 +709,25 @@ }, /obj/effect/landmark/damageturf, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "zO" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "zR" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/door_assembly/door_assembly_mhatch, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "zZ" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/machinery/conveyor/west, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Au" = ( /turf/simulated/wall/r_wall, @@ -1049,11 +736,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/structure/door_assembly/door_assembly_mhatch, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "AE" = ( /obj/effect/decal/cleanable/dirt, @@ -1063,30 +746,18 @@ /obj/machinery/power/terminal{ dir = 8 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "AH" = ( /obj/effect/landmark/burnturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "AL" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "AT" = ( /obj/effect/decal/cleanable/dirt, @@ -1096,11 +767,7 @@ "BB" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/portable/pump, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "BG" = ( /obj/effect/decal/cleanable/dirt, @@ -1110,21 +777,13 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "BM" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/burnturf, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "BO" = ( /obj/effect/decal/cleanable/dirt, @@ -1134,11 +793,7 @@ "BV" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "BX" = ( /obj/effect/decal/cleanable/dirt, @@ -1149,11 +804,7 @@ }, /obj/item/clothing/under/rank/cargo/miner, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "CF" = ( /obj/effect/decal/cleanable/dirt, @@ -1166,20 +817,12 @@ dir = 8 }, /obj/machinery/economy/vending/assist/free, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Dd" = ( /obj/structure/grille/broken, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Dg" = ( /obj/effect/mapping_helpers/no_lava, @@ -1189,11 +832,7 @@ /area/lavaland/surface/outdoors) "Dp" = ( /obj/machinery/disposal, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Dt" = ( /obj/effect/decal/cleanable/dirt, @@ -1202,27 +841,15 @@ /obj/item/storage/box/donkpockets/empty, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Dv" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/door_assembly/door_assembly_mhatch, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Dz" = ( -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "DM" = ( /obj/effect/decal/cleanable/dirt, @@ -1230,11 +857,7 @@ /obj/effect/landmark/damageturf, /obj/effect/landmark/damageturf, /obj/structure/disposalpipe/segment, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Ec" = ( /obj/effect/decal/cleanable/dirt, @@ -1242,11 +865,7 @@ dir = 5 }, /obj/machinery/mineral/processing_unit, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Ek" = ( /obj/effect/mapping_helpers/no_lava, @@ -1263,22 +882,14 @@ dir = 2 }, /obj/effect/landmark/burnturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Fa" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Fd" = ( /obj/effect/decal/cleanable/dirt, @@ -1288,11 +899,7 @@ }, /obj/item/tank/internals/oxygen, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "FW" = ( /obj/effect/decal/cleanable/dirt, @@ -1310,11 +917,7 @@ pixel_y = -2; pixel_x = -29 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "FX" = ( /obj/structure/disposalpipe/broken{ @@ -1323,11 +926,7 @@ /obj/structure/disposalpipe/broken{ dir = 8 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Ge" = ( /obj/effect/decal/cleanable/dirt, @@ -1336,33 +935,21 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Gk" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/remains/human, /obj/item/clothing/under/rank/cargo/miner, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Gt" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, /obj/structure/disposalpipe/segment, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "GF" = ( /obj/effect/mapping_helpers/no_lava, @@ -1372,11 +959,7 @@ "GV" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/girder, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Hj" = ( /obj/effect/mapping_helpers/no_lava, @@ -1388,11 +971,7 @@ "Hs" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/baseturf_helper/lava/mapping_lava, -/turf/simulated/floor/plasteel{ - temperature = 300; - oxygen = 14; - nitrogen = 23 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Hx" = ( /obj/effect/decal/cleanable/dirt, @@ -1400,32 +979,20 @@ /obj/effect/decal/cleanable/dirt, /mob/living/simple_animal/hostile/asteroid/hivelord/legion, /obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Hz" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/baseturf_helper/lava/mapping_lava, -/turf/simulated/floor/plasteel{ - temperature = 300; - oxygen = 14; - nitrogen = 23 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "HO" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/simple/hidden, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Ic" = ( /obj/effect/decal/cleanable/dirt, @@ -1433,39 +1000,23 @@ /obj/effect/turf_decal/delivery/white/hollow, /obj/structure/closet/crate/miningcar, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "In" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/burnturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Io" = ( /obj/item/chair, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "IT" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery/white/hollow, /obj/structure/ore_box, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Jw" = ( /obj/structure/table, @@ -1475,32 +1026,20 @@ }, /obj/item/reagent_containers/drinks/cans/beer, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "JE" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/machinery/mech_bay_recharge_port, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "JT" = ( /obj/structure/grille, /obj/item/shard, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "KJ" = ( /obj/effect/decal/cleanable/dirt, @@ -1508,11 +1047,7 @@ /obj/effect/landmark/burnturf, /obj/effect/landmark/damageturf, /obj/machinery/atmospherics/portable/scrubber, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "KN" = ( /obj/structure/disposalpipe/segment{ @@ -1527,11 +1062,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "KZ" = ( /obj/effect/mapping_helpers/no_lava, @@ -1545,11 +1076,7 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Ln" = ( /obj/effect/decal/cleanable/dirt, @@ -1557,63 +1084,39 @@ /obj/structure/closet/crate/miningcar, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Lq" = ( /obj/machinery/light_construct/small{ dir = 4 }, /obj/effect/landmark/burnturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "LA" = ( /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Ms" = ( /obj/structure/girder, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Mu" = ( /obj/structure/disposalpipe/segment/corner{ dir = 8 }, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Mw" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/structure/closet/crate/secure/loot, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "MO" = ( /obj/effect/decal/cleanable/dirt, @@ -1624,79 +1127,51 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "MY" = ( /obj/effect/landmark/burnturf, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Og" = ( /obj/structure/girder, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating/airless, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Oh" = ( /obj/structure/table, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/item/paper/fluff/ruins/althland/journal, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "OJ" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/burnturf, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "OW" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/item/t_scanner/adv_mining_scanner, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Pn" = ( /obj/structure/disposalpipe/segment, /obj/effect/landmark/burnturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Po" = ( /obj/structure/grille/broken, /obj/item/shard, /obj/item/shard, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Px" = ( /obj/effect/decal/cleanable/dirt, @@ -1708,48 +1183,28 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "PF" = ( /obj/structure/grille/broken, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "PJ" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "PY" = ( /obj/structure/marker_beacon/dock_marker, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Qj" = ( /obj/effect/decal/cleanable/dirt, /obj/structure/closet/crate, /obj/item/clothing/mask/gas/explorer, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Qu" = ( /obj/effect/mapping_helpers/no_lava, @@ -1769,11 +1224,7 @@ amount = 5 }, /obj/effect/landmark/burnturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "RX" = ( /obj/structure/lattice/catwalk/mining, @@ -1791,30 +1242,18 @@ }, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "TN" = ( /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "TX" = ( /obj/structure/disposalpipe/broken{ dir = 2 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "UP" = ( /obj/effect/decal/cleanable/dirt, @@ -1824,11 +1263,7 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Vj" = ( /obj/effect/decal/cleanable/dirt, @@ -1837,11 +1272,7 @@ dir = 4; invisibility = 101 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "VJ" = ( /obj/effect/mapping_helpers/no_lava, @@ -1856,11 +1287,7 @@ /area/lavaland/surface/outdoors) "VO" = ( /obj/machinery/economy/vending/cigarette, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Wb" = ( /obj/effect/decal/cleanable/dirt, @@ -1874,19 +1301,11 @@ pixel_x = -3; pixel_y = 28 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Wl" = ( /obj/structure/grille, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Wp" = ( /obj/structure/grille/broken, @@ -1895,11 +1314,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/burnturf, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "WQ" = ( /obj/effect/decal/cleanable/dirt, @@ -1909,11 +1324,7 @@ pixel_x = -3; pixel_y = 28 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "WU" = ( /obj/effect/mapping_helpers/no_lava, @@ -1930,22 +1341,14 @@ /obj/effect/decal/cleanable/dirt, /obj/machinery/computer/nonfunctional, /obj/item/paper/fluff/ruins/althland/geology, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "XD" = ( /obj/effect/decal/remains/human, /obj/item/clothing/under/rank/cargo/miner, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "XO" = ( /obj/item/shard, @@ -1953,11 +1356,7 @@ /obj/structure/grille/broken, /obj/effect/landmark/damageturf, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "XT" = ( /obj/effect/decal/cleanable/dirt, @@ -1967,28 +1366,16 @@ /obj/effect/landmark/burnturf, /obj/effect/landmark/damageturf, /obj/machinery/atmospherics/pipe/manifold/hidden, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Yd" = ( /obj/structure/grille, /obj/item/shard, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Yl" = ( /obj/structure/girder, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Yt" = ( /obj/effect/decal/cleanable/dirt, @@ -1997,51 +1384,31 @@ /obj/machinery/light_construct/small{ dir = 4 }, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "Yx" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/unary/tank/oxygen_agent_b, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "YF" = ( /obj/machinery/power/terminal{ dir = 8 }, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "YK" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/damageturf, -/turf/simulated/floor/plasteel{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plasteel/lavaland_air, /area/ruin/unpowered/althland_processing) "YN" = ( /obj/structure/grille/broken, /obj/item/shard, /obj/effect/decal/cleanable/glass, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/lavaland/surface/outdoors) "Zi" = ( /obj/effect/decal/cleanable/dirt, @@ -2051,11 +1418,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/burnturf, /obj/effect/landmark/damageturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "Zr" = ( /obj/effect/mapping_helpers/no_lava, @@ -2070,11 +1433,7 @@ "ZA" = ( /obj/structure/grille, /obj/item/shard, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "ZB" = ( /obj/effect/mapping_helpers/no_lava, @@ -2089,11 +1448,7 @@ /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, /obj/effect/landmark/burnturf, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) "ZN" = ( /obj/effect/decal/cleanable/dirt, @@ -2103,11 +1458,7 @@ pixel_x = -1; pixel_y = 32 }, -/turf/simulated/floor{ - temperature = 500; - oxygen = 8; - nitrogen = 14 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/althland_processing) (1,1,1) = {" @@ -2428,7 +1779,7 @@ BM Hz bO In -dM +GV ab ab ab diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm index c443e7528b8..33d456c77ea 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm @@ -26,15 +26,6 @@ /obj/structure/reagent_dispensers/watertank/high, /turf/simulated/floor/plating, /area/shuttle/freegolem) -"h" = ( -/obj/structure/shuttle/engine/heater{ - dir = 4 - }, -/obj/structure/window/reinforced{ - dir = 8 - }, -/turf/simulated/floor/plating/lavaland_air, -/area/shuttle/freegolem) "i" = ( /obj/structure/shuttle/engine/propulsion{ dir = 4; @@ -258,6 +249,15 @@ /obj/structure/ore_box, /turf/simulated/floor/plating, /area/shuttle/freegolem) +"U" = ( +/obj/structure/shuttle/engine/heater{ + dir = 4 + }, +/obj/structure/window/plasmareinforced{ + dir = 8 + }, +/turf/simulated/floor/plating/lavaland_air, +/area/shuttle/freegolem) (1,1,1) = {" a @@ -585,20 +585,20 @@ b "} (19,1,1) = {" b -h -h +U +U b -h -h +U +U b z E b -h -h +U +U b -h -h +U +U b "} (20,1,1) = {" diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm index 1748cdfd341..70e871e0b52 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm @@ -165,11 +165,7 @@ /area/ruin/powered) "J" = ( /obj/effect/spawner/window/shuttle, -/turf/simulated/floor/plating{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/plating, /area/ruin/powered) "K" = ( /obj/effect/baseturf_helper, diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm index 93341452885..3b983ab744c 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_pizzaparty.dmm @@ -14,65 +14,37 @@ /area/ruin/unpowered/misc_lavaruin) "e" = ( /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "f" = ( /obj/structure/table/wood, /obj/item/storage/box/cups, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "g" = ( /obj/structure/reagent_dispensers/water_cooler/pizzaparty, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "h" = ( /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "i" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "j" = ( /obj/item/food/snacks/mushroompizzaslice, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "k" = ( /obj/structure/table/wood, /obj/effect/spawner/lootdrop/pizzaparty, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "l" = ( /obj/machinery/light{ @@ -82,56 +54,32 @@ /obj/effect/spawner/lootdrop/pizzaparty, /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/cobweb2, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "m" = ( /obj/item/chair/wood/wings, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "n" = ( /obj/structure/glowshroom, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "o" = ( /obj/item/trash/plate, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "p" = ( /obj/effect/decal/remains/human, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "q" = ( /obj/item/chair/wood/wings, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "r" = ( /obj/structure/chair/wood/wings, @@ -140,35 +88,19 @@ desc = "A festive party hat with the name 'timmy' scribbled on the front."; name = "party hat" }, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "s" = ( -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "t" = ( /obj/structure/chair/wood/wings, /obj/effect/decal/remains/human, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "u" = ( /obj/structure/glowshroom, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "v" = ( /obj/structure/lattice, @@ -178,130 +110,74 @@ "w" = ( /obj/item/kitchen/utensil/fork, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "x" = ( /obj/structure/table/wood, /obj/effect/spawner/lootdrop/pizzaparty, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "y" = ( /obj/structure/table/wood, /obj/item/trash/plate, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "z" = ( /obj/structure/table/wood, /obj/structure/glowshroom, /obj/item/a_gift, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "A" = ( /obj/structure/table/wood, /obj/item/trash/plate, /obj/item/kitchen/utensil/fork, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "B" = ( /obj/effect/baseturf_helper/lava/mapping_lava, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "C" = ( /obj/structure/chair/wood/wings{ dir = 4 }, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "D" = ( /obj/structure/table/wood, /obj/item/food/snacks/margheritapizzaslice, /obj/item/trash/plate, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "E" = ( /obj/structure/table/wood, /obj/item/food/snacks/meatpizzaslice, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "F" = ( /obj/structure/table/wood, /obj/item/food/snacks/sliceable/birthdaycake, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "G" = ( /obj/structure/table/wood, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "H" = ( /obj/item/chair/wood/wings, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "I" = ( /obj/item/kitchen/utensil/fork, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "J" = ( /obj/structure/glowshroom, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "K" = ( /obj/structure/chair/wood/wings{ @@ -309,29 +185,17 @@ }, /obj/effect/decal/remains/human, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "L" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/plating{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "M" = ( /obj/effect/decal/cleanable/dirt, /obj/item/a_gift, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "N" = ( /obj/structure/lattice, @@ -341,29 +205,17 @@ "O" = ( /obj/item/kitchen/knife, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "P" = ( /obj/machinery/light{ dir = 4 }, /obj/effect/decal/cleanable/dirt, -/turf/simulated/floor/wood{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/wood/lavaland_air, /area/ruin/unpowered/misc_lavaruin) "Q" = ( -/turf/simulated/floor/plating{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/plating/lavaland_air, /area/ruin/unpowered/misc_lavaruin) (1,1,1) = {" diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_pride.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_pride.dmm index 9dd7728d1f8..754614d2091 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_pride.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_pride.dmm @@ -10,22 +10,22 @@ /area/lavaland/surface/outdoors) "d" = ( /obj/effect/baseturf_helper/lava/mapping_lava, -/turf/simulated/floor/mineral/silver, +/turf/simulated/floor/mineral/silver/lavaland_air, /area/ruin/powered/pride) "e" = ( /obj/structure/mirror{ pixel_x = -32 }, -/turf/simulated/floor/mineral/silver, +/turf/simulated/floor/mineral/silver/lavaland_air, /area/ruin/powered/pride) "f" = ( /obj/structure/mirror{ pixel_x = 32 }, -/turf/simulated/floor/mineral/silver, +/turf/simulated/floor/mineral/silver/lavaland_air, /area/ruin/powered/pride) "g" = ( -/turf/simulated/floor/mineral/silver, +/turf/simulated/floor/mineral/silver/lavaland_air, /area/ruin/powered/pride) "j" = ( /obj/structure/mirror{ @@ -34,7 +34,7 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/mineral/silver, +/turf/simulated/floor/mineral/silver/lavaland_air, /area/ruin/powered/pride) "k" = ( /obj/structure/mirror{ @@ -43,7 +43,7 @@ /obj/machinery/light/small{ dir = 1 }, -/turf/simulated/floor/mineral/silver, +/turf/simulated/floor/mineral/silver/lavaland_air, /area/ruin/powered/pride) "l" = ( /obj/structure/mirror{ @@ -53,7 +53,7 @@ brightness_range = 3; dir = 8 }, -/turf/simulated/floor/mineral/silver, +/turf/simulated/floor/mineral/silver/lavaland_air, /area/ruin/powered/pride) "m" = ( /obj/structure/mirror{ @@ -62,11 +62,11 @@ /obj/machinery/light/small{ dir = 4 }, -/turf/simulated/floor/mineral/silver, +/turf/simulated/floor/mineral/silver/lavaland_air, /area/ruin/powered/pride) "r" = ( /obj/machinery/light/small, -/turf/simulated/floor/mineral/silver, +/turf/simulated/floor/mineral/silver/lavaland_air, /area/ruin/powered/pride) "G" = ( /turf/simulated/wall/mineral/diamond, @@ -78,9 +78,7 @@ "Y" = ( /obj/machinery/door/airlock/diamond, /obj/structure/fans/tiny/invisible, -/turf/simulated/floor/mineral/silver{ - blocks_air = 1 - }, +/turf/simulated/floor/mineral/silver/lavaland_air, /area/ruin/powered/pride) (1,1,1) = {" diff --git a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm index 4088486eed1..becf4900929 100644 --- a/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm +++ b/_maps/map_files/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm @@ -323,7 +323,7 @@ /turf/simulated/floor/plasteel/freezer, /area/ruin/powered/seedvault) "FS" = ( -/obj/effect/spawner/window/reinforced/tinted, +/obj/effect/spawner/window/reinforced/plasma, /turf/simulated/floor/plating, /area/ruin/powered/seedvault) "HL" = ( diff --git a/_maps/map_files/RandomRuins/SpaceRuins/syndie_space_base.dmm b/_maps/map_files/RandomRuins/SpaceRuins/syndie_space_base.dmm index 91e421e0522..ffba441d118 100644 --- a/_maps/map_files/RandomRuins/SpaceRuins/syndie_space_base.dmm +++ b/_maps/map_files/RandomRuins/SpaceRuins/syndie_space_base.dmm @@ -2801,6 +2801,7 @@ /area/ruin/unpowered/syndicate_space_base/toxtest) "pk" = ( /obj/machinery/door/airlock/external, +/obj/structure/fans/tiny, /turf/simulated/floor/catwalk, /area/ruin/unpowered/syndicate_space_base/toxtest) "pl" = ( @@ -6702,6 +6703,7 @@ "Lj" = ( /obj/machinery/door/airlock/hatch/syndicate, /obj/machinery/door/firedoor, +/obj/structure/fans/tiny, /turf/simulated/floor/plasteel{ icon_state = "dark" }, diff --git a/_maps/map_files/generic/Lavaland.dmm b/_maps/map_files/generic/Lavaland.dmm index 952d3a3964a..ae3ca3c8756 100644 --- a/_maps/map_files/generic/Lavaland.dmm +++ b/_maps/map_files/generic/Lavaland.dmm @@ -80,7 +80,7 @@ /turf/simulated/floor/plating, /area/mine/outpost/maintenance/south) "ap" = ( -/obj/effect/spawner/window/reinforced, +/obj/effect/spawner/window/reinforced/plasma, /turf/simulated/floor/plating, /area/mine/laborcamp) "aq" = ( @@ -454,7 +454,7 @@ /area/mine/outpost/hallway/west) "bJ" = ( /obj/machinery/door/firedoor, -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /turf/simulated/floor/plating, /area/mine/outpost/cafeteria) "bK" = ( @@ -632,17 +632,14 @@ /area/mine/outpost/maintenance/south) "ch" = ( /obj/structure/shuttle/engine/heater, -/obj/structure/window/reinforced{ - dir = 8 +/obj/structure/window/plasmareinforced{ + dir = 1 }, -/obj/structure/window/reinforced{ - dir = 4 - }, -/obj/structure/window/reinforced{ +/obj/structure/window/plasmareinforced{ dir = 1 }, /turf/simulated/floor/plating/lavaland_air, -/area/shuttle/mining) +/area/shuttle/siberia) "cj" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/portable/pump, @@ -878,7 +875,7 @@ /area/lavaland/surface/outdoors/outpost/catwalk) "cN" = ( /obj/machinery/door/firedoor, -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /turf/simulated/floor/plating, /area/mine/outpost/medbay) "cO" = ( @@ -952,7 +949,7 @@ /area/mine/outpost/medbay) "cU" = ( /obj/machinery/door/firedoor, -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /turf/simulated/floor/plating, /area/mine/outpost/storage) "cV" = ( @@ -1056,7 +1053,7 @@ }, /area/mine/outpost/airlock) "dg" = ( -/obj/effect/spawner/window/reinforced, +/obj/effect/spawner/window/reinforced/plasma, /turf/simulated/floor/plating, /area/mine/outpost/mechbay) "dh" = ( @@ -1467,7 +1464,9 @@ }, /area/mine/outpost/medbay) "dR" = ( -/turf/simulated/mineral/ancient, +/turf/simulated/mineral/ancient{ + temperature = 293.15 + }, /area/mine/outpost/engineering) "dS" = ( /obj/machinery/hologram/holopad, @@ -2095,15 +2094,15 @@ /area/mine/outpost/maintenance/south) "fc" = ( /obj/structure/shuttle/engine/heater, -/obj/structure/window/reinforced{ - dir = 8 - }, -/obj/structure/window/reinforced{ +/obj/structure/window/plasmareinforced{ dir = 1 }, -/obj/structure/window/reinforced{ +/obj/structure/window/plasmareinforced{ dir = 4 }, +/obj/structure/window/plasmareinforced{ + dir = 8 + }, /turf/simulated/floor/plating/lavaland_air, /area/shuttle/mining) "fd" = ( @@ -2473,8 +2472,8 @@ /area/mine/laborcamp) "fO" = ( /obj/structure/disposalpipe/segment, -/obj/effect/spawner/window/reinforced/tinted/grilled, /obj/machinery/atmospherics/pipe/simple/hidden/scrubbers, +/obj/effect/spawner/window/plasma/grilled, /turf/simulated/floor/plating, /area/mine/outpost/hallway/east) "fP" = ( @@ -3387,6 +3386,7 @@ /obj/effect/spawner/window/reinforced/polarized/grilled{ id = "mining qm" }, +/obj/structure/fans/tiny, /turf/simulated/floor/plating, /area/mine/outpost/quartermaster) "jk" = ( @@ -3567,7 +3567,7 @@ /area/mine/laborcamp) "kf" = ( /obj/machinery/door/firedoor, -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /turf/simulated/floor/plating, /area/mine/outpost/airlock) "kg" = ( @@ -3702,7 +3702,7 @@ /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "lf" = ( -/obj/effect/spawner/window/grilled, +/obj/effect/spawner/window/plasma/grilled, /turf/simulated/floor/plating, /area/mine/outpost/maintenance/south) "lg" = ( @@ -5151,7 +5151,7 @@ /area/mine/laborcamp) "sk" = ( /obj/machinery/door/firedoor, -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /turf/simulated/floor/plating, /area/mine/outpost/lockers) "sr" = ( @@ -5402,7 +5402,7 @@ }, /area/mine/laborcamp) "um" = ( -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /turf/simulated/floor/plating, /area/mine/outpost/hallway/west) "uo" = ( @@ -5634,7 +5634,7 @@ /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "vy" = ( -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /obj/structure/cable{ d2 = 2; icon_state = "0-2" @@ -5814,7 +5814,7 @@ /area/mine/laborcamp) "wi" = ( /obj/machinery/door/firedoor, -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /obj/effect/turf_decal/delivery/hollow, /turf/simulated/floor/plating, /area/mine/outpost/cafeteria) @@ -5881,7 +5881,7 @@ }, /area/mine/outpost/hallway/east) "xa" = ( -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /obj/structure/cable, /turf/simulated/floor/plating, /area/mine/laborcamp/security) @@ -7225,6 +7225,7 @@ /obj/effect/spawner/window/reinforced/polarized/grilled{ id = "mining qm" }, +/obj/structure/fans/tiny, /turf/simulated/floor/plating, /area/mine/outpost/quartermaster) "Em" = ( @@ -7877,9 +7878,8 @@ /area/lavaland/surface/outdoors) "IR" = ( /obj/structure/shuttle/engine/heater, -/obj/structure/window/reinforced{ - dir = 1; - layer = 2.9 +/obj/structure/window/plasmareinforced{ + dir = 1 }, /turf/simulated/floor/plating/lavaland_air, /area/shuttle/siberia) @@ -8021,7 +8021,7 @@ }, /area/lavaland/surface/outdoors) "JF" = ( -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /obj/machinery/door/poddoor/preopen{ id_tag = "Labor"; name = "labor camp blast door" @@ -8810,7 +8810,7 @@ /turf/simulated/floor/lava/mapping_lava, /area/lavaland/surface/outdoors) "OX" = ( -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /obj/machinery/door/poddoor/preopen{ id_tag = "Labor"; name = "labor camp blast door" @@ -8847,7 +8847,7 @@ /obj/structure/sign/securearea{ name = "\improper KEEP CLEAR: DOCKING AREA" }, -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /turf/simulated/floor/plating, /area/mine/outpost/hallway/west) "Ph" = ( @@ -8930,6 +8930,7 @@ /obj/effect/spawner/window/reinforced/polarized/grilled{ id = "mining qm" }, +/obj/structure/fans/tiny, /turf/simulated/floor/plating, /area/mine/outpost/quartermaster) "PI" = ( @@ -9089,7 +9090,7 @@ /turf/simulated/floor/mineral/plastitanium/red, /area/shuttle/siberia) "QE" = ( -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /obj/structure/cable{ d2 = 2; icon_state = "0-2" @@ -10263,7 +10264,7 @@ /area/mine/outpost/mechbay) "XZ" = ( /obj/machinery/door/firedoor, -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /turf/simulated/floor/plating, /area/mine/outpost/hallway/west) "Ya" = ( @@ -10508,7 +10509,7 @@ /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface, /area/lavaland/surface/outdoors) "Zm" = ( -/obj/effect/spawner/window/reinforced/grilled, +/obj/effect/spawner/window/reinforced/plasma/grilled, /turf/simulated/floor/plating, /area/mine/laborcamp) "Zn" = ( @@ -12613,7 +12614,7 @@ kI Wd kA pq -IR +ch xD ab ai @@ -20085,7 +20086,7 @@ xC tb fU tb -ch +fc xo LM vZ diff --git a/_maps/map_files/templates/biodome_beach.dmm b/_maps/map_files/templates/biodome_beach.dmm index c6af4cff658..2be2f80961b 100644 --- a/_maps/map_files/templates/biodome_beach.dmm +++ b/_maps/map_files/templates/biodome_beach.dmm @@ -427,11 +427,7 @@ /obj/machinery/light{ dir = 4 }, -/turf/simulated/floor/pod/light{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/pod/light/lavaland_air, /area/ruin/powered/beach) "lM" = ( /obj/structure/dresser, @@ -547,11 +543,7 @@ /obj/machinery/light{ dir = 8 }, -/turf/simulated/floor/pod/light{ - nitrogen = 14; - oxygen = 8; - temperature = 500 - }, +/turf/simulated/floor/pod/light/lavaland_air, /area/ruin/powered/beach) "TW" = ( /obj/structure/table/reinforced, diff --git a/code/__DEFINES/atmospherics_defines.dm b/code/__DEFINES/atmospherics_defines.dm index a9e2c82b71e..5cdec032861 100644 --- a/code/__DEFINES/atmospherics_defines.dm +++ b/code/__DEFINES/atmospherics_defines.dm @@ -43,11 +43,14 @@ //HEAT TRANSFER COEFFICIENTS //Must be between 0 and 1. Values closer to 1 equalize temperature faster -//Should not exceed 0.4 else strange heat flow occur -#define FLOOR_HEAT_TRANSFER_COEFFICIENT 0.15 +//Capped at OPEN_HEAT_TRANSFER_COEFFICIENT, both here and in Rust. #define WALL_HEAT_TRANSFER_COEFFICIENT 0.0 +#define DOOR_HEAT_TRANSFER_COEFFICIENT 0.001 #define OPEN_HEAT_TRANSFER_COEFFICIENT 0.4 -#define WINDOW_HEAT_TRANSFER_COEFFICIENT 0.1 //a hack for now +#define WINDOW_HEAT_TRANSFER_COEFFICIENT 0.001 +// This looks silly, but it's for clarity when reading elsewhere. +#define ZERO_HEAT_TRANSFER_COEFFICIENT 0.0 + #define HEAT_CAPACITY_VACUUM 700000 //a hack to help make vacuums "cold", sacrificing realism for gameplay //FIRE @@ -148,3 +151,15 @@ // Reactions #define N2O_DECOMPOSITION_MIN_ENERGY 1400 #define N2O_DECOMPOSITION_ENERGY_RELEASED 200000 + +// From milla/src/lib.rs +#define ATMOS_MODE_SPACE 0 +#define ATMOS_MODE_SEALED 1 +#define ATMOS_MODE_EXPOSED_TO_ENVIRONMENT 2 + +/// Lavaland environment: hot, low pressure. +#define ENVIRONMENT_LAVALAND "lavaland" +/// Temperate environment: Normal atmosphere, 20 C. +#define ENVIRONMENT_TEMPERATE "temperate" +/// Cold environment: Normal atmosphere, -93 C. +#define ENVIRONMENT_COLD "cold" diff --git a/code/__DEFINES/milla.dm b/code/__DEFINES/milla.dm new file mode 100644 index 00000000000..bf5f2ddca09 --- /dev/null +++ b/code/__DEFINES/milla.dm @@ -0,0 +1,126 @@ +// milla.dm - DM API for milla extension library + +// Default automatic MILLA detection. +// Look for it in the build location first, then in `.`, then in standard places. + +/* This comment bypasses grep checks */ /var/__milla + +/proc/__detect_milla() + if(world.system_type == UNIX) +#ifdef CIBUILDING + // CI override, use libmilla_ci.so if possible. + if(fexists("./tools/ci/libmilla_ci.so")) + return __milla = "tools/ci/libmilla_ci.so" +#endif + // First check if it's built in the usual place. + if(fexists("./milla/target/i686-unknown-linux-gnu/release/libmilla.so")) + return __milla = "./milla/target/i686-unknown-linux-gnu/release/libmilla.so" + // Then check in the current directory. + if(fexists("./libmilla.so")) + return __milla = "./libmilla.so" + // And elsewhere. + return __milla = "libmilla.so" + else + // First check if it's built in the usual place. + if(fexists("./milla/target/i686-pc-windows-msvc/release/milla.dll")) + return __milla = "./milla/target/i686-pc-windows-msvc/release/milla.dll" + // Then check in the current directory. + if(fexists("./milla.dll")) + return __milla = "./milla.dll" + // And elsewhere. + return __milla = "milla.dll" + +#define MILLA (__milla || __detect_milla()) + +#define MILLA_CALL(func, args...) call_ext(MILLA, "byond:[#func]_ffi")(args) + +/proc/milla_init_z(z) + return MILLA_CALL(initialize, z) + +/proc/is_milla_synchronous(tick) + return MILLA_CALL(is_synchronous, tick) + +/proc/set_tile_atmos(turf/T, airtight_north, airtight_east, airtight_south, airtight_west, atmos_mode, environment_id, oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, temperature, innate_heat_capacity) + return MILLA_CALL(set_tile, T, airtight_north, airtight_east, airtight_south, airtight_west, atmos_mode, environment_id, oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, temperature, innate_heat_capacity) + +/proc/get_tile_atmos(turf/T, list/L) + return MILLA_CALL(get_tile, T, L) + +/proc/spawn_milla_tick_thread() + return MILLA_CALL(spawn_tick_thread) + +/proc/get_milla_tick_time() + return MILLA_CALL(get_tick_time) + +/proc/get_interesting_atmos_tiles() + return MILLA_CALL(get_interesting_tiles) + +/proc/reduce_superconductivity(turf/T, list/superconductivity) + var/north = superconductivity[1] + var/east = superconductivity[2] + var/south = superconductivity[3] + var/west = superconductivity[4] + + return MILLA_CALL(reduce_superconductivity, T, north, east, south, west) + +/proc/reset_superconductivity(turf/T) + return MILLA_CALL(reset_superconductivity, T) + +/proc/set_tile_airtight(turf/T, list/airtight) + var/north = airtight[1] + var/east = airtight[2] + var/south = airtight[3] + var/west = airtight[4] + + return MILLA_CALL(set_tile_airtight, T, north, east, south, west) + +/proc/get_random_interesting_tile() + return MILLA_CALL(get_random_interesting_tile) + +/proc/create_environment(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, temperature) + return MILLA_CALL(create_environment, oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, temperature) + +#undef MILLA +#undef MILLA_CALL + +// Indexes for Tiles and InterestingTiles +// Must match the order in milla/src/model.rs +#define MILLA_INDEX_AIRTIGHT_DIRECTIONS 1 +#define MILLA_INDEX_OXYGEN 2 +#define MILLA_INDEX_CARBON_DIOXIDE 3 +#define MILLA_INDEX_NITROGEN 4 +#define MILLA_INDEX_TOXINS 5 +#define MILLA_INDEX_SLEEPING_AGENT 6 +#define MILLA_INDEX_AGENT_B 7 +#define MILLA_INDEX_ATMOS_MODE 8 +#define MILLA_INDEX_ENVIRONMENT_ID 9 +#define MILLA_INDEX_SUPERCONDUCTIVITY_NORTH 10 +#define MILLA_INDEX_SUPERCONDUCTIVITY_EAST 11 +#define MILLA_INDEX_SUPERCONDUCTIVITY_SOUTH 12 +#define MILLA_INDEX_SUPERCONDUCTIVITY_WEST 13 +#define MILLA_INDEX_INNATE_HEAT_CAPACITY 14 +#define MILLA_INDEX_TEMPERATURE 15 + +/// The number of values per tile. +#define MILLA_TILE_SIZE MILLA_INDEX_TEMPERATURE + +// These are only for InterestingTiles. +#define MILLA_INDEX_TURF 16 +#define MILLA_INDEX_INTERESTING_REASONS 17 +#define MILLA_INDEX_AIRFLOW_X 18 +#define MILLA_INDEX_AIRFLOW_Y 19 + +/// The number of values per interesting tile. +#define MILLA_INTERESTING_TILE_SIZE MILLA_INDEX_AIRFLOW_Y + +/// Interesting because it needs a display update. +#define MILLA_INTERESTING_REASON_DISPLAY (1 << 0) +/// Interesting because it's hot enough to start a fire. Excludes normal-temperature Lavaland tiles without an active fire. +#define MILLA_INTERESTING_REASON_HOT (1 << 1) +/// Interesting because it has wind that can push stuff around. +#define MILLA_INTERESTING_REASON_WIND (1 << 2) + +#define MILLA_NORTH (1 << 0) +#define MILLA_EAST (1 << 1) +#define MILLA_SOUTH (1 << 2) +#define MILLA_WEST (1 << 3) diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 17cb3e0cb91..e6f5604890c 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -399,7 +399,7 @@ . = FALSE if(!istype(T)) return - var/datum/gas_mixture/environment = T.return_air() + var/datum/gas_mixture/environment = T.get_readonly_air() if(!istype(environment)) return var/pressure = environment.return_pressure() diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 387463afa83..3182629e953 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -819,8 +819,8 @@ Returns 1 if the chain up to the area contains the given typepath // Give the new turf our air, if simulated if(issimulatedturf(X) && issimulatedturf(T)) - var/turf/simulated/sim = X - sim.copy_air_with_tile(T) + var/datum/milla_safe/area_move_transrer_gas/milla = new() + milla.invoke_async(T, X) // Quick visual fix for some weird shuttle corner artefacts when on transit space tiles if(direction && findtext(X.icon_state, "swall_s")) @@ -876,18 +876,10 @@ Returns 1 if the chain up to the area contains the given typepath refined_trg -= B continue moving - if(length(to_update)) - for(var/turf/simulated/T1 in to_update) - SSair.remove_from_active(T1) - T1.CalculateAdjacentTurfs() - SSair.add_to_active(T1, TRUE) - - if(length(from_update)) - for(var/turf/simulated/T2 in from_update) - SSair.remove_from_active(T2) - T2.CalculateAdjacentTurfs() - SSair.add_to_active(T2, TRUE) +/datum/milla_safe/area_move_transrer_gas +/datum/milla_safe/area_move_transrer_gas/on_run(turf/source, turf/target) + get_turf_air(target).copy_from(get_turf_air(source)) /proc/DuplicateObject(obj/original, perfectcopy = 0, sameloc = 0, atom/newloc) if(!original) @@ -1008,11 +1000,6 @@ Returns 1 if the chain up to the area contains the given typepath refined_trg -= B continue moving - if(length(to_update)) - for(var/turf/simulated/T1 in to_update) - T1.CalculateAdjacentTurfs() - SSair.add_to_active(T1,1) - return copied_objects diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index e69962965c5..a322747f0e5 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -279,11 +279,15 @@ /datum/controller/subsystem/Initialize() CRASH("Initialize() not overridden for [type]! Make the subsystem Initialize or add SS_NO_INIT to the flags") +/// Returns what to display as the ms cost for this subsystem. +/datum/controller/subsystem/proc/get_cost() + return round(cost, 1) + /datum/controller/subsystem/stat_entry(msg) var/ss_info = get_stat_details() if(can_fire && !(SS_NO_FIRE & flags)) - msg = "[round(cost, 1)]ms | [round(tick_usage, 1)]%([round(tick_overrun, 1)]%) | [round(ticks, 0.1)]\t[ss_info]" + msg = "[get_cost()]ms | [round(tick_usage, 1)]%([round(tick_overrun, 1)]%) | [round(ticks, 0.1)]\t[ss_info]" else msg = "OFFLINE\t[ss_info]" diff --git a/code/controllers/subsystem/SSair.dm b/code/controllers/subsystem/SSair.dm index 832b52cb571..fa9fbd8b6b7 100644 --- a/code/controllers/subsystem/SSair.dm +++ b/code/controllers/subsystem/SSair.dm @@ -1,11 +1,10 @@ #define SSAIR_DEFERREDPIPENETS 1 #define SSAIR_PIPENETS 2 #define SSAIR_ATMOSMACHINERY 3 -#define SSAIR_ACTIVETURFS 4 -#define SSAIR_EXCITEDGROUPS 5 -#define SSAIR_HIGHPRESSURE 6 -#define SSAIR_HOTSPOTS 7 -#define SSAIR_SUPERCONDUCTIVITY 8 +#define SSAIR_INTERESTING_TILES 4 +#define SSAIR_HOTSPOTS 5 +#define SSAIR_BOUND_MIXTURES 6 +#define SSAIR_MILLA_TICK 7 SUBSYSTEM_DEF(air) name = "Atmospherics" @@ -16,167 +15,272 @@ SUBSYSTEM_DEF(air) runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME offline_implications = "Turfs will no longer process atmos, and all atmospheric machines (including cryotubes) will no longer function. Shuttle call recommended." cpu_display = SS_CPUDISPLAY_HIGH - var/cost_turfs = 0 - var/cost_groups = 0 - var/cost_highpressure = 0 - var/cost_hotspots = 0 - var/cost_superconductivity = 0 - var/cost_pipenets = 0 - var/cost_deferred_pipenets = 0 - var/cost_atmos_machinery = 0 - var/list/excited_groups = list() - var/list/active_turfs = list() + /// How long we took for a full pass through the subsystem. Custom-tracked version of `cost`. + var/datum/resumable_cost_counter/cost_full = new() + /// How long we spent sleeping while waiting for MILLA to finish the last tick, shown in SS Info's C block as ZZZ. + var/datum/resumable_cost_counter/time_slept = new() + /// The cost of a pass through bound gas mixtures, shown in SS Info's C block as BM. + var/datum/resumable_cost_counter/cost_bound_mixtures = new() + /// The cost of a MILLA tick in ms, shown in SS Info's C block as MT. + var/cost_milla_tick = 0 + /// The cost of a pass through interesting tiles, shown in SS Info's C block as IT. + var/datum/resumable_cost_counter/cost_interesting_tiles = new() + /// The cost of a pass through hotspots, shown in SS Info's C block as HS. + var/datum/resumable_cost_counter/cost_hotspots = new() + /// The cost of a pass through pipenets, shown in SS Info's C block as PN. + var/datum/resumable_cost_counter/cost_pipenets = new() + /// The cost of a pass through building pipenets, shown in SS Info's C block as DPN. + var/datum/resumable_cost_counter/cost_pipenets_to_build = new() + /// The cost of a pass through atmos machinery, shown in SS Info's C block as AM. + var/datum/resumable_cost_counter/cost_atmos_machinery = new() + + /// The set of current bound mixtures. Shown in SS Info as BM:x+y, where x is the length at the start of the most recent processing, and y is the number of mixtures that have been added during processing. + var/list/bound_mixtures = list() + /// The original length of bound_mixtures. + var/original_bound_mixtures = 0 + /// The number of bound mixtures we saw when we last stopped processing them. + var/last_bound_mixtures = 0 + /// The number of bound mixtures that were added during this processing cycle. + var/added_bound_mixtures = 0 + /// The length of the most recent interesting tiles list, shown in SS Info as IT. + var/interesting_tile_count = 0 + /// The set of current active hotspots. Length shown in SS Info as HS. var/list/hotspots = list() - var/list/deferred_pipenet_rebuilds = list() - var/list/networks = list() + /// The set of pipenets that need to be built. Length shown in SS Info as PTB. + var/list/pipenets_to_build = list() + /// The set of active pipenets. Length shown in SS Info as PN. + var/list/pipenets = list() + /// The set of active atmos machinery. Length shown in SS Info as AM. var/list/atmos_machinery = list() - var/list/pipe_init_dirs_cache = list() + + /// A list of atmos machinery to set up in Initialize. var/list/machinery_to_construct = list() - - - //Special functions lists - var/list/active_super_conductivity = list() - var/list/high_pressure_delta = list() - /// Pipe overlay/underlay icon manager var/datum/pipe_icon_manager/icon_manager - + /// An arbitrary list of stuff currently being processed. var/list/currentrun = list() + + /// Which step we're currently on, used to let us resume if our time budget elapses. var/currentpart = SSAIR_DEFERREDPIPENETS + /// Is MILLA currently in synchronous mode? TRUE if data is fresh and changes can be made, FALSE if data is from last tick and changes cannot be made (because this tick is still processing). + var/is_synchronous = TRUE + + /// Are we currently running in a MILLA-safe context, i.e. is is_synchronous *guaranteed* to be TRUE. Nothing outside of this file should change this. + VAR_PRIVATE/in_milla_safe_code = FALSE + + /// When did we start the last MILLA tick? + var/milla_tick_start = null + + /// Is MILLA (and hence SSair) reliably healthy? + var/healthy = TRUE + + /// When was MILLA last seen unhealthy? + var/last_unhealthy = 0 + + /// A list of callbacks waiting for MILLA to finish its tick and enter synchronous mode. + var/list/waiting_for_sync = list() + +/// A cost counter for resumable, repeating processes. +/datum/resumable_cost_counter + var/last_complete_ms = 0 + var/ongoing_ms = 0 + +/// Updates the counter based on the time spent making progress and whether we finished the task. +/datum/resumable_cost_counter/proc/record_progress(cost_ms, finished) + if(finished) + last_complete_ms = ongoing_ms + cost_ms + ongoing_ms = 0 + else + ongoing_ms += cost_ms + +/// Gets a display string for this cost counter. +/datum/resumable_cost_counter/proc/to_string() + if(ongoing_ms > last_complete_ms) + // We're in the middle of a task that's already longer than the prior one took in total, report the in-progress time instead, but mark that it's still incomplete with a + + return "[round(ongoing_ms, 1)]+" + return "[round(last_complete_ms, 1)]" + +/datum/controller/subsystem/air/get_cost() + return cost_full.to_string() + /datum/controller/subsystem/air/get_stat_details() var/list/msg = list() msg += "C:{" - msg += "AT:[round(cost_turfs,1)]|" - msg += "EG:[round(cost_groups,1)]|" - msg += "HP:[round(cost_highpressure,1)]|" - msg += "HS:[round(cost_hotspots,1)]|" - msg += "SC:[round(cost_superconductivity,1)]|" - msg += "PN:[round(cost_pipenets,1)]|" - msg += "DPN:[round(cost_deferred_pipenets,1)]|" - msg += "AM:[round(cost_atmos_machinery,1)]" + msg += "ZZZ:[time_slept.to_string()]|" + msg += "BM:[cost_bound_mixtures.to_string()]|" + msg += "MT:[round(cost_milla_tick,1)]|" + msg += "IT:[cost_interesting_tiles.to_string()]|" + msg += "HS:[cost_hotspots.to_string()]|" + msg += "PN:[cost_pipenets.to_string()]|" + msg += "PTB:[cost_pipenets_to_build.to_string()]|" + msg += "AM:[cost_atmos_machinery.to_string()]" msg += "} " - msg += "AT:[length(active_turfs)]|" - msg += "EG:[length(excited_groups)]|" + msg += "BM:[original_bound_mixtures]+[added_bound_mixtures]|" + msg += "IT:[interesting_tile_count]|" msg += "HS:[length(hotspots)]|" - msg += "PN:[length(networks)]|" - msg += "HP:[length(high_pressure_delta)]|" - msg += "AS:[length(active_super_conductivity)]|" - msg += "AT/MS:[round((cost ? length(active_turfs)/cost : 0),0.1)]" + msg += "PN:[length(pipenets)]|" + msg += "AM:[length(atmos_machinery)]|" return msg.Join("") /datum/controller/subsystem/air/get_metrics() . = ..() var/list/cust = list() - cust["active_turfs"] = length(active_turfs) cust["hotspots"] = length(hotspots) + cust["interesting turfs"] = interesting_tile_count + .["cost"] = cost_full.last_complete_ms .["custom"] = cust /datum/controller/subsystem/air/Initialize() + in_milla_safe_code = TRUE + setup_overlays() // Assign icons and such for gas-turf-overlays icon_manager = new() // Sets up icon manager for pipes setup_allturfs() - if(length(active_turfs)) - throw_error_on_active_roundstart_turfs() + setup_write_to_milla() setup_atmos_machinery(GLOB.machines) setup_pipenets(GLOB.machines) for(var/obj/machinery/atmospherics/A in machinery_to_construct) A.initialize_atmos_network() + in_milla_safe_code = FALSE + /datum/controller/subsystem/air/Recover() - excited_groups = SSair.excited_groups - active_turfs = SSair.active_turfs hotspots = SSair.hotspots - deferred_pipenet_rebuilds = SSair.deferred_pipenet_rebuilds - networks = SSair.networks + pipenets_to_build = SSair.pipenets_to_build + pipenets = SSair.pipenets atmos_machinery = SSair.atmos_machinery - pipe_init_dirs_cache = SSair.pipe_init_dirs_cache machinery_to_construct = SSair.machinery_to_construct - active_super_conductivity = SSair.active_super_conductivity - high_pressure_delta = SSair.high_pressure_delta icon_manager = SSair.icon_manager currentrun = SSair.currentrun currentpart = SSair.currentpart + is_synchronous = SSair.is_synchronous /datum/controller/subsystem/air/fire(resumed = 0) + // All atmos stuff assumes MILLA is synchronous. Ensure it actually is. + if(!is_synchronous) + var/timer = TICK_USAGE_REAL + + while(!is_synchronous) + // Sleep for 1ms. + sleep(0.01) + if(MC_TICK_CHECK) + time_slept.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE) + cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE) + return + + cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE) + time_slept.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), TRUE) + + fire_sleepless(resumed) + +/datum/controller/subsystem/air/proc/fire_sleepless(resumed) + // Any proc that wants MILLA to be synchronous should not sleep. + SHOULD_NOT_SLEEP(TRUE) + in_milla_safe_code = TRUE + var/timer = TICK_USAGE_REAL if(currentpart == SSAIR_DEFERREDPIPENETS || !resumed) - process_deferred_pipenets(resumed) - cost_deferred_pipenets = MC_AVERAGE(cost_deferred_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) + timer = TICK_USAGE_REAL + + build_pipenets(resumed) + + cost_pipenets_to_build.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING) + cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE) + if(state == SS_PAUSED || state == SS_PAUSING) + in_milla_safe_code = FALSE return resumed = 0 currentpart = SSAIR_PIPENETS if(currentpart == SSAIR_PIPENETS || !resumed) + timer = TICK_USAGE_REAL + process_pipenets(resumed) - cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) + + cost_pipenets.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING) + cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE) + if(state == SS_PAUSED || state == SS_PAUSING) + in_milla_safe_code = FALSE return resumed = 0 currentpart = SSAIR_ATMOSMACHINERY if(currentpart == SSAIR_ATMOSMACHINERY) timer = TICK_USAGE_REAL + process_atmos_machinery(resumed) - cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) + + cost_atmos_machinery.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING) + cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE) + if(state == SS_PAUSED || state == SS_PAUSING) + in_milla_safe_code = FALSE return resumed = 0 - currentpart = SSAIR_ACTIVETURFS + currentpart = SSAIR_INTERESTING_TILES - if(currentpart == SSAIR_ACTIVETURFS) + if(currentpart == SSAIR_INTERESTING_TILES) timer = TICK_USAGE_REAL - process_active_turfs(resumed) - cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) - return - resumed = 0 - currentpart = SSAIR_EXCITEDGROUPS - if(currentpart == SSAIR_EXCITEDGROUPS) - timer = TICK_USAGE_REAL - process_excited_groups(resumed) - cost_groups = MC_AVERAGE(cost_groups, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) - return - resumed = 0 - currentpart = SSAIR_HIGHPRESSURE + process_interesting_tiles(resumed) - if(currentpart == SSAIR_HIGHPRESSURE) - timer = TICK_USAGE_REAL - process_high_pressure_delta(resumed) - cost_highpressure = MC_AVERAGE(cost_highpressure, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) + cost_interesting_tiles.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING) + cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE) + if(state == SS_PAUSED || state == SS_PAUSING) + in_milla_safe_code = FALSE return resumed = 0 currentpart = SSAIR_HOTSPOTS if(currentpart == SSAIR_HOTSPOTS) timer = TICK_USAGE_REAL + process_hotspots(resumed) - cost_hotspots = MC_AVERAGE(cost_hotspots, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) + + cost_hotspots.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING) + cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE) + if(state == SS_PAUSED || state == SS_PAUSING) + in_milla_safe_code = FALSE return resumed = 0 - currentpart = SSAIR_SUPERCONDUCTIVITY + currentpart = SSAIR_BOUND_MIXTURES - if(currentpart == SSAIR_SUPERCONDUCTIVITY) + if(currentpart == SSAIR_BOUND_MIXTURES) timer = TICK_USAGE_REAL - process_super_conductivity(resumed) - cost_superconductivity = MC_AVERAGE(cost_superconductivity, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer)) - if(state != SS_RUNNING) + + process_bound_mixtures(resumed) + + cost_bound_mixtures.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING) + cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), FALSE) + if(state == SS_PAUSED || state == SS_PAUSING) + in_milla_safe_code = FALSE return resumed = 0 - currentpart = SSAIR_DEFERREDPIPENETS + currentpart = SSAIR_MILLA_TICK -/datum/controller/subsystem/air/proc/process_deferred_pipenets(resumed = 0) + if(currentpart == SSAIR_MILLA_TICK) + timer = TICK_USAGE_REAL + + spawn_milla_tick_thread() + is_synchronous = FALSE + + cost_milla_tick = MC_AVERAGE(cost_milla_tick, get_milla_tick_time()) + cost_full.record_progress(TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer), state != SS_PAUSED && state != SS_PAUSING) + if(state == SS_PAUSED || state == SS_PAUSING) + in_milla_safe_code = FALSE + return + resumed = 0 + + currentpart = SSAIR_DEFERREDPIPENETS + in_milla_safe_code = FALSE + +/datum/controller/subsystem/air/proc/build_pipenets(resumed = 0) if(!resumed) - src.currentrun = deferred_pipenet_rebuilds.Copy() + src.currentrun = pipenets_to_build.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun while(length(currentrun)) @@ -185,13 +289,13 @@ SUBSYSTEM_DEF(air) if(A) A.build_network(remove_deferral = TRUE) else - deferred_pipenet_rebuilds.Remove(A) + pipenets_to_build.Remove(A) if(MC_TICK_CHECK) return /datum/controller/subsystem/air/proc/process_pipenets(resumed = 0) if(!resumed) - src.currentrun = networks.Copy() + src.currentrun = pipenets.Copy() //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun while(length(currentrun)) @@ -200,7 +304,7 @@ SUBSYSTEM_DEF(air) if(thing) thing.process() else - networks.Remove(thing) + pipenets.Remove(thing) if(MC_TICK_CHECK) return @@ -213,20 +317,8 @@ SUBSYSTEM_DEF(air) while(length(currentrun)) var/obj/machinery/atmospherics/M = currentrun[length(currentrun)] currentrun.len-- - if(!M || (M.process_atmos(seconds) == PROCESS_KILL)) - atmos_machinery.Remove(M) - if(MC_TICK_CHECK) - return - -/datum/controller/subsystem/air/proc/process_super_conductivity(resumed = 0) - if(!resumed) - src.currentrun = active_super_conductivity.Copy() - //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun - while(length(currentrun)) - var/turf/simulated/T = currentrun[length(currentrun)] - currentrun.len-- - T.super_conduct() + if(isnull(M) || (M.process_atmos(seconds) == PROCESS_KILL)) + atmos_machinery -= M if(MC_TICK_CHECK) return @@ -245,108 +337,106 @@ SUBSYSTEM_DEF(air) if(MC_TICK_CHECK) return -/datum/controller/subsystem/air/proc/process_high_pressure_delta(resumed = 0) - while(length(high_pressure_delta)) - var/turf/simulated/T = high_pressure_delta[length(high_pressure_delta)] - high_pressure_delta.len-- - T.high_pressure_movements() - T.pressure_difference = 0 - if(MC_TICK_CHECK) - return - -/datum/controller/subsystem/air/proc/process_active_turfs(resumed = 0) - //cache for sanic speed - var/fire_count = times_fired +/datum/controller/subsystem/air/proc/process_interesting_tiles(resumed = 0) if(!resumed) - src.currentrun = active_turfs.Copy() + // Fetch the list of interesting tiles from MILLA. + src.currentrun = get_interesting_atmos_tiles() + interesting_tile_count = length(src.currentrun) / MILLA_INTERESTING_TILE_SIZE //cache for sanic speed (lists are references anyways) var/list/currentrun = src.currentrun while(length(currentrun)) - var/turf/simulated/T = currentrun[length(currentrun)] - currentrun.len-- - if(T) - T.process_cell(fire_count) + // Pop a tile off the list. + var/offset = length(currentrun) - MILLA_INTERESTING_TILE_SIZE + var/turf/T = currentrun[offset + MILLA_INDEX_TURF] + if(!istype(T)) + currentrun.len -= MILLA_INTERESTING_TILE_SIZE + if(MC_TICK_CHECK) + return + continue + + var/reasons = currentrun[offset + MILLA_INDEX_INTERESTING_REASONS] + var/x_flow = currentrun[offset + MILLA_INDEX_AIRFLOW_X] + var/y_flow = currentrun[offset + MILLA_INDEX_AIRFLOW_Y] + var/milla_tile = currentrun.Copy(offset + 1, offset + 1 + MILLA_TILE_SIZE + 1) + currentrun.len -= MILLA_INTERESTING_TILE_SIZE + + // Bind the MILLA tile we got, if needed. + if(isnull(T.bound_air)) + bind_turf(T, milla_tile) + else if(T.bound_air.lastread < times_fired) + T.bound_air.copy_from_milla(milla_tile) + T.bound_air.lastread = times_fired + T.bound_air.readonly = null + T.bound_air.dirty = FALSE + T.bound_air.synchronized = FALSE + + if(reasons & MILLA_INTERESTING_REASON_DISPLAY) + var/turf/simulated/S = T + if(istype(S)) + S.update_visuals() + + if(reasons & MILLA_INTERESTING_REASON_HOT) + var/datum/gas_mixture/air = T.get_readonly_air() + T.hotspot_expose(air.temperature(), CELL_VOLUME) + for(var/atom/movable/item in T) + item.temperature_expose(air, air.temperature(), CELL_VOLUME) + T.temperature_expose(air, air.temperature(), CELL_VOLUME) + + if(reasons & MILLA_INTERESTING_REASON_WIND) + T.high_pressure_movements(x_flow, y_flow) + if(MC_TICK_CHECK) return -/datum/controller/subsystem/air/proc/process_excited_groups(resumed = 0) +/datum/controller/subsystem/air/proc/process_bound_mixtures(resumed = 0) if(!resumed) - src.currentrun = excited_groups.Copy() + original_bound_mixtures = length(bound_mixtures) + last_bound_mixtures = length(bound_mixtures) + // Note that we do NOT copy this list to src.currentrun. We're fine with things being added to it as we work, because it all needs to get written before the next MILLA tick. //cache for sanic speed (lists are references anyways) - var/list/currentrun = src.currentrun + var/list/currentrun = bound_mixtures + added_bound_mixtures = length(currentrun) - last_bound_mixtures while(length(currentrun)) - var/datum/excited_group/EG = currentrun[length(currentrun)] + var/datum/gas_mixture/bound_to_turf/mixture = currentrun[length(currentrun)] currentrun.len-- - EG.breakdown_cooldown++ - if(EG.breakdown_cooldown == 10) - EG.self_breakdown() - else if(EG.breakdown_cooldown >= 20) - EG.dismantle() + mixture.synchronized = FALSE + if(mixture.dirty) + // This is one of two places expected to call this otherwise-unsafe method. + mixture.private_unsafe_write() + mixture.dirty = FALSE if(MC_TICK_CHECK) + last_bound_mixtures = length(bound_mixtures) return -/datum/controller/subsystem/air/proc/remove_from_active(turf/simulated/T) - active_turfs -= T - active_super_conductivity -= T // bug: if a turf is hit by ex_act 1 while processing, it can end up in super conductivity as /turf/space and cause runtimes - if(currentpart == SSAIR_ACTIVETURFS || currentpart == SSAIR_SUPERCONDUCTIVITY) - currentrun -= T - if(istype(T)) - T.excited = 0 - if(T.excited_group) - T.excited_group.garbage_collect() - -/datum/controller/subsystem/air/proc/add_to_active(turf/simulated/T, blockchanges = 1) - if(!initialized) - /* it makes no sense to "activate" turfs before setup_allturfs is - * called, as setup_allturfs would simply cull the list incorrectly. - * only /turf/simulated/Initialize_Atmos() is blessed enough to - * activate turfs during this phase of initialization, as it happens - * post-cull and inlines the logic (perhaps incorrectly) - **/ - return - - if(istype(T) && T.air) - T.excited = 1 - active_turfs |= T - if(currentpart == SSAIR_ACTIVETURFS) - currentrun |= T - if(blockchanges && T.excited_group) - T.excited_group.garbage_collect() - else - for(var/turf/simulated/S in T.atmos_adjacent_turfs) - add_to_active(S) - /datum/controller/subsystem/air/proc/setup_allturfs(list/turfs_to_init = block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz))) - for(var/thing in turfs_to_init) - var/turf/T = thing - if(T.blocks_air) - continue + for(var/turf/T as anything in turfs_to_init) T.Initialize_Atmos(times_fired) CHECK_TICK -/turf/simulated/proc/resolve_active_graph() - . = list() - var/datum/excited_group/EG = excited_group - if(blocks_air || !air) - return - if(!EG) - EG = new - EG.add_turf(src) +/datum/controller/subsystem/air/proc/setup_allturfs_sleepless(list/turfs_to_init = block(locate(1, 1, 1), locate(world.maxx, world.maxy, world.maxz))) + for(var/turf/T as anything in turfs_to_init) + T.Initialize_Atmos(times_fired) - for(var/turf/simulated/ET in atmos_adjacent_turfs) - if(ET.blocks_air || !ET.air) - continue +/datum/controller/subsystem/air/proc/setup_write_to_milla() + var/watch = start_watch() + log_startup_progress("Writing tiles to MILLA...") - var/ET_EG = ET.excited_group - if(ET_EG) - if(ET_EG != EG) - EG.merge_groups(ET_EG) - EG = excited_group //merge_groups() may decide to replace our current EG - else - EG.add_turf(ET) - if(!ET.excited) - ET.excited = 1 - . += ET + //cache for sanic speed (lists are references anyways) + var/list/cache = bound_mixtures + var/count = length(cache) + while(length(cache)) + var/datum/gas_mixture/bound_to_turf/mixture = cache[length(cache)] + cache.len-- + if(mixture.dirty) + in_milla_safe_code = TRUE + // This is one of two places expected to call this otherwise-unsafe method. + mixture.private_unsafe_write() + in_milla_safe_code = FALSE + mixture.bound_turf.bound_air = null + mixture.bound_turf = null + CHECK_TICK + + log_startup_progress("Wrote [count] tiles in [stop_watch(watch)]s.") /datum/controller/subsystem/air/proc/setup_atmos_machinery(list/machines_to_init) var/watch = start_watch() @@ -369,7 +459,7 @@ SUBSYSTEM_DEF(air) // pipenet can be built. /datum/controller/subsystem/air/proc/setup_pipenets(list/pipes) var/watch = start_watch() - log_startup_progress("Initializing pipe networks...") + log_startup_progress("Initializing pipe pipenets...") var/count = _setup_pipenets(pipes) log_startup_progress("Initialized [count] pipenets in [stop_watch(watch)]s.") @@ -399,27 +489,110 @@ SUBSYSTEM_DEF(air) GLOB.plmaster = new /obj/effect/overlay/turf/plasma GLOB.slmaster = new /obj/effect/overlay/turf/sleeping_agent -/datum/controller/subsystem/air/proc/throw_error_on_active_roundstart_turfs() - // Can't properly test lavaland due to Init order issues and EVERYTHING being surrounded by rocks, as such we just ignore any turfs on that level - var/list/active_turfs_we_care_about = list() - var/z_level_to_exclude = level_name_to_num(MINING) - for(var/turf/is_lavaland_turf in active_turfs) - if(is_lavaland_turf.z != z_level_to_exclude) - active_turfs_we_care_about += is_lavaland_turf - if(!length(active_turfs_we_care_about)) - return - log_debug("Turfs were active before init! Please check the runtime logger for information on the specific turfs.") - stack_trace("Failed sanity check: active_turfs is not empty before init ([length(active_turfs)], turfs are as follows:)") - for(var/turf/shouldnt_be_active in active_turfs_we_care_about) - stack_trace("[shouldnt_be_active] was active before init, turf x=[shouldnt_be_active.x], turf y=[shouldnt_be_active.y], turf z=[shouldnt_be_active.z], turf area=[shouldnt_be_active.loc]") - message_admins("[shouldnt_be_active] was active before init, [ADMIN_JMP(shouldnt_be_active)])") +/datum/controller/subsystem/air/proc/bind_turf(turf/T, list/milla_tile = null) + var/datum/gas_mixture/bound_to_turf/B = new() + T.bound_air = B + B.bound_turf = T + if(isnull(milla_tile)) + milla_tile = new/list(MILLA_TILE_SIZE) + get_tile_atmos(T, milla_tile) + B.copy_from_milla(milla_tile) + B.lastread = src.times_fired + B.readonly = null + B.dirty = FALSE + B.synchronized = FALSE -#undef SSAIR_PIPENETS -#undef SSAIR_ATMOSMACHINERY -#undef SSAIR_ACTIVETURFS -#undef SSAIR_EXCITEDGROUPS -#undef SSAIR_HIGHPRESSURE -#undef SSAIR_HOTSPOTS -#undef SSAIR_SUPERCONDUCTIVITY + +/// Similar to addtimer, but triggers once MILLA enters synchronous mode. +/datum/controller/subsystem/air/proc/synchronize(datum/milla_safe/CB) + // Any proc that wants MILLA to be synchronous should not sleep. + SHOULD_NOT_SLEEP(TRUE) + + if(is_synchronous) + var/was_safe = SSair.in_milla_safe_code + SSair.in_milla_safe_code = TRUE + // This is one of two intended places to call this otherwise-unsafe proc. + CB.private_unsafe_invoke() + SSair.in_milla_safe_code = was_safe + return + + waiting_for_sync += CB + +/datum/controller/subsystem/air/proc/is_in_milla_safe_code() + return in_milla_safe_code + +/datum/controller/subsystem/air/proc/on_milla_tick_finished() + is_synchronous = TRUE + in_milla_safe_code = TRUE + for(var/datum/milla_safe/CB as anything in waiting_for_sync) + // This is one of two intended places to call this otherwise-unsafe proc. + CB.private_unsafe_invoke() + waiting_for_sync.Cut() + in_milla_safe_code = FALSE + +/proc/milla_tick_finished() + // Any proc that wants MILLA to be synchronous should not sleep. + SHOULD_NOT_SLEEP(TRUE) + + SSair.on_milla_tick_finished() + +/// Create a subclass of this and implement `on_run` to manipulate tile air safely. +/datum/milla_safe + var/run_args = list() + +/// All subclasses should implement this. +/datum/milla_safe/proc/on_run(...) + // Any proc that wants MILLA to be synchronous should not sleep. + SHOULD_NOT_SLEEP(TRUE) + + CRASH("[src.type] does not implement on_run") + +/// Call this to make the subclass run when it's safe to do so. Args will be passed to on_run. +/datum/milla_safe/proc/invoke_async(...) + run_args = args.Copy() + SSair.synchronize(src) + +/// Do not call this yourself. This is what is called to run your code from a safe context. +/datum/milla_safe/proc/private_unsafe_invoke() + soft_assert_safe() + on_run(arglist(run_args)) + +/// Used internally to check that we're running safely, but without breaking things worse if we aren't. +/datum/milla_safe/proc/soft_assert_safe() + ASSERT(SSair.is_in_milla_safe_code()) + +/// Fetch the air for a turf. Only use from `on_run`. +/datum/milla_safe/proc/get_turf_air(turf/T) + RETURN_TYPE(/datum/gas_mixture) + soft_assert_safe() + // This is one of two intended places to call this otherwise-unsafe proc. + var/datum/gas_mixture/bound_to_turf/air = T.private_unsafe_get_air() + if(air.lastread < SSair.times_fired) + var/list/milla_tile = new/list(MILLA_TILE_SIZE) + get_tile_atmos(T, milla_tile) + air.copy_from_milla(milla_tile) + air.lastread = SSair.times_fired + air.readonly = null + air.dirty = FALSE + if(!air.synchronized) + air.synchronized = TRUE + SSair.bound_mixtures += air + return air + +/// Add air to a turf. Only use from `on_run`. +/datum/milla_safe/proc/add_turf_air(turf/T, datum/gas_mixture/air) + var/datum/gas_mixture/turf_air = get_turf_air(T) + turf_air.merge(air) + +/// Completely replace the air for a turf. Only use from `on_run`. +/datum/milla_safe/proc/set_turf_air(turf/T, datum/gas_mixture/air) + var/datum/gas_mixture/turf_air = get_turf_air(T) + turf_air.copy_from(air) #undef SSAIR_DEFERREDPIPENETS +#undef SSAIR_PIPENETS +#undef SSAIR_ATMOSMACHINERY +#undef SSAIR_INTERESTING_TILES +#undef SSAIR_HOTSPOTS +#undef SSAIR_BOUND_MIXTURES +#undef SSAIR_MILLA_TICK diff --git a/code/controllers/subsystem/SSdebugview.dm b/code/controllers/subsystem/SSdebugview.dm index 4d4547f5dd7..f47d7016aaa 100644 --- a/code/controllers/subsystem/SSdebugview.dm +++ b/code/controllers/subsystem/SSdebugview.dm @@ -15,7 +15,7 @@ SUBSYSTEM_DEF(debugview) // Generate debug text var/list/entries = list() entries += "CPU: [round(world.cpu, 1)] | MCPU: [round(world.map_cpu, 1)] | FPS/TPS: [world.fps] | Clients: [length(GLOB.clients)] | BYOND: [world.byond_version].[world.byond_build]" - entries += "\[Air] Cost: [round(SSair.cost, 1)]ms | AT: [length(SSair.active_turfs)]" + entries += "\[Air] Cost: [SSair.get_cost()]ms | MT: [round(SSair.cost_milla_tick, 1)]ms | IT: [SSair.interesting_tile_count]" entries += "\[Debug] Cost: [round(SSdebugview.cost, 1)]ms | P: [length(SSdebugview.processing)]" // meta af (tbf we need to know how much were using) entries += "\[FP] Cost: [round(SSfastprocess.cost, 1)]ms | P: [length(SSfastprocess.processing)]" // Snowflakery for SSgarbage @@ -87,7 +87,7 @@ SUBSYSTEM_DEF(debugview) if((SS.flags & SS_NO_FIRE) || !SS.can_fire) continue - html += "[SS.state_colour()]\[[SS.state_letter()]][SS.ss_id]\t[round(SS.cost, 1)]ms | [round(SS.tick_usage, 1)]% [SS.get_stat_details() ? "| [SS.get_stat_details()] " : ""]| VV Edit" + html += "[SS.state_colour()]\[[SS.state_letter()]][SS.ss_id]\t[SS.get_cost()]ms | [round(SS.tick_usage, 1)]% [SS.get_stat_details() ? "| [SS.get_stat_details()] " : ""]| VV Edit" popup.set_content(html.Join("
")) popup.open(FALSE) diff --git a/code/controllers/subsystem/non_firing/SSmapping.dm b/code/controllers/subsystem/non_firing/SSmapping.dm index cef6d19cb47..2303a11a306 100644 --- a/code/controllers/subsystem/non_firing/SSmapping.dm +++ b/code/controllers/subsystem/non_firing/SSmapping.dm @@ -17,6 +17,9 @@ SUBSYSTEM_DEF(mapping) ///What primary cave theme we have picked for cave generation today. var/cave_theme + /// A mapping of environment names to MILLA environment IDs. + var/list/environments + // This has to be here because world/New() uses [station_name()], which looks this datum up /datum/controller/subsystem/mapping/PreInit() . = ..() @@ -40,6 +43,11 @@ SUBSYSTEM_DEF(mapping) F << next_map.type /datum/controller/subsystem/mapping/Initialize() + environments = list() + environments[ENVIRONMENT_LAVALAND] = create_environment(oxygen = LAVALAND_OXYGEN, nitrogen = LAVALAND_NITROGEN, temperature = LAVALAND_TEMPERATURE) + environments[ENVIRONMENT_TEMPERATE] = create_environment(oxygen = MOLES_O2STANDARD, nitrogen = MOLES_N2STANDARD, temperature = T20C) + environments[ENVIRONMENT_COLD] = create_environment(oxygen = MOLES_O2STANDARD, nitrogen = MOLES_N2STANDARD, temperature = 180) + var/datum/lavaland_theme/lavaland_theme_type = pick(subtypesof(/datum/lavaland_theme)) ASSERT(lavaland_theme_type) lavaland_theme = new lavaland_theme_type diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm index 5cfe3ca970d..00e4479e899 100644 --- a/code/datums/diseases/_disease.dm +++ b/code/datums/diseases/_disease.dm @@ -143,19 +143,20 @@ GLOBAL_LIST_INIT(diseases, subtypesof(/datum/disease)) if(spread_flags & AIRBORNE) spread_range++ - var/turf/T = affected_mob.loc - if(istype(T)) + var/turf/target = affected_mob.loc + if(istype(target)) for(var/mob/living/carbon/C in oview(spread_range, affected_mob)) - var/turf/V = get_turf(C) - if(V) + var/turf/current = get_turf(C) + if(current) while(TRUE) - if(V == T) + if(current == target) C.ContractDisease(src) break - var/turf/Temp = get_step_towards(V, T) - if(!V.CanAtmosPass(Temp)) + var/direction = get_dir(current, target) + var/turf/next = get_step(current, direction) + if(!current.CanAtmosPass(direction) || !next.CanAtmosPass(turn(direction, 180))) break - V = Temp + current = next /datum/disease/proc/cure() diff --git a/code/datums/helper_datums/map_template.dm b/code/datums/helper_datums/map_template.dm index 6ce46ac564c..ebcbc4708f2 100644 --- a/code/datums/helper_datums/map_template.dm +++ b/code/datums/helper_datums/map_template.dm @@ -62,14 +62,14 @@ stack_trace("One of the smoothing corners is bust") catch(var/exception/e) GLOB.space_manager.remove_dirt(placement.z) - late_setup_level(block(bot_left, top_right), block(ST_bot_left, ST_top_right)) + var/datum/milla_safe/late_setup_level/milla = new() + milla.invoke_async(block(bot_left, top_right), block(ST_bot_left, ST_top_right)) message_admins("Map template [name] threw an error while loading. Safe exit attempted, but check for errors at [ADMIN_COORDJMP(placement)].") log_admin("Map template [name] threw an error while loading. Safe exit attempted.") throw e GLOB.space_manager.remove_dirt(placement.z) - late_setup_level( - block(bot_left, top_right), - block(ST_bot_left, ST_top_right)) + var/datum/milla_safe/late_setup_level/milla = new() + milla.invoke_async(block(bot_left, top_right), block(ST_bot_left, ST_top_right)) log_game("[name] loaded at [min_x],[min_y],[placement.z]") return 1 diff --git a/code/datums/weather/weather_types/ash_storm.dm b/code/datums/weather/weather_types/ash_storm.dm index 636dbb3dc60..5fd50d78ba6 100644 --- a/code/datums/weather/weather_types/ash_storm.dm +++ b/code/datums/weather/weather_types/ash_storm.dm @@ -60,7 +60,6 @@ outside_areas += place else inside_areas += place - CHECK_TICK sound_ao.output_atoms = outside_areas sound_ai.output_atoms = inside_areas diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 7b85b1d2b30..365e65123dd 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -276,20 +276,6 @@ L.unEquip(M) M.forceMove(src) -/atom/proc/assume_air(datum/gas_mixture/giver) - qdel(giver) - return null - -/atom/proc/remove_air(amount) - return null - -/atom/proc/return_air() - RETURN_TYPE(/datum/gas_mixture) - if(loc) - return loc.return_air() - else - return null - ///Return the air if we can analyze it /atom/proc/return_analyzable_air() return null diff --git a/code/game/gamemodes/miniantags/guardian/types/gaseous.dm b/code/game/gamemodes/miniantags/guardian/types/gaseous.dm index 63b9ae2a6b6..b1ef225f5b8 100644 --- a/code/game/gamemodes/miniantags/guardian/types/gaseous.dm +++ b/code/game/gamemodes/miniantags/guardian/types/gaseous.dm @@ -41,7 +41,6 @@ var/turf/simulated/target_turf = get_turf(src) if(istype(target_turf)) target_turf.atmos_spawn_air(linda_flags, moles_of_gas) - target_turf.air_update_turf() /mob/living/simple_animal/hostile/guardian/gaseous/ToggleMode() var/picked_gas = tgui_input_list(src, "Select a gas to expel.", "Gas Producer", possible_gases) @@ -68,9 +67,8 @@ if("Agent B") linda_flags = LINDA_SPAWN_AGENT_B | LINDA_SPAWN_20C -/mob/living/simple_animal/hostile/guardian/gaseous/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta) - . = ..() - return FALSE +/mob/living/simple_animal/hostile/guardian/gaseous/experience_pressure_difference(flow_x, flow_y) + return // Immune to gas flow. /mob/living/simple_animal/hostile/guardian/gaseous/death(gibbed) if(summoner) diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm index 71af7f47793..d3530ae4e88 100644 --- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm +++ b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm @@ -792,8 +792,8 @@ /mob/living/simple_animal/demon/pulse_demon/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) return -/mob/living/simple_animal/demon/pulse_demon/experience_pressure_difference() - return // no thanks +/mob/living/simple_animal/demon/pulse_demon/experience_pressure_difference(flow_x, flow_y) + return // Immune to gas flow. /mob/living/simple_animal/demon/pulse_demon/singularity_pull() return diff --git a/code/game/machinery/airlock_control/airlock_controllers.dm b/code/game/machinery/airlock_control/airlock_controllers.dm index 1a229fb8073..fd30655fe80 100644 --- a/code/game/machinery/airlock_control/airlock_controllers.dm +++ b/code/game/machinery/airlock_control/airlock_controllers.dm @@ -153,11 +153,11 @@ //the airlock will not allow itself to continue to cycle when any of the doors are forced open. stop_cycling() + var/turf/T = get_turf(src) + var/chamber_pressure = T.get_readonly_air().return_pressure() switch(state) if(CONTROL_STATE_PREPARE) if(check_doors_secured()) - var/chamber_pressure = return_air().return_pressure() - if(chamber_pressure <= target_pressure) state = CONTROL_STATE_PRESSURIZE signalPumps(TRUE, TRUE, target_pressure) //send a signal to start pressurizing @@ -171,7 +171,7 @@ target_pressure = ONE_ATMOSPHERE * 0.05 if(CONTROL_STATE_PRESSURIZE) - if(return_air().return_pressure() >= (target_pressure * 0.95)) + if(chamber_pressure >= (target_pressure * 0.95)) cycleDoors(target_state) state = CONTROL_STATE_IDLE @@ -181,7 +181,7 @@ if(CONTROL_STATE_DEPRESSURIZE) - if(return_air().return_pressure() <= (target_pressure * 1.05)) + if(chamber_pressure <= (target_pressure * 1.05)) cycleDoors(target_state) state = CONTROL_STATE_IDLE @@ -393,7 +393,9 @@ send an additional command to open the door again. /obj/machinery/airlock_controller/air_cycler/ui_data(mob/user) var/list/data = list() - data["chamber_pressure"] = round(return_air().return_pressure()) + var/turf/T = get_turf(src) + var/chamber_pressure = T.get_readonly_air().return_pressure() + data["chamber_pressure"] = round(chamber_pressure, 1) data["exterior_status"] = (check_doors_match_state_uid(exterior_doors, "closed") ? "closed" : "open") data["interior_status"] = (check_doors_match_state_uid(interior_doors, "closed") ? "closed" : "open") data["processing"] = (state != target_state) diff --git a/code/game/machinery/computer/atmos_controllers.dm b/code/game/machinery/computer/atmos_controllers.dm index 2a8286e2eaf..cb1d2638e43 100644 --- a/code/game/machinery/computer/atmos_controllers.dm +++ b/code/game/machinery/computer/atmos_controllers.dm @@ -223,7 +223,8 @@ GLOBAL_LIST_EMPTY(gas_sensors) // Cache here to avoid a ton of list lookups var/obj/machinery/atmospherics/air_sensor/AS = AM var/list/sensor_data = sensor_name_data_map[sensor_name] - var/datum/gas_mixture/air_sample = AS.return_air() + var/turf/T = get_turf(AS) + var/datum/gas_mixture/air_sample = T.get_readonly_air() // We remove it from the list incase sensor reporting is ever disabled // We only want to show the information available @@ -233,7 +234,7 @@ GLOBAL_LIST_EMPTY(gas_sensors) sensor_data -= "pressure" if(AS.output & SENSOR_TEMPERATURE) - sensor_data["temperature"] = air_sample.return_temperature() + sensor_data["temperature"] = air_sample.temperature() else sensor_data -= "temperature" @@ -241,27 +242,27 @@ GLOBAL_LIST_EMPTY(gas_sensors) if(total_moles > 0) if(AS.output & SENSOR_O2) - sensor_data["o2"] = round(100 * air_sample.oxygen / total_moles, 0.1) + sensor_data["o2"] = round(100 * air_sample.oxygen() / total_moles, 0.1) else sensor_data -= "o2" if(AS.output & SENSOR_PLASMA) - sensor_data["plasma"] = round(100 * air_sample.toxins / total_moles, 0.1) + sensor_data["plasma"] = round(100 * air_sample.toxins() / total_moles, 0.1) else sensor_data -= "plasma" if(AS.output & SENSOR_N2) - sensor_data["n2"] = round(100 * air_sample.nitrogen / total_moles, 0.1) + sensor_data["n2"] = round(100 * air_sample.nitrogen() / total_moles, 0.1) else sensor_data -= "n2" if(AS.output & SENSOR_CO2) - sensor_data["co2"] = round(100 * air_sample.carbon_dioxide / total_moles, 0.1) + sensor_data["co2"] = round(100 * air_sample.carbon_dioxide() / total_moles, 0.1) else sensor_data -= "co2" if(AS.output & SENSOR_N2O) - sensor_data["n2o"] = round(100 * air_sample.sleeping_agent / total_moles, 0.1) + sensor_data["n2o"] = round(100 * air_sample.sleeping_agent() / total_moles, 0.1) else sensor_data -= "n2o" @@ -269,10 +270,10 @@ GLOBAL_LIST_EMPTY(gas_sensors) var/list/meter_data = sensor_name_data_map[sensor_name] var/obj/machinery/atmospherics/meter/the_meter = AM if(the_meter.target) - var/datum/gas_mixture/meter_env = the_meter.target.return_air() + var/datum/gas_mixture/meter_env = the_meter.target.return_obj_air() if(meter_env) meter_data["pressure"] = meter_env.return_pressure() - meter_data["temperature"] = meter_env.return_temperature() + meter_data["temperature"] = meter_env.temperature() /obj/machinery/computer/general_air_control/process() diff --git a/code/game/machinery/computer/sm_monitor.dm b/code/game/machinery/computer/sm_monitor.dm index 443443dabd1..8abbfa6b9a1 100644 --- a/code/game/machinery/computer/sm_monitor.dm +++ b/code/game/machinery/computer/sm_monitor.dm @@ -44,7 +44,7 @@ active = null refresh() return - var/datum/gas_mixture/air = T.return_air() + var/datum/gas_mixture/air = T.get_readonly_air() if(!air) active = null return @@ -52,18 +52,18 @@ data["active"] = TRUE data["SM_integrity"] = active.get_integrity() data["SM_power"] = active.power - data["SM_ambienttemp"] = air.temperature + data["SM_ambienttemp"] = air.temperature() data["SM_ambientpressure"] = air.return_pressure() //data["SM_EPR"] = round((air.total_moles / air.group_multiplier) / 23.1, 0.01) var/list/gasdata = list() var/TM = air.total_moles() if(TM) - gasdata.Add(list(list("name"= "Oxygen", "amount" = round(100 * air.oxygen / TM, 0.01)))) - gasdata.Add(list(list("name"= "Carbon Dioxide", "amount" = round(100 * air.carbon_dioxide / TM, 0.01)))) - gasdata.Add(list(list("name"= "Nitrogen", "amount" = round(100 * air.nitrogen / TM, 0.01)))) - gasdata.Add(list(list("name"= "Plasma", "amount" = round(100 * air.toxins / TM, 0.01)))) - gasdata.Add(list(list("name"= "Nitrous Oxide", "amount" = round(100 * air.sleeping_agent / TM, 0.01)))) - gasdata.Add(list(list("name"= "Agent B", "amount" = round(100 * air.agent_b / TM, 0.01)))) + gasdata.Add(list(list("name"= "Oxygen", "amount" = round(100 * air.oxygen() / TM, 0.01)))) + gasdata.Add(list(list("name"= "Carbon Dioxide", "amount" = round(100 * air.carbon_dioxide() / TM, 0.01)))) + gasdata.Add(list(list("name"= "Nitrogen", "amount" = round(100 * air.nitrogen() / TM, 0.01)))) + gasdata.Add(list(list("name"= "Plasma", "amount" = round(100 * air.toxins() / TM, 0.01)))) + gasdata.Add(list(list("name"= "Nitrous Oxide", "amount" = round(100 * air.sleeping_agent() / TM, 0.01)))) + gasdata.Add(list(list("name"= "Agent B", "amount" = round(100 * air.agent_b() / TM, 0.01)))) else gasdata.Add(list(list("name"= "Oxygen", "amount" = 0))) gasdata.Add(list(list("name"= "Carbon Dioxide", "amount" = 0))) diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index e6bd12e67c3..e524f50d8c2 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1291,7 +1291,7 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays) density = FALSE if(width > 1) set_fillers_density(FALSE) - air_update_turf(1) + recalculate_atmos_connectivity() sleep(1) layer = OPEN_DOOR_LAYER update_icon(AIRLOCK_OPEN, 1) @@ -1333,7 +1333,7 @@ GLOBAL_LIST_EMPTY(airlock_emissive_underlays) density = TRUE if(width > 1) set_fillers_density(TRUE) - air_update_turf(1) + recalculate_atmos_connectivity() if(!override) sleep(4) if(!safe) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 0e8f172e04a..3a563f347bc 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -48,6 +48,9 @@ var/polarized_glass = FALSE var/polarized_on + /// How much this door reduces superconductivity to when closed. + var/superconductivity = DOOR_HEAT_TRANSFER_COEFFICIENT + /obj/machinery/door/Initialize(mapload) . = ..() set_init_door_layer() @@ -64,7 +67,7 @@ explosion_block = EXPLOSION_BLOCK_PROC update_icon() - air_update_turf(1) + recalculate_atmos_connectivity() /obj/machinery/door/proc/set_init_door_layer() if(density) @@ -83,7 +86,7 @@ /obj/machinery/door/Destroy() density = FALSE - air_update_turf(1) + recalculate_atmos_connectivity() update_freelook_sight() GLOB.airlocks -= src QDEL_NULL(spark_system) @@ -134,9 +137,14 @@ return !opacity return !density -/obj/machinery/door/CanAtmosPass() +/obj/machinery/door/CanAtmosPass(direction) return !density +/obj/machinery/door/get_superconductivity(direction) + if(density) + return superconductivity + return ..() + /obj/machinery/door/proc/bumpopen(mob/user) if(operating) return @@ -367,7 +375,7 @@ if(width > 1) set_fillers_opacity(0) operating = NONE - air_update_turf(1) + recalculate_atmos_connectivity() update_freelook_sight() if(autoclose) autoclose_in(normalspeed ? auto_close_time : auto_close_time_dangerous) @@ -402,7 +410,7 @@ if(width > 1) set_fillers_opacity(TRUE) operating = NONE - air_update_turf(1) + recalculate_atmos_connectivity() update_freelook_sight() if(safe) CheckForMobs() @@ -450,10 +458,11 @@ if(!glass && GLOB.cameranet) GLOB.cameranet.updateVisibility(src, 0) -/obj/machinery/door/BlockSuperconductivity() // Only heatproof airlocks block heat, currently only varedited doors have this - if(heat_proof) - return 1 - return 0 +/obj/machinery/door/get_superconductivity(direction) + // Only heatproof airlocks block heat, currently only varedited doors have this + if(heat_proof && density) + return FALSE + return ..() /obj/machinery/door/proc/check_unres() //unrestricted sides. This overlay indicates which directions the player can access even without an ID if(hasPower() && unres_sides) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 00defea21fb..bee8a313d29 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -23,6 +23,7 @@ assemblytype = /obj/structure/firelock_frame blocks_emissive = EMISSIVE_BLOCK_GENERIC armor = list(MELEE = 30, BULLET = 30, LASER = 20, ENERGY = 20, BOMB = 10, RAD = 100, FIRE = 95, ACID = 70) + superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT /// How long does opening by hand take, in deciseconds. var/manual_open_time = 5 SECONDS var/can_crush = TRUE @@ -321,13 +322,17 @@ if(get_dir(loc, target) == dir) return !density else - return 1 + return TRUE -/obj/machinery/door/firedoor/border_only/CanAtmosPass(turf/T) - if(get_dir(loc, T) == dir) +/obj/machinery/door/firedoor/border_only/CanAtmosPass(direction) + if(direction == dir) return !density - else - return 1 + return TRUE + +/obj/machinery/door/firedoor/border_only/get_superconductivity(direction) + if(direction == dir && density) + return FALSE + return ..() /obj/machinery/door/firedoor/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) ..() diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index 411214d3a59..46778d0243a 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -12,6 +12,7 @@ integrity_failure = 0 armor = list(MELEE = 20, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 10, RAD = 100, FIRE = 70, ACID = 100) glass = TRUE // Used by polarized helpers. Windoors are always glass. + superconductivity = WINDOW_HEAT_TRANSFER_COEFFICIENT var/obj/item/airlock_electronics/electronics var/base_state = "left" var/reinf = FALSE @@ -159,13 +160,13 @@ else if(istype(mover, /obj/machinery/door/window) && !valid_window_location(loc, mover.dir)) return FALSE else - return 1 + return TRUE -/obj/machinery/door/window/CanAtmosPass(turf/T) - if(get_dir(loc, T) == dir) +/obj/machinery/door/window/CanAtmosPass(direction) + if(direction == dir) return !density else - return 1 + return TRUE //used in the AStar algorithm to determinate if the turf the door is on is passable /obj/machinery/door/window/CanPathfindPass(obj/item/card/id/ID, to_dir, no_id = FALSE) @@ -202,7 +203,7 @@ density = FALSE // sd_set_opacity(0) //TODO: why is this here? Opaque windoors? ~Carn - air_update_turf(1) + recalculate_atmos_connectivity() update_freelook_sight() if(operating) //emag again @@ -226,7 +227,7 @@ density = TRUE if(polarized_on) set_opacity(TRUE) - air_update_turf(1) + recalculate_atmos_connectivity() update_freelook_sight() sleep(10) diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm index 4fd9c886d92..bd9f7066f8c 100644 --- a/code/game/machinery/shieldgen.dm +++ b/code/game/machinery/shieldgen.dm @@ -14,12 +14,12 @@ /obj/machinery/shield/Initialize(mapload) . = ..() dir = pick(NORTH, SOUTH, EAST, WEST) - air_update_turf(1) + recalculate_atmos_connectivity() /obj/machinery/shield/Destroy() opacity = FALSE density = FALSE - air_update_turf(1) + recalculate_atmos_connectivity() return ..() /obj/machinery/shield/Move() @@ -32,7 +32,7 @@ return FALSE return ..() -/obj/machinery/shield/CanAtmosPass(turf/T) +/obj/machinery/shield/CanAtmosPass(direction) return !density /obj/machinery/shield/ex_act(severity) @@ -120,7 +120,7 @@ invisibility = INVISIBILITY_MAXIMUM visible = FALSE - air_update_turf(1) + recalculate_atmos_connectivity() return visible /obj/machinery/shieldgen diff --git a/code/game/machinery/snow_machine.dm b/code/game/machinery/snow_machine.dm index dee2ceb914c..a880654452f 100644 --- a/code/game/machinery/snow_machine.dm +++ b/code/game/machinery/snow_machine.dm @@ -76,12 +76,30 @@ return for(var/turf/TF in range(1, src)) if(issimulatedturf(TF)) - var/turf/simulated/S = TF - affect_turf_temperature(S, cooling_speed) + var/datum/milla_safe/snow_machine_cooling/milla = new() + milla.invoke_async(src, cooling_speed) if(prob(50)) continue make_snowcloud(TF) +/datum/milla_safe/snow_machine_cooling + +/datum/milla_safe/snow_machine_cooling/on_run(obj/machinery/snow_machine/snowy, modifier) + var/turf/T = get_turf(snowy) + var/datum/gas_mixture/env = get_turf_air(T) + + if(!issimulatedturf(T) || T.density) + return + + var/initial_temperature = env.temperature() + if(initial_temperature <= snowy.lower_temperature_limit) //Can we actually cool this? + return + var/old_thermal_energy = env.thermal_energy() + var/amount_cooled = initial_temperature - modifier * 8000 / env.heat_capacity() + env.set_temperature(max(amount_cooled, snowy.lower_temperature_limit)) + var/new_thermal_energy = env.thermal_energy() + snowy.power_used_this_cycle += (old_thermal_energy - new_thermal_energy) / 100 + /obj/machinery/snow_machine/power_change() if(!..()) return @@ -95,29 +113,13 @@ else icon_state = "snow_machine_[active ? "on" : "off"]" -/obj/machinery/snow_machine/proc/affect_turf_temperature(turf/T, modifier) - if(!issimulatedturf(T) || T.density) - return - var/turf/simulated/S = T - var/initial_temperature = S.air.temperature - if(initial_temperature <= lower_temperature_limit) //Can we actually cool this? - return - var/old_thermal_energy = S.air.thermal_energy() - var/amount_cooled = initial_temperature - modifier * 8000 / S.air.heat_capacity() - S.air.temperature = max(amount_cooled, lower_temperature_limit) - air_update_turf() - var/new_thermal_energy = S.air.thermal_energy() - power_used_this_cycle += (old_thermal_energy - new_thermal_energy) / 100 - /obj/machinery/snow_machine/proc/make_snowcloud(turf/T) if(isspaceturf(T)) return if(T.density) return - if(issimulatedturf(T)) - var/turf/simulated/S = T - if(S.air.temperature > T0C + 1) - return + if(T.get_readonly_air().temperature() > T0C + 1) + return if(locate(/obj/effect/snowcloud, T)) //Ice to see you return if(infinite_snow || !reagents.remove_reagent(reagents.get_master_reagent_id(), 3)) diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index 667c27a3710..d02de4a3863 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -163,27 +163,35 @@ /obj/machinery/space_heater/process() - if(on) - if(cell && cell.charge > 0) - var/turf/simulated/L = loc - if(istype(L)) - var/datum/gas_mixture/env = L.return_air() - if(env.temperature != set_temperature + T0C) - var/transfer_moles = 0.25 * env.total_moles() + var/datum/milla_safe/space_heater_process/milla = new() + milla.invoke_async(src) - var/datum/gas_mixture/removed = env.remove(transfer_moles) +/datum/milla_safe/space_heater_process - if(removed) - var/heat_capacity = removed.heat_capacity() +/datum/milla_safe/space_heater_process/on_run(obj/machinery/space_heater/heater) + if(heater.on) + if(heater.cell && heater.cell.charge > 0) + var/turf/simulated/L = get_turf(heater) + if(!istype(L)) + return + var/datum/gas_mixture/env = get_turf_air(L) + if(env.temperature() == heater.set_temperature + T0C) + return + var/transfer_moles = 0.25 * env.total_moles() - if(heat_capacity) // Added check to avoid divide by zero (oshi-) runtime errors -- TLE - if(removed.temperature < set_temperature + T0C) - removed.temperature = min(removed.temperature + heating_power/heat_capacity, 1000) // Added min() check to try and avoid wacky superheating issues in low gas scenarios -- TLE - else - removed.temperature = max(removed.temperature - heating_power/heat_capacity, TCMB) - cell.use(heating_power/20000) - 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) + if(removed.temperature() < heater.set_temperature + T0C) + removed.set_temperature(min(removed.temperature() + heater.heating_power / heat_capacity, 1000)) + else + removed.set_temperature(max(removed.temperature() - heater.heating_power / heat_capacity, TCMB)) + heater.cell.use(heater.heating_power / 20000) + env.merge(removed) else - on = FALSE - update_icon() + heater.on = FALSE + heater.update_icon() diff --git a/code/game/mecha/combat/honker.dm b/code/game/mecha/combat/honker.dm index 6d54e9dc01a..c6f7da80db9 100644 --- a/code/game/mecha/combat/honker.dm +++ b/code/game/mecha/combat/honker.dm @@ -34,7 +34,7 @@ var/cell_charge = get_charge() var/tank_pressure = internal_tank ? round(internal_tank.return_pressure(),0.01) : "None" var/tank_temperature = internal_tank ? internal_tank.return_temperature() : "Unknown" - var/cabin_pressure = round(return_pressure(),0.01) + var/cabin_pressure = round(cabin_air.return_pressure(),0.01) var/output = {"[report_internal_damage()] [integrity<30?"DAMAGE LEVEL CRITICAL
":null] [internal_damage&MECHA_INT_TEMP_CONTROL?"CLOWN SUPPORT SYSTEM MALFUNCTION
":null] @@ -46,7 +46,7 @@ AirHONK pressure: [tank_pressure]kPa
AirHONK temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
HONK pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
- HONK temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
+ HONK temperature: [cabin_air.temperature()]°K|[cabin_air.temperature() - T0C]°C
Lights: [lights?"on":"off"]
[dna?"DNA-locked:
[dna] \[Reset\]
":null] "} diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm index c4d9484ad1f..7b7976c79c0 100644 --- a/code/game/mecha/equipment/tools/work_tools.dm +++ b/code/game/mecha/equipment/tools/work_tools.dm @@ -245,7 +245,7 @@ if(do_after_cooldown(F)) chassis.spark_system.start() F.ChangeTurf(F.baseturf) - F.air_update_turf() + F.recalculate_atmos_connectivity() playsound(F, usesound, 50, 1) else if(istype(target, /obj/machinery/door/airlock)) occupant_message("Deconstructing [target]...") diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index d398cc1c870..94eebd80efb 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -167,10 +167,10 @@ /obj/mecha/proc/add_cabin() cabin_air = new - cabin_air.temperature = T20C + cabin_air.set_temperature(T20C) cabin_air.volume = 200 - cabin_air.oxygen = O2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) - cabin_air.nitrogen = N2STANDARD*cabin_air.volume/(R_IDEAL_GAS_EQUATION*cabin_air.temperature) + cabin_air.set_oxygen(O2STANDARD * cabin_air.volume / (R_IDEAL_GAS_EQUATION * cabin_air.temperature())) + cabin_air.set_nitrogen(N2STANDARD * cabin_air.volume / (R_IDEAL_GAS_EQUATION * cabin_air.temperature())) return cabin_air /obj/mecha/proc/add_radio() @@ -658,9 +658,9 @@ QDEL_NULL(internal_tank) QDEL_NULL(radio) GLOB.poi_list.Remove(src) - if(loc) - loc.assume_air(cabin_air) - air_update_turf() + var/turf/T = get_turf(src) + if(T) + T.blind_release_air(cabin_air) else qdel(cabin_air) cabin_air = null @@ -1031,41 +1031,17 @@ //////// MARK: Atmospheric stuff ///////////////////////////////////// -/obj/mecha/proc/get_turf_air() - var/turf/T = get_turf(src) - if(T) - . = T.return_air() - -/obj/mecha/remove_air(amount) - if(use_internal_tank) - return cabin_air.remove(amount) - else - var/turf/T = get_turf(src) - if(T) - return T.remove_air(amount) - -/obj/mecha/return_air() +/obj/mecha/return_obj_air() RETURN_TYPE(/datum/gas_mixture) if(use_internal_tank) return cabin_air - return get_turf_air() + return null /obj/mecha/return_analyzable_air() if(use_internal_tank) return cabin_air return null -/obj/mecha/proc/return_pressure() - var/datum/gas_mixture/t_air = return_air() - if(t_air) - . = t_air.return_pressure() - -//skytodo: //No idea what you want me to do here, mate. -/obj/mecha/proc/return_temperature() - var/datum/gas_mixture/t_air = return_air() - if(t_air) - . = t_air.return_temperature() - /obj/mecha/proc/connect(obj/machinery/atmospherics/unary/portables_connector/new_port) //Make sure not already connected to something else if(connected_port || !istype(new_port) || new_port.connected_device) @@ -1099,7 +1075,7 @@ return TRUE /obj/mecha/portableConnectorReturnAir() - return internal_tank.return_air() + return internal_tank.return_obj_air() /obj/mecha/proc/toggle_lights(show_message = TRUE) lights = !lights @@ -1457,25 +1433,25 @@ if(!(internal_damage & MECHA_INT_TEMP_CONTROL) && prob(5)) clearInternalDamage(MECHA_INT_FIRE) if(internal_tank) - var/datum/gas_mixture/int_tank_air = internal_tank.return_air() + var/datum/gas_mixture/int_tank_air = internal_tank.return_obj_air() if(int_tank_air.return_pressure() > internal_tank.maximum_pressure && !(internal_damage & MECHA_INT_TANK_BREACH)) setInternalDamage(MECHA_INT_TANK_BREACH) if(int_tank_air && int_tank_air.return_volume() > 0) - int_tank_air.temperature = min(6000 + T0C, cabin_air.return_temperature() + rand(10, 15)) + int_tank_air.set_temperature(min(6000 + T0C, cabin_air.temperature() + rand(10, 15))) - if(cabin_air && cabin_air.return_volume()>0) - cabin_air.temperature = min(6000+T0C, cabin_air.return_temperature()+rand(10,15)) - if(cabin_air.return_temperature() > max_temperature/2) - take_damage(4/round(max_temperature/cabin_air.return_temperature(),0.1), BURN, 0, 0) + if(cabin_air && cabin_air.return_volume() > 0) + cabin_air.set_temperature(min(6000 + T0C, cabin_air.temperature() + rand(10, 15))) + if(cabin_air.temperature() > max_temperature / 2) + take_damage(4 / round(max_temperature / cabin_air.temperature(), 0.1), BURN, 0, 0) if(internal_damage & MECHA_INT_TANK_BREACH) //remove some air from internal tank if(internal_tank) - var/datum/gas_mixture/int_tank_air = internal_tank.return_air() + var/datum/gas_mixture/int_tank_air = internal_tank.return_obj_air() var/datum/gas_mixture/leaked_gas = int_tank_air.remove_ratio(0.10) - if(loc) - loc.assume_air(leaked_gas) - air_update_turf() + var/turf/T = get_turf(src) + if(T) + T.blind_release_air(leaked_gas) else qdel(leaked_gas) @@ -1485,41 +1461,51 @@ cell.charge -= min(20,cell.charge) cell.maxcharge -= min(20,cell.maxcharge) +/obj/mecha/proc/release_gas(datum/gas_mixture/environment, datum/gas_mixture/leaked_gas) + // Any proc that wants MILLA to be synchronous should not sleep. + SHOULD_NOT_SLEEP(TRUE) + + environment.merge(leaked_gas) + /obj/mecha/proc/regulate_temp() if(internal_damage & MECHA_INT_TEMP_CONTROL) return if(cabin_air && cabin_air.return_volume() > 0) - var/delta = cabin_air.temperature - T20C - cabin_air.temperature -= max(-10, min(10, round(delta / 4, 0.1))) + var/delta = cabin_air.temperature() - T20C + cabin_air.set_temperature(cabin_air.temperature() - max(-10, min(10, round(delta / 4, 0.1)))) /obj/mecha/proc/give_air() if(!internal_tank) return - var/datum/gas_mixture/tank_air = internal_tank.return_air() + var/datum/gas_mixture/tank_air = internal_tank.return_obj_air() var/release_pressure = internal_tank_valve var/cabin_pressure = cabin_air.return_pressure() var/pressure_delta = min(release_pressure - cabin_pressure, (tank_air.return_pressure() - cabin_pressure)/2) var/transfer_moles = 0 if(pressure_delta > 0) //cabin pressure lower than release pressure - if(tank_air.return_temperature() > 0) - transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + if(tank_air.temperature() > 0) + transfer_moles = pressure_delta*cabin_air.return_volume() / (cabin_air.temperature() * R_IDEAL_GAS_EQUATION) var/datum/gas_mixture/removed = tank_air.remove(transfer_moles) cabin_air.merge(removed) else if(pressure_delta < 0) //cabin pressure higher than release pressure - var/datum/gas_mixture/t_air = return_air() + var/datum/gas_mixture/active_tank_air = return_obj_air() pressure_delta = cabin_pressure - release_pressure - if(t_air) - pressure_delta = min(cabin_pressure - t_air.return_pressure(), pressure_delta) + if(active_tank_air) + pressure_delta = min(cabin_pressure - active_tank_air.return_pressure(), pressure_delta) if(pressure_delta > 0) //if location pressure is lower than cabin pressure - transfer_moles = pressure_delta*cabin_air.return_volume()/(cabin_air.return_temperature() * R_IDEAL_GAS_EQUATION) + transfer_moles = pressure_delta * cabin_air.return_volume() / (cabin_air.temperature() * R_IDEAL_GAS_EQUATION) var/datum/gas_mixture/removed = cabin_air.remove(transfer_moles) - if(t_air) - t_air.merge(removed) - else //just delete the cabin gas, we're in space or some shit - qdel(removed) + if(active_tank_air) + active_tank_air.merge(removed) + else + var/turf/T = get_turf(src) + if(T) + T.blind_release_air(removed) + else + qdel(removed) /obj/mecha/proc/update_huds() diag_hud_set_mechhealth() diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm index 72c9272cb1b..24b8de4ee38 100644 --- a/code/game/mecha/mecha_control_console.dm +++ b/code/game/mecha/mecha_control_console.dm @@ -100,7 +100,7 @@ else answer["cell"] = 0 answer["integrity"] = round((M.obj_integrity/M.max_integrity*100), 0.01) - answer["airtank"] = M.return_pressure() + answer["airtank"] = M.internal_tank.return_pressure() answer["pilot"] = "[M.occupant||"None"]" var/area/area = get_area(M) answer["location"] = "[sanitize(area.name)||"Unknown"]" @@ -121,7 +121,7 @@ var/answer = {"Name: [M.name] Integrity: [M.obj_integrity / M.max_integrity * 100]% Cell charge: [isnull(cell_charge)?"Not found":"[M.cell.percent()]%"] - Airtank: [M.return_pressure()]kPa + Airtank: [M.internal_tank.return_pressure()]kPa Pilot: [M.occupant||"None"] Location: [sanitize(A.name)||"Unknown"] Active equipment: [M.selected||"None"]
"} @@ -145,7 +145,7 @@ if(M.cell) data["cellCharge"] = M.cell.charge data["cellMaxCharge"] = M.cell.maxcharge - data["airtank"] = M.return_pressure() + data["airtank"] = M.internal_tank.return_pressure() data["pilot"] = M.occupant data["location"] = get_area(M) data["active"] = M.selected diff --git a/code/game/mecha/mecha_topic.dm b/code/game/mecha/mecha_topic.dm index c41573b8b44..b00cd44314b 100644 --- a/code/game/mecha/mecha_topic.dm +++ b/code/game/mecha/mecha_topic.dm @@ -63,7 +63,7 @@ if(hasInternalDamage(intdamflag)) output += dam_reports[tflag] output += "
" - if(return_pressure() > WARNING_HIGH_PRESSURE) + if(cabin_air.return_pressure() > WARNING_HIGH_PRESSURE) output += "DANGEROUSLY HIGH CABIN PRESSURE
" return output @@ -74,7 +74,7 @@ var/tank_pressure = internal_tank ? round(internal_tank.return_pressure(),0.01) : "None" var/tank_temperature = internal_tank ? internal_tank.return_temperature() : "Unknown" var/tank_temperature_c = internal_tank ? internal_tank.return_temperature() - T0C : "Unknown" - var/cabin_pressure = round(return_pressure(),0.01) + var/cabin_pressure = round(cabin_air.return_pressure(), 0.01) . = "[report_internal_damage()]" . += "[integrity<30?"DAMAGE LEVEL CRITICAL
":null]" . += "Integrity: [integrity]%
" @@ -83,7 +83,7 @@ . += "Airtank pressure: [tank_pressure]kPa
" . += "Airtank temperature: [tank_temperature]°K|[tank_temperature_c]°C
" . += "Cabin pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
" - . += "Cabin temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
" + . += "Cabin temperature: [cabin_air.temperature()]°K|[cabin_air.temperature() - T0C]°C
" . += "Lights: [lights?"on":"off"]
" . += "[dna ? "DNA-locked:
[dna] \[Reset\]
" : ""]" . += "[defense_action.owner ? "Defence Mode: [defence_mode ? "Enabled" : "Disabled"]
" : ""]" diff --git a/code/game/objects/effects/anomalies.dm b/code/game/objects/effects/anomalies.dm index f3a3eab8320..d94e36e03aa 100644 --- a/code/game/objects/effects/anomalies.dm +++ b/code/game/objects/effects/anomalies.dm @@ -355,7 +355,11 @@ ticks = 0 var/turf/simulated/T = get_turf(src) if(istype(T)) - T.atmos_spawn_air(LINDA_SPAWN_HEAT | LINDA_SPAWN_TOXINS | LINDA_SPAWN_OXYGEN, 20) + var/datum/gas_mixture/air = new() + air.set_temperature(1000) + air.set_toxins(20) + air.set_oxygen(20) + T.blind_release_air(air) /obj/effect/anomaly/pyro/detonate() if(produces_slime) @@ -364,7 +368,12 @@ /obj/effect/anomaly/pyro/proc/makepyroslime() var/turf/simulated/T = get_turf(src) if(istype(T)) - T.atmos_spawn_air(LINDA_SPAWN_HEAT | LINDA_SPAWN_TOXINS | LINDA_SPAWN_OXYGEN, 500) //Make it hot and burny for the new slime + //Make it hot and burny for the new slime + var/datum/gas_mixture/air = new() + air.set_temperature(1000) + air.set_toxins(500) + air.set_oxygen(500) + T.blind_release_air(air) var/new_colour = pick("red", "orange") var/mob/living/simple_animal/slime/S = new(T, new_colour) S.rabid = TRUE @@ -409,7 +418,11 @@ var/turf/simulated/T = get_turf(src) if(istype(T)) - T.atmos_spawn_air(LINDA_SPAWN_COLD | LINDA_SPAWN_N2O | LINDA_SPAWN_CO2, 20) + var/datum/gas_mixture/air = new() + air.set_temperature(TCMB) + air.set_sleeping_agent(20) + air.set_carbon_dioxide(20) + T.blind_release_air(air) if(prob(10)) var/obj/effect/nanofrost_container/A = new /obj/effect/nanofrost_container(get_turf(src)) @@ -436,7 +449,11 @@ /obj/effect/anomaly/cryo/detonate() var/turf/simulated/T = get_turf(src) if(istype(T) && drops_core) - T.atmos_spawn_air(LINDA_SPAWN_COLD | LINDA_SPAWN_CO2, 1000) + var/datum/gas_mixture/air = new() + air.set_temperature(TCMB) + air.set_sleeping_agent(1000) + air.set_carbon_dioxide(1000) + T.blind_release_air(air) ///////////////////// diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm index e426e2fbbbd..e058c3c0efc 100644 --- a/code/game/objects/effects/effect_system/effects_foam.dm +++ b/code/game/objects/effects/effect_system/effects_foam.dm @@ -178,12 +178,12 @@ /obj/structure/foamedmetal/Initialize() . = ..() - air_update_turf(1) + recalculate_atmos_connectivity() /obj/structure/foamedmetal/Destroy() var/turf/T = get_turf(src) . = ..() - T.air_update_turf(TRUE) + T.recalculate_atmos_connectivity() /obj/structure/foamedmetal/Move() var/turf/T = loc @@ -221,5 +221,5 @@ /obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target) return !density -/obj/structure/foamedmetal/CanAtmosPass() +/obj/structure/foamedmetal/CanAtmosPass(direction) return !density diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm index f813ae88e22..ca60beb0ca6 100644 --- a/code/game/objects/effects/effect_system/effects_smoke.dm +++ b/code/game/objects/effects/effect_system/effects_smoke.dm @@ -152,16 +152,9 @@ /datum/effect_system/smoke_spread/freezing/proc/Chilled(atom/A) if(issimulatedturf(A)) var/turf/simulated/T = A - if(T.air) - var/datum/gas_mixture/G = T.air - if(get_dist(T, src) < 2) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air - G.temperature = 2 - T.air_update_turf() - for(var/obj/effect/hotspot/H in T) - qdel(H) - if(G.toxins) - G.nitrogen += (G.toxins) - G.toxins = 0 + if(!T.blocks_air) + var/datum/milla_safe/smoke_spread_chill/milla = new() + milla.invoke_async(src, T) for(var/obj/machinery/atmospherics/unary/vent_pump/V in T) if(!isnull(V.welded) && !V.welded) //must be an unwelded vent pump. V.welded = TRUE @@ -177,6 +170,18 @@ for(var/obj/item/Item in T) Item.extinguish() +/datum/milla_safe/smoke_spread_chill + +/datum/milla_safe/smoke_spread_chill/on_run(datum/effect_system/smoke_spread/smoke, turf/T) + var/datum/gas_mixture/env = get_turf_air(T) + if(get_dist(T, smoke) < 2) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air + env.set_temperature(2) + for(var/obj/effect/hotspot/H in T) + qdel(H) + if(env.toxins()) + env.set_nitrogen(env.nitrogen() + env.toxins()) + env.set_toxins(0) + /datum/effect_system/smoke_spread/freezing/set_up(amount = 5, only_cardinals = FALSE, source, desired_direction, datum/reagents/chemicals, blasting = FALSE) ..() blast = blasting diff --git a/code/game/objects/effects/effects.dm b/code/game/objects/effects/effects.dm index cbf3f46175a..60107130674 100644 --- a/code/game/objects/effects/effects.dm +++ b/code/game/objects/effects/effects.dm @@ -31,8 +31,8 @@ /obj/effect/blob_act(obj/structure/blob/B) return -/obj/effect/experience_pressure_difference() - return +/obj/effect/experience_pressure_difference(flow_x, flow_y) + return // Immune to gas flow. /obj/effect/ex_act(severity) switch(severity) diff --git a/code/game/objects/effects/forcefields.dm b/code/game/objects/effects/forcefields.dm index 85ad204b556..32637ebc05f 100644 --- a/code/game/objects/effects/forcefields.dm +++ b/code/game/objects/effects/forcefields.dm @@ -12,7 +12,7 @@ if(lifetime) QDEL_IN(src, lifetime) -/obj/effect/forcefield/CanAtmosPass(turf/T) +/obj/effect/forcefield/CanAtmosPass(direction) return !density /obj/effect/forcefield/wizard @@ -40,15 +40,15 @@ /obj/structure/forcefield/Initialize(mapload) . = ..() if(blocks_atmos) - air_update_turf(TRUE) + recalculate_atmos_connectivity() /obj/structure/forcefield/Destroy() if(blocks_atmos) blocks_atmos = FALSE - air_update_turf(TRUE) + recalculate_atmos_connectivity() return ..() -/obj/structure/forcefield/CanAtmosPass(turf/T) +/obj/structure/forcefield/CanAtmosPass(direction) return !blocks_atmos /obj/structure/forcefield/mime diff --git a/code/game/objects/effects/snowcloud.dm b/code/game/objects/effects/snowcloud.dm index 266e4314bb7..76a2f8127b1 100644 --- a/code/game/objects/effects/snowcloud.dm +++ b/code/game/objects/effects/snowcloud.dm @@ -23,10 +23,8 @@ if(isspaceturf(T) || T.density) // Don't want snowclouds or snow on walls qdel(src) return - var/turf_hotness - if(issimulatedturf(T)) - var/turf/simulated/S = T - turf_hotness = S.air.temperature + var/datum/gas_mixture/G = T.get_readonly_air() + var/turf_hotness = G.temperature() if(turf_hotness > T0C && prob(10 * (turf_hotness - T0C))) //Cloud disappears if it's too warm qdel(src) return @@ -36,16 +34,16 @@ return try_to_snow() try_to_spread_cloud() - parent_machine.affect_turf_temperature(T, 0.25 * parent_machine.cooling_speed) + var/datum/milla_safe/snow_machine_cooling/milla = new() + milla.invoke_async(parent_machine, 0.25 * parent_machine.cooling_speed) /obj/effect/snowcloud/proc/try_to_snow() var/turf/T = get_turf(src) if(locate(/obj/effect/snow, T)) return - if(issimulatedturf(T)) - var/turf/simulated/S = T - if(prob(75 + S.air.temperature - T0C)) //Colder turf = more chance of snow - return + var/datum/gas_mixture/G = T.get_readonly_air() + if(prob(75 + G.temperature() - T0C)) //Colder turf = more chance of snow + return new /obj/effect/snow(T) /obj/effect/snowcloud/proc/try_to_spread_cloud() @@ -56,7 +54,7 @@ var/turf/T = get_turf(get_step(src, potential)) if(isspaceturf(T) || T.density) continue - if(!T.CanAtmosPass(T)) + if(!CanAtmosPass(potential) || !T.CanAtmosPass(turn(potential, 180))) continue if(parent_machine.make_snowcloud(T)) return @@ -84,12 +82,11 @@ if(isspaceturf(T) || T.density) // Don't want snowclouds or snow on walls qdel(src) return - else if(issimulatedturf(T)) - var/turf/simulated/S = T - if(S.air.temperature <= T0C) - return - if(prob(10 + S.air.temperature - T0C)) - qdel(src) + var/datum/gas_mixture/G = T.get_readonly_air() + if(G.temperature() <= T0C) + return + if(prob(10 + G.temperature() - T0C)) + qdel(src) /obj/effect/snow/attack_hand(mob/living/carbon/human/user) if(!istype(user)) //Nonhumans don't have the balls to fight in the snow diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm index 10600cb1fee..8b6b959473a 100644 --- a/code/game/objects/effects/spawners/bombspawner.dm +++ b/code/game/objects/effects/spawners/bombspawner.dm @@ -33,8 +33,8 @@ PT.master = V OT.master = V - PT.air_contents.temperature = btemp1 + T0C - OT.air_contents.temperature = btemp2 + T0C + PT.air_contents.set_temperature(btemp1 + T0C) + OT.air_contents.set_temperature(btemp2 + T0C) var/obj/item/assembly/S diff --git a/code/game/objects/effects/spawners/windowspawner.dm b/code/game/objects/effects/spawners/windowspawner.dm index 32ccfdfdd7c..72de05b92fc 100644 --- a/code/game/objects/effects/spawners/windowspawner.dm +++ b/code/game/objects/effects/spawners/windowspawner.dm @@ -32,7 +32,7 @@ if(useGrille) new /obj/structure/grille(get_turf(src)) - air_update_turf(TRUE) //atmos can pass otherwise + recalculate_atmos_connectivity() //atmos can pass otherwise return INITIALIZE_HINT_QDEL /obj/effect/spawner/window/grilled diff --git a/code/game/objects/explosion.dm b/code/game/objects/explosion.dm index 1c6b50e64fe..d68802eb413 100644 --- a/code/game/objects/explosion.dm +++ b/code/game/objects/explosion.dm @@ -157,7 +157,9 @@ if(T) if(flame_dist && prob(40) && !isspaceturf(T) && !T.density) - new /obj/effect/hotspot(T) //Mostly for ambience! + var/obj/effect/hotspot/hotspot = new /obj/effect/hotspot/fake(T) //Mostly for ambience! + hotspot.temperature = 1000 + hotspot.recolor() if(dist > 0) if(issimulatedturf(T)) var/turf/simulated/S = T diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 5b040e8a28e..13cd0522d61 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -599,8 +599,17 @@ SLIME SCANNER * Outputs a message to the user describing the target's gasmixes. * Used in chat-based gas scans. */ -/proc/atmos_scan(mob/user, atom/target, silent = FALSE, print = TRUE) - var/mixture = target.return_analyzable_air() +/proc/atmos_scan(mob/user, atom/target, silent = FALSE, print = TRUE, milla_turf_details = FALSE) + var/mixture + var/list/milla = null + if(milla_turf_details) + milla = new/list(MILLA_TILE_SIZE) + get_tile_atmos(target, milla) + var/datum/gas_mixture/GM = new() + GM.copy_from_milla(milla) + mixture = GM + else + mixture = target.return_analyzable_air() if(!mixture) return FALSE @@ -628,19 +637,19 @@ SLIME SCANNER if(total_moles) message += "Total: [round(total_moles, 0.01)] moles" - if(air.oxygen && air.oxygen / total_moles > 0.01) - message += " Oxygen: [round(air.oxygen, 0.01)] moles ([round(air.oxygen / total_moles * 100, 0.01)] %)" - if(air.nitrogen && air.nitrogen / total_moles > 0.01) - message += " Nitrogen: [round(air.nitrogen, 0.01)] moles ([round(air.nitrogen / total_moles * 100, 0.01)] %)" - if(air.carbon_dioxide && air.carbon_dioxide / total_moles > 0.01) - message += " Carbon Dioxide: [round(air.carbon_dioxide, 0.01)] moles ([round(air.carbon_dioxide / total_moles * 100, 0.01)] %)" - if(air.toxins && air.toxins / total_moles > 0.01) - message += " Plasma: [round(air.toxins, 0.01)] moles ([round(air.toxins / total_moles * 100, 0.01)] %)" - if(air.sleeping_agent && air.sleeping_agent / total_moles > 0.01) - message += " Nitrous Oxide: [round(air.sleeping_agent, 0.01)] moles ([round(air.sleeping_agent / total_moles * 100, 0.01)] %)" - if(air.agent_b && air.agent_b / total_moles > 0.01) - message += " Agent B: [round(air.agent_b, 0.01)] moles ([round(air.agent_b / total_moles * 100, 0.01)] %)" - message += "Temperature: [round(air.temperature-T0C)] °C ([round(air.temperature)] K)" + if(air.oxygen() && (milla_turf_details || air.oxygen() / total_moles > 0.01)) + message += " Oxygen: [round(air.oxygen(), 0.01)] moles ([round(air.oxygen() / total_moles * 100, 0.01)] %)" + if(air.nitrogen() && (milla_turf_details || air.nitrogen() / total_moles > 0.01)) + message += " Nitrogen: [round(air.nitrogen(), 0.01)] moles ([round(air.nitrogen() / total_moles * 100, 0.01)] %)" + if(air.carbon_dioxide() && (milla_turf_details || air.carbon_dioxide() / total_moles > 0.01)) + message += " Carbon Dioxide: [round(air.carbon_dioxide(), 0.01)] moles ([round(air.carbon_dioxide() / total_moles * 100, 0.01)] %)" + if(air.toxins() && (milla_turf_details || air.toxins() / total_moles > 0.01)) + message += " Plasma: [round(air.toxins(), 0.01)] moles ([round(air.toxins() / total_moles * 100, 0.01)] %)" + if(air.sleeping_agent() && (milla_turf_details || air.sleeping_agent() / total_moles > 0.01)) + message += " Nitrous Oxide: [round(air.sleeping_agent(), 0.01)] moles ([round(air.sleeping_agent() / total_moles * 100, 0.01)] %)" + if(air.agent_b() && (milla_turf_details || air.agent_b() / total_moles > 0.01)) + message += " Agent B: [round(air.agent_b(), 0.01)] moles ([round(air.agent_b() / total_moles * 100, 0.01)] %)" + message += "Temperature: [round(air.temperature()-T0C)] °C ([round(air.temperature())] K)" message += "Volume: [round(volume)] Liters" message += "Pressure: [round(pressure, 0.1)] kPa" message += "Heat Capacity: [DisplayJoules(heat_capacity)] / K" @@ -649,6 +658,28 @@ SLIME SCANNER message += length(airs) > 1 ? "This node is empty!" : "[target] is empty!" message += "Volume: [round(volume)] Liters" // don't want to change the order volume appears in, suck it + if(milla) + // Values from milla/src/lib.rs, +1 due to array indexing difference. + message += "Airtight North: [(milla[MILLA_INDEX_AIRTIGHT_DIRECTIONS] & MILLA_NORTH) ? "yes" : "no"]" + message += "Airtight East: [(milla[MILLA_INDEX_AIRTIGHT_DIRECTIONS] & MILLA_EAST) ? "yes" : "no"]" + message += "Airtight South: [(milla[MILLA_INDEX_AIRTIGHT_DIRECTIONS] & MILLA_SOUTH) ? "yes" : "no"]" + message += "Airtight West: [(milla[MILLA_INDEX_AIRTIGHT_DIRECTIONS] & MILLA_WEST) ? "yes" : "no"]" + switch(milla[MILLA_INDEX_ATMOS_MODE]) + // These are enum values, so they don't get increased. + if(0) + message += "Atmos Mode: Space" + if(1) + message += "Atmos Mode: Sealed" + if(2) + message += "Atmos Mode: Exposed to Environment (ID: [milla[MILLA_INDEX_ENVIRONMENT_ID]])" + else + message += "Atmos Mode: Unknown ([milla[MILLA_INDEX_ATMOS_MODE]]), contact a coder." + message += "Superconductivity North: [milla[MILLA_INDEX_SUPERCONDUCTIVITY_NORTH]]" + message += "Superconductivity East: [milla[MILLA_INDEX_SUPERCONDUCTIVITY_EAST]]" + message += "Superconductivity South: [milla[MILLA_INDEX_SUPERCONDUCTIVITY_SOUTH]]" + message += "Superconductivity West: [milla[MILLA_INDEX_SUPERCONDUCTIVITY_WEST]]" + message += "Turf's Innate Heat Capacity: [milla[MILLA_INDEX_INNATE_HEAT_CAPACITY]]" + to_chat(user, chat_box_examine(message.Join("\n"))) return TRUE diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm index 6b8e1c7527e..c3eb9ee2e06 100644 --- a/code/game/objects/items/latexballoon.dm +++ b/code/game/objects/items/latexballoon.dm @@ -35,7 +35,8 @@ var/mob/living/user = loc user.update_inv_r_hand() user.update_inv_l_hand() - loc.assume_air(air_contents) + var/turf/T = get_turf(src) + T.blind_release_air(air_contents) /obj/item/latexballon/ex_act(severity) burst() diff --git a/code/game/objects/items/weapons/chrono_eraser.dm b/code/game/objects/items/weapons/chrono_eraser.dm index 32b55d5b29a..3f5aee56bca 100644 --- a/code/game/objects/items/weapons/chrono_eraser.dm +++ b/code/game/objects/items/weapons/chrono_eraser.dm @@ -239,15 +239,13 @@ else return 0 -/obj/structure/chrono_field/assume_air() - return 0 - -/obj/structure/chrono_field/return_air() //we always have nominal air and temperature +/obj/structure/chrono_field/return_obj_air() + //we always have nominal air and temperature RETURN_TYPE(/datum/gas_mixture) var/datum/gas_mixture/GM = new - GM.oxygen = MOLES_O2STANDARD - GM.nitrogen = MOLES_N2STANDARD - GM.temperature = T20C + GM.set_oxygen(MOLES_O2STANDARD) + GM.set_nitrogen(MOLES_N2STANDARD) + GM.set_temperature(T20C) return GM /obj/structure/chrono_field/Move() diff --git a/code/game/objects/items/weapons/flamethrower.dm b/code/game/objects/items/weapons/flamethrower.dm index c5c72de57f8..7940fb082c2 100644 --- a/code/game/objects/items/weapons/flamethrower.dm +++ b/code/game/objects/items/weapons/flamethrower.dm @@ -207,11 +207,11 @@ operating = TRUE var/turf/previousturf = get_turf(src) for(var/turf/simulated/T in turflist) - if(!T.air) + if(T.blocks_air) break if(T == previousturf) continue //so we don't burn the tile we be standin on - if(!T.CanAtmosPass(previousturf)) + if(!T.CanAtmosPass(get_dir(T, previousturf)) || !previousturf.CanAtmosPass(get_dir(previousturf, T))) break if(igniter) igniter.ignite_turf(src, T) @@ -229,13 +229,10 @@ //TODO: DEFERRED Consider checking to make sure tank pressure is high enough before doing this... //Transfer 5% of current tank air contents to turf var/datum/gas_mixture/air_transfer = ptank.air_contents.remove_ratio(release_amount) - if(air_transfer.toxins) - air_transfer.toxins = air_transfer.toxins * 5 - target.assume_air(air_transfer) - //Burn it based on transfered gas - target.hotspot_expose((ptank.air_contents.temperature*2) + 380, 500) - //location.hotspot_expose(1000,500,1) - SSair.add_to_active(target, 0) + if(air_transfer.toxins()) + air_transfer.set_toxins(air_transfer.toxins() * 5) + target.blind_release_air(air_transfer) + target.hotspot_expose((ptank.air_contents.temperature() * 2) + 380, 500) /obj/item/flamethrower/Initialize(mapload) diff --git a/code/game/objects/items/weapons/grenades/atmosgrenade.dm b/code/game/objects/items/weapons/grenades/atmosgrenade.dm index 7da1f504009..68933f6c0e4 100644 --- a/code/game/objects/items/weapons/grenades/atmosgrenade.dm +++ b/code/game/objects/items/weapons/grenades/atmosgrenade.dm @@ -12,7 +12,13 @@ var/turf/simulated/target_turf = get_turf(src) if(istype(target_turf)) target_turf.atmos_spawn_air(spawn_contents, spawn_amount) - target_turf.air_update_turf() + +/obj/item/grenade/gas/proc/release_air(turf/simulated/target_turf) + // Any proc that wants MILLA to be synchronous should not sleep. + SHOULD_NOT_SLEEP(TRUE) + + target_turf.atmos_spawn_air(spawn_contents, spawn_amount) + qdel(src) /obj/item/grenade/gas/plasma diff --git a/code/game/objects/items/weapons/grenades/flashbang.dm b/code/game/objects/items/weapons/grenades/flashbang.dm index 3ca62ab6d34..5ed12d3b438 100644 --- a/code/game/objects/items/weapons/grenades/flashbang.dm +++ b/code/game/objects/items/weapons/grenades/flashbang.dm @@ -61,8 +61,8 @@ var/ear_safety = M.check_ear_prot() //Atmosphere affects sound var/pressure_factor = 1 - var/datum/gas_mixture/hearer_env = source_turf.return_air() - var/datum/gas_mixture/source_env = T.return_air() + var/datum/gas_mixture/hearer_env = source_turf.get_readonly_air() + var/datum/gas_mixture/source_env = T.get_readonly_air() if(hearer_env && source_env) var/pressure = min(hearer_env.return_pressure(), source_env.return_pressure()) diff --git a/code/game/objects/items/weapons/powerfist.dm b/code/game/objects/items/weapons/powerfist.dm index c1d1b85dfee..8151e7fd1c0 100644 --- a/code/game/objects/items/weapons/powerfist.dm +++ b/code/game/objects/items/weapons/powerfist.dm @@ -93,7 +93,7 @@ if(!tank) to_chat(user, "[src] can't operate without a source of gas!") return - if(tank && !tank.air_contents.boolean_remove(((gasperfist * fisto_setting) * tank.air_contents.return_volume()) / (R_IDEAL_GAS_EQUATION * tank.air_contents.return_temperature()))) + if(tank && !tank.air_contents.boolean_remove(((gasperfist * fisto_setting) * tank.air_contents.return_volume()) / (R_IDEAL_GAS_EQUATION * tank.air_contents.temperature()))) to_chat(user, "[src]'s piston-ram lets out a weak hiss, it needs more gas!") playsound(loc, 'sound/effects/refill.ogg', 50, 1) return diff --git a/code/game/objects/items/weapons/rpd.dm b/code/game/objects/items/weapons/rpd.dm index a9f15097ab8..89043519bfe 100644 --- a/code/game/objects/items/weapons/rpd.dm +++ b/code/game/objects/items/weapons/rpd.dm @@ -114,6 +114,8 @@ else if(!iconrotation) //If user selected a rotation P.dir = user.dir to_chat(user, "[src] rapidly dispenses [P]!") + if(istype(user.get_inactive_hand(), /obj/item/wrench) && (user.can_reach(P, user.get_inactive_hand()))) + P.wrench_act(user, user.get_inactive_hand()) activate_rpd(TRUE) /obj/item/rpd/proc/create_disposals_pipe(mob/user, turf/T) //Make a disposals pipe / construct @@ -125,6 +127,8 @@ if(!iconrotation && whatdpipe != PIPE_DISPOSALS_JUNCTION_RIGHT) //Disposals pipes are in the opposite direction to atmos pipes, so we need to flip them. Junctions don't have this quirk though P.flip() to_chat(user, "[src] rapidly dispenses [P]!") + if(istype(user.get_inactive_hand(), /obj/item/wrench) && (user.can_reach(P, user.get_inactive_hand()))) + P.attackby(user.get_inactive_hand(), user) activate_rpd(TRUE) /obj/item/rpd/proc/create_transit_tube(mob/user, turf/dest) @@ -140,6 +144,8 @@ S.dir = iconrotation ? iconrotation : user.dir to_chat(user, "[src] rapidly dispenses [S]!") + if(istype(user.get_inactive_hand(), /obj/item/wrench) && (user.can_reach(S, user.get_inactive_hand()))) + S.wrench_act(user, user.get_inactive_hand()) activate_rpd(TRUE) /obj/item/rpd/proc/rotate_all_pipes(mob/user, turf/T) //Rotate all pipes on a turf diff --git a/code/game/objects/items/weapons/tanks/jetpack.dm b/code/game/objects/items/weapons/tanks/jetpack.dm index 796ee726096..0ddddced092 100644 --- a/code/game/objects/items/weapons/tanks/jetpack.dm +++ b/code/game/objects/items/weapons/tanks/jetpack.dm @@ -17,9 +17,9 @@ if(gas_type) switch(gas_type) if("oxygen") - air_contents.oxygen = ((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) + air_contents.set_oxygen(((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))) if("carbon dioxide") - air_contents.carbon_dioxide = ((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) + air_contents.set_carbon_dioxide(((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))) /obj/item/tank/jetpack/on_mob_move(direction, mob/user) if(on) @@ -77,7 +77,7 @@ return 0 var/turf/T = get_turf(user) - T.assume_air(removed) + T.blind_release_air(removed) return 1 /obj/item/tank/jetpack/improvised diff --git a/code/game/objects/items/weapons/tanks/tank_types.dm b/code/game/objects/items/weapons/tanks/tank_types.dm index b368af7a528..c635c7816a9 100644 --- a/code/game/objects/items/weapons/tanks/tank_types.dm +++ b/code/game/objects/items/weapons/tanks/tank_types.dm @@ -20,7 +20,7 @@ dog_fashion = /datum/dog_fashion/back /obj/item/tank/internals/oxygen/populate_gas() - air_contents.oxygen = (6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_oxygen((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /obj/item/tank/internals/oxygen/yellow desc = "A tank of oxygen, this one is yellow." @@ -46,8 +46,8 @@ force = 10 /obj/item/tank/internals/anesthetic/populate_gas() - air_contents.oxygen = (3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * O2STANDARD - air_contents.sleeping_agent = (3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * N2STANDARD + air_contents.set_oxygen((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * O2STANDARD) + air_contents.set_sleeping_agent((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * N2STANDARD) /* * Plasma @@ -61,7 +61,7 @@ force = 8 /obj/item/tank/internals/plasma/populate_gas() - air_contents.toxins = (3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_toxins((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /obj/item/tank/internals/plasma/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/flamethrower)) @@ -77,7 +77,7 @@ return ..() /obj/item/tank/internals/plasma/full/populate_gas() - air_contents.toxins = (10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_toxins((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /obj/item/tank/internals/plasma/empty/populate_gas() return @@ -94,10 +94,10 @@ distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE /obj/item/tank/internals/plasmaman/populate_gas() - air_contents.toxins = (3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_toxins((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /obj/item/tank/internals/plasmaman/full/populate_gas() - air_contents.toxins = (10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_toxins((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /obj/item/tank/internals/plasmaman/belt @@ -110,7 +110,7 @@ w_class = WEIGHT_CLASS_SMALL /obj/item/tank/internals/plasmaman/belt/full/populate_gas() - air_contents.toxins = (10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_toxins((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /obj/item/tank/internals/plasmaman/belt/empty/populate_gas() return @@ -121,7 +121,7 @@ icon_state = "emergency_p" /obj/item/tank/internals/emergency_oxygen/plasma/populate_gas() - air_contents.toxins = (10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_toxins((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /* * Emergency Oxygen @@ -139,7 +139,7 @@ volume = 3 //Tiny. Real life equivalents only have 21 breaths of oxygen in them. They're EMERGENCY tanks anyway -errorage (dangercon 2011) /obj/item/tank/internals/emergency_oxygen/populate_gas() - air_contents.oxygen = (10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_oxygen((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /obj/item/tank/internals/emergency_oxygen/empty/populate_gas() return @@ -175,7 +175,7 @@ distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE /obj/item/tank/internals/nitrogen/populate_gas() - air_contents.nitrogen = (6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_nitrogen((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /obj/item/tank/internals/emergency_oxygen/nitrogen name = "emergency nitrogen tank" @@ -183,7 +183,7 @@ icon_state = "emergency_nitrogen" /obj/item/tank/internals/emergency_oxygen/nitrogen/populate_gas() - air_contents.nitrogen = (10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_nitrogen((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /obj/item/tank/internals/emergency_oxygen/double/vox name = "vox specialized nitrogen tank" @@ -192,7 +192,7 @@ volume = 35 /obj/item/tank/internals/emergency_oxygen/double/vox/populate_gas() - air_contents.nitrogen = (10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) + air_contents.set_nitrogen((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)) /* * Air Mix @@ -205,8 +205,8 @@ distribute_pressure = ONE_ATMOSPHERE /obj/item/tank/internals/air/populate_gas() - air_contents.oxygen = (3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * O2STANDARD - air_contents.nitrogen = (3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * N2STANDARD + air_contents.set_oxygen((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * O2STANDARD) + air_contents.set_nitrogen((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * N2STANDARD) /* * Generic diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 96acdc91e60..0cb398e24c6 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -22,7 +22,7 @@ air_contents = new /datum/gas_mixture() air_contents.volume = volume //liters - air_contents.temperature = T20C + air_contents.set_temperature(T20C) populate_gas() @@ -85,7 +85,7 @@ . += "It's [p_a()] [bicon(icon)] [name]! If you want any more information you'll need to get closer." return - var/celsius_temperature = air_contents.temperature - T0C + var/celsius_temperature = air_contents.temperature() - T0C var/descriptive if(celsius_temperature < 20) @@ -111,7 +111,7 @@ qdel(src) if(air_contents) - location.assume_air(air_contents) + location.blind_release_air(air_contents) qdel(src) @@ -133,8 +133,7 @@ if(!disassembled) var/turf/T = get_turf(src) if(T) - T.assume_air(air_contents) - air_update_turf() + T.blind_release_air(air_contents) playsound(src.loc, 'sound/effects/spray.ogg', 10, TRUE, -3) qdel(src) @@ -205,22 +204,13 @@ if(.) add_fingerprint(usr) -/obj/item/tank/remove_air(amount) - return air_contents.remove(amount) - -/obj/item/tank/return_air() +/obj/item/tank/return_obj_air() RETURN_TYPE(/datum/gas_mixture) return air_contents /obj/item/tank/return_analyzable_air() return air_contents -/obj/item/tank/assume_air(datum/gas_mixture/giver) - air_contents.merge(giver) - - check_status() - return 1 - /obj/item/tank/proc/remove_air_volume(volume_to_return) if(!air_contents) return null @@ -228,9 +218,9 @@ var/tank_pressure = air_contents.return_pressure() var/actual_distribute_pressure = clamp(tank_pressure, 0, distribute_pressure) - var/moles_needed = actual_distribute_pressure * volume_to_return / (R_IDEAL_GAS_EQUATION * air_contents.temperature) + var/moles_needed = actual_distribute_pressure * volume_to_return / (R_IDEAL_GAS_EQUATION * air_contents.temperature()) - return remove_air(moles_needed) + return air_contents.remove(moles_needed) /obj/item/tank/process() //Allow for reactions @@ -272,8 +262,8 @@ var/turf/simulated/T = get_turf(src) if(!T) return - T.assume_air(air_contents) - playsound(loc, 'sound/effects/spray.ogg', 10, 1, -3) + T.blind_release_air(air_contents) + playsound(loc, 'sound/effects/spray.ogg', 10, TRUE, -3) qdel(src) else integrity-- @@ -285,7 +275,7 @@ if(!T) return var/datum/gas_mixture/leaked_gas = air_contents.remove_ratio(0.25) - T.assume_air(leaked_gas) + T.blind_release_air(leaked_gas) else integrity-- diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index a7e1a8ff76c..ccb88ca23a3 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -103,35 +103,21 @@ /obj/proc/suicide_act(mob/user) return FALSE -/obj/assume_air(datum/gas_mixture/giver) - if(loc) - return loc.assume_air(giver) - else - return null - -/obj/remove_air(amount) - if(loc) - return loc.remove_air(amount) - else - return null - -/obj/return_air() - RETURN_TYPE(/datum/gas_mixture) - if(loc) - return loc.return_air() - else - return null - -/obj/proc/handle_internal_lifeform(mob/lifeform_inside_me, breath_request) +/obj/proc/handle_internal_lifeform(mob/lifeform_inside_me, breath_request, datum/gas_mixture/environment) //Return: (NONSTANDARD) // null if object handles breathing logic for lifeform // datum/air_group to tell lifeform to process using that breath return //DEFAULT: Take air from turf to give to have mob process if(breath_request > 0) - var/datum/gas_mixture/environment = return_air() - var/breath_percentage = BREATH_VOLUME / environment.return_volume() - return remove_air(environment.total_moles() * breath_percentage) + var/datum/gas_mixture/air = return_obj_air() + if(isnull(air)) + air = environment + if(isnull(air)) + return + + var/breath_percentage = BREATH_VOLUME / air.return_volume() + return air.remove(air.total_moles() * breath_percentage) else return null @@ -316,3 +302,11 @@ C.Weaken(3 SECONDS) else C.KnockDown(3 SECONDS) + +/obj/proc/return_obj_air() + RETURN_TYPE(/datum/gas_mixture) + if(isobj(loc)) + var/obj/O = loc + return O.return_obj_air() + else + return null diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm index 9beb67b5e35..1e5b6d38159 100644 --- a/code/game/objects/structures/aliens.dm +++ b/code/game/objects/structures/aliens.dm @@ -55,7 +55,7 @@ var/is_alien = TRUE /obj/structure/alien/resin/Initialize(mapload) - air_update_turf(1) + recalculate_atmos_connectivity() if(!is_alien) return ..() for(var/obj/structure/alien/weeds/node/W in get_turf(src)) @@ -69,14 +69,14 @@ var/turf/T = get_turf(src) playsound(loc, 'sound/effects/alien_resin_break2.ogg', 100, TRUE) . = ..() - T.air_update_turf(TRUE) + T.recalculate_atmos_connectivity() /obj/structure/alien/resin/Move() var/turf/T = loc ..() move_update_air(T) -/obj/structure/alien/resin/CanAtmosPass() +/obj/structure/alien/resin/CanAtmosPass(direction) return !density /obj/structure/alien/resin/attack_alien(mob/living/carbon/alien/humanoid/user) @@ -96,8 +96,8 @@ smoothing_groups = list(SMOOTH_GROUP_ALIEN_RESIN, SMOOTH_GROUP_ALIEN_WALLS) canSmoothWith = list(SMOOTH_GROUP_ALIEN_WALLS) -/obj/structure/alien/resin/wall/BlockSuperconductivity() - return TRUE +/obj/structure/alien/resin/wall/get_superconductivity(direction) + return FALSE /* *Resin-Door - Borrows its code from Mineral-Door, not a subtype due to needing many overrides if so @@ -135,7 +135,7 @@ /obj/structure/alien/resin/door/Destroy() density = FALSE QUEUE_SMOOTH_NEIGHBORS(src) - air_update_turf(1) + recalculate_atmos_connectivity() return ..() /obj/structure/alien/resin/door/Move() @@ -153,7 +153,7 @@ if(user.can_advanced_admin_interact()) operate() -/obj/structure/alien/resin/door/CanAtmosPass(turf/T) +/obj/structure/alien/resin/door/CanAtmosPass(direction) return !density /obj/structure/alien/resin/door/proc/try_to_operate(mob/user, bumped_open = FALSE) @@ -197,7 +197,7 @@ addtimer(CALLBACK(src, PROC_REF(operate_update), bumped_open), 1 SECONDS) /obj/structure/alien/resin/door/proc/operate_update(bumped_open) - air_update_turf(1) + recalculate_atmos_connectivity() update_icon(UPDATE_ICON_STATE) is_operating = FALSE diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm index 1f790290870..56e0c837004 100644 --- a/code/game/objects/structures/crates_lockers/crates.dm +++ b/code/game/objects/structures/crates_lockers/crates.dm @@ -383,23 +383,25 @@ var/target_temp = T0C - 40 var/cooling_power = 40 -/obj/structure/closet/crate/freezer/return_air() +/obj/structure/closet/crate/freezer/return_obj_air() RETURN_TYPE(/datum/gas_mixture) - var/datum/gas_mixture/gas = (..()) - if(!gas) return null + var/datum/gas_mixture/gas = ..() + if(!gas) + var/turf/T = get_turf(src) + gas = T.get_readonly_air() var/datum/gas_mixture/newgas = new/datum/gas_mixture() - newgas.oxygen = gas.oxygen - newgas.carbon_dioxide = gas.carbon_dioxide - newgas.nitrogen = gas.nitrogen - newgas.toxins = gas.toxins + newgas.set_oxygen(gas.oxygen()) + newgas.set_carbon_dioxide(gas.carbon_dioxide()) + newgas.set_nitrogen(gas.nitrogen()) + newgas.set_toxins(gas.toxins()) newgas.volume = gas.volume - newgas.temperature = gas.temperature - if(newgas.temperature <= target_temp) return + newgas.set_temperature(gas.temperature()) + if(newgas.temperature() <= target_temp) return - if((newgas.temperature - cooling_power) > target_temp) - newgas.temperature -= cooling_power + if((newgas.temperature() - cooling_power) > target_temp) + newgas.set_temperature(newgas.temperature() - cooling_power) else - newgas.temperature = target_temp + newgas.set_temperature(target_temp) return newgas /obj/structure/closet/crate/freezer/iv_storage diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index ec5520a98cc..6047210a6b1 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -35,7 +35,7 @@ /obj/structure/falsewall/Initialize(mapload) . = ..() - air_update_turf(1) + recalculate_atmos_connectivity() /obj/structure/falsewall/examine_status(mob/user) var/healthpercent = (obj_integrity/max_integrity) * 100 @@ -52,10 +52,10 @@ /obj/structure/falsewall/Destroy() density = FALSE - air_update_turf(1) + recalculate_atmos_connectivity() return ..() -/obj/structure/falsewall/CanAtmosPass(turf/T) +/obj/structure/falsewall/CanAtmosPass(direction) return !density /obj/structure/falsewall/attack_ghost(mob/user) @@ -84,7 +84,7 @@ density = TRUE set_opacity(TRUE) icon_state = "fwall_closing" - air_update_turf(TRUE) + recalculate_atmos_connectivity() opening = FALSE update_icon() diff --git a/code/game/objects/structures/grey_autocloner.dm b/code/game/objects/structures/grey_autocloner.dm index d2bba365c31..f2609eb4176 100644 --- a/code/game/objects/structures/grey_autocloner.dm +++ b/code/game/objects/structures/grey_autocloner.dm @@ -15,9 +15,9 @@ /obj/machinery/grey_autocloner/Initialize(mapload) . = ..() air_contents = new() - air_contents.oxygen = MOLES_O2STANDARD * 2 - air_contents.nitrogen = MOLES_N2STANDARD - air_contents.temperature = T20C + air_contents.set_oxygen(MOLES_O2STANDARD * 2) + air_contents.set_nitrogen(MOLES_N2STANDARD) + air_contents.set_temperature(T20C) /obj/machinery/grey_autocloner/Destroy() //These will only be not null if deleted with someone in it occupant = null diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 4097219ef38..5a1b7c26277 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -205,7 +205,7 @@ W.setDir(dir_to_set) W.ini_dir = dir_to_set W.anchored = FALSE - air_update_turf(TRUE) + recalculate_atmos_connectivity() W.update_nearby_icons() W.state = WINDOW_OUT_OF_FRAME S.use(2) diff --git a/code/game/objects/structures/holosigns.dm b/code/game/objects/structures/holosigns.dm index 4e10e0c6265..a01546b39c7 100644 --- a/code/game/objects/structures/holosigns.dm +++ b/code/game/objects/structures/holosigns.dm @@ -85,15 +85,20 @@ /obj/structure/holosign/barrier/atmos/Initialize(mapload) . = ..() - air_update_turf(TRUE) + recalculate_atmos_connectivity() -/obj/structure/holosign/barrier/atmos/CanAtmosPass(turf/T) +// Airtight. +/obj/structure/holosign/barrier/atmos/CanAtmosPass(direction) return FALSE +// Heatproof. +/obj/structure/holosign/barrier/atmos/get_superconductivity(direction) + return 0 + /obj/structure/holosign/barrier/atmos/Destroy() var/turf/T = get_turf(src) . = ..() - T.air_update_turf(TRUE) + T.recalculate_atmos_connectivity() /obj/structure/holosign/barrier/cyborg name = "Energy Field" diff --git a/code/game/objects/structures/inflatable.dm b/code/game/objects/structures/inflatable.dm index 578d482c180..571d8a446a3 100644 --- a/code/game/objects/structures/inflatable.dm +++ b/code/game/objects/structures/inflatable.dm @@ -35,17 +35,17 @@ /obj/structure/inflatable/Initialize(location) ..() - air_update_turf(TRUE) + recalculate_atmos_connectivity() /obj/structure/inflatable/Destroy() var/turf/T = get_turf(src) . = ..() - T.air_update_turf(TRUE) + T.recalculate_atmos_connectivity() /obj/structure/inflatable/CanPass(atom/movable/mover, turf/target, height=0) return -/obj/structure/inflatable/CanAtmosPass(turf/T) +/obj/structure/inflatable/CanAtmosPass(direction) return !density /obj/structure/inflatable/attack_hand(mob/user) @@ -121,7 +121,7 @@ return !opacity return !density -/obj/structure/inflatable/door/CanAtmosPass(turf/T) +/obj/structure/inflatable/door/CanAtmosPass(direction) return !density /obj/structure/inflatable/door/proc/try_to_operate(atom/user) @@ -151,7 +151,7 @@ state_open = !state_open update_icon(UPDATE_ICON_STATE) is_operating = FALSE - air_update_turf(1) + recalculate_atmos_connectivity() /obj/structure/inflatable/door/update_icon_state() if(state_open) diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm index ec197bb5c3d..f17c3f0dba5 100644 --- a/code/game/objects/structures/mineral_doors.dm +++ b/code/game/objects/structures/mineral_doors.dm @@ -26,12 +26,12 @@ /obj/structure/mineral_door/Initialize() . = ..() initial_state = icon_state - air_update_turf(1) + recalculate_atmos_connectivity() AddComponent(/datum/component/debris, DEBRIS_SPARKS, -20, 10) /obj/structure/mineral_door/Destroy() density = FALSE - air_update_turf(1) + recalculate_atmos_connectivity() return ..() /obj/structure/mineral_door/Move() @@ -62,7 +62,7 @@ return !opacity return !density -/obj/structure/mineral_door/CanAtmosPass(turf/T) +/obj/structure/mineral_door/CanAtmosPass(direction) return !density /obj/structure/mineral_door/proc/try_to_operate(atom/user) @@ -98,7 +98,7 @@ density = !density opacity = !opacity state_open = !state_open - air_update_turf(1) + recalculate_atmos_connectivity() update_icon(UPDATE_ICON_STATE) is_operating = FALSE @@ -168,7 +168,7 @@ /obj/structure/mineral_door/transparent/operate_update() density = !density state_open = !state_open - air_update_turf(TRUE) + recalculate_atmos_connectivity() update_icon(UPDATE_ICON_STATE) is_operating = FALSE diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm index 45159cb37c4..8b828eacc2f 100644 --- a/code/game/objects/structures/plasticflaps.dm +++ b/code/game/objects/structures/plasticflaps.dm @@ -101,12 +101,12 @@ /obj/structure/plasticflaps/mining/Initialize() . = ..() - air_update_turf(TRUE) + recalculate_atmos_connectivity() /obj/structure/plasticflaps/mining/Destroy() var/turf/T = get_turf(src) . = ..() - T.air_update_turf(TRUE) + T.recalculate_atmos_connectivity() -/obj/structure/plasticflaps/mining/CanAtmosPass(turf/T) +/obj/structure/plasticflaps/mining/CanAtmosPass(direction) return FALSE diff --git a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm index 4a1a1cebe74..45809087903 100644 --- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm +++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm @@ -29,9 +29,9 @@ /obj/structure/transit_tube_pod/Initialize(mapload) . = ..() - air_contents.oxygen = MOLES_O2STANDARD * 2 - air_contents.nitrogen = MOLES_N2STANDARD - air_contents.temperature = T20C + air_contents.set_oxygen(MOLES_O2STANDARD * 2) + air_contents.set_nitrogen(MOLES_N2STANDARD) + air_contents.set_temperature(T20C) for(var/obj/structure/transit_tube/tube in loc) dir = pick(tube.directions()) @@ -171,32 +171,30 @@ else moving = FALSE -// Should I return a copy here? If the caller edits or qdel()s the returned -// datum, there might be problems if I don't... -/obj/structure/transit_tube_pod/return_air() +/obj/structure/transit_tube_pod/return_obj_air() RETURN_TYPE(/datum/gas_mixture) - var/datum/gas_mixture/GM = new() - GM.copy_from(air_contents) - return GM - -// For now, copying what I found in an unused FEA file (and almost identical in a -// used ZAS file). Means that assume_air and remove_air don't actually alter the -// air contents. -/obj/structure/transit_tube_pod/assume_air(datum/gas_mixture/giver) - return air_contents.merge(giver) - -/obj/structure/transit_tube_pod/remove_air(amount) - return air_contents.remove(amount) - - + return air_contents // Called when a pod arrives at, and before a pod departs from a station, // giving it a chance to mix its internal air supply with the turf it is // currently on. /obj/structure/transit_tube_pod/proc/mix_air() - var/datum/gas_mixture/environment = loc.return_air() + var/datum/milla_safe/transit_pod_mix/milla = new() + milla.invoke_async(src) + +/datum/milla_safe/transit_pod_mix + +/datum/milla_safe/transit_pod_mix/on_run(obj/structure/transit_tube_pod/pod) + var/datum/gas_mixture/environment = null + if(isobj(pod.loc)) + var/obj/O = pod.loc + environment = O.return_obj_air() + if(isnull(environment)) + var/turf/T = get_turf(pod) + environment = get_turf_air(T) + var/env_pressure = environment.return_pressure() - var/int_pressure = air_contents.return_pressure() + var/int_pressure = pod.air_contents.return_pressure() var/total_pressure = env_pressure + int_pressure if(total_pressure == 0) @@ -211,11 +209,11 @@ var/transfer_in = max(0.1, 0.5 * (env_pressure - int_pressure) / total_pressure) var/transfer_out = max(0.1, 0.3 * (int_pressure - env_pressure) / total_pressure) - var/datum/gas_mixture/from_env = loc.remove_air(environment.total_moles() * transfer_in) - var/datum/gas_mixture/from_int = air_contents.remove(air_contents.total_moles() * transfer_out) + var/datum/gas_mixture/from_env = environment.remove(environment.total_moles() * transfer_in) + var/datum/gas_mixture/from_int = pod.air_contents.remove(pod.air_contents.total_moles() * transfer_out) - loc.assume_air(from_int) - air_contents.merge(from_env) + environment.merge(from_int) + pod.air_contents.merge(from_env) diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm index 6c34c677f50..c1df7564dc8 100644 --- a/code/game/objects/structures/windoor_assembly.dm +++ b/code/game/objects/structures/windoor_assembly.dm @@ -55,12 +55,12 @@ if(set_dir) dir = set_dir ini_dir = dir - air_update_turf(1) + recalculate_atmos_connectivity() /obj/structure/windoor_assembly/Destroy() density = FALSE QDEL_NULL(electronics) - air_update_turf(1) + recalculate_atmos_connectivity() return ..() /obj/structure/windoor_assembly/Move() @@ -87,13 +87,13 @@ return FALSE else if(istype(mover, /obj/machinery/door/window) && !valid_window_location(loc, mover.dir)) return FALSE - return 1 + return TRUE -/obj/structure/windoor_assembly/CanAtmosPass(turf/T) - if(get_dir(loc, T) == dir) +/obj/structure/windoor_assembly/CanAtmosPass(direction) + if(direction == dir) return !density else - return 1 + return TRUE /obj/structure/windoor_assembly/CheckExit(atom/movable/mover, turf/target) if(istype(mover) && mover.checkpass(PASSGLASS)) diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index cf78c3c4fdd..0a509b5f4b1 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -35,6 +35,8 @@ var/mutable_appearance/edge_overlay /// Minimum environment smash level (found on simple animals) to break through this instantly var/env_smash_level = ENVIRONMENT_SMASH_STRUCTURES + /// How well this window resists superconductivity. + var/superconductivity = WINDOW_HEAT_TRANSFER_COEFFICIENT /obj/structure/window/examine(mob/user) . = ..() @@ -75,7 +77,7 @@ real_explosion_block = explosion_block explosion_block = EXPLOSION_BLOCK_PROC - air_update_turf(TRUE) + recalculate_atmos_connectivity() /obj/structure/window/proc/toggle_polarization() if(opacity) @@ -266,7 +268,7 @@ if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = CALLBACK(src, PROC_REF(check_state_and_anchored), state, anchored))) return anchored = !anchored - air_update_turf(TRUE) + recalculate_atmos_connectivity() update_nearby_icons() to_chat(user, "You [anchored ? "fasten the frame to":"unfasten the frame from"] the floor.") @@ -276,7 +278,7 @@ if(!I.use_tool(src, user, decon_speed, volume = I.tool_volume, extra_checks = CALLBACK(src, PROC_REF(check_anchored), anchored))) return anchored = !anchored - air_update_turf(TRUE) + recalculate_atmos_connectivity() update_nearby_icons() to_chat(user, "You [anchored ? "fasten the window to":"unfasten the window from"] the floor.") @@ -398,7 +400,7 @@ /obj/structure/window/Destroy() density = FALSE - air_update_turf(1) + recalculate_atmos_connectivity() update_nearby_icons() return ..() @@ -413,10 +415,15 @@ anchored = FALSE QUEUE_SMOOTH_NEIGHBORS(src) -/obj/structure/window/CanAtmosPass(turf/T) +/obj/structure/window/CanAtmosPass(direction) if(!anchored || !density) return TRUE - return !(FULLTILE_WINDOW_DIR == dir || (dir & get_dir(loc, T))) + return !(FULLTILE_WINDOW_DIR == dir || (dir & direction)) + +/obj/structure/window/get_superconductivity(direction) + if(dir == FULLTILE_WINDOW_DIR || dir & direction) + return superconductivity + return ..() //This proc is used to update the icons of nearby windows. /obj/structure/window/proc/update_nearby_icons() @@ -619,9 +626,7 @@ explosion_block = 1 armor = list(MELEE = 75, BULLET = 5, LASER = 0, ENERGY = 0, BOMB = 45, RAD = 100, FIRE = 99, ACID = 100) rad_insulation = RAD_NO_INSULATION - -/obj/structure/window/plasmabasic/BlockSuperconductivity() - return 1 + superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT /obj/structure/window/plasmareinforced name = "reinforced plasma window" @@ -638,13 +643,11 @@ rad_insulation = RAD_NO_INSULATION damage_deflection = 21 env_smash_level = ENVIRONMENT_SMASH_WALLS // these windows are a fair bit tougher + superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT /obj/structure/window/plasmareinforced/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) return -/obj/structure/window/plasmareinforced/BlockSuperconductivity() - return 1 //okay this SHOULD MAKE THE TOXINS CHAMBER WORK - /obj/structure/window/full glass_amount = 2 dir = FULLTILE_WINDOW_DIR @@ -679,9 +682,7 @@ rad_insulation = RAD_NO_INSULATION edge_overlay_file = 'icons/obj/smooth_structures/windows/window_edges.dmi' env_smash_level = ENVIRONMENT_SMASH_WALLS // these windows are a fair bit tougher - -/obj/structure/window/full/plasmabasic/BlockSuperconductivity() - return TRUE + superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT /obj/structure/window/full/plasmareinforced name = "reinforced plasma window" @@ -700,13 +701,11 @@ rad_insulation = RAD_NO_INSULATION edge_overlay_file = 'icons/obj/smooth_structures/windows/reinforced_window_edges.dmi' env_smash_level = ENVIRONMENT_SMASH_RWALLS // these ones are insanely tough + superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT /obj/structure/window/full/plasmareinforced/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) return -/obj/structure/window/full/plasmareinforced/BlockSuperconductivity() - return TRUE - /obj/structure/window/full/reinforced name = "reinforced window" desc = "It looks rather strong. Might take a few good hits to shatter it." @@ -751,6 +750,8 @@ canSmoothWith = list(SMOOTH_GROUP_WINDOW_FULLTILE_SHUTTLE, SMOOTH_GROUP_TITANIUM_WALLS) glass_type = /obj/item/stack/sheet/titaniumglass env_smash_level = ENVIRONMENT_SMASH_RWALLS // shuttle windows should probably be a bit stronger, too + // Mostly for the mining shuttle. + superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT /obj/structure/window/full/shuttle/narsie_act() color = "#3C3434" @@ -773,6 +774,7 @@ glass_type = /obj/item/stack/sheet/plastitaniumglass smoothing_groups = list(SMOOTH_GROUP_SHUTTLE_PARTS, SMOOTH_GROUP_WINDOW_FULLTILE_PLASTITANIUM, SMOOTH_GROUP_PLASTITANIUM_WALLS) canSmoothWith = list(SMOOTH_GROUP_WINDOW_FULLTILE_PLASTITANIUM, SMOOTH_GROUP_SYNDICATE_WALLS, SMOOTH_GROUP_PLASTITANIUM_WALLS) + superconductivity = ZERO_HEAT_TRANSFER_COEFFICIENT /obj/structure/window/reinforced/clockwork name = "brass window" diff --git a/code/game/sound.dm b/code/game/sound.dm index f80daa18ac2..2e2e4621906 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -112,16 +112,17 @@ falloff_distance - Distance at which falloff begins. Sound is at peak volume (in if(pressure_affected) //Atmosphere affects sound - var/pressure_factor = 1 - var/datum/gas_mixture/hearer_env = T.return_air() - var/datum/gas_mixture/source_env = turf_source.return_air() + var/pressure = ONE_ATMOSPHERE + if(!T.blocks_air) + var/datum/gas_mixture/hearer_env = T.get_readonly_air() + pressure = hearer_env.return_pressure() + if(!turf_source.blocks_air) + var/datum/gas_mixture/source_env = turf_source.get_readonly_air() + pressure = min(pressure, source_env.return_pressure()) - if(hearer_env && source_env) - var/pressure = min(hearer_env.return_pressure(), source_env.return_pressure()) - if(pressure < ONE_ATMOSPHERE) - pressure_factor = max((pressure - SOUND_MINIMUM_PRESSURE)/(ONE_ATMOSPHERE - SOUND_MINIMUM_PRESSURE), 0) - else //space - pressure_factor = 0 + var/pressure_factor = 1 + if(pressure < ONE_ATMOSPHERE) + pressure_factor = max((pressure - SOUND_MINIMUM_PRESSURE) / (ONE_ATMOSPHERE - SOUND_MINIMUM_PRESSURE), 0) if(distance <= 1) pressure_factor = max(pressure_factor, 0.15) //touching the source of the sound diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm index 8ff12079448..a175af95f5a 100644 --- a/code/game/turfs/simulated.dm +++ b/code/game/turfs/simulated.dm @@ -19,18 +19,17 @@ var/excited = 0 /// Was this turf recently activated? Probably not needed anymore var/recently_active = 0 - /// The air mixture that this turf controls. - var/datum/gas_mixture/air var/archived_cycle = 0 var/current_cycle = 0 /// The active hotspot on this turf. The fact this is done through a literal object is painful var/obj/effect/hotspot/active_hotspot - /// Air will revert to its initial mix over time. It's probably a good idea to just make it so that these turfs don't process atmos as this doesn't really do anything - var/planetary_atmos = FALSE /// The temp we were when we got archived var/temperature_archived - // Current gas overlay. Can be set to plasma or sleeping_gas + /// Current gas overlay. Can be set to plasma or sleeping_gas var/atmos_overlay_type = null + /// If a fire is ongoing, how much fuel did we burn last tick? + /// Value is not updated while below PLASMA_MINIMUM_BURN_TEMPERATURE. + var/fuel_burnt = 0 /turf/simulated/proc/break_tile() return @@ -56,13 +55,27 @@ if(volume >= 3) MakeSlippery() - var/hotspot = (locate(/obj/effect/hotspot) in src) - if(hotspot) - var/datum/gas_mixture/lowertemp = remove_air(air.total_moles()) - lowertemp.temperature = max(min(lowertemp.temperature-2000,lowertemp.temperature / 2), 0) - lowertemp.react() - assume_air(lowertemp) + quench(1000, 2) + +/// Quenches any fire on the turf, and if it does, cools down the turf's air by the given parameters. +/turf/simulated/proc/quench(delta, divisor) + var/found = FALSE + for(var/obj/effect/hotspot/hotspot in src) qdel(hotspot) + found = TRUE + + if(!found) + return + + var/datum/milla_safe/turf_cool/milla = new() + milla.invoke_async(src, delta, divisor) + +/datum/milla_safe/turf_cool + +/datum/milla_safe/turf_cool/on_run(turf/T, delta, divisor) + var/datum/gas_mixture/air = get_turf_air(T) + air.set_temperature(max(min(air.temperature()-delta * divisor,air.temperature() / divisor), TCMB)) + air.react() /* * Makes a turf slippery using the given parameters diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index 496a9753e5e..534ff6134dd 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -80,12 +80,10 @@ GLOBAL_LIST_INIT(icons_to_ignore_at_floor_init, list("damaged1","damaged2","dama // Checks if the turf is safe to be on /turf/simulated/floor/is_safe() - if(!air) - return FALSE - var/datum/gas_mixture/Z = air + var/datum/gas_mixture/Z = get_readonly_air() var/pressure = Z.return_pressure() // Can most things breathe and tolerate the temperature and pressure? - if(Z.oxygen < 16 || Z.toxins >= 0.05 || Z.carbon_dioxide >= 10 || Z.sleeping_agent >= 1 || (Z.temperature <= 270) || (Z.temperature >= 360) || (pressure <= 20) || (pressure >= 550)) + if(Z.oxygen() < 16 || Z.toxins() >= 0.05 || Z.carbon_dioxide() >= 10 || Z.sleeping_agent() >= 1 || (Z.temperature() <= 270) || (Z.temperature() >= 360) || (pressure <= 20) || (pressure >= 550)) return FALSE return TRUE diff --git a/code/game/turfs/simulated/floor/asteroid_floors.dm b/code/game/turfs/simulated/floor/asteroid_floors.dm index aadfe6c447a..31d0aeb81f2 100644 --- a/code/game/turfs/simulated/floor/asteroid_floors.dm +++ b/code/game/turfs/simulated/floor/asteroid_floors.dm @@ -149,14 +149,16 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE - planetary_atmos = TRUE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND baseturf = /turf/simulated/floor/lava/mapping_lava /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface_hard oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE - planetary_atmos = TRUE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND color = COLOR_FLOOR_HARD_ROCK baseturf = /turf/simulated/floor/lava/lava_land_surface @@ -445,7 +447,8 @@ GLOBAL_LIST_INIT(megafauna_spawn_list, list(/mob/living/simple_animal/hostile/me temperature = 180 slowdown = 2 environment_type = "snow" - planetary_atmos = TRUE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_COLD digResult = /obj/item/stack/sheet/mineral/snow /turf/simulated/floor/plating/asteroid/snow/burn_tile() @@ -464,12 +467,7 @@ GLOBAL_LIST_INIT(megafauna_spawn_list, list(/mob/living/simple_animal/hostile/me temperature = TCMB oxygen = 0 nitrogen = 0 - -/turf/simulated/floor/plating/asteroid/snow/temperature - temperature = 255.37 + atmos_mode = ATMOS_MODE_SEALED /turf/simulated/floor/plating/asteroid/snow/atmosphere - oxygen = 22 - nitrogen = 82 - temperature = 180 - planetary_atmos = FALSE + atmos_mode = ATMOS_MODE_SEALED diff --git a/code/game/turfs/simulated/floor/chasm.dm b/code/game/turfs/simulated/floor/chasm.dm index ffacfcf3ea8..e23b6cf2101 100644 --- a/code/game/turfs/simulated/floor/chasm.dm +++ b/code/game/turfs/simulated/floor/chasm.dm @@ -176,7 +176,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE - planetary_atmos = TRUE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND baseturf = /turf/simulated/floor/chasm/straight_down/lava_land_surface //Chasms should not turn into lava light_range = 2 light_power = 0.75 @@ -278,6 +279,8 @@ oxygen = MOLES_O2STANDARD nitrogen = MOLES_N2STANDARD temperature = T20C + atmos_mode = ATMOS_MODE_SEALED + atmos_environment = null /turf/simulated/floor/chasm/CanPass(atom/movable/mover, turf/target) return 1 diff --git a/code/game/turfs/simulated/floor/fancy_floor.dm b/code/game/turfs/simulated/floor/fancy_floor.dm index 310b171bc0c..f1fbe9c2f07 100644 --- a/code/game/turfs/simulated/floor/fancy_floor.dm +++ b/code/game/turfs/simulated/floor/fancy_floor.dm @@ -53,9 +53,11 @@ temperature = 180 /turf/simulated/floor/wood/lavaland_air - nitrogen = LAVALAND_NITROGEN oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND // Grass /turf/simulated/floor/grass @@ -212,6 +214,13 @@ oxygen = 0 nitrogen = 0 temperature = TCMB + +/turf/simulated/floor/carpet/lavaland_air + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND //End of carpets // Bamboo mats diff --git a/code/game/turfs/simulated/floor/indestructible.dm b/code/game/turfs/simulated/floor/indestructible.dm index 43b99723b42..4b0d28d8d21 100644 --- a/code/game/turfs/simulated/floor/indestructible.dm +++ b/code/game/turfs/simulated/floor/indestructible.dm @@ -47,7 +47,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE - planetary_atmos = TRUE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND footstep = FOOTSTEP_LAVA barefootstep = FOOTSTEP_LAVA clawfootstep = FOOTSTEP_LAVA @@ -72,7 +73,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE - planetary_atmos = TRUE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND /turf/simulated/floor/indestructible/boss/air oxygen = MOLES_O2STANDARD @@ -86,7 +88,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE - planetary_atmos = TRUE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND smoothing_flags = SMOOTH_CORNERS /turf/simulated/floor/indestructible/hierophant/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir) diff --git a/code/game/turfs/simulated/floor/lava.dm b/code/game/turfs/simulated/floor/lava.dm index 08ec20fb8f7..6a633d180bc 100644 --- a/code/game/turfs/simulated/floor/lava.dm +++ b/code/game/turfs/simulated/floor/lava.dm @@ -160,10 +160,11 @@ return /turf/simulated/floor/lava/lava_land_surface - temperature = LAVALAND_TEMPERATURE oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN - planetary_atmos = TRUE + temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND baseturf = /turf/simulated/floor/chasm/straight_down/lava_land_surface /turf/simulated/floor/lava/lava_land_surface/plasma @@ -256,11 +257,11 @@ icon_state = "mappinglava" base_icon_state = "mappinglava" baseturf = /turf/simulated/floor/lava/mapping_lava - temperature = LAVALAND_TEMPERATURE oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN - planetary_atmos = TRUE - + temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND /turf/simulated/floor/lava/mapping_lava/Initialize(mapload) . = ..() diff --git a/code/game/turfs/simulated/floor/light_floor.dm b/code/game/turfs/simulated/floor/light_floor.dm index 8268cb51af4..9c9ca17bb2d 100644 --- a/code/game/turfs/simulated/floor/light_floor.dm +++ b/code/game/turfs/simulated/floor/light_floor.dm @@ -154,3 +154,11 @@ /turf/simulated/floor/light/disco/Destroy() STOP_PROCESSING(SSobj, src) return ..() + +/turf/simulated/floor/light/lavaland_air + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND + diff --git a/code/game/turfs/simulated/floor/mineral_floors.dm b/code/game/turfs/simulated/floor/mineral_floors.dm index aa6ea18b283..6eed3f080b3 100644 --- a/code/game/turfs/simulated/floor/mineral_floors.dm +++ b/code/game/turfs/simulated/floor/mineral_floors.dm @@ -80,6 +80,13 @@ floor_tile = /obj/item/stack/tile/mineral/silver icons = list("silver","silver_dam") +/turf/simulated/floor/mineral/silver/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/mineral/silver/fancy icon_state = "silverfancy" floor_tile = /obj/item/stack/tile/mineral/silver/fancy @@ -204,6 +211,13 @@ H.slip("the floor", 10 SECONDS, tilesSlipped = 4, walkSafely = 0, slipAny = 1) return +/turf/simulated/floor/mineral/bananium/lubed/lavaland_air + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND + //TRANQUILLITE /turf/simulated/floor/mineral/tranquillite name = "silent floor" @@ -287,6 +301,8 @@ return //unburnable /turf/simulated/floor/plating/abductor/lavaland_air - temperature = LAVALAND_TEMPERATURE oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND diff --git a/code/game/turfs/simulated/floor/misc_floor.dm b/code/game/turfs/simulated/floor/misc_floor.dm index ba176cd0c8d..8bdaae79ec5 100644 --- a/code/game/turfs/simulated/floor/misc_floor.dm +++ b/code/game/turfs/simulated/floor/misc_floor.dm @@ -4,10 +4,11 @@ smoothing_flags = NONE /turf/simulated/floor/vault/lavaland_air - temperature = LAVALAND_TEMPERATURE oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN - planetary_atmos = TRUE + temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND baseturf = /turf/simulated/floor/chasm/straight_down/lava_land_surface /turf/simulated/wall/vault @@ -149,7 +150,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE - planetary_atmos = TRUE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND /turf/simulated/floor/lubed name = "slippery floor" @@ -166,6 +168,13 @@ H.slip("the floor", 10 SECONDS, tilesSlipped = 4, walkSafely = 0, slipAny = 1) return +/turf/simulated/floor/lubed/lavaland_air + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND + //Clockwork floor: Slowly heals toxin damage on nearby servants. /turf/simulated/floor/clockwork name = "clockwork floor" @@ -236,9 +245,11 @@ uses_overlay = FALSE /turf/simulated/floor/clockwork/lavaland_air - nitrogen = LAVALAND_NITROGEN oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND /turf/simulated/floor/catwalk name = "catwalk" diff --git a/code/game/turfs/simulated/floor/plasteel_floor.dm b/code/game/turfs/simulated/floor/plasteel_floor.dm index 6911afdce1f..da4915de892 100644 --- a/code/game/turfs/simulated/floor/plasteel_floor.dm +++ b/code/game/turfs/simulated/floor/plasteel_floor.dm @@ -16,6 +16,13 @@ temperature = TCMB smoothing_groups = list(SMOOTH_GROUP_TURF, SMOOTH_GROUP_LATTICE) +/turf/simulated/floor/plasteel/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/plasteel/airless/Initialize(mapload) . = ..() name = "floor" diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index 050beadb770..89b4b6e48cd 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -170,9 +170,11 @@ name = "plating" /turf/simulated/floor/plating/lavaland_air - temperature = LAVALAND_TEMPERATURE oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND /turf/simulated/floor/engine name = "reinforced floor" @@ -255,9 +257,11 @@ return /turf/simulated/floor/engine/cult/lavaland_air - nitrogen = LAVALAND_NITROGEN oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND //air filled floors; used in atmos pressure chambers diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index 9116c66a534..279acca967b 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -242,9 +242,11 @@ desc = "A dense volcanic rock that appears to be resistant to everything except diamond and sonic tools!" mine_time = 15 SECONDS color = COLOR_HARD_ROCK - oxygen = 14 - nitrogen = 23 - temperature = 300 + oxygen = LAVALAND_OXYGEN + nitrogen = LAVALAND_NITROGEN + temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND turf_type = /turf/simulated/floor/plating/asteroid/basalt/lava_land_surface_hard var/static/list/allowed_picks_typecache @@ -283,6 +285,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 mineralSpawnChanceList = list( /turf/simulated/mineral/uranium/volcanic = 35, /turf/simulated/mineral/diamond/volcanic = 30, /turf/simulated/mineral/gold/volcanic = 45, /turf/simulated/mineral/titanium/volcanic = 45, @@ -303,6 +307,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 mineralChance = 10 @@ -332,6 +338,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 mineralSpawnChanceList = list( /turf/simulated/mineral/uranium/volcanic = 3, /turf/simulated/mineral/diamond/volcanic = 1, /turf/simulated/mineral/gold/volcanic = 8, /turf/simulated/mineral/titanium/volcanic = 8, @@ -352,6 +360,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 /turf/simulated/mineral/uranium @@ -367,6 +377,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 /turf/simulated/mineral/diamond @@ -382,6 +394,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 /turf/simulated/mineral/gold @@ -397,6 +411,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 /turf/simulated/mineral/silver @@ -412,6 +428,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 /turf/simulated/mineral/titanium @@ -427,6 +445,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 /turf/simulated/mineral/plasma @@ -442,6 +462,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 /turf/simulated/mineral/clown @@ -458,6 +480,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 /turf/simulated/mineral/mime @@ -473,6 +497,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 /turf/simulated/mineral/bscrystal @@ -489,6 +515,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 /turf/simulated/mineral/volcanic @@ -498,6 +526,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND /turf/simulated/mineral/volcanic/lava_land_surface environment_type = "basalt" @@ -613,6 +643,8 @@ oxygen = LAVALAND_OXYGEN nitrogen = LAVALAND_NITROGEN temperature = LAVALAND_TEMPERATURE + atmos_mode = ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + atmos_environment = ENVIRONMENT_LAVALAND defer_change = 1 #undef GIBTONITE_UNSTRUCK diff --git a/code/game/turfs/space/space_turf.dm b/code/game/turfs/space/space_turf.dm index e40b3382e26..21d4a3f4b7d 100644 --- a/code/game/turfs/space/space_turf.dm +++ b/code/game/turfs/space/space_turf.dm @@ -17,6 +17,8 @@ var/destination_x var/destination_y + atmos_mode = ATMOS_MODE_SPACE + /turf/space/Initialize(mapload) SHOULD_CALL_PARENT(FALSE) if(!istype(src, /turf/space/transit)) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 14a953bb0ed..8fd61b81973 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -53,8 +53,6 @@ var/pressure_difference = 0 /// The direction movables should travel when affected by pressure. Set to the biggest difference in atmos by turf neighbors var/pressure_direction = 0 - /// The neighbors of the turf. - var/list/atmos_adjacent_turfs = list() /// makes turfs less picky about where they transfer gas. Largely just used in the SM var/atmos_superconductivity = 0 @@ -77,6 +75,13 @@ /// Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile. var/tmp/has_opaque_atom = FALSE + /// The general behavior of atmos on this tile. + var/atmos_mode = ATMOS_MODE_SEALED + /// The external environment that this tile is exposed to for ATMOS_MODE_EXPOSED_TO_ENVIRONMENT + var/atmos_environment + + var/datum/gas_mixture/bound_to_turf/bound_air + /turf/Initialize(mapload) SHOULD_CALL_PARENT(FALSE) if(initialized) @@ -115,6 +120,8 @@ if(opacity) has_opaque_atom = TRUE + initialize_milla() + return INITIALIZE_HINT_NORMAL /turf/Destroy(force) @@ -130,13 +137,10 @@ qdel(A) return REMOVE_FROM_SMOOTH_QUEUE(src) - // Adds the adjacent turfs to the current atmos processing - for(var/turf/simulated/T in atmos_adjacent_turfs) - SSair.add_to_active(T) - SSair.remove_from_active(src) visibilityChanged() QDEL_LIST_CONTENTS(blueprint_data) initialized = FALSE + bound_air = null ..() /turf/attack_hand(mob/user as mob) @@ -321,10 +325,8 @@ // I'm including `ignore_air` because BYOND lacks positional-only arguments /turf/proc/AfterChange(ignore_air = FALSE, keep_cabling = FALSE) //called after a turf has been replaced in ChangeTurf() levelupdate() - CalculateAdjacentTurfs() - - if(!ignore_air) - SSair.add_to_active(src) + initialize_milla() + recalculate_atmos_connectivity() //update firedoor adjacency var/list/turfs_to_check = get_adjacent_open_turfs(src) | src @@ -346,45 +348,34 @@ ..() RemoveLattice() if(!ignore_air) - Assimilate_Air() + var/datum/milla_safe/turf_assimilate_air/milla = new() + milla.invoke_async(src) -//////Assimilate Air////// -/turf/simulated/proc/Assimilate_Air() - if(air) - var/aoxy = 0 //Holders to assimilate air from nearby turfs - var/anitro = 0 - var/aco = 0 - var/atox = 0 - var/asleep = 0 - var/ab = 0 - var/atemp = 0 +/datum/milla_safe/turf_assimilate_air - var/turf_count = 0 +/datum/milla_safe/turf_assimilate_air/on_run(turf/self) + if(isnull(self)) + return - for(var/turf/T in atmos_adjacent_turfs) - if(isspaceturf(T))//Counted as no air - turf_count++//Considered a valid turf for air calcs - continue - else if(isfloorturf(T)) - var/turf/simulated/S = T - if(S.air)//Add the air's contents to the holders - aoxy += S.air.oxygen - anitro += S.air.nitrogen - aco += S.air.carbon_dioxide - atox += S.air.toxins - asleep += S.air.sleeping_agent - ab += S.air.agent_b - atemp += S.air.temperature - turf_count++ - air.oxygen = (aoxy / max(turf_count, 1)) //Averages contents of the turfs, ignoring walls and the like - air.nitrogen = (anitro / max(turf_count, 1)) - air.carbon_dioxide = (aco / max(turf_count, 1)) - air.toxins = (atox / max(turf_count, 1)) - air.sleeping_agent = (asleep / max(turf_count, 1)) - air.agent_b = (ab / max(turf_count, 1)) - air.temperature = (atemp / max(turf_count, 1)) - if(SSair) - SSair.add_to_active(src) + var/datum/gas_mixture/merged = new() + var/turf_count = 0 + for(var/turf/T in self.GetAtmosAdjacentTurfs()) + if(isspaceturf(T)) + turf_count += 1 + continue + if(T.blocks_air) + continue + merged.merge(get_turf_air(T)) + turf_count += 1 + if(turf_count > 0) + // Average the contents of the turfs. + merged.set_oxygen(merged.oxygen() / turf_count) + merged.set_nitrogen(merged.nitrogen() / turf_count) + merged.set_carbon_dioxide(merged.carbon_dioxide() / turf_count) + merged.set_toxins(merged.toxins() / turf_count) + merged.set_sleeping_agent(merged.sleeping_agent() / turf_count) + merged.set_agent_b(merged.agent_b() / turf_count) + get_turf_air(self).copy_from(merged) /turf/proc/ReplaceWithLattice() ChangeTurf(baseturf, keep_icon = FALSE) @@ -574,10 +565,6 @@ T0.ChangeTurf(turf_type) - SSair.remove_from_active(T0) - T0.CalculateAdjacentTurfs() - SSair.add_to_active(T0, TRUE) - /turf/AllowDrop() return TRUE @@ -608,3 +595,58 @@ else C.take_organ_damage(damage) C.KnockDown(3 SECONDS) + +/turf/proc/initialize_milla() + var/datum/milla_safe/initialize_turf/milla = new() + milla.invoke_async(src) + +/datum/milla_safe/initialize_turf + +/datum/milla_safe/initialize_turf/on_run(turf/T) + if(!isnull(T)) + set_tile_atmos(T, atmos_mode = T.atmos_mode, environment_id = SSmapping.environments[T.atmos_environment], innate_heat_capacity = T.heat_capacity, temperature = T.temperature) + +/// Do not call this directly. Use get_readonly_air or implement /datum/milla_safe. +/turf/proc/private_unsafe_get_air() + RETURN_TYPE(/datum/gas_mixture) + if(isnull(bound_air)) + SSair.bind_turf(src) + return bound_air + +/// Gets a read-only version of this tile's air. Do not use if you intend to modify the air later, implement /datum/milla_safe instead. +/turf/proc/get_readonly_air() + RETURN_TYPE(/datum/gas_mixture) + // This is one of two intended places to call this otherwise-unsafe proc. + var/datum/gas_mixture/bound_to_turf/air = private_unsafe_get_air() + if(air.lastread < SSair.times_fired) + var/list/milla_tile = new/list(MILLA_TILE_SIZE) + get_tile_atmos(src, milla_tile) + air.copy_from_milla(milla_tile) + air.lastread = SSair.times_fired + air.readonly = null + air.dirty = FALSE + air.synchronized = FALSE + return air.get_readonly() + +/// Blindly releases air to this tile. Do not use if you care what the tile previously held, implement /datum/milla_safe instead. +/turf/proc/blind_release_air(datum/gas_mixture/air) + var/datum/milla_safe/turf_blind_release/milla = new() + milla.invoke_async(src, air) + +/datum/milla_safe/turf_blind_release + +/datum/milla_safe/turf_blind_release/on_run(turf/T, datum/gas_mixture/air) + get_turf_air(T).merge(air) + +// Blindly sets the air in this tile. Do not use if you care what the tile previously held, implement /datum/milla_safe instead. +/turf/proc/blind_set_air(datum/gas_mixture/air) + var/datum/milla_safe/turf_blind_set/milla = new() + milla.invoke_async(src, air) + +/datum/milla_safe/turf_blind_set + +/datum/milla_safe/turf_blind_set/on_run(turf/T, datum/gas_mixture/air) + get_turf_air(T).copy_from(air) + +/turf/return_analyzable_air() + return get_readonly_air() diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index c0122c20c77..88ff8198086 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -157,7 +157,6 @@ GLOBAL_LIST_INIT(admin_verbs_debug, list( /client/proc/view_runtimes, /client/proc/admin_serialize, /client/proc/uid_log, - /client/proc/visualise_active_turfs, /client/proc/reestablish_db_connection, /client/proc/ss_breakdown, #ifdef REFERENCE_TRACKING @@ -172,6 +171,9 @@ GLOBAL_LIST_INIT(admin_verbs_debug, list( /client/proc/force_verb_bypass, /client/proc/show_gc_queues, /client/proc/debug_global_variables, + /client/proc/raw_gas_scan, + /client/proc/teleport_interesting_turf, + /client/proc/visualize_interesting_turfs, /client/proc/profile_code, /client/proc/debug_atom_init )) @@ -242,9 +244,11 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list( /client/proc/ss_breakdown, /client/proc/show_gc_queues, /client/proc/debug_global_variables, - /client/proc/visualise_active_turfs, /client/proc/debug_timers, /client/proc/timer_log, + /client/proc/raw_gas_scan, + /client/proc/teleport_interesting_turf, + /client/proc/visualize_interesting_turfs, /client/proc/profile_code )) @@ -1117,3 +1121,107 @@ GLOBAL_LIST_INIT(view_runtimes_verbs, list( if(ishuman(mob)) var/mob/living/carbon/human/H = mob H.export_dmi_json() + +/client/proc/raw_gas_scan() + set name = "Raw Gas Scan" + set category = "Debug" + set desc = "Scans your current tile, including LINDA data not normally displayed." + + if(!check_rights(R_DEBUG | R_VIEWRUNTIMES)) + return + + atmos_scan(mob, get_turf(mob), silent = TRUE, milla_turf_details = TRUE) + +/client/proc/teleport_interesting_turf() + set name = "Interesting Turf" + set category = "Debug" + set desc = "Teleports you to a random Interesting Turf from MILLA" + + if(!check_rights(R_DEBUG | R_VIEWRUNTIMES)) + return + + if(!isobserver(mob)) + to_chat(mob, "You must be an observer to do this!") + return + + var/list/interesting_tile = get_random_interesting_tile() + if(!length(interesting_tile)) + to_chat(mob, "There are no interesting turfs. How interesting!") + return + + var/turf/T = interesting_tile[MILLA_INDEX_TURF] + var/mob/dead/observer/O = mob + admin_forcemove(O, T) + O.ManualFollow(T) + +/client/proc/visualize_interesting_turfs() + set name = "Visualize Interesting Turfs" + set category = "Debug" + set desc = "Shows all the Interesting Turfs from MILLA" + + if(!check_rights(R_DEBUG | R_VIEWRUNTIMES)) + return + + if(SSair.interesting_tile_count > 500) + // This can potentially iterate through a list thats 20k things long. Give ample warning to the user + var/confirm = alert(usr, "WARNING: There are [SSair.interesting_tile_count] Interesting Turfs. This process will be lag intensive and should only be used if the atmos controller is screaming bloody murder. Are you sure you with to continue", "WARNING", "I am sure", "Nope") + if(confirm != "I am sure") + return + + var/display_turfs_overlay = FALSE + var/do_display_turf_overlay = alert(usr, "Would you like to have all interesting 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 interesting atmos turfs. Server may lag.") + + var/list/zlevel_turf_indexes = list() + + var/list/coords = get_interesting_atmos_tiles() + if(!length(coords)) + to_chat(mob, "There are no interesting turfs. How interesting!") + return + + while(length(coords)) + var/offset = length(coords) - MILLA_INTERESTING_TILE_SIZE + var/turf/T = coords[offset + MILLA_INDEX_TURF] + coords.len -= MILLA_INTERESTING_TILE_SIZE + + + // 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]"])] Interesting Turfs") + + var/z_to_view = input(usr, "A list of z-levels their ITs 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", "Interesting 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) + 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, Error> { + if value.is_null() { + Ok(None) + } else { + Ok(f32_to_option_f32(value.get_number()?)) + } +} + +/// Turns a BYOND number into an Option, clamping it to the specified bounds. +// The option will be None if the number was null or NaN. +pub(crate) fn bounded_byond_to_option_f32( + value: ByondValue, + min_value: f32, + max_value: f32, +) -> Result, Error> { + if value.is_null() { + Ok(None) + } else { + Ok(f32_to_option_f32( + value.get_number()?.max(min_value).min(max_value), + )) + } +} + +/// Wraps an f32 into an Option by converting NaN into None. +pub(crate) fn f32_to_option_f32(value: f32) -> Option { + if value.is_nan() { + None + } else { + Some(value) + } +} diff --git a/milla/src/lib.rs b/milla/src/lib.rs new file mode 100644 index 00000000000..7c2e81ff85d --- /dev/null +++ b/milla/src/lib.rs @@ -0,0 +1,17 @@ +//! This is the MILLA atmospherics system, a successor to LINDA. +//! MILLA stands for Multi-threaded, Improved, Low-Level Atmospherics +//! (Or it's just a Psychonauts reference.) +//! Some folks have also taken to calling it funnymos, after the author, FunnyMan. +//! +//! MILLA takes the majority of atmos out of BYOND and puts it here, in Rust code. +//! It stores its own model of the air distribution, and BYOND will call in to view and make +//! adjustments, as well as to trigger atmos ticks. + +mod api; +mod constants; +mod conversion; +mod logging; +mod model; +mod simulate; +mod statics; +mod tick; diff --git a/milla/src/logging.rs b/milla/src/logging.rs new file mode 100644 index 00000000000..9a5d6429104 --- /dev/null +++ b/milla/src/logging.rs @@ -0,0 +1,26 @@ +use std::backtrace::Backtrace; +use std::fs::File; +use std::io::Write; + +/// Simple logging function, appends to ./milla_log.txt +#[allow(dead_code)] +pub(crate) fn write_log>(x: T) { + let mut f = File::options() + .create(true) + .append(true) + .open("./milla_log.txt") + .unwrap(); + writeln!(&mut f, "{}", String::from_utf8_lossy(x.as_ref())).unwrap(); +} + +/// Panic handler that dumps info out to ./milla_panic.txt (overwriting) if we crash. +pub(crate) fn setup_panic_handler() { + std::panic::set_hook(Box::new(|info| { + let backtrace = Backtrace::force_capture(); + std::fs::write( + "./milla_panic.txt", + format!("Panic {:#?}\n{:#?}", info, backtrace), + ) + .unwrap(); + })) +} diff --git a/milla/src/model.rs b/milla/src/model.rs new file mode 100644 index 00000000000..d8aa7b1c519 --- /dev/null +++ b/milla/src/model.rs @@ -0,0 +1,543 @@ +use crate::constants::*; +use atomic_float::AtomicF32; +use bitflags::bitflags; +use byondapi::map::{byond_locatexyz, ByondXYZ}; +use byondapi::prelude::*; +use std::sync::{atomic::AtomicBool, atomic::Ordering::Relaxed, RwLock}; + +/// Represents a collection of gases, with amounts in moles. +#[derive(Debug)] +pub(crate) struct GasSet { + pub(crate) values: [f32; GAS_COUNT], + moles_cache: AtomicF32, + heat_capacity_cache: AtomicF32, + dirty: AtomicBool, +} + +#[allow(dead_code)] +impl GasSet { + pub(crate) fn new() -> Self { + GasSet { + values: [0.0; GAS_COUNT], + moles_cache: 0.0.into(), + heat_capacity_cache: 0.0.into(), + dirty: true.into(), + } + } + pub(crate) fn oxygen(&self) -> f32 { + self.values[GAS_OXYGEN] + } + pub(crate) fn set_oxygen(&mut self, value: f32) { + self.values[GAS_OXYGEN] = value; + self.dirty.store(true, Relaxed); + } + pub(crate) fn carbon_dioxide(&self) -> f32 { + self.values[GAS_CARBON_DIOXIDE] + } + pub(crate) fn set_carbon_dioxide(&mut self, value: f32) { + self.values[GAS_CARBON_DIOXIDE] = value; + self.dirty.store(true, Relaxed); + } + pub(crate) fn nitrogen(&self) -> f32 { + self.values[GAS_NITROGEN] + } + pub(crate) fn set_nitrogen(&mut self, value: f32) { + self.values[GAS_NITROGEN] = value; + self.dirty.store(true, Relaxed); + } + pub(crate) fn toxins(&self) -> f32 { + self.values[GAS_TOXINS] + } + pub(crate) fn set_toxins(&mut self, value: f32) { + self.values[GAS_TOXINS] = value; + self.dirty.store(true, Relaxed); + } + pub(crate) fn sleeping_agent(&self) -> f32 { + self.values[GAS_SLEEPING_AGENT] + } + pub(crate) fn set_sleeping_agent(&mut self, value: f32) { + self.values[GAS_SLEEPING_AGENT] = value; + self.dirty.store(true, Relaxed); + } + pub(crate) fn agent_b(&self) -> f32 { + self.values[GAS_AGENT_B] + } + pub(crate) fn set_agent_b(&mut self, value: f32) { + self.values[GAS_AGENT_B] = value; + self.dirty.store(true, Relaxed); + } + pub(crate) fn set_dirty(&mut self) { + self.dirty.store(true, Relaxed); + } + fn recalculate(&self) { + let mut moles = 0.0; + let mut heat_capacity = 0.0; + for i in 0..GAS_COUNT { + moles += self.values[i]; + heat_capacity += self.values[i] * SPECIFIC_HEATS[i]; + } + self.moles_cache.store(moles, Relaxed); + self.heat_capacity_cache.store(heat_capacity, Relaxed); + self.dirty.store(false, Relaxed); + } + /// The heat capacity of this set of gases, in joules per kelvin. + #[allow(clippy::needless_range_loop)] + pub(crate) fn heat_capacity(&self) -> f32 { + if self.dirty.load(Relaxed) { + self.recalculate(); + } + self.heat_capacity_cache.load(Relaxed) + } + /// The total number of moles of gas. + #[allow(clippy::needless_range_loop)] + pub(crate) fn moles(&self) -> f32 { + if self.dirty.load(Relaxed) { + self.recalculate(); + } + self.moles_cache.load(Relaxed) + } + pub(crate) fn copy_from(&mut self, other: &GasSet) { + for i in 0..GAS_COUNT { + self.values[i] = other.values[i]; + let dirty = self.dirty.load(Relaxed); + if dirty { + self.dirty.store(true, Relaxed); + } else { + self.heat_capacity_cache + .store(other.heat_capacity_cache.load(Relaxed), Relaxed); + self.moles_cache + .store(other.moles_cache.load(Relaxed), Relaxed); + self.dirty.store(false, Relaxed); + } + } + } +} + +impl Clone for GasSet { + fn clone(&self) -> Self { + let mut clone = GasSet::new(); + clone.copy_from(self); + clone + } +} + +/// Determines the general behavior of a tile. +#[derive(Debug, Copy, Clone, PartialEq)] +pub(crate) enum AtmosMode { + /// Tile is exposed to space, and will lose all of its air every tick. + Space, + /// Tile has no special behavior. + Sealed, + /// Tile is exposed to the given environment. + ExposedTo { environment_id: u8 }, +} + +impl From for ByondValue { + fn from(value: AtmosMode) -> Self { + match value { + AtmosMode::Space => ByondValue::from(0.0), + AtmosMode::Sealed => ByondValue::from(1.0), + AtmosMode::ExposedTo { .. } => ByondValue::from(2.0), + } + } +} + +/// How well a tile conducts heat in each direction. +/// Valid values are 0.0 to 0.4, inclusive. +#[derive(Debug, Copy, Clone)] +pub(crate) struct Superconductivity { + pub(crate) north: f32, + pub(crate) east: f32, + pub(crate) south: f32, + pub(crate) west: f32, +} + +impl Superconductivity { + pub(crate) fn new() -> Self { + Superconductivity { + north: OPEN_HEAT_TRANSFER_COEFFICIENT, + east: OPEN_HEAT_TRANSFER_COEFFICIENT, + south: OPEN_HEAT_TRANSFER_COEFFICIENT, + west: OPEN_HEAT_TRANSFER_COEFFICIENT, + } + } + pub(crate) fn copy_from(&mut self, other: &Superconductivity) { + self.north = other.north; + self.east = other.east; + self.south = other.south; + self.west = other.west; + } +} + +bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub(crate) struct AirtightDirections: u8 { + const NORTH = 1 << 0; + const EAST = 1 << 1; + const SOUTH = 1 << 2; + const WEST = 1 << 3; + } +} + +/// A single tile in the atmos model. +#[repr(align(64))] +#[derive(Debug, Clone)] +pub(crate) struct Tile { + /// Which directions this tile cannot transmit gases in. + pub(crate) airtight_directions: AirtightDirections, + /// The gases this tile holds. + pub(crate) gases: GasSet, + /// How much thermal energy this tile has, in joules. + pub(crate) thermal_energy: f32, + /// The general behavior of this tile. + pub(crate) mode: AtmosMode, + /// How well this tile conducts heat in each direction + pub(crate) superconductivity: Superconductivity, + /// How much heat capacity the tile itself has, in joules per kelvin. + pub(crate) innate_heat_capacity: f32, +} + +impl Tile { + pub(crate) fn new() -> Self { + Tile { + airtight_directions: AirtightDirections::empty(), + gases: GasSet::new(), + thermal_energy: 0.0, + mode: AtmosMode::Space, + superconductivity: Superconductivity::new(), + innate_heat_capacity: 0.0, + } + } + /// The total heat capacity of this tile and its gases, in joules per kelvin. + pub(crate) fn heat_capacity(&self) -> f32 { + self.gases.heat_capacity() + self.innate_heat_capacity + } + /// The temperature of this tile, in kelvin. + pub(crate) fn temperature(&self) -> f32 { + let heat_capacity = self.heat_capacity(); + if heat_capacity <= 0.0 { + 0.0 + } else { + self.thermal_energy / heat_capacity + } + } + // Calculates the pressure of a tile. + #[allow(clippy::needless_range_loop)] + pub(crate) fn pressure(&self) -> f32 { + if let AtmosMode::Space = self.mode { + return 0.0; + } + let mut heat_capacity = self.gases.heat_capacity(); + heat_capacity += self.innate_heat_capacity; + if heat_capacity <= 0.0 { + 0.0 + } else { + let temperature = self.thermal_energy / heat_capacity; + self.gases.moles() * temperature * R_IDEAL_GAS_EQUATION / TILE_VOLUME + } + } + pub(crate) fn copy_from(&mut self, other: &Tile) { + self.airtight_directions = other.airtight_directions; + self.gases.copy_from(&other.gases); + self.thermal_energy = other.thermal_energy; + self.mode = other.mode; + self.superconductivity.copy_from(&other.superconductivity); + self.innate_heat_capacity = other.innate_heat_capacity; + } +} + +/// Converts a tile into BYOND values. +/// Must match the order in code/__DEFINES/milla.dm +impl From<&Tile> for Vec { + fn from(value: &Tile) -> Self { + let mut environment_id: u8 = 0; + if let AtmosMode::ExposedTo { + environment_id: env, + } = value.mode + { + environment_id = env; + } + vec![ + ByondValue::from(value.airtight_directions.bits() as f32), + ByondValue::from(value.gases.oxygen()), + ByondValue::from(value.gases.carbon_dioxide()), + ByondValue::from(value.gases.nitrogen()), + ByondValue::from(value.gases.toxins()), + ByondValue::from(value.gases.sleeping_agent()), + ByondValue::from(value.gases.agent_b()), + ByondValue::from(value.mode), + ByondValue::from(environment_id as f32), + ByondValue::from(value.superconductivity.north), + ByondValue::from(value.superconductivity.east), + ByondValue::from(value.superconductivity.south), + ByondValue::from(value.superconductivity.west), + ByondValue::from(value.innate_heat_capacity), + ByondValue::from(value.temperature()), + ] + } +} + +bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub(crate) struct ReasonFlags: u8 { + const DISPLAY = 1 << 0; + const HOT = 1 << 1; + const WIND = 1 << 2; + } +} + +/// A tile that we consider interesting for some reason. +#[derive(Debug, Clone)] +pub(crate) struct InterestingTile { + /// The tile itself. + pub(crate) tile: Tile, + /// Where the tile is. + pub(crate) coords: ByondXYZ, + /// A bitmask of reasons this tile is interesting, values are REASON_*. + pub(crate) reasons: ReasonFlags, + /// These represent the net force generated by air flowing out of the tile along each axis. + /// For a tile losing air equally in all directions, they will be zero. + /// For a tile losing air towards positive X only, flow_x will be the air pressure moved. + pub(crate) flow_x: f32, + /// See flow_x. + pub(crate) flow_y: f32, +} + +/// Convert an InterestingTile into a flat vector of ByondValues. +/// This will be assembled into one long list in BYOND. +/// +/// It'd be friendlier to make these BYOND lists or even datums, but this way is faster than lists, +/// and datums isn't possible. +/// +/// Must match the order in code/__DEFINES/milla.dm +impl From<&InterestingTile> for Vec { + fn from(value: &InterestingTile) -> Self { + let mut ret: Vec = (&value.tile).into(); + ret.extend(vec![ + byond_locatexyz(value.coords).unwrap(), + ByondValue::from(value.reasons.bits() as f32), + ByondValue::from(value.flow_x), + ByondValue::from(value.flow_y), + ]); + + ret + } +} + +/// A single Z level in the atmos model. +pub(crate) struct ZLevel(Box<[Tile; MAP_SIZE * MAP_SIZE]>); + +impl ZLevel { + pub(crate) fn new() -> Self { + let mut unbuilt: Vec = Vec::with_capacity(MAP_SIZE * MAP_SIZE); + for _ in 0..MAP_SIZE * MAP_SIZE { + unbuilt.push(Tile::new()); + } + ZLevel(unbuilt.into_boxed_slice().try_into().unwrap()) + } + + pub(crate) fn maybe_get_index(x: i32, y: i32) -> Option { + if x < 0 || x >= MAP_SIZE as i32 || y < 0 || y >= MAP_SIZE as i32 { + None + } else { + Some(x as usize * MAP_SIZE + y as usize) + } + } + + pub(crate) fn get_tile(&self, index: usize) -> &Tile { + &self.0[index] + } + + pub(crate) fn maybe_get_tile(&self, x: i32, y: i32) -> Option<&Tile> { + Some(&self.0[ZLevel::maybe_get_index(x, y)?]) + } + + pub(crate) fn get_tile_mut(&mut self, index: usize) -> &mut Tile { + &mut self.0[index] + } + + pub(crate) fn get_pair_mut(&mut self, index1: usize, index2: usize) -> (&mut Tile, &mut Tile) { + // Split borrow to get two mutable tiles at the same time. + // Ref: https://doc.rust-lang.org/nomicon/borrow-splitting.html + let ptr = self.0.as_mut_ptr(); + unsafe { + assert!(index1 != index2); + + ( + ptr.add(index1).as_mut().unwrap(), + ptr.add(index2).as_mut().unwrap(), + ) + } + } + + pub(crate) fn copy_from(&mut self, other: &ZLevel) { + for i in 0..self.0.len() { + self.0[i].copy_from(&other.0[i]); + } + } +} + +/// A complete atmos model, including all Z levels. +pub(crate) struct Model(pub(crate) Vec>); + +impl Model { + pub(crate) fn new() -> Self { + Model(Vec::new()) + } +} + +/// The main buffers that hold the active and inactive versions of the model. +/// Whichever buffer is active represents the current tick, and is the only thing BYOND can see. +/// Normally, the active buffer is read-write. +/// +/// During tick(), things change: +/// * The active buffer is now read-only, as it represents the values from the previous tick. +/// * The inactive buffer is now available read-write, as it represents the values of the next tick, +/// the ones we're currently computing. +/// Note that we do read some values from the inactive buffer here, as they are intermediate results +/// during computation. +pub(crate) struct Buffers { + buffer_a: RwLock, + buffer_b: RwLock, + /// The atomic boolean that's used to determine which buffer is active. + flipper: AtomicBool, + pub(crate) environments: RwLock>, +} + +/// Readability constant for flipper's value. +const A_IS_ACTIVE: bool = false; + +impl Buffers { + pub(crate) fn new() -> Self { + Buffers { + buffer_a: RwLock::new(Model::new()), + buffer_b: RwLock::new(Model::new()), + flipper: AtomicBool::new(true), + environments: RwLock::new(Vec::new()), + } + } + + /// Ensures that all buffers up to ZLevel `z` exist. + pub(crate) fn init_to(&self, z: i32) { + let mut a_levels = self.buffer_a.write().unwrap(); + while z >= a_levels.0.len() as i32 { + a_levels.0.push(RwLock::new(ZLevel::new())); + } + let mut b_levels = self.buffer_b.write().unwrap(); + while z >= b_levels.0.len() as i32 { + b_levels.0.push(RwLock::new(ZLevel::new())); + } + } + + /// Fetches the active buffer map, which could be either buffer_a or buffer_b. + pub(crate) fn get_active(&self) -> &RwLock { + match self.flipper.load(std::sync::atomic::Ordering::Relaxed) { + A_IS_ACTIVE => &self.buffer_a, + _ => &self.buffer_b, + } + } + + /// Fetches the inactive buffer map, which could be either buffer_a or buffer_b. + pub(crate) fn get_inactive(&self) -> &RwLock { + match self.flipper.load(std::sync::atomic::Ordering::Relaxed) { + A_IS_ACTIVE => &self.buffer_b, + _ => &self.buffer_a, + } + } + + /// Flips wether buffer_a or buffer_b is active. + pub(crate) fn flip(&self) { + self.flipper + .fetch_xor(true, std::sync::atomic::Ordering::Relaxed); + } + + /// Create an environment for ExposedTo. + pub(crate) fn create_environment(&self, tile: Tile) -> u8 { + let mut environments = self.environments.write().unwrap(); + let id = environments.len() as u8; + environments.push(tile); + id + } +} + +// Yay, tests! +#[cfg(test)] +mod tests { + use super::*; + + // The model should start empty. + #[test] + fn initial_zero() { + let buffers = Buffers::new(); + buffers.init_to(0); + + let active = buffers.get_active().read().unwrap(); + let z_level = active.0[0].read().unwrap(); + let tile = z_level.get_tile(ZLevel::maybe_get_index(0, 0).unwrap()); + assert_eq!(tile.airtight_directions, AirtightDirections::empty()); + for i in 0..GAS_COUNT { + assert_eq!(tile.gases.values[i], 0.0, "{}", i); + } + assert_eq!(tile.thermal_energy, 0.0); + assert_eq!(tile.mode, AtmosMode::Space); + assert_eq!(tile.superconductivity.north, OPEN_HEAT_TRANSFER_COEFFICIENT); + assert_eq!(tile.superconductivity.east, OPEN_HEAT_TRANSFER_COEFFICIENT); + assert_eq!(tile.superconductivity.south, OPEN_HEAT_TRANSFER_COEFFICIENT); + assert_eq!(tile.superconductivity.west, OPEN_HEAT_TRANSFER_COEFFICIENT); + assert_eq!(tile.innate_heat_capacity, 0.0); + } + + /// flip_buffers() should alternate us betweeen two buffers, and changes should be preserved + /// when we switch back to the original one. + #[test] + fn flip_works() { + let buffers = Buffers::new(); + buffers.init_to(0); + + // Write some arbitrary data to the first buffer. + { + let active = buffers.get_active().read().unwrap(); + let mut z_level = active.0[0].write().unwrap(); + let tile = z_level.get_tile_mut(ZLevel::maybe_get_index(0, 0).unwrap()); + tile.gases.values[0] = 1.0; + } + + buffers.flip(); + + // Verify that the second buffer is still empty. + { + let active = buffers.get_active().read().unwrap(); + let z_level = active.0[0].write().unwrap(); + let tile = z_level.get_tile(ZLevel::maybe_get_index(0, 0).unwrap()); + assert_eq!(tile.gases.values[0], 0.0); + } + + // Write a different set of arbitrary data to the second buffer. + { + let active = buffers.get_active().read().unwrap(); + let mut z_level = active.0[0].write().unwrap(); + let tile = z_level.get_tile_mut(ZLevel::maybe_get_index(0, 0).unwrap()); + tile.gases.values[0] = 2.0; + } + + buffers.flip(); + + // Verify that what we wrote to the first buffer is still there. + { + let active = buffers.get_active().read().unwrap(); + let z_level = active.0[0].write().unwrap(); + let tile = z_level.get_tile(ZLevel::maybe_get_index(0, 0).unwrap()); + assert_eq!(tile.gases.values[0], 1.0); + } + + buffers.flip(); + + // Verify that what we wrote to the second buffer is still there. + { + let active = buffers.get_active().read().unwrap(); + let z_level = active.0[0].write().unwrap(); + let tile = z_level.get_tile(ZLevel::maybe_get_index(0, 0).unwrap()); + assert_eq!(tile.gases.values[0], 2.0); + } + } +} diff --git a/milla/src/simulate.rs b/milla/src/simulate.rs new file mode 100644 index 00000000000..7eb359b4a27 --- /dev/null +++ b/milla/src/simulate.rs @@ -0,0 +1,614 @@ +use crate::constants::*; +use crate::model::*; +use byondapi::map::ByondXYZ; +use eyre::eyre; +use scc::Bag; + +/// Calculates the pressure flow out from this tile to the two neighboring tiles on this axis. +/// For a tile losing air equally in all directions, flow will be zero. +/// For a tile losing air towards positive only, flow will be the air pressure moved. +pub(crate) fn calculate_flow( + maybe_negative_tile: Option<&Tile>, + tile: &Tile, + maybe_positive_tile: Option<&Tile>, + is_x: bool, +) -> f32 { + let mut flow = 0.0; + let my_pressure = tile.pressure(); + if let Some(negative_tile) = maybe_negative_tile { + // Make sure air can pass this way. + let mut permeable = true; + if is_x { + permeable = permeable + && !negative_tile + .airtight_directions + .contains(AirtightDirections::EAST); + permeable = permeable && !tile.airtight_directions.contains(AirtightDirections::WEST); + } else { + permeable = permeable + && !negative_tile + .airtight_directions + .contains(AirtightDirections::NORTH); + permeable = permeable && !tile.airtight_directions.contains(AirtightDirections::SOUTH); + } + if permeable { + let negative_pressure = negative_tile.pressure(); + if negative_pressure < my_pressure { + // Causes flow in the negative direction. + flow += negative_pressure - my_pressure; + } + } + } + if let Some(positive_tile) = maybe_positive_tile { + // Make sure air can pass this way. + let mut permeable = true; + if is_x { + permeable = permeable + && !positive_tile + .airtight_directions + .contains(AirtightDirections::WEST); + permeable = permeable && !tile.airtight_directions.contains(AirtightDirections::EAST); + } else { + permeable = permeable + && !positive_tile + .airtight_directions + .contains(AirtightDirections::SOUTH); + permeable = permeable && !tile.airtight_directions.contains(AirtightDirections::NORTH); + } + if permeable { + let positive_pressure = positive_tile.pressure(); + if positive_pressure < my_pressure { + // Causes flow in the positive direction. + flow += my_pressure - positive_pressure; + } + } + } + flow +} + +/// Counts the number of adjacent tiles that can share atmos with this tile, i.e. have no blockers +/// on either tile. +#[allow(clippy::if_same_then_else)] +pub(crate) fn count_connected_dirs( + z_level: &ZLevel, + index: usize, + x: i32, + y: i32, +) -> Result { + let mut connected_dirs = 0; + + let tile = z_level.get_tile(index); + if let AtmosMode::Space = tile.mode { + // Space can always accept as much air as you throw at it. + return Ok(1); + } + for (dx, dy) in DIRECTIONS { + let maybe_other_index = ZLevel::maybe_get_index(x + dx, y + dy); + let other_index; + match maybe_other_index { + Some(index) => other_index = index, + None => continue, + } + let other_tile = z_level.get_tile(other_index); + + if dx > 0 + && !tile.airtight_directions.contains(AirtightDirections::EAST) + && !other_tile + .airtight_directions + .contains(AirtightDirections::WEST) + { + connected_dirs += 1; + } else if dy > 0 + && !tile.airtight_directions.contains(AirtightDirections::NORTH) + && !other_tile + .airtight_directions + .contains(AirtightDirections::SOUTH) + { + connected_dirs += 1; + } else if dx < 0 + && !tile.airtight_directions.contains(AirtightDirections::WEST) + && !other_tile + .airtight_directions + .contains(AirtightDirections::EAST) + { + connected_dirs += 1; + } else if dy < 0 + && !tile.airtight_directions.contains(AirtightDirections::SOUTH) + && !other_tile + .airtight_directions + .contains(AirtightDirections::NORTH) + { + connected_dirs += 1; + } + } + + Ok(connected_dirs) +} + +/// Sanitizes a tile to make sure it's not problematic. +pub(crate) fn sanitize(my_inactive_tile: &mut Tile, my_tile: &Tile) -> bool { + let mut sanitized = false; + for i in 0..GAS_COUNT { + if !my_inactive_tile.gases.values[i].is_finite() { + // Reset back to the last value, in the hopes that it's safe. + my_inactive_tile.gases.values[i] = my_tile.gases.values[i]; + my_inactive_tile.gases.set_dirty(); + sanitized = true; + } else if my_inactive_tile.gases.values[i] < 0.0 { + // Zero out anything that becomes negative. + my_inactive_tile.gases.values[i] = 0.0; + my_inactive_tile.gases.set_dirty(); + sanitized = true; + } + } + if !my_inactive_tile.thermal_energy.is_finite() { + // Reset back to the last value, in the hopes that it's safe. + my_inactive_tile.thermal_energy = my_tile.thermal_energy; + sanitized = true; + } else if my_inactive_tile.thermal_energy < 0.0 { + // Zero out anything that becomes negative. + my_inactive_tile.thermal_energy = 0.0; + sanitized = true; + } + if my_inactive_tile.gases.moles() < MINIMUM_NONZERO_MOLES { + for i in 0..GAS_COUNT { + my_inactive_tile.gases.values[i] = 0.0; + } + my_inactive_tile.thermal_energy = 0.0; + // We don't count this as sanitized because it's expected. + } + + sanitized +} + +#[allow(clippy::if_same_then_else)] +/// Checks a tile to see if it's "interesting" and should be sent to BYOND. +pub(crate) fn check_interesting( + x: i32, + y: i32, + z: i32, + active: &std::sync::RwLockReadGuard, + environments: &Box<[Tile]>, + my_tile: &Tile, + my_inactive_tile: &Tile, + fuel_burnt: f32, + new_interesting_tiles: &Bag, +) -> Result<(), eyre::Error> { + let mut reasons: ReasonFlags = ReasonFlags::empty(); + if (my_inactive_tile.gases.toxins() >= TOXINS_VISIBILITY_MOLES) + != (my_tile.gases.toxins() >= TOXINS_VISIBILITY_MOLES) + { + // Crossed the toxins visibility threshold. + reasons |= ReasonFlags::DISPLAY; + } else if (my_inactive_tile.gases.sleeping_agent() >= SLEEPING_GAS_VISIBILITY_MOLES) + != (my_tile.gases.sleeping_agent() >= SLEEPING_GAS_VISIBILITY_MOLES) + { + // Crossed the sleeping agent visibility threshold. + reasons |= ReasonFlags::DISPLAY; + } + let temperature = my_inactive_tile.temperature(); + if temperature > PLASMA_BURN_MIN_TEMP { + match my_inactive_tile.mode { + // In environments we expect to be hot, we don't normally flag that as interesting. + AtmosMode::ExposedTo { environment_id } => { + if fuel_burnt > 0.0 { + // Active fires are interesting, even if it's hot here normally. + reasons |= ReasonFlags::HOT; + } else { + if environment_id as usize > environments.len() { + return Err(eyre!("Invalid environment ID {}", environment_id)); + } + + let environment_temp = environments[environment_id as usize].temperature(); + if environment_temp + 1.0 >= temperature { + // No active fire, not hotter than normal. Not interesting. + } else { + // Oh, hey, we're hotter than normal, and can start fires. + // That's interesting. + reasons |= ReasonFlags::HOT; + } + } + } + // Anywhere else is interesting if it can start fires. + _ => reasons |= ReasonFlags::HOT, + } + } + let flow_x = calculate_flow( + active.maybe_get_tile(x - 1, y), + my_tile, + active.maybe_get_tile(x + 1, y), + true, + ); + if flow_x.abs() > 1.0 { + // Pressure flowing out of this tile along the X axis. + reasons |= ReasonFlags::WIND; + } + let flow_y = calculate_flow( + active.maybe_get_tile(x, y - 1), + my_tile, + active.maybe_get_tile(x, y + 1), + false, + ); + if flow_x.powi(2) + flow_y.powi(2) > 1.0 { + // Pressure flowing out of this tile along the Y axis. + reasons |= ReasonFlags::WIND; + } + + if !reasons.is_empty() { + // Boooooring. + + // :eyes: + new_interesting_tiles.push(InterestingTile { + tile: my_inactive_tile.clone(), + // +1 here to convert from our 0-indexing to BYOND's 1-indexing. + coords: ByondXYZ::with_coords((x as i16 + 1, y as i16 + 1, z as i16 + 1)), + reasons, + flow_x, + flow_y, + }); + } + + Ok(()) +} + +/// Is the amount of gas present significant? +pub(crate) fn is_significant(tile: &Tile, gas: usize) -> bool { + if tile.gases.values[gas] < REACTION_SIGNIFICANCE_MOLES { + return false; + } + if gas != GAS_AGENT_B + && tile.gases.values[gas] / tile.gases.moles() < REACTION_SIGNIFICANCE_RATIO + { + return false; + } + return true; +} + +/// Perform chemical reactions on the tile. +pub(crate) fn react(my_inactive_tile: &mut Tile) -> f32 { + let mut fuel_burnt: f32 = 0.0; + // Handle reactions + let mut my_inactive_temperature = my_inactive_tile.temperature(); + // Agent B converting CO2 to O2 + if my_inactive_temperature > AGENT_B_CONVERSION_TEMP + && is_significant(my_inactive_tile, GAS_AGENT_B) + && is_significant(my_inactive_tile, GAS_CARBON_DIOXIDE) + && is_significant(my_inactive_tile, GAS_TOXINS) + { + let co2_converted = (my_inactive_tile.gases.carbon_dioxide() * 0.75) + .min(my_inactive_tile.gases.toxins() * 0.25) + .min(my_inactive_tile.gases.agent_b() * 0.05); + + my_inactive_tile + .gases + .set_carbon_dioxide(my_inactive_tile.gases.carbon_dioxide() - co2_converted); + my_inactive_tile + .gases + .set_oxygen(my_inactive_tile.gases.oxygen() + co2_converted); + my_inactive_tile + .gases + .set_agent_b(my_inactive_tile.gases.agent_b() - co2_converted * 0.05); + // Recalculate existing thermal energy to account for the decrease in heat capacity + // caused by turning very high capacity toxins into much lower capacity carbon + // dioxide. + my_inactive_tile.thermal_energy = + my_inactive_temperature * my_inactive_tile.heat_capacity(); + // THEN we can add in the new thermal energy. + my_inactive_tile.thermal_energy += co2_converted * AGENT_B_CONVERSION_ENERGY; + // Recalculate temperature for any subsequent reactions. + my_inactive_temperature = my_inactive_tile.temperature(); + fuel_burnt += co2_converted; + } + // Nitrous Oxide breaking down into nitrogen and oxygen. + if my_inactive_temperature > SLEEPING_GAS_BREAKDOWN_TEMP + && is_significant(my_inactive_tile, GAS_SLEEPING_AGENT) + { + let reaction_percent = (0.00002 + * (my_inactive_temperature - (0.00001 * (my_inactive_temperature.powi(2))))) + .max(0.0) + .min(1.0); + let nitrous_decomposed = reaction_percent * my_inactive_tile.gases.sleeping_agent(); + + my_inactive_tile + .gases + .set_sleeping_agent(my_inactive_tile.gases.sleeping_agent() - nitrous_decomposed); + my_inactive_tile + .gases + .set_nitrogen(my_inactive_tile.gases.nitrogen() + nitrous_decomposed); + my_inactive_tile + .gases + .set_oxygen(my_inactive_tile.gases.oxygen() + nitrous_decomposed / 2.0); + // Recalculate existing thermal energy to account for the decrease in heat capacity + // caused by turning very high capacity toxins into much lower capacity carbon + // dioxide. + my_inactive_tile.thermal_energy = + my_inactive_temperature * my_inactive_tile.heat_capacity(); + // THEN we can add in the new thermal energy. + my_inactive_tile.thermal_energy += NITROUS_BREAKDOWN_ENERGY * nitrous_decomposed; + // Recalculate temperature for any subsequent reactions. + my_inactive_temperature = my_inactive_tile.temperature(); + fuel_burnt += nitrous_decomposed; + } + // Plasmafire! + if my_inactive_temperature > PLASMA_BURN_MIN_TEMP + && is_significant(my_inactive_tile, GAS_TOXINS) + && is_significant(my_inactive_tile, GAS_OXYGEN) + { + // How efficient is the burn? + // Linear scaling fom 0 to 1 as temperatue goes from minimum to optimal. + let efficiency = ((my_inactive_temperature - PLASMA_BURN_MIN_TEMP) + / (PLASMA_BURN_OPTIMAL_TEMP - PLASMA_BURN_MIN_TEMP)) + .max(0.0) + .min(1.0); + + // How much oxygen do we consume per plasma burnt? + // Linear scaling from worst to best as efficiency goes from 0 to 1. + let oxygen_per_plasma = PLASMA_BURN_WORST_OXYGEN_PER_PLASMA + + (PLASMA_BURN_BEST_OXYGEN_PER_PLASMA - PLASMA_BURN_WORST_OXYGEN_PER_PLASMA) + * efficiency; + + // How much plasma is available to burn? + // Capped by oxygen availability. Significantly more oxygen is required than is + // consumed. This means that if there is enough oxygen to burn all the plasma, the + // oxygen-to-plasm ratio will increase while burning. + let burnable_plasma = my_inactive_tile + .gases + .toxins() + .min(my_inactive_tile.gases.oxygen() / PLASMA_BURN_REQUIRED_OXYGEN_AVAILABILITY); + + // Actual burn amount. + let plasma_burnt = efficiency * PLASMA_BURN_MAX_RATIO * burnable_plasma; + + my_inactive_tile + .gases + .set_toxins(my_inactive_tile.gases.toxins() - plasma_burnt); + my_inactive_tile + .gases + .set_carbon_dioxide(my_inactive_tile.gases.carbon_dioxide() + plasma_burnt); + my_inactive_tile + .gases + .set_oxygen(my_inactive_tile.gases.oxygen() - plasma_burnt * oxygen_per_plasma); + // Recalculate existing thermal energy to account for the decrease in heat capacity + // caused by turning very high capacity toxins into much lower capacity carbon + // dioxide. + my_inactive_tile.thermal_energy = + my_inactive_temperature * my_inactive_tile.heat_capacity(); + // THEN we can add in the new thermal energy. + my_inactive_tile.thermal_energy += PLASMA_BURN_ENERGY * plasma_burnt; + fuel_burnt += plasma_burnt; + } + + fuel_burnt +} + +/// Apply effects caused by the tile's atmos mode. +pub(crate) fn apply_tile_mode( + my_tile: &Tile, + my_inactive_tile: &mut Tile, + environments: &Box<[Tile]>, +) -> Result<(), eyre::Error> { + match my_tile.mode { + AtmosMode::Space => { + // Space tiles lose all gas and thermal energy every tick. + for gas in 0..GAS_COUNT { + my_inactive_tile.gases.values[gas] = 0.0; + } + my_inactive_tile.gases.set_dirty(); + my_inactive_tile.thermal_energy = 0.0; + } + AtmosMode::ExposedTo { environment_id } => { + if environment_id as usize > environments.len() { + return Err(eyre!("Invalid environment ID {}", environment_id)); + } + + let mut environment = environments[environment_id as usize].clone(); + + // Calculate the amount of air and thermal energy transferred. + let (gas_change, thermal_energy_change) = share_air( + // Planetary atmos is aggressive and does a 1-connected-direction share + // with the otherwise-final air. + my_inactive_tile, + &environment, + 1, + 1, + ); + + // Transfer it. + for i in 0..GAS_COUNT { + if gas_change.values[i] != 0.0 { + my_inactive_tile.gases.values[i] += gas_change.values[i]; + my_inactive_tile.gases.set_dirty(); + } + } + my_inactive_tile.thermal_energy += thermal_energy_change; + + // Temporarily override the tile's superconductivity, since there's no UP. + let real_superconductivity = my_inactive_tile.superconductivity; + my_inactive_tile.superconductivity = Superconductivity::new(); + + // Superconduct with planetary atmos. + superconduct(my_inactive_tile, &mut environment, true); + + // Restore original superconductivity + my_inactive_tile.superconductivity = real_superconductivity; + } + AtmosMode::Sealed => { + if my_inactive_tile.temperature() > T20C { + my_inactive_tile.thermal_energy *= 1.0 - SPACE_COOLING_FACTOR; + } + } + } + Ok(()) +} + +/// Shares air between two connected tiles. +#[allow(clippy::needless_range_loop)] +pub(crate) fn share_air( + mine: &Tile, + theirs: &Tile, + my_connected_dirs: i32, + their_connected_dirs: i32, +) -> (GasSet, f32) { + let mut delta_gases = GasSet::new(); + let mut delta_thermal_energy: f32 = 0.0; + + // Since we're moving bits of gas independantly, we need to know the temperature of the gas + // mix. + let my_old_temperature = mine.temperature(); + let their_old_temperature = theirs.temperature(); + + // Each gas is handled separately. This is dumb, but it's how LINDA did it, so it's used in V1. + for gas in 0..GAS_COUNT { + delta_gases.values[gas] = theirs.gases.values[gas] - mine.gases.values[gas]; + if delta_gases.values[gas] > 0.0 { + // Gas flowing in from the other tile, limit by its connected_dirs. + delta_gases.values[gas] /= (their_connected_dirs + 1) as f32; + // Heat flowing in. + delta_thermal_energy += + SPECIFIC_HEATS[gas] * delta_gases.values[gas] * their_old_temperature; + } else { + // Gas flowing out from this tile, limit by our connected_dirs. + delta_gases.values[gas] /= (my_connected_dirs + 1) as f32; + // Heat flowing out. + delta_thermal_energy += + SPECIFIC_HEATS[gas] * delta_gases.values[gas] * my_old_temperature; + } + } + + (delta_gases, delta_thermal_energy) +} + +/// Performs superconduction between two superconductivity-connected tiles. +pub(crate) fn superconduct(my_tile: &mut Tile, their_tile: &mut Tile, is_east: bool) { + // Superconduction is scaled to the smaller directional superconductivity setting of the two + // tiles. + let mut transfer_coefficient: f32; + if is_east { + transfer_coefficient = my_tile + .superconductivity + .east + .min(their_tile.superconductivity.west); + } else { + transfer_coefficient = my_tile + .superconductivity + .north + .min(their_tile.superconductivity.south); + } + + let my_heat_capacity = my_tile.heat_capacity(); + let their_heat_capacity = their_tile.heat_capacity(); + if transfer_coefficient <= 0.0 || my_heat_capacity <= 0.0 || their_heat_capacity <= 0.0 { + // Nothing to do. + return; + } + + // Temporary workaround to match LINDA better for high temperatures. + if my_tile.temperature() > T20C || their_tile.temperature() > T20C { + transfer_coefficient = (transfer_coefficient * 100.0).min(OPEN_HEAT_TRANSFER_COEFFICIENT); + } + + // This is the formula from LINDA. I have no idea if it's a good one, I just copied it. + let conduction = transfer_coefficient + * (my_tile.temperature() - their_tile.temperature()) + * my_heat_capacity + * their_heat_capacity + / (my_heat_capacity + their_heat_capacity); + my_tile.thermal_energy -= conduction; + their_tile.thermal_energy += conduction; +} + +// Yay, tests! +#[cfg(test)] +mod tests { + use super::*; + // share_air() should do nothing to two space tiles. + #[test] + fn share_nothing() { + let tile_a = Tile::new(); + let tile_b = Tile::new(); + + let (gas_change, thermal_energy_change) = share_air(&tile_a, &tile_b, 1, 1); + for i in 0..GAS_COUNT { + assert_eq!(gas_change.values[i], 0.0, "{}", i); + } + assert_eq!(thermal_energy_change, 0.0); + } + + // share_air() should do nothing to two matching tiles. + #[test] + fn share_equilibrium() { + let mut tile_a = Tile::new(); + tile_a.gases.set_oxygen(80.0); + tile_a.gases.set_nitrogen(20.0); + tile_a.thermal_energy = 100.0; + let mut tile_b = Tile::new(); + tile_b.gases.set_oxygen(80.0); + tile_b.gases.set_nitrogen(20.0); + tile_b.thermal_energy = 100.0; + + let (gas_change, thermal_energy_change) = share_air(&tile_a, &tile_b, 1, 1); + for i in 0..GAS_COUNT { + assert_eq!(gas_change.values[i], 0.0, "{}", i); + } + assert_eq!(thermal_energy_change, 0.0); + } + + // share_air() should split air into 2 equal parts with connected_dirs of 1. + #[test] + fn share_splits_air_cd1() { + let mut tile_a = Tile::new(); + tile_a.gases.set_oxygen(100.0); + tile_a.thermal_energy = 100.0; + let tile_b = Tile::new(); + + let (gas_change, thermal_energy_change) = share_air(&tile_a, &tile_b, 1, 1); + for i in 0..GAS_COUNT { + if i == GAS_OXYGEN { + assert_eq!(gas_change.values[i], -50.0); + } else { + assert_eq!(gas_change.values[i], 0.0, "{}", i); + } + } + assert_eq!(thermal_energy_change, -50.0); + } + + // share_air() should split air into 5 equal parts with connected_dirs of 4. + #[test] + fn share_splits_air_cd4() { + let mut tile_a = Tile::new(); + tile_a.gases.set_oxygen(100.0); + tile_a.thermal_energy = 100.0; + let tile_b = Tile::new(); + + let (gas_change, thermal_energy_change) = share_air(&tile_a, &tile_b, 4, 4); + for i in 0..GAS_COUNT { + if i == GAS_OXYGEN { + assert_eq!(gas_change.values[i], -20.0); + } else { + assert_eq!(gas_change.values[i], 0.0, "{}", i); + } + } + assert_eq!(thermal_energy_change, -20.0); + } + + // superconduct() should transfer part of the thermal energy between two tiles that differ + // only in thermal energy. + #[test] + fn superconduct_temperature() { + let mut tile_a = Tile::new(); + tile_a.gases.set_oxygen(80.0); + tile_a.gases.set_nitrogen(20.0); + tile_a.thermal_energy = 100.0; + let mut tile_b = Tile::new(); + tile_b.gases.set_oxygen(80.0); + tile_b.gases.set_nitrogen(20.0); + tile_b.thermal_energy = 200.0; + + superconduct(&mut tile_a, &mut tile_b, true); + + // These values are arbitrary, they're just what we get right now. + // Update them if the calculations changed intentionally. + assert_eq!(tile_a.thermal_energy, 120.0); + assert_eq!(tile_b.thermal_energy, 180.0); + } +} diff --git a/milla/src/statics.rs b/milla/src/statics.rs new file mode 100644 index 00000000000..76a0305abfe --- /dev/null +++ b/milla/src/statics.rs @@ -0,0 +1,14 @@ +use crate::model::*; +use std::sync::{atomic::AtomicUsize, Mutex, OnceLock}; + +/// The buffers that contain the atmos model. +/// OnceLock means we only ever set this once, and it's read-only after that. +/// (The RwLocks inside it are what let us modify the model anyway.) +pub(crate) static BUFFERS: OnceLock = OnceLock::new(); + +/// The current set of interesting tiles. +/// We only write this once per tick, and only read it on user input. +pub(crate) static INTERESTING_TILES: Mutex> = Mutex::new(Vec::new()); + +/// How long the last tick took, in milliseconds. +pub(crate) static TICK_TIME: AtomicUsize = AtomicUsize::new(0); diff --git a/milla/src/tick.rs b/milla/src/tick.rs new file mode 100644 index 00000000000..b8a6991102f --- /dev/null +++ b/milla/src/tick.rs @@ -0,0 +1,910 @@ +use crate::constants::*; +use crate::model::*; +use crate::simulate; +use crate::statics::*; +use scc::Bag; +use std::sync::RwLock; +use std::thread; +use std::thread::ScopedJoinHandle; +use thread_priority; + +/// Runs a single tick of the atmospherics model, multi-threaded by Z level. +pub(crate) fn tick(buffers: &Buffers) -> Result<(), eyre::Error> { + assert!(thread_priority::ThreadPriority::Min + .set_for_current() + .is_ok()); + let active = buffers.get_active().read().unwrap(); + let inactive = buffers.get_inactive().read().unwrap(); + + let new_interesting_tiles: Bag = Bag::default(); + let mut result: Result<(), eyre::Error> = Ok(()); + + // The scope tells Rust that all the threads we create here will end by the time the scope + // closes. This allows us to pass things into them that are only borrowed for the lifetime of + // this function. + thread::scope(|s| { + // Force most things to be captured by reference, despite the `move` + // in the thread spawn, which is really just for `z`. + let active = &active; + let inactive = &inactive; + let new_interesting_tiles = &new_interesting_tiles; + + // Handle each Z level in its own thread. + let mut handles = Vec::>::new(); + for z in 0..active.0.len() { + handles.push(s.spawn(move || { + assert!(thread_priority::ThreadPriority::Min + .set_for_current() + .is_ok()); + tick_z_level( + buffers, + &active.0[z], + &inactive.0[z], + z as i32, + &new_interesting_tiles, + ) + .unwrap(); + })); + } + for handle in handles { + if let Err(e) = handle.join() { + result = Err(eyre::eyre!("Worker thread failed: {:#?}", e)); + } + } + }); + + result?; + + buffers.flip(); + + let mut interesting_tiles = INTERESTING_TILES.lock().unwrap(); + // drake_no: Last tick's interesting tiles. + interesting_tiles.clear(); + // drake_yes: This tick's interesting tiles. + interesting_tiles.extend(new_interesting_tiles); + + Ok(()) +} + +/// Runs a single tick of one Z level's atmospherics model. +pub(crate) fn tick_z_level( + buffers: &Buffers, + active_atmos_lock: &RwLock, + inactive_atmos_lock: &RwLock, + z: i32, + new_interesting_tiles: &Bag, +) -> Result<(), eyre::Error> { + let environments; + { + let global_environments = buffers.environments.read().unwrap(); + environments = global_environments.clone().into_boxed_slice(); + } + let active = active_atmos_lock.read().unwrap(); + let mut inactive = inactive_atmos_lock.write().unwrap(); + // Initialize the new frame as a copy of the old one. + inactive.copy_from(&active); + for my_index in 0..MAP_SIZE * MAP_SIZE { + let x = (my_index / MAP_SIZE) as i32; + let y = (my_index % MAP_SIZE) as i32; + let my_tile = active.get_tile(my_index); + let my_connected_dirs = simulate::count_connected_dirs(&active, my_index, x, y)?; + + // Handle gas and heat exchange with neighbors. + for (dx, dy) in AXES { + let maybe_their_index = ZLevel::maybe_get_index(x + dx, y + dy); + let their_index; + match maybe_their_index { + Some(index) => their_index = index, + None => continue, + } + + let their_tile = active.get_tile(their_index); + if let AtmosMode::Space = my_tile.mode { + if let AtmosMode::Space = their_tile.mode { + // Exchange what, exactly? + continue; + } + } + let their_connected_dirs = + simulate::count_connected_dirs(&active, their_index, x + dx, y + dy)?; + + let (my_inactive_tile, their_inactive_tile) = + inactive.get_pair_mut(my_index, their_index); + + // Bail if we shouldn't share air this way, but still run superconductivity. + if dx > 0 + && (my_tile + .airtight_directions + .contains(AirtightDirections::EAST) + || their_tile + .airtight_directions + .contains(AirtightDirections::WEST)) + { + simulate::superconduct(my_inactive_tile, their_inactive_tile, true); + continue; + } + if dy > 0 + && (my_tile + .airtight_directions + .contains(AirtightDirections::NORTH) + || their_tile + .airtight_directions + .contains(AirtightDirections::SOUTH)) + { + simulate::superconduct(my_inactive_tile, their_inactive_tile, false); + continue; + } + + // Calculate the amount of air and thermal energy transferred. + let (gas_change, thermal_energy_change) = + simulate::share_air(my_tile, their_tile, my_connected_dirs, their_connected_dirs); + + // Transfer it. + for i in 0..GAS_COUNT { + if gas_change.values[i] != 0.0 { + my_inactive_tile.gases.values[i] += gas_change.values[i]; + my_inactive_tile.gases.set_dirty(); + their_inactive_tile.gases.values[i] -= gas_change.values[i]; + their_inactive_tile.gases.set_dirty(); + } + } + my_inactive_tile.thermal_energy += thermal_energy_change; + their_inactive_tile.thermal_energy -= thermal_energy_change; + + // Run superconductivity. + simulate::superconduct(my_inactive_tile, their_inactive_tile, dx > 0); + } + + let my_inactive_tile = inactive.get_tile_mut(my_index); + simulate::apply_tile_mode(my_tile, my_inactive_tile, &environments)?; + + if let AtmosMode::Space = my_tile.mode { + // Space has no reactions, doesn't need to be sanitized, and is never interesting. + continue; + } + + // Track how much "fuel" was burnt across all reactions. + let fuel_burnt = simulate::react(my_inactive_tile); + + // Sanitize the tile, to avoid negative/NaN/infinity spread. + simulate::sanitize(my_inactive_tile, my_tile); + + simulate::check_interesting( + x, + y, + z, + &active, + &environments, + my_tile, + my_inactive_tile, + fuel_burnt, + new_interesting_tiles, + )?; + } + + Ok(()) +} + +// Yay, tests! +#[cfg(test)] +mod tests { + use super::*; + + fn set_with_defaults(legend: F) -> impl Fn(char) -> Tile + where + F: Fn(char) -> Option, + { + move |c: char| { + match legend(c) { + Some(tile) => tile, + None => { + match c { + // Sealed tile with simple air. + 'X' => TileBuilder::sealed() // + .oxygen(100.0) + .thermal_energy(100.0) + .build(), + // Sealed vacuum. + '0' => TileBuilder::sealed().build(), + // Solid wall, non-superconducting. + '#' => TileBuilder::wall().build(), + // Space. + ' ' => TileBuilder::space().build(), + // ??? + _ => { + assert!(false); + Tile::new() + } + } + } + } + } + } + + // Testing function for setting the initial state of the air in a region. + fn set_pattern(buffers: &Buffers, pattern: &[&str], legend: F, z: i32) + where + F: Fn(char) -> Tile, + { + let active = buffers.get_active().read().unwrap(); + let mut z_level = active.0[z as usize].write().unwrap(); + for inv_y in 0..pattern.len() { + // Reverse the Y direction, so +Y is up, like in the game. + let y = pattern.len() - inv_y - 1; + for x in 0..pattern[inv_y].len() { + z_level + .get_tile_mut(ZLevel::maybe_get_index(x as i32, y as i32).unwrap()) + .copy_from(&legend(pattern[inv_y].chars().nth(x).unwrap())); + } + } + } + + fn expect_with_defaults(legend: F) -> impl Fn(char) -> TileChecker + where + F: Fn(char) -> Option, + { + move |c: char| match legend(c) { + Some(checker) => checker, + None => match c { + 'X' => TileChecker::new() // + .oxygen(100.0) + .carbon_dioxide(0.0) + .nitrogen(0.0) + .toxins(0.0) + .sleeping_agent(0.0) + .agent_b(0.0) + .thermal_energy(100.0), + '0' => TileChecker::new() // + .oxygen(0.0) + .carbon_dioxide(0.0) + .nitrogen(0.0) + .toxins(0.0) + .sleeping_agent(0.0) + .agent_b(0.0) + .thermal_energy(0.0), + '#' => TileChecker::new(), + ' ' => TileChecker::new(), + _ => { + assert!(false); + TileChecker::new() + } + }, + } + } + + // Testing function for cheking that the resulting air is what we expect. + fn expect_pattern(buffers: &Buffers, pattern: &[&str], legend: F, z: i32) + where + F: Fn(char) -> TileChecker, + { + let active = buffers.get_active().read().unwrap(); + let z_level = active.0[z as usize].read().unwrap(); + for inv_y in 0..pattern.len() { + // Reverse the Y direction, so +Y is up, like in the game. + let y = pattern.len() - inv_y - 1; + for x in 0..pattern[inv_y].len() { + let actual = z_level.get_tile(ZLevel::maybe_get_index(x as i32, y as i32).unwrap()); + let checker = legend(pattern[inv_y].chars().nth(x).unwrap()); + checker.check(actual, x as i32, y as i32); + } + } + } + + struct TileBuilder(Tile); + + #[allow(dead_code)] + impl TileBuilder { + fn new(mode: AtmosMode) -> Self { + let mut tile = Tile::new(); + tile.mode = mode; + Self(tile) + } + fn space() -> Self { + Self::new(AtmosMode::Space) + } + fn sealed() -> Self { + Self::new(AtmosMode::Sealed) + } + fn exposed_to(environment_id: u8) -> Self { + Self::new(AtmosMode::ExposedTo { environment_id }) + } + fn wall() -> Self { + let mut builder = Self::sealed(); + builder + .0 + .airtight_directions + .set(AirtightDirections::NORTH, true); + builder + .0 + .airtight_directions + .set(AirtightDirections::EAST, true); + builder + .0 + .airtight_directions + .set(AirtightDirections::SOUTH, true); + builder + .0 + .airtight_directions + .set(AirtightDirections::WEST, true); + builder + } + fn superconducts(mut self, value: f32) -> Self { + self.0.superconductivity.north = value; + self.0.superconductivity.east = value; + self.0.superconductivity.south = value; + self.0.superconductivity.west = value; + self + } + fn oxygen(mut self, value: f32) -> Self { + self.0.gases.set_oxygen(value); + self + } + fn carbon_dioxide(mut self, value: f32) -> Self { + self.0.gases.set_carbon_dioxide(value); + self + } + fn nitrogen(mut self, value: f32) -> Self { + self.0.gases.set_nitrogen(value); + self + } + fn toxins(mut self, value: f32) -> Self { + self.0.gases.set_toxins(value); + self + } + fn sleeping_agent(mut self, value: f32) -> Self { + self.0.gases.set_sleeping_agent(value); + self + } + fn agent_b(mut self, value: f32) -> Self { + self.0.gases.set_agent_b(value); + self + } + fn thermal_energy(mut self, value: f32) -> Self { + self.0.thermal_energy = value; + self + } + fn innate_heat_capacity(mut self, value: f32) -> Self { + self.0.innate_heat_capacity = value; + self + } + fn temperature(mut self, value: f32) -> Self { + self.0.thermal_energy = value * self.0.heat_capacity(); + self + } + fn build(self) -> Tile { + self.0 + } + } + + struct TileChecker { + oxygen_: Option, + carbon_dioxide_: Option, + nitrogen_: Option, + toxins_: Option, + sleeping_agent_: Option, + agent_b_: Option, + thermal_energy_: Option, + temperature_: Option, + } + + impl TileChecker { + fn new() -> Self { + TileChecker { + oxygen_: None, + carbon_dioxide_: None, + nitrogen_: None, + toxins_: None, + sleeping_agent_: None, + agent_b_: None, + thermal_energy_: None, + temperature_: None, + } + } + fn check(self, tile: &Tile, x: i32, y: i32) { + if let Some(value) = self.oxygen_ { + assert!( + (tile.gases.oxygen() - value).abs() < TEST_TOLERANCE, + "{} != {} @ ({}, {})", + tile.gases.oxygen(), + value, + x, + y + ); + } + if let Some(value) = self.carbon_dioxide_ { + assert!( + (tile.gases.carbon_dioxide() - value).abs() < TEST_TOLERANCE, + "{} != {} @ ({}, {})", + tile.gases.carbon_dioxide(), + value, + x, + y + ); + } + if let Some(value) = self.nitrogen_ { + assert!( + (tile.gases.nitrogen() - value).abs() < TEST_TOLERANCE, + "{} != {} @ ({}, {})", + tile.gases.nitrogen(), + value, + x, + y + ); + } + if let Some(value) = self.toxins_ { + assert!( + (tile.gases.toxins() - value).abs() < TEST_TOLERANCE, + "{} != {} @ ({}, {})", + tile.gases.toxins(), + value, + x, + y + ); + } + if let Some(value) = self.sleeping_agent_ { + assert!( + (tile.gases.sleeping_agent() - value).abs() < TEST_TOLERANCE, + "{} != {} @ ({}, {})", + tile.gases.sleeping_agent(), + value, + x, + y + ); + } + if let Some(value) = self.agent_b_ { + assert!( + (tile.gases.agent_b() - value).abs() < TEST_TOLERANCE, + "{} != {} @ ({}, {})", + tile.gases.agent_b(), + value, + x, + y + ); + } + if let Some(value) = self.thermal_energy_ { + assert!( + (tile.thermal_energy - value).abs() < TEST_TOLERANCE, + "{} != {} @ ({}, {})", + tile.thermal_energy, + value, + x, + y + ); + } + if let Some(value) = self.temperature_ { + assert!( + (tile.temperature() - value).abs() < TEST_TOLERANCE, + "{} != {} @ ({}, {})", + tile.temperature(), + value, + x, + y + ); + } + } + fn oxygen(mut self, value: f32) -> Self { + self.oxygen_ = Some(value); + self + } + fn carbon_dioxide(mut self, value: f32) -> Self { + self.carbon_dioxide_ = Some(value); + self + } + fn nitrogen(mut self, value: f32) -> Self { + self.nitrogen_ = Some(value); + self + } + fn toxins(mut self, value: f32) -> Self { + self.toxins_ = Some(value); + self + } + fn sleeping_agent(mut self, value: f32) -> Self { + self.sleeping_agent_ = Some(value); + self + } + fn agent_b(mut self, value: f32) -> Self { + self.agent_b_ = Some(value); + self + } + fn thermal_energy(mut self, value: f32) -> Self { + self.thermal_energy_ = Some(value); + self + } + fn temperature(mut self, value: f32) -> Self { + self.temperature_ = Some(value); + self + } + } + + // The empty comments from here on out are to force rustfmt to preserve + // line breaks, rather than compressing things into a single line. + // This is especially important for the pattern, which should visually + // look like a grid. + // + // rustfmt provides a #[rustfmt::skip] directive that we could use, + // unfortunately, the compiler won't let it be applied in the middle of + // the code right now. It formats right, it just won't compile. + + // Air should split evenly to surrounding vacuum tiles. + #[test] + fn tick_splits_air() { + let buffers = Buffers::new(); + buffers.init_to(0); + + set_pattern( + &buffers, + &[ + "#######", // + "# #", // + "# 0 #", // + "# 0X0 #", // + "# 0 #", // + "# #", // + "#######", // + ], + set_with_defaults(|_c: char| None), + 0, + ); + + tick(&buffers).unwrap(); + + expect_pattern( + &buffers, + &[ + "#######", // + "# #", // + "# x #", // + "# xxx #", // + "# x #", // + "# #", // + "#######", // + ], + expect_with_defaults(|c: char| match c { + 'x' => Some( + TileChecker::new() // + .oxygen(20.0) + .thermal_energy(20.0), + ), + _ => None, + }), + 0, + ); + } + + // Air should not flow into walls. + #[test] + fn tick_respects_walls() { + let buffers = Buffers::new(); + buffers.init_to(0); + + set_pattern( + &buffers, + &[ + "###", // + "#X#", // + "###", // + ], + set_with_defaults(|_c: char| None), + 0, + ); + + tick(&buffers).unwrap(); + + expect_pattern( + &buffers, + &[ + "#0#", // + "0X0", // + "#0#", // + ], + expect_with_defaults(|_c: char| None), + 0, + ); + } + + // Air should flow properly into dead-end tiles. + #[test] + fn tick_handles_different_connections() { + let buffers = Buffers::new(); + buffers.init_to(0); + + set_pattern( + &buffers, + &[ + "#####", // + "##0##", // + "#0X0#", // + "##0##", // + "#####", // + ], + set_with_defaults(|_c: char| None), + 0, + ); + + tick(&buffers).unwrap(); + + expect_pattern( + &buffers, + &[ + "#####", // + "##x##", // + "#xxx#", // + "##x##", // + "#####", // + ], + expect_with_defaults(|c: char| match c { + 'x' => Some( + TileChecker::new() // + .oxygen(20.0) + .thermal_energy(20.0), + ), + _ => None, + }), + 0, + ); + } + + // Four equal dead-end tiles around a vacuum should distribute air evenly between all 5 tiles. + // Temp: Or not, because we're matching MILLA behavior. + #[test] + fn tick_merges_properly() { + let buffers = Buffers::new(); + buffers.init_to(0); + + set_pattern( + &buffers, + &[ + "#####", // + "##X##", // + "#X0X#", // + "##X##", // + "#####", // + ], + set_with_defaults(|_c: char| None), + 0, + ); + + tick(&buffers).unwrap(); + + expect_pattern( + &buffers, + &[ + "#####", // + "##x##", // + "#x!x#", // + "##x##", // + "#####", // + ], + expect_with_defaults(|c: char| match c { + '!' => Some( + TileChecker::new() // + .oxygen(200.0) + .thermal_energy(200.0), + ), + 'x' => Some( + TileChecker::new() // + .oxygen(50.0) + .thermal_energy(50.0), + ), + _ => None, + }), + 0, + ); + } + + // Energy should be transferred into superconducting walls. + #[test] + fn tick_superconducts_into_walls() { + let buffers = Buffers::new(); + buffers.init_to(0); + + set_pattern( + &buffers, + &[ + "######", // + "##XS##", // + "#S##X#", // + "#X##S#", // + "##SX##", // + "######", // + ], + set_with_defaults(|c: char| match c { + 'S' => Some( + TileBuilder::wall() // + .superconducts(OPEN_HEAT_TRANSFER_COEFFICIENT) + .innate_heat_capacity(2000.0) + .build(), + ), + _ => None, + }), + 0, + ); + + tick(&buffers).unwrap(); + + expect_pattern( + &buffers, + &[ + "######", // + "##xS##", // + "#S##x#", // + "#x##S#", // + "##Sx##", // + "######", // + ], + expect_with_defaults(|c: char| match c { + 'x' => Some( + TileChecker::new() // + .oxygen(100.0) + // This value is arbitrary, it's just what we get right now. + // Update it if the calculations changed intentionally. + .thermal_energy(80.0), + ), + 'S' => Some( + TileChecker::new() // + // This value is arbitrary, it's just what we get right now. + // Update it if the calculations changed intentionally. + .thermal_energy(20.0), + ), + _ => None, + }), + 0, + ); + } + + // Air should flow into a space tile, and be deleted. + #[test] + fn tick_empties_space() { + let buffers = Buffers::new(); + buffers.init_to(0); + + set_pattern( + &buffers, + &[ + "#####", // + "##X##", // + "#X X#", // + "##X##", // + "#####", // + ], + set_with_defaults(|c: char| match c { + 'x' => Some( + TileBuilder::sealed() // + .oxygen(100.0) + .thermal_energy(100.0) + .build(), + ), + _ => None, + }), + 0, + ); + + tick(&buffers).unwrap(); + + expect_pattern( + &buffers, + &[ + "#####", // + "##x##", // + "#x0x#", // + "##x##", // + "#####", // + ], + expect_with_defaults(|c: char| match c { + 'x' => Some( + TileChecker::new() // + .oxygen(50.0) + .thermal_energy(50.0), + ), + _ => None, + }), + 0, + ); + } + + // Air should tend towards the environment's temperature, if any. + #[test] + fn tick_affected_by_environment_temperature() { + let buffers = Buffers::new(); + buffers.init_to(0); + let lavaland = buffers.create_environment( + TileBuilder::sealed() // + .oxygen(8.0) + .nitrogen(14.0) + .temperature(500.0) + .build(), + ); + + set_pattern( + &buffers, + &[ + "###", // + "#X#", // + "###", // + ], + set_with_defaults(|c: char| match c { + 'X' => Some( + TileBuilder::exposed_to(lavaland) + .oxygen(8.0) + .nitrogen(14.0) + .thermal_energy(0.0) + .build(), + ), + _ => None, + }), + 0, + ); + + tick(&buffers).unwrap(); + + expect_pattern( + &buffers, + &[ + "###", // + "#Y#", // + "###", // + ], + expect_with_defaults(|c: char| match c { + 'Y' => Some( + TileChecker::new() // + .oxygen(8.0) + .nitrogen(14.0) + // This value is arbitrary, it's just what we get right now. + // Update it if the calculations changed intentionally. + .thermal_energy(44_000.0), + ), + _ => None, + }), + 0, + ); + } + + // Air should exchange with the tile's environment, if any. + #[test] + fn tick_affected_by_environment() { + let buffers = Buffers::new(); + buffers.init_to(0); + let lavaland = buffers.create_environment( + TileBuilder::sealed() // + .oxygen(8.0) + .nitrogen(14.0) + .temperature(500.0) + .build(), + ); + + set_pattern( + &buffers, + &[ + "###", // + "#X#", // + "###", // + ], + set_with_defaults(|c: char| match c { + 'X' => Some(TileBuilder::exposed_to(lavaland).build()), + _ => None, + }), + 0, + ); + + tick(&buffers).unwrap(); + + expect_pattern( + &buffers, + &[ + "###", // + "#Y#", // + "###", // + ], + expect_with_defaults(|c: char| match c { + 'Y' => Some( + TileChecker::new() // + .oxygen(4.0) + .nitrogen(7.0) + .temperature(500.0), + ), + _ => None, + }), + 0, + ); + } +} diff --git a/paradise.dme b/paradise.dme index b8d7a5c5e01..f79ae27cc6f 100644 --- a/paradise.dme +++ b/paradise.dme @@ -87,6 +87,7 @@ #include "code\__DEFINES\mecha_defines.dm" #include "code\__DEFINES\mecha_hides.dm" #include "code\__DEFINES\medal.dm" +#include "code\__DEFINES\milla.dm" #include "code\__DEFINES\misc_defines.dm" #include "code\__DEFINES\mob_defines.dm" #include "code\__DEFINES\mod.dm" diff --git a/tools/ci/libmilla_ci.so b/tools/ci/libmilla_ci.so new file mode 100755 index 00000000000..877c0069516 Binary files /dev/null and b/tools/ci/libmilla_ci.so differ diff --git a/tools/tgs_scripts/PreCompile.sh b/tools/tgs_scripts/PreCompile.sh index 349093b515f..2b93c8df538 100755 --- a/tools/tgs_scripts/PreCompile.sh +++ b/tools/tgs_scripts/PreCompile.sh @@ -44,3 +44,9 @@ cd paradise-rust-g env PKG_CONFIG_ALLOW_CROSS=1 ~/.cargo/bin/cargo build --release --features all --target=i686-unknown-linux-gnu mv target/i686-unknown-linux-gnu/release/librust_g.so "$1/librust_g.so" cd ../../ + +echo "Deploying MILLA..." +cd $1/milla +env PKG_CONFIG_ALLOW_CROSS=1 ~/.cargo/bin/cargo build --release --features all --target=i686-unknown-linux-gnu +mv target/i686-unknown-linux-gnu/release/libmilla.so "$1/libmilla.so" +cd ..