diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml
index 43eeda344d694..d628c813e36b9 100644
--- a/.github/workflows/run_integration_tests.yml
+++ b/.github/workflows/run_integration_tests.yml
@@ -48,9 +48,6 @@ jobs:
# - name: Install dreamluau
# run: |
# bash tools/ci/install_dreamluau.sh
- - name: Install auxmos
- run: |
- bash tools/ci/install_auxmos.sh
- name: Configure version
run: |
echo "BYOND_MAJOR=${{ inputs.major }}" >> $GITHUB_ENV
diff --git a/Dockerfile b/Dockerfile
index 185132e507a8f..e82cab34b1222 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -27,15 +27,6 @@ RUN git init \
&& git checkout FETCH_HEAD \
&& cargo build --release --all-features --target i686-unknown-linux-gnu
-# Build auxmos
-FROM rust-build as auxmos
-RUN git init \
- && git remote add origin https://github.com/BeeStation/auxmos \
- && /bin/bash -c "source dependencies.sh \
- && git fetch --depth 1 origin \$AUXMOS_VERSION" \
- && git checkout FETCH_HEAD \
- && cargo rustc --target=i686-unknown-linux-gnu --release --features=trit_fire_hook,plasma_fire_hook,generic_fire_hook
-
# Install nodejs which is required to deploy BeeStation
FROM base as node
COPY dependencies.sh .
@@ -51,7 +42,6 @@ ENV TG_BOOTSTRAP_NODE_LINUX=1
WORKDIR /dm-build
COPY . .
# Required to satisfy our compile_options
-COPY --from=auxmos /build/target/i686-unknown-linux-gnu/release/libauxmos.so /dm-build/auxtools/libauxmos.so
RUN tools/build/build \
&& tools/deploy.sh /deploy \
&& apt-get autoremove curl -y \
diff --git a/_maps/RandomRooms/10x10/sk_rdm134_snowforest.dmm b/_maps/RandomRooms/10x10/sk_rdm134_snowforest.dmm
index 62b0715fbedef..83fb295deb9bd 100644
--- a/_maps/RandomRooms/10x10/sk_rdm134_snowforest.dmm
+++ b/_maps/RandomRooms/10x10/sk_rdm134_snowforest.dmm
@@ -1,114 +1,128 @@
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
"a" = (
/obj/effect/turf_decal/tile/blue,
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"d" = (
/obj/effect/turf_decal/tile/blue{
dir = 8
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"f" = (
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"g" = (
/obj/effect/spawner/lootdrop/costume,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"h" = (
/obj/structure/flora/bush,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"j" = (
/obj/structure/flora/tree/pine,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"k" = (
/obj/effect/spawner/lootdrop/gloves,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"m" = (
/obj/item/dnainjector/geladikinesis,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"o" = (
/obj/item/soap,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"p" = (
/obj/item/clothing/shoes/winterboots,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"q" = (
/obj/effect/spawner/lootdrop/grille_or_trash,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"r" = (
/obj/structure/statue/snow/snowman,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"s" = (
/obj/effect/trap/trigger/reusable/all,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"t" = (
/obj/item/clothing/suit/hooded/wintercoat,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"u" = (
/obj/item/hatchet,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"v" = (
/obj/effect/turf_decal/tile/blue{
dir = 4
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"y" = (
/obj/effect/turf_decal/tile/blue{
dir = 1
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"z" = (
/obj/effect/trap/nexus/trickyspawner/tree,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"A" = (
/obj/effect/trap/nexus/darkness,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"B" = (
/obj/effect/spawner/lootdrop/maintenance,
/obj/effect/trap/nexus/trickyspawner/tree,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"C" = (
/obj/item/shovel,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"D" = (
/obj/item/nullrod/chainsaw,
-/turf/open/floor/plating/asteroid/snow,
+/turf/open/floor/plating/asteroid/snow/temperatre,
/area/template_noop)
"G" = (
/obj/effect/turf_decal/tile/blue/half/contrasted,
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"L" = (
/obj/machinery/light{
dir = 8
},
/obj/effect/turf_decal/tile/blue/half/contrasted,
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"M" = (
/obj/effect/turf_decal/tile/blue/half/contrasted{
dir = 4
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"O" = (
/obj/machinery/light{
@@ -117,7 +131,9 @@
/obj/effect/turf_decal/tile/blue/half/contrasted{
dir = 8
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"P" = (
/obj/machinery/light{
@@ -126,26 +142,34 @@
/obj/effect/turf_decal/tile/blue/half/contrasted{
dir = 1
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"S" = (
/obj/machinery/light,
/obj/effect/turf_decal/tile/blue/half/contrasted{
dir = 4
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"T" = (
/obj/effect/turf_decal/tile/blue/half/contrasted{
dir = 1
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
"Z" = (
/obj/effect/turf_decal/tile/blue/half/contrasted{
dir = 8
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark{
+ initial_gas_mix = "o2=22;n2=82;TEMP=255.37"
+ },
/area/template_noop)
(1,1,1) = {"
diff --git a/_maps/RandomRooms/3x3/sk_rdm009_airstation.dmm b/_maps/RandomRooms/3x3/sk_rdm009_airstation.dmm
index 46946f44c55ab..b965f2e8ceb8f 100644
--- a/_maps/RandomRooms/3x3/sk_rdm009_airstation.dmm
+++ b/_maps/RandomRooms/3x3/sk_rdm009_airstation.dmm
@@ -17,7 +17,7 @@
/turf/open/floor/plating,
/area/template_noop)
"d" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8
},
/obj/machinery/light{
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_animal_hospital.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_animal_hospital.dmm
index 344afa36d5b7e..d5c0f7e685a2e 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_animal_hospital.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_animal_hospital.dmm
@@ -265,7 +265,7 @@
},
/area/lavaland/surface/outdoors)
"ca" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/turf/open/floor/grass{
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm
index 8dee467d9b536..28dc55ae6e601 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_golem_ship.dmm
@@ -161,7 +161,9 @@
dir = 8;
icon_state = "pwindow"
},
-/turf/open/floor/plating,
+/turf/open/floor/plating{
+ initial_gas_mix = "o2=14;n2=5;co2=13;TEMP=300"
+ },
/area/ruin/powered/golem_ship)
"aA" = (
/turf/template_noop,
@@ -331,7 +333,9 @@
dir = 4;
icon_state = "huge_engine"
},
-/turf/open/floor/plating,
+/turf/open/floor/plating{
+ initial_gas_mix = "o2=14;n2=5;co2=13;TEMP=300"
+ },
/area/ruin/powered/golem_ship)
"bc" = (
/obj/structure/fans/tiny,
@@ -891,6 +895,11 @@
/obj/item/storage/toolbox/mechanical,
/turf/open/floor/plating,
/area/ruin/powered/golem_ship)
+"YQ" = (
+/turf/open/floor/plating{
+ initial_gas_mix = "o2=14;n2=5;co2=13;TEMP=300"
+ },
+/area/ruin/powered/golem_ship)
(1,1,1) = {"
aa
@@ -1336,8 +1345,8 @@ ab
(22,1,1) = {"
aa
ab
-af
-af
+YQ
+YQ
bb
ab
aa
@@ -1348,8 +1357,8 @@ aa
aa
aa
ab
-af
-af
+YQ
+YQ
bb
ab
aa
@@ -1357,9 +1366,9 @@ aa
(23,1,1) = {"
aa
aa
-af
-af
-af
+YQ
+YQ
+YQ
aa
aa
aa
@@ -1369,9 +1378,9 @@ aa
aa
aa
aa
-af
-af
-af
+YQ
+YQ
+YQ
aa
aa
"}
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm
index e78618e875b3a..ea118be14b310 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_hermit.dmm
@@ -153,16 +153,22 @@
/obj/machinery/door/airlock/titanium{
name = "Escape Pod Airlock"
},
-/turf/open/floor/mineral/titanium/blue,
+/turf/open/floor/mineral/titanium/blue{
+ initial_gas_mix = "o2=14;n2=5;co2=13;TEMP=300"
+ },
/area/ruin/powered)
"I" = (
/obj/structure/chair{
dir = 4
},
-/turf/open/floor/mineral/titanium/blue,
+/turf/open/floor/mineral/titanium/blue{
+ initial_gas_mix = "o2=14;n2=5;co2=13;TEMP=300"
+ },
/area/ruin/powered)
"J" = (
-/turf/open/floor/mineral/titanium/blue,
+/turf/open/floor/mineral/titanium/blue{
+ initial_gas_mix = "o2=14;n2=5;co2=13;TEMP=300"
+ },
/area/ruin/powered)
"M" = (
/obj/item/stack/sheet/iron/twenty,
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_pride.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_pride.dmm
index b46f581539b68..cf4938f3690b1 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_pride.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_pride.dmm
@@ -73,7 +73,9 @@
/area/ruin/powered/pride)
"Y" = (
/obj/machinery/door/airlock/diamond,
-/turf/open/floor/mineral/silver,
+/turf/open/floor/mineral/silver{
+ blocks_air = 1
+ },
/area/ruin/powered/pride)
(1,1,1) = {"
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_puzzle.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_puzzle.dmm
index 911ee904fe5d0..af5a30e2981a4 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_puzzle.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_puzzle.dmm
@@ -1,6 +1,6 @@
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
"a" = (
-/turf/template_noop,
+/turf/template_noop/open,
/area/lavaland/surface/outdoors)
"b" = (
/obj/effect/sliding_puzzle/lavaland,
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
index 73e6ae270c375..0646a736004a9 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm
@@ -222,7 +222,7 @@
/turf/open/floor/plating,
/area/ruin/powered/seedvault)
"jY" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/obj/structure/closet,
/turf/open/floor/pod,
/area/ruin/powered/seedvault)
@@ -264,7 +264,7 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/grass,
+/turf/template_noop/open,
/area/lavaland/surface/outdoors)
"kN" = (
/obj/structure/railing/corner{
@@ -399,7 +399,8 @@
"qR" = (
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/stairs/left{
- dir = 8
+ dir = 8;
+ initial_gas_mix = "o2=14;n2=5;co2=13;TEMP=300"
},
/area/lavaland/surface/outdoors)
"qX" = (
@@ -612,7 +613,7 @@
/obj/structure/railing,
/obj/structure/flora/ausbushes/sparsegrass,
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/grass,
+/turf/template_noop/open,
/area/lavaland/surface/outdoors)
"Be" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
@@ -774,7 +775,8 @@
"Gt" = (
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/iron/stairs/right{
- dir = 8
+ dir = 8;
+ initial_gas_mix = "o2=14;n2=5;co2=13;TEMP=300"
},
/area/lavaland/surface/outdoors)
"Gz" = (
@@ -824,9 +826,6 @@
},
/turf/open/floor/pod,
/area/ruin/powered/seedvault)
-"ID" = (
-/turf/open/floor/grass,
-/area/lavaland/surface/outdoors)
"IL" = (
/obj/machinery/light,
/obj/machinery/vending/hydronutrients,
@@ -1144,8 +1143,8 @@
/area/ruin/powered/seedvault)
"Qu" = (
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/grass,
-/area/lavaland/surface/outdoors)
+/turf/open/floor/iron/stairs/left,
+/area/ruin/powered/seedvault)
"Qv" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{
dir = 8
@@ -1689,7 +1688,7 @@ sG
dK
rb
GA
-Nn
+Qu
Qb
Ex
Gz
@@ -1793,7 +1792,7 @@ GC
GC
GC
GC
-Qu
+cp
aj
dM
dM
@@ -1802,7 +1801,7 @@ dw
dM
dM
kG
-ID
+GC
GC
GC
GC
@@ -1823,7 +1822,7 @@ MZ
MZ
br
kq
-Qu
+cp
GC
GC
GC
@@ -1863,7 +1862,7 @@ ab
GC
GC
kN
-ID
+GC
cp
uB
GC
diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_sloth.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_sloth.dmm
index 2089bc287fb1e..d07c93e33bf85 100644
--- a/_maps/RandomRuins/LavaRuins/lavaland_surface_sloth.dmm
+++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_sloth.dmm
@@ -8,17 +8,20 @@
"c" = (
/obj/item/paper/fluff/stations/lavaland/sloth/note,
/turf/open/floor/sepia{
+ blocks_air = 0;
slowdown = 10
},
/area/ruin/unpowered)
"d" = (
/turf/open/floor/sepia{
+ blocks_air = 0;
slowdown = 10
},
/area/ruin/unpowered)
"e" = (
/obj/machinery/door/airlock/wood,
/turf/open/floor/sepia{
+ blocks_air = 0;
slowdown = 10
},
/area/ruin/unpowered)
@@ -26,6 +29,7 @@
/obj/structure/table/wood,
/obj/item/food/grown/citrus/orange,
/turf/open/floor/sepia{
+ blocks_air = 0;
slowdown = 10
},
/area/ruin/unpowered)
@@ -33,6 +37,7 @@
/obj/structure/bed,
/obj/item/bedsheet/brown,
/turf/open/floor/sepia{
+ blocks_air = 0;
slowdown = 10
},
/area/ruin/unpowered)
diff --git a/_maps/RandomRuins/SpaceRuins/Fast_Food.dmm b/_maps/RandomRuins/SpaceRuins/Fast_Food.dmm
index 9d236a1dcd6a5..af184e561c945 100644
--- a/_maps/RandomRuins/SpaceRuins/Fast_Food.dmm
+++ b/_maps/RandomRuins/SpaceRuins/Fast_Food.dmm
@@ -12,7 +12,7 @@
/turf/closed/wall,
/area/ruin/space/has_grav/powered/macspace)
"af" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/iron/cafeteria,
/area/ruin/space/has_grav/powered/macspace)
"ag" = (
@@ -787,7 +787,7 @@
/turf/closed/wall,
/area/ruin/space/has_grav/powered/macspace)
"dk" = (
-/obj/machinery/atmospherics/components/unary/tank/oxygen,
+/obj/machinery/atmospherics/components/tank/oxygen,
/turf/open/floor/mineral/titanium,
/area/ruin/space/has_grav/powered/macspace)
"dl" = (
diff --git a/_maps/RandomRuins/SpaceRuins/TheDerelict.dmm b/_maps/RandomRuins/SpaceRuins/TheDerelict.dmm
index 2f1b40c5b4bb0..c722f4d0a0a68 100644
--- a/_maps/RandomRuins/SpaceRuins/TheDerelict.dmm
+++ b/_maps/RandomRuins/SpaceRuins/TheDerelict.dmm
@@ -3402,7 +3402,7 @@
/turf/open/floor/plating/airless,
/area/ruin/space/derelict/atmospherics)
"lw" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/plating/airless,
/area/ruin/space/derelict/atmospherics)
"lx" = (
diff --git a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm
index 7e92a59ce4b1d..bc986e58b4e59 100644
--- a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm
+++ b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm
@@ -733,7 +733,7 @@
/turf/open/floor/plating/airless,
/area/shuttle/caravan/freighter3)
"jH" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 4
},
/obj/effect/turf_decal/stripes/line{
diff --git a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm
index 89618fd243b0a..8d1ac6a860c62 100644
--- a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm
+++ b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm
@@ -536,7 +536,7 @@
/turf/open/floor/plating,
/area/ruin/space/has_grav/listeningstation)
"bH" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/obj/effect/turf_decal/bot,
diff --git a/_maps/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/RandomRuins/SpaceRuins/oldstation.dmm
index 2a114fb99921f..1feef14d2b856 100644
--- a/_maps/RandomRuins/SpaceRuins/oldstation.dmm
+++ b/_maps/RandomRuins/SpaceRuins/oldstation.dmm
@@ -3403,7 +3403,7 @@
/area/ruin/space/has_grav/ancientstation/atmo)
"kC" = (
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/turf/open/floor/plating,
diff --git a/_maps/RandomRuins/SpaceRuins/spacehotel.dmm b/_maps/RandomRuins/SpaceRuins/spacehotel.dmm
index adeeca1933aa7..f31909e37622c 100644
--- a/_maps/RandomRuins/SpaceRuins/spacehotel.dmm
+++ b/_maps/RandomRuins/SpaceRuins/spacehotel.dmm
@@ -3105,14 +3105,14 @@
/turf/open/floor/iron/freezer,
/area/ruin/space/has_grav/hotel/pool)
"lp" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/turf/open/floor/plating,
/area/ruin/space/has_grav/hotel/power)
"lq" = (
/obj/machinery/light/small,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/turf/open/floor/plating,
diff --git a/_maps/RandomZLevels/moonoutpost19.dmm b/_maps/RandomZLevels/moonoutpost19.dmm
index 601b3cd395d35..abcc1fd38408f 100644
--- a/_maps/RandomZLevels/moonoutpost19.dmm
+++ b/_maps/RandomZLevels/moonoutpost19.dmm
@@ -79,8 +79,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged2";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"bd" = (
@@ -122,8 +121,7 @@
/obj/structure/alien/weeds,
/obj/effect/turf_decal/tile/red/half/contrasted,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"bM" = (
@@ -185,8 +183,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged3";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"cS" = (
@@ -564,8 +561,7 @@
dir = 1
},
/turf/open/floor/iron/cafeteria{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"gW" = (
@@ -886,8 +882,7 @@
},
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"jn" = (
@@ -1013,8 +1008,7 @@
/turf/open/floor/plating{
icon_plating = "asteroidplating";
icon_state = "asteroidplating";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/main)
"kZ" = (
@@ -1097,8 +1091,7 @@
dir = 8
},
/turf/open/floor/plating{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"lQ" = (
@@ -1339,8 +1332,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/tile/red/half/contrasted,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"nN" = (
@@ -1413,15 +1405,13 @@
dir = 9
},
/turf/open/floor/plating{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"oQ" = (
/obj/effect/turf_decal/tile/red/half/contrasted,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"oY" = (
@@ -1570,8 +1560,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"qz" = (
@@ -1599,8 +1588,7 @@
/turf/open/floor/plating{
icon_plating = "asteroidplating";
icon_state = "asteroidplating";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"qK" = (
@@ -1622,8 +1610,7 @@
/turf/open/floor/plating{
icon_plating = "asteroidplating";
icon_state = "asteroidplating";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"qO" = (
@@ -1637,8 +1624,7 @@
},
/turf/open/floor/plating{
broken = 1;
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"qU" = (
@@ -1764,8 +1750,7 @@
dir = 4
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"rI" = (
@@ -1802,16 +1787,14 @@
},
/obj/structure/alien/weeds,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"sn" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"sB" = (
@@ -1819,8 +1802,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"sK" = (
@@ -1858,8 +1840,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "floorscorched2";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"th" = (
@@ -1905,8 +1886,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"tB" = (
@@ -1959,8 +1939,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"tW" = (
@@ -1985,8 +1964,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged1";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"un" = (
@@ -2145,8 +2123,7 @@
dir = 1
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"vL" = (
@@ -2218,8 +2195,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "floorscorched2";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"wn" = (
@@ -2296,8 +2272,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/tile/red/half/contrasted,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"wO" = (
@@ -2308,16 +2283,14 @@
dir = 4
},
/turf/open/floor/plating{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"wQ" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/tile/neutral/half/contrasted,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"wV" = (
@@ -2411,8 +2384,7 @@
dir = 1
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"ye" = (
@@ -2427,8 +2399,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"yr" = (
@@ -2473,8 +2444,7 @@
dir = 4
},
/turf/open/floor/plating{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"yP" = (
@@ -2489,8 +2459,7 @@
},
/turf/open/floor/plating{
broken = 1;
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"yV" = (
@@ -2530,8 +2499,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged5";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"zi" = (
@@ -2595,8 +2563,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "floorscorched2";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"zF" = (
@@ -2660,8 +2627,7 @@
dir = 1
},
/turf/open/floor/iron/cafeteria{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Aw" = (
@@ -2695,8 +2661,7 @@
},
/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"AE" = (
@@ -2717,9 +2682,7 @@
},
/obj/item/storage/box/mousetraps,
/obj/item/clothing/under/suit/waiter,
-/turf/open/floor/iron/showroomfloor{
- initial_temperature = 273.15
- },
+/turf/open/floor/iron/showroomfloor,
/area/awaymission/moonoutpost19/arrivals)
"AG" = (
/obj/structure/sign/warning/vacuum{
@@ -2732,8 +2695,7 @@
dir = 10
},
/turf/open/floor/plating{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"AH" = (
@@ -2762,8 +2724,7 @@
/obj/item/stack/rods,
/turf/open/floor/plating{
broken = 1;
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"AT" = (
@@ -2771,8 +2732,7 @@
/obj/effect/turf_decal/loading_area,
/obj/structure/alien/weeds,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"AZ" = (
@@ -2800,8 +2760,7 @@
dir = 1
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Bj" = (
@@ -2920,8 +2879,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "floorscorched2";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Cx" = (
@@ -2952,8 +2910,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Dc" = (
@@ -2993,8 +2950,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged4";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Ds" = (
@@ -3025,8 +2981,7 @@
dir = 1
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"DI" = (
@@ -3087,8 +3042,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"EE" = (
@@ -3104,8 +3058,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"EF" = (
@@ -3116,8 +3069,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"EM" = (
@@ -3241,8 +3193,7 @@
},
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"FL" = (
@@ -3320,17 +3271,14 @@
},
/turf/open/floor/plating{
broken = 1;
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Gz" = (
/turf/open/floor/iron/dark,
/area/awaymission/moonoutpost19/syndicate)
"GA" = (
-/turf/open/floor/iron/showroomfloor{
- initial_temperature = 273.15
- },
+/turf/open/floor/iron/showroomfloor,
/area/awaymission/moonoutpost19/arrivals)
"GE" = (
/obj/structure/cable{
@@ -3379,8 +3327,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged2";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"GP" = (
@@ -3448,8 +3395,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Hi" = (
@@ -3465,8 +3411,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Hq" = (
@@ -3509,8 +3454,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"HE" = (
@@ -3560,8 +3504,7 @@
dir = 5
},
/turf/open/floor/plating{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"HU" = (
@@ -3570,8 +3513,7 @@
},
/obj/effect/turf_decal/tile/red/half/contrasted,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Ia" = (
@@ -3582,8 +3524,7 @@
/turf/open/floor/plating{
icon_plating = "asteroidplating";
icon_state = "asteroidplating";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/main)
"Ic" = (
@@ -3656,8 +3597,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged1";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"IA" = (
@@ -3716,8 +3656,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged1";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Jd" = (
@@ -3752,8 +3691,7 @@
"Jn" = (
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Jq" = (
@@ -3765,8 +3703,7 @@
"Ju" = (
/obj/effect/turf_decal/tile/neutral/half/contrasted,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"JC" = (
@@ -3888,8 +3825,7 @@
/turf/open/floor/plating{
icon_plating = "asteroidplating";
icon_state = "asteroidplating";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"KK" = (
@@ -3909,8 +3845,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged1";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"KR" = (
@@ -4078,8 +4013,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Mg" = (
@@ -4092,8 +4026,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Mi" = (
@@ -4124,8 +4057,7 @@
},
/obj/effect/turf_decal/tile/red/half/contrasted,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Ms" = (
@@ -4247,9 +4179,7 @@
name = "old sink";
pixel_y = 28
},
-/turf/open/floor/iron/showroomfloor{
- initial_temperature = 273.15
- },
+/turf/open/floor/iron/showroomfloor,
/area/awaymission/moonoutpost19/arrivals)
"Nq" = (
/obj/structure/table,
@@ -4265,8 +4195,7 @@
/turf/open/floor/plating{
icon_plating = "asteroidplating";
icon_state = "asteroidplating";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Nv" = (
@@ -4305,8 +4234,7 @@
},
/turf/open/floor/iron{
dir = 1;
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"NE" = (
@@ -4334,16 +4262,13 @@
/obj/item/reagent_containers/condiment/milk,
/obj/item/reagent_containers/condiment/milk,
/obj/item/storage/fancy/egg_box,
-/turf/open/floor/iron/showroomfloor{
- initial_temperature = 273.15
- },
+/turf/open/floor/iron/showroomfloor,
/area/awaymission/moonoutpost19/arrivals)
"NM" = (
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged2";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"NQ" = (
@@ -4387,8 +4312,7 @@
dir = 1
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Og" = (
@@ -4461,8 +4385,7 @@
dir = 6
},
/turf/open/floor/plating{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"OL" = (
@@ -4519,8 +4442,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged3";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"OU" = (
@@ -4594,8 +4516,7 @@
dir = 4
},
/turf/open/floor/plating{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Po" = (
@@ -4674,8 +4595,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "damaged4";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"PK" = (
@@ -4686,8 +4606,7 @@
},
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"PP" = (
@@ -4731,8 +4650,7 @@
/obj/structure/alien/weeds,
/obj/effect/turf_decal/tile/red/anticorner/contrasted,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"PY" = (
@@ -4824,9 +4742,7 @@
/obj/item/reagent_containers/condiment/flour,
/obj/item/reagent_containers/condiment/sugar,
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/iron/showroomfloor{
- initial_temperature = 273.15
- },
+/turf/open/floor/iron/showroomfloor,
/area/awaymission/moonoutpost19/arrivals)
"Rb" = (
/obj/machinery/light/small{
@@ -4866,8 +4782,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "floorscorched1";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Rn" = (
@@ -4899,8 +4814,7 @@
/turf/open/floor/plating{
icon_plating = "asteroidplating";
icon_state = "asteroidplating";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/main)
"Rr" = (
@@ -4908,8 +4822,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Ru" = (
@@ -4934,8 +4847,7 @@
/turf/open/floor/iron{
dir = 8;
icon_state = "floorscorched2";
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Rx" = (
@@ -5012,8 +4924,7 @@
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating{
broken = 1;
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Sz" = (
@@ -5052,8 +4963,7 @@
"Te" = (
/turf/open/floor/plating{
broken = 1;
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Th" = (
@@ -5097,8 +5007,7 @@
},
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"TF" = (
@@ -5111,9 +5020,7 @@
/obj/item/food/meat/slab/monkey,
/obj/item/food/meat/slab/monkey,
/obj/item/food/meat/slab/monkey,
-/turf/open/floor/iron/showroomfloor{
- initial_temperature = 273.15
- },
+/turf/open/floor/iron/showroomfloor,
/area/awaymission/moonoutpost19/arrivals)
"TG" = (
/obj/effect/spawner/structure/window/reinforced,
@@ -5307,8 +5214,7 @@
},
/turf/open/floor/iron{
dir = 1;
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Vy" = (
@@ -5391,8 +5297,7 @@
dir = 8
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Wg" = (
@@ -5567,9 +5472,7 @@
desc = "They look like human remains. The skeleton is sitting upright with its legs tucked in and hands still holding onto its arms."
},
/obj/item/gun/ballistic/shotgun/sc_pump,
-/turf/open/floor/iron/showroomfloor{
- initial_temperature = 273.15
- },
+/turf/open/floor/iron/showroomfloor,
/area/awaymission/moonoutpost19/arrivals)
"XY" = (
/obj/structure/bed,
@@ -5587,8 +5490,7 @@
"Yj" = (
/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Yk" = (
@@ -5610,8 +5512,7 @@
/obj/effect/decal/cleanable/generic,
/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"Yq" = (
@@ -5629,8 +5530,7 @@
dir = 4
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Ys" = (
@@ -5644,8 +5544,7 @@
"Yz" = (
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/arrivals)
"YA" = (
@@ -5685,8 +5584,7 @@
/obj/item/pickaxe,
/turf/open/floor/plating{
broken = 1;
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"YX" = (
@@ -5724,8 +5622,7 @@
dir = 1
},
/turf/open/floor/iron{
- initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251";
- initial_temperature = 251
+ initial_gas_mix = "co2=48.7;n2=13.2;o2=32.4;TEMP=251"
},
/area/awaymission/moonoutpost19/syndicate)
"Zp" = (
diff --git a/_maps/RandomZLevels/snowdin.dmm b/_maps/RandomZLevels/snowdin.dmm
index 1520fd80e77e0..667b38c6a167e 100644
--- a/_maps/RandomZLevels/snowdin.dmm
+++ b/_maps/RandomZLevels/snowdin.dmm
@@ -1340,14 +1340,14 @@
"gc" = (
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"gd" = (
/obj/effect/spawner/lootdrop/crate_spawner,
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"ge" = (
@@ -1358,7 +1358,7 @@
/obj/effect/spawner/lootdrop/snowdin/dungeonheavy,
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"gg" = (
@@ -1546,14 +1546,14 @@
/obj/effect/decal/remains/human,
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"gV" = (
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"gW" = (
@@ -1703,7 +1703,7 @@
/obj/structure/destructible/cult/pylon,
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"hG" = (
@@ -1851,7 +1851,7 @@
/obj/effect/spawner/lootdrop/snowdin/dungeonmid,
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"im" = (
@@ -1861,7 +1861,7 @@
},
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"in" = (
@@ -1871,7 +1871,7 @@
},
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"is" = (
@@ -2169,7 +2169,7 @@
},
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"jQ" = (
@@ -2464,7 +2464,7 @@
/obj/effect/spawner/lootdrop/snowdin/dungeonlite,
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"lU" = (
@@ -3540,7 +3540,7 @@
/obj/structure/flora/rock/pile/icy,
/turf/open/floor/engine/cult{
initial_gas_mix = "n2=82;plasma=24;TEMP=120";
- initial_temperature = 120
+ temperature = 120
},
/area/awaymission/snowdin/cave/cavern)
"qh" = (
@@ -7992,7 +7992,7 @@
/turf/open/floor/mineral/plastitanium{
initial_gas_mix = "o2=22;n2=82;TEMP=180";
planetary_atmos = 1;
- initial_temperature = 180
+ temperature = 180
},
/area/awaymission/snowdin/cave)
"EF" = (
@@ -8004,7 +8004,7 @@
/turf/open/floor/mineral/plastitanium{
initial_gas_mix = "o2=22;n2=82;TEMP=180";
planetary_atmos = 1;
- initial_temperature = 180
+ temperature = 180
},
/area/awaymission/snowdin/cave)
"EG" = (
@@ -8018,7 +8018,7 @@
/turf/open/floor/mineral/plastitanium{
initial_gas_mix = "o2=22;n2=82;TEMP=180";
planetary_atmos = 1;
- initial_temperature = 180
+ temperature = 180
},
/area/awaymission/snowdin/cave)
"EH" = (
diff --git a/_maps/RandomZLevels/undergroundoutpost45.dmm b/_maps/RandomZLevels/undergroundoutpost45.dmm
index 1dc69fd3463f5..f75f6aaaecb1f 100644
--- a/_maps/RandomZLevels/undergroundoutpost45.dmm
+++ b/_maps/RandomZLevels/undergroundoutpost45.dmm
@@ -165,7 +165,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/research)
@@ -446,7 +445,6 @@
/obj/effect/decal/cleanable/blood/splatter,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -550,7 +548,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -749,7 +746,6 @@
"fh" = (
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -1051,7 +1047,6 @@
/obj/structure/alien/weeds,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -1066,7 +1061,6 @@
/obj/effect/decal/cleanable/blood/gibs/up,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -1086,7 +1080,6 @@
/obj/structure/bed/nest,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -1242,7 +1235,6 @@
/obj/structure/ore_box,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -1551,7 +1543,6 @@
/obj/structure/glowshroom/single,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 351.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -2730,7 +2721,6 @@
/obj/effect/decal/cleanable/blood/gibs/down,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -2856,7 +2846,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -2917,7 +2906,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -3027,7 +3015,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/central)
@@ -3237,7 +3224,6 @@
/obj/effect/decal/cleanable/blood/gibs/limb,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -3298,7 +3284,6 @@
/obj/structure/alien/weeds,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -3386,7 +3371,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -3463,13 +3447,6 @@
},
/turf/open/floor/iron,
/area/awaymission/undergroundoutpost45/crew_quarters)
-"Br" = (
-/turf/open/floor/plating/asteroid{
- initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 351.9;
- name = "Cave Floor"
- },
-/area/awaymission/undergroundoutpost45/caves)
"Bs" = (
/obj/structure/cable{
icon_state = "1-2"
@@ -3800,7 +3777,6 @@
/obj/effect/decal/cleanable/blood/splatter,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -4325,7 +4301,6 @@
/obj/effect/mob_spawn/human,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -4359,7 +4334,6 @@
/obj/structure/closet/crate,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -4400,7 +4374,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -4418,7 +4391,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -4942,8 +4914,7 @@
/turf/open/floor/plating{
icon_plating = "asteroidplating";
icon_state = "asteroidplating";
- initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9
+ initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9"
},
/area/awaymission/undergroundoutpost45/caves)
"Gs" = (
@@ -4998,7 +4969,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/mining)
@@ -5122,7 +5092,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/gateway)
@@ -5178,7 +5147,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/crew_quarters)
@@ -5429,7 +5397,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/crew_quarters)
@@ -5574,7 +5541,6 @@
/obj/effect/mob_spawn/human,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -6061,7 +6027,6 @@
/obj/structure/alien/resin/membrane,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -6186,7 +6151,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/mining)
@@ -7368,7 +7332,6 @@
/obj/structure/glowshroom/single,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -7856,7 +7819,6 @@
/obj/machinery/light/small,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/research)
@@ -8043,7 +8005,6 @@
/obj/machinery/light/small,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/gateway)
@@ -8146,7 +8107,6 @@
/obj/machinery/light/small,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/crew_quarters)
@@ -8621,7 +8581,6 @@
/obj/effect/mob_spawn/human,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -8842,7 +8801,6 @@
/obj/effect/decal/cleanable/blood/gibs/core,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -8906,7 +8864,6 @@
/obj/structure/alien/resin/wall,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -8964,7 +8921,6 @@
/obj/effect/decal/cleanable/blood/gibs/down,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -9302,7 +9258,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/research)
@@ -9412,7 +9367,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/central)
@@ -9511,7 +9465,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -9567,14 +9520,6 @@
},
/turf/open/floor/carpet,
/area/awaymission/undergroundoutpost45/central)
-"WE" = (
-/obj/structure/glowshroom/single,
-/turf/open/floor/plating/asteroid{
- initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
- name = "Cave Floor"
- },
-/area/awaymission/undergroundoutpost45/caves)
"WG" = (
/obj/machinery/door/airlock{
name = "Unisex Restrooms"
@@ -9681,7 +9626,6 @@
/obj/effect/mob_spawn/human,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -9811,7 +9755,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/engineering)
@@ -9899,7 +9842,6 @@
/obj/effect/mob_spawn/human,
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/caves)
@@ -9978,7 +9920,6 @@
},
/turf/open/floor/plating/asteroid{
initial_gas_mix = "co2=173.4;n2=135.1;plasma=229.8;TEMP=351.9";
- initial_temperature = 363.9;
name = "Cave Floor"
},
/area/awaymission/undergroundoutpost45/crew_quarters)
@@ -30769,7 +30710,7 @@ Ul
ad
ad
ad
-WE
+ob
fh
Cu
ad
@@ -31743,7 +31684,7 @@ gK
gw
gv
fh
-WE
+ob
ad
ad
ad
@@ -31802,7 +31743,7 @@ fh
XJ
Kz
in
-WE
+ob
Cu
fh
Ul
@@ -32761,7 +32702,7 @@ gL
gv
gv
gv
-WE
+ob
fh
fh
gv
@@ -32772,7 +32713,7 @@ fh
fh
fh
fh
-WE
+ob
ad
ad
ad
@@ -33287,7 +33228,7 @@ fh
fh
fh
fh
-WE
+ob
ad
ad
ad
@@ -33529,9 +33470,9 @@ ad
ad
ad
ad
-WE
+ob
fh
-WE
+ob
fh
fh
fh
@@ -34055,10 +33996,10 @@ EN
NI
fh
fh
-WE
+ob
fh
fh
-WE
+ob
fh
ad
ad
@@ -34301,7 +34242,7 @@ ad
ad
ad
fh
-WE
+ob
fh
fh
fh
@@ -34819,16 +34760,16 @@ fh
fh
fh
fh
-WE
+ob
gw
ZU
FY
gv
fh
-WE
+ob
fh
fh
-WE
+ob
ad
ad
ad
@@ -35074,7 +35015,7 @@ ad
ad
ad
fh
-WE
+ob
fh
gz
gw
@@ -37194,7 +37135,7 @@ ad
ad
ad
fh
-WE
+ob
fh
fh
fh
@@ -37454,7 +37395,7 @@ fh
fh
fh
fh
-WE
+ob
ad
ad
ad
@@ -37898,7 +37839,7 @@ ad
fh
fh
fh
-WE
+ob
fh
fh
fh
@@ -37963,7 +37904,7 @@ ad
ad
ad
ad
-WE
+ob
fh
fh
fh
@@ -38152,7 +38093,7 @@ ad
ad
ad
ad
-WE
+ob
fh
fh
fh
@@ -38416,7 +38357,7 @@ fh
fh
fh
fh
-WE
+ob
fh
Yy
Ag
@@ -38671,7 +38612,7 @@ fh
fh
fh
fh
-WE
+ob
fh
fh
gz
@@ -38735,10 +38676,10 @@ fh
ad
ad
ad
-WE
+ob
fh
fh
-WE
+ob
ad
ad
ad
@@ -39510,7 +39451,7 @@ ad
ad
fh
fh
-WE
+ob
ad
ad
ad
@@ -39700,7 +39641,7 @@ fh
fh
fh
fh
-WE
+ob
ad
ad
gz
@@ -39757,7 +39698,7 @@ ad
fh
fh
fh
-WE
+ob
ad
ad
ad
@@ -39950,7 +39891,7 @@ SN
sp
aC
ad
-WE
+ob
fh
fh
fh
@@ -40226,7 +40167,7 @@ YR
nX
fh
fh
-WE
+ob
fh
fh
fh
@@ -40265,10 +40206,10 @@ ad
ad
ad
ad
-WE
+ob
fh
fh
-WE
+ob
ad
ad
ad
@@ -40472,7 +40413,7 @@ fh
fh
fh
fh
-WE
+ob
ad
gy
Gw
@@ -40487,7 +40428,7 @@ fh
fh
fh
fh
-WE
+ob
fh
fh
fh
@@ -40496,7 +40437,7 @@ fh
fh
fh
fh
-WE
+ob
fh
ad
ad
@@ -41000,17 +40941,17 @@ Xz
Xe
Xe
fh
-WE
+ob
fh
fh
fh
-WE
+ob
fh
fh
fh
fh
fh
-WE
+ob
ad
ad
ad
@@ -41756,7 +41697,7 @@ XU
fh
fh
fh
-WE
+ob
gg
gg
Hb
@@ -41772,7 +41713,7 @@ Bg
Xe
fh
fh
-WE
+ob
fh
fh
fh
@@ -42033,7 +41974,7 @@ fh
fh
fh
fh
-WE
+ob
fh
fh
fh
@@ -42265,10 +42206,10 @@ qE
fh
fh
fh
-WE
+ob
fh
fh
-WE
+ob
fh
fh
fh
@@ -43036,7 +42977,7 @@ an
fh
fh
fh
-WE
+ob
gg
Xe
Xe
@@ -43062,7 +43003,7 @@ fh
fh
fh
fh
-WE
+ob
fh
fh
fh
@@ -43071,7 +43012,7 @@ fh
fh
fh
fh
-WE
+ob
fh
fh
fh
@@ -43289,7 +43230,7 @@ yW
ae
ad
ad
-WE
+ob
fh
fh
fh
@@ -43316,7 +43257,7 @@ dF
fN
ad
ad
-WE
+ob
fh
fh
fh
@@ -43330,7 +43271,7 @@ fh
fh
fh
fh
-WE
+ob
fh
fh
fh
@@ -44060,7 +44001,7 @@ GM
qE
fh
fh
-WE
+ob
fh
fh
fh
@@ -44560,7 +44501,7 @@ ad
ad
ad
ad
-Br
+fh
an
Jz
de
@@ -44816,7 +44757,7 @@ ad
ad
ad
ad
-Br
+fh
ob
ae
Jz
@@ -44833,7 +44774,7 @@ VW
fh
fh
fh
-WE
+ob
fh
gg
br
@@ -45073,8 +45014,8 @@ ad
ad
ad
ob
-Br
-Br
+fh
+fh
an
Jz
de
@@ -45329,9 +45270,9 @@ ad
ad
ad
ad
-Br
-Br
-Br
+fh
+fh
+fh
an
yJ
df
@@ -45586,9 +45527,9 @@ ad
ad
ad
ad
-Br
-Br
-Br
+fh
+fh
+fh
qE
HX
df
@@ -45845,7 +45786,7 @@ ad
ad
ad
ob
-Br
+fh
qE
rV
Sx
@@ -45945,7 +45886,7 @@ ad
ad
fh
fh
-WE
+ob
ad
ad
ad
@@ -46101,8 +46042,8 @@ ad
ad
ad
ad
-Br
-Br
+fh
+fh
an
Wa
XW
@@ -46199,7 +46140,7 @@ fh
fh
fh
fh
-WE
+ob
fh
fh
fh
@@ -46358,8 +46299,8 @@ ad
ad
ad
ad
-Br
-Br
+fh
+fh
an
Cw
CR
@@ -46616,7 +46557,7 @@ ad
ad
ad
ob
-Br
+fh
an
He
XW
@@ -46711,7 +46652,7 @@ ad
ad
ad
ad
-WE
+ob
fh
fh
fh
@@ -46872,8 +46813,8 @@ ad
ad
ad
ad
-Br
-Br
+fh
+fh
ae
SO
CZ
@@ -47229,7 +47170,7 @@ ad
ad
ad
fh
-WE
+ob
fh
ad
ad
@@ -52858,7 +52799,7 @@ ad
ad
ad
fh
-WE
+ob
ad
ad
ad
@@ -53369,7 +53310,7 @@ ad
ad
ad
fh
-WE
+ob
fh
ad
ad
@@ -53629,7 +53570,7 @@ fh
fh
fh
fh
-WE
+ob
fh
fh
fh
@@ -53892,7 +53833,7 @@ fh
fh
fh
fh
-WE
+ob
fh
ad
fh
@@ -54396,7 +54337,7 @@ ad
ad
ad
ad
-WE
+ob
fh
fh
fh
@@ -54654,7 +54595,7 @@ ad
ad
ad
fh
-WE
+ob
fh
fh
fh
@@ -54918,7 +54859,7 @@ ad
ad
ad
fh
-WE
+ob
fh
fh
fh
diff --git a/_maps/RuinGeneration/13x13_listening_base.dmm b/_maps/RuinGeneration/13x13_listening_base.dmm
index 1f1ae3eab42c3..d6b8aaf0408be 100644
--- a/_maps/RuinGeneration/13x13_listening_base.dmm
+++ b/_maps/RuinGeneration/13x13_listening_base.dmm
@@ -814,7 +814,7 @@
/turf/closed/wall,
/area/ruin/space/has_grav/listeningstation)
"Vh" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/obj/effect/turf_decal/bot,
diff --git a/_maps/RuinGeneration/41x41_corgasteroid.dmm b/_maps/RuinGeneration/41x41_corgasteroid.dmm
index b85f97d499258..78874a00a0fda 100644
--- a/_maps/RuinGeneration/41x41_corgasteroid.dmm
+++ b/_maps/RuinGeneration/41x41_corgasteroid.dmm
@@ -106,7 +106,7 @@
/obj/structure/sign/warning/vacuum{
pixel_y = 32
},
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plating,
/area/ruin/unpowered)
diff --git a/_maps/arenas/aiupload.dmm b/_maps/arenas/aiupload.dmm
index 32be0208f4a19..2868231f6dac5 100644
--- a/_maps/arenas/aiupload.dmm
+++ b/_maps/arenas/aiupload.dmm
@@ -28,7 +28,7 @@
dir = 1
},
/obj/structure/window/reinforced{
- CanAtmosPass = 3;
+ can_atmos_pass = 3;
dir = 4
},
/turf/open/floor/iron/techmaint,
diff --git a/_maps/map_files/BoxStation/BoxStation.dmm b/_maps/map_files/BoxStation/BoxStation.dmm
index 2f9aca62834f2..b75e78e0640e9 100644
--- a/_maps/map_files/BoxStation/BoxStation.dmm
+++ b/_maps/map_files/BoxStation/BoxStation.dmm
@@ -880,7 +880,7 @@
/turf/open/floor/plating,
/area/maintenance/port/fore)
"alF" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/plating,
/area/maintenance/port/fore)
"alL" = (
@@ -2082,7 +2082,7 @@
/area/maintenance/disposal/incinerator)
"aCD" = (
/obj/effect/decal/cleanable/dirt/dust,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8
},
/turf/open/floor/plating,
@@ -4237,7 +4237,7 @@
/obj/machinery/light/small{
dir = 8
},
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 4
},
/turf/open/floor/plating,
@@ -4404,7 +4404,7 @@
/turf/open/floor/iron,
/area/hallway/primary/aft)
"baL" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 4
},
/turf/open/floor/plating,
@@ -7973,7 +7973,7 @@
dir = 4
},
/obj/machinery/meter,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix{
+/obj/machinery/airlock_controller/incinerator_toxmix{
pixel_x = -24
},
/obj/effect/turf_decal/stripes/corner{
@@ -8646,7 +8646,7 @@
/turf/open/floor/plating/airless,
/area/engine/atmos)
"bQB" = (
-/obj/machinery/air_sensor/atmos/mix_tank,
+/obj/machinery/air_sensor/mix_tank,
/turf/open/floor/engine/vacuum,
/area/engine/atmos)
"bQC" = (
@@ -9396,7 +9396,7 @@
/turf/open/floor/engine/n2o,
/area/engine/atmos)
"bUV" = (
-/obj/machinery/air_sensor/atmos/nitrous_tank,
+/obj/machinery/air_sensor/nitrous_tank,
/turf/open/floor/engine/n2o,
/area/engine/atmos)
"bUW" = (
@@ -9635,7 +9635,7 @@
/area/hallway/secondary/service)
"bWB" = (
/obj/machinery/telecomms/processor/preset_four,
-/turf/open/floor/circuit/green,
+/turf/open/floor/circuit/green/telecomms,
/area/tcommsat/server)
"bWC" = (
/obj/effect/turf_decal/siding/wideplating_new/dark{
@@ -10124,7 +10124,7 @@
/turf/open/floor/engine/plasma,
/area/engine/atmos)
"bYV" = (
-/obj/machinery/air_sensor/atmos/plasma_tank,
+/obj/machinery/air_sensor/plasma_tank,
/turf/open/floor/engine/plasma,
/area/engine/atmos)
"bYW" = (
@@ -10827,7 +10827,7 @@
/turf/open/floor/engine/co2,
/area/engine/atmos)
"ccC" = (
-/obj/machinery/air_sensor/atmos/carbon_tank,
+/obj/machinery/air_sensor/carbon_tank,
/turf/open/floor/engine/co2,
/area/engine/atmos)
"ccD" = (
@@ -10952,7 +10952,7 @@
/turf/open/floor/engine/co2,
/area/engine/atmos)
"cdR" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
"cdU" = (
@@ -11968,7 +11968,7 @@
/turf/open/floor/engine/n2,
/area/engine/atmos)
"ckW" = (
-/obj/machinery/air_sensor/atmos/nitrogen_tank,
+/obj/machinery/air_sensor/nitrogen_tank,
/turf/open/floor/engine/n2,
/area/engine/atmos)
"ckX" = (
@@ -11984,7 +11984,7 @@
/turf/closed/wall/r_wall,
/area/engine/atmos)
"ckZ" = (
-/obj/machinery/air_sensor/atmos/oxygen_tank,
+/obj/machinery/air_sensor/oxygen_tank,
/turf/open/floor/engine/o2,
/area/engine/atmos)
"cla" = (
@@ -12002,7 +12002,7 @@
/turf/closed/wall/r_wall,
/area/engine/atmos)
"clc" = (
-/obj/machinery/air_sensor/atmos/air_tank,
+/obj/machinery/air_sensor/air_tank,
/turf/open/floor/engine/air,
/area/engine/atmos)
"clf" = (
@@ -13778,7 +13778,7 @@
/area/medical/morgue)
"cBE" = (
/obj/effect/landmark/event_spawn,
-/obj/machinery/air_sensor/atmos/toxins_mixing_tank,
+/obj/machinery/air_sensor/toxins_mixing_tank,
/turf/open/floor/engine/vacuum,
/area/science/mixing/chamber)
"cBF" = (
@@ -17812,7 +17812,7 @@
icon_state = "1-2"
},
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_atmos{
+/obj/machinery/airlock_controller/incinerator_atmos{
pixel_x = 38;
pixel_y = 6
},
@@ -23271,7 +23271,7 @@
/turf/open/floor/iron,
/area/hallway/secondary/entry)
"fXX" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/obj/effect/decal/cleanable/dirt/dust,
@@ -32767,7 +32767,7 @@
/turf/open/floor/iron,
/area/science/robotics/lab)
"jJw" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/plating,
/area/ai_monitored/turret_protected/aisat/atmos)
"jJF" = (
@@ -50161,7 +50161,7 @@
/area/crew_quarters/theatre/backstage)
"qTo" = (
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/components/unary/tank/plasma{
+/obj/machinery/atmospherics/components/tank/plasma{
dir = 4
},
/obj/effect/turf_decal/delivery,
@@ -53057,7 +53057,7 @@
/area/crew_quarters/fitness)
"rTt" = (
/obj/machinery/telecomms/bus/preset_four,
-/turf/open/floor/circuit/green,
+/turf/open/floor/circuit/green/telecomms,
/area/tcommsat/server)
"rTw" = (
/obj/structure/table,
diff --git a/_maps/map_files/CorgStation/CorgStation.dmm b/_maps/map_files/CorgStation/CorgStation.dmm
index b07c8eee98b40..7650c7665516e 100644
--- a/_maps/map_files/CorgStation/CorgStation.dmm
+++ b/_maps/map_files/CorgStation/CorgStation.dmm
@@ -2854,7 +2854,7 @@
/turf/open/floor/iron/dark,
/area/lawoffice)
"aKi" = (
-/obj/machinery/air_sensor/atmos/sm_core,
+/obj/machinery/air_sensor/sm_core,
/turf/open/floor/engine,
/area/engine/supermatter)
"aKm" = (
@@ -3957,7 +3957,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 6
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"aWW" = (
/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
@@ -7430,7 +7430,9 @@
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4{
dir = 1
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"ceo" = (
/obj/machinery/power/apc/auto_name/directional/east,
@@ -10786,7 +10788,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"dpG" = (
/obj/effect/spawner/structure/window/reinforced,
@@ -12819,7 +12823,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"dYI" = (
/obj/item/kirbyplants/random,
@@ -14974,7 +14980,7 @@
/turf/open/floor/iron/dark,
/area/security/courtroom)
"eMp" = (
-/obj/machinery/air_sensor/atmos/toxins_mixing_tank,
+/obj/machinery/air_sensor/toxins_mixing_tank,
/turf/open/floor/engine/vacuum,
/area/science/mixing/chamber)
"eMt" = (
@@ -19812,7 +19818,9 @@
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4{
dir = 1
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"gpP" = (
/obj/effect/turf_decal/stripes/corner{
@@ -21156,7 +21164,9 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 10
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"gMB" = (
/obj/effect/turf_decal/stripes/line{
@@ -23082,7 +23092,9 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 6
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"hsd" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -27179,7 +27191,9 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 5
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"iEX" = (
/obj/structure/disposalpipe/segment{
@@ -33211,7 +33225,7 @@
/obj/structure/sign/warning/vacuum{
pixel_y = 32
},
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/plating,
/area/maintenance/starboard/secondary)
@@ -37630,7 +37644,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"mca" = (
/obj/structure/disposalpipe/segment{
@@ -38450,7 +38466,7 @@
/turf/open/floor/iron,
/area/crew_quarters/fitness/recreation)
"mnA" = (
-/obj/machinery/air_sensor/atmos/oxygen_tank,
+/obj/machinery/air_sensor/oxygen_tank,
/turf/open/floor/engine/o2,
/area/engine/atmos)
"mnO" = (
@@ -39297,12 +39313,6 @@
},
/turf/open/floor/wood,
/area/security/prison)
-"mAy" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plating,
-/area/space/nearstation)
"mAF" = (
/obj/machinery/camera/directional/east{
c_tag = "Medbay Break Room"
@@ -43451,7 +43461,7 @@
/turf/open/floor/plating,
/area/maintenance/starboard/aft)
"nRU" = (
-/obj/machinery/air_sensor/atmos/nitrogen_tank,
+/obj/machinery/air_sensor/nitrogen_tank,
/turf/open/floor/engine/n2,
/area/engine/atmos)
"nSi" = (
@@ -45101,7 +45111,9 @@
dir = 8
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"ovu" = (
/obj/effect/turf_decal/stripes/line{
@@ -45119,7 +45131,9 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 9
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"ovw" = (
/obj/effect/turf_decal/siding/dark{
@@ -47664,7 +47678,6 @@
/turf/open/floor/iron/dark,
/area/crew_quarters/heads/hos)
"psB" = (
-/obj/machinery/portable_atmospherics/canister/proto,
/obj/effect/turf_decal/stripes/corner{
dir = 1
},
@@ -49317,7 +49330,7 @@
"pTo" = (
/obj/machinery/door/airlock/public/glass/incinerator/atmos_interior,
/obj/effect/mapping_helpers/airlock/locked,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_atmos{
+/obj/machinery/airlock_controller/incinerator_atmos{
pixel_x = -23;
pixel_y = 1
},
@@ -52766,7 +52779,9 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 4
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"rca" = (
/obj/structure/railing/corner{
@@ -54698,7 +54713,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 5
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"rIq" = (
/obj/item/radio/intercom{
@@ -56161,7 +56176,9 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 4
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"shn" = (
/obj/structure/chair/stool,
@@ -57777,7 +57794,7 @@
/turf/open/floor/iron/dark,
/area/ai_monitored/storage/eva)
"sHT" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 4
},
/turf/open/floor/plating,
@@ -57925,7 +57942,7 @@
/turf/open/floor/iron,
/area/teleporter)
"sKh" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/obj/effect/turf_decal/tile/green/anticorner/contrasted{
dir = 4
},
@@ -58978,7 +58995,6 @@
/area/engine/atmos)
"tbG" = (
/obj/machinery/light,
-/obj/machinery/portable_atmospherics/canister/proto,
/obj/machinery/atmospherics/components/unary/portables_connector/visible{
dir = 1
},
@@ -59530,7 +59546,7 @@
icon_state = "4-8"
},
/obj/machinery/igniter/incinerator_atmos,
-/obj/machinery/air_sensor/atmos/incinerator_tank{
+/obj/machinery/air_sensor/incinerator_tank{
pixel_x = 32;
pixel_y = -32
},
@@ -61068,7 +61084,9 @@
/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{
dir = 4
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"tMA" = (
/obj/machinery/door/poddoor{
@@ -65374,7 +65392,7 @@
dir = 1
},
/obj/machinery/meter,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix{
+/obj/machinery/airlock_controller/incinerator_toxmix{
pixel_y = 27
},
/turf/open/floor/catwalk_floor/flat_white,
@@ -68753,7 +68771,7 @@
/turf/open/floor/iron/white,
/area/medical/sleeper)
"wjc" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/obj/effect/turf_decal/tile/green/anticorner/contrasted,
@@ -69580,7 +69598,7 @@
/turf/open/floor/engine,
/area/science/mixing/chamber)
"wxJ" = (
-/obj/machinery/air_sensor/atmos/air_tank,
+/obj/machinery/air_sensor/air_tank,
/turf/open/floor/engine/air,
/area/engine/atmos)
"wxT" = (
@@ -74910,7 +74928,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"ylE" = (
/obj/effect/turf_decal/stripes/line,
@@ -99155,7 +99175,7 @@ aMT
aMT
aMT
agE
-mAy
+xOI
oCW
hfp
oCW
@@ -99412,7 +99432,7 @@ aMT
aMT
aMT
agE
-mAy
+xOI
oCW
bCW
oCW
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 6fc52cf867f08..149eba795cba6 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -959,7 +959,7 @@
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 8
},
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_atmos{
+/obj/machinery/airlock_controller/incinerator_atmos{
pixel_y = 27
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
@@ -1510,7 +1510,7 @@
/turf/open/floor/plating,
/area/maintenance/port/fore)
"ali" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8
},
/turf/open/floor/plating,
@@ -3016,7 +3016,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 1
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"auM" = (
/obj/structure/disposalpipe/segment{
@@ -4490,7 +4492,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 4
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"aBA" = (
/obj/structure/disposalpipe/segment{
@@ -6359,7 +6363,7 @@
/obj/structure/cable{
icon_state = "4-8"
},
-/obj/machinery/air_sensor/atmos/incinerator_tank{
+/obj/machinery/air_sensor/incinerator_tank{
pixel_x = -32;
pixel_y = 32
},
@@ -7346,7 +7350,7 @@
/turf/open/floor/plating,
/area/engine/atmos)
"aUZ" = (
-/obj/machinery/air_sensor/atmos/air_tank,
+/obj/machinery/air_sensor/air_tank,
/turf/open/floor/engine/air,
/area/engine/atmos)
"aVa" = (
@@ -7654,7 +7658,7 @@
/turf/open/floor/engine/co2,
/area/engine/atmos)
"aXX" = (
-/obj/machinery/air_sensor/atmos/carbon_tank,
+/obj/machinery/air_sensor/carbon_tank,
/turf/open/floor/engine/co2,
/area/engine/atmos)
"aYa" = (
@@ -8048,7 +8052,7 @@
/turf/open/floor/iron,
/area/engine/atmos)
"bbN" = (
-/obj/machinery/air_sensor/atmos/oxygen_tank,
+/obj/machinery/air_sensor/oxygen_tank,
/turf/open/floor/engine/o2,
/area/engine/atmos)
"bbO" = (
@@ -8532,7 +8536,7 @@
/turf/open/floor/engine/plasma,
/area/engine/atmos)
"bew" = (
-/obj/machinery/air_sensor/atmos/plasma_tank,
+/obj/machinery/air_sensor/plasma_tank,
/turf/open/floor/engine/plasma,
/area/engine/atmos)
"beB" = (
@@ -8962,7 +8966,7 @@
/turf/open/floor/iron,
/area/engine/atmos)
"bhv" = (
-/obj/machinery/air_sensor/atmos/nitrogen_tank,
+/obj/machinery/air_sensor/nitrogen_tank,
/turf/open/floor/engine/n2,
/area/engine/atmos)
"bhw" = (
@@ -9385,7 +9389,7 @@
/turf/open/floor/engine/n2o,
/area/engine/atmos)
"bkI" = (
-/obj/machinery/air_sensor/atmos/nitrous_tank,
+/obj/machinery/air_sensor/nitrous_tank,
/turf/open/floor/engine/n2o,
/area/engine/atmos)
"bkK" = (
@@ -10607,7 +10611,7 @@
/turf/open/floor/engine/vacuum,
/area/engine/atmos)
"brU" = (
-/obj/machinery/air_sensor/atmos/mix_tank,
+/obj/machinery/air_sensor/mix_tank,
/turf/open/floor/engine/vacuum,
/area/engine/atmos)
"brW" = (
@@ -22970,7 +22974,9 @@
/turf/open/floor/iron,
/area/library)
"cSI" = (
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"cSL" = (
/obj/machinery/door/airlock/research{
@@ -23945,7 +23951,9 @@
/obj/effect/turf_decal/edges/borderfloor{
dir = 4
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"dar" = (
/obj/structure/table/reinforced,
@@ -26817,7 +26825,9 @@
/area/maintenance/port)
"dzh" = (
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"dzi" = (
/obj/effect/landmark/xeno_spawn,
@@ -32338,7 +32348,7 @@
/turf/open/floor/iron/white,
/area/medical/virology)
"exE" = (
-/obj/machinery/air_sensor/atmos/toxins_mixing_tank,
+/obj/machinery/air_sensor/toxins_mixing_tank,
/turf/open/floor/engine/vacuum,
/area/science/mixing/chamber)
"exO" = (
@@ -33915,7 +33925,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 1
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"eWM" = (
/obj/effect/turf_decal/tile/red/half/contrasted{
@@ -34316,7 +34328,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 6
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"fcx" = (
/obj/structure/disposalpipe/segment{
@@ -35275,7 +35289,7 @@
/area/crew_quarters/heads/cmo)
"fsz" = (
/obj/machinery/atmospherics/components/binary/valve,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix{
+/obj/machinery/airlock_controller/incinerator_toxmix{
pixel_y = 26
},
/obj/effect/decal/cleanable/dirt,
@@ -35504,7 +35518,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 9
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"fxp" = (
/obj/machinery/vending/coffee,
@@ -37206,7 +37222,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 8
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"fWI" = (
/obj/structure/cable/yellow,
@@ -37463,7 +37481,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 8
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"gaz" = (
/obj/structure/closet/firecloset,
@@ -40547,7 +40567,7 @@
/turf/open/floor/plating,
/area/maintenance/port/aft)
"gWa" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8
},
/turf/open/floor/plating{
@@ -41254,11 +41274,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/turf/open/floor/plating{
- initial_gas_mix = "o2=0.01;n2=0.01;TEMP=2.7";
- initial_temperature = 2.7;
- luminosity = 2
- },
+/turf/open/floor/plating/airless,
/area/security/main)
"hha" = (
/obj/machinery/vending/coffee,
@@ -42605,7 +42621,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 5
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"hFh" = (
/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted,
@@ -42739,7 +42757,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 9
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"hHG" = (
/obj/structure/chair/office{
@@ -44179,7 +44199,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 8
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"ibE" = (
/obj/effect/decal/cleanable/dirt,
@@ -52854,7 +52876,7 @@
/obj/effect/mapping_helpers/atmos_auto_connect,
/obj/machinery/airalarm/server{
pixel_x = -22;
- dir = 4
+ dir = 8
},
/turf/open/floor/iron,
/area/tcommsat/server)
@@ -53427,7 +53449,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 1
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"ljy" = (
/obj/item/kirbyplants/random,
@@ -56646,7 +56670,7 @@
/area/hallway/primary/aft)
"mjr" = (
/obj/effect/turf_decal/bot,
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/iron,
/area/science/xenobiology)
"mjz" = (
@@ -58813,7 +58837,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 8
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"mUt" = (
/obj/machinery/computer/telecomms/monitor{
@@ -59857,7 +59883,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 10
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"njx" = (
/obj/effect/turf_decal/siding/wood,
@@ -60819,7 +60847,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 8
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"nxM" = (
/obj/structure/cable/yellow{
@@ -61987,7 +62017,9 @@
/obj/effect/turf_decal/tile/techfloor{
dir = 1
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"nPV" = (
/obj/structure/cable/yellow{
@@ -63360,9 +63392,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating/airless,
/area/security/main)
"ooQ" = (
/obj/item/radio/intercom{
@@ -63882,7 +63912,9 @@
/obj/effect/turf_decal/tile/techfloor{
dir = 4
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"owZ" = (
/obj/structure/cable/yellow{
@@ -65735,7 +65767,9 @@
icon_state = "0-8"
},
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"pcV" = (
/obj/effect/decal/cleanable/dirt,
@@ -66973,7 +67007,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 8
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"pzz" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -68555,7 +68591,9 @@
icon_state = "2-4"
},
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"qaN" = (
/obj/machinery/door/poddoor/preopen{
@@ -70089,7 +70127,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 10
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"qxz" = (
/obj/item/kirbyplants{
@@ -70386,7 +70426,9 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"qDG" = (
/obj/effect/turf_decal/stripes/line,
@@ -73610,7 +73652,9 @@
dir = 9
},
/obj/effect/turf_decal/tile/techfloor,
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"rCv" = (
/obj/effect/turf_decal/stripes/line{
@@ -75470,7 +75514,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 4
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"seN" = (
/obj/effect/decal/cleanable/dirt,
@@ -76870,7 +76916,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 3
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"sAO" = (
/obj/structure/cable/yellow{
@@ -82574,7 +82622,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 4
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"urb" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -85860,7 +85910,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 4
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"vtt" = (
/obj/effect/turf_decal/delivery,
@@ -86288,7 +86340,9 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"vzs" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4,
@@ -86446,7 +86500,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 6
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"vCv" = (
/obj/effect/decal/cleanable/dirt,
@@ -88024,7 +88080,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 8
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"wcJ" = (
/obj/effect/turf_decal/delivery,
@@ -89157,7 +89215,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 8
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"wsU" = (
/obj/structure/disposalpipe/segment{
@@ -89353,7 +89413,9 @@
/obj/effect/turf_decal/trimline/dark/warning{
dir = 1
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"wuY" = (
/obj/effect/decal/cleanable/dirt,
@@ -89452,7 +89514,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 5
},
-/turf/open/floor/catwalk_floor/iron_smooth,
+/turf/open/floor/catwalk_floor/iron_smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"wwe" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -90384,7 +90448,9 @@
/obj/effect/turf_decal/tile/techfloor{
dir = 8
},
-/turf/open/floor/iron/smooth,
+/turf/open/floor/iron/smooth{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"wKx" = (
/obj/effect/turf_decal/tile/purple,
@@ -92173,11 +92239,7 @@
width = 3;
dir = 4
},
-/turf/open/floor/plating{
- initial_gas_mix = "o2=0.01;n2=0.01;TEMP=2.7";
- initial_temperature = 2.7;
- luminosity = 2
- },
+/turf/open/floor/plating/airless,
/area/security/main)
"xov" = (
/obj/item/kirbyplants/random,
@@ -93584,7 +93646,9 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 4
},
-/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4,
+/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4{
+ dir = 2
+ },
/turf/open/floor/iron,
/area/quartermaster/miningoffice)
"xKK" = (
diff --git a/_maps/map_files/EchoStation/EchoStation.dmm b/_maps/map_files/EchoStation/EchoStation.dmm
index a917f28df849f..6a8299d7e2472 100644
--- a/_maps/map_files/EchoStation/EchoStation.dmm
+++ b/_maps/map_files/EchoStation/EchoStation.dmm
@@ -388,7 +388,9 @@
/area/ai_monitored/turret_protected/ai_upload)
"aky" = (
/obj/effect/decal/cleanable/glass,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/mixing)
"akz" = (
/obj/effect/turf_decal/bot,
@@ -1291,7 +1293,7 @@
/turf/open/floor/iron/white,
/area/medical/storage)
"aBF" = (
-/obj/machinery/air_sensor/atmos/toxins_mixing_tank,
+/obj/machinery/air_sensor/toxins_mixing_tank,
/obj/effect/decal/cleanable/blood/old,
/obj/machinery/igniter/incinerator_toxmix,
/turf/open/floor/engine/vacuum,
@@ -1685,7 +1687,7 @@
/area/science/lab)
"aJy" = (
/obj/machinery/atmospherics/components/binary/valve,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix{
+/obj/machinery/airlock_controller/incinerator_toxmix{
pixel_y = 26
},
/obj/effect/turf_decal/stripes/line{
@@ -3937,7 +3939,7 @@
/turf/open/floor/engine,
/area/science/mixing/chamber)
"bKc" = (
-/obj/machinery/air_sensor/atmos/nitrogen_tank,
+/obj/machinery/air_sensor/nitrogen_tank,
/obj/machinery/atmospherics/pipe/manifold/yellow/hidden/layer2{
dir = 4
},
@@ -4546,7 +4548,9 @@
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/glass,
/obj/item/shard,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"cbi" = (
/obj/structure/closet/cardboard,
@@ -6142,7 +6146,9 @@
dir = 5
},
/obj/effect/decal/cleanable/cobweb/cobweb2,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"cUy" = (
/obj/effect/decal/cleanable/dirt,
@@ -6408,7 +6414,9 @@
"cZA" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/greenglow,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"dav" = (
/obj/effect/decal/cleanable/dirt/dust,
@@ -8010,7 +8018,9 @@
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/dirt/dust,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"dPH" = (
/obj/structure/railing/corner{
@@ -8573,7 +8583,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"efr" = (
/obj/effect/spawner/structure/window/reinforced,
@@ -11481,7 +11493,7 @@
icon_state = "1-2"
},
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_atmos{
+/obj/machinery/airlock_controller/incinerator_atmos{
pixel_x = 38;
pixel_y = 6
},
@@ -11823,7 +11835,9 @@
"fJV" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/item/beacon,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"fJW" = (
/obj/structure/table/wood,
@@ -12800,7 +12814,7 @@
/turf/open/floor/plating/asteroid/basalt/planetary,
/area/engine/atmos)
"ghT" = (
-/obj/machinery/air_sensor/atmos/sm_core,
+/obj/machinery/air_sensor/sm_core,
/turf/open/floor/engine,
/area/engine/supermatter)
"gid" = (
@@ -13615,7 +13629,9 @@
"gBy" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/dirt/dust,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"gBH" = (
/obj/item/kirbyplants/random{
@@ -13746,7 +13762,7 @@
/turf/open/floor/iron,
/area/ai_monitored/turret_protected/aisat/maint)
"gFd" = (
-/obj/machinery/air_sensor/atmos/plasma_tank,
+/obj/machinery/air_sensor/plasma_tank,
/obj/machinery/atmospherics/pipe/layer_manifold/visible,
/turf/open/floor/engine/plasma,
/area/engine/atmos)
@@ -14536,7 +14552,9 @@
},
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/generic,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"han" = (
/obj/structure/closet/firecloset/full,
@@ -15814,7 +15832,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1;
initialize_directions = 1
},
@@ -16207,7 +16225,9 @@
/turf/open/floor/iron/half,
/area/engine/engineering)
"hQk" = (
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/mixing)
"hRb" = (
/obj/effect/landmark/start/shaft_miner,
@@ -16296,7 +16316,9 @@
/area/maintenance/department/engine)
"hSS" = (
/obj/effect/decal/cleanable/cobweb,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/mixing)
"hST" = (
/obj/machinery/door/poddoor/shutters/radiation/preopen{
@@ -16418,7 +16440,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 6
},
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"hVs" = (
/obj/effect/spawner/room/fivexthree,
@@ -16592,7 +16616,9 @@
"ibz" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/dirt/dust,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/mixing)
"ibQ" = (
/obj/machinery/vending/wardrobe/hydro_wardrobe,
@@ -17334,7 +17360,9 @@
/obj/machinery/camera/preset/toxins{
dir = 4
},
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"iwM" = (
/obj/effect/turf_decal/stripes/line{
@@ -19312,7 +19340,9 @@
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/glass,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"jCZ" = (
/obj/machinery/button/door{
@@ -21030,7 +21060,9 @@
/obj/machinery/light/small{
dir = 1
},
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/mixing)
"krL" = (
/obj/structure/lattice/catwalk/over,
@@ -23925,7 +23957,9 @@
/area/crew_quarters/dorms)
"lQm" = (
/obj/effect/decal/cleanable/oil,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/mixing)
"lQo" = (
/obj/effect/turf_decal/sand/plating,
@@ -25416,7 +25450,7 @@
/turf/open/floor/iron,
/area/maintenance/department/chapel)
"mCk" = (
-/obj/machinery/air_sensor/atmos/nitrous_tank,
+/obj/machinery/air_sensor/nitrous_tank,
/obj/machinery/atmospherics/pipe/layer_manifold/visible,
/turf/open/floor/engine/n2o,
/area/engine/atmos)
@@ -25668,7 +25702,9 @@
},
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/dirt/dust,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"mIh" = (
/obj/structure/lattice,
@@ -27121,7 +27157,7 @@
/turf/open/floor/iron/dark,
/area/ai_monitored/security/armory)
"nxm" = (
-/obj/machinery/air_sensor/atmos/oxygen_tank,
+/obj/machinery/air_sensor/oxygen_tank,
/obj/machinery/atmospherics/pipe/simple/green/hidden/layer4,
/obj/machinery/atmospherics/pipe/simple/yellow/hidden/layer2{
dir = 10
@@ -27696,7 +27732,7 @@
},
/area/hallway/primary/central)
"nIy" = (
-/obj/machinery/air_sensor/atmos/carbon_tank,
+/obj/machinery/air_sensor/carbon_tank,
/obj/machinery/atmospherics/pipe/simple/yellow/hidden/layer4{
dir = 8
},
@@ -31158,7 +31194,9 @@
dir = 1
},
/obj/effect/decal/cleanable/dirt/dust,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"pxs" = (
/turf/closed/mineral/bscrystal,
@@ -33474,7 +33512,9 @@
"qOu" = (
/obj/item/target,
/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"qOE" = (
/obj/structure/stairs,
@@ -35867,7 +35907,9 @@
dir = 8
},
/obj/effect/decal/cleanable/dirt/dust,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"rVy" = (
/obj/structure/cable{
@@ -37098,7 +37140,9 @@
"sBs" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/molten_object/large,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"sBt" = (
/obj/effect/decal/cleanable/dirt/dust,
@@ -37549,7 +37593,7 @@
/turf/open/floor/iron,
/area/engine/atmos)
"sPS" = (
-/obj/machinery/air_sensor/atmos/air_tank,
+/obj/machinery/air_sensor/air_tank,
/obj/machinery/atmospherics/pipe/layer_manifold/visible,
/turf/open/floor/engine/air,
/area/engine/atmos)
@@ -43426,7 +43470,9 @@
/area/engine/atmos)
"vFT" = (
/obj/effect/decal/cleanable/dirt/dust,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/mixing)
"vGc" = (
/obj/structure/cable/yellow{
@@ -44279,7 +44325,9 @@
"wdl" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/blood/gibs/old,
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"wdv" = (
/obj/structure/cable/yellow{
@@ -46648,7 +46696,9 @@
/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/science/test_area)
"xoG" = (
/obj/machinery/holopad,
@@ -47269,7 +47319,7 @@
/turf/open/floor/iron/techmaint/planetary,
/area/asteroid/paradise/surface)
"xDF" = (
-/obj/machinery/air_sensor/atmos/mix_tank,
+/obj/machinery/air_sensor/mix_tank,
/obj/machinery/atmospherics/pipe/layer_manifold/visible,
/turf/open/floor/engine/airless,
/area/engine/atmos)
diff --git a/_maps/map_files/FlandStation/FlandStation.dmm b/_maps/map_files/FlandStation/FlandStation.dmm
index 5d75bf0ca0794..99017a959d72a 100644
--- a/_maps/map_files/FlandStation/FlandStation.dmm
+++ b/_maps/map_files/FlandStation/FlandStation.dmm
@@ -154,7 +154,7 @@
/area/chapel/main)
"abJ" = (
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/iron,
+/turf/open/floor/iron/airless,
/area/space/nearstation)
"abN" = (
/turf/open/floor/plating/asteroid/airless,
@@ -177,7 +177,7 @@
/area/hallway/primary/aft)
"acn" = (
/obj/structure/girder,
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"aco" = (
/obj/structure/lattice,
@@ -1057,7 +1057,9 @@
/turf/open/floor/iron/dark,
/area/security/execution/transfer)
"aob" = (
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/space/nearstation)
"aod" = (
/obj/effect/decal/cleanable/dirt,
@@ -1069,9 +1071,7 @@
"aoe" = (
/obj/effect/turf_decal/stripes/line,
/obj/machinery/atmospherics/pipe/simple/cyan/visible,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"aoh" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -1107,7 +1107,9 @@
/area/hydroponics/garden)
"aoW" = (
/obj/structure/girder,
-/turf/open/floor/plating/foam,
+/turf/open/floor/plating/foam{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/space/nearstation)
"ape" = (
/obj/machinery/atmospherics/components/unary/portables_connector/visible,
@@ -1167,9 +1169,7 @@
/obj/machinery/button/shieldwallgen/directional/south{
name = "Arrivals"
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"aqg" = (
/obj/effect/turf_decal/stripes/line{
@@ -1225,7 +1225,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
/obj/structure/grille/broken,
-/turf/open/floor/iron,
+/turf/open/floor/iron/airless,
/area/asteroid/nearstation)
"arg" = (
/obj/structure/grille,
@@ -1716,7 +1716,7 @@
/obj/item/shard{
icon_state = "medium"
},
-/turf/open/floor/iron,
+/turf/open/floor/iron/airless,
/area/asteroid/nearstation)
"awC" = (
/obj/machinery/power/solar{
@@ -1789,7 +1789,9 @@
/obj/structure/railing{
dir = 8
},
-/turf/open/floor/plating/foam,
+/turf/open/floor/plating/foam{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/asteroid/nearstation)
"axS" = (
/obj/machinery/power/apc/auto_name/directional/south,
@@ -2006,7 +2008,7 @@
"aBk" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/lattice/catwalk/over,
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/asteroid/nearstation)
"aBo" = (
/obj/effect/spawner/structure/window/reinforced/tinted,
@@ -2085,9 +2087,6 @@
/obj/structure/table,
/turf/open/floor/iron/white,
/area/medical/medbay/lobby)
-"aCb" = (
-/turf/open/floor/plating,
-/area/asteroid/nearstation)
"aCf" = (
/turf/closed/wall/r_wall,
/area/science/shuttle)
@@ -2223,7 +2222,9 @@
/turf/open/floor/iron/grid/steel,
/area/hallway/primary/central)
"aDF" = (
-/turf/open/floor/plating/rust,
+/turf/open/floor/plating/rust{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/asteroid/nearstation)
"aDZ" = (
/obj/structure/cable/yellow{
@@ -3010,9 +3011,7 @@
/obj/machinery/light{
dir = 8
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"aLF" = (
/obj/structure/rack,
@@ -3264,7 +3263,7 @@
/obj/structure/extinguisher_cabinet{
pixel_x = -26
},
-/turf/open/floor/iron/dark/airless,
+/turf/open/floor/iron/dark,
/area/medical/surgery)
"aOI" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
@@ -4464,9 +4463,7 @@
/turf/open/floor/iron,
/area/hallway/primary/aft)
"bbm" = (
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/docking/arrival)
"bbq" = (
/obj/structure/cable/yellow{
@@ -4826,9 +4823,7 @@
/area/science/robotics/mechbay)
"bhg" = (
/obj/item/shard,
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating/airless,
/area/asteroid/nearstation)
"bhp" = (
/turf/open/floor/plating/rust,
@@ -4922,9 +4917,7 @@
pixel_x = -24;
pixel_y = -10
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"bii" = (
/obj/structure/cable{
@@ -5406,19 +5399,13 @@
},
/area/hallway/primary/fore)
"bnD" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/structure/lattice/catwalk/over,
/obj/machinery/atmospherics/pipe/manifold/cyan/hidden{
dir = 4
},
/obj/structure/cable/orange{
icon_state = "1-2"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"bnT" = (
/obj/structure/table/wood,
@@ -5988,6 +5975,7 @@
roundstart_template = /datum/map_template/shuttle/escape_pod/default;
width = 3
},
+/obj/structure/fans/tiny/invisible,
/turf/open/space/basic,
/area/space)
"bvZ" = (
@@ -6214,9 +6202,8 @@
/turf/open/floor/iron/grid/steel,
/area/science/robotics/lab)
"bzV" = (
-/obj/structure/lattice/catwalk/over,
/obj/structure/railing,
-/turf/open/floor/plating,
+/turf/open/floor/catwalk_floor,
/area/bridge)
"bAb" = (
/obj/item/stack/sheet/glass/fifty,
@@ -6805,15 +6792,6 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/white,
/area/science/shuttledock)
-"bKE" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/bridge)
"bKK" = (
/obj/effect/turf_decal/trimline/red/filled/line{
dir = 4
@@ -7044,17 +7022,13 @@
/turf/open/floor/iron/dark,
/area/engine/atmos)
"bOE" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line,
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
dir = 8
},
/obj/machinery/light{
dir = 1
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"bOO" = (
/obj/effect/decal/cleanable/dirt,
@@ -7088,9 +7062,7 @@
/obj/structure/cable/orange{
icon_state = "4-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/docking/bridge)
"bOZ" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
@@ -7280,7 +7252,6 @@
/obj/structure/cable{
icon_state = "4-8"
},
-/obj/effect/turf_decal/delivery,
/obj/machinery/atmospherics/components/binary/dp_vent_pump/layer4{
dir = 8
},
@@ -8116,7 +8087,7 @@
/obj/effect/turf_decal/stripes/end{
dir = 1
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/science/mixing/chamber)
"ccX" = (
/obj/effect/decal/cleanable/dirt,
@@ -8197,7 +8168,9 @@
/turf/open/floor/iron/techmaint,
/area/maintenance/disposal)
"cer" = (
-/turf/open/floor/plating/foam,
+/turf/open/floor/plating/foam{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/space/nearstation)
"ceB" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer2,
@@ -8890,11 +8863,6 @@
},
/turf/open/floor/iron/dark,
/area/engine/engine_room)
-"cov" = (
-/turf/open/floor/plating{
- burnt = 1
- },
-/area/space/nearstation)
"coA" = (
/obj/machinery/disposal/bin,
/obj/effect/turf_decal/delivery,
@@ -9088,12 +9056,6 @@
/obj/item/shovel,
/turf/open/floor/iron/techmaint,
/area/maintenance/solars/port)
-"crA" = (
-/obj/structure/girder,
-/turf/open/floor/plating{
- burnt = 1
- },
-/area/space/nearstation)
"crB" = (
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/sepia,
@@ -9177,7 +9139,7 @@
/turf/open/floor/plating,
/area/maintenance/department/security/brig)
"csp" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/obj/effect/turf_decal/stripes/line{
@@ -9292,9 +9254,7 @@
charge = 5e+006
},
/obj/machinery/camera/directional/east,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"ctN" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
@@ -9379,9 +9339,7 @@
/obj/effect/decal/remains/human,
/obj/effect/decal/cleanable/blood/old,
/obj/item/pickaxe,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/asteroid/nearstation)
"cuR" = (
/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted,
@@ -10000,9 +9958,7 @@
/obj/machinery/button/shieldwallgen/directional/east{
name = "Arrivals"
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"cDE" = (
/obj/machinery/light{
@@ -10425,7 +10381,7 @@
/obj/effect/turf_decal/stripes/red/line{
dir = 8
},
-/obj/machinery/air_sensor/atmos/sm_core,
+/obj/machinery/air_sensor/sm_core,
/turf/open/floor/engine,
/area/engine/supermatter)
"cKl" = (
@@ -11432,7 +11388,9 @@
name = "server vent"
},
/obj/effect/turf_decal/bot,
-/turf/open/floor/iron/techmaint,
+/turf/open/floor/iron/techmaint{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/science/server)
"cVB" = (
/obj/structure/girder,
@@ -12034,17 +11992,13 @@
/turf/open/floor/plating,
/area/engine/storage)
"def" = (
-/obj/effect/turf_decal/stripes/line,
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
dir = 8
},
/obj/structure/cable/orange{
icon_state = "1-8"
},
-/obj/structure/lattice/catwalk/over,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"dek" = (
/obj/structure/cable/yellow{
@@ -12836,9 +12790,7 @@
/obj/machinery/atmospherics/pipe/simple/cyan/visible{
dir = 5
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"dpI" = (
/obj/effect/turf_decal/trimline/purple/filled/line,
@@ -13309,16 +13261,10 @@
/turf/open/floor/prison,
/area/security/prison)
"dvX" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
/obj/machinery/light{
dir = 4
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/bridge)
"dvZ" = (
/obj/structure/cable{
@@ -13689,24 +13635,6 @@
dir = 1
},
/area/hallway/primary/central)
-"dDv" = (
-/obj/structure/lattice/catwalk/over,
-/obj/item/stack/marker_beacon{
- anchored = 1;
- icon_state = "markerburgundy-on";
- light_color = "#FA644B";
- light_power = 3;
- light_range = 2;
- name = "landing marker";
- picked_color = "Burgundy"
- },
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/bridge)
"dDH" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
@@ -13771,9 +13699,7 @@
name = "Bridge Bay";
width = 12
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/docking/bridge)
"dFA" = (
/obj/effect/turf_decal/stripes/closeup{
@@ -14330,9 +14256,7 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{
dir = 8
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/docking/bridge)
"dLt" = (
/obj/structure/table/wood,
@@ -14351,14 +14275,8 @@
/turf/open/floor/iron/grid/steel,
/area/medical/apothecary)
"dLx" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
/obj/machinery/camera/directional/east,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/bridge)
"dLy" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -14488,9 +14406,7 @@
/obj/machinery/light_switch{
pixel_x = -24
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/drydock)
"dNa" = (
/obj/structure/disposalpipe/segment{
@@ -15063,12 +14979,6 @@
},
/turf/open/floor/iron,
/area/security/checkpoint/medical)
-"dUK" = (
-/obj/structure/lattice,
-/turf/open/floor/plating{
- broken = 1
- },
-/area/space/nearstation)
"dUS" = (
/obj/machinery/door/firedoor,
/obj/effect/turf_decal/stripes/closeup,
@@ -15298,9 +15208,7 @@
/area/science/breakroom)
"dYM" = (
/obj/structure/girder,
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating/airless,
/area/asteroid/nearstation)
"dYU" = (
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
@@ -15747,11 +15655,6 @@
/obj/effect/turf_decal/bot,
/turf/open/floor/iron/grid/steel,
/area/science/misc_lab)
-"eew" = (
-/turf/open/floor/plating{
- burnt = 1
- },
-/area/asteroid/nearstation)
"eeW" = (
/obj/effect/turf_decal/stripes/line,
/obj/structure/closet,
@@ -15766,9 +15669,7 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 4
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/drydock)
"efp" = (
/obj/effect/turf_decal/guideline/guideline_out_arrow_con/blue{
@@ -16455,17 +16356,11 @@
/turf/open/floor/vault,
/area/science/server)
"eoY" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
/obj/structure/cable/orange{
icon_state = "1-2"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"epc" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -16483,7 +16378,6 @@
/turf/open/floor/iron/dark,
/area/tcommsat/computer)
"epQ" = (
-/obj/structure/lattice/catwalk/over,
/obj/item/stack/marker_beacon{
anchored = 1;
icon_state = "markerburgundy-on";
@@ -16493,13 +16387,8 @@
name = "landing marker";
picked_color = "Burgundy"
},
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/bridge)
+/turf/open/floor/catwalk_floor,
+/area/docking/bridge)
"epX" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
@@ -17069,9 +16958,7 @@
/obj/machinery/atmospherics/pipe/simple/cyan/visible{
dir = 4
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"ezG" = (
/obj/effect/landmark/start/librarian,
@@ -17421,28 +17308,6 @@
},
/turf/open/floor/plating,
/area/bridge)
-"eDO" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/item/stack/marker_beacon{
- anchored = 1;
- icon_state = "markerburgundy-on";
- light_color = "#FA644B";
- light_power = 3;
- light_range = 2;
- name = "landing marker";
- picked_color = "Burgundy"
- },
-/obj/structure/cable/orange{
- icon_state = "1-2"
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/arrival)
"eDW" = (
/obj/machinery/door/window/northleft{
dir = 2;
@@ -18544,9 +18409,7 @@
/obj/machinery/atmospherics/pipe/simple/cyan/visible{
dir = 4
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"ePW" = (
/obj/item/kirbyplants/random,
@@ -20639,17 +20502,13 @@
/turf/open/floor/wood,
/area/library)
"fpO" = (
-/obj/effect/turf_decal/stripes/line,
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
dir = 8
},
/obj/structure/cable/orange{
icon_state = "4-8"
},
-/obj/structure/lattice/catwalk/over,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"fpS" = (
/obj/machinery/door/morgue{
@@ -21463,9 +21322,7 @@
/obj/machinery/light{
dir = 8
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"fzQ" = (
/obj/effect/turf_decal/stripes/line,
@@ -21875,13 +21732,10 @@
/turf/open/floor/carpet/purple,
/area/crew_quarters/heads/hor)
"fEn" = (
-/obj/structure/lattice/catwalk/over,
/obj/structure/cable/orange{
icon_state = "4-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"fEp" = (
/obj/effect/decal/cleanable/dirt,
@@ -24871,9 +24725,7 @@
dir = 4;
name = "manual inlet valve"
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"gpZ" = (
/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted,
@@ -24938,16 +24790,6 @@
},
/turf/open/floor/iron/grid/steel,
/area/medical/cryo)
-"grl" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line,
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
- dir = 8
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/arrival)
"grv" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
@@ -25104,14 +24946,8 @@
},
/area/hallway/primary/fore)
"gsS" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/bridge)
+/turf/open/floor/catwalk_floor,
+/area/docking/bridge)
"gsT" = (
/obj/machinery/atmospherics/components/binary/pump{
dir = 8;
@@ -25408,9 +25244,7 @@
/obj/structure/cable/orange{
icon_state = "1-2"
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"gxl" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -25932,9 +25766,7 @@
/area/science/mixing)
"gDc" = (
/obj/structure/lattice/catwalk/over,
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating/airless,
/area/asteroid/nearstation)
"gDi" = (
/obj/effect/turf_decal/siding/wideplating_new/dark{
@@ -28467,9 +28299,7 @@
roundstart_template = /datum/map_template/shuttle/arrival/fland;
width = 9
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/docking/arrival)
"hlJ" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
@@ -29039,9 +28869,7 @@
"hvt" = (
/obj/effect/turf_decal/box,
/obj/machinery/atmospherics/components/unary/vent_pump/on,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/drydock/security)
"hvz" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
@@ -30807,9 +30635,7 @@
/turf/open/floor/wood,
/area/library)
"hSG" = (
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating/airless,
/area/space)
"hSO" = (
/obj/effect/turf_decal/stripes/line{
@@ -32413,7 +32239,7 @@
},
/obj/machinery/stasis,
/obj/machinery/light,
-/turf/open/floor/iron/dark/airless,
+/turf/open/floor/iron/dark,
/area/medical/surgery)
"ipn" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4{
@@ -32508,7 +32334,7 @@
/turf/open/floor/engine/co2/light,
/area/engine/atmos)
"iqL" = (
-/obj/machinery/atmospherics/components/unary/tank/plasma{
+/obj/machinery/atmospherics/components/tank/plasma{
dir = 8
},
/obj/effect/turf_decal/bot,
@@ -33724,7 +33550,7 @@
},
/area/ai_monitored/turret_protected/ai)
"iEQ" = (
-/obj/machinery/air_sensor/atmos/air_tank,
+/obj/machinery/air_sensor/air_tank,
/turf/open/floor/engine/air/light,
/area/engine/atmos)
"iES" = (
@@ -34078,7 +33904,7 @@
/turf/open/floor/iron,
/area/hydroponics)
"iIU" = (
-/obj/machinery/air_sensor/atmos/nitrogen_tank,
+/obj/machinery/air_sensor/nitrogen_tank,
/turf/open/floor/engine/n2/light,
/area/engine/atmos)
"iIX" = (
@@ -35651,7 +35477,7 @@
id = 4;
dir = 4
},
-/obj/structure/cable/yellow{
+/obj/structure/cable/orange{
icon_state = "0-2"
},
/turf/open/floor/plating/airless,
@@ -35838,9 +35664,7 @@
pixel_x = -11;
pixel_y = -22
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/docking/bridge)
"jhn" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
@@ -36314,15 +36138,6 @@
/obj/structure/filingcabinet/chestdrawer,
/turf/open/floor/carpet/blue,
/area/crew_quarters/heads/hop)
-"jnd" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/arrival)
"jne" = (
/obj/structure/closet/crate,
/obj/effect/spawner/lootdrop/maintenance,
@@ -36402,7 +36217,7 @@
/turf/open/floor/iron/dark,
/area/hydroponics)
"jot" = (
-/obj/machinery/air_sensor/atmos/mix_tank,
+/obj/machinery/air_sensor/mix_tank,
/turf/open/floor/engine/vacuum/light,
/area/engine/atmos)
"joE" = (
@@ -37088,16 +36903,6 @@
},
/turf/open/floor/iron/dark,
/area/security/brig)
-"jzQ" = (
-/obj/effect/turf_decal/box,
-/obj/effect/turf_decal/stripes/line,
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
- dir = 8
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/arrival)
"jAa" = (
/turf/open/floor/iron/dark/side,
/area/hallway/secondary/service)
@@ -37813,7 +37618,7 @@
/area/security/main)
"jIP" = (
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/components/unary/tank/plasma{
+/obj/machinery/atmospherics/components/tank/plasma{
dir = 1
},
/obj/effect/turf_decal/delivery,
@@ -38005,7 +37810,7 @@
external_pressure_bound = 120;
name = "killroom vent"
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark/telecomms,
/area/science/xenobiology)
"jLx" = (
/obj/effect/turf_decal/bot,
@@ -38650,13 +38455,11 @@
/turf/open/floor/iron,
/area/quartermaster/office)
"jTj" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8
},
/obj/effect/turf_decal/bot,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"jTm" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{
@@ -40213,7 +40016,7 @@
/turf/open/floor/plating/airless{
initial_gas_mix = "o2=14;n2=23;TEMP=300"
},
-/area/bridge)
+/area/docking/bridge)
"kmD" = (
/obj/structure/table/wood,
/obj/item/reagent_containers/cup/soda_cans/dr_gibb,
@@ -40460,9 +40263,7 @@
dir = 4
},
/obj/machinery/portable_atmospherics/canister/air,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"kqP" = (
/obj/machinery/hydroponics/constructable,
@@ -41369,7 +41170,7 @@
/obj/machinery/atmospherics/pipe/simple/general/hidden{
dir = 10
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark/telecomms,
/area/science/xenobiology)
"kAO" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -44017,16 +43818,10 @@
/turf/open/floor/iron,
/area/security/courtroom)
"lgP" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
/obj/machinery/light{
dir = 4
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"lgU" = (
/turf/open/floor/iron/dark,
@@ -44976,24 +44771,6 @@
},
/turf/open/floor/plating,
/area/crew_quarters/heads/cmo)
-"lrt" = (
-/obj/structure/lattice/catwalk/over,
-/obj/item/stack/marker_beacon{
- anchored = 1;
- icon_state = "markerburgundy-on";
- light_color = "#FA644B";
- light_power = 3;
- light_range = 2;
- name = "landing marker";
- picked_color = "Burgundy"
- },
-/obj/effect/turf_decal/stripes/corner{
- dir = 8
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/arrival)
"lru" = (
/obj/structure/chair/stool/directional/south,
/turf/open/floor/carpet,
@@ -47460,7 +47237,7 @@
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
dir = 4
},
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_atmos{
+/obj/machinery/airlock_controller/incinerator_atmos{
pixel_y = 27
},
/obj/machinery/door/airlock/public/glass/incinerator/atmos_interior,
@@ -48973,7 +48750,7 @@
/turf/open/floor/iron/grid/steel,
/area/medical/apothecary)
"mwq" = (
-/obj/machinery/air_sensor/atmos/plasma_tank,
+/obj/machinery/air_sensor/plasma_tank,
/turf/open/floor/engine/plasma/light,
/area/engine/atmos)
"mwr" = (
@@ -50038,9 +49815,7 @@
/obj/machinery/atmospherics/components/binary/valve/digital{
dir = 4
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"mKk" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4{
@@ -51729,9 +51504,7 @@
/obj/structure/cable/orange{
icon_state = "4-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/docking/bridge)
"nhu" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
@@ -53453,9 +53226,7 @@
/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
dir = 1
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"nFb" = (
/obj/structure/table/wood,
@@ -53903,7 +53674,9 @@
/area/engine/atmos)
"nJU" = (
/obj/effect/turf_decal/bot,
-/turf/open/floor/iron/techmaint,
+/turf/open/floor/iron/techmaint{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/science/server)
"nKa" = (
/obj/machinery/atmospherics/components/unary/portables_connector/visible,
@@ -54287,9 +54060,7 @@
/obj/structure/cable/yellow{
icon_state = "0-2"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/drydock/security)
"nRh" = (
/obj/structure/closet/secure_closet/freezer/meat,
@@ -54754,20 +54525,14 @@
/turf/open/floor/vault,
/area/engine/engine_room)
"nYU" = (
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/structure/lattice/catwalk/over,
/obj/structure/cable/yellow{
icon_state = "0-8"
},
/obj/machinery/power/terminal{
dir = 1
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/bridge)
+/turf/open/floor/catwalk_floor,
+/area/docking/bridge)
"nZa" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -54798,7 +54563,6 @@
/turf/open/floor/iron/dark/telecomms,
/area/tcommsat/server)
"nZl" = (
-/obj/structure/lattice/catwalk/over,
/obj/item/stack/marker_beacon{
anchored = 1;
icon_state = "markerburgundy-on";
@@ -54808,12 +54572,7 @@
name = "landing marker";
picked_color = "Burgundy"
},
-/obj/effect/turf_decal/stripes/corner{
- dir = 1
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"nZq" = (
/obj/structure/cable/yellow{
@@ -55911,20 +55670,14 @@
name = "landing marker";
picked_color = "Burgundy"
},
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/structure/lattice/catwalk/over,
/obj/machinery/button/shieldwallgen/directional/north{
id = 4
},
/obj/structure/cable/orange{
icon_state = "2-4"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/bridge)
+/turf/open/floor/catwalk_floor,
+/area/docking/bridge)
"onz" = (
/obj/structure/cable/yellow{
icon_state = "4-8"
@@ -56303,11 +56056,10 @@
/turf/open/floor/plating,
/area/hallway/primary/starboard)
"orP" = (
-/obj/structure/lattice/catwalk/over,
/obj/machinery/advanced_airlock_controller{
pixel_y = 26
},
-/turf/open/floor/plating/airless,
+/turf/open/floor/catwalk_floor,
/area/maintenance/solars/starboard/fore)
"orV" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4,
@@ -56368,7 +56120,7 @@
/obj/structure/cable/orange{
icon_state = "0-8"
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/drydock)
"osF" = (
/obj/effect/turf_decal/siding/thinplating_new/dark{
@@ -56955,13 +56707,6 @@
/obj/effect/spawner/lootdrop/grille_or_trash,
/turf/open/floor/plating,
/area/maintenance/aft)
-"oBY" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/arrival)
"oCf" = (
/obj/structure/table/reinforced,
/obj/item/clothing/gloves/color/black,
@@ -57441,9 +57186,7 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 4
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/docking/arrival)
"oIu" = (
/obj/machinery/telecomms/server/presets/engineering,
@@ -59790,9 +59533,7 @@
/area/library)
"pqt" = (
/obj/structure/lattice,
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"pqv" = (
/obj/item/toy/figure/scientist{
@@ -60276,8 +60017,7 @@
/area/maintenance/solars/starboard/fore)
"pyl" = (
/obj/machinery/light/small,
-/obj/structure/lattice/catwalk/over,
-/turf/open/floor/plating/airless,
+/turf/open/floor/catwalk_floor,
/area/maintenance/solars/starboard/fore)
"pyo" = (
/obj/effect/mapping_helpers/airlock/cyclelink_helper{
@@ -60509,7 +60249,7 @@
/obj/structure/cable/orange{
icon_state = "0-8"
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/drydock)
"pBe" = (
/obj/effect/turf_decal/bot{
@@ -60541,14 +60281,8 @@
/turf/open/floor/iron,
/area/hallway/primary/port)
"pBz" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
/obj/machinery/light,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"pBC" = (
/obj/effect/turf_decal/trimline/blue/line{
@@ -60609,6 +60343,7 @@
roundstart_template = /datum/map_template/shuttle/escape_pod/default;
width = 3
},
+/obj/structure/fans/tiny/invisible,
/turf/open/space/basic,
/area/space)
"pBX" = (
@@ -62375,14 +62110,10 @@
/turf/open/floor/iron/dark,
/area/vacant_room/commissary/commissaryFood)
"qaM" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line,
/obj/machinery/light{
dir = 1
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"qaO" = (
/obj/machinery/vending/boozeomat{
@@ -62834,7 +62565,7 @@
/area/crew_quarters/locker)
"qfX" = (
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/asteroid/nearstation)
"qgh" = (
/obj/structure/cable/yellow{
@@ -63537,7 +63268,7 @@
/turf/open/floor/iron/dark,
/area/quartermaster/storage)
"qpm" = (
-/obj/machinery/air_sensor/atmos/toxins_mixing_tank,
+/obj/machinery/air_sensor/toxins_mixing_tank,
/turf/open/floor/engine/vacuum,
/area/science/mixing/chamber)
"qpD" = (
@@ -65216,7 +64947,7 @@
/obj/machinery/atmospherics/pipe/manifold/general/hidden{
dir = 1
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark/telecomms,
/area/science/xenobiology)
"qKw" = (
/obj/structure/closet/radiation,
@@ -65707,7 +65438,7 @@
/turf/open/floor/plating,
/area/maintenance/port/central)
"qRb" = (
-/obj/machinery/air_sensor/atmos/nitrous_tank,
+/obj/machinery/air_sensor/nitrous_tank,
/turf/open/floor/engine/n2o/light,
/area/engine/atmos)
"qRg" = (
@@ -66037,7 +65768,7 @@
"qTZ" = (
/obj/effect/mapping_helpers/airlock/locked,
/obj/machinery/door/airlock/research/glass/incinerator/toxmix_interior,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix{
+/obj/machinery/airlock_controller/incinerator_toxmix{
pixel_x = -24
},
/obj/effect/turf_decal/stripes/closeup,
@@ -66247,17 +65978,13 @@
/turf/open/floor/carpet/red,
/area/crew_quarters/bar/atrium)
"qYy" = (
-/obj/effect/turf_decal/stripes/line,
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
dir = 4
},
-/obj/structure/lattice/catwalk/over,
/obj/structure/cable/orange{
icon_state = "4-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"qYA" = (
/obj/structure/cable/yellow{
@@ -66391,9 +66118,7 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"rbz" = (
/obj/effect/decal/cleanable/cobweb/cobweb2,
@@ -66584,9 +66309,7 @@
/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
dir = 1
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"rdZ" = (
/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/toxins_mixing_input{
@@ -66989,13 +66712,11 @@
/obj/machinery/light{
dir = 4
},
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8
},
/obj/effect/turf_decal/bot,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"rjE" = (
/obj/effect/turf_decal/siding/dark,
@@ -68172,7 +67893,7 @@
/obj/item/radio/intercom{
pixel_x = 28
},
-/turf/open/floor/iron/dark/airless,
+/turf/open/floor/iron/dark,
/area/medical/surgery)
"rzi" = (
/obj/structure/table/wood,
@@ -69249,9 +68970,8 @@
dir = 8
},
/obj/structure/closet/emcloset,
-/obj/structure/lattice/catwalk/over,
/obj/structure/railing,
-/turf/open/floor/plating,
+/turf/open/floor/catwalk_floor,
/area/bridge)
"rMD" = (
/obj/structure/closet/firecloset,
@@ -69328,7 +69048,7 @@
c_tag = "Medbay - Sleepers";
name = "medbay camera"
},
-/turf/open/floor/iron/dark/airless,
+/turf/open/floor/iron/dark,
/area/medical/surgery)
"rNL" = (
/obj/effect/turf_decal/bot,
@@ -69403,9 +69123,7 @@
/area/medical/surgery)
"rOn" = (
/obj/machinery/atmospherics/pipe/simple/cyan/visible,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"rOo" = (
/obj/item/kirbyplants/random,
@@ -69685,7 +69403,7 @@
"rQn" = (
/obj/effect/turf_decal/stripes/full,
/obj/effect/turf_decal/stripes/white/full,
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/drydock)
"rQq" = (
/obj/structure/lattice/catwalk,
@@ -70221,7 +69939,7 @@
/turf/closed/wall/r_wall,
/area/maintenance/department/engine)
"rXD" = (
-/obj/machinery/air_sensor/atmos/carbon_tank,
+/obj/machinery/air_sensor/carbon_tank,
/turf/open/floor/engine/co2/light,
/area/engine/atmos)
"rXH" = (
@@ -71664,11 +71382,6 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
/turf/open/floor/plating,
/area/maintenance/department/medical)
-"sqV" = (
-/turf/open/floor/plating{
- broken = 1
- },
-/area/space/nearstation)
"srh" = (
/obj/machinery/portable_atmospherics/canister/plasma,
/obj/machinery/conveyor{
@@ -72419,9 +72132,7 @@
/area/hallway/primary/port)
"sAP" = (
/obj/structure/lattice,
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating/airless,
/area/asteroid/nearstation)
"sAU" = (
/obj/machinery/status_display/evac{
@@ -73490,19 +73201,13 @@
name = "landing marker";
picked_color = "Burgundy"
},
-/obj/effect/turf_decal/stripes/corner{
- dir = 4
- },
-/obj/structure/lattice/catwalk/over,
/obj/machinery/atmospherics/pipe/manifold/cyan/hidden{
dir = 8
},
/obj/structure/cable/orange{
icon_state = "1-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"sPK" = (
/obj/structure/closet/crate/medical,
@@ -76223,9 +75928,7 @@
dir = 8
},
/obj/machinery/button/shieldwallgen/directional/west,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"tAi" = (
/obj/structure/lattice/catwalk/over,
@@ -76297,9 +76000,7 @@
/obj/machinery/atmospherics/pipe/simple/cyan/visible{
dir = 4
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"tAY" = (
/obj/effect/turf_decal/bot,
@@ -76718,9 +76419,7 @@
/obj/structure/cable/orange{
icon_state = "0-4"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/drydock)
"tGU" = (
/obj/structure/tank_dispenser/oxygen,
@@ -76909,20 +76608,16 @@
name = "landing marker";
picked_color = "Burgundy"
},
-/obj/effect/turf_decal/stripes/corner,
/obj/machinery/atmospherics/pipe/manifold/cyan/hidden{
dir = 8
},
-/obj/structure/lattice/catwalk/over,
/obj/structure/cable/orange{
icon_state = "2-8"
},
/obj/structure/cable/orange{
icon_state = "2-4"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"tJu" = (
/obj/structure/chair/stool,
@@ -77075,9 +76770,7 @@
/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
dir = 4
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"tLe" = (
/turf/open/floor/iron/techmaint,
@@ -77624,9 +77317,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"tSo" = (
/obj/effect/decal/cleanable/dirt,
@@ -77924,9 +77615,7 @@
dir = 4
},
/obj/structure/cable/yellow,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"tVx" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4{
@@ -80411,9 +80100,7 @@
pixel_x = -24
},
/obj/effect/turf_decal/box,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/drydock/security)
"uAb" = (
/obj/effect/spawner/structure/window,
@@ -80720,7 +80407,9 @@
"uEa" = (
/obj/machinery/rnd/server,
/obj/effect/turf_decal/bot,
-/turf/open/floor/iron/techmaint,
+/turf/open/floor/iron/techmaint{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/science/server)
"uEn" = (
/obj/machinery/conveyor{
@@ -81217,9 +80906,7 @@
/turf/open/floor/iron,
/area/maintenance/disposal)
"uJQ" = (
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating,
/area/docking/bridge)
"uJW" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
@@ -81372,10 +81059,6 @@
/turf/open/floor/plating,
/area/crew_quarters/dorms)
"uME" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
/obj/item/stack/marker_beacon{
anchored = 1;
@@ -81389,9 +81072,7 @@
/obj/structure/cable/orange{
icon_state = "1-2"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"uMM" = (
/obj/structure/closet/firecloset,
@@ -82580,7 +82261,7 @@
/area/storage/tools)
"vby" = (
/obj/machinery/igniter/incinerator_atmos,
-/obj/machinery/air_sensor/atmos/incinerator_tank{
+/obj/machinery/air_sensor/incinerator_tank{
pixel_x = 32;
pixel_y = 32
},
@@ -82903,12 +82584,6 @@
/obj/effect/turf_decal/tile/purple/opposingcorners,
/turf/open/floor/iron/white,
/area/science/lobby)
-"vfD" = (
-/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating{
- broken = 1
- },
-/area/space/nearstation)
"vfE" = (
/obj/structure/sign/departments/minsky/research/research,
/turf/closed/wall,
@@ -85816,9 +85491,7 @@
/turf/open/floor/catwalk_floor,
/area/docking/bridge)
"vKJ" = (
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating/airless,
/area/asteroid/nearstation)
"vKW" = (
/obj/effect/turf_decal/stripes/end{
@@ -85867,7 +85540,7 @@
/turf/open/floor/iron/techmaint,
/area/maintenance/department/engine)
"vLy" = (
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix{
+/obj/machinery/airlock_controller/incinerator_toxmix{
pixel_y = 26
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
@@ -86031,9 +85704,7 @@
/obj/machinery/light{
dir = 1
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"vNv" = (
/obj/effect/turf_decal/guideline/guideline_mid/purple{
@@ -86937,9 +86608,7 @@
/obj/machinery/atmospherics/pipe/simple/cyan/visible{
dir = 5
},
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"vWy" = (
/obj/structure/chair/fancy/comfy{
@@ -87042,9 +86711,7 @@
/obj/item/multitool,
/obj/item/clothing/mask/gas,
/obj/item/tank/internals/oxygen/red,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"vYE" = (
/obj/structure/disposalpipe/segment{
@@ -88233,9 +87900,7 @@
/area/chapel/main)
"wov" = (
/obj/machinery/camera/directional/south,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"woJ" = (
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
@@ -88984,7 +88649,7 @@
name = "killroom vent";
pressure_checks = 0
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark/telecomms,
/area/science/xenobiology)
"wyB" = (
/obj/structure/disposalpipe/sorting/mail{
@@ -89734,7 +89399,9 @@
name = "server vent";
pressure_checks = 0
},
-/turf/open/floor/iron/techmaint,
+/turf/open/floor/iron/techmaint{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/science/server)
"wIz" = (
/obj/effect/decal/cleanable/dirt/dust,
@@ -90246,7 +89913,7 @@
id = 4;
dir = 8
},
-/obj/structure/cable/yellow{
+/obj/structure/cable/orange{
icon_state = "0-2"
},
/turf/open/floor/plating/airless,
@@ -90384,12 +90051,6 @@
/obj/effect/turf_decal/tile/purple/opposingcorners,
/turf/open/floor/iron/white,
/area/science/shuttledock)
-"wQm" = (
-/obj/structure/lattice/catwalk/over,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/arrival)
"wQu" = (
/turf/closed/wall,
/area/science/lobby)
@@ -90420,7 +90081,6 @@
/turf/open/floor/plating,
/area/quartermaster/storage)
"wRq" = (
-/obj/structure/lattice/catwalk/over,
/obj/item/stack/marker_beacon{
anchored = 1;
icon_state = "markerburgundy-on";
@@ -90430,15 +90090,10 @@
name = "landing marker";
picked_color = "Burgundy"
},
-/obj/effect/turf_decal/stripes/line{
- dir = 8
- },
/obj/structure/cable/orange{
icon_state = "1-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/bridge)
"wRr" = (
/obj/structure/sign/poster/official/nanotrasen_logo,
@@ -90670,9 +90325,7 @@
/obj/structure/railing/corner{
dir = 1
},
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating/airless,
/area/asteroid/nearstation)
"wTK" = (
/obj/effect/turf_decal/trimline/red/filled/line,
@@ -91289,19 +90942,6 @@
/obj/effect/turf_decal/tile/neutral/half/contrasted,
/turf/open/floor/iron,
/area/crew_quarters/locker)
-"wZw" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/structure/lattice/catwalk/over,
-/obj/structure/cable/orange{
- icon_state = "1-2"
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/arrival)
"wZy" = (
/obj/machinery/atmospherics/pipe/simple/cyan/visible,
/obj/machinery/light{
@@ -92162,16 +91802,10 @@
},
/area/quartermaster/office)
"xhP" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
/obj/machinery/atmospherics/pipe/simple/cyan/hidden{
dir = 8
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"xhU" = (
/obj/effect/spawner/structure/window/reinforced,
@@ -92181,13 +91815,7 @@
/turf/open/floor/plating,
/area/hallway/secondary/entry)
"xib" = (
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/catwalk_floor,
/area/docking/arrival)
"xid" = (
/obj/machinery/atmospherics/pipe/simple/dark/visible{
@@ -93089,9 +92717,7 @@
/area/engine/engine_room)
"xrR" = (
/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"xsj" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
@@ -94147,9 +93773,7 @@
/turf/open/floor/iron/dark,
/area/engine/engine_room)
"xDa" = (
-/turf/open/floor/engine{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/engine,
/area/docking/arrival)
"xDf" = (
/obj/machinery/airalarm/directional/south{
@@ -94747,7 +94371,7 @@
/turf/open/floor/plating,
/area/maintenance/central)
"xIu" = (
-/obj/machinery/air_sensor/atmos/oxygen_tank,
+/obj/machinery/air_sensor/oxygen_tank,
/turf/open/floor/engine/o2/light,
/area/engine/atmos)
"xIB" = (
@@ -96070,9 +95694,6 @@
/area/science/xenobiology)
"xWi" = (
/obj/effect/turf_decal/box,
-/obj/effect/turf_decal/stripes/line{
- dir = 1
- },
/obj/machinery/atmospherics/components/unary/vent_pump/on{
dir = 8
},
@@ -96849,19 +96470,6 @@
"yfq" = (
/turf/closed/wall/r_wall,
/area/science/robotics/lab)
-"yfG" = (
-/obj/machinery/atmospherics/pipe/simple/cyan/hidden,
-/obj/structure/lattice/catwalk/over,
-/obj/effect/turf_decal/stripes/line{
- dir = 4
- },
-/obj/structure/cable/orange{
- icon_state = "1-2"
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/docking/arrival)
"yfI" = (
/obj/effect/turf_decal/stripes/line{
dir = 1
@@ -96888,12 +96496,6 @@
"yfU" = (
/turf/closed/wall,
/area/library)
-"yfY" = (
-/obj/machinery/power/terminal{
- dir = 1
- },
-/turf/open/space/basic,
-/area/space)
"ygc" = (
/obj/effect/turf_decal/stripes/line{
dir = 1
@@ -97317,9 +96919,7 @@
/area/security/nuke_storage)
"yky" = (
/obj/effect/landmark/xeno_spawn,
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"ykE" = (
/obj/item/radio/intercom{
@@ -110452,15 +110052,15 @@ xOI
vYB
tAg
fEn
-wQm
-wQm
-wQm
-wQm
+xib
+xib
+xib
+xib
oIm
-wQm
-wQm
-wQm
-wQm
+xib
+xib
+xib
+xib
fEn
fzy
wov
@@ -110709,10 +110309,10 @@ big
rOn
aoe
tJh
-wZw
-yfG
-eDO
-yfG
+eoY
+eoY
+uME
+eoY
bnD
eoY
uME
@@ -113021,7 +112621,7 @@ tNT
tNT
gfc
djY
-grl
+xhP
bbm
bbm
bbm
@@ -113278,7 +112878,7 @@ tLV
lSq
tNJ
djY
-jzQ
+xWi
bbm
bbm
bbm
@@ -113535,7 +113135,7 @@ tNT
tNT
tNJ
djY
-oBY
+xib
bbm
bbm
bbm
@@ -114820,7 +114420,7 @@ tNJ
djY
dCe
xub
-oBY
+xib
bbm
bbm
bbm
@@ -115077,7 +114677,7 @@ tNJ
djY
cNG
xub
-oBY
+xib
bbm
bbm
bbm
@@ -115334,7 +114934,7 @@ tNJ
djY
xpd
xub
-oBY
+xib
bbm
bbm
bbm
@@ -115591,16 +115191,16 @@ tNJ
djY
eiU
xub
-lrt
-jnd
-jnd
-jnd
-jnd
+nZl
+xib
+xib
+xib
+xib
lgP
-jnd
-jnd
-jnd
-jnd
+xib
+xib
+xib
+xib
nZl
xub
xOJ
@@ -125771,7 +125371,7 @@ xJu
hSG
aco
acn
-sqV
+bXh
csJ
csJ
kHH
@@ -126024,7 +125624,7 @@ csJ
csJ
nnx
nnx
-sqV
+bXh
acn
abN
xJu
@@ -126276,9 +125876,9 @@ nnx
nnx
aar
nnx
-dUK
-sqV
-cov
+pqt
+bXh
+bXh
bbZ
bbZ
csJ
@@ -126535,7 +126135,7 @@ csJ
nnx
nnx
csJ
-sqV
+bXh
csJ
abJ
csJ
@@ -126543,7 +126143,7 @@ nnx
nnx
csJ
nnx
-cov
+bXh
ahx
nnx
anu
@@ -126794,17 +126394,17 @@ nnx
nnx
bbZ
csJ
-crA
-dUK
+acn
+pqt
cer
-vfD
+amr
csJ
csJ
pqt
aco
csJ
anE
-aCb
+vKJ
qfX
oaI
lLM
@@ -127048,20 +126648,20 @@ nnx
nnx
nnx
bXh
-sqV
+bXh
bXh
bbZ
aoW
bXh
-sqV
-cov
+bXh
+bXh
csJ
bbZ
bbZ
asG
-eew
+vKJ
axD
-aCb
+vKJ
vKJ
oaI
jID
@@ -127307,11 +126907,11 @@ csJ
nnx
nnx
csJ
-sqV
+bXh
csJ
csJ
csJ
-cov
+bXh
tuT
adt
cib
@@ -127573,7 +127173,7 @@ acO
aep
cib
sAP
-aCb
+vKJ
vKJ
kHH
jID
@@ -127822,11 +127422,11 @@ nnx
nnx
nnx
csJ
-cov
-sqV
bXh
+bXh
+bXh
+vKJ
vKJ
-eew
acO
baI
dYM
@@ -128076,7 +127676,7 @@ nnx
nnx
nnx
nnx
-cov
+bXh
aob
jID
hsU
@@ -128588,7 +128188,7 @@ nnx
nnx
bbZ
nnx
-crA
+acn
nnx
nnx
aoW
@@ -128842,7 +128442,7 @@ nnx
nnx
nnx
nnx
-sqV
+bXh
nnx
nnx
nnx
@@ -146342,7 +145942,7 @@ nnx
nnx
nnx
nnx
-yfY
+nnx
nnx
nnx
nnx
@@ -148407,18 +148007,18 @@ nnx
nnx
wON
wRq
-bKE
+gsS
dvX
-bKE
-bKE
-bKE
+gsS
+gsS
+gsS
dLx
-bKE
-bKE
-bKE
+gsS
+gsS
+gsS
dvX
-bKE
-dDv
+gsS
+epQ
vNw
fYs
kiO
diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm
index 546616589ca9d..ce4b658f96abf 100644
--- a/_maps/map_files/KiloStation/KiloStation.dmm
+++ b/_maps/map_files/KiloStation/KiloStation.dmm
@@ -2952,11 +2952,6 @@
},
/turf/open/floor/plating,
/area/engine/engineering)
-"aDQ" = (
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/space/nearstation)
"aDT" = (
/obj/effect/turf_decal/stripes/line{
dir = 9
@@ -3379,7 +3374,7 @@
/turf/open/floor/engine/n2,
/area/engine/atmos)
"aGV" = (
-/obj/machinery/air_sensor/atmos/nitrogen_tank,
+/obj/machinery/air_sensor/nitrogen_tank,
/turf/open/floor/engine/n2,
/area/engine/atmos)
"aGW" = (
@@ -3395,7 +3390,7 @@
/turf/open/floor/engine/o2,
/area/engine/atmos)
"aGY" = (
-/obj/machinery/air_sensor/atmos/oxygen_tank,
+/obj/machinery/air_sensor/oxygen_tank,
/turf/open/floor/engine/o2,
/area/engine/atmos)
"aGZ" = (
@@ -3411,7 +3406,7 @@
/turf/open/floor/engine/air,
/area/engine/atmos)
"aHb" = (
-/obj/machinery/air_sensor/atmos/air_tank,
+/obj/machinery/air_sensor/air_tank,
/turf/open/floor/engine/air,
/area/engine/atmos)
"aHc" = (
@@ -3427,7 +3422,7 @@
/turf/open/floor/engine/co2,
/area/engine/atmos)
"aHe" = (
-/obj/machinery/air_sensor/atmos/carbon_tank,
+/obj/machinery/air_sensor/carbon_tank,
/turf/open/floor/engine/co2,
/area/engine/atmos)
"aHf" = (
@@ -3443,7 +3438,7 @@
/turf/open/floor/engine/plasma,
/area/engine/atmos)
"aHh" = (
-/obj/machinery/air_sensor/atmos/plasma_tank,
+/obj/machinery/air_sensor/plasma_tank,
/turf/open/floor/engine/plasma,
/area/engine/atmos)
"aHi" = (
@@ -3459,7 +3454,7 @@
/turf/open/floor/engine/n2o,
/area/engine/atmos)
"aHk" = (
-/obj/machinery/air_sensor/atmos/nitrous_tank,
+/obj/machinery/air_sensor/nitrous_tank,
/turf/open/floor/engine/n2o,
/area/engine/atmos)
"aHl" = (
@@ -3475,7 +3470,7 @@
/turf/open/floor/engine/vacuum,
/area/engine/atmos)
"aHn" = (
-/obj/machinery/air_sensor/atmos/mix_tank,
+/obj/machinery/air_sensor/mix_tank,
/turf/open/floor/engine/vacuum,
/area/engine/atmos)
"aHo" = (
@@ -4332,12 +4327,6 @@
},
/turf/open/floor/iron,
/area/hallway/secondary/exit/departure_lounge)
-"aTd" = (
-/obj/effect/decal/cleanable/blood/old,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/space/nearstation)
"aTe" = (
/obj/machinery/flasher{
id = "AI";
@@ -4424,16 +4413,6 @@
/obj/structure/disposalpipe/segment,
/turf/open/floor/iron/showroomfloor,
/area/science/xenobiology)
-"aUq" = (
-/obj/machinery/light/small,
-/obj/effect/turf_decal/sand/plating,
-/obj/structure/cable/yellow{
- icon_state = "0-4"
- },
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/space/nearstation)
"aUz" = (
/obj/structure/flora/rock/pile,
/turf/open/floor/plating/asteroid/airless,
@@ -4764,9 +4743,7 @@
/obj/structure/cable/yellow{
icon_state = "2-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"aYG" = (
/obj/machinery/computer/card/minor/rd{
@@ -4937,8 +4914,9 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/plating/airless,
-/area/space/nearstation)
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plating,
+/area/ai_monitored/turret_protected/ai_upload)
"aZS" = (
/turf/closed/wall/r_wall,
/area/science/robotics/lab)
@@ -5005,8 +4983,9 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/plating/airless,
-/area/space/nearstation)
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plating,
+/area/ai_monitored/turret_protected/ai_upload)
"baC" = (
/obj/effect/spawner/structure/window/reinforced,
/turf/open/floor/plating,
@@ -5114,7 +5093,7 @@
},
/area/maintenance/port/fore)
"bbt" = (
-/obj/machinery/air_sensor/atmos/toxins_mixing_tank,
+/obj/machinery/air_sensor/toxins_mixing_tank,
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/engine/vacuum,
/area/science/mixing/chamber)
@@ -5535,9 +5514,7 @@
/obj/structure/cable/yellow{
icon_state = "1-4"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"bfU" = (
/obj/effect/landmark/blobstart,
@@ -7579,9 +7556,7 @@
"byY" = (
/obj/structure/flora/grass/jungle,
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"bzb" = (
/obj/structure/table,
@@ -8336,9 +8311,7 @@
"bFR" = (
/obj/structure/flora/rock/pile,
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"bFU" = (
/obj/machinery/light/small{
@@ -8987,8 +8960,8 @@
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
+/turf/open/floor/plating{
+ burnt = 1
},
/area/quartermaster/exploration_dock)
"bNm" = (
@@ -9202,19 +9175,11 @@
/obj/structure/sign/warning/docking,
/turf/closed/wall,
/area/hallway/secondary/entry)
-"bQb" = (
-/obj/structure/flora/rock,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/space/nearstation)
"bQc" = (
/obj/effect/decal/cleanable/blood/old,
/obj/effect/decal/cleanable/blood/gibs/old,
/obj/effect/decal/remains/xeno,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/space/nearstation)
"bQg" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer2,
@@ -9231,9 +9196,7 @@
"bQq" = (
/obj/effect/decal/cleanable/blood/old,
/obj/effect/decal/cleanable/blood/gibs/limb,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/space/nearstation)
"bQr" = (
/obj/effect/turf_decal/tile/neutral{
@@ -9274,9 +9237,7 @@
/obj/effect/decal/remains/human,
/obj/effect/decal/cleanable/blood/old,
/obj/item/pickaxe,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/space/nearstation)
"bQO" = (
/obj/effect/decal/cleanable/dirt,
@@ -9308,9 +9269,7 @@
"bRy" = (
/obj/effect/decal/cleanable/blood/old,
/obj/effect/decal/cleanable/blood/gibs/old,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/space/nearstation)
"bRA" = (
/obj/machinery/status_display/evac,
@@ -9858,7 +9817,8 @@
"bZy" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/grille/broken,
-/turf/open/floor/plating/airless,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"bZD" = (
/obj/machinery/button/door{
@@ -11621,11 +11581,6 @@
},
/turf/open/space/basic,
/area/solar/port/fore)
-"crn" = (
-/turf/open/floor/plating{
- broken = 1
- },
-/area/space/nearstation)
"crq" = (
/obj/structure/sign/warning/nosmoking,
/turf/closed/wall/rust,
@@ -12156,7 +12111,9 @@
/obj/item/wallframe/light_fixture/small{
pixel_y = -14
},
-/turf/open/floor/catwalk_floor,
+/turf/open/floor/catwalk_floor{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/quartermaster/warehouse)
"cxo" = (
/obj/effect/spawner/room/tenxten,
@@ -12250,9 +12207,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 6
},
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"cze" = (
/obj/effect/decal/cleanable/dirt,
@@ -12375,6 +12330,11 @@
},
/turf/open/floor/iron/dark,
/area/maintenance/fore)
+"cAt" = (
+/turf/open/floor/catwalk_floor{
+ initial_gas_mix = "TEMP=2.7"
+ },
+/area/quartermaster/warehouse)
"cAy" = (
/obj/structure/table,
/obj/machinery/light/small{
@@ -13818,7 +13778,7 @@
/obj/machinery/igniter{
id = "Incinerator"
},
-/obj/machinery/air_sensor/atmos/incinerator_tank{
+/obj/machinery/air_sensor/incinerator_tank{
pixel_x = -32;
pixel_y = -32
},
@@ -14809,9 +14769,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"cVZ" = (
/obj/item/kirbyplants/random,
@@ -15823,9 +15781,7 @@
/area/engine/engineering)
"dmA" = (
/obj/effect/turf_decal/box/corners,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"dmJ" = (
/obj/effect/turf_decal/tile/neutral{
@@ -17315,12 +17271,6 @@
/obj/machinery/camera/directional/south,
/turf/open/floor/iron/dark,
/area/security/brig/aft)
-"dLt" = (
-/obj/item/flashlight/lantern,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/space/nearstation)
"dLv" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -17415,8 +17365,8 @@
pixel_x = 32
},
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
+/turf/open/floor/plating{
+ burnt = 1
},
/area/quartermaster/exploration_dock)
"dLX" = (
@@ -18820,6 +18770,7 @@
pixel_y = -32
},
/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating{
broken = 1
},
@@ -20030,7 +19981,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/structure/table,
/obj/item/stack/rods/ten,
-/turf/open/floor/plating/airless,
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"eAv" = (
/obj/effect/decal/cleanable/dirt,
@@ -21476,7 +21427,7 @@
/obj/effect/turf_decal/stripes/closeup{
dir = 1
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark/airless,
/area/quartermaster/warehouse)
"eYs" = (
/obj/machinery/atmospherics/components/binary/pump{
@@ -21498,7 +21449,7 @@
/turf/open/floor/engine,
/area/engine/engineering)
"eYu" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/plating,
/area/maintenance/port/aft)
"eYx" = (
@@ -22265,9 +22216,7 @@
},
/area/hallway/primary/central)
"fkv" = (
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"fkw" = (
/obj/effect/decal/cleanable/dirt,
@@ -23174,7 +23123,7 @@
"fzP" = (
/obj/effect/turf_decal/bot,
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/obj/effect/turf_decal/tile/yellow{
dir = 8
},
@@ -24610,9 +24559,7 @@
/obj/structure/cable/yellow{
icon_state = "1-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"fWS" = (
/obj/effect/turf_decal/tile/blue/half/contrasted{
@@ -24805,9 +24752,7 @@
dir = 8
},
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"gaQ" = (
/obj/machinery/atmospherics/pipe/manifold/general/visible{
@@ -25057,9 +25002,7 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"geV" = (
/obj/machinery/power/apc{
@@ -25605,9 +25548,7 @@
/obj/structure/flora/ausbushes/grassybush,
/obj/structure/flora/ausbushes/palebush,
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"goQ" = (
/obj/effect/turf_decal/box/corners{
@@ -25769,9 +25710,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"grE" = (
/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted,
@@ -26612,9 +26551,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"gHx" = (
/obj/structure/filingcabinet,
@@ -26711,7 +26648,7 @@
/mob/living/simple_animal/hostile/asteroid/basilisk{
environment_smash = 0
},
-/turf/open/floor/plating/asteroid/airless,
+/turf/open/floor/plating/asteroid,
/area/quartermaster/warehouse)
"gKd" = (
/obj/machinery/clonepod/prefilled,
@@ -27140,9 +27077,7 @@
"gQV" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/flora/grass/jungle/b,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"gRe" = (
/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2{
@@ -27160,9 +27095,7 @@
icon_state = "1-2"
},
/obj/structure/lattice/catwalk,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"gRv" = (
/obj/machinery/computer/card/minor/hos{
@@ -27808,7 +27741,7 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/plating{
broken = 1
},
@@ -28214,9 +28147,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"hhY" = (
/obj/machinery/atmospherics/pipe/simple/green/visible,
@@ -28734,9 +28665,7 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 4
},
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"hqB" = (
/obj/effect/decal/cleanable/dirt,
@@ -30258,12 +30187,6 @@
/obj/effect/turf_decal/stripes/closeup,
/turf/open/floor/iron/dark,
/area/hallway/primary/starboard)
-"hPF" = (
-/obj/item/pickaxe,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
-/area/space/nearstation)
"hPN" = (
/obj/structure/disposalpipe/segment,
/obj/structure/cable/yellow{
@@ -31085,9 +31008,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"icc" = (
/obj/machinery/door/firedoor,
@@ -31277,8 +31198,8 @@
pixel_x = -25;
req_access_txt = "49"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
+/turf/open/floor/plating{
+ burnt = 1
},
/area/quartermaster/exploration_dock)
"igj" = (
@@ -33136,7 +33057,7 @@
/obj/effect/turf_decal/stripes/closeup{
dir = 1
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark/airless,
/area/quartermaster/warehouse)
"iKB" = (
/obj/machinery/telecomms/server/presets/exploration,
@@ -34031,9 +33952,7 @@
/turf/open/floor/iron/dark,
/area/ai_monitored/storage/eva)
"iXp" = (
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"iXC" = (
/obj/effect/turf_decal/tile/red/half/contrasted{
@@ -35119,9 +35038,7 @@
icon_state = "1-2"
},
/obj/structure/lattice/catwalk,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"jsj" = (
/obj/machinery/door/firedoor,
@@ -36773,9 +36690,7 @@
/obj/structure/cable/yellow{
icon_state = "0-2"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"jSa" = (
/obj/machinery/meter/atmos/distro_loop,
@@ -37179,8 +37094,8 @@
/obj/structure/sign/warning/securearea{
pixel_x = 32
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
+/turf/open/floor/plating{
+ burnt = 1
},
/area/quartermaster/exploration_dock)
"jZU" = (
@@ -37476,9 +37391,7 @@
pixel_y = -25;
req_access_txt = "19"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"kgm" = (
/obj/effect/spawner/structure/window/reinforced,
@@ -38413,9 +38326,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/spawner/lootdrop/glowstick,
/obj/structure/grille/broken,
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"kvl" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
@@ -39999,7 +39910,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/structure/table,
/obj/effect/spawner/lootdrop/maintenance,
-/turf/open/floor/plating/airless,
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"kZz" = (
/obj/machinery/holopad,
@@ -42326,7 +42237,8 @@
icon_state = "0-4"
},
/turf/open/floor/plating{
- burnt = 1
+ burnt = 1;
+ initial_gas_mix = "n2=100;TEMP=80"
},
/area/tcommsat/server)
"lLq" = (
@@ -42754,7 +42666,7 @@
/obj/item/storage/toolbox/emergency{
pixel_y = 5
},
-/turf/open/floor/plating/airless,
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"lUc" = (
/obj/machinery/door/airlock/maintenance{
@@ -42983,9 +42895,7 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 10
},
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"lXy" = (
/obj/effect/decal/cleanable/dirt,
@@ -43476,9 +43386,7 @@
/area/hallway/primary/port)
"mdx" = (
/obj/machinery/portable_atmospherics/canister/air,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"mdB" = (
/turf/open/floor/plating{
@@ -44017,9 +43925,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 10
},
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"mmO" = (
/obj/structure/disposalpipe/segment{
@@ -44082,9 +43988,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 5
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"mnW" = (
/obj/structure/grille/broken,
@@ -44219,9 +44123,7 @@
"mpg" = (
/obj/structure/flora/grass/jungle/b,
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"mpi" = (
/obj/machinery/power/apc{
@@ -44341,9 +44243,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 10
},
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"mrO" = (
/obj/structure/cable/yellow{
@@ -45304,7 +45204,7 @@
"mHw" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/ash,
-/turf/open/floor/plating/airless,
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"mHC" = (
/obj/effect/turf_decal/tile/red/half/contrasted{
@@ -46634,9 +46534,7 @@
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4{
dir = 4
},
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"nhh" = (
/obj/structure/sign/poster/contraband/random{
@@ -47114,17 +47012,6 @@
},
/turf/open/floor/iron/dark,
/area/quartermaster/warehouse)
-"npe" = (
-/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
-/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
-/obj/structure/sign/poster/contraband/random{
- pixel_x = -32
- },
-/turf/open/floor/plating{
- burnt = 1
- },
-/area/maintenance/port/aft)
"npg" = (
/obj/structure/disposalpipe/segment,
/obj/structure/cable/yellow{
@@ -48592,9 +48479,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 1
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"nPI" = (
/obj/structure/table,
@@ -50119,9 +50004,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 10
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"ono" = (
/obj/effect/turf_decal/tile/neutral/half/contrasted{
@@ -50481,9 +50364,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 8
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"otk" = (
/obj/structure/disposalpipe/segment,
@@ -50665,9 +50546,8 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/cobweb,
/obj/structure/closet/wardrobe/green,
-/turf/open/floor/plating{
- broken = 1
- },
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"ouU" = (
/obj/structure/table,
@@ -51215,9 +51095,7 @@
/obj/effect/turf_decal/box/corners{
dir = 8
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"oDt" = (
/obj/structure/table,
@@ -52475,7 +52353,7 @@
/area/maintenance/port/aft)
"oYK" = (
/obj/structure/flora/rock/pile,
-/turf/open/floor/plating/asteroid/airless,
+/turf/open/floor/plating/asteroid,
/area/quartermaster/warehouse)
"oYL" = (
/obj/machinery/atmospherics/components/unary/portables_connector/visible{
@@ -52528,9 +52406,7 @@
dir = 5
},
/obj/machinery/light/small,
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"oZK" = (
/obj/item/radio/intercom{
@@ -52717,9 +52593,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 9
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"pcx" = (
/obj/effect/mapping_helpers/airlock/locked,
@@ -52826,9 +52700,7 @@
/area/maintenance/fore)
"peL" = (
/obj/structure/flora/rock/pile,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"peN" = (
/obj/machinery/status_display/ai{
@@ -54789,9 +54661,7 @@
/area/hallway/primary/starboard)
"pJN" = (
/obj/machinery/atmospherics/components/unary/outlet_injector/on,
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating/airless,
/area/engine/atmos)
"pJP" = (
/obj/effect/turf_decal/bot,
@@ -55548,7 +55418,7 @@
"pXJ" = (
/obj/effect/turf_decal/bot,
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/iron/dark,
/area/maintenance/port/aft)
"pXK" = (
@@ -56695,6 +56565,11 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
/turf/open/floor/plating,
/area/maintenance/disposal)
+"qpn" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plating,
+/area/maintenance/port/aft)
"qpr" = (
/obj/machinery/atmospherics/pipe/simple/yellow/visible{
dir = 4
@@ -56745,9 +56620,7 @@
/obj/effect/turf_decal/box/corners{
dir = 1
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"qqf" = (
/obj/structure/extinguisher_cabinet{
@@ -58507,9 +58380,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"qUP" = (
/turf/closed/wall/r_wall,
@@ -58670,9 +58541,7 @@
/obj/effect/turf_decal/stripes/corner{
dir = 9
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"qWI" = (
/obj/machinery/door/firedoor,
@@ -59614,9 +59483,7 @@
"rmu" = (
/obj/structure/flora/ausbushes/palebush,
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"rmD" = (
/obj/structure/cable/yellow{
@@ -60405,9 +60272,7 @@
/obj/structure/cable/yellow{
icon_state = "0-2"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"rAJ" = (
/obj/structure/cable/yellow{
@@ -61112,6 +60977,10 @@
/obj/effect/turf_decal/bot,
/turf/open/floor/iron/showroomfloor,
/area/medical/virology)
+"rMt" = (
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plating/airless,
+/area/quartermaster/warehouse)
"rMy" = (
/obj/machinery/door/firedoor,
/obj/machinery/door/airlock/mining/glass{
@@ -61973,9 +61842,7 @@
/area/maintenance/port)
"saY" = (
/obj/effect/turf_decal/stripes/line,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"sbv" = (
/obj/effect/decal/cleanable/dirt,
@@ -62901,6 +62768,9 @@
},
/turf/open/floor/iron/dark/smooth_large,
/area/ai_monitored/security/armory)
+"srV" = (
+/turf/open/floor/plating/airless,
+/area/quartermaster/warehouse)
"ssg" = (
/obj/machinery/door/airlock/engineering,
/obj/structure/barricade/wooden/crude,
@@ -63094,9 +62964,7 @@
/obj/structure/sign/poster/contraband/random{
pixel_x = -32
},
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"svS" = (
/obj/effect/decal/cleanable/dirt,
@@ -63114,9 +62982,7 @@
"swh" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/flora/grass/jungle,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"sws" = (
/obj/effect/decal/cleanable/dirt,
@@ -63680,9 +63546,7 @@
/obj/structure/flora/ausbushes/lavendergrass,
/obj/structure/flora/ausbushes/fernybush,
/obj/effect/decal/cleanable/dirt,
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"sDD" = (
/obj/effect/decal/cleanable/dirt,
@@ -64147,9 +64011,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 5
},
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"sLJ" = (
/obj/effect/landmark/start/station_engineer,
@@ -64918,9 +64780,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"sWQ" = (
/obj/effect/spawner/randomvend/cola,
@@ -66881,7 +66741,9 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/catwalk_floor,
+/turf/open/floor/catwalk_floor{
+ initial_gas_mix = "TEMP=2.7"
+ },
/area/quartermaster/warehouse)
"tFf" = (
/obj/structure/rack,
@@ -67029,9 +66891,8 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 4
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"tHq" = (
/obj/machinery/computer/mecha{
@@ -67249,7 +67110,7 @@
/obj/structure/cable/yellow{
icon_state = "0-4"
},
-/obj/machinery/atmospherics/components/unary/tank/plasma,
+/obj/machinery/atmospherics/components/tank/plasma,
/obj/effect/turf_decal/tile/neutral/half/contrasted,
/turf/open/floor/iron/dark,
/area/maintenance/disposal/incinerator)
@@ -67994,9 +67855,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"ucl" = (
/obj/machinery/light{
@@ -69014,9 +68873,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"uqQ" = (
/obj/machinery/firealarm{
@@ -69210,9 +69067,7 @@
"utn" = (
/obj/effect/decal/cleanable/oil,
/obj/machinery/portable_atmospherics/canister/air,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"utp" = (
/obj/structure/table,
@@ -69470,9 +69325,7 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 9
},
-/turf/open/floor/plating{
- broken = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"uwn" = (
/obj/machinery/rnd/production/techfab/department/medical,
@@ -69655,9 +69508,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/plating/asteroid/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/asteroid/airless,
/area/docking/arrival)
"uzO" = (
/obj/structure/table/wood/fancy,
@@ -70604,8 +70455,8 @@
dir = 8
},
/obj/structure/lattice/catwalk,
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
+/turf/open/floor/plating{
+ burnt = 1
},
/area/quartermaster/exploration_dock)
"uQe" = (
@@ -72139,6 +71990,12 @@
broken = 1
},
/area/maintenance/aft)
+"vpt" = (
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/catwalk_floor{
+ initial_gas_mix = "TEMP=2.7"
+ },
+/area/quartermaster/warehouse)
"vpA" = (
/obj/machinery/status_display/evac{
pixel_x = 32;
@@ -73200,7 +73057,7 @@
/obj/structure/cable{
icon_state = "1-2"
},
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_atmos{
+/obj/machinery/airlock_controller/incinerator_atmos{
pixel_x = -24;
pixel_y = 6
},
@@ -73798,7 +73655,7 @@
/area/janitor)
"vOC" = (
/obj/machinery/atmospherics/components/binary/valve,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix{
+/obj/machinery/airlock_controller/incinerator_toxmix{
pixel_y = 26
},
/obj/machinery/light/small{
@@ -74563,7 +74420,7 @@
},
/area/maintenance/starboard/fore)
"waD" = (
-/turf/open/floor/plating/asteroid/airless,
+/turf/open/floor/plating/asteroid,
/area/quartermaster/warehouse)
"waG" = (
/obj/structure/chair/office/light{
@@ -74868,9 +74725,7 @@
/obj/structure/cable/yellow{
icon_state = "4-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"wgX" = (
/turf/closed/wall/r_wall/rust,
@@ -75295,9 +75150,7 @@
/obj/effect/turf_decal/box/corners{
dir = 4
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"wnB" = (
/obj/structure/disposalpipe/sorting/mail/flip{
@@ -76745,9 +76598,7 @@
/obj/structure/cable/yellow{
icon_state = "1-2"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"wLe" = (
/obj/effect/decal/cleanable/dirt,
@@ -77097,9 +76948,7 @@
"wPY" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/grille,
-/turf/open/floor/plating{
- burnt = 1
- },
+/turf/open/floor/plating,
/area/maintenance/port/aft)
"wQt" = (
/obj/effect/turf_decal/stripes/line{
@@ -77975,9 +77824,7 @@
/obj/structure/cable/yellow{
icon_state = "2-8"
},
-/turf/open/floor/plating/airless{
- initial_gas_mix = "o2=14;n2=23;TEMP=300"
- },
+/turf/open/floor/plating/airless,
/area/docking/arrival)
"xbp" = (
/obj/effect/decal/cleanable/dirt,
@@ -93143,7 +92990,7 @@ aeU
aeu
aeu
aeu
-bKl
+aUz
aeu
aeu
bUG
@@ -93655,8 +93502,8 @@ aUz
aeU
aeu
aeu
-bKl
-aDQ
+aUz
+aeU
aeu
aeu
aeu
@@ -94170,7 +94017,7 @@ aeu
aeu
aeu
bQc
-aDQ
+aeU
aeu
aeu
aeu
@@ -94425,8 +94272,8 @@ aeU
aeu
aeu
aeu
-aDQ
-aDQ
+aeU
+aeU
aeu
aeu
aeu
@@ -94683,8 +94530,8 @@ aeu
aeu
aeu
aeu
-aDQ
-aDQ
+aeU
+aeU
aeu
aeu
aeu
@@ -94938,11 +94785,11 @@ cwp
aeu
aeu
aeu
-aDQ
-bKl
+aeU
+aUz
bQq
-bQb
-aDQ
+coy
+aeU
aeu
aeu
amA
@@ -95194,12 +95041,12 @@ czz
cwq
aeu
aeu
-bKl
-aDQ
-dLt
-aDQ
-aDQ
-aDQ
+aUz
+aeU
+oxq
+aeU
+aeU
+aeU
aeu
aeu
amR
@@ -95451,12 +95298,12 @@ cwp
cwp
cwp
cwp
-aDQ
-aDQ
-aTd
-bKl
-hPF
-aDQ
+aeU
+aeU
+aoz
+aUz
+mkf
+aeU
aeu
aeu
amA
@@ -95708,11 +95555,11 @@ jen
wgZ
dpG
emS
-aDQ
-aDQ
-bQb
-aDQ
-aDQ
+aeU
+aeU
+coy
+aeU
+aeU
amA
amR
amA
@@ -95965,11 +95812,11 @@ wgZ
oTh
wgZ
emS
-aDQ
+aeU
aeu
-aDQ
-aDQ
-aUq
+aeU
+aeU
+sRS
amA
mGY
hzg
@@ -96011,8 +95858,8 @@ lRg
jtU
jtU
idS
-jtU
-jtU
+cnm
+cnm
ajd
cmU
aeU
@@ -96225,7 +96072,7 @@ cwp
aeu
aeu
aeu
-aDQ
+aeU
aYE
uQQ
iMQ
@@ -96269,7 +96116,7 @@ jtU
jtU
ajd
mHw
-jtU
+cnm
ajd
cmU
coy
@@ -96526,7 +96373,7 @@ cJr
cJr
cJr
eAp
-jtU
+cnm
ajd
cmU
aeU
@@ -96783,7 +96630,7 @@ dgY
oWY
cJr
kZj
-jtU
+cnm
ajd
cmU
aeU
@@ -97040,11 +96887,11 @@ cjw
clQ
cJr
lTS
-jtU
+cnm
ajd
cmU
aeU
-crn
+aeU
aeu
aeu
cnS
@@ -97554,7 +97401,7 @@ fGu
uVf
lXJ
cJI
-jtU
+qpn
ajd
mvK
xbl
@@ -97811,7 +97658,7 @@ jLI
xDP
wBA
cJr
-cnm
+qpn
gfk
vNp
nnW
@@ -105502,7 +105349,7 @@ bIV
bIV
cza
nha
-npe
+svy
fKt
dku
gMg
@@ -107049,7 +106896,7 @@ rZP
ylu
ajd
nmt
-bMR
+cnm
aaY
aaY
axB
@@ -107850,7 +107697,7 @@ aMY
aFM
acK
bHB
-crn
+cko
cko
acm
aaa
@@ -132644,8 +132491,8 @@ aeu
aeu
aeu
act
-nDJ
-cCI
+vpt
+srV
tEO
abq
aeu
@@ -132901,8 +132748,8 @@ aeu
aeu
aeu
act
-fyQ
-cCU
+cAt
+rMt
cxg
act
aeu
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 5cc91b2484665..1937a4ed47930 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -11656,7 +11656,7 @@
/turf/open/floor/iron,
/area/engine/atmos)
"bEd" = (
-/obj/machinery/air_sensor/atmos/mix_tank,
+/obj/machinery/air_sensor/mix_tank,
/turf/open/floor/engine/vacuum,
/area/engine/atmos)
"bEe" = (
@@ -12714,7 +12714,7 @@
/turf/open/floor/iron/dark,
/area/engine/atmos)
"bKH" = (
-/obj/machinery/air_sensor/atmos/nitrous_tank,
+/obj/machinery/air_sensor/nitrous_tank,
/turf/open/floor/engine/n2o,
/area/engine/atmos)
"bKJ" = (
@@ -13707,7 +13707,7 @@
/turf/open/floor/iron,
/area/engine/atmos)
"bQX" = (
-/obj/machinery/air_sensor/atmos/plasma_tank,
+/obj/machinery/air_sensor/plasma_tank,
/turf/open/floor/engine/plasma,
/area/engine/atmos)
"bQZ" = (
@@ -14752,7 +14752,7 @@
/turf/open/floor/iron,
/area/engine/atmos)
"bVN" = (
-/obj/machinery/air_sensor/atmos/carbon_tank,
+/obj/machinery/air_sensor/carbon_tank,
/turf/open/floor/engine/co2,
/area/engine/atmos)
"bVP" = (
@@ -16024,7 +16024,7 @@
/turf/open/floor/engine/n2,
/area/engine/atmos)
"chO" = (
-/obj/machinery/air_sensor/atmos/nitrogen_tank,
+/obj/machinery/air_sensor/nitrogen_tank,
/turf/open/floor/engine/n2,
/area/engine/atmos)
"chP" = (
@@ -16040,7 +16040,7 @@
/turf/open/floor/engine/o2,
/area/engine/atmos)
"chR" = (
-/obj/machinery/air_sensor/atmos/oxygen_tank,
+/obj/machinery/air_sensor/oxygen_tank,
/turf/open/floor/engine/o2,
/area/engine/atmos)
"chS" = (
@@ -16056,7 +16056,7 @@
/turf/open/floor/engine/air,
/area/engine/atmos)
"chU" = (
-/obj/machinery/air_sensor/atmos/air_tank,
+/obj/machinery/air_sensor/air_tank,
/turf/open/floor/engine/air,
/area/engine/atmos)
"chV" = (
@@ -17721,7 +17721,7 @@
external_pressure_bound = 120;
name = "server vent"
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark/telecomms,
/area/science/server)
"cxa" = (
/obj/item/stack/cable_coil,
@@ -21715,7 +21715,9 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 5
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"dle" = (
/obj/effect/landmark/start/virologist,
@@ -28787,7 +28789,9 @@
},
/obj/machinery/atmospherics/pipe/manifold/supply/hidden/layer2,
/obj/machinery/atmospherics/pipe/heat_exchanging/manifold,
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"fRq" = (
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2,
@@ -39247,7 +39251,7 @@
icon_state = "1-2"
},
/turf/open/floor/wood,
-/area/library)
+/area/maintenance/department/science)
"jQR" = (
/obj/effect/landmark/start/lawyer,
/obj/effect/turf_decal/siding/wood{
@@ -42095,7 +42099,7 @@
icon_state = "1-2"
},
/obj/effect/mapping_helpers/airlock/cyclelink_helper,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_atmos{
+/obj/machinery/airlock_controller/incinerator_atmos{
pixel_x = 38;
pixel_y = 6
},
@@ -42599,7 +42603,7 @@
/obj/machinery/atmospherics/pipe/manifold/cyan/visible{
dir = 1
},
-/turf/open/floor/iron/dark,
+/turf/open/floor/iron/dark/telecomms,
/area/science/server)
"lfu" = (
/obj/effect/decal/cleanable/dirt,
@@ -43788,7 +43792,9 @@
},
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"lCt" = (
/obj/effect/turf_decal/tile/blue{
@@ -48127,8 +48133,8 @@
/area/engine/break_room)
"ndq" = (
/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on{
- dir = 1;
- initialize_directions = 1
+ initialize_directions = 1;
+ dir = 1
},
/turf/open/floor/carpet/grimy,
/area/tcommsat/computer)
@@ -48941,6 +48947,9 @@
},
/turf/open/floor/plating,
/area/science/lab)
+"nuK" = (
+/turf/open/space/basic,
+/area/maintenance/department/science)
"nuR" = (
/obj/machinery/door/airlock{
name = "Service Hall";
@@ -53166,7 +53175,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 9
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"oRB" = (
/obj/structure/cable/yellow{
@@ -54415,7 +54426,9 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 8
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"psw" = (
/obj/structure/chair{
@@ -55268,7 +55281,9 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 4
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"pKq" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer2,
@@ -57050,7 +57065,9 @@
/area/crew_quarters/dorms)
"qpw" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"qpE" = (
/obj/structure/table,
@@ -58058,7 +58075,7 @@
"qJb" = (
/obj/machinery/atmospherics/pipe/simple/general/visible,
/obj/machinery/meter,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix{
+/obj/machinery/airlock_controller/incinerator_toxmix{
pixel_y = -24
},
/obj/structure/cable/yellow{
@@ -58077,7 +58094,9 @@
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
dir = 9
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"qKa" = (
/obj/effect/turf_decal/siding/white/corner,
@@ -61184,7 +61203,9 @@
/area/maintenance/aft)
"rSp" = (
/obj/machinery/atmospherics/pipe/heat_exchanging/simple,
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"rSy" = (
/obj/structure/chair,
@@ -61539,7 +61560,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 5
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"rXW" = (
/obj/machinery/door/airlock/maintenance{
@@ -63387,7 +63410,9 @@
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4{
dir = 8
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"sHt" = (
/obj/machinery/light/small,
@@ -63623,7 +63648,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 10
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"sLD" = (
/obj/structure/sink{
@@ -65894,7 +65921,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 4
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"tBm" = (
/obj/effect/turf_decal/stripes/line{
@@ -67062,7 +67091,7 @@
/area/science/research)
"tWN" = (
/obj/machinery/airalarm/server{
- dir = 4;
+ dir = 8;
pixel_x = -22
},
/obj/machinery/light/small{
@@ -72036,7 +72065,9 @@
/area/security/brig)
"vKV" = (
/obj/machinery/atmospherics/pipe/manifold/scrubbers/hidden/layer4,
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"vKY" = (
/obj/structure/cable/yellow{
@@ -74749,7 +74780,7 @@
/turf/open/floor/iron,
/area/hallway/primary/central)
"wLZ" = (
-/obj/machinery/air_sensor/atmos/toxins_mixing_tank,
+/obj/machinery/air_sensor/toxins_mixing_tank,
/turf/open/floor/engine,
/area/science/mixing/chamber)
"wMy" = (
@@ -76676,7 +76707,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 6
},
-/turf/open/floor/catwalk_floor/iron_dark,
+/turf/open/floor/catwalk_floor/iron_dark{
+ initial_gas_mix = "n2=100;TEMP=80"
+ },
/area/tcommsat/server)
"xty" = (
/obj/item/cigbutt,
@@ -119497,7 +119530,7 @@ aaa
aaa
aaa
aaa
-aaa
+nuK
aaa
aaa
aaa
diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm
index 37c6fed74298a..e87ba16a09849 100644
--- a/_maps/map_files/Mining/Lavaland.dmm
+++ b/_maps/map_files/Mining/Lavaland.dmm
@@ -1667,7 +1667,9 @@
/obj/machinery/light/small{
dir = 1
},
-/turf/open/floor/iron/dark/telecomms,
+/turf/open/floor/iron/dark/telecomms{
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
+ },
/area/mine/living_quarters)
"kV" = (
/obj/machinery/atmospherics/pipe/simple/general/hidden{
@@ -2069,7 +2071,7 @@
/turf/closed/indestructible/riveted/boss,
/area/lavaland/surface/outdoors)
"nQ" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8
},
/obj/structure/lattice/catwalk/over,
@@ -2957,7 +2959,7 @@
/turf/open/floor/plating/asteroid/basalt/lava_land_surface,
/area/lavaland/surface/outdoors)
"uZ" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8
},
/obj/machinery/light/small{
diff --git a/_maps/map_files/RadStation/RadStation.dmm b/_maps/map_files/RadStation/RadStation.dmm
index 22f6758e458c8..4156dffedf126 100644
--- a/_maps/map_files/RadStation/RadStation.dmm
+++ b/_maps/map_files/RadStation/RadStation.dmm
@@ -962,7 +962,7 @@
/obj/structure/cable{
icon_state = "0-8"
},
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"aps" = (
/obj/machinery/camera/directional/north{
@@ -4729,7 +4729,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 6
},
-/turf/open/floor/circuit/green/telecomms/mainframe,
+/turf/open/floor/circuit/green/telecomms/mainframe{
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
+ },
/area/quartermaster/exploration_prep)
"bwK" = (
/obj/effect/landmark/start/assistant,
@@ -8817,7 +8819,7 @@
/obj/structure/cable{
icon_state = "1-2"
},
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"cNI" = (
/obj/item/radio/intercom{
@@ -9806,7 +9808,7 @@
/area/medical/break_room)
"deN" = (
/obj/structure/lattice/catwalk,
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"deW" = (
/obj/effect/landmark/xeno_spawn,
@@ -9958,7 +9960,7 @@
uses = 10
},
/obj/effect/turf_decal/box,
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"diq" = (
/obj/machinery/camera/directional/east,
@@ -10713,7 +10715,9 @@
/obj/structure/window/reinforced{
dir = 8
},
-/turf/open/floor/circuit/green/telecomms/mainframe,
+/turf/open/floor/circuit/green/telecomms/mainframe{
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
+ },
/area/quartermaster/exploration_prep)
"dvV" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4{
@@ -16980,7 +16984,7 @@
dir = 8
},
/obj/structure/lattice/catwalk,
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"fpi" = (
/obj/effect/turf_decal/stripes/line{
@@ -18718,7 +18722,6 @@
/obj/machinery/light{
dir = 8
},
-/obj/machinery/firealarm/directional/west,
/turf/open/floor/engine{
initial_gas_mix = "n2=100;TEMP=80";
name = "mainframe floor"
@@ -19039,7 +19042,7 @@
"fXw" = (
/obj/structure/lattice/catwalk,
/obj/structure/marker_beacon,
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"fXJ" = (
/turf/closed/wall/r_wall/rust,
@@ -21836,7 +21839,9 @@
/obj/structure/window/reinforced{
dir = 8
},
-/turf/open/floor/circuit/green/telecomms/mainframe,
+/turf/open/floor/circuit/green/telecomms/mainframe{
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
+ },
/area/quartermaster/exploration_prep)
"gRR" = (
/obj/machinery/camera/directional/west{
@@ -22375,7 +22380,7 @@
/turf/open/floor/iron/tech,
/area/engine/engine_room)
"gZx" = (
-/obj/machinery/air_sensor/atmos/oxygen_tank,
+/obj/machinery/air_sensor/oxygen_tank,
/turf/open/floor/engine/o2,
/area/engine/atmos)
"gZQ" = (
@@ -26301,7 +26306,7 @@
/turf/open/floor/iron/white,
/area/science/lab)
"iqg" = (
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"iqm" = (
/obj/structure/sign/warning/pods,
@@ -26586,7 +26591,7 @@
/turf/open/floor/iron,
/area/engine/break_room)
"ivH" = (
-/obj/machinery/air_sensor/atmos/air_tank,
+/obj/machinery/air_sensor/air_tank,
/turf/open/floor/engine/air,
/area/engine/atmos)
"ivY" = (
@@ -28663,7 +28668,7 @@
icon_state = "4-8"
},
/obj/effect/mapping_helpers/airlock/locked,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_atmos{
+/obj/machinery/airlock_controller/incinerator_atmos{
pixel_x = 6;
pixel_y = 28
},
@@ -29049,7 +29054,7 @@
/turf/open/floor/iron/dark,
/area/security/brig)
"jlM" = (
-/obj/machinery/air_sensor/atmos/sm_core,
+/obj/machinery/air_sensor/sm_core,
/turf/open/floor/engine,
/area/engine/supermatter)
"jlP" = (
@@ -30630,7 +30635,7 @@
/obj/machinery/porta_turret/ai{
dir = 4
},
-/turf/open/floor/engine/air,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"jNP" = (
/obj/structure/cable/yellow{
@@ -31476,7 +31481,7 @@
/area/crew_quarters/heads/captain)
"kaD" = (
/obj/machinery/airalarm/directional/north,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8;
initialize_directions = 8
},
@@ -31845,7 +31850,9 @@
"khS" = (
/obj/machinery/telecomms/processor/preset_exploration,
/obj/machinery/camera/directional/east,
-/turf/open/floor/circuit/green/telecomms/mainframe,
+/turf/open/floor/circuit/green/telecomms/mainframe{
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
+ },
/area/quartermaster/exploration_prep)
"khT" = (
/obj/structure/disposalpipe/segment{
@@ -33022,7 +33029,7 @@
/obj/structure/cable{
icon_state = "1-8"
},
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"kBB" = (
/obj/machinery/light/floor,
@@ -45891,7 +45898,7 @@
/turf/open/floor/iron/dark,
/area/security/brig/dock)
"oFY" = (
-/obj/machinery/air_sensor/atmos/plasma_tank,
+/obj/machinery/air_sensor/plasma_tank,
/turf/open/floor/engine/plasma,
/area/engine/atmos)
"oGm" = (
@@ -48801,7 +48808,7 @@
/turf/open/floor/prison,
/area/security/prison)
"pxB" = (
-/obj/machinery/air_sensor/atmos/carbon_tank,
+/obj/machinery/air_sensor/carbon_tank,
/turf/open/floor/engine/co2,
/area/engine/atmos)
"pxM" = (
@@ -48844,7 +48851,7 @@
/area/security/prison)
"pyp" = (
/obj/structure/grille,
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/space/nearstation)
"pyt" = (
/obj/structure/table,
@@ -49100,7 +49107,9 @@
pixel_y = -8
},
/obj/item/kirbyplants/random,
-/turf/open/floor/circuit/green/telecomms/mainframe,
+/turf/open/floor/circuit/green/telecomms/mainframe{
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
+ },
/area/quartermaster/exploration_prep)
"pCW" = (
/obj/effect/turf_decal/stripes/line,
@@ -49319,7 +49328,7 @@
/turf/open/floor/iron,
/area/science/mixing)
"pGp" = (
-/obj/machinery/air_sensor/atmos/mix_tank,
+/obj/machinery/air_sensor/mix_tank,
/turf/open/floor/engine/airless,
/area/engine/atmos)
"pGt" = (
@@ -49798,7 +49807,7 @@
/turf/open/floor/prison,
/area/security/prison)
"pNR" = (
-/obj/machinery/air_sensor/atmos/nitrogen_tank,
+/obj/machinery/air_sensor/nitrogen_tank,
/turf/open/floor/engine/n2,
/area/engine/atmos)
"pOc" = (
@@ -50090,7 +50099,7 @@
dir = 4
},
/obj/structure/lattice/catwalk,
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"pSf" = (
/obj/effect/turf_decal/siding/wideplating/dark,
@@ -50417,7 +50426,9 @@
/obj/structure/window/reinforced{
dir = 8
},
-/turf/open/floor/circuit/green/telecomms/mainframe,
+/turf/open/floor/circuit/green/telecomms/mainframe{
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
+ },
/area/quartermaster/exploration_prep)
"pWY" = (
/obj/effect/landmark/start/chemist,
@@ -51548,7 +51559,9 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/simple{
dir = 10
},
-/turf/open/floor/circuit/green/telecomms/mainframe,
+/turf/open/floor/circuit/green/telecomms/mainframe{
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
+ },
/area/quartermaster/exploration_prep)
"qpA" = (
/obj/effect/turf_decal/siding/wideplating/dark,
@@ -55310,6 +55323,7 @@
/obj/machinery/atmospherics/components/unary/portables_connector{
dir = 4
},
+/obj/effect/mapping_helpers/atmos_auto_connect,
/turf/open/floor/iron/dark,
/area/quartermaster/exploration_prep)
"rzL" = (
@@ -62677,7 +62691,7 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix{
+/obj/machinery/airlock_controller/incinerator_toxmix{
pixel_x = -24
},
/turf/open/floor/iron/dark/side{
@@ -63796,7 +63810,7 @@
/turf/open/space/basic,
/area/space/nearstation)
"uiP" = (
-/obj/machinery/air_sensor/atmos/nitrous_tank,
+/obj/machinery/air_sensor/nitrous_tank,
/turf/open/floor/engine/n2o,
/area/engine/atmos)
"uiZ" = (
@@ -70268,7 +70282,7 @@
/obj/structure/cable{
icon_state = "1-2"
},
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"wxK" = (
/obj/structure/cable/yellow{
@@ -70989,7 +71003,9 @@
/area/security/detectives_office)
"wHX" = (
/obj/machinery/telecomms/server/presets/exploration,
-/turf/open/floor/circuit/green/telecomms/mainframe,
+/turf/open/floor/circuit/green/telecomms/mainframe{
+ initial_gas_mix = "o2=22;n2=82;TEMP=293.15"
+ },
/area/quartermaster/exploration_prep)
"wHY" = (
/obj/structure/closet,
@@ -75257,7 +75273,7 @@
pixel_y = -5;
req_access_txt = "19"
},
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"ycs" = (
/obj/machinery/atmospherics/pipe/simple/scrubbers/hidden/layer4,
@@ -75428,7 +75444,7 @@
/obj/structure/cable{
icon_state = "4-8"
},
-/turf/open/floor/engine/o2,
+/turf/open/floor/engine/airless,
/area/ai_monitored/turret_protected/ai)
"ygY" = (
/obj/machinery/atmospherics/pipe/manifold/general/visible,
diff --git a/_maps/map_files/debug/multiz.dmm b/_maps/map_files/debug/multiz.dmm
index cb883ac183f9c..72d9097321e7b 100644
--- a/_maps/map_files/debug/multiz.dmm
+++ b/_maps/map_files/debug/multiz.dmm
@@ -46,7 +46,7 @@
/turf/open/floor/plating,
/area/engine/atmos)
"am" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/plating,
/area/engine/atmos)
"an" = (
diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm
index 733e57dab0129..ccdcac0b586df 100644
--- a/_maps/map_files/debug/runtimestation.dmm
+++ b/_maps/map_files/debug/runtimestation.dmm
@@ -40,7 +40,7 @@
/turf/closed/wall/r_wall,
/area/engine/gravity_generator)
"am" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/plating,
/area/engine/atmos)
"an" = (
@@ -1081,7 +1081,7 @@
/turf/open/floor/iron,
/area/security/brig)
"dS" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/obj/machinery/camera/directional/north,
/turf/open/floor/plating,
/area/engine/atmos)
@@ -2853,7 +2853,7 @@
/turf/open/floor/iron,
/area/hallway/primary/central)
"XU" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/obj/machinery/light{
dir = 1
},
diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm
index 17b55609d0fd0..4c377c51d0d2e 100644
--- a/_maps/map_files/generic/CentCom.dmm
+++ b/_maps/map_files/generic/CentCom.dmm
@@ -355,7 +355,7 @@
/turf/open/floor/iron/dark,
/area/centcom/evac)
"bp" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+/obj/machinery/atmospherics/components/unary/vent_pump{
dir = 8
},
/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted,
@@ -1748,7 +1748,7 @@
/obj/structure/window/reinforced/survival_pod{
dir = 1
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/centcom/evac)
"gs" = (
/obj/machinery/vending/cola,
@@ -3478,7 +3478,7 @@
name = "Shower"
},
/obj/item/soap/deluxe,
-/obj/machinery/atmospherics/components/unary/vent_pump/on,
+/obj/machinery/atmospherics/components/unary/vent_pump,
/turf/open/floor/iron/white,
/area/centcom/ferry)
"nl" = (
@@ -3887,7 +3887,7 @@
/turf/open/floor/plating/asteroid/snow/airless,
/area/syndicate_mothership)
"oY" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+/obj/machinery/atmospherics/components/unary/vent_pump{
dir = 4
},
/turf/open/floor/wood,
@@ -3912,7 +3912,7 @@
/turf/open/floor/grass,
/area/centcom/evac)
"pe" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/iron/smooth_large,
/area/centcom/evac)
"ph" = (
@@ -5169,7 +5169,7 @@
/obj/machinery/computer/monitor/secret{
dir = 1
},
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+/obj/machinery/atmospherics/components/unary/vent_pump{
dir = 1
},
/obj/effect/decal/cleanable/dirt,
@@ -5185,7 +5185,7 @@
/turf/open/floor/iron,
/area/centcom/ferry)
"tF" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/obj/machinery/firealarm{
@@ -5486,7 +5486,7 @@
/turf/open/floor/wood,
/area/centcom/ferry)
"us" = (
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+/obj/machinery/atmospherics/components/unary/vent_pump{
dir = 1
},
/turf/open/floor/wood,
@@ -6081,7 +6081,7 @@
dir = 8;
pixel_x = 24
},
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+/obj/machinery/atmospherics/components/unary/vent_pump{
dir = 8
},
/turf/open/floor/carpet/grimy,
@@ -6523,7 +6523,7 @@
/obj/machinery/computer/security/telescreen/entertainment{
pixel_x = -32
},
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+/obj/machinery/atmospherics/components/unary/vent_pump{
dir = 4
},
/obj/machinery/light{
@@ -8796,7 +8796,9 @@
/turf/open/floor/iron/white,
/area/ctf)
"Gg" = (
-/turf/open/floor/plating/snowed,
+/turf/open/floor/plating/snowed{
+ temperature = 293.15
+ },
/area/ctf)
"Gh" = (
/obj/item/kirbyplants{
@@ -9212,7 +9214,7 @@
/area/space)
"HH" = (
/obj/structure/shuttle/engine/large,
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/centcom/evac)
"HJ" = (
/obj/effect/turf_decal/trimline/dark_blue/filled/line{
@@ -10029,7 +10031,7 @@
color = "#596479";
dir = 1
},
-/obj/machinery/atmospherics/components/unary/vent_pump/on{
+/obj/machinery/atmospherics/components/unary/vent_pump{
dir = 8
},
/turf/open/floor/carpet/grimy,
@@ -10275,7 +10277,7 @@
/turf/open/floor/iron/dark,
/area/centcom/ferry)
"Lv" = (
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/centcom/evac)
"Lx" = (
/obj/structure/chair,
@@ -10963,7 +10965,7 @@
/area/centcom/control)
"NT" = (
/obj/structure/window/paperframe{
- CanAtmosPass = 0
+ can_atmos_pass = 0
},
/turf/open/floor/wood,
/area/centcom/holding)
diff --git a/_maps/shuttles/emergency/emergency_delta.dmm b/_maps/shuttles/emergency/emergency_delta.dmm
index cd967380d5889..39eb6fe82e3d9 100644
--- a/_maps/shuttles/emergency/emergency_delta.dmm
+++ b/_maps/shuttles/emergency/emergency_delta.dmm
@@ -455,7 +455,7 @@
pixel_y = 9
},
/obj/effect/turf_decal/bot,
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/iron,
/area/shuttle/escape)
"bC" = (
diff --git a/_maps/shuttles/emergency/emergency_meta.dmm b/_maps/shuttles/emergency/emergency_meta.dmm
index 8b1be9081bdbb..e7652a11ed0e0 100644
--- a/_maps/shuttles/emergency/emergency_meta.dmm
+++ b/_maps/shuttles/emergency/emergency_meta.dmm
@@ -776,7 +776,7 @@
/area/shuttle/escape)
"fH" = (
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 4
},
/obj/effect/turf_decal/bot,
diff --git a/_maps/shuttles/emergency/emergency_raven.dmm b/_maps/shuttles/emergency/emergency_raven.dmm
index 9a2f8ab6f9f51..b8adceba015fe 100644
--- a/_maps/shuttles/emergency/emergency_raven.dmm
+++ b/_maps/shuttles/emergency/emergency_raven.dmm
@@ -1459,7 +1459,7 @@
name = "Station Intercom (General)";
pixel_y = 22
},
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/turf/open/floor/plating,
/area/shuttle/escape)
"vE" = (
diff --git a/_maps/shuttles/exploration/exploration_delta.dmm b/_maps/shuttles/exploration/exploration_delta.dmm
index 23b7e2567d416..c49606f045f7a 100644
--- a/_maps/shuttles/exploration/exploration_delta.dmm
+++ b/_maps/shuttles/exploration/exploration_delta.dmm
@@ -122,7 +122,7 @@
/turf/open/floor/mineral/titanium,
/area/shuttle/exploration)
"qa" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 4;
initialize_directions = 4
},
diff --git a/_maps/shuttles/exploration/exploration_rad.dmm b/_maps/shuttles/exploration/exploration_rad.dmm
index 70d4e205ba83b..429dd2bf0361f 100644
--- a/_maps/shuttles/exploration/exploration_rad.dmm
+++ b/_maps/shuttles/exploration/exploration_rad.dmm
@@ -319,7 +319,7 @@
/obj/machinery/firealarm/directional/south,
/obj/machinery/light,
/obj/effect/decal/cleanable/dirt/dust,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1;
initialize_directions = 1
},
diff --git a/_maps/shuttles/infiltrator/infiltrator_advanced.dmm b/_maps/shuttles/infiltrator/infiltrator_advanced.dmm
index a549ecf6db38c..16520dd26c5fa 100644
--- a/_maps/shuttles/infiltrator/infiltrator_advanced.dmm
+++ b/_maps/shuttles/infiltrator/infiltrator_advanced.dmm
@@ -2157,7 +2157,7 @@
/turf/open/floor/mineral/plastitanium,
/area/shuttle/syndicate/armory)
"eb" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8
},
/obj/effect/turf_decal/bot,
diff --git a/_maps/shuttles/pirate/pirate_default.dmm b/_maps/shuttles/pirate/pirate_default.dmm
index 9a11216e64085..6dfbac76e4f05 100644
--- a/_maps/shuttles/pirate/pirate_default.dmm
+++ b/_maps/shuttles/pirate/pirate_default.dmm
@@ -1864,7 +1864,7 @@
/turf/closed/wall/mineral/plastitanium,
/area/shuttle/pirate)
"Tl" = (
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 4
},
/obj/effect/turf_decal/stripes/line{
diff --git a/_maps/shuttles/ruin/ruin_caravan_victim.dmm b/_maps/shuttles/ruin/ruin_caravan_victim.dmm
index 851f1bd4af8f8..510c0f5f35e5f 100644
--- a/_maps/shuttles/ruin/ruin_caravan_victim.dmm
+++ b/_maps/shuttles/ruin/ruin_caravan_victim.dmm
@@ -475,7 +475,7 @@
/area/shuttle/caravan/freighter1)
"zd" = (
/obj/effect/turf_decal/bot,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 4
},
/obj/effect/decal/cleanable/dirt,
diff --git a/_maps/shuttles/ruin/ruin_pirate_cutter.dmm b/_maps/shuttles/ruin/ruin_pirate_cutter.dmm
index cddb5cd3f86d1..7f2d2fcc79847 100644
--- a/_maps/shuttles/ruin/ruin_pirate_cutter.dmm
+++ b/_maps/shuttles/ruin/ruin_pirate_cutter.dmm
@@ -643,7 +643,7 @@
/turf/open/floor/plating,
/area/shuttle/caravan/pirate)
"Gh" = (
-/obj/machinery/atmospherics/components/unary/tank/air,
+/obj/machinery/atmospherics/components/tank/air,
/obj/effect/turf_decal/bot,
/turf/open/floor/plating,
/area/shuttle/caravan/pirate)
diff --git a/_maps/shuttles/whiteship/whiteship_box.dmm b/_maps/shuttles/whiteship/whiteship_box.dmm
index 2276abbd60287..20a3612513227 100644
--- a/_maps/shuttles/whiteship/whiteship_box.dmm
+++ b/_maps/shuttles/whiteship/whiteship_box.dmm
@@ -388,7 +388,7 @@
/area/shuttle/abandoned/engine)
"bq" = (
/obj/effect/decal/cleanable/dirt/dust,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/obj/effect/turf_decal/bot,
diff --git a/_maps/shuttles/whiteship/whiteship_delta.dmm b/_maps/shuttles/whiteship/whiteship_delta.dmm
index 5ca8343ad2e6a..9d54a355e7898 100644
--- a/_maps/shuttles/whiteship/whiteship_delta.dmm
+++ b/_maps/shuttles/whiteship/whiteship_delta.dmm
@@ -529,7 +529,7 @@
dir = 1
},
/obj/effect/decal/cleanable/dirt/dust,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/turf/open/floor/plating,
diff --git a/_maps/shuttles/whiteship/whiteship_fland.dmm b/_maps/shuttles/whiteship/whiteship_fland.dmm
index 29cee5609ea4c..91f174527a3aa 100644
--- a/_maps/shuttles/whiteship/whiteship_fland.dmm
+++ b/_maps/shuttles/whiteship/whiteship_fland.dmm
@@ -769,7 +769,7 @@
"Uo" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 8
},
/obj/effect/turf_decal/bot,
diff --git a/_maps/shuttles/whiteship/whiteship_meta.dmm b/_maps/shuttles/whiteship/whiteship_meta.dmm
index 464a28f46c281..72c7a66fb6294 100644
--- a/_maps/shuttles/whiteship/whiteship_meta.dmm
+++ b/_maps/shuttles/whiteship/whiteship_meta.dmm
@@ -339,7 +339,7 @@
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/dirt/dust,
-/obj/machinery/atmospherics/components/unary/tank/air{
+/obj/machinery/atmospherics/components/tank/air{
dir = 1
},
/obj/effect/turf_decal/bot,
diff --git a/beestation.dme b/beestation.dme
index 68661c5cfe9a7..24b90796fdb8c 100644
--- a/beestation.dme
+++ b/beestation.dme
@@ -19,6 +19,7 @@
#include "code\_compile_options.dm"
#include "code\_debugger.dm"
#include "code\world.dm"
+#include "code\__DEFINES\_atoms.dm"
#include "code\__DEFINES\_click.dm"
#include "code\__DEFINES\_globals.dm"
#include "code\__DEFINES\_helpers.dm"
@@ -34,6 +35,7 @@
#include "code\__DEFINES\ai.dm"
#include "code\__DEFINES\airlock.dm"
#include "code\__DEFINES\alarm.dm"
+#include "code\__DEFINES\alerts.dm"
#include "code\__DEFINES\announcements.dm"
#include "code\__DEFINES\anomalies.dm"
#include "code\__DEFINES\antagonists.dm"
@@ -44,7 +46,6 @@
#include "code\__DEFINES\assemblies.dm"
#include "code\__DEFINES\assets.dm"
#include "code\__DEFINES\async.dm"
-#include "code\__DEFINES\atmospherics.dm"
#include "code\__DEFINES\atom_hud.dm"
#include "code\__DEFINES\balloon_alert.dm"
#include "code\__DEFINES\bans.dm"
@@ -200,6 +201,12 @@
#include "code\__DEFINES\xenoartifact_materials.dm"
#include "code\__DEFINES\xenobiology.dm"
#include "code\__DEFINES\zmimic.dm"
+#include "code\__DEFINES\atmospherics\atmos_core.dm"
+#include "code\__DEFINES\atmospherics\atmos_gasses.dm"
+#include "code\__DEFINES\atmospherics\atmos_helpers.dm"
+#include "code\__DEFINES\atmospherics\atmos_mapping_helpers.dm"
+#include "code\__DEFINES\atmospherics\atmos_mob_interaction.dm"
+#include "code\__DEFINES\atmospherics\atmos_piping.dm"
#include "code\__DEFINES\dcs\flags.dm"
#include "code\__DEFINES\dcs\helpers.dm"
#include "code\__DEFINES\dcs\signals.dm"
@@ -256,6 +263,7 @@
#include "code\__HELPERS\admin.dm"
#include "code\__HELPERS\announcements.dm"
#include "code\__HELPERS\areas.dm"
+#include "code\__HELPERS\atmospherics.dm"
#include "code\__HELPERS\atoms.dm"
#include "code\__HELPERS\bitflag_list.dm"
#include "code\__HELPERS\chat.dm"
@@ -285,6 +293,7 @@
#include "code\__HELPERS\names.dm"
#include "code\__HELPERS\path.dm"
#include "code\__HELPERS\patrons.dm"
+#include "code\__HELPERS\piping_colors_lists.dm"
#include "code\__HELPERS\position_point_vector.dm"
#include "code\__HELPERS\priority_announce.dm"
#include "code\__HELPERS\pronouns.dm"
@@ -336,6 +345,7 @@
#include "code\_globalvars\lists\admin.dm"
#include "code\_globalvars\lists\ambience.dm"
#include "code\_globalvars\lists\client.dm"
+#include "code\_globalvars\lists\color.dm"
#include "code\_globalvars\lists\flavor_misc.dm"
#include "code\_globalvars\lists\icons.dm"
#include "code\_globalvars\lists\maintenance_loot.dm"
@@ -418,7 +428,6 @@
#include "code\controllers\configuration\entries\resources.dm"
#include "code\controllers\subsystem\achievements.dm"
#include "code\controllers\subsystem\acid.dm"
-#include "code\controllers\subsystem\adjacent_air.dm"
#include "code\controllers\subsystem\air.dm"
#include "code\controllers\subsystem\ambience.dm"
#include "code\controllers\subsystem\area_contents.dm"
@@ -430,7 +439,6 @@
#include "code\controllers\subsystem\autotransfer.dm"
#include "code\controllers\subsystem\ban_cache.dm"
#include "code\controllers\subsystem\blackbox.dm"
-#include "code\controllers\subsystem\callback.dm"
#include "code\controllers\subsystem\chat.dm"
#include "code\controllers\subsystem\circuit_component.dm"
#include "code\controllers\subsystem\combat_logging.dm"
@@ -667,6 +675,7 @@
#include "code\datums\components\explodable.dm"
#include "code\datums\components\force_move.dm"
#include "code\datums\components\forensics.dm"
+#include "code\datums\components\gas_leaker.dm"
#include "code\datums\components\gps.dm"
#include "code\datums\components\grillable.dm"
#include "code\datums\components\haircolor_clothes.dm"
@@ -850,6 +859,7 @@
#include "code\datums\elements\_element.dm"
#include "code\datums\elements\art.dm"
#include "code\datums\elements\atmos_requirements.dm"
+#include "code\datums\elements\atmos_sensitive.dm"
#include "code\datums\elements\basic_body_temp_sensitive.dm"
#include "code\datums\elements\bed_tucking.dm"
#include "code\datums\elements\bsa_blocker.dm"
@@ -886,6 +896,7 @@
#include "code\datums\elements\undertile.dm"
#include "code\datums\elements\update_icon_blocker.dm"
#include "code\datums\elements\update_icon_updates_onmob.dm"
+#include "code\datums\elements\volatile_gas_storage.dm"
#include "code\datums\elements\weather_listener.dm"
#include "code\datums\elements\decals\blood.dm"
#include "code\datums\elements\food\dunkable.dm"
@@ -1187,7 +1198,6 @@
#include "code\game\machinery\computer\arcade.dm"
#include "code\game\machinery\computer\arena.dm"
#include "code\game\machinery\computer\atmos_alert.dm"
-#include "code\game\machinery\computer\atmos_control.dm"
#include "code\game\machinery\computer\buildandrepair.dm"
#include "code\game\machinery\computer\camera.dm"
#include "code\game\machinery\computer\camera_advanced.dm"
@@ -1206,13 +1216,20 @@
#include "code\game\machinery\computer\station_alert.dm"
#include "code\game\machinery\computer\teleporter.dm"
#include "code\game\machinery\computer\warrant.dm"
+#include "code\game\machinery\computer\atmos_computers\_air_sensor.dm"
+#include "code\game\machinery\computer\atmos_computers\_atmos_control.dm"
+#include "code\game\machinery\computer\atmos_computers\_identifiers.dm"
+#include "code\game\machinery\computer\atmos_computers\air_sensors.dm"
+#include "code\game\machinery\computer\atmos_computers\atmos_controls.dm"
+#include "code\game\machinery\computer\atmos_computers\inlets.dm"
+#include "code\game\machinery\computer\atmos_computers\meters.dm"
+#include "code\game\machinery\computer\atmos_computers\outlets.dm"
#include "code\game\machinery\computer\prisoner\_prisoner.dm"
#include "code\game\machinery\computer\prisoner\gulag_teleporter.dm"
#include "code\game\machinery\computer\prisoner\management.dm"
#include "code\game\machinery\doors\airlock.dm"
#include "code\game\machinery\doors\airlock_electronics.dm"
#include "code\game\machinery\doors\airlock_types.dm"
-#include "code\game\machinery\doors\alarmlock.dm"
#include "code\game\machinery\doors\brigdoors.dm"
#include "code\game\machinery\doors\door.dm"
#include "code\game\machinery\doors\firedoor.dm"
@@ -1220,10 +1237,7 @@
#include "code\game\machinery\doors\shutters.dm"
#include "code\game\machinery\doors\unpowered.dm"
#include "code\game\machinery\doors\windowdoor.dm"
-#include "code\game\machinery\embedded_controller\access_controller.dm"
#include "code\game\machinery\embedded_controller\airlock_controller.dm"
-#include "code\game\machinery\embedded_controller\embedded_controller_base.dm"
-#include "code\game\machinery\embedded_controller\simple_vent_controller.dm"
#include "code\game\machinery\fabricators\autolathe.dm"
#include "code\game\machinery\fabricators\exosuit_fab.dm"
#include "code\game\machinery\fabricators\modular_fabricator.dm"
@@ -1842,6 +1856,7 @@
#include "code\modules\admin\verbs\deadsay.dm"
#include "code\modules\admin\verbs\debug.dm"
#include "code\modules\admin\verbs\diagnostics.dm"
+#include "code\modules\admin\verbs\fix_air.dm"
#include "code\modules\admin\verbs\forcecryo.dm"
#include "code\modules\admin\verbs\fps.dm"
#include "code\modules\admin\verbs\getlogs.dm"
@@ -2197,20 +2212,25 @@
#include "code\modules\asset_cache\spritesheet\batched\universal_icon.dm"
#include "code\modules\asset_cache\transports\asset_transport.dm"
#include "code\modules\asset_cache\transports\webroot_transport.dm"
-#include "code\modules\atmospherics\auxgm\breathing_classes.dm"
-#include "code\modules\atmospherics\auxgm\gas_types.dm"
#include "code\modules\atmospherics\environmental\LINDA_fire.dm"
#include "code\modules\atmospherics\environmental\LINDA_system.dm"
#include "code\modules\atmospherics\environmental\LINDA_turf_tile.dm"
-#include "code\modules\atmospherics\gasmixtures\auxgm.dm"
+#include "code\modules\atmospherics\gasmixtures\breathing_classes.dm"
#include "code\modules\atmospherics\gasmixtures\gas_mixture.dm"
+#include "code\modules\atmospherics\gasmixtures\gas_types.dm"
#include "code\modules\atmospherics\gasmixtures\immutable_mixtures.dm"
#include "code\modules\atmospherics\gasmixtures\reactions.dm"
-#include "code\modules\atmospherics\machinery\airalarm.dm"
#include "code\modules\atmospherics\machinery\atmosmachinery.dm"
#include "code\modules\atmospherics\machinery\datum_pipeline.dm"
+#include "code\modules\atmospherics\machinery\air_alarm\_airalarm.dm"
+#include "code\modules\atmospherics\machinery\air_alarm\air_alarm_circuit.dm"
+#include "code\modules\atmospherics\machinery\air_alarm\air_alarm_interact.dm"
+#include "code\modules\atmospherics\machinery\air_alarm\air_alarm_modes.dm"
+#include "code\modules\atmospherics\machinery\air_alarm\air_alarm_thresholds.dm"
+#include "code\modules\atmospherics\machinery\air_alarm\air_alarm_variants.dm"
#include "code\modules\atmospherics\machinery\components\components_base.dm"
#include "code\modules\atmospherics\machinery\components\mapping.dm"
+#include "code\modules\atmospherics\machinery\components\tank.dm"
#include "code\modules\atmospherics\machinery\components\binary_devices\binary_devices.dm"
#include "code\modules\atmospherics\machinery\components\binary_devices\circulator.dm"
#include "code\modules\atmospherics\machinery\components\binary_devices\dp_vent_pump.dm"
@@ -2224,25 +2244,25 @@
#include "code\modules\atmospherics\machinery\components\trinary_devices\filter.dm"
#include "code\modules\atmospherics\machinery\components\trinary_devices\mixer.dm"
#include "code\modules\atmospherics\machinery\components\trinary_devices\trinary_devices.dm"
+#include "code\modules\atmospherics\machinery\components\unary_devices\airlock_pump.dm"
#include "code\modules\atmospherics\machinery\components\unary_devices\cryo.dm"
#include "code\modules\atmospherics\machinery\components\unary_devices\heat_exchanger.dm"
#include "code\modules\atmospherics\machinery\components\unary_devices\outlet_injector.dm"
#include "code\modules\atmospherics\machinery\components\unary_devices\passive_vent.dm"
#include "code\modules\atmospherics\machinery\components\unary_devices\portables_connector.dm"
-#include "code\modules\atmospherics\machinery\components\unary_devices\tank.dm"
#include "code\modules\atmospherics\machinery\components\unary_devices\thermomachine.dm"
#include "code\modules\atmospherics\machinery\components\unary_devices\unary_devices.dm"
#include "code\modules\atmospherics\machinery\components\unary_devices\vent_pump.dm"
#include "code\modules\atmospherics\machinery\components\unary_devices\vent_scrubber.dm"
#include "code\modules\atmospherics\machinery\other\meter.dm"
#include "code\modules\atmospherics\machinery\other\miner.dm"
+#include "code\modules\atmospherics\machinery\pipes\bridge_pipe.dm"
+#include "code\modules\atmospherics\machinery\pipes\color_adapter.dm"
#include "code\modules\atmospherics\machinery\pipes\layermanifold.dm"
-#include "code\modules\atmospherics\machinery\pipes\manifold.dm"
-#include "code\modules\atmospherics\machinery\pipes\manifold4w.dm"
#include "code\modules\atmospherics\machinery\pipes\mapping.dm"
#include "code\modules\atmospherics\machinery\pipes\multiz.dm"
#include "code\modules\atmospherics\machinery\pipes\pipes.dm"
-#include "code\modules\atmospherics\machinery\pipes\simple.dm"
+#include "code\modules\atmospherics\machinery\pipes\smart.dm"
#include "code\modules\atmospherics\machinery\pipes\heat_exchange\he_pipes.dm"
#include "code\modules\atmospherics\machinery\pipes\heat_exchange\junction.dm"
#include "code\modules\atmospherics\machinery\pipes\heat_exchange\manifold.dm"
diff --git a/code/__DEFINES/_atoms.dm b/code/__DEFINES/_atoms.dm
new file mode 100644
index 0000000000000..abc4d805170c4
--- /dev/null
+++ b/code/__DEFINES/_atoms.dm
@@ -0,0 +1,12 @@
+#define BAD_INIT_QDEL_BEFORE 1
+#define BAD_INIT_DIDNT_INIT 2
+#define BAD_INIT_SLEPT 4
+#define BAD_INIT_NO_HINT 8
+
+#ifdef PROFILE_MAPLOAD_INIT_ATOM
+#define PROFILE_INIT_ATOM_BEGIN(...) var/__profile_stat_time = TICK_USAGE
+#define PROFILE_INIT_ATOM_END(atom) mapload_init_times[##atom.type] += TICK_USAGE_TO_MS(__profile_stat_time)
+#else
+#define PROFILE_INIT_ATOM_BEGIN(...)
+#define PROFILE_INIT_ATOM_END(...)
+#endif
diff --git a/code/__DEFINES/alerts.dm b/code/__DEFINES/alerts.dm
new file mode 100644
index 0000000000000..67fab4471ab38
--- /dev/null
+++ b/code/__DEFINES/alerts.dm
@@ -0,0 +1,17 @@
+/** Atmos related */
+#define ALERT_TOO_MUCH_OXYGEN "too_much_oxy"
+#define ALERT_NOT_ENOUGH_OXYGEN "not_enough_oxy"
+
+#define ALERT_TOO_MUCH_PLASMA "too_much_plas"
+#define ALERT_NOT_ENOUGH_PLASMA "not_enough_plas"
+
+#define ALERT_TOO_MUCH_CO2 "too_much_co2"
+#define ALERT_NOT_ENOUGH_CO2 "not_enough_co2"
+
+#define ALERT_TOO_MUCH_N2O "too_much_n2o"
+#define ALERT_NOT_ENOUGH_N2O "not_enough_n2o"
+
+#define ALERT_TOO_MUCH_NITRO "too_much_nitro"
+#define ALERT_NOT_ENOUGH_NITRO "not_enough_nitro"
+
+#define ALERT_NOT_ENOUGH_WATER "not_enough_water"
diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm
deleted file mode 100644
index c5caf46379798..0000000000000
--- a/code/__DEFINES/atmospherics.dm
+++ /dev/null
@@ -1,404 +0,0 @@
-//ATMOS
-//stuff you should probably leave well alone!
-/// kPa*L/(K*mol)
-#define R_IDEAL_GAS_EQUATION 8.31
-/// kPa
-#define ONE_ATMOSPHERE 101.325
-/// -270.3degC
-#define TCMB 2.7
-/// -48.15degC
-#define TCRYO 225
-/// 0degC
-#define T0C 273.15
-/// 20degC
-#define T20C 293.15
-/// -14C - Temperature used for kitchen cold room, medical freezer, etc.
-#define COLD_ROOM_TEMP 259.15
-
-///moles in a 2.5 m^3 cell at 101.325 Pa and 20 degC (103 or so)
-#define MOLES_CELLSTANDARD (ONE_ATMOSPHERE*CELL_VOLUME/(T20C*R_IDEAL_GAS_EQUATION))
-///compared against for superconductivity
-#define M_CELL_WITH_RATIO (MOLES_CELLSTANDARD * 0.005)
-/// percentage of oxygen in a normal mixture of air
-#define O2STANDARD 0.21
-/// same but for nitrogen
-#define N2STANDARD 0.79
-/// O2 standard value (21%)
-#define MOLES_O2STANDARD (MOLES_CELLSTANDARD*O2STANDARD)
-/// N2 standard value (79%)
-#define MOLES_N2STANDARD (MOLES_CELLSTANDARD*N2STANDARD)
-/// liters in a cell
-#define CELL_VOLUME 2500
-
-#define BREATH_VOLUME 0.5 //! liters in a normal breath
-#define BREATH_PERCENTAGE (BREATH_VOLUME/CELL_VOLUME) //! Amount of air to take a from a tile
-
-//EXCITED GROUPS
-#define EXCITED_GROUP_BREAKDOWN_CYCLES 3 //! number of FULL air controller ticks before an excited group breaks down (averages gas contents across turfs)
-#define EXCITED_GROUP_DISMANTLE_CYCLES 15 //! number of FULL air controller ticks before an excited group dismantles and removes its turfs from active
-#define MINIMUM_AIR_RATIO_TO_SUSPEND 0.1 //! Ratio of air that must move to/from a tile to reset group processing
-#define MINIMUM_AIR_RATIO_TO_MOVE 0.05 //! Minimum ratio of air that must move to/from a tile
-#define MINIMUM_AIR_TO_SUSPEND (MOLES_CELLSTANDARD*MINIMUM_AIR_RATIO_TO_SUSPEND) //! Minimum amount of air that has to move before a group processing can be suspended
-#define MINIMUM_MOLES_DELTA_TO_MOVE (MOLES_CELLSTANDARD*MINIMUM_AIR_RATIO_TO_MOVE) //! Either this must be active or MINIMUM_TEMPERATURE_TO_MOVE
-#define MINIMUM_TEMPERATURE_TO_MOVE (T20C+100) //! Either this must be active or MINIMUM_MOLES_DELTA_TO_MOVE
-#define MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND 4 //! Minimum temperature difference before group processing is suspended
-#define MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER 1 //! Minimum temperature difference before the gas temperatures are just set to be equal
-#define MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION (T20C+10)
-#define MINIMUM_TEMPERATURE_START_SUPERCONDUCTION (T20C+200)
-
-//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 WALL_HEAT_TRANSFER_COEFFICIENT 0.0
-#define OPEN_HEAT_TRANSFER_COEFFICIENT 0.4
-#define WINDOW_HEAT_TRANSFER_COEFFICIENT 0.1 //a hack for now
-#define HEAT_CAPACITY_VACUUM 7000 //a hack to help make vacuums "cold", sacrificing realism for gameplay
-
-//FIRE
-#define FIRE_MINIMUM_TEMPERATURE_TO_SPREAD (150+T0C)
-#define FIRE_MINIMUM_TEMPERATURE_TO_EXIST (100+T0C)
-#define FIRE_SPREAD_RADIOSITY_SCALE 0.85
-#define FIRE_GROWTH_RATE 40000 //For small fires
-#define PLASMA_MINIMUM_BURN_TEMPERATURE (100+T0C)
-#define PLASMA_UPPER_TEMPERATURE (1370+T0C)
-#define PLASMA_OXYGEN_FULLBURN 10
-
-//GASES
-#define MIN_TOXIC_GAS_DAMAGE 1
-#define MAX_TOXIC_GAS_DAMAGE 10
-#define MOLES_GAS_VISIBLE 0.25 //! Moles in a standard cell after which gases are visible
-
-#define FACTOR_GAS_VISIBLE_MAX 20 //! moles_visible * FACTOR_GAS_VISIBLE_MAX = Moles after which gas is at maximum visibility
-#define MOLES_GAS_VISIBLE_STEP 0.25 //! Mole step for alpha updates. This means alpha can update at 0.25, 0.5, 0.75 and so on
-
-//REACTIONS
-//return values for reactions (bitflags)
-#define NO_REACTION 0
-#define REACTING 1
-#define STOP_REACTIONS 2
-
-// Pressure limits.
-/// This determins at what pressure the ultra-high pressure red icon is displayed. (This one is set as a constant)
-#define HAZARD_HIGH_PRESSURE 550
-/// This determins when the orange pressure icon is displayed (it is 0.7 * HAZARD_HIGH_PRESSURE)
-#define WARNING_HIGH_PRESSURE 325
-/// This is when the gray low pressure icon is displayed. (it is 2.5 * HAZARD_LOW_PRESSURE)
-#define WARNING_LOW_PRESSURE 50
-/// This is when the black ultra-low pressure icon is displayed. (This one is set as a constant)
-#define HAZARD_LOW_PRESSURE 20
-
-/// This is used in handle_temperature_damage() for humans, and in reagents that affect body temperature. Temperature damage is multiplied by this amount.
-#define TEMPERATURE_DAMAGE_COEFFICIENT 1.5
-
-/// The natural temperature for a body
-#define BODYTEMP_NORMAL 310.15
-/// This is the divisor which handles how much of the temperature difference between the current body temperature and 310.15K (optimal temperature) humans auto-regenerate each tick. The higher the number, the slower the recovery. This is applied each tick, so long as the mob is alive.
-#define BODYTEMP_AUTORECOVERY_DIVISOR 14
-/// Minimum amount of kelvin moved toward 310K per tick. So long as abs(310.15 - bodytemp) is more than 50.
-#define BODYTEMP_AUTORECOVERY_MINIMUM 6
-///Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is lower than their body temperature. Make it lower to lose bodytemp faster.
-#define BODYTEMP_COLD_DIVISOR 15
-/// Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is higher than their body temperature. Make it lower to gain bodytemp faster.
-#define BODYTEMP_HEAT_DIVISOR 15
-/// The maximum number of degrees that your body can cool in 1 tick, due to the environment, when in a cold area.
-#define BODYTEMP_COOLING_MAX -30
-/// The maximum number of degrees that your body can heat up in 1 tick, due to the environment, when in a hot area.
-#define BODYTEMP_HEATING_MAX 30
-
-/// The body temperature limit the human body can take before it starts taking damage from heat.
-/// This also affects how fast the body normalises it's temperature when hot.
-/// 340k is about 66c, and rather high for a human.
-#define BODYTEMP_HEAT_DAMAGE_LIMIT (BODYTEMP_NORMAL + 30)
-/// The body temperature limit the human body can take before it starts taking damage from cold.
-/// This also affects how fast the body normalises it's temperature when cold.
-/// 270k is about -3c, that is below freezing and would hurt over time.
-#define BODYTEMP_COLD_DAMAGE_LIMIT (BODYTEMP_NORMAL - 40)
-/// The body temperature limit the human body can take before it will take wound damage.
-#define BODYTEMP_HEAT_WOUND_LIMIT (BODYTEMP_NORMAL + 90) // 400.5 k
-
-// Body temperature warning icons
-/// The temperature the red icon is displayed.
-#define BODYTEMP_HEAT_WARNING_3 (BODYTEMP_HEAT_DAMAGE_LIMIT + 360) //+700k
-/// The temperature the orange icon is displayed.
-#define BODYTEMP_HEAT_WARNING_2 (BODYTEMP_HEAT_DAMAGE_LIMIT + 120) //460K
-/// The temperature the yellow icon is displayed.
-#define BODYTEMP_HEAT_WARNING_1 (BODYTEMP_HEAT_DAMAGE_LIMIT) //340K
-/// The temperature the light green icon is displayed.
-#define BODYTEMP_COLD_WARNING_1 (BODYTEMP_COLD_DAMAGE_LIMIT) //270k
-/// The temperature the cyan icon is displayed.
-#define BODYTEMP_COLD_WARNING_2 (BODYTEMP_COLD_DAMAGE_LIMIT - 70) //200k
-/// The temperature the blue icon is displayed.
-#define BODYTEMP_COLD_WARNING_3 (BODYTEMP_COLD_DAMAGE_LIMIT - 150) //120k
-
-/// what min_cold_protection_temperature is set to for space-helmet quality headwear. MUST NOT BE 0.
-#define SPACE_HELM_MIN_TEMP_PROTECT 2.0
-/// Thermal insulation works both ways /Malkevin
-#define SPACE_HELM_MAX_TEMP_PROTECT 1500
-/// what min_cold_protection_temperature is set to for space-suit quality jumpsuits or suits. MUST NOT BE 0.
-#define SPACE_SUIT_MIN_TEMP_PROTECT 2.0
-/// The min cold protection of a space suit without the heater active
-#define SPACE_SUIT_MIN_TEMP_PROTECT_OFF 72
-#define SPACE_SUIT_MAX_TEMP_PROTECT 1500
-
-#define FIRE_SUIT_MIN_TEMP_PROTECT 60 //! Cold protection for firesuits
-#define FIRE_SUIT_MAX_TEMP_PROTECT 30000 //! what max_heat_protection_temperature is set to for firesuit quality suits. MUST NOT BE 0.
-#define FIRE_HELM_MIN_TEMP_PROTECT 60 //! Cold protection for fire helmets
-#define FIRE_HELM_MAX_TEMP_PROTECT 30000 //! for fire helmet quality items (red and white hardhats)
-
-#define FIRE_IMMUNITY_MAX_TEMP_PROTECT 35000 //! what max_heat_protection_temperature is set to for firesuit quality suits and helmets. MUST NOT BE 0.
-
-//Emergency skinsuits
-#define EMERGENCY_HELM_MIN_TEMP_PROTECT 2.0 //The helmet is pressurized with air from the oxygen tank. If they don't take damage from that they won't take damage here
-#define EMERGENCY_SUIT_MIN_TEMP_PROTECT 237 //This is the approximate average temperature of Mt. Everest in the winter
-
-#define HELMET_MIN_TEMP_PROTECT 160 //For normal helmets
-#define HELMET_MAX_TEMP_PROTECT 600 //For normal helmets
-#define ARMOR_MIN_TEMP_PROTECT 160 //For armor
-#define ARMOR_MAX_TEMP_PROTECT 600 //For armor
-
-#define GLOVES_MIN_TEMP_PROTECT 2.0 //For some gloves (black and)
-#define GLOVES_MAX_TEMP_PROTECT 1500 //For some gloves
-#define SHOES_MIN_TEMP_PROTECT 2.0 //For gloves
-#define SHOES_MAX_TEMP_PROTECT 1500 //For gloves
-
-#define PRESSURE_DAMAGE_COEFFICIENT 4 //! The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT, with the maximum of MAX_PRESSURE_DAMAGE
-#define MAX_HIGH_PRESSURE_DAMAGE 4
-#define LOW_PRESSURE_DAMAGE 4 //! The amount of damage someone takes when in a low pressure area (The pressure threshold is so low that it doesn't make sense to do any calculations, so it just applies this flat value).
-
-#define COLD_SLOWDOWN_FACTOR 20 //! Humans are slowed by the difference between bodytemp and BODYTEMP_COLD_DAMAGE_LIMIT divided by this
-
-//PIPES
-//Atmos pipe limits
-/// (kPa) What pressure pumps and powered equipment max out at.
-#define MAX_OUTPUT_PRESSURE 4500
-/// (L/s) Maximum speed powered equipment can work at.
-#define MAX_TRANSFER_RATE 200
-/// How many percent of the contents that an overclocked volume pumps leak into the air
-#define VOLUME_PUMP_LEAK_AMOUNT 0.1
-
-//used for device_type vars
-#define UNARY 1
-#define BINARY 2
-#define TRINARY 3
-#define QUATERNARY 4
-
-//TANKS
-#define TANK_MELT_TEMPERATURE 1000000 //! temperature in kelvins at which a tank will start to melt
-#define TANK_LEAK_PRESSURE (30.*ONE_ATMOSPHERE) //! temperature in kelvins at which a tank starts leaking
-#define TANK_RUPTURE_PRESSURE (35.*ONE_ATMOSPHERE) //! temperature in kelvins at which a tank spills all contents into atmosphere
-#define TANK_FRAGMENT_PRESSURE (40.*ONE_ATMOSPHERE) //! temperature in kelvins at which a tank creates a boom 3x3 base explosion
-#define TANK_FRAGMENT_SCALE (6.*ONE_ATMOSPHERE) //! +1 for each SCALE kPa aboe threshold
-#define TANK_MAX_RELEASE_PRESSURE (ONE_ATMOSPHERE*3)
-#define TANK_MIN_RELEASE_PRESSURE 0
-#define TANK_DEFAULT_RELEASE_PRESSURE 17
-
-//CANATMOSPASS
-#define ATMOS_PASS_YES 1
-#define ATMOS_PASS_NO 0
-#define ATMOS_PASS_PROC -1 //ask CanAtmosPass()
-#define ATMOS_PASS_DENSITY -2 //just check density
-
-#define CANATMOSPASS(A, O) ( A.CanAtmosPass == ATMOS_PASS_PROC ? A.CanAtmosPass(O) : ( A.CanAtmosPass == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPass ) )
-#define CANVERTICALATMOSPASS(A, O) ( A.CanAtmosPassVertical == ATMOS_PASS_PROC ? A.CanAtmosPass(O, TRUE) : ( A.CanAtmosPassVertical == ATMOS_PASS_DENSITY ? !A.density : A.CanAtmosPassVertical ) )
-
-//OPEN TURF ATMOS
-/// the default air mix that open turfs spawn
-#define OPENTURF_DEFAULT_ATMOS "o2=22;n2=82;TEMP=293.15"
-#define OPENTURF_LOW_PRESSURE "o2=14;n2=30;TEMP=293.15"
-/// -193,15°C telecommunications. also used for xenobiology slime killrooms
-#define TCOMMS_ATMOS "n2=100;TEMP=80"
-/// space
-#define AIRLESS_ATMOS "TEMP=2.7"
-/// -93.15°C snow and ice turfs
-#define FROZEN_ATMOS "o2=22;n2=82;TEMP=180"
-/// -14°C kitchen coldroom, just might lose your tail; higher amount of mol to reach about 101.3 kpA
-#define KITCHEN_COLDROOM_ATMOS "o2=26;n2=97;TEMP=[COLD_ROOM_TEMP]"
-/// used in the holodeck burn test program
-#define BURNMIX_ATMOS "o2=100;plasma=200;TEMP=370" //used in the holodeck burn test program
-
-//ATMOSPHERICS DEPARTMENT GAS TANK TURFS
-#define ATMOS_TANK_N2O "n2o=6000;TEMP=293.15"
-#define ATMOS_TANK_CO2 "co2=50000;TEMP=293.15"
-#define ATMOS_TANK_PLASMA "plasma=70000;TEMP=293.15"
-#define ATMOS_TANK_O2 "o2=100000;TEMP=293.15"
-#define ATMOS_TANK_N2 "n2=100000;TEMP=293.15"
-#define ATMOS_TANK_AIRMIX "o2=2644;n2=10580;TEMP=293.15"
-
-//LAVALAND
-#define MAXIMUM_LAVALAND_EQUIPMENT_EFFECT_PRESSURE 90 //! what pressure you have to be under to increase the effect of equipment meant for lavaland
-#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=5;co2=13;TEMP=300"
-
-//ATMOS MIX IDS
-//Lavaland used to live here. That was a mistake.
-
-//ATMOSIA GAS MONITOR TAGS
-#define ATMOS_GAS_MONITOR_INPUT_O2 "o2_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_O2 "o2_out"
-#define ATMOS_GAS_MONITOR_SENSOR_O2 "o2_sensor"
-
-#define ATMOS_GAS_MONITOR_INPUT_PLASMA "plasma_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_PLASMA "plasma_out"
-#define ATMOS_GAS_MONITOR_SENSOR_PLASMA "plasma_sensor"
-
-#define ATMOS_GAS_MONITOR_INPUT_AIR "air_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_AIR "air_out"
-#define ATMOS_GAS_MONITOR_SENSOR_AIR "air_sensor"
-
-#define ATMOS_GAS_MONITOR_INPUT_MIX "mix_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_MIX "mix_out"
-#define ATMOS_GAS_MONITOR_SENSOR_MIX "mix_sensor"
-
-#define ATMOS_GAS_MONITOR_INPUT_N2O "n2o_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_N2O "n2o_out"
-#define ATMOS_GAS_MONITOR_SENSOR_N2O "n2o_sensor"
-
-#define ATMOS_GAS_MONITOR_INPUT_N2 "n2_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_N2 "n2_out"
-#define ATMOS_GAS_MONITOR_SENSOR_N2 "n2_sensor"
-
-#define ATMOS_GAS_MONITOR_INPUT_CO2 "co2_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_CO2 "co2_out"
-#define ATMOS_GAS_MONITOR_SENSOR_CO2 "co2_sensor"
-
-#define ATMOS_GAS_MONITOR_INPUT_INCINERATOR "incinerator_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_INCINERATOR "incinerator_out"
-#define ATMOS_GAS_MONITOR_SENSOR_INCINERATOR "incinerator_sensor"
-
-#define ATMOS_GAS_MONITOR_INPUT_TOXINS_LAB "toxinslab_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_TOXINS_LAB "toxinslab_out"
-#define ATMOS_GAS_MONITOR_SENSOR_TOXINS_LAB "toxinslab_sensor"
-
-#define ATMOS_GAS_MONITOR_LOOP_DISTRIBUTION "distro-loop_meter"
-#define ATMOS_GAS_MONITOR_LOOP_ATMOS_WASTE "atmos-waste_loop_meter"
-
-#define ATMOS_GAS_MONITOR_WASTE_ENGINE "engine-waste_out"
-#define ATMOS_GAS_MONITOR_WASTE_ATMOS "atmos-waste_out"
-
-#define ATMOS_GAS_MONITOR_INPUT_SM "sm_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_SM "sm_out"
-#define ATMOS_GAS_MONITOR_SENSOR_SM "sm_sense"
-
-#define ATMOS_GAS_MONITOR_INPUT_SM_WASTE "sm_waste_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_SM_WASTE "sm_waste_out"
-#define ATMOS_GAS_MONITOR_SENSOR_SM_WASTE "sm_waste_sense"
-
-#define ATMOS_GAS_MONITOR_INPUT_TOXINS_WASTE "toxins_waste_in"
-#define ATMOS_GAS_MONITOR_OUTPUT_TOXINS_WASTE "toxins_waste_out"
-#define ATMOS_GAS_MONITOR_SENSOR_TOXINS_WASTE "toxins_waste_sense"
-
-//AIRLOCK CONTROLLER TAGS
-
-//RnD toxins burn chamber
-#define INCINERATOR_TOXMIX_IGNITER "toxmix_igniter"
-#define INCINERATOR_TOXMIX_VENT "toxmix_vent"
-#define INCINERATOR_TOXMIX_DP_VENTPUMP "toxmix_airlock_pump"
-#define INCINERATOR_TOXMIX_AIRLOCK_SENSOR "toxmix_airlock_sensor"
-#define INCINERATOR_TOXMIX_AIRLOCK_CONTROLLER "toxmix_airlock_controller"
-#define INCINERATOR_TOXMIX_AIRLOCK_INTERIOR "toxmix_airlock_interior"
-#define INCINERATOR_TOXMIX_AIRLOCK_EXTERIOR "toxmix_airlock_exterior"
-
-//Atmospherics/maintenance incinerator
-#define INCINERATOR_ATMOS_IGNITER "atmos_incinerator_igniter"
-#define INCINERATOR_ATMOS_MAINVENT "atmos_incinerator_mainvent"
-#define INCINERATOR_ATMOS_AUXVENT "atmos_incinerator_auxvent"
-#define INCINERATOR_ATMOS_DP_VENTPUMP "atmos_incinerator_airlock_pump"
-#define INCINERATOR_ATMOS_AIRLOCK_SENSOR "atmos_incinerator_airlock_sensor"
-#define INCINERATOR_ATMOS_AIRLOCK_CONTROLLER "atmos_incinerator_airlock_controller"
-#define INCINERATOR_ATMOS_AIRLOCK_INTERIOR "atmos_incinerator_airlock_interior"
-#define INCINERATOR_ATMOS_AIRLOCK_EXTERIOR "atmos_incinerator_airlock_exterior"
-
-//Syndicate lavaland base incinerator (lavaland_surface_syndicate_base1.dmm)
-#define INCINERATOR_SYNDICATELAVA_IGNITER "syndicatelava_igniter"
-#define INCINERATOR_SYNDICATELAVA_MAINVENT "syndicatelava_mainvent"
-#define INCINERATOR_SYNDICATELAVA_AUXVENT "syndicatelava_auxvent"
-#define INCINERATOR_SYNDICATELAVA_DP_VENTPUMP "syndicatelava_airlock_pump"
-#define INCINERATOR_SYNDICATELAVA_AIRLOCK_SENSOR "syndicatelava_airlock_sensor"
-#define INCINERATOR_SYNDICATELAVA_AIRLOCK_CONTROLLER "syndicatelava_airlock_controller"
-#define INCINERATOR_SYNDICATELAVA_AIRLOCK_INTERIOR "syndicatelava_airlock_interior"
-#define INCINERATOR_SYNDICATELAVA_AIRLOCK_EXTERIOR "syndicatelava_airlock_exterior"
-
-//MULTIPIPES
-//IF YOU EVER CHANGE THESE CHANGE SPRITES TO MATCH.
-#define PIPING_LAYER_MIN 1
-#define PIPING_LAYER_MAX 5
-#define PIPING_LAYER_DEFAULT 3
-#define PIPING_LAYER_P_X 5
-#define PIPING_LAYER_P_Y 5
-#define PIPING_LAYER_LCHANGE 0.05
-
-#define PIPING_ALL_LAYER (1<<0) //! intended to connect with all layers, check for all instead of just one.
-#define PIPING_ONE_PER_TURF (1<<1) //! can only be built if nothing else with this flag is on the tile already.
-#define PIPING_DEFAULT_LAYER_ONLY (1<<2) //! can only exist at PIPING_LAYER_DEFAULT
-#define PIPING_CARDINAL_AUTONORMALIZE (1<<3) //! north/south east/west doesn't matter, auto normalize on build.
-
-// Gas defines because i hate typepaths
-#define GAS_O2 "o2"
-#define GAS_N2 "n2"
-#define GAS_CO2 "co2"
-#define GAS_PLASMA "plasma"
-#define GAS_H2O "water_vapor"
-#define GAS_HYPERNOB "nob"
-#define GAS_NITROUS "n2o"
-#define GAS_NITRYL "no2"
-#define GAS_TRITIUM "tritium"
-#define GAS_BZ "bz"
-#define GAS_STIMULUM "stim"
-#define GAS_PLUOXIUM "pluox"
-
-#define GAS_FLAG_DANGEROUS (1<<0)
-#define GAS_FLAG_BREATH_PROC (1<<1)
-
-//HELPERS
-#define PIPING_LAYER_SHIFT(T, PipingLayer) \
- if(T.dir & (NORTH|SOUTH)) { \
- T.pixel_x = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_X;\
- } \
- if(T.dir & (EAST|WEST)) { \
- T.pixel_y = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_Y;\
- }
-
-#define PIPING_FORWARD_SHIFT(T, PipingLayer, more_shift) \
- if(T.dir & (NORTH|SOUTH)) { \
- T.pixel_y += more_shift * (PipingLayer - PIPING_LAYER_DEFAULT);\
- } \
- if(T.dir & (EAST|WEST)) { \
- T.pixel_x += more_shift * (PipingLayer - PIPING_LAYER_DEFAULT);\
- }
-
-#define PIPING_LAYER_DOUBLE_SHIFT(T, PipingLayer) \
- T.pixel_x = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_X;\
- T.pixel_y = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_Y;
-
-#ifdef TESTING
-GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
-#define CALCULATE_ADJACENT_TURFS(T) if (SSadjacent_air.queue[T]) { GLOB.atmos_adjacent_savings[1] += 1 } else { GLOB.atmos_adjacent_savings[2] += 1; SSadjacent_air.queue[T] = 1 }
-#else
-#define CALCULATE_ADJACENT_TURFS(T) SSadjacent_air.queue[T] = 1
-#endif
-
-GLOBAL_LIST_INIT(pipe_paint_colors, sort_list(list(
- "amethyst" = rgb(130,43,255),
- "blue" = rgb(0,0,255),
- "brown" = rgb(178,100,56),
- "cyan" = rgb(0,255,249),
- "dark" = rgb(69,69,69),
- "green" = rgb(30,255,0),
- "grey" = rgb(255,255,255),
- "orange" = rgb(255,129,25),
- "purple" = rgb(128,0,182),
- "red" = rgb(255,0,0),
- "violet" = rgb(64,0,128),
- "yellow" = rgb(255,198,0)
-)))
-
-//PIPENET UPDATE STATUS
-#define PIPENET_UPDATE_STATUS_DORMANT 0
-#define PIPENET_UPDATE_STATUS_REACT_NEEDED 1
-#define PIPENET_UPDATE_STATUS_RECONCILE_NEEDED 2
-
-// GAS MIXTURE STUFF (used to be in code/modules/atmospherics/gasmixtures/gas_mixture.dm)
-#define MINIMUM_HEAT_CAPACITY 0.0003
-#define MINIMUM_MOLE_COUNT 0.01
-/*I feel the need to document what happens here. Basically this is used to catch most rounding errors, however it's previous value made it so that
-once gases got hot enough, most procedures wouldnt occur due to the fact that the mole counts would get rounded away. Thus, we lowered it a few orders of magnititude */
-#define QUANTIZE(variable) (round(variable,0.0000001))
diff --git a/code/__DEFINES/atmospherics/atmos_core.dm b/code/__DEFINES/atmospherics/atmos_core.dm
new file mode 100644
index 0000000000000..439dcaf89d459
--- /dev/null
+++ b/code/__DEFINES/atmospherics/atmos_core.dm
@@ -0,0 +1,297 @@
+//LISTMOS
+//indices of values in gas lists.
+///Amount of total moles in said gas mixture
+#define MOLES 1
+///Archived version of MOLES
+#define ARCHIVE 2
+///All gas related variables
+#define GAS_META 3
+///Gas specific heat per mole
+#define META_GAS_SPECIFIC_HEAT 1
+///Name of the gas
+#define META_GAS_NAME 2
+///Amount of moles required of the gas to be visible
+#define META_GAS_MOLES_VISIBLE 3
+///Overlay path of the gas, also setup the alpha based on the amount
+#define META_GAS_OVERLAY 4
+///Let the air alarm know if the gas is dangerous
+#define META_GAS_DANGER 5
+///Id of the gas for quick access
+#define META_GAS_ID 6
+///Short description of the gas.
+#define META_GAS_DESC 7
+///Power of the gas when used in the current iteration of fusion
+#define META_GAS_FUSION_POWER 8
+///Defines the alert that should jump out if the quantity of a gas affects to a point it's too much or not enough
+#define META_GAS_BREATH_ALERT_INFO 9
+///Defines the reagents applied on breathing the gas
+#define META_GAS_BREATH_REAGENT 10
+///Defines the gas to which this gas is a result of breathing
+#define META_GAS_BREATH_RESULTS 11
+///Reagents applied when the gas passes its dangerous threshold
+#define META_GAS_BREATH_REAGENT_DANGEROUS 12
+
+
+//ATMOS
+//stuff you should probably leave well alone!
+/// kPa*L/(K*mol)
+#define R_IDEAL_GAS_EQUATION 8.31
+/// kPa
+#define ONE_ATMOSPHERE 101.325
+/// -270.3degC
+#define TCMB 2.7
+/// -48.15degC
+#define TCRYO 225
+/// 0degC
+#define T0C 273.15
+/// 20degC
+#define T20C 293.15
+/// -14C - Temperature used for kitchen cold room, medical freezer, etc.
+#define COLD_ROOM_TEMP 259.15
+
+/**
+ *I feel the need to document what happens here. Basically this is used
+ *catch rounding errors, and make gas go away in small portions.
+ *People have raised it to higher levels in the past, do not do this. Consider this number a soft limit
+ *If you're making gasmixtures that have unexpected behavior related to this value, you're doing something wrong.
+ *
+ *On an unrelated note this may cause a bug that creates negative gas, related to round(). When it has a second arg it will round up.
+ *So for instance round(0.5, 1) == 1. I've hardcoded a fix for this into share, by forcing the garbage collect.
+ *Any other attempts to fix it just killed atmos. I leave this to a greater man then I
+ */
+/// The minimum heat capacity of a gas
+#define MINIMUM_HEAT_CAPACITY 0.0003
+/// Minimum mole count of a gas
+#define MINIMUM_MOLE_COUNT 0.01
+/// Molar accuracy to round to
+#define MOLAR_ACCURACY 1E-4
+/// Types of gases (based on gaslist_cache)
+#define GAS_TYPE_COUNT GLOB.gaslist_cache.len
+/// Maximum error caused by QUANTIZE when removing gas (roughly, in reality around 2 * MOLAR_ACCURACY less)
+#define MAXIMUM_ERROR_GAS_REMOVAL (MOLAR_ACCURACY * GAS_TYPE_COUNT)
+
+/// Moles in a standard cell after which gases are visible
+#define MOLES_GAS_VISIBLE 0.25
+
+/// moles_visible * FACTOR_GAS_VISIBLE_MAX = Moles after which gas is at maximum visibility
+#define FACTOR_GAS_VISIBLE_MAX 20
+/// Mole step for alpha updates. This means alpha can update at 0.25, 0.5, 0.75 and so on
+#define MOLES_GAS_VISIBLE_STEP 0.25
+/// The total visible states
+#define TOTAL_VISIBLE_STATES (FACTOR_GAS_VISIBLE_MAX * (1 / MOLES_GAS_VISIBLE_STEP))
+
+//REACTIONS
+//return values for reactions (bitflags)
+///The gas mixture is not reacting
+#define NO_REACTION 0
+///The gas mixture is reacting
+#define REACTING 1
+///The gas mixture is able to stop all reactions
+#define STOP_REACTIONS 2
+
+
+//EXCITED GROUPS
+/**
+ * Some further context on breakdown. Unlike dismantle, the breakdown ticker doesn't reset itself when a tile is added
+ * This is because we cannot expect maps to have small spaces, so we need to even ourselves out often
+ * We do this to avoid equalizing a large space in one tick, with some significant amount of say heat diff
+ * This way large areas don't suddenly all become cold at once, it acts more like a wave
+ *
+ * Because of this and the behavior of share(), the breakdown cycles value can be tweaked directly to effect how fast we want gas to move
+ */
+/// number of FULL air controller ticks before an excited group breaks down (averages gas contents across turfs)
+#define EXCITED_GROUP_BREAKDOWN_CYCLES 4
+/// number of FULL air controller ticks before an excited group dismantles and removes its turfs from active
+#define EXCITED_GROUP_DISMANTLE_CYCLES (EXCITED_GROUP_BREAKDOWN_CYCLES * 2) + 1 //Reset after 2 breakdowns
+/// Ratio of air that must move to/from a tile to reset group processing
+#define MINIMUM_AIR_RATIO_TO_SUSPEND 0.1
+/// Minimum ratio of air that must move to/from a tile
+#define MINIMUM_AIR_RATIO_TO_MOVE 0.001
+/// Minimum amount of air that has to move before a group processing can be suspended (Round about 10)
+#define MINIMUM_AIR_TO_SUSPEND (MOLES_CELLSTANDARD*MINIMUM_AIR_RATIO_TO_SUSPEND)
+/// Either this must be active (round about 0.1) //Might need to raise this a tad to better support space leaks. we'll see
+#define MINIMUM_MOLES_DELTA_TO_MOVE (MOLES_CELLSTANDARD*MINIMUM_AIR_RATIO_TO_MOVE)
+/// or this (or both, obviously)
+#define MINIMUM_TEMPERATURE_TO_MOVE (T20C+100)
+/// Minimum temperature difference before group processing is suspended
+#define MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND 4
+/// Minimum temperature difference before the gas temperatures are just set to be equal
+#define MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER 0.5
+///Minimum temperature to continue superconduction once started
+#define MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION (T20C+80)
+///Minimum temperature to start doing superconduction calculations
+#define MINIMUM_TEMPERATURE_START_SUPERCONDUCTION (T20C+400)
+
+//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 WALL_HEAT_TRANSFER_COEFFICIENT 0.0
+#define OPEN_HEAT_TRANSFER_COEFFICIENT 0.4
+/// a hack for now
+#define WINDOW_HEAT_TRANSFER_COEFFICIENT 0.1
+/// a hack to help make vacuums "cold", sacrificing realism for gameplay
+#define HEAT_CAPACITY_VACUUM 7000
+
+//FIRE
+///Minimum temperature for fire to move to the next turf (150 °C or 433 K)
+#define FIRE_MINIMUM_TEMPERATURE_TO_SPREAD (150+T0C)
+///Minimum temperature for fire to exist on a turf (100 °C or 373 K)
+#define FIRE_MINIMUM_TEMPERATURE_TO_EXIST (100+T0C)
+///Multiplier for the temperature shared to other turfs
+#define FIRE_SPREAD_RADIOSITY_SCALE 0.85
+///Helper for small fires to grow
+#define FIRE_GROWTH_RATE 40000
+///Minimum temperature to burn plasma
+#define PLASMA_MINIMUM_BURN_TEMPERATURE (100+T0C)
+///Upper temperature ceiling for plasmafire reaction calculations for fuel consumption
+#define PLASMA_UPPER_TEMPERATURE (1370+T0C)
+///Multiplier for plasmafire with O2 moles * PLASMA_OXYGEN_FULLBURN for the maximum fuel consumption
+#define PLASMA_OXYGEN_FULLBURN 10
+///Minimum temperature to burn hydrogen
+#define HYDROGEN_MINIMUM_BURN_TEMPERATURE (100+T0C)
+///Upper temperature ceiling for h2fire reaction calculations for fuel consumption
+#define HYDROGEN_UPPER_TEMPERATURE (1370+T0C)
+///Multiplier for h2fire with O2 moles * HYDROGEN_OXYGEN_FULLBURN for the maximum fuel consumption
+#define HYDROGEN_OXYGEN_FULLBURN 10
+
+//COLD FIRE (this is used only for the freon-o2 reaction, there is no fire still)
+///fire will spread if the temperature is -10 °C
+#define COLD_FIRE_MAXIMUM_TEMPERATURE_TO_SPREAD 263
+///fire will start if the temperature is 0 °C
+#define COLD_FIRE_MAXIMUM_TEMPERATURE_TO_EXIST 273
+#define COLD_FIRE_SPREAD_RADIOSITY_SCALE 0.95 //Not yet implemented
+#define COLD_FIRE_GROWTH_RATE 40000 //Not yet implemented
+///Maximum temperature to burn freon
+#define FREON_MAXIMUM_BURN_TEMPERATURE 283
+///Minimum temperature allowed for the burn to go, we would have negative pressure otherwise
+#define FREON_LOWER_TEMPERATURE 60
+///Multiplier for freonfire with O2 moles * FREON_OXYGEN_FULLBURN for the maximum fuel consumption
+#define FREON_OXYGEN_FULLBURN 10
+
+///moles in a 2.5 m^3 cell at 101.325 Pa and 20 degC (103 or so)
+#define MOLES_CELLSTANDARD (ONE_ATMOSPHERE*CELL_VOLUME/(T20C*R_IDEAL_GAS_EQUATION))
+///compared against for superconductivity
+#define M_CELL_WITH_RATIO (MOLES_CELLSTANDARD * 0.005)
+/// percentage of oxygen in a normal mixture of air
+#define O2STANDARD 0.21
+/// same but for nitrogen
+#define N2STANDARD 0.79
+/// O2 standard value (21%)
+#define MOLES_O2STANDARD (MOLES_CELLSTANDARD*O2STANDARD)
+/// N2 standard value (79%)
+#define MOLES_N2STANDARD (MOLES_CELLSTANDARD*N2STANDARD)
+/// liters in a cell
+#define CELL_VOLUME 2500
+
+//CANATMOSPASS
+#define ATMOS_PASS_YES 1
+#define ATMOS_PASS_NO 0
+/// ask can_atmos_pass()
+#define ATMOS_PASS_PROC -1
+/// just check density
+#define ATMOS_PASS_DENSITY -2
+
+//Adjacent turf related defines, they dictate what to do with a turf once it's been recalculated
+//Used as "state" in CALCULATE_ADJACENT_TURFS
+///Normal non-active turf
+#define NORMAL_TURF 1
+///Set the turf to be activated on the next calculation
+#define MAKE_ACTIVE 2
+///Disable excited group
+#define KILL_EXCITED 3
+
+/// How many maximum iterations do we allow the Newton-Raphson approximation for gas pressure to do.
+#define ATMOS_PRESSURE_APPROXIMATION_ITERATIONS 10
+
+/// Used when an atmos machine has "external" selected.
+/// Found in `pressure_checks` of vents and air alarms.
+#define ATMOS_EXTERNAL_BOUND (1 << 0)
+
+/// Used when an atmos machine has "internal" selected.
+/// Found in `pressure_checks` of vents and air alarms.
+#define ATMOS_INTERNAL_BOUND (1 << 1)
+
+/// The maximum bound of an atmos machine.
+/// Found in `pressure_checks` of vents and air alarms.
+#define ATMOS_BOUND_MAX (ATMOS_EXTERNAL_BOUND | ATMOS_INTERNAL_BOUND)
+
+/// Used when an atmos machine is siphoning out air.
+/// Found in air alarms, vents, and scrubbers.
+#define ATMOS_DIRECTION_SIPHONING 0
+
+/// Used when a vent is releasing air.
+/// Found in air alarms, vents, and scrubbers.
+#define ATMOS_DIRECTION_RELEASING 1
+
+/// Used when a scrubber is scrubbing air.
+/// Found in air alarms, vents, and scrubbers.
+#define ATMOS_DIRECTION_SCRUBBING 1
+
+/// The max pressure of pumps.
+#define ATMOS_PUMP_MAX_PRESSURE (ONE_ATMOSPHERE * 50)
+
+// Value of [/obj/machinery/airalarm/var/danger_level] and retvals of [/datum/tlv/proc/check_value]
+/// No TLV exceeded.
+#define AIR_ALARM_ALERT_NONE 0
+/// TLV warning exceeded but not hazardous.
+#define AIR_ALARM_ALERT_WARNING 1
+/// TLV hazard exceeded or someone pulled the switch.
+#define AIR_ALARM_ALERT_HAZARD 2
+
+// Air alarm buildstage [/obj/machinery/airalarm/buildstage]
+/// Air alarm missing circuit
+#define AIR_ALARM_BUILD_NO_CIRCUIT 0
+/// Air alarm has circuit but is missing wires
+#define AIR_ALARM_BUILD_NO_WIRES 1
+/// Air alarm has all components but isn't completed
+#define AIR_ALARM_BUILD_COMPLETE 2
+
+// Fire alarm buildstage [/obj/machinery/firealarm/buildstage]
+/// Fire alarm missing circuit
+#define FIRE_ALARM_BUILD_NO_CIRCUIT 0
+/// Fire alarm has circuit but is missing wires
+#define FIRE_ALARM_BUILD_NO_WIRES 1
+/// Fire alarm has all components but isn't completed
+#define FIRE_ALARM_BUILD_SECURED 2
+
+// Fault levels for air alarm display
+/// Area faults clear
+#define AREA_FAULT_NONE 0
+/// Fault triggered by manual intervention (ie: fire alarm pull)
+#define AREA_FAULT_MANUAL 1
+/// Fault triggered automatically (ie: firedoor detection)
+#define AREA_FAULT_AUTOMATIC 2
+
+// threshold_type values for [/datum/tlv/proc/set_value] and [/datum/tlv/proc/reset_value]
+/// [/datum/tlv/var/warning_min]
+#define TLV_VAR_WARNING_MIN (1 << 0)
+/// [/datum/tlv/var/hazard_min]
+#define TLV_VAR_HAZARD_MIN (1 << 1)
+/// [/datum/tlv/var/warning_max]
+#define TLV_VAR_WARNING_MAX (1 << 2)
+/// [/datum/tlv/var/hazard_max]
+#define TLV_VAR_HAZARD_MAX (1 << 3)
+/// All the vars in [/datum/tlv]
+#define TLV_VAR_ALL (TLV_VAR_WARNING_MIN | TLV_VAR_HAZARD_MIN | TLV_VAR_WARNING_MAX | TLV_VAR_HAZARD_MAX)
+
+/// TLV datums will ignore variables set to this.
+#define TLV_VALUE_IGNORE -1
+
+#define CIRCULATOR_HOT 0
+#define CIRCULATOR_COLD 1
+
+///Default pressure, used in the UI to reset the settings
+#define PUMP_DEFAULT_PRESSURE (ONE_ATMOSPHERE)
+///Maximum settable pressure
+#define PUMP_MAX_PRESSURE (PUMP_DEFAULT_PRESSURE * 25)
+///Minimum settable pressure
+#define PUMP_MIN_PRESSURE (PUMP_DEFAULT_PRESSURE / 10)
+///The machine pumps from the turf to the internal tank
+#define PUMP_IN TRUE
+///The machine pumps from the internal source to the turf
+#define PUMP_OUT FALSE
+
+///Max allowed pressure for canisters to release air per tick
+#define CAN_MAX_RELEASE_PRESSURE (ONE_ATMOSPHERE * 25)
+///Min allowed pressure for canisters to release air per tick
+#define CAN_MIN_RELEASE_PRESSURE (ONE_ATMOSPHERE * 0.1)
diff --git a/code/__DEFINES/atmospherics/atmos_gasses.dm b/code/__DEFINES/atmospherics/atmos_gasses.dm
new file mode 100644
index 0000000000000..8fbc37726a372
--- /dev/null
+++ b/code/__DEFINES/atmospherics/atmos_gasses.dm
@@ -0,0 +1,13 @@
+#define GAS_N2 "n2"
+#define GAS_O2 "o2"
+#define GAS_CO2 "co2"
+#define GAS_PLASMA "plasma"
+#define GAS_N2O "n2o"
+#define GAS_NITRYL "nitryl"
+#define GAS_BZ "bz"
+#define GAS_AIR "air"
+#define GAS_WATER_VAPOR "water_vapor"
+#define GAS_TRITIUM "tritium"
+#define GAS_HYPER_NOBLIUM "hypernoblium"
+#define GAS_PLUOXIUM "pluoxium"
+#define GAS_STIMULUM "stimulum"
diff --git a/code/__DEFINES/atmospherics/atmos_helpers.dm b/code/__DEFINES/atmospherics/atmos_helpers.dm
new file mode 100644
index 0000000000000..c3baf9371a66f
--- /dev/null
+++ b/code/__DEFINES/atmospherics/atmos_helpers.dm
@@ -0,0 +1,165 @@
+//DO NOT USE THESE FOR ACCESSING ATMOS DATA, THEY MUTATE THINGS WHEN CALLED. I WILL BEAT YOU WITH A STICK. See the actual proc for more details
+///Check if an atom (A) and a turf (O) allow gas passage based on the atom's can_atmos_pass var, do not use.
+///(V) is if the share is vertical or not. True or False
+#define CANATMOSPASS(A, O, V) ( A.can_atmos_pass == ATMOS_PASS_PROC ? A.can_atmos_pass(O, V) : ( A.can_atmos_pass == ATMOS_PASS_DENSITY ? !A.density : A.can_atmos_pass ) )
+
+//Helpers
+///Moves the icon of the device based on the piping layer and on the direction
+#define PIPING_LAYER_SHIFT(T, PipingLayer) \
+ if(T.dir & (NORTH|SOUTH)) { \
+ T.pixel_x = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_X;\
+ } \
+ if(T.dir & (EAST|WEST)) { \
+ T.pixel_y = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_Y;\
+ }
+
+///Moves the icon of the device based on the piping layer and on the direction, the shift amount is dictated by more_shift
+#define PIPING_FORWARD_SHIFT(T, PipingLayer, more_shift) \
+ if(T.dir & (NORTH|SOUTH)) { \
+ T.pixel_y += more_shift * (PipingLayer - PIPING_LAYER_DEFAULT);\
+ } \
+ if(T.dir & (EAST|WEST)) { \
+ T.pixel_x += more_shift * (PipingLayer - PIPING_LAYER_DEFAULT);\
+ }
+
+///Moves the icon of the device based on the piping layer on both x and y
+#define PIPING_LAYER_DOUBLE_SHIFT(T, PipingLayer) \
+ T.pixel_x = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_X;\
+ T.pixel_y = (PipingLayer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_P_Y;
+
+///Calculate the thermal energy of the selected gas (J)
+#define THERMAL_ENERGY(gas) (gas.temperature * gas.heat_capacity())
+
+///Directly adds a gas to a gas mixture without checking for its presence beforehand, use only if is certain the absence of said gas
+#define ADD_GAS(gas_id, out_list)\
+ var/list/tmp_gaslist = GLOB.gaslist_cache[gas_id]; out_list[gas_id] = tmp_gaslist.Copy();
+
+///Adds a gas to a gas mixture but checks if is already present, faster than the same proc
+#define ASSERT_GAS(gas_id, gas_mixture) ASSERT_GAS_IN_LIST(gas_id, gas_mixture.gases)
+
+///Adds a gas to a gas LIST but checks if is already present, accepts a list instead of a datum, so faster if the list is locally cached
+#define ASSERT_GAS_IN_LIST(gas_id, gases) if (!gases[gas_id]) { ADD_GAS(gas_id, gases) };
+
+//prefer this to gas_mixture/total_moles in performance critical areas
+///Calculate the total moles of the gas mixture, faster than the proc, good for performance critical areas
+#define TOTAL_MOLES(cached_gases, out_var)\
+ out_var = 0;\
+ for(var/total_moles_id in cached_gases){\
+ out_var += cached_gases[total_moles_id][MOLES];\
+ }
+
+GLOBAL_LIST_INIT(nonoverlaying_gases, typecache_of_gases_with_no_overlays())
+///Returns a list of overlays of every gas in the mixture
+#define GAS_OVERLAYS(gases, out_var)\
+ out_var = list();\
+ for(var/_ID in gases){\
+ if(GLOB.nonoverlaying_gases[_ID]) continue;\
+ var/_GAS = gases[_ID];\
+ var/_GAS_META = _GAS[GAS_META];\
+ if(_GAS[MOLES] <= _GAS_META[META_GAS_MOLES_VISIBLE]) continue;\
+ var/_GAS_OVERLAY = _GAS_META[META_GAS_OVERLAY];\
+ out_var += _GAS_OVERLAY[min(TOTAL_VISIBLE_STATES, CEILING(_GAS[MOLES] / MOLES_GAS_VISIBLE_STEP, 1))];\
+ }
+
+#ifdef TESTING
+GLOBAL_LIST_INIT(atmos_adjacent_savings, list(0,0))
+#define CALCULATE_ADJACENT_TURFS(T, state) if (SSair.adjacent_rebuild[T]) { GLOB.atmos_adjacent_savings[1] += 1 } else { GLOB.atmos_adjacent_savings[2] += 1; SSair.adjacent_rebuild[T] = state}
+#else
+#define CALCULATE_ADJACENT_TURFS(T, state) SSair.adjacent_rebuild[T] = state
+#endif
+
+//If you're doing spreading things related to atmos, DO NOT USE CANATMOSPASS, IT IS NOT CHEAP. use this instead, the info is cached after all. it's tweaked just a bit to allow for circular checks
+#define TURFS_CAN_SHARE(T1, T2) (LAZYACCESS(T2.atmos_adjacent_turfs, T1) || LAZYLEN(T1.atmos_adjacent_turfs & T2.atmos_adjacent_turfs))
+//Use this to see if a turf is fully blocked or not, think windows or firelocks. Fails with 1x1 non full tile windows, but it's not worth the cost.
+#define TURF_SHARES(T) (LAZYLEN(T.atmos_adjacent_turfs))
+/// Rounding
+#define QUANTIZE(variable) (round((variable), (MOLAR_ACCURACY)))
+
+// Macros to access moles. Used instead of listmos only when nullchecking is necessary.
+
+///Gets the moles of a specific gas in a gas mixture.
+#define GET_MOLES(gas, gas_mixture) (gas_mixture.gases[gas] ? gas_mixture.gases[gas][MOLES] : 0)
+
+///Adds moles to a specific gas in a gas mixture.
+#define ADD_MOLES(gas, gas_mixture, moles)\
+ ASSERT_GAS(gas, gas_mixture);\
+ gas_mixture.gases[gas][MOLES] += moles;
+
+///Removes moles while making sure it doesn't go under 0.
+#define REMOVE_MOLES(gas, gas_mixture, moles)\
+ ASSERT_GAS(gas, gas_mixture);\
+ gas_mixture.gases[gas][MOLES] -= max(moles, 0);
+
+/// Basically REMOVE_MOLES but with the thing sign flipped. Use this when sign is unknown
+#define ADJUST_MOLES(gas, gas_mixture, moles)\
+ ASSERT_GAS(gas, gas_mixture);\
+ gas_mixture.gases[gas][MOLES] += max(moles, 0);
+
+///Sets the moles of a specific gas in a gas mixture, asserts the gas is present.
+#define SET_MOLES(gas, gas_mixture, moles)\
+ ASSERT_GAS(gas, gas_mixture);\
+ gas_mixture.gases[gas][MOLES] = moles;
+
+///Adds moles to a specific gas list in a gas mixture.
+#define ADD_MOLES_LIST(gas_id, gases, moles)\
+ ASSERT_GAS_IN_LIST(gas_id, gases);\
+ gases[gas_id][MOLES] += moles;
+
+///Removes moles while making sure it doesn't go under 0, also a list.
+#define REMOVE_MOLES_LIST(gas_id, gases, moles)\
+ ASSERT_GAS_IN_LIST(gas_id, gases);\
+ gases[gas_id][MOLES] -= max(moles, 0);
+
+/// Basically REMOVE_MOLES but with the thing sign flipped. Use this when sign is unknown AND A LIST
+#define ADJUST_MOLES_LIST(gas_id, gases, moles)\
+ ASSERT_GAS_IN_LIST(gas_id, gases);\
+ gases[gas_id][MOLES] += max(moles, 0);
+
+///Sets the moles of a specific gas in a gas list, asserts the gas is present.
+#define SET_MOLES_LIST(gas_id, gases, moles)\
+ ASSERT_GAS_IN_LIST(gas_id, gases);\
+ gases[gas_id][MOLES] = moles;
+
+#define LINDA_CYCLE_ARCHIVE(turf)\
+ turf.air.archive();\
+ turf.archived_cycle = SSair.times_fired;\
+ turf.temperature_archived = turf.temperature;
+
+/* Fetch the energy transferred when two gas mixtures' temperature equalize.
+ *
+ * To equalize two gas mixtures, we simply pool the energy and divide it by the pooled heat capacity.
+ * T' = (W1+W2) / (C1+C2)
+ * But if we want to moderate this conduction, maybe we can calculate the energy transferred
+ * and multiply a coefficient to it instead.
+ * This is the energy transferred:
+ * W = T' * C1 - W1
+ * W = (W1+W2) / (C1+C2) * C1 - W1
+ * W = (W1C1 + W2C1) / (C1+C2) - W1
+ * W = ((W1C1 + W2C1) - (W1 * (C1+C2))) / (C1+C2)
+ * W = ((W1C1 + W2C1) - (W1C1 + W1C2)) / (C1+C2)
+ * W = (W1C1 - W1C1 + W2C1 - W1C2) / (C1+C2)
+ * W = (W2C1 - W1C2) / (C1+C2)
+ * W = (T2*C2*C1 - T1*C1*C2) / (C1+C2)
+ * W = (C1*C2) * (T2-T1) / (C1+C2)
+ *
+ * W: Energy involved in the operation
+ * T': Combined temperature
+ * T1, C1, W1: Temp, heat cap, and thermal energy of the first gas mixture
+ * T2, C2, W2: Temp, heat cap, and thermal energy of the second gas mixture
+ *
+ * Not immediately obvious, but saves us operation time.
+ *
+ * We put a lot of parentheses here because the numbers get really really big.
+ * By prioritizing the division we try to tone the number down so we don't get overflows.
+ *
+ * Arguments:
+ * * temperature_delta: T2 - T1. [/datum/gas_mixture/var/temperature]
+ * If you have any moderating (less than 1) coefficients and are dealing with very big numbers
+ * multiply the temperature_delta by it first before passing so we get even more breathing room.
+ * * heat_capacity_one: gasmix one's [/datum/gas_mixture/proc/heat_capacity]
+ * * heat_capacity_two: gasmix two's [/datum/gas_mixture/proc/heat_capacity]
+ * Returns: The energy gained by gas mixture one. Negative if gas mixture one loses energy.
+ * Honestly the heat capacity is interchangeable, just make sure the delta is right.
+ */
+#define CALCULATE_CONDUCTION_ENERGY(temperature_delta, heat_capacity_one, heat_capacity_two)\
+ ((temperature_delta) * ((heat_capacity_one) * ((heat_capacity_two) / ((heat_capacity_one) + (heat_capacity_two)))))
diff --git a/code/__DEFINES/atmospherics/atmos_mapping_helpers.dm b/code/__DEFINES/atmospherics/atmos_mapping_helpers.dm
new file mode 100644
index 0000000000000..8337cf5219657
--- /dev/null
+++ b/code/__DEFINES/atmospherics/atmos_mapping_helpers.dm
@@ -0,0 +1,69 @@
+//OPEN TURF ATMOS
+/// the default air mix that open turfs spawn
+#define OPENTURF_DEFAULT_ATMOS "o2=22;n2=82;TEMP=293.15"
+#define OPENTURF_LOW_PRESSURE "o2=14;n2=30;TEMP=293.15"
+/// -193,15°C telecommunications. also used for xenobiology slime killrooms
+#define TCOMMS_ATMOS "n2=100;TEMP=80"
+/// space
+#define AIRLESS_ATMOS "TEMP=2.7"
+/// -93.15°C snow and ice turfs
+#define FROZEN_ATMOS "o2=22;n2=82;TEMP=180"
+/// -14°C kitchen coldroom, just might loss your tail; higher amount of mol to reach about 101.3 kpA
+#define KITCHEN_COLDROOM_ATMOS "o2=26;n2=97;TEMP=[COLD_ROOM_TEMP]"
+/// used in the holodeck burn test program
+#define BURNMIX_ATMOS "o2=2500;plasma=5000;TEMP=370"
+
+//ATMOSPHERICS DEPARTMENT GAS TANK TURFS
+#define ATMOS_TANK_N2O "n2o=6000;TEMP=293.15"
+#define ATMOS_TANK_CO2 "co2=50000;TEMP=293.15"
+#define ATMOS_TANK_PLASMA "plasma=70000;TEMP=293.15"
+#define ATMOS_TANK_O2 "o2=100000;TEMP=293.15"
+#define ATMOS_TANK_N2 "n2=100000;TEMP=293.15"
+#define ATMOS_TANK_BZ "bz=100000;TEMP=293.15"
+#define ATMOS_TANK_HYPERNOBLIUM "nob=100000;TEMP=293.15"
+#define ATMOS_TANK_NO2 "no2=100000;TEMP=293.15"
+#define ATMOS_TANK_PLUOXIUM "pluox=100000;TEMP=293.15"
+#define ATMOS_TANK_STIMULUM "stim=100000;TEMP=293.15"
+#define ATMOS_TANK_TRITIUM "tritium=100000;TEMP=293.15"
+#define ATMOS_TANK_H2O "water_vapor=100000;TEMP=293.15"
+#define ATMOS_TANK_AIRMIX "o2=2777;n2=10447;TEMP=293.15" // 21% oxygen, 79% nitrogen. Roughly.
+
+//LAVALAND
+/// what pressure you have to be under to increase the effect of equipment meant for lavaland
+#define MAXIMUM_LAVALAND_EQUIPMENT_EFFECT_PRESSURE 90
+
+//ATMOS MIX IDS
+#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=5;co2=13;TEMP=300"
+
+//AIRLOCK CONTROLLER TAGS
+
+//RnD ordnance burn chamber
+#define INCINERATOR_ORDMIX_IGNITER "ordmix_igniter"
+#define INCINERATOR_ORDMIX_VENT "ordmix_vent"
+#define INCINERATOR_ORDMIX_DP_VENTPUMP "ordmix_airlock_pump"
+#define INCINERATOR_ORDMIX_AIRLOCK_SENSOR "ordmix_airlock_sensor"
+#define INCINERATOR_ORDMIX_AIRLOCK_CONTROLLER "ordmix_airlock_controller"
+#define INCINERATOR_ORDMIX_AIRLOCK_INTERIOR "ordmix_airlock_interior"
+#define INCINERATOR_ORDMIX_AIRLOCK_EXTERIOR "ordmix_airlock_exterior"
+
+//Atmospherics/maintenance incinerator
+#define INCINERATOR_ATMOS_IGNITER "atmos_incinerator_igniter"
+#define INCINERATOR_ATMOS_MAINVENT "atmos_incinerator_mainvent"
+#define INCINERATOR_ATMOS_AUXVENT "atmos_incinerator_auxvent"
+#define INCINERATOR_ATMOS_DP_VENTPUMP "atmos_incinerator_airlock_pump"
+#define INCINERATOR_ATMOS_AIRLOCK_SENSOR "atmos_incinerator_airlock_sensor"
+#define INCINERATOR_ATMOS_AIRLOCK_CONTROLLER "atmos_incinerator_airlock_controller"
+#define INCINERATOR_ATMOS_AIRLOCK_INTERIOR "atmos_incinerator_airlock_interior"
+#define INCINERATOR_ATMOS_AIRLOCK_EXTERIOR "atmos_incinerator_airlock_exterior"
+#define TEST_ROOM_ATMOS_MAINVENT_1 "atmos_test_room_mainvent_1"
+#define TEST_ROOM_ATMOS_MAINVENT_2 "atmos_test_room_mainvent_2"
+
+//Syndicate lavaland base incinerator (lavaland_surface_syndicate_base1.dmm)
+#define INCINERATOR_SYNDICATELAVA_IGNITER "syndicatelava_igniter"
+#define INCINERATOR_SYNDICATELAVA_MAINVENT "syndicatelava_mainvent"
+#define INCINERATOR_SYNDICATELAVA_AUXVENT "syndicatelava_auxvent"
+#define INCINERATOR_SYNDICATELAVA_DP_VENTPUMP "syndicatelava_airlock_pump"
+#define INCINERATOR_SYNDICATELAVA_AIRLOCK_SENSOR "syndicatelava_airlock_sensor"
+#define INCINERATOR_SYNDICATELAVA_AIRLOCK_CONTROLLER "syndicatelava_airlock_controller"
+#define INCINERATOR_SYNDICATELAVA_AIRLOCK_INTERIOR "syndicatelava_airlock_interior"
+#define INCINERATOR_SYNDICATELAVA_AIRLOCK_EXTERIOR "syndicatelava_airlock_exterior"
diff --git a/code/__DEFINES/atmospherics/atmos_mob_interaction.dm b/code/__DEFINES/atmospherics/atmos_mob_interaction.dm
new file mode 100644
index 0000000000000..2069d6695b3d5
--- /dev/null
+++ b/code/__DEFINES/atmospherics/atmos_mob_interaction.dm
@@ -0,0 +1,135 @@
+/** liters in a normal breath. note that breaths are taken once every 4 life ticks, which is 8 seconds
+ * Addendum for people tweaking this value in the future.
+ * Because o2 tank release values/human o2 requirements are very strictly set to the same pressure, small errors can cause breakage
+ * This comes from QUANTIZE being used in /datum/gas_mixture.remove(), forming a slight sawtooth pattern of the added/removed gas, centered on the actual pressure
+ * Changing BREATH_VOLUME can set us on the lower half of this sawtooth, making humans unable to breath at standard pressure.
+ * There's no good way I can come up with to hardcode a fix for this. So if you're going to change this variable
+ * graph the functions that describe how it is used/how it interacts with breath code, and pick something on the upper half of the sawtooth
+ *
+**/
+#define BREATH_VOLUME 1.99
+/// Amount of air to take a from a tile
+#define BREATH_PERCENTAGE (BREATH_VOLUME/CELL_VOLUME)
+
+//Defines for N2O and Healium euphoria moodlets
+#define EUPHORIA_INACTIVE 0
+#define EUPHORIA_ACTIVE 1
+#define EUPHORIA_LAST_FLAG 2
+
+#define MIASMA_CORPSE_MOLES 0.02
+#define MIASMA_GIBS_MOLES 0.005
+
+#define MIN_TOXIC_GAS_DAMAGE 1
+#define MAX_TOXIC_GAS_DAMAGE 10
+
+// Pressure limits.
+/// This determins at what pressure the ultra-high pressure red icon is displayed. (This one is set as a constant)
+#define HAZARD_HIGH_PRESSURE 550
+/// This determins when the orange pressure icon is displayed (it is 0.7 * HAZARD_HIGH_PRESSURE)
+#define WARNING_HIGH_PRESSURE 325
+/// This is when the gray low pressure icon is displayed. (it is 2.5 * HAZARD_LOW_PRESSURE)
+#define WARNING_LOW_PRESSURE 50
+/// This is when the black ultra-low pressure icon is displayed. (This one is set as a constant)
+#define HAZARD_LOW_PRESSURE 20
+
+/// This is used in handle_temperature_damage() for humans, and in reagents that affect body temperature. Temperature damage is multiplied by this amount.
+#define TEMPERATURE_DAMAGE_COEFFICIENT 1.5
+
+/// The natural temperature for a body
+#define BODYTEMP_NORMAL 310.15
+/// This is the divisor which handles how much of the temperature difference between the current body temperature and 310.15K (optimal temperature) humans auto-regenerate each tick. The higher the number, the slower the recovery. This is applied each tick, so long as the mob is alive.
+#define BODYTEMP_AUTORECOVERY_DIVISOR 28
+/// Minimum amount of kelvin moved toward 310K per tick. So long as abs(310.15 - bodytemp) is more than 50.
+#define BODYTEMP_AUTORECOVERY_MINIMUM 3
+///Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is lower than their body temperature. Make it lower to lose bodytemp faster.
+#define BODYTEMP_COLD_DIVISOR 15
+/// Similar to the BODYTEMP_AUTORECOVERY_DIVISOR, but this is the divisor which is applied at the stage that follows autorecovery. This is the divisor which comes into play when the human's loc temperature is higher than their body temperature. Make it lower to gain bodytemp faster.
+#define BODYTEMP_HEAT_DIVISOR 15
+/// The maximum number of degrees that your body can cool in 1 tick, due to the environment, when in a cold area.
+#define BODYTEMP_COOLING_MAX -30
+/// The maximum number of degrees that your body can heat up in 1 tick, due to the environment, when in a hot area.
+#define BODYTEMP_HEATING_MAX 30
+/// The body temperature limit the human body can take before it starts taking damage from heat.
+/// This also affects how fast the body normalises it's temperature when hot.
+/// 340k is about 66c, and rather high for a human.
+#define BODYTEMP_HEAT_DAMAGE_LIMIT (BODYTEMP_NORMAL + 30)
+/// The body temperature limit the human body can take before it starts taking damage from cold.
+/// This also affects how fast the body normalises it's temperature when cold.
+/// 270k is about -3c, that is below freezing and would hurt over time.
+#define BODYTEMP_COLD_DAMAGE_LIMIT (BODYTEMP_NORMAL - 40)
+/// The body temperature limit the human body can take before it will take wound damage.
+#define BODYTEMP_HEAT_WOUND_LIMIT (BODYTEMP_NORMAL + 90) // 400.5 k
+/// The modifier on cold damage limit hulks get ontop of their regular limit
+#define BODYTEMP_HULK_COLD_DAMAGE_LIMIT_MODIFIER 25
+/// The modifier on cold damage hulks get.
+#define HULK_COLD_DAMAGE_MOD 2
+
+// Body temperature warning icons
+/// The temperature the red icon is displayed.
+#define BODYTEMP_HEAT_WARNING_3 (BODYTEMP_HEAT_DAMAGE_LIMIT + 360) //+700k
+/// The temperature the orange icon is displayed.
+#define BODYTEMP_HEAT_WARNING_2 (BODYTEMP_HEAT_DAMAGE_LIMIT + 120) //460K
+/// The temperature the yellow icon is displayed.
+#define BODYTEMP_HEAT_WARNING_1 (BODYTEMP_HEAT_DAMAGE_LIMIT) //340K
+/// The temperature the light green icon is displayed.
+#define BODYTEMP_COLD_WARNING_1 (BODYTEMP_COLD_DAMAGE_LIMIT) //270k
+/// The temperature the cyan icon is displayed.
+#define BODYTEMP_COLD_WARNING_2 (BODYTEMP_COLD_DAMAGE_LIMIT - 70) //200k
+/// The temperature the blue icon is displayed.
+#define BODYTEMP_COLD_WARNING_3 (BODYTEMP_COLD_DAMAGE_LIMIT - 150) //120k
+
+/// The amount of pressure damage someone takes is equal to (pressure / HAZARD_HIGH_PRESSURE)*PRESSURE_DAMAGE_COEFFICIENT, with the maximum of MAX_PRESSURE_DAMAGE
+#define PRESSURE_DAMAGE_COEFFICIENT 2
+#define MAX_HIGH_PRESSURE_DAMAGE 2
+/// The amount of damage someone takes when in a low pressure area (The pressure threshold is so low that it doesn't make sense to do any calculations, so it just applies this flat value).
+#define LOW_PRESSURE_DAMAGE 2
+
+/// Humans are slowed by the difference between bodytemp and BODYTEMP_COLD_DAMAGE_LIMIT divided by this
+#define COLD_SLOWDOWN_FACTOR 20
+
+
+//CLOTHES
+
+//Emergency skinsuits
+#define EMERGENCY_HELM_MIN_TEMP_PROTECT 2.0 //The helmet is pressurized with air from the oxygen tank. If they don't take damage from that they won't take damage here
+#define EMERGENCY_SUIT_MIN_TEMP_PROTECT 237 //This is the approximate average temperature of Mt. Everest in the winter
+
+/// what min_cold_protection_temperature is set to for space-helmet quality headwear. MUST NOT BE 0.
+#define SPACE_HELM_MIN_TEMP_PROTECT 2.0
+/// Thermal insulation works both ways /Malkevin
+#define SPACE_HELM_MAX_TEMP_PROTECT 1500
+/// what min_cold_protection_temperature is set to for space-suit quality jumpsuits or suits. MUST NOT BE 0.
+#define SPACE_SUIT_MIN_TEMP_PROTECT 2.0
+/// The min cold protection of a space suit without the heater active
+#define SPACE_SUIT_MIN_TEMP_PROTECT_OFF 72
+#define SPACE_SUIT_MAX_TEMP_PROTECT 1500
+
+/// Cold protection for firesuits
+#define FIRE_SUIT_MIN_TEMP_PROTECT 60
+/// what max_heat_protection_temperature is set to for firesuit quality suits. MUST NOT BE 0.
+#define FIRE_SUIT_MAX_TEMP_PROTECT 30000
+/// Cold protection for fire helmets
+#define FIRE_HELM_MIN_TEMP_PROTECT 60
+/// for fire helmet quality items (red and white hardhats)
+#define FIRE_HELM_MAX_TEMP_PROTECT 30000
+
+/// what max_heat_protection_temperature is set to for firesuit quality suits and helmets. MUST NOT BE 0.
+#define FIRE_IMMUNITY_MAX_TEMP_PROTECT 35000
+
+/// For normal helmets
+#define HELMET_MIN_TEMP_PROTECT 160
+/// For normal helmets
+#define HELMET_MAX_TEMP_PROTECT 600
+/// For armor
+#define ARMOR_MIN_TEMP_PROTECT 160
+/// For armor
+#define ARMOR_MAX_TEMP_PROTECT 600
+
+/// For some gloves (black and)
+#define GLOVES_MIN_TEMP_PROTECT 2.0
+/// For some gloves
+#define GLOVES_MAX_TEMP_PROTECT 1500
+/// For gloves
+#define SHOES_MIN_TEMP_PROTECT 2.0
+/// For gloves
+#define SHOES_MAX_TEMP_PROTECT 1500
diff --git a/code/__DEFINES/atmospherics/atmos_piping.dm b/code/__DEFINES/atmospherics/atmos_piping.dm
new file mode 100644
index 0000000000000..74f60fcd23699
--- /dev/null
+++ b/code/__DEFINES/atmospherics/atmos_piping.dm
@@ -0,0 +1,71 @@
+//PIPES
+//Defines for pipe bitmasking
+#define NORTH_FULLPIPE (1<<0) //also just NORTH
+#define SOUTH_FULLPIPE (1<<1) //also just SOUTH
+#define EAST_FULLPIPE (1<<2) //also just EAST
+#define WEST_FULLPIPE (1<<3) //also just WEST
+#define NORTH_SHORTPIPE (1<<4)
+#define SOUTH_SHORTPIPE (1<<5)
+#define EAST_SHORTPIPE (1<<6)
+#define WEST_SHORTPIPE (1<<7)
+//Atmos pipe limits
+/// (kPa) What pressure pumps and powered equipment max out at.
+#define MAX_OUTPUT_PRESSURE 4500
+/// (L/s) Maximum speed powered equipment can work at.
+#define MAX_TRANSFER_RATE 200
+/// How many percent of the contents that an overclocked volume pumps leak into the air
+#define VOLUME_PUMP_LEAK_AMOUNT 0.1
+//used for device_type vars
+#define UNARY 1
+#define BINARY 2
+#define TRINARY 3
+#define QUATERNARY 4
+
+//TANKS
+/// temperature in kelvins at which a tank will start to melt
+#define TANK_MELT_TEMPERATURE 1000000
+/// Tank starts leaking
+#define TANK_LEAK_PRESSURE (30.*ONE_ATMOSPHERE)
+/// Tank spills all contents into atmosphere
+#define TANK_RUPTURE_PRESSURE (35.*ONE_ATMOSPHERE)
+/// Boom 3x3 base explosion
+#define TANK_FRAGMENT_PRESSURE (40.*ONE_ATMOSPHERE)
+/// +1 for each SCALE kPa aboe threshold
+#define TANK_FRAGMENT_SCALE (6.*ONE_ATMOSPHERE)
+#define TANK_MAX_RELEASE_PRESSURE (ONE_ATMOSPHERE*3)
+#define TANK_MIN_RELEASE_PRESSURE 0
+#define TANK_DEFAULT_RELEASE_PRESSURE 16
+
+//MULTIPIPES
+//IF YOU EVER CHANGE THESE CHANGE SPRITES TO MATCH.
+//layer = initial(layer) + piping_layer / 1000 in atmospherics/update_icon() to determine order of pipe overlap
+#define PIPING_LAYER_MIN 1
+#define PIPING_LAYER_MAX 5
+#define PIPING_LAYER_DEFAULT 3
+#define PIPING_LAYER_P_X 5
+#define PIPING_LAYER_P_Y 5
+#define PIPING_LAYER_LCHANGE 0.05
+
+/// intended to connect with all layers, check for all instead of just one.
+#define PIPING_ALL_LAYER (1<<0)
+/// can only be built if nothing else with this flag is on the tile already.
+#define PIPING_ONE_PER_TURF (1<<1)
+/// can only exist at PIPING_LAYER_DEFAULT
+#define PIPING_DEFAULT_LAYER_ONLY (1<<2)
+/// north/south east/west doesn't matter, auto normalize on build.
+#define PIPING_CARDINAL_AUTONORMALIZE (1<<3)
+/// intended to connect with everything, both layers and colors
+#define PIPING_ALL_COLORS (1<<4)
+/// can bridge over pipenets
+#define PIPING_BRIDGE (1<<5)
+/// intended to connect with layers 2 and 4 only
+#define PIPING_DISTRO_AND_WASTE_LAYERS (1<<6)
+
+// Ventcrawling bitflags, handled in var/vent_movement
+///Allows for ventcrawling to occur. All atmospheric machines have this flag on by default. Cryo is the exception
+#define VENTCRAWL_ALLOWED (1<<0)
+///Allows mobs to enter or leave from atmospheric machines. On for passive, unary, and scrubber vents.
+#define VENTCRAWL_ENTRANCE_ALLOWED (1<<1)
+///Used to check if a machinery is visible. Called by update_pipe_vision(). On by default for all except cryo.
+#define VENTCRAWL_CAN_SEE (1<<2)
+
diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm
index 3fe2d6671f74c..b9cbd34565fdb 100644
--- a/code/__DEFINES/colors.dm
+++ b/code/__DEFINES/colors.dm
@@ -66,6 +66,7 @@
#define COLOR_BLUE_GRAY "#75A2BB"
#define COLOR_PINK "#FFC0CB"
+#define COLOR_LIGHT_PINK "#FF3CC8"
#define COLOR_MOSTLY_PURE_PINK "#E4005B"
#define COLOR_BLUSH_PINK "#DE5D83"
#define COLOR_FADED_PINK "#ff80d5"
@@ -73,14 +74,19 @@
#define COLOR_STRONG_MAGENTA "#B800B8"
#define COLOR_PURPLE "#800080"
#define COLOR_VIOLET "#B900F7"
+#define COLOR_AMETHYST "#822BFF"
#define COLOR_STRONG_VIOLET "#6927C5"
#define COLOR_DARK_PURPLE "#551A8B"
+
#define COLOR_ORANGE "#FF9900"
#define COLOR_LIGHT_ORANGE "#ffc44d"
+#define COLOR_ENGINEERING_ORANGE "#FFA62B"
#define COLOR_DARK_ORANGE "#C3630C"
#define COLOR_BEIGE "#CEB689"
#define COLOR_DARK_MODERATE_ORANGE "#8B633B"
+#define COLOR_TAN_ORANGE "#FF7B00"
+
#define COLOR_BROWN "#BA9F6D"
#define COLOR_DARK_BROWN "#997C4F"
diff --git a/code/__DEFINES/dcs/signals/signals_area.dm b/code/__DEFINES/dcs/signals/signals_area.dm
index 077917470f361..e3caaa0accd9d 100644
--- a/code/__DEFINES/dcs/signals/signals_area.dm
+++ b/code/__DEFINES/dcs/signals/signals_area.dm
@@ -10,3 +10,16 @@
///! from base of area/Exited(): (atom/movable/M)
#define COMSIG_AREA_EXITED "area_exited"
+///from base of area/Entered(): (area/new_area). Sent to "area-sensitive" movables, see __DEFINES/traits.dm for info.
+#define COMSIG_ENTER_AREA "enter_area"
+///from base of area/Exited(): (area). Sent to "area-sensitive" movables, see __DEFINES/traits.dm for info.
+#define COMSIG_EXIT_AREA "exit_area"
+
+/// Called when an alarm handler fires an alarm
+#define COMSIG_ALARM_TRIGGERED "alarm_triggered"
+/// Called when an alarm handler clears an alarm
+#define COMSIG_ALARM_CLEARED "alarm_cleared"
+
+// Area fire signals
+/// Sent when an area's fire var changes: (fire_value)
+#define COMSIG_AREA_FIRE_CHANGED "area_fire_set"
diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm
index c5d3e717def13..1269121f093c6 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_attack.dm
@@ -18,6 +18,8 @@
#define COMSIG_ATOM_BREAK "atom_break"
/// from base of [/atom/proc/atom_fix]: ()
#define COMSIG_ATOM_FIX "atom_fix"
+/// from base of [/atom/proc/atom_destruction]: (damage_flag)
+#define COMSIG_ATOM_DESTRUCTION "atom_destruction"
///from base of [/atom/proc/update_integrity]: (old_value, new_value)
#define COMSIG_ATOM_INTEGRITY_CHANGED "atom_integrity_changed"
///from base of [/atom/proc/take_damage]: (damage_amount, damage_type, damage_flag, sound_effect, attack_dir, aurmor_penetration)
diff --git a/code/__DEFINES/dcs/signals/signals_datum/signals_datum.dm b/code/__DEFINES/dcs/signals/signals_datum/signals_datum.dm
index e76747e22846f..86c81d17a16cd 100644
--- a/code/__DEFINES/dcs/signals/signals_datum/signals_datum.dm
+++ b/code/__DEFINES/dcs/signals/signals_datum/signals_datum.dm
@@ -106,12 +106,6 @@
/// signals from globally accessible objects
-// Alarm listener datum signals
-///Sent when an alarm is fired (alarm, area/source_area)
-#define COMSIG_ALARM_TRIGGERED "comsig_alarm_triggered"
-///Send when an alarm source is cleared (alarm_type, area/source_area)
-#define COMSIG_ALARM_CLEARED "comsig_alarm_clear"
-
// Radio jammer signals
/// Calls something to toggle its jamming ability. (mob/user, silent = FALSE)
#define COMSIG_TOGGLE_JAMMER "toggle_jammer"
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob.dm
index 9492d89c06ac6..618471d5d7474 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob.dm
@@ -27,9 +27,6 @@
#define COMSIG_MOB_CLIENT_MOVED "mob_client_moved"
/// From base of /mob/proc/reset_perspective() : ()
#define COMSIG_MOB_RESET_PERSPECTIVE "mob_reset_perspective"
-
- /// Should we stop the current living movement attempt
- #define COMSIG_MOB_CLIENT_BLOCK_PRE_LIVING_MOVE COMPONENT_MOVABLE_BLOCK_PRE_MOVE
#define COMSIG_MOB_ALLOWED "mob_allowed" //! from base of obj/allowed(mob/M): (/obj) returns bool, if TRUE the mob has id access to the obj
#define COMSIG_MOB_RECEIVE_MAGIC "mob_receive_magic" //! from base of mob/anti_magic_check(): (mob/user, magic, holy, major, self, protection_sources)
#define COMPONENT_BLOCK_MAGIC 1
@@ -66,6 +63,8 @@
#define COMSIG_MOB_POINTED "mob_pointed" //from base of /mob/verb/pointed: (atom/A)
/// From base of /client/Move()
#define COMSIG_MOB_CLIENT_PRE_LIVING_MOVE "mob_client_pre_living_move"
+ /// Should we stop the current living movement attempt
+ #define COMSIG_MOB_CLIENT_BLOCK_PRE_LIVING_MOVE COMPONENT_MOVABLE_BLOCK_PRE_MOVE
///Called after a client connects to a mob and all UI elements have been setup
#define COMSIG_MOB_CLIENT_LOGIN "comsig_mob_client_login"
#define COMSIG_MOB_MOUSE_SCROLL_ON "comsig_mob_mouse_scroll_on" //! from base of /mob/MouseWheelOn(): (atom/A, delta_x, delta_y, params)
diff --git a/code/__DEFINES/dcs/signals/signals_obj/signals_atmospheric_machine.dm b/code/__DEFINES/dcs/signals/signals_obj/signals_atmospheric_machine.dm
index 9ae06608196a6..9bd8d96b9b2a3 100644
--- a/code/__DEFINES/dcs/signals/signals_obj/signals_atmospheric_machine.dm
+++ b/code/__DEFINES/dcs/signals/signals_obj/signals_atmospheric_machine.dm
@@ -7,6 +7,9 @@
/// from /obj/machinery/atmospherics/components/binary/valve/toggle(): (on)
#define COMSIG_VALVE_SET_OPEN "valve_toggled"
+/// from /obj/machinery/atmospherics/set_on(active): (on)
+#define COMSIG_ATMOS_MACHINE_SET_ON "atmos_machine_set_on"
-/// from /obj/machinery/atmospherics/components/binary/pump/set_on(active): (on)
-#define COMSIG_PUMP_SET_ON "pump_set_on"
+/// from /obj/machinery/fire_alarm/reset(), /obj/machinery/fire_alarm/alarm(): (status)
+#define COMSIG_FIREALARM_ON_TRIGGER "firealarm_trigger"
+#define COMSIG_FIREALARM_ON_RESET "firealarm_reset"
diff --git a/code/__DEFINES/dcs/signals/signals_obj/signals_machine/signals_machinery.dm b/code/__DEFINES/dcs/signals/signals_obj/signals_machine/signals_machinery.dm
index 70a267b692555..427549a7ba41b 100644
--- a/code/__DEFINES/dcs/signals/signals_obj/signals_machine/signals_machinery.dm
+++ b/code/__DEFINES/dcs/signals/signals_obj/signals_machine/signals_machinery.dm
@@ -23,3 +23,8 @@
/// from /obj/machinery/atmospherics/components/unary/cryo_cell/set_on(bool): (on)
#define COMSIG_CRYO_SET_ON "cryo_set_on"
+
+///from /datum/controller/subsystem/air/proc/start_processing_machine: ()
+#define COMSIG_MACHINERY_START_PROCESSING_AIR "start_processing_air"
+///from /datum/controller/subsystem/air/proc/stop_processing_machine: ()
+#define COMSIG_MACHINERY_STOP_PROCESSING_AIR "stop_processing_air"
diff --git a/code/__DEFINES/dcs/signals/signals_obj/signals_object.dm b/code/__DEFINES/dcs/signals/signals_obj/signals_object.dm
index 357d32dc19ae0..8ea666eab2987 100644
--- a/code/__DEFINES/dcs/signals/signals_obj/signals_object.dm
+++ b/code/__DEFINES/dcs/signals/signals_obj/signals_object.dm
@@ -23,3 +23,6 @@
///from /obj/item/assembly/proc/pulsed(mob/pulser)
#define COMSIG_ASSEMBLY_PULSED "assembly_pulsed"
+
+/// from /obj/proc/obj_break: ()
+#define COMSIG_OBJ_BREAK "obj_break"
diff --git a/code/__DEFINES/dcs/signals/signals_turf.dm b/code/__DEFINES/dcs/signals/signals_turf.dm
index bec34d81c2614..4ae48a9008c62 100644
--- a/code/__DEFINES/dcs/signals/signals_turf.dm
+++ b/code/__DEFINES/dcs/signals/signals_turf.dm
@@ -15,3 +15,7 @@
#define COMSIG_TURF_AFTER_SHUTTLE_MOVE "turf_after_shuttle_move"
/// from base of /datum/turf_reservation/proc/Release: (datum/turf_reservation/reservation)
#define COMSIG_TURF_RESERVATION_RELEASED "turf_reservation_released"
+//from /turf/open/temperature_expose(datum/gas_mixture/air, exposed_temperature)
+#define COMSIG_TURF_EXPOSE "turf_expose"
+///from /turf/proc/immediate_calculate_adjacent_turfs()
+#define COMSIG_TURF_CALCULATED_ADJACENT_ATMOS "turf_calculated_adjacent_atmos"
diff --git a/code/__DEFINES/flags.dm b/code/__DEFINES/flags.dm
index 342b99743fd63..b0fd0e8fe1f11 100644
--- a/code/__DEFINES/flags.dm
+++ b/code/__DEFINES/flags.dm
@@ -56,14 +56,16 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define HTML_USE_INITAL_ICON_1 (1<<13)
/// Prevents direct access for anything in the contents of this atom.
#define NO_DIRECT_ACCESS_FROM_CONTENTS_1 (1<<14)
+/// Is this object currently processing in the atmos object list?
+#define ATMOS_IS_PROCESSING_1 (1<<15)
//turf-only flags. These use flags_1 too.
// These exist to cover /turf and /area at the same time
-#define NOJAUNT_1 (1<<15)
-#define UNUSED_RESERVATION_TURF_1 (1<<16)
-#define CAN_BE_DIRTY_1 (1<<17) //! If a turf can be made dirty at roundstart. This is also used in areas.
-#define NO_LAVA_GEN_1 (1<<18) //! Blocks lava rivers being generated on the turf
-#define NO_RUINS_1 (1<<19) //! Blocks ruins spawning on the turf
+#define NOJAUNT_1 (1<<17)
+#define UNUSED_RESERVATION_TURF_1 (1<<18)
+#define CAN_BE_DIRTY_1 (1<<19) //! If a turf can be made dirty at roundstart. This is also used in areas.
+#define NO_LAVA_GEN_1 (1<<20) //! Blocks lava rivers being generated on the turf
+#define NO_RUINS_1 (1<<21) //! Blocks ruins spawning on the turf
// Update flags for [/atom/proc/update_appearance]
/// Update the atom's name
diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index 2237790303e24..c7e3ef6b6713c 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -53,6 +53,7 @@
#define CATWALK_LAYER 2.51
#define LOW_SIGIL_LAYER 2.52
#define SIGIL_LAYER 2.54
+#define HIGH_PIPE_LAYER 2.55
#define HIGH_SIGIL_LAYER 2.56
#define BELOW_OPEN_DOOR_LAYER 2.6
@@ -150,6 +151,9 @@
/// Plane for balloon text (text that fades up)
#define BALLOON_CHAT_PLANE 651
+#define ATMOS_GROUP_PLANE 652
+#define ATMOS_GROUP_LAYER 652
+
///--------------- FULLSCREEN IMAGES ------------
#define FLASH_LAYER 1
#define FULLSCREEN_LAYER 2
diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm
index e1e49b411afb4..fe7ec7061a828 100644
--- a/code/__DEFINES/machines.dm
+++ b/code/__DEFINES/machines.dm
@@ -220,12 +220,6 @@ GLOBAL_LIST_INIT(approved_status_pictures, list(
#define CHUNK_SIZE 16 // Only chunk sizes that are to the power of 2. E.g: 2, 4, 8, 16, etc..
-// Circulator defines
-// ---------------------------------------------------
-
-#define CIRCULATOR_HOT 0
-#define CIRCULATOR_COLD 1
-
// Particle Accelerator defines
// ---------------------------------------------------
diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm
index e447eb3149ed0..e7a3b86930230 100644
--- a/code/__DEFINES/maths.dm
+++ b/code/__DEFINES/maths.dm
@@ -1,3 +1,9 @@
+// Remove these once we have Byond implementation.
+#define ISNAN(a) (!(a==a))
+#define ISINF(a) (!ISNAN(a) && ISNAN(a-a))
+#define IS_INF_OR_NAN(a) (ISNAN(a-a))
+// Aight dont remove the rest
+
// Credits to Nickr5 for the useful procs I've taken from his library resource.
// This file is quadruple wrapped for your pleasure
// (
@@ -99,7 +105,7 @@
. = list()
var/d = b*b - 4 * a * c
var/bottom = 2 * a
- if(d < 0)
+ if(d < 0 || IS_INF_OR_NAN(d) || IS_INF_OR_NAN(bottom))
return
var/root = sqrt(d)
. += (-b + root) / bottom
diff --git a/code/__DEFINES/radio.dm b/code/__DEFINES/radio.dm
index 1c74f6276cc45..66f3a5f481df0 100644
--- a/code/__DEFINES/radio.dm
+++ b/code/__DEFINES/radio.dm
@@ -80,18 +80,14 @@
#define FREQ_EXPLORATION 1361 //! Exploration comms frequency, cyan
#define FREQ_STATUS_DISPLAYS 1435
-#define FREQ_ATMOS_ALARMS 1437 //! air alarms <-> alert computers
-#define FREQ_ATMOS_CONTROL 1439 //! air alarms <-> vents and scrubbers
#define MIN_FREQ 1441 // ------------------------------------------------------
// Only the 1441 to 1489 range is freely available for general conversation.
// This represents 1/8th of the available spectrum.
-#define FREQ_ATMOS_STORAGE 1441
#define FREQ_NAV_BEACON 1445
#define FREQ_AI_PRIVATE 1447 //! AI private comms frequency, magenta
#define FREQ_PRESSURE_PLATE 1447
-#define FREQ_AIRLOCK_CONTROL 1449
#define FREQ_ELECTROPACK 1449
#define FREQ_MAGNETS 1449
#define FREQ_LOCATOR_IMPLANT 1451
@@ -109,10 +105,7 @@
#define TRANSMISSION_SUPERSPACE 3 //! reaches independent (CentCom) radios only
// Filter types, used as an optimization to avoid unnecessary proc calls.
-#define RADIO_TO_AIRALARM "to_airalarm"
-#define RADIO_FROM_AIRALARM "from_airalarm"
#define RADIO_SIGNALER "signaler"
-#define RADIO_ATMOSIA "atmosia"
#define RADIO_AIRLOCK "airlock"
#define RADIO_MAGNETS "magnets"
#define RADIO_XENOA "xenoa_radio"
diff --git a/code/__DEFINES/reactions.dm b/code/__DEFINES/reactions.dm
index fd0dc83d6ad36..158cbdcb4c6eb 100644
--- a/code/__DEFINES/reactions.dm
+++ b/code/__DEFINES/reactions.dm
@@ -7,6 +7,7 @@
#define PLASMA_MINIMUM_OXYGEN_PLASMA_RATIO 30
#define FIRE_CARBON_ENERGY_RELEASED 100000 //! Amount of heat released per mole of burnt carbon into the tile
#define FIRE_HYDROGEN_ENERGY_RELEASED 280000 //! Amount of heat released per mole of burnt hydrogen and/or tritium(hydrogen isotope)
+#define FIRE_HYDROGEN_ENERGY_WEAK 280000
#define FIRE_PLASMA_ENERGY_RELEASED 3000000 //! Amount of heat released per mole of burnt plasma into the tile
// Water Vapor:
@@ -57,3 +58,8 @@
#define FUSION_RAD_MIDPOINT 15 //! If you decrease this by one, the fusion rads will *triple* and vice versa
#define FUSION_MIDDLE_ENERGY_REFERENCE 1e6 //! This number is deceptively dangerous; sort of tied to TOROID_CALCULATED_THRESHOLD
#define FUSION_BUFFER_DIVISOR 1 //! Increase this to cull unrobust fusions faster
+
+#define PRIORITY_PRE_FORMATION 1
+#define PRIORITY_FORMATION 2
+#define PRIORITY_POST_FORMATION 3
+#define PRIORITY_FIRE 4
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 8e7c24ca5a0ae..beef96b8296b5 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -217,7 +217,6 @@
#define FIRE_PRIORITY_ASSETS 105
#define FIRE_PRIORITY_TGUI 110
#define FIRE_PRIORITY_TICKER 200
-#define FIRE_PRIORITY_ATMOS_ADJACENCY 300
#define FIRE_PRIORITY_CHAT 400
#define FIRE_PRIORITY_RUNECHAT 410
#define FIRE_PRIORITY_OVERLAYS 500
@@ -238,25 +237,6 @@
#define RUNLEVELS_DEFAULT (RUNLEVEL_SETUP | RUNLEVEL_GAME | RUNLEVEL_POSTGAME)
-// SSair run section
-#define SSAIR_PIPENETS 1
-#define SSAIR_ATMOSMACHINERY 2
-#define SSAIR_EXCITEDGROUPS 3
-#define SSAIR_HIGHPRESSURE 4
-#define SSAIR_HOTSPOTS 5
-#define SSAIR_TURF_CONDUCTION 6
-#define SSAIR_REBUILD_PIPENETS 7
-#define SSAIR_EQUALIZE 8
-#define SSAIR_ACTIVETURFS 9
-#define SSAIR_TURF_POST_PROCESS 10
-#define SSAIR_FINALIZE_TURFS 11
-#define SSAIR_ATMOSMACHINERY_AIR 12
-#define SSAIR_DEFERRED_AIRS 13
-
-// Explosion Subsystem subtasks
-#define SSEXPLOSIONS_MOVABLES 1
-#define SSEXPLOSIONS_TURFS 2
-#define SSEXPLOSIONS_THROWS 3
//SSticker.current_state values
/// Game is loading
@@ -303,6 +283,25 @@
*/
#define addtimer(args...) _addtimer(args, file = __FILE__, line = __LINE__)
+// Air subsystem subtasks
+#define SSAIR_PIPENETS 1
+#define SSAIR_ATMOSMACHINERY 2
+#define SSAIR_ACTIVETURFS 3
+#define SSAIR_HOTSPOTS 4
+#define SSAIR_EXCITEDGROUPS 5
+#define SSAIR_HIGHPRESSURE 6
+#define SSAIR_SUPERCONDUCTIVITY 7
+#define SSAIR_PROCESS_ATOMS 8
+
+//Pipeline rebuild helper defines, these suck but it'll do for now
+#define SSAIR_REBUILD_PIPELINE 1
+#define SSAIR_REBUILD_QUEUE 2
+
+// Explosion Subsystem subtasks
+#define SSEXPLOSIONS_MOVABLES 1
+#define SSEXPLOSIONS_TURFS 2
+#define SSEXPLOSIONS_THROWS 3
+
// Subsystem delta times or tickrates, in seconds. I.e, how many seconds in between each process() call for objects being processed by that subsystem.
// Only use these defines if you want to access some other objects processing delta_time, otherwise use the delta_time that is sent as a parameter to process()
#define SSMACHINES_DT (SSmachines.wait/10)
diff --git a/code/__HELPERS/areas.dm b/code/__HELPERS/areas.dm
index 9e81c7044de12..33721fb74b428 100644
--- a/code/__HELPERS/areas.dm
+++ b/code/__HELPERS/areas.dm
@@ -11,7 +11,7 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
// break_if_found is a typecache of turf/area types to return false if found
// Please keep this proc type agnostic. If you need to restrict it do it elsewhere or add an arg.
/proc/detect_room(turf/origin, list/break_if_found)
- if(isclosedturf(origin))
+ if(origin.blocks_air)
return list(origin)
. = list()
@@ -34,7 +34,7 @@ GLOBAL_LIST_INIT(typecache_powerfailure_safe_areas, typecacheof(/area/engine/eng
if(break_if_found[checkT.type] || break_if_found[checkT.loc.type])
return FALSE
var/static/list/cardinal_cache = list("[NORTH]"=TRUE, "[EAST]"=TRUE, "[SOUTH]"=TRUE, "[WEST]"=TRUE)
- if(!cardinal_cache["[dir]"] || isclosedturf(checkT) || !CANATMOSPASS(sourceT, checkT))
+ if(!cardinal_cache["[dir]"] || checkT.blocks_air || !CANATMOSPASS(sourceT, checkT, FALSE))
continue
found_turfs += checkT // Since checkT is connected, add it to the list to be processed
diff --git a/code/__HELPERS/atmospherics.dm b/code/__HELPERS/atmospherics.dm
new file mode 100644
index 0000000000000..87d1b924ca7f5
--- /dev/null
+++ b/code/__HELPERS/atmospherics.dm
@@ -0,0 +1,82 @@
+/proc/molar_cmp_less_than(a,b,epsilon = MAXIMUM_ERROR_GAS_REMOVAL)
+ return (a < (b + epsilon))
+
+/proc/molar_cmp_greater_than(a,b,epsilon = MAXIMUM_ERROR_GAS_REMOVAL)
+ return ((a + epsilon) > b)
+
+/proc/molar_cmp_equals(a,b,epsilon = MAXIMUM_ERROR_GAS_REMOVAL)
+ return (((a + epsilon) > b) && ((a - epsilon) < b))
+
+/** A simple rudimentary gasmix to information list converter. Can be used for UIs.
+ * Args:
+ * * gasmix: [/datum/gas_mixture]
+ * * name: String used to name the list, optional.
+ * Returns: A list parsed_gasmixes with the following structure:
+ * - parsed_gasmixes Value: Assoc List Desc: The thing we return
+ * -- Key: name Value: String Desc: Gasmix Name
+ * -- Key: temperature Value: Number Desc: Temperature in kelvins
+ * -- Key: volume Value: Number Desc: Volume in liters
+ * -- Key: pressure Value: Number Desc: Pressure in kPa
+ * -- Key: ref Value: String Desc: The reference for the instantiated gasmix.
+ * -- Key: gases Value: Numbered list Desc: List of gasses in our gasmix
+ * --- Key: 1 Value: String Desc: gas id var from the gas
+ * --- Key: 2 Value: String Desc: Human readable gas name.
+ * --- Key: 3 Value: Number Desc: Mol amount of the gas.
+ * -- Key: gases Value: Numbered list Desc: Assoc list of reactions that occur inside.
+ * --- Key: 1 Value: String Desc: reaction id var from the gas.
+ * --- Key: 2 Value: String Desc: Human readable reaction name.
+ * --- Key: 3 Value: Number Desc: The number associated with the reaction.
+ * Returned list should always be filled with keys even if value are nulls.
+ */
+/proc/gas_mixture_parser(datum/gas_mixture/gasmix, name)
+ . = list(
+ "gases" = list(),
+ "reactions" = list(),
+ "name" = format_text(name),
+ "total_moles" = null,
+ "temperature" = null,
+ "volume"= null,
+ "pressure"= null,
+ "reference" = null,
+ )
+ if(!gasmix)
+ return
+ for(var/gas_path in gasmix.gases)
+ .["gases"] += list(list(
+ gasmix.gases[gas_path][GAS_META][META_GAS_ID],
+ gasmix.gases[gas_path][GAS_META][META_GAS_NAME],
+ gasmix.gases[gas_path][MOLES],
+ ))
+ for(var/datum/gas_reaction/reaction_result as anything in gasmix.reaction_results)
+ .["reactions"] += list(list(
+ initial(reaction_result.id),
+ initial(reaction_result.name),
+ gasmix.reaction_results[reaction_result],
+ ))
+ .["total_moles"] = gasmix.total_moles()
+ .["temperature"] = gasmix.temperature
+ .["volume"] = gasmix.volume
+ .["pressure"] = gasmix.return_pressure()
+ .["reference"] = REF(gasmix)
+
+/proc/extract_id_tags(list/objects)
+ var/list/tags = list()
+
+ for (var/obj/object as anything in objects)
+ tags += object.id_tag
+
+ return tags
+
+/proc/find_by_id_tag(list/objects, id_tag)
+ for (var/obj/object as anything in objects)
+ if (object.id_tag == id_tag)
+ return object
+
+ return null
+
+/proc/print_gas_mixture(datum/gas_mixture/gas_mixture)
+ var/message = "TEMPERATURE: [gas_mixture.temperature]K, QUANTITY: [gas_mixture.total_moles()] mols, VOLUME: [gas_mixture.volume]L; "
+ for(var/key in gas_mixture.gases)
+ var/list/gaslist = gas_mixture.gases[key]
+ message += "[gaslist[GAS_META][META_GAS_ID]]=[gaslist[MOLES]] mols;"
+ return message
diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm
index 9198ea42d2bb7..5dea423cfbc89 100644
--- a/code/__HELPERS/global_lists.dm
+++ b/code/__HELPERS/global_lists.dm
@@ -147,7 +147,6 @@ GLOBAL_LIST_INIT(WALLITEMS_INTERIOR, typecacheof(list(
/obj/structure/noticeboard,
/obj/machinery/button,
/obj/machinery/computer/security/telescreen,
- /obj/machinery/embedded_controller/radio/simple_vent_controller,
/obj/item/storage/secure/safe,
/obj/machinery/flasher,
/obj/machinery/keycard_auth,
diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm
index 15dc3592a4de5..5f4a2e1b9f455 100644
--- a/code/__HELPERS/names.dm
+++ b/code/__HELPERS/names.dm
@@ -262,3 +262,36 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex)
return "a rolling pin"
else
return "something... but the gods didn't set this up right (Please report this bug)"
+
+/**
+ * Generate a name devices
+ *
+ * Creates a randomly generated tag or name for devices or anything really
+ * it keeps track of a special list that makes sure no name is used more than
+ * once
+ *
+ * args:
+ * * len (int)(Optional) Default=5 The length of the name
+ * * prefix (string)(Optional) static text in front of the random name
+ * * postfix (string)(Optional) static text in back of the random name
+ * Returns (string) The generated name
+ */
+/proc/assign_random_name(len=5, prefix="", postfix="")
+ //DO NOT REMOVE NAMES HERE UNLESS YOU KNOW WHAT YOU'RE DOING
+ //All names already used
+ var/static/list/used_names = list()
+
+ var/static/valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+ var/list/new_name = list()
+ var/text
+ // machine id's should be fun random chars hinting at a larger world
+ do
+ new_name.Cut()
+ new_name += prefix
+ for(var/i = 1 to len)
+ new_name += valid_chars[rand(1,length(valid_chars))]
+ new_name += postfix
+ text = new_name.Join()
+ while(used_names[text])
+ used_names[text] = TRUE
+ return text
diff --git a/code/__HELPERS/piping_colors_lists.dm b/code/__HELPERS/piping_colors_lists.dm
new file mode 100644
index 0000000000000..b934c0bc4dddb
--- /dev/null
+++ b/code/__HELPERS/piping_colors_lists.dm
@@ -0,0 +1,31 @@
+///All colors available to pipes and atmos components
+GLOBAL_LIST_INIT(pipe_paint_colors, list(
+ "grey" = COLOR_VERY_LIGHT_GRAY,
+ "blue" = COLOR_BLUE,
+ "red" = COLOR_RED,
+ "green" = COLOR_VIBRANT_LIME,
+ "orange" = COLOR_TAN_ORANGE,
+ "cyan" = COLOR_CYAN,
+ "dark" = COLOR_DARK,
+ "yellow" = COLOR_YELLOW,
+ "brown" = COLOR_BROWN,
+ "pink" = COLOR_LIGHT_PINK,
+ "purple" = COLOR_PURPLE,
+ "violet" = COLOR_STRONG_VIOLET
+))
+
+///List that sorts the colors and is used for setting up the pipes layer so that they overlap correctly
+GLOBAL_LIST_INIT(pipe_colors_ordered, sort_list(list(
+ COLOR_AMETHYST = -6,
+ COLOR_BLUE = -5,
+ COLOR_BROWN = -4,
+ COLOR_CYAN = -3,
+ COLOR_DARK = -2,
+ COLOR_VIBRANT_LIME = -1,
+ COLOR_VERY_LIGHT_GRAY = 0,
+ COLOR_TAN_ORANGE = 1,
+ COLOR_PURPLE = 2,
+ COLOR_RED = 3,
+ COLOR_STRONG_VIOLET = 4,
+ COLOR_YELLOW = 5
+)))
diff --git a/code/__HELPERS/turfs.dm b/code/__HELPERS/turfs.dm
index 5a932b02c8ada..9f953ac259418 100644
--- a/code/__HELPERS/turfs.dm
+++ b/code/__HELPERS/turfs.dm
@@ -400,13 +400,13 @@ Turf and target are separate in case you want to teleport some distance from a t
if(QDELETED(air))
return FALSE
// Can most things breathe?
- for(var/id in air.get_gases())
+ for(var/id in air.gases)
if(id in GLOB.hardcoded_gases)
continue
return FALSE
- if(air.get_moles(GAS_O2) < 16 || air.get_moles(GAS_PLASMA) || air.get_moles(GAS_CO2) >= 10)
+ if(GET_MOLES(/datum/gas/oxygen, air) < 16 || GET_MOLES(/datum/gas/plasma, air) || GET_MOLES(/datum/gas/carbon_dioxide, air) >= 10)
return FALSE
- var/temperature = air.return_temperature()
+ var/temperature = air.temperature
if(temperature <= 270 || temperature >= 360)
return FALSE
var/pressure = air.return_pressure()
diff --git a/code/__HELPERS/type_processing.dm b/code/__HELPERS/type_processing.dm
index a5d006113a368..5a7162ecb7f7a 100644
--- a/code/__HELPERS/type_processing.dm
+++ b/code/__HELPERS/type_processing.dm
@@ -59,3 +59,6 @@
if(findtext("[key]", filter) || findtext("[value]", filter))
matches[key] = value
return matches
+
+/proc/return_typenames(type)
+ return splittext("[type]", "/")
diff --git a/code/__byond_version_compat.dm b/code/__byond_version_compat.dm
index fc667f8b9dd82..692f8e2feead4 100644
--- a/code/__byond_version_compat.dm
+++ b/code/__byond_version_compat.dm
@@ -27,9 +27,12 @@
// AnturK says there are issues with savefiles that would make it dangerous to test merge,
// and so this check is in place to stop serious damage.
// That being said, if you really are ready, you can give YES_I_WANT_515 to TGS.
+
+/* Temporarily commented out due to LINDA being updated.
#if !defined(YES_I_WANT_515) && DM_VERSION >= 515
#error We do not yet completely support BYOND 515.
#endif
+*/
// 515 split call for external libraries into call_ext
#if DM_VERSION < 515
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index ce997dd8a79f9..b642f8035e1ee 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -28,7 +28,8 @@
#endif //ifdef REFERENCE_TRACKING
-//#define VISUALIZE_ACTIVE_TURFS //Highlights atmos active turfs in green
+#define VISUALIZE_ACTIVE_TURFS //Highlights atmos active turfs in green
+#define TRACK_MAX_SHARE //Allows max share tracking, for use in the atmos debugging ui
#endif //ifdef TESTING
/// Enables BYOND TRACY, which allows profiling using Tracy.
@@ -101,11 +102,14 @@
#endif
//Update this whenever the byond version is stable so people stop updating to hilariously broken versions
+//One LINDA update later, done! ...maybe
+/*
#define MAX_COMPILER_VERSION 514
#define MAX_COMPILER_BUILD 1589
#if DM_VERSION > MAX_COMPILER_VERSION || DM_BUILD > MAX_COMPILER_BUILD
#warn WARNING: Your BYOND version is over the recommended version (514.1589)! Stability is not guaranteed.
#endif
+*/
//Log the full sendmaps profile on 514.1556+, any earlier and we get bugs or it not existing
#if DM_VERSION >= 514 && DM_BUILD >= 1556
#define SENDMAPS_PROFILE
@@ -138,24 +142,11 @@
#define CBT
#endif
+
+//Someone else should probably update this once LINDA is fully merged. Probably Bacon or Crossed.
#if defined(OPENDREAM) && !defined(CIBUILDING)
#error Compiling BeeStation in OpenDream is unsupported due to BeeStation's dependence on the auxtools DLL to function.
#elif !defined(CBT) && !defined(SPACEMAN_DMM) && !defined(FASTDMM) && !defined(CIBUILDING)
#warn Building with Dream Maker is no longer supported and will result in missing interface files.
#warn Switch to VSCode and when prompted install the recommended extensions, you can then either use the UI or press Ctrl+Shift+B to build the codebase.
#endif
-
-#define AUXMOS (world.system_type == MS_WINDOWS ? "auxtools/auxmos.dll" : __detect_auxmos())
-
-/proc/__detect_auxmos()
- var/static/auxmos_path
- if(!auxmos_path)
- if (fexists("./libauxmos.so"))
- auxmos_path = "./libauxmos.so"
- else if (fexists("./auxtools/libauxmos.so"))
- auxmos_path = "./auxtools/libauxmos.so"
- else if (fexists("[world.GetConfig("env", "HOME")]/.byond/bin/libauxmos.so"))
- auxmos_path = "[world.GetConfig("env", "HOME")]/.byond/bin/libauxmos.so"
- else
- CRASH("Could not find libauxmos.so")
- return auxmos_path
diff --git a/code/_globalvars/lists/color.dm b/code/_globalvars/lists/color.dm
new file mode 100644
index 0000000000000..26c0d89b9f188
--- /dev/null
+++ b/code/_globalvars/lists/color.dm
@@ -0,0 +1,7 @@
+GLOBAL_LIST_INIT(contrast_colors, list(
+ COLOR_BLACK,
+ COLOR_DARK_CYAN,
+ COLOR_RED,
+ COLOR_TAN_ORANGE,
+ COLOR_VIOLET,
+))
diff --git a/code/_globalvars/turf.dm b/code/_globalvars/turf.dm
index ab277cbd05521..24f6607267afd 100644
--- a/code/_globalvars/turf.dm
+++ b/code/_globalvars/turf.dm
@@ -3,7 +3,7 @@
*/
GLOBAL_LIST_INIT(default_turf_damage, list("damaged1", "damaged2", "damaged3", "damaged4", "damaged5", "damaged6", "damaged7"))
-GLOBAL_LIST_INIT(default_turf_burn, list("damaged1", "damaged2", "damaged3", "damaged4"))
+GLOBAL_LIST_INIT(default_burn_turf, list("damaged1", "damaged2", "damaged3", "damaged4"))
GLOBAL_LIST_INIT(wood_turf_damage, list("damaged_wood1", "damaged_wood2"))
GLOBAL_LIST_INIT(wood_big_turf_damage, list("damaged_woodbig1", "damaged_woodbig2"))
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index dd5f5e8722411..1ad6f9edaa258 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -87,6 +87,10 @@
client.screen -= alert
qdel(alert)
+// Proc to check for an alert
+/mob/proc/has_alert(category)
+ return !isnull(alerts[category])
+
/atom/movable/screen/alert
icon = 'icons/hud/screen_alert.dmi'
icon_state = "default"
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 80a0c4896153b..e596b39c41f44 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -69,6 +69,8 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
// subtypes can override this to force a specific UI style
var/ui_style
+ /// If this client is being shown atmos debug overlays or not
+ var/atmos_debug_overlays = FALSE
/datum/hud/New(mob/owner)
mymob = owner
diff --git a/code/_onclick/hud/rendering/plane_master.dm b/code/_onclick/hud/rendering/plane_master.dm
index b40b76a38d63d..60fcc271a3ee8 100644
--- a/code/_onclick/hud/rendering/plane_master.dm
+++ b/code/_onclick/hud/rendering/plane_master.dm
@@ -277,3 +277,10 @@
. = ..()
add_filter("glow", 1, list(type = "bloom", threshold = rgb(128, 128, 128), size = 2, offset = 1, alpha = 255))
add_filter("mask", 2, alpha_mask_filter(render_source = "blind_fullscreen_overlay"))
+
+/obj/screen/plane_master/excited_turfs
+ name = "atmos excited turfs"
+ plane = ATMOS_GROUP_PLANE
+ appearance_flags = PLANE_MASTER
+ blend_mode = BLEND_OVERLAY
+ alpha = 0
diff --git a/code/controllers/subsystem/adjacent_air.dm b/code/controllers/subsystem/adjacent_air.dm
deleted file mode 100644
index 200dbc3e30de5..0000000000000
--- a/code/controllers/subsystem/adjacent_air.dm
+++ /dev/null
@@ -1,54 +0,0 @@
-SUBSYSTEM_DEF(adjacent_air)
- name = "Atmos Adjacency"
- flags = SS_BACKGROUND
- runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
- wait = 10
- priority = FIRE_PRIORITY_ATMOS_ADJACENCY
- var/list/queue = list()
- var/list/disable_queue = list()
-
-/datum/controller/subsystem/adjacent_air/stat_entry()
-#ifdef TESTING
- . = ..("P:[length(queue)], S:[GLOB.atmos_adjacent_savings[1]], T:[GLOB.atmos_adjacent_savings[2]]")
-#else
- . = ..("P:[length(queue)]")
-#endif
-
-/datum/controller/subsystem/adjacent_air/Initialize()
- while(length(queue))
- fire(mc_check = FALSE)
- return SS_INIT_SUCCESS
-
-/datum/controller/subsystem/adjacent_air/fire(resumed = FALSE, mc_check = TRUE)
- if(SSair.thread_running())
- pause()
- return
-
- var/list/disable_queue = src.disable_queue
-
- while (length(disable_queue))
- var/turf/terf = disable_queue[1]
- var/arg = disable_queue[terf]
- disable_queue.Cut(1,2)
-
- terf.ImmediateDisableAdjacency(arg)
-
- if(mc_check)
- if(MC_TICK_CHECK)
- return
- else
- CHECK_TICK
-
- var/list/queue = src.queue
-
- while (length(queue))
- var/turf/currT = queue[1]
- queue.Cut(1,2)
-
- currT.ImmediateCalculateAdjacentTurfs()
-
- if(mc_check)
- if(MC_TICK_CHECK)
- break
- else
- CHECK_TICK
diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm
index 94c3f34263af0..01e2d6d011828 100644
--- a/code/controllers/subsystem/air.dm
+++ b/code/controllers/subsystem/air.dm
@@ -6,64 +6,54 @@ SUBSYSTEM_DEF(air)
flags = SS_BACKGROUND
runlevels = RUNLEVEL_GAME | RUNLEVEL_POSTGAME
+ var/cached_cost = 0
+
+ var/cost_atoms = 0
var/cost_turfs = 0
+ var/cost_hotspots = 0
var/cost_groups = 0
var/cost_highpressure = 0
- var/cost_deferred_airs
- var/cost_hotspots = 0
- var/cost_post_process = 0
var/cost_superconductivity = 0
var/cost_pipenets = 0
- var/cost_rebuilds = 0
var/cost_atmos_machinery = 0
- var/cost_equalize = 0
- var/thread_wait_ticks = 0
- var/cur_thread_wait_ticks = 0
- ///The last time the subsystem completely processed
- var/last_complete_process = 0
-
- var/low_pressure_turfs = 0
- var/high_pressure_turfs = 0
-
- var/num_group_turfs_processed = 0
- var/num_equalize_processed = 0
+ var/cost_rebuilds = 0
+ var/cost_adjacent = 0
+ var/list/excited_groups = list()
+ var/list/active_turfs = list()
var/list/hotspots = list()
var/list/networks = list()
- var/list/pipenets_needing_rebuilt = list()
- var/list/deferred_airs = list()
- var/max_deferred_airs = 0
+ var/list/rebuild_queue = list()
+ //Subservient to rebuild queue
+ var/list/expansion_queue = list()
+ /// List of turfs to recalculate adjacent turfs on before processing
+ var/list/adjacent_rebuild = list()
+ /// A list of machines that will be processed when currentpart == SSAIR_ATMOSMACHINERY. Use SSair.begin_processing_machine and SSair.stop_processing_machine to add and remove machines.
var/list/obj/machinery/atmos_machinery = list()
- var/list/obj/machinery/atmos_air_machinery = list()
- var/list/pipe_init_dirs_cache = list()
+ var/list/pipe_init_dirs_cache = list()
//atmos singletons
var/list/gas_reactions = list()
+ var/list/atmos_gen
+ var/list/planetary = list() //Lets cache static planetary mixes
+ /// List of gas string -> canonical gas mixture
+ var/list/strings_to_mix = list()
+
//Special functions lists
+ var/list/turf/active_super_conductivity = list()
var/list/turf/open/high_pressure_delta = list()
+ var/list/atom_process = list()
-
+ /// A cache of objects that perisists between processing runs when resumed == TRUE. Dangerous, qdel'd objects not cleared from this may cause runtimes on processing.
var/list/currentrun = list()
- var/currentpart = SSAIR_REBUILD_PIPENETS
+ var/currentpart = SSAIR_PIPENETS
var/map_loading = TRUE
+ var/list/queued_for_activation
+ var/display_all_groups = FALSE
- var/log_explosive_decompression = TRUE // If things get spammy, admemes can turn this off.
-
- // Max number of turfs equalization will grab.
- var/equalize_turf_limit = 10
- // Max number of turfs to look for a space turf, and max number of turfs that will be decompressed.
- var/equalize_hard_turf_limit = 2000
- // Whether equalization should be enabled at all.
- var/equalize_enabled = FALSE
- // Whether turf-to-turf heat exchanging should be enabled.
- var/heat_enabled = FALSE
- // Max number of times process_turfs will share in a tick.
- var/share_max_steps = 3
- // Excited group processing will try to equalize groups with total pressure difference less than this amount.
- var/excited_group_pressure_goal = 1
-
+ // Supercruise Z-pausing
var/list/paused_z_levels //Paused z-levels will not add turfs to active
var/list/unpausing_z_levels = list()
var/list/unpause_processing = list()
@@ -71,72 +61,53 @@ SUBSYSTEM_DEF(air)
var/list/pausing_z_levels = list()
var/list/pause_processing = list()
+ ///The last time the subsystem completely processed
+ var/last_complete_process = 0
+
+
/datum/controller/subsystem/air/stat_entry(msg)
msg += "C:{"
- msg += "HP:[round(cost_highpressure,1)]|"
+ msg += "AT:[round(cost_turfs,1)]|"
msg += "HS:[round(cost_hotspots,1)]|"
- msg += "HE:[round(heat_process_time(),1)]|"
+ msg += "EG:[round(cost_groups,1)]|"
+ msg += "HP:[round(cost_highpressure,1)]|"
msg += "SC:[round(cost_superconductivity,1)]|"
msg += "PN:[round(cost_pipenets,1)]|"
- msg += "AM:[round(cost_atmos_machinery,1)]"
+ msg += "AM:[round(cost_atmos_machinery,1)]|"
+ msg += "AO:[round(cost_atoms, 1)]|"
+ msg += "RB:[round(cost_rebuilds,1)]|"
+ msg += "AJ:[round(cost_adjacent,1)]|"
msg += "} "
- msg += "TC:{"
- msg += "AT:[round(cost_turfs,1)]|"
- msg += "EG:[round(cost_groups,1)]|"
- msg += "EQ:[round(cost_equalize,1)]|"
- msg += "PO:[round(cost_post_process,1)]"
- msg += "}"
- msg += "TH:[round(thread_wait_ticks,1)]|"
+ msg += "AT:[active_turfs.len]|"
msg += "HS:[hotspots.len]|"
- msg += "PN:[networks.len]|"
+ msg += "EG:[excited_groups.len]|"
msg += "HP:[high_pressure_delta.len]|"
- msg += "HT:[high_pressure_turfs]|"
- msg += "LT:[low_pressure_turfs]|"
- msg += "ET:[num_equalize_processed]|"
- msg += "GT:[num_group_turfs_processed]|"
- msg += "DF:[max_deferred_airs]|"
- msg += "GA:[get_amt_gas_mixes()]|"
- msg += "MG:[get_max_gas_mixes()]"
+ msg += "SC:[active_super_conductivity.len]|"
+ msg += "PN:[networks.len]|"
+ msg += "AM:[atmos_machinery.len]|"
+ msg += "AO:[atom_process.len]|"
+ msg += "RB:[rebuild_queue.len]|"
+ msg += "EP:[expansion_queue.len]|"
+ msg += "AJ:[adjacent_rebuild.len]|"
+ msg += "AT/MS:[round((cost ? active_turfs.len/cost : 0),0.1)]"
return ..()
-/datum/controller/subsystem/air/Initialize()
+
+/datum/controller/subsystem/air/Initialize(timeofday)
map_loading = FALSE
+ gas_reactions = init_gas_reactions()
setup_allturfs()
setup_atmos_machinery()
setup_pipenets()
- gas_reactions = init_gas_reactions()
- auxtools_update_reactions()
+ setup_turf_visuals()
+ process_adjacent_rebuild()
return SS_INIT_SUCCESS
-/datum/controller/subsystem/air/proc/extools_update_ssair()
-
-/datum/controller/subsystem/air/proc/auxtools_update_reactions()
-
-/proc/reset_all_air()
- SSair.can_fire = 0
- message_admins("Air reset begun.")
- for(var/turf/open/T in world)
- T.Initalize_Atmos(0)
- CHECK_TICK
- message_admins("Air reset done.")
- SSair.can_fire = 1
-
-/datum/controller/subsystem/air/proc/thread_running()
- return FALSE
-
-/proc/fix_corrupted_atmos()
-
-/datum/admins/proc/fixcorruption()
- set category = "Debug"
- set desc="Fixes air that has weird NaNs (-1.#IND and such). Hopefully."
- set name="Fix Infinite Air"
- fix_corrupted_atmos()
-
-/datum/controller/subsystem/air/fire(resumed = 0)
+/datum/controller/subsystem/air/fire(resumed = FALSE)
var/timer = TICK_USAGE_REAL
- //If we have unpausing z-level, process them first
+ //If we have unpausing z-level, process them first
if(length(unpausing_z_levels) && !length(unpause_processing))
var/z_value = unpausing_z_levels[1]
unpausing_z_levels.Remove(z_value)
@@ -162,7 +133,7 @@ SUBSYSTEM_DEF(air)
while(length(pause_processing))
var/turf/T = pause_processing[length(pause_processing)]
- T.ImmediateDisableAdjacency()
+ T.immediate_disable_adjacency()
//Goodbye
pause_processing.len --
//We overran this tick, stop processing
@@ -171,164 +142,166 @@ SUBSYSTEM_DEF(air)
if(MC_TICK_CHECK)
return
- if(currentpart == SSAIR_REBUILD_PIPENETS)
+ //Rebuilds can happen at any time, so this needs to be done outside of the normal system
+ cost_rebuilds = 0
+ cost_adjacent = 0
+
+ // We need to have a solid setup for turfs before fire, otherwise we'll get massive runtimes and strange behavior
+ if(length(adjacent_rebuild))
timer = TICK_USAGE_REAL
- var/list/pipenet_rebuilds = pipenets_needing_rebuilt
- for(var/thing in pipenet_rebuilds)
- var/obj/machinery/atmospherics/AT = thing
- if(!istype(AT))
- continue
- AT.build_network()
- cost_rebuilds = MC_AVERAGE(cost_rebuilds, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
- pipenets_needing_rebuilt.Cut()
+ process_adjacent_rebuild()
+ //This does mean that the apperent rebuild costs fluctuate very quickly, this is just the cost of having them always process, no matter what
+ cost_adjacent = TICK_USAGE_REAL - timer
+ if(state != SS_RUNNING)
+ return
+
+ // Every time we fire, we want to make sure pipenets are rebuilt. The game state could have changed between each fire() proc call
+ // and anything missing a pipenet can lead to unintended behaviour at worse and various runtimes at best.
+ if(length(rebuild_queue) || length(expansion_queue))
+ timer = TICK_USAGE_REAL
+ process_rebuilds()
+ //This does mean that the apperent rebuild costs fluctuate very quickly, this is just the cost of having them always process, no matter what
+ cost_rebuilds = TICK_USAGE_REAL - timer
if(state != SS_RUNNING)
return
- resumed = FALSE
- currentpart = SSAIR_PIPENETS
if(currentpart == SSAIR_PIPENETS || !resumed)
timer = TICK_USAGE_REAL
+ if(!resumed)
+ cached_cost = 0
process_pipenets(resumed)
- cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ cached_cost += TICK_USAGE_REAL - timer
if(state != SS_RUNNING)
return
- resumed = 0
+ cost_pipenets = MC_AVERAGE(cost_pipenets, TICK_DELTA_TO_MS(cached_cost))
+ resumed = FALSE
currentpart = SSAIR_ATMOSMACHINERY
- // This is only machinery like filters, mixers that don't interact with air
+
if(currentpart == SSAIR_ATMOSMACHINERY)
timer = TICK_USAGE_REAL
+ if(!resumed)
+ cached_cost = 0
process_atmos_machinery(resumed)
- cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ cached_cost += TICK_USAGE_REAL - timer
if(state != SS_RUNNING)
return
- resumed = 0
- currentpart = SSAIR_HIGHPRESSURE
+ cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(cached_cost))
+ resumed = FALSE
+ currentpart = SSAIR_ACTIVETURFS
- if(currentpart == SSAIR_HIGHPRESSURE)
- timer = TICK_USAGE_REAL
- process_high_pressure_delta(resumed)
- cost_highpressure = MC_AVERAGE(cost_highpressure, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
- if(state != SS_RUNNING)
- return
- resumed = 0
- currentpart = SSAIR_FINALIZE_TURFS
- // This literally just waits for the turf processing thread to finish, doesn't do anything else.
- // this is necessary cause the next step after this interacts with the air--we get consistency
- // issues if we don't wait for it, disappearing gases etc.
- if(currentpart == SSAIR_FINALIZE_TURFS)
- finish_turf_processing(resumed)
- if(state != SS_RUNNING)
- cur_thread_wait_ticks++
- return
- resumed = 0
- thread_wait_ticks = MC_AVERAGE(thread_wait_ticks, cur_thread_wait_ticks)
- cur_thread_wait_ticks = 0
- currentpart = SSAIR_DEFERRED_AIRS
- if(currentpart == SSAIR_DEFERRED_AIRS)
- timer = TICK_USAGE_REAL
- process_deferred_airs(resumed)
- cost_deferred_airs = MC_AVERAGE(cost_deferred_airs, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
- if(state != SS_RUNNING)
- return
- resumed = 0
- currentpart = SSAIR_ATMOSMACHINERY_AIR
- if(currentpart == SSAIR_ATMOSMACHINERY_AIR)
+ if(currentpart == SSAIR_ACTIVETURFS)
timer = TICK_USAGE_REAL
- process_atmos_air_machinery(resumed)
- cost_atmos_machinery = MC_AVERAGE(cost_atmos_machinery, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ if(!resumed)
+ cached_cost = 0
+ process_active_turfs(resumed)
+ cached_cost += TICK_USAGE_REAL - timer
if(state != SS_RUNNING)
return
- resumed = 0
+ cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(cached_cost))
+ resumed = FALSE
currentpart = SSAIR_HOTSPOTS
- if(currentpart == SSAIR_HOTSPOTS)
+ if(currentpart == SSAIR_HOTSPOTS) //We do this before excited groups to allow breakdowns to be independent of adding turfs while still *mostly preventing mass fires
timer = TICK_USAGE_REAL
+ if(!resumed)
+ cached_cost = 0
process_hotspots(resumed)
- cost_hotspots = MC_AVERAGE(cost_hotspots, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
- if(state != SS_RUNNING)
- return
- resumed = 0
- currentpart = heat_enabled ? SSAIR_TURF_CONDUCTION : SSAIR_ACTIVETURFS
- // Heat -- slow and of questionable usefulness. Off by default for this reason. Pretty cool, though.
- if(currentpart == SSAIR_TURF_CONDUCTION)
- timer = TICK_USAGE_REAL
- if(process_turf_heat(MC_TICK_REMAINING_MS))
- pause()
- cost_superconductivity = MC_AVERAGE(cost_superconductivity, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ cached_cost += TICK_USAGE_REAL - timer
if(state != SS_RUNNING)
return
- resumed = 0
- currentpart = SSAIR_ACTIVETURFS
- // This simply starts the turf thread. It runs in the background until the FINALIZE_TURFS step, at which point it's waited for.
- // This also happens to do all the commented out stuff below, all in a single separate thread. This is mostly so that the
- // waiting is consistent.
- if(currentpart == SSAIR_ACTIVETURFS)
+ cost_hotspots = MC_AVERAGE(cost_hotspots, TICK_DELTA_TO_MS(cached_cost))
+ resumed = FALSE
+ currentpart = SSAIR_EXCITEDGROUPS
+
+ if(currentpart == SSAIR_EXCITEDGROUPS)
timer = TICK_USAGE_REAL
- process_turfs(resumed)
- cost_turfs = MC_AVERAGE(cost_turfs, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ if(!resumed)
+ cached_cost = 0
+ process_excited_groups(resumed)
+ cached_cost += TICK_USAGE_REAL - timer
if(state != SS_RUNNING)
return
- resumed = 0
- /*
- // Monstermos and/or Putnamos--making large pressure deltas move faster
- if(currentpart == SSAIR_EQUALIZE)
+ cost_groups = MC_AVERAGE(cost_groups, TICK_DELTA_TO_MS(cached_cost))
+ resumed = FALSE
+ currentpart = SSAIR_HIGHPRESSURE
+
+ if(currentpart == SSAIR_HIGHPRESSURE)
timer = TICK_USAGE_REAL
- process_turf_equalize(resumed)
- cost_equalize = MC_AVERAGE(cost_equalize, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ if(!resumed)
+ cached_cost = 0
+ process_high_pressure_delta(resumed)
+ cached_cost += TICK_USAGE_REAL - timer
if(state != SS_RUNNING)
return
- resumed = 0
- currentpart = SSAIR_EXCITEDGROUPS
- // Making small pressure deltas equalize immediately so they don't process anymore
- if(currentpart == SSAIR_EXCITEDGROUPS)
+ cost_highpressure = MC_AVERAGE(cost_highpressure, TICK_DELTA_TO_MS(cached_cost))
+ resumed = FALSE
+ currentpart = SSAIR_SUPERCONDUCTIVITY
+
+ if(currentpart == SSAIR_SUPERCONDUCTIVITY)
timer = TICK_USAGE_REAL
- process_excited_groups(resumed)
- cost_groups = MC_AVERAGE(cost_groups, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ if(!resumed)
+ cached_cost = 0
+ process_super_conductivity(resumed)
+ cached_cost += TICK_USAGE_REAL - timer
if(state != SS_RUNNING)
return
- resumed = 0
- currentpart = SSAIR_TURF_POST_PROCESS
- // Quick multithreaded "should we display/react?" checks followed by finishing those up before the next step
- if(currentpart == SSAIR_TURF_POST_PROCESS)
+ cost_superconductivity = MC_AVERAGE(cost_superconductivity, TICK_DELTA_TO_MS(cached_cost))
+ resumed = FALSE
+ currentpart = SSAIR_PROCESS_ATOMS
+
+ if(currentpart == SSAIR_PROCESS_ATOMS)
timer = TICK_USAGE_REAL
- post_process_turfs(resumed)
- cost_post_process = MC_AVERAGE(cost_post_process, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ if(!resumed)
+ cached_cost = 0
+ process_atoms(resumed)
+ cached_cost += TICK_USAGE_REAL - timer
if(state != SS_RUNNING)
return
- resumed = 0
- currentpart = SSAIR_HOTSPOTS
- */
- currentpart = SSAIR_REBUILD_PIPENETS
+ cost_atoms = MC_AVERAGE(cost_atoms, TICK_DELTA_TO_MS(cached_cost))
+ resumed = FALSE
+
+ currentpart = SSAIR_PIPENETS
last_complete_process = world.time
+ SStgui.update_uis(SSair) //Lightning fast debugging motherfucker
/datum/controller/subsystem/air/Recover()
- thread_wait_ticks = SSair.thread_wait_ticks
- cur_thread_wait_ticks = SSair.cur_thread_wait_ticks
- low_pressure_turfs = SSair.low_pressure_turfs
- high_pressure_turfs = SSair.high_pressure_turfs
- num_group_turfs_processed = SSair.num_group_turfs_processed
- num_equalize_processed = SSair.num_equalize_processed
+ excited_groups = SSair.excited_groups
+ active_turfs = SSair.active_turfs
hotspots = SSair.hotspots
networks = SSair.networks
- pipenets_needing_rebuilt = SSair.pipenets_needing_rebuilt
- deferred_airs = SSair.deferred_airs
- max_deferred_airs = SSair.max_deferred_airs
+ rebuild_queue = SSair.rebuild_queue
+ expansion_queue = SSair.expansion_queue
+ adjacent_rebuild = SSair.adjacent_rebuild
atmos_machinery = SSair.atmos_machinery
- atmos_air_machinery = SSair.atmos_air_machinery
pipe_init_dirs_cache = SSair.pipe_init_dirs_cache
gas_reactions = SSair.gas_reactions
+ atmos_gen = SSair.atmos_gen
+ planetary = SSair.planetary
+ active_super_conductivity = SSair.active_super_conductivity
high_pressure_delta = SSair.high_pressure_delta
+ atom_process = SSair.atom_process
currentrun = SSair.currentrun
- currentpart = SSair.currentpart
- map_loading = SSair.map_loading
- log_explosive_decompression = SSair.log_explosive_decompression
- equalize_turf_limit = SSair.equalize_turf_limit
- equalize_hard_turf_limit = SSair.equalize_hard_turf_limit
- equalize_enabled = SSair.equalize_enabled
- heat_enabled = SSair.heat_enabled
- share_max_steps = SSair.share_max_steps
- excited_group_pressure_goal = SSair.excited_group_pressure_goal
- paused_z_levels = SSair.paused_z_levels
+ queued_for_activation = SSair.queued_for_activation
+
+/datum/controller/subsystem/air/proc/process_adjacent_rebuild(init = FALSE)
+ var/list/queue = adjacent_rebuild
+
+ while (length(queue))
+ var/turf/currT = queue[1]
+ var/goal = queue[currT]
+ queue.Cut(1,2)
+
+ currT.immediate_calculate_adjacent_turfs()
+ if(goal == MAKE_ACTIVE)
+ add_to_active(currT)
+ else if(goal == KILL_EXCITED)
+ add_to_active(currT, TRUE)
+
+ if(init)
+ CHECK_TICK
+ else
+ if(MC_TICK_CHECK)
+ break
/datum/controller/subsystem/air/proc/process_pipenets(resumed = FALSE)
if (!resumed)
@@ -345,115 +318,65 @@ SUBSYSTEM_DEF(air)
if(MC_TICK_CHECK)
return
-/datum/controller/subsystem/air/proc/add_to_rebuild_queue(atmos_machine)
- if(istype(atmos_machine, /obj/machinery/atmospherics))
- pipenets_needing_rebuilt += atmos_machine
-
-/datum/controller/subsystem/air/proc/process_deferred_airs(resumed = 0)
- max_deferred_airs = max(deferred_airs.len,max_deferred_airs)
- while(deferred_airs.len)
- var/list/cur_op = deferred_airs[deferred_airs.len]
- deferred_airs.len--
- var/datum/gas_mixture/air1
- var/datum/gas_mixture/air2
- if(isopenturf(cur_op[1]))
- var/turf/open/T = cur_op[1]
- air1 = T.return_air()
- else
- air1 = cur_op[1]
- if(isopenturf(cur_op[2]))
- var/turf/open/T = cur_op[2]
- air2 = T.return_air()
- else
- air2 = cur_op[2]
- if(istype(cur_op[3], /datum/callback))
- var/datum/callback/cb = cur_op[3]
- cb.Invoke(air1, air2)
- else
- if(cur_op[3] == 0)
- air1.transfer_to(air2, air1.total_moles())
- else
- air1.transfer_ratio_to(air2, cur_op[3])
+/datum/controller/subsystem/air/proc/add_to_rebuild_queue(obj/machinery/atmospherics/atmos_machine)
+ if(istype(atmos_machine, /obj/machinery/atmospherics) && !atmos_machine.rebuilding)
+ rebuild_queue += atmos_machine
+ atmos_machine.rebuilding = TRUE
+
+/datum/controller/subsystem/air/proc/add_to_expansion(datum/pipeline/line, starting_point)
+ var/list/new_packet = new(SSAIR_REBUILD_QUEUE)
+ new_packet[SSAIR_REBUILD_PIPELINE] = line
+ new_packet[SSAIR_REBUILD_QUEUE] = list(starting_point)
+ expansion_queue += list(new_packet)
+
+/datum/controller/subsystem/air/proc/remove_from_expansion(datum/pipeline/line)
+ for(var/list/packet in expansion_queue)
+ if(packet[SSAIR_REBUILD_PIPELINE] == line)
+ expansion_queue -= packet
+ return
+
+/datum/controller/subsystem/air/proc/process_atoms(resumed = FALSE)
+ if(!resumed)
+ src.currentrun = atom_process.Copy()
+ //cache for sanic speed (lists are references anyways)
+ var/list/currentrun = src.currentrun
+ while(currentrun.len)
+ var/atom/talk_to = currentrun[currentrun.len]
+ currentrun.len--
+ if(!talk_to)
+ return
+ talk_to.process_exposure()
if(MC_TICK_CHECK)
return
-/datum/controller/subsystem/air/proc/process_atmos_machinery(resumed = 0)
+/datum/controller/subsystem/air/proc/process_atmos_machinery(resumed = FALSE)
if (!resumed)
src.currentrun = atmos_machinery.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
- var/obj/machinery/current_machinery = currentrun[currentrun.len]
+ var/obj/machinery/M = currentrun[currentrun.len]
currentrun.len--
- if(!current_machinery)
- atmos_machinery -= current_machinery
- // Prevents uninitalized atmos machinery from processing.
- if (!(current_machinery.flags_1 & INITIALIZED_1))
- continue
- if(current_machinery.process_atmos() == PROCESS_KILL)
- stop_processing_machine(current_machinery)
+ if(!M)
+ atmos_machinery -= M
+ if(M.process_atmos() == PROCESS_KILL)
+ stop_processing_machine(M)
if(MC_TICK_CHECK)
return
-/datum/controller/subsystem/air/proc/process_atmos_air_machinery(resumed = 0)
- var/seconds = wait * 0.1
+
+/datum/controller/subsystem/air/proc/process_super_conductivity(resumed = FALSE)
if (!resumed)
- src.currentrun = atmos_air_machinery.Copy()
+ src.currentrun = active_super_conductivity.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
- var/obj/machinery/current_machinery = currentrun[currentrun.len]
+ var/turf/T = currentrun[currentrun.len]
currentrun.len--
- // Prevents uninitalized atmos machinery from processing.
- if (!(current_machinery.flags_1 & INITIALIZED_1))
- continue
- if(!current_machinery)
- atmos_air_machinery -= current_machinery
- if(current_machinery.process_atmos(seconds) == PROCESS_KILL)
- stop_processing_machine(current_machinery)
+ T.super_conduct()
if(MC_TICK_CHECK)
return
-/**
- * Adds a given machine to the processing system for SSAIR_ATMOSMACHINERY processing.
- *
- * Arguments:
- * * machine - The machine to start processing. Can be any /obj/machinery.
- */
-/datum/controller/subsystem/air/proc/start_processing_machine(obj/machinery/machine)
- if(machine.atmos_processing)
- return
- machine.atmos_processing = TRUE
- if(machine.interacts_with_air)
- atmos_air_machinery += machine
- else
- atmos_machinery += machine
-
-/**
- * Removes a given machine to the processing system for SSAIR_ATMOSMACHINERY processing.
- *
- * Arguments:
- * * machine - The machine to stop processing.
- */
-/datum/controller/subsystem/air/proc/stop_processing_machine(obj/machinery/machine)
- if(!machine.atmos_processing)
- return
- machine.atmos_processing = FALSE
- if(machine.interacts_with_air)
- atmos_air_machinery -= machine
- else
- atmos_machinery -= machine
-
- // If we're currently processing atmos machines, there's a chance this machine is in
- // the currentrun list, which is a cache of atmos_machinery. Remove it from that list
- // as well to prevent processing qdeleted objects in the cache.
- if(currentpart == SSAIR_ATMOSMACHINERY)
- currentrun -= machine
- if(machine.interacts_with_air && currentpart == SSAIR_ATMOSMACHINERY_AIR)
- currentrun -= machine
-
-/datum/controller/subsystem/air/proc/process_turf_heat()
-
/datum/controller/subsystem/air/proc/process_hotspots(resumed = FALSE)
if (!resumed)
src.currentrun = hotspots.Copy()
@@ -469,21 +392,16 @@ SUBSYSTEM_DEF(air)
if(MC_TICK_CHECK)
return
-
-/datum/controller/subsystem/air/proc/process_high_pressure_delta(resumed = 0)
+/datum/controller/subsystem/air/proc/process_high_pressure_delta(resumed = FALSE)
while (high_pressure_delta.len)
var/turf/open/T = high_pressure_delta[high_pressure_delta.len]
high_pressure_delta.len--
T.high_pressure_movements()
T.pressure_difference = 0
- T.pressure_specific_target = null
if(MC_TICK_CHECK)
return
-/datum/controller/subsystem/air/proc/process_turf_equalize(resumed = 0)
- if(process_turf_equalize_auxtools(resumed,MC_TICK_REMAINING_MS))
- pause()
- /*
+/datum/controller/subsystem/air/proc/process_active_turfs(resumed = FALSE)
//cache for sanic speed
var/fire_count = times_fired
if (!resumed)
@@ -494,124 +412,493 @@ SUBSYSTEM_DEF(air)
var/turf/open/T = currentrun[currentrun.len]
currentrun.len--
if (T)
- T.equalize_pressure_in_zone(fire_count)
- //equalize_pressure_in_zone(T, fire_count)
+ T.process_cell(fire_count)
if (MC_TICK_CHECK)
return
- */
-/datum/controller/subsystem/air/proc/process_turfs(resumed = 0)
- if(process_turfs_auxtools(resumed,MC_TICK_REMAINING_MS))
- pause()
- /*
- //cache for sanic speed
- var/fire_count = times_fired
+/datum/controller/subsystem/air/proc/process_excited_groups(resumed = FALSE)
if (!resumed)
- src.currentrun = active_turfs.Copy()
+ src.currentrun = excited_groups.Copy()
//cache for sanic speed (lists are references anyways)
var/list/currentrun = src.currentrun
while(currentrun.len)
- var/turf/open/T = currentrun[currentrun.len]
+ var/datum/excited_group/EG = currentrun[currentrun.len]
currentrun.len--
- if (T)
- T.process_cell(fire_count)
+ EG.breakdown_cooldown++
+ EG.dismantle_cooldown++
+ if(EG.breakdown_cooldown >= EXCITED_GROUP_BREAKDOWN_CYCLES)
+ EG.self_breakdown(poke_turfs = TRUE)
+ else if(EG.dismantle_cooldown >= EXCITED_GROUP_DISMANTLE_CYCLES && !(EG.turf_reactions & (REACTING | STOP_REACTIONS)))
+ EG.dismantle()
+ EG.turf_reactions = NONE
+ if (MC_TICK_CHECK)
+ return
+
+/datum/controller/subsystem/air/proc/process_rebuilds()
+ //Yes this does mean rebuilding pipenets can freeze up the subsystem forever, but if we're in that situation something else is very wrong
+ var/list/currentrun = rebuild_queue
+ while(currentrun.len || length(expansion_queue))
+ while(currentrun.len && !length(expansion_queue)) //If we found anything, process that first
+ var/obj/machinery/atmospherics/remake = currentrun[currentrun.len]
+ currentrun.len--
+ if (!remake)
+ continue
+ remake.rebuild_pipes()
+ if (MC_TICK_CHECK)
+ return
+
+ var/list/queue = expansion_queue
+ while(queue.len)
+ var/list/pack = queue[queue.len]
+ //We operate directly with the pipeline like this because we can trust any rebuilds to remake it properly
+ var/datum/pipeline/linepipe = pack[SSAIR_REBUILD_PIPELINE]
+ var/list/border = pack[SSAIR_REBUILD_QUEUE]
+ expand_pipeline(linepipe, border)
+ if(state != SS_RUNNING) //expand_pipeline can fail a tick check, we shouldn't let things get too fucky here
+ return
+
+ linepipe.building = FALSE
+ queue.len--
+ if (MC_TICK_CHECK)
+ return
+
+///Rebuilds a pipeline by expanding outwards, while yielding when sane
+/datum/controller/subsystem/air/proc/expand_pipeline(datum/pipeline/net, list/border)
+ while(border.len)
+ var/obj/machinery/atmospherics/borderline = border[border.len]
+ border.len--
+
+ var/list/result = borderline.pipeline_expansion(net)
+ if(!length(result))
+ continue
+ for(var/obj/machinery/atmospherics/considered_device in result)
+ if(!istype(considered_device, /obj/machinery/atmospherics/pipe))
+ considered_device.set_pipenet(net, borderline)
+ net.add_machinery_member(considered_device)
+ continue
+ var/obj/machinery/atmospherics/pipe/item = considered_device
+ if(net.members.Find(item))
+ continue
+ if(item.parent)
+ var/static/pipenetwarnings = 10
+ if(pipenetwarnings > 0)
+ log_mapping("build_pipeline(): [item.type] added to a pipenet while still having one. (pipes leading to the same spot stacking in one turf) around [AREACOORD(item)].")
+ pipenetwarnings--
+ if(pipenetwarnings == 0)
+ log_mapping("build_pipeline(): further messages about pipenets will be suppressed")
+
+ net.members += item
+ border += item
+
+ net.air.volume += item.volume
+ item.parent = net
+
+ if(item.air_temporary)
+ net.air.merge(item.air_temporary)
+ item.air_temporary = null
+
if (MC_TICK_CHECK)
return
- */
-
-/datum/controller/subsystem/air/proc/process_excited_groups(resumed = 0)
- if(process_excited_groups_auxtools(resumed,MC_TICK_REMAINING_MS))
- pause()
-
-/datum/controller/subsystem/air/proc/finish_turf_processing(resumed = 0)
- if(finish_turf_processing_auxtools(MC_TICK_REMAINING_MS))
- pause()
-
-/datum/controller/subsystem/air/proc/post_process_turfs(resumed = 0)
- if(post_process_turfs_auxtools(resumed,MC_TICK_REMAINING_MS))
- pause()
-
-/datum/controller/subsystem/air/proc/finish_turf_processing_auxtools()
-/datum/controller/subsystem/air/proc/process_turfs_auxtools()
-/datum/controller/subsystem/air/proc/post_process_turfs_auxtools()
-/datum/controller/subsystem/air/proc/process_turf_equalize_auxtools()
-/datum/controller/subsystem/air/proc/process_excited_groups_auxtools()
-/datum/controller/subsystem/air/proc/get_amt_gas_mixes()
-/datum/controller/subsystem/air/proc/get_max_gas_mixes()
-/datum/controller/subsystem/air/proc/turf_process_time()
-/datum/controller/subsystem/air/proc/heat_process_time()
+
+///Removes a turf from processing, and causes its excited group to clean up so things properly adapt to the change
+/datum/controller/subsystem/air/proc/remove_from_active(turf/open/T)
+ active_turfs -= T
+ if(currentpart == SSAIR_ACTIVETURFS)
+ currentrun -= T
+ #ifdef VISUALIZE_ACTIVE_TURFS //Use this when you want details about how the turfs are moving, display_all_groups should work for normal operation
+ T.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_VIBRANT_LIME)
+ #endif
+ if(istype(T))
+ T.excited = FALSE
+ if(T.excited_group)
+ //If this fires during active turfs it'll cause a slight removal of active turfs, as they breakdown if they have no excited group
+ //The group also expands by a tile per rebuild on each edge, suffering
+ T.excited_group.garbage_collect() //Kill the excited group, it'll reform on its own later
+
+///Puts an active turf to sleep so it doesn't process. Do this without cleaning up its excited group.
+/datum/controller/subsystem/air/proc/sleep_active_turf(turf/open/T)
+ active_turfs -= T
+ if(currentpart == SSAIR_ACTIVETURFS)
+ currentrun -= T
+ #ifdef VISUALIZE_ACTIVE_TURFS
+ T.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_VIBRANT_LIME)
+ #endif
+ if(istype(T))
+ T.excited = FALSE
+
+///Adds a turf to active processing, handles duplicates. Call this with blockchanges == TRUE if you want to nuke the assoc excited group
+/datum/controller/subsystem/air/proc/add_to_active(turf/open/T, blockchanges = FALSE)
+ if(istype(T) && T.air)
+ T.significant_share_ticker = 0
+ if(blockchanges && T.excited_group) //This is used almost exclusivly for shuttles, so the excited group doesn't stay behind
+ T.excited_group.garbage_collect() //Nuke it
+ if(T.excited) //Don't keep doing it if there's no point
+ return
+ #ifdef VISUALIZE_ACTIVE_TURFS
+ T.add_atom_colour(COLOR_VIBRANT_LIME, TEMPORARY_COLOUR_PRIORITY)
+ #endif
+ T.excited = TRUE
+ active_turfs += T
+ if(currentpart == SSAIR_ACTIVETURFS)
+ currentrun += T
+ else if(T.flags_1 & INITIALIZED_1)
+ for(var/turf/S in T.atmos_adjacent_turfs)
+ add_to_active(S, TRUE)
+ else if(map_loading)
+ if(queued_for_activation)
+ queued_for_activation[T] = T
+ return
+ else
+ T.requires_activation = TRUE
/datum/controller/subsystem/air/StartLoadingMap()
+ LAZYINITLIST(queued_for_activation)
map_loading = TRUE
/datum/controller/subsystem/air/StopLoadingMap()
map_loading = FALSE
-
-/datum/controller/subsystem/air/proc/pause_z(z_level)
- LAZYADD(paused_z_levels, z_level)
- unpausing_z_levels -= z_level
- pausing_z_levels |= z_level
-
-/datum/controller/subsystem/air/proc/unpause_z(z_level)
- pausing_z_levels -= z_level
- unpausing_z_levels |= z_level
- LAZYREMOVE(paused_z_levels, z_level)
+ for(var/T in queued_for_activation)
+ add_to_active(T, TRUE)
+ queued_for_activation.Cut()
/datum/controller/subsystem/air/proc/setup_allturfs()
- var/times_fired = ++src.times_fired
-
- for(var/turf/T as anything in ALL_TURFS())
- if (!T.init_air)
+ var/list/active_turfs = src.active_turfs
+ times_fired++
+
+ // Clear active turfs - faster than removing every single turf in the world
+ // one-by-one, and Initalize_Atmos only ever adds `src` back in.
+ #ifdef VISUALIZE_ACTIVE_TURFS
+ for(var/jumpy in active_turfs)
+ var/turf/active = jumpy
+ active.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_VIBRANT_LIME)
+ #endif
+ active_turfs.Cut()
+ var/time = 0
+
+ var/list/turf/open/difference_check = list()
+ for(var/turf/setup as anything in ALL_TURFS())
+ if (!setup.init_air)
continue
- T.Initalize_Atmos(times_fired)
+ // We pass the tick as the current step so if we sleep the step changes
+ // This way we can make setting up adjacent turfs O(n) rather then O(n^2)
+ setup.Initalize_Atmos(time)
+ // We assert that we'll only get open turfs here
+ difference_check += setup
+ if(CHECK_TICK)
+ time++
+
+ // Now we're gonna compare for differences
+ // Taking advantage of current cycle being set to negative before this run to do A->B B->A prevention
+ for(var/turf/open/potential_diff as anything in difference_check)
+ // I can't use 0 here, so we're gonna do this instead. If it ever breaks I'll eat my shoe
+ potential_diff.current_cycle = -INFINITY
+ for(var/turf/open/enemy_tile as anything in potential_diff.atmos_adjacent_turfs)
+ // If it's already been processed, then it's already talked to us
+ if(enemy_tile.current_cycle == -INFINITY)
+ continue
+ // .air instead of .return_air() because we can guarentee that the proc won't do anything
+ if(potential_diff.air.compare(enemy_tile.air))
+ //testing("Active turf found. Return value of compare(): [T.air.compare(enemy_tile.air)]")
+ if(!potential_diff.excited)
+ potential_diff.excited = TRUE
+ SSair.active_turfs += potential_diff
+ if(!enemy_tile.excited)
+ enemy_tile.excited = TRUE
+ SSair.active_turfs += enemy_tile
+ // No sense continuing to iterate
+ break
CHECK_TICK
+ if(active_turfs.len)
+ var/starting_ats = active_turfs.len
+ sleep(world.tick_lag)
+ var/timer = world.timeofday
+ log_mapping("There are [starting_ats] active turfs at roundstart caused by a difference of the air between the adjacent turfs. You can see its coordinates using \"Mapping -> Show roundstart AT list\" verb (debug verbs required).")
+ for(var/turf/T in active_turfs)
+ GLOB.active_turfs_startlist += T
+
+ //now lets clear out these active turfs
+ var/list/turfs_to_check = active_turfs.Copy()
+ do
+ var/list/new_turfs_to_check = list()
+ for(var/turf/open/T in turfs_to_check)
+ new_turfs_to_check += T.resolve_active_graph()
+ CHECK_TICK
+
+ active_turfs += new_turfs_to_check
+ turfs_to_check = new_turfs_to_check
+ while (turfs_to_check.len)
+
+ var/ending_ats = active_turfs.len
+ for(var/thing in excited_groups)
+ var/datum/excited_group/EG = thing
+ EG.self_breakdown(roundstart = TRUE)
+ EG.dismantle()
+ CHECK_TICK
+
+ var/msg = "HEY! LISTEN! [DisplayTimeText(world.timeofday - timer)] were wasted processing [starting_ats] turf(s) (connected to [ending_ats - starting_ats] other turfs) with atmos differences at round start."
+ to_chat(world, "[msg]")
+ warning(msg)
+
+/turf/open/proc/resolve_active_graph()
+ . = list()
+ var/datum/excited_group/EG = excited_group
+ if (blocks_air || !air)
+ return
+ if (!EG)
+ EG = new
+ EG.add_turf(src)
+
+ for (var/turf/open/ET in atmos_adjacent_turfs)
+ if (ET.blocks_air || !ET.air)
+ continue
+
+ var/ET_EG = ET.excited_group
+ if (ET_EG)
+ if (ET_EG != EG)
+ EG.merge_groups(ET_EG)
+ EG = excited_group //merge_groups() may decide to replace our current EG
+ else
+ EG.add_turf(ET)
+ if (!ET.excited)
+ ET.excited = TRUE
+ . += ET
+
+/turf/open/space/resolve_active_graph()
+ return list()
+
/datum/controller/subsystem/air/proc/setup_atmos_machinery()
- for (var/obj/machinery/atmospherics/AM in atmos_machinery + atmos_air_machinery)
- AM.atmosinit()
+ for (var/obj/machinery/atmospherics/AM in atmos_machinery)
+ AM.atmos_init()
CHECK_TICK
//this can't be done with setup_atmos_machinery() because
// all atmos machinery has to initalize before the first
// pipenet can be built.
/datum/controller/subsystem/air/proc/setup_pipenets()
- for (var/obj/machinery/atmospherics/AM in atmos_machinery + atmos_air_machinery)
- AM.build_network()
+ for (var/obj/machinery/atmospherics/AM in atmos_machinery)
+ var/list/targets = AM.get_rebuild_targets()
+ for(var/datum/pipeline/build_off as anything in targets)
+ build_off.build_pipeline_blocking(AM)
CHECK_TICK
+GLOBAL_LIST_EMPTY(colored_turfs)
+GLOBAL_LIST_EMPTY(colored_images)
+/datum/controller/subsystem/air/proc/setup_turf_visuals()
+ for(var/sharp_color in GLOB.contrast_colors)
+ var/obj/effect/overlay/atmos_excited/suger_high = new()
+ GLOB.colored_turfs += suger_high
+ var/image/shiny = new('icons/effects/effects.dmi', suger_high, "atmos_top")
+ shiny.plane = ATMOS_GROUP_PLANE
+ shiny.color = sharp_color
+ GLOB.colored_images += shiny
+
/datum/controller/subsystem/air/proc/setup_template_machinery(list/atmos_machines)
- if(!initialized) // yogs - fixes randomized bars
- return // yogs
var/obj/machinery/atmospherics/AM
for(var/A in 1 to atmos_machines.len)
AM = atmos_machines[A]
- AM.atmosinit()
+ AM.atmos_init()
CHECK_TICK
for(var/A in 1 to atmos_machines.len)
AM = atmos_machines[A]
- AM.build_network()
+ var/list/targets = AM.get_rebuild_targets()
+ for(var/datum/pipeline/build_off as anything in targets)
+ build_off.build_pipeline_blocking(AM)
CHECK_TICK
+
/datum/controller/subsystem/air/proc/get_init_dirs(type, dir)
if(!pipe_init_dirs_cache[type])
pipe_init_dirs_cache[type] = list()
if(!pipe_init_dirs_cache[type]["[dir]"])
var/obj/machinery/atmospherics/temp = new type(null, FALSE, dir)
- pipe_init_dirs_cache[type]["[dir]"] = temp.GetInitDirections()
+ pipe_init_dirs_cache[type]["[dir]"] = temp.get_init_directions()
qdel(temp)
return pipe_init_dirs_cache[type]["[dir]"]
-#undef SSAIR_PIPENETS
-#undef SSAIR_ATMOSMACHINERY
-#undef SSAIR_EXCITEDGROUPS
-#undef SSAIR_HIGHPRESSURE
-#undef SSAIR_HOTSPOTS
-#undef SSAIR_TURF_CONDUCTION
-#undef SSAIR_EQUALIZE
-#undef SSAIR_ACTIVETURFS
-#undef SSAIR_TURF_POST_PROCESS
-#undef SSAIR_FINALIZE_TURFS
-#undef SSAIR_ATMOSMACHINERY_AIR
+/datum/controller/subsystem/air/proc/generate_atmos()
+ atmos_gen = list()
+ for(var/T in subtypesof(/datum/atmosphere))
+ var/datum/atmosphere/atmostype = T
+ atmos_gen[initial(atmostype.id)] = new atmostype
+
+/// Takes a gas string, returns the matching mutable gas_mixture
+/datum/controller/subsystem/air/proc/parse_gas_string(gas_string)
+ var/datum/gas_mixture/cached = strings_to_mix[gas_string]
+ if(cached)
+ if(istype(cached, /datum/gas_mixture/immutable))
+ return cached
+ return cached.copy()
+
+ var/datum/gas_mixture/canonical_mix = new()
+ // We set here so any future key changes don't fuck us
+ strings_to_mix[gas_string] = canonical_mix
+ gas_string = preprocess_gas_string(gas_string)
+
+ var/list/gas = params2list(gas_string)
+ if(gas["TEMP"])
+ canonical_mix.temperature = text2num(gas["TEMP"])
+ canonical_mix.temperature_archived = canonical_mix.temperature
+ gas -= "TEMP"
+ else // if we do not have a temp in the new gas mix lets assume room temp.
+ canonical_mix.temperature = T20C
+ for(var/id in gas)
+ var/path = id
+ if(!ispath(path))
+ path = gas_id2path(path) //a lot of these strings can't have embedded expressions (especially for mappers), so support for IDs needs to stick around
+ SET_MOLES(path, canonical_mix, text2num(gas[id]))
+
+ if(istype(canonical_mix, /datum/gas_mixture/immutable))
+ return canonical_mix
+ return canonical_mix.copy()
+
+/datum/controller/subsystem/air/proc/preprocess_gas_string(gas_string)
+ if(!atmos_gen)
+ generate_atmos()
+ if(!atmos_gen[gas_string])
+ return gas_string
+ var/datum/atmosphere/mix = atmos_gen[gas_string]
+ return mix.gas_string
+
+/**
+ * Adds a given machine to the processing system for SSAIR_ATMOSMACHINERY processing.
+ *
+ * This should be fast, so no error checking is done.
+ * If you start adding in things you shouldn't, you'll cause runtimes every 2 seconds for every
+ * object you added. Do not use irresponsibly.
+ * Arguments:
+ * * machine - The machine to start processing. Can be any /obj/machinery.
+ */
+/datum/controller/subsystem/air/proc/start_processing_machine(obj/machinery/machine)
+ if(machine.atmos_processing)
+ return
+ if(QDELETED(machine))
+ stack_trace("We tried to add a garbage collecting machine to SSair. Don't")
+ return
+ machine.atmos_processing = TRUE
+ atmos_machinery += machine
+
+/**
+ * Removes a given machine to the processing system for SSAIR_ATMOSMACHINERY processing.
+ *
+ * This should be fast, so no error checking is done.
+ * If you call this proc when your machine isn't processing, you're likely attempting to
+ * remove something that isn't in a list with over 1000 objects, twice. Do not use
+ * irresponsibly.
+ * Arguments:
+ * * machine - The machine to stop processing.
+ */
+/datum/controller/subsystem/air/proc/stop_processing_machine(obj/machinery/machine)
+ if(!machine.atmos_processing)
+ return
+ machine.atmos_processing = FALSE
+ atmos_machinery -= machine
+
+ // If we're currently processing atmos machines, there's a chance this machine is in
+ // the currentrun list, which is a cache of atmos_machinery. Remove it from that list
+ // as well to prevent processing qdeleted objects in the cache.
+ if(currentpart == SSAIR_ATMOSMACHINERY)
+ currentrun -= machine
+
+/datum/controller/subsystem/air/ui_state(mob/user)
+ return GLOB.debug_state
+
+/datum/controller/subsystem/air/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "AtmosControlPanel")
+ ui.set_autoupdate(FALSE)
+ ui.open()
+
+/datum/controller/subsystem/air/ui_data(mob/user)
+ var/list/data = list()
+ data["excited_groups"] = list()
+ for(var/datum/excited_group/group in excited_groups)
+ var/turf/T = group.turf_list[1]
+ var/area/target = get_area(T)
+ var/max = 0
+ #ifdef TRACK_MAX_SHARE
+ for(var/who in group.turf_list)
+ var/turf/open/lad = who
+ max = max(lad.max_share, max)
+ #endif
+ data["excited_groups"] += list(list(
+ "jump_to" = REF(T), //Just go to the first turf
+ "group" = REF(group),
+ "area" = target.name,
+ "breakdown" = group.breakdown_cooldown,
+ "dismantle" = group.dismantle_cooldown,
+ "size" = group.turf_list.len,
+ "should_show" = group.should_display,
+ "max_share" = max
+ ))
+ data["active_size"] = active_turfs.len
+ data["hotspots_size"] = hotspots.len
+ data["excited_size"] = excited_groups.len
+ data["conducting_size"] = active_super_conductivity.len
+ data["frozen"] = can_fire
+ data["show_all"] = display_all_groups
+ data["fire_count"] = times_fired
+ #ifdef TRACK_MAX_SHARE
+ data["display_max"] = TRUE
+ #else
+ data["display_max"] = FALSE
+ #endif
+ data["showing_user"] = user.hud_used.atmos_debug_overlays
+ return data
+
+/datum/controller/subsystem/air/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(. || !check_rights_for(usr.client, R_DEBUG))
+ return
+ switch(action)
+ if("move-to-target")
+ var/turf/target = locate(params["spot"])
+ if(!target)
+ return
+ usr.forceMove(target)
+ if("toggle-freeze")
+ can_fire = !can_fire
+ return TRUE
+ if("toggle_show_group")
+ var/datum/excited_group/group = locate(params["group"])
+ if(!group)
+ return
+ group.should_display = !group.should_display
+ if(display_all_groups)
+ return TRUE
+ if(group.should_display)
+ group.display_turfs()
+ else
+ group.hide_turfs()
+ return TRUE
+ if("toggle_show_all")
+ display_all_groups = !display_all_groups
+ for(var/datum/excited_group/group in excited_groups)
+ if(display_all_groups)
+ group.display_turfs()
+ else if(!group.should_display) //Don't flicker yeah?
+ group.hide_turfs()
+ return TRUE
+ if("toggle_user_display")
+ var/mob/user = ui.user
+ user.hud_used.atmos_debug_overlays = !user.hud_used.atmos_debug_overlays
+ if(user.hud_used.atmos_debug_overlays)
+ user.client.images += GLOB.colored_images
+ else
+ user.client.images -= GLOB.colored_images
+ return TRUE
+
+// Supercruise Z-pausing
+/datum/controller/subsystem/air/proc/pause_z(z_level)
+ LAZYADD(paused_z_levels, z_level)
+ unpausing_z_levels -= z_level
+ pausing_z_levels |= z_level
+
+/datum/controller/subsystem/air/proc/unpause_z(z_level)
+ pausing_z_levels -= z_level
+ unpausing_z_levels |= z_level
+ LAZYREMOVE(paused_z_levels, z_level)
diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm
index 142f1539861a5..80963c96a65b5 100644
--- a/code/controllers/subsystem/atoms.dm
+++ b/code/controllers/subsystem/atoms.dm
@@ -1,8 +1,3 @@
-#define BAD_INIT_QDEL_BEFORE 1
-#define BAD_INIT_DIDNT_INIT 2
-#define BAD_INIT_SLEPT 4
-#define BAD_INIT_NO_HINT 8
-
#define SUBSYSTEM_INIT_SOURCE "subsystem init"
SUBSYSTEM_DEF(atoms)
name = "Atoms"
@@ -46,14 +41,6 @@ SUBSYSTEM_DEF(atoms)
InitializeAtoms()
return SS_INIT_SUCCESS
-#ifdef PROFILE_MAPLOAD_INIT_ATOM
-#define PROFILE_INIT_ATOM_BEGIN(...) var/__profile_stat_time = TICK_USAGE
-#define PROFILE_INIT_ATOM_END(atom) mapload_init_times += list(list(##atom.type, TICK_USAGE_TO_MS(__profile_stat_time)))
-#else
-#define PROFILE_INIT_ATOM_BEGIN(...)
-#define PROFILE_INIT_ATOM_END(...)
-#endif
-
/datum/controller/subsystem/atoms/proc/InitializeAtoms(list/atoms, list/atoms_to_return)
if(initialized == INITIALIZATION_INSSATOMS)
return
@@ -272,9 +259,3 @@ SUBSYSTEM_DEF(atoms)
#undef SUBSYSTEM_INIT_SOURCE
-#undef BAD_INIT_QDEL_BEFORE
-#undef BAD_INIT_DIDNT_INIT
-#undef BAD_INIT_SLEPT
-#undef BAD_INIT_NO_HINT
-#undef PROFILE_INIT_ATOM_BEGIN
-#undef PROFILE_INIT_ATOM_END
diff --git a/code/controllers/subsystem/callback.dm b/code/controllers/subsystem/callback.dm
deleted file mode 100644
index ecc65760f4e80..0000000000000
--- a/code/controllers/subsystem/callback.dm
+++ /dev/null
@@ -1,14 +0,0 @@
-SUBSYSTEM_DEF(callbacks)
- name = "Auxtools Callbacks"
- flags = SS_TICKER | SS_NO_INIT
- wait = 1
- priority = FIRE_PRIORITY_CALLBACKS
-
-/proc/process_atmos_callbacks()
- SScallbacks.can_fire = 0
- SScallbacks.flags |= SS_NO_FIRE
- CRASH("Auxtools not found! Callback subsystem shutting itself off.")
-
-/datum/controller/subsystem/callbacks/fire()
- if(process_atmos_callbacks(MC_TICK_REMAINING_MS))
- pause()
diff --git a/code/controllers/subsystem/explosion.dm b/code/controllers/subsystem/explosion.dm
index 76c517e7eb0b2..d74e8910d94bb 100644
--- a/code/controllers/subsystem/explosion.dm
+++ b/code/controllers/subsystem/explosion.dm
@@ -33,7 +33,7 @@ SUBSYSTEM_DEF(explosions)
var/list/explosions = list()
- var/currentpart = SSAIR_REBUILD_PIPENETS
+ var/currentpart = SSAIR_REBUILD_PIPELINE
/datum/controller/subsystem/explosions/stat_entry(msg)
@@ -625,8 +625,6 @@ SUBSYSTEM_DEF(explosions)
currentpart = SSEXPLOSIONS_TURFS
-#undef SSAIR_REBUILD_PIPENETS
-
#undef EXPLOSION_THROW_SPEED
#undef SSEX_TURF
#undef SSEX_OBJ
diff --git a/code/controllers/subsystem/overlays.dm b/code/controllers/subsystem/overlays.dm
index 957e5806f02a7..12dea7035bb80 100644
--- a/code/controllers/subsystem/overlays.dm
+++ b/code/controllers/subsystem/overlays.dm
@@ -46,21 +46,17 @@ SUBSYSTEM_DEF(overlays)
count++
if(!atom_to_compile)
continue
+ if(length(atom_to_compile.overlays) >= MAX_ATOM_OVERLAYS)
+ //Break it real GOOD
+ stack_trace("Too many overlays on [atom_to_compile.type] - [length(atom_to_compile.overlays)], refusing to update and cutting.")
+ atom_to_compile.overlays.Cut()
+ continue
STAT_START_STOPWATCH
COMPILE_OVERLAYS(atom_to_compile)
UNSETEMPTY(atom_to_compile.add_overlays)
UNSETEMPTY(atom_to_compile.remove_overlays)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(stats, atom_to_compile.type)
- if(length(atom_to_compile.overlays) >= MAX_ATOM_OVERLAYS)
- //Break it real GOOD
- var/text_lays = overlays2text(atom_to_compile.overlays)
- stack_trace("Too many overlays on [atom_to_compile.type] - [length(atom_to_compile.overlays)], refusing to update and cutting.\
- \n What follows is a printout of all existing overlays at the time of the overflow \n[text_lays]")
- atom_to_compile.overlays.Cut()
- //Let them know they fucked up
- atom_to_compile.add_overlay(mutable_appearance('icons/testing/greyscale_error.dmi'))
- continue
if(mc_check)
if(MC_TICK_CHECK)
break
diff --git a/code/datums/atmosphere/_atmosphere.dm b/code/datums/atmosphere/_atmosphere.dm
index df76b3f2a4111..f4667adedb448 100644
--- a/code/datums/atmosphere/_atmosphere.dm
+++ b/code/datums/atmosphere/_atmosphere.dm
@@ -17,15 +17,18 @@
generate_gas_string()
/datum/atmosphere/proc/generate_gas_string()
+ var/list/spicy_gas = restricted_gases.Copy()
var/target_pressure = rand(minimum_pressure, maximum_pressure)
var/pressure_scalar = target_pressure / maximum_pressure
// First let's set up the gasmix and base gases for this template
// We make the string from a gasmix in this proc because gases need to calculate their pressure
var/datum/gas_mixture/gasmix = new
- gasmix.set_temperature(rand(minimum_temp, maximum_temp))
+ var/list/gaslist = gasmix.gases
+ gasmix.temperature = rand(minimum_temp, maximum_temp)
for(var/i in base_gases)
- gasmix.set_moles(i, base_gases[i])
+ ADD_GAS(i, gaslist)
+ gaslist[i][MOLES] = base_gases[i]
// Now let the random choices begin
var/datum/gas/gastype
@@ -37,23 +40,24 @@
else
gastype = pick(restricted_gases)
amount = restricted_gases[gastype]
- if(gasmix.get_moles(gastype))
- continue
+ spicy_gas -= gastype //You can only pick each restricted gas once
amount *= rand(50, 200) / 100 // Randomly modifes the amount from half to double the base for some variety
amount *= pressure_scalar // If we pick a really small target pressure we want roughly the same mix but less of it all
amount = CEILING(amount, 0.1)
- gasmix.set_moles(gastype, gasmix.get_moles(gastype) + amount)
+ ADD_MOLES_LIST(gastype, gaslist, amount)
// That last one put us over the limit, remove some of it
while(gasmix.return_pressure() > target_pressure)
- gasmix.set_moles(gastype, gasmix.get_moles(gastype) - (gasmix.get_moles(gastype) * 0.1))
- gasmix.set_moles(gastype, FLOOR(gasmix.get_moles(gastype), 0.1))
+ gaslist[gastype][MOLES] -= gaslist[gastype][MOLES] * 0.1
+ gaslist[gastype][MOLES] = FLOOR(gaslist[gastype][MOLES], 0.1)
+ gasmix.garbage_collect()
// Now finally lets make that string
var/list/gas_string_builder = list()
- for(var/i in gasmix.get_gases())
- gas_string_builder += "[GLOB.gas_data.ids[i]]=[gasmix.get_moles(i)]"
- gas_string_builder += "TEMP=[gasmix.return_temperature()]"
+ for(var/i in gasmix.gases)
+ var/list/gas = gaslist[i]
+ gas_string_builder += "[gas[GAS_META][META_GAS_ID]]=[gas[MOLES]]"
+ gas_string_builder += "TEMP=[gasmix.temperature]"
gas_string = gas_string_builder.Join(";")
diff --git a/code/datums/components/gas_leaker.dm b/code/datums/components/gas_leaker.dm
new file mode 100644
index 0000000000000..eeceb73f5fa25
--- /dev/null
+++ b/code/datums/components/gas_leaker.dm
@@ -0,0 +1,87 @@
+#define PROCESS_COMPONENT "component"
+#define PROCESS_MACHINE "machine"
+#define PROCESS_OBJ "obj"
+
+/// A component to leak gas over time from damaged objects with gas storage
+/datum/component/gas_leaker
+ /// Keeps track of what type we were attached to so we don't need to istype every process
+ var/process_type
+
+ /// The percent of max integrity that we start leaking. From 0 to 1
+ var/integrity_leak_percent
+
+ /// The rate at which gas leaks, you probably want this *very* low. From 0 to 1
+ var/leak_rate
+
+ /// Mirror of the machine var signifying whether this is live in the air subsystem
+ var/atmos_processing = FALSE
+
+/datum/component/gas_leaker/Initialize(integrity_leak_percent=0.9, leak_rate=1)
+ . = ..()
+ if(istype(parent, /obj/machinery/atmospherics/components))
+ process_type = PROCESS_COMPONENT
+ else if(ismachinery(parent))
+ process_type = PROCESS_MACHINE
+ else if(isobj(parent))
+ process_type = PROCESS_OBJ
+ else
+ return COMPONENT_INCOMPATIBLE
+
+ src.integrity_leak_percent = integrity_leak_percent
+ src.leak_rate = leak_rate
+
+/datum/component/gas_leaker/Destroy(force)
+ SSair.stop_processing_machine(src)
+ return ..()
+
+/datum/component/gas_leaker/RegisterWithParent()
+ . = ..()
+ RegisterSignal(parent, COMSIG_ATOM_TAKE_DAMAGE, PROC_REF(start_processing))
+
+/datum/component/gas_leaker/UnregisterFromParent()
+ . = ..()
+ UnregisterSignal(parent, COMSIG_ATOM_TAKE_DAMAGE)
+
+/datum/component/gas_leaker/proc/process_atmos()
+ . = PROCESS_KILL
+ switch(process_type)
+ if(PROCESS_OBJ)
+ . = process_obj(parent)
+ if(PROCESS_MACHINE)
+ . = process_machine(parent)
+ if(PROCESS_COMPONENT)
+ . = process_component(parent)
+
+/datum/component/gas_leaker/proc/start_processing()
+ SIGNAL_HANDLER
+ // Hello fellow atmospherics machines, I too am definitely an atmos machine like you!
+ // This component needs to tick at the same rate as the atmos system
+ SSair.start_processing_machine(src)
+
+/datum/component/gas_leaker/proc/process_obj(obj/master, list/airs=list())
+ airs += master.return_air()
+ return process_leak(master, airs)
+
+/datum/component/gas_leaker/proc/process_machine(obj/machinery/master, list/airs=list())
+ if(master.machine_stat & BROKEN)
+ return PROCESS_KILL
+ return process_obj(master, airs)
+
+/datum/component/gas_leaker/proc/process_component(obj/machinery/atmospherics/components/master, list/airs=list())
+ airs += master.airs
+ return process_machine(master, airs)
+
+/datum/component/gas_leaker/proc/process_leak(obj/master, list/airs)
+ var/current_integrity = master.get_integrity()
+ if(current_integrity > master.max_integrity * integrity_leak_percent)
+ return PROCESS_KILL
+ var/turf/location = get_turf(master)
+ var/true_rate = (1 - (current_integrity / master.max_integrity)) * leak_rate
+ for(var/datum/gas_mixture/mix as anything in airs)
+ var/pressure = mix.return_pressure()
+ if(mix.release_gas_to(location.return_air(), pressure, true_rate))
+ location.air_update_turf(FALSE, FALSE)
+
+#undef PROCESS_OBJ
+#undef PROCESS_MACHINE
+#undef PROCESS_COMPONENT
diff --git a/code/datums/components/orbiter.dm b/code/datums/components/orbiter.dm
index 31bafd87fcf45..dd9d8bb9953ef 100644
--- a/code/datums/components/orbiter.dm
+++ b/code/datums/components/orbiter.dm
@@ -161,12 +161,12 @@
if(!newturf)
qdel(src)
- var/atom/curloc = master.loc
+ var/atom/current_location = master.loc
for(var/atom/movable/movable_orbiter as anything in current_orbiters)
if(QDELETED(movable_orbiter) || movable_orbiter.loc == newturf)
continue
movable_orbiter.abstract_move(newturf)
- if(CHECK_TICK && master.loc != curloc)
+ if(CHECK_TICK && master.loc != current_location)
// We moved again during the checktick, cancel current operation
break
diff --git a/code/datums/components/wet_floor.dm b/code/datums/components/wet_floor.dm
index cbaf051bdefb4..d0ae8d089cbca 100644
--- a/code/datums/components/wet_floor.dm
+++ b/code/datums/components/wet_floor.dm
@@ -115,7 +115,7 @@
var/turf/open/T = parent
var/diff = world.time - last_process
var/decrease = 0
- var/t = T.GetTemperature()
+ var/t = T.get_temperature()
switch(t)
if(-INFINITY to T0C)
add_wet(TURF_WET_ICE, max_time_left()) //Water freezes into ice!
diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm
index 2058459838839..87e2bf66adb4f 100644
--- a/code/datums/diseases/_disease.dm
+++ b/code/datums/diseases/_disease.dm
@@ -134,7 +134,7 @@
if(end == start)
return TRUE
var/turf/Temp = get_step_towards(end, start)
- if(!CANATMOSPASS(end, Temp))
+ if(!CANATMOSPASS(end, Temp, FALSE))
return FALSE
end = Temp
diff --git a/code/datums/diseases/advance/symptoms/clockwork.dm b/code/datums/diseases/advance/symptoms/clockwork.dm
index efc5526b72d83..796b950d948ef 100644
--- a/code/datums/diseases/advance/symptoms/clockwork.dm
+++ b/code/datums/diseases/advance/symptoms/clockwork.dm
@@ -107,8 +107,8 @@
var/obj/item/organ/lungs/clockwork/organ = new()
if(robustbits)
organ.gas_max = list(
- GAS_PLASMA = 15,
- GAS_CO2 = 15,
+ /datum/gas/plasma = 15,
+ /datum/gas/carbon_dioxide = 15,
)
organ.SA_para_min = 15
organ.SA_sleep_min = 15
diff --git a/code/datums/elements/atmos_requirements.dm b/code/datums/elements/atmos_requirements.dm
index d944a4dbac53f..ddffd374ba120 100644
--- a/code/datums/elements/atmos_requirements.dm
+++ b/code/datums/elements/atmos_requirements.dm
@@ -45,10 +45,10 @@
if(!ST.air && (atmos_requirements["min_oxy"] || atmos_requirements["min_tox"] || atmos_requirements["min_n2"] || atmos_requirements["min_co2"]))
return FALSE
- var/plas = ST.air.get_moles(GAS_PLASMA)
- var/oxy = ST.air.get_moles(GAS_O2)
- var/n2 = ST.air.get_moles(GAS_N2)
- var/co2 = ST.air.get_moles(GAS_CO2)
+ var/plas = GET_MOLES(/datum/gas/plasma, ST.air)
+ var/oxy = GET_MOLES(/datum/gas/oxygen, ST.air)
+ var/n2 = GET_MOLES(/datum/gas/nitrogen, ST.air)
+ var/co2 = GET_MOLES(/datum/gas/carbon_dioxide, ST.air)
. = TRUE
if(atmos_requirements["min_oxy"] && oxy < atmos_requirements["min_oxy"])
diff --git a/code/datums/elements/atmos_sensitive.dm b/code/datums/elements/atmos_sensitive.dm
new file mode 100644
index 0000000000000..07187f9f57da9
--- /dev/null
+++ b/code/datums/elements/atmos_sensitive.dm
@@ -0,0 +1,71 @@
+//This element facilitates reaction to atmos changes when a tile is inactive.
+//It adds the object to a list on SSair to be processed for so long as the object wants to be processed
+//And removes it as soon as the object is no longer interested
+//Don't put it on things that tend to clump into one spot, you will cause lag spikes.
+/datum/element/atmos_sensitive
+ element_flags = ELEMENT_DETACH
+
+/datum/element/atmos_sensitive/Attach(datum/target)
+ if(!isatom(target)) //How
+ return ELEMENT_INCOMPATIBLE
+ var/atom/to_track = target
+ if(isopenturf(to_track.loc))
+ to_track.RegisterSignal(to_track.loc, COMSIG_TURF_EXPOSE, /atom/proc/check_atmos_process)
+ RegisterSignal(to_track, COMSIG_MOVABLE_MOVED, PROC_REF(handle_move))
+ return ..()
+
+/datum/element/atmos_sensitive/Detach(datum/source, force)
+ var/atom/us = source
+ us.UnregisterSignal(get_turf(us), COMSIG_TURF_EXPOSE)
+ if(us.flags_1 & ATMOS_IS_PROCESSING_1)
+ SSair.atom_process -= us
+ us.flags_1 &= ~ATMOS_IS_PROCESSING_1
+ return ..()
+
+/datum/element/atmos_sensitive/proc/handle_move(datum/source, atom/movable/oldloc, direction, forced)
+ var/atom/microchipped_lad = source
+ microchipped_lad.UnregisterSignal(oldloc, COMSIG_TURF_EXPOSE)
+ if(isopenturf(microchipped_lad.loc))
+ var/turf/open/new_spot = microchipped_lad.loc
+ microchipped_lad.RegisterSignal(new_spot, COMSIG_TURF_EXPOSE, /atom/proc/check_atmos_process)
+ microchipped_lad.check_atmos_process(null, new_spot.air, new_spot.temperature) //Make sure you're properly registered
+
+/atom/proc/check_atmos_process(datum/source, datum/gas_mixture/air, exposed_temperature)
+ if(should_atmos_process(air, exposed_temperature))
+ if(flags_1 & ATMOS_IS_PROCESSING_1)
+ return
+ SSair.atom_process += src
+ flags_1 |= ATMOS_IS_PROCESSING_1
+ else if(flags_1 & ATMOS_IS_PROCESSING_1)
+ SSair.atom_process -= src
+ flags_1 &= ~ATMOS_IS_PROCESSING_1
+
+/atom/proc/process_exposure()
+ var/turf/open/spot
+ if(istype(loc, /turf/open))
+ spot = loc
+ else //If you end up in a locker or a wall reconsider your life decisions
+ SSair.atom_process -= src
+ flags_1 &= ~ATMOS_IS_PROCESSING_1
+ return
+ if(!should_atmos_process(spot.air, spot.air.temperature)) //Things can change without a tile becoming active
+ SSair.atom_process -= src
+ flags_1 &= ~ATMOS_IS_PROCESSING_1
+ return
+ atmos_expose(spot.air, spot.air.temperature)
+
+/turf/open/process_exposure()
+ if(!should_atmos_process(air, air.temperature))
+ SSair.atom_process -= src
+ flags_1 &= ~ATMOS_IS_PROCESSING_1
+ return
+ atmos_expose(air, air.temperature)
+
+///We use this proc to check if we should start processing an item, or continue processing it. Returns true/false as expected
+/atom/proc/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return FALSE
+
+
+///This is your process() proc
+/atom/proc/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ return
diff --git a/code/datums/elements/volatile_gas_storage.dm b/code/datums/elements/volatile_gas_storage.dm
new file mode 100644
index 0000000000000..22c5f52fdf5a8
--- /dev/null
+++ b/code/datums/elements/volatile_gas_storage.dm
@@ -0,0 +1,49 @@
+/// An element to make an /obj explode based on gas pressure when broken
+/datum/element/volatile_gas_storage
+ element_flags = ELEMENT_BESPOKE
+
+ /// The minimum pressure of the gas storage to consider an explosion when broken
+ var/minimum_explosive_pressure
+ /// The max pressure to stop scaling the explosion at, you can go higher but the explosion range will stay at max
+ var/max_explosive_pressure
+ /// The max explsion range at the max pressure
+ var/max_explosive_force
+
+/datum/element/volatile_gas_storage/Attach(datum/target, minimum_explosive_pressure=5000, max_explosive_pressure=100000, max_explosive_force=9)
+ . = ..()
+ if(istype(target, /obj/machinery/atmospherics/components))
+ RegisterSignal(target, COMSIG_ATOM_BREAK, PROC_REF(AtmosComponentBreak))
+ else if(isobj(target))
+ RegisterSignal(target, COMSIG_ATOM_BREAK, PROC_REF(ObjBreak))
+ else
+ return ELEMENT_INCOMPATIBLE
+
+ src.minimum_explosive_pressure = minimum_explosive_pressure
+ src.max_explosive_pressure = max_explosive_pressure
+ src.max_explosive_force = max_explosive_force
+
+/datum/element/volatile_gas_storage/Detach(datum/source, ...)
+ . = ..()
+ UnregisterSignal(source, COMSIG_ATOM_BREAK)
+
+/datum/element/volatile_gas_storage/proc/Break(atom/origin, datum/gas_mixture/released_gas)
+ var/expelled_pressure = min(released_gas?.return_pressure(), max_explosive_pressure)
+
+ if(expelled_pressure < minimum_explosive_pressure)
+ return
+
+ var/explosive_force = CEILING((expelled_pressure / max_explosive_pressure) * max_explosive_force , 1)
+ // This is supposed to represent only shrapnel and no fire
+ // Maybe one day we'll get something a bit better
+ explosion(get_turf(origin), light_impact_range=explosive_force, adminlog = origin)
+
+/datum/element/volatile_gas_storage/proc/AtmosComponentBreak(obj/machinery/atmospherics/components/owner)
+ SIGNAL_HANDLER
+ for(var/datum/gas_mixture/gas_contents as anything in owner.airs)
+ if(!gas_contents)
+ continue
+ Break(owner, gas_contents)
+
+/datum/element/volatile_gas_storage/proc/ObjBreak(obj/owner)
+ SIGNAL_HANDLER
+ Break(owner, owner.return_air())
diff --git a/code/datums/greyscale/greyscale_configs.dm b/code/datums/greyscale/greyscale_configs.dm
index dd93c881bc20a..8da5baa5c61f2 100644
--- a/code/datums/greyscale/greyscale_configs.dm
+++ b/code/datums/greyscale/greyscale_configs.dm
@@ -23,10 +23,16 @@
name = "Hazard Striped Canister"
json_config = 'code/datums/greyscale/json_configs/canister_hazard.json'
-/datum/greyscale_config/prototype_canister
- name = "Prototype Canister"
- icon_file = 'icons/obj/atmospherics/prototype_canister.dmi'
- json_config = 'code/datums/greyscale/json_configs/canister_proto.json'
+// MISC ATMOSPHERICS
+/datum/greyscale_config/meter
+ name = "Meter"
+ icon_file = 'icons/obj/atmospherics/pipes/meter.dmi'
+ json_config = 'code/datums/greyscale/json_configs/meter.json'
+
+/datum/greyscale_config/thermomachine
+ name = "Thermomachine"
+ icon_file = 'icons/obj/atmospherics/components/thermomachine.dmi'
+ json_config = 'code/datums/greyscale/json_configs/thermomachine.json'
/datum/greyscale_config/carp
name = "Space Carp"
diff --git a/code/datums/greyscale/json_configs/meter.json b/code/datums/greyscale/json_configs/meter.json
new file mode 100644
index 0000000000000..344500c2a9dcc
--- /dev/null
+++ b/code/datums/greyscale/json_configs/meter.json
@@ -0,0 +1,374 @@
+{
+ "meter": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure_off",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter0": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure0",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons0",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter1_1": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure1_1",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons1",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter1_2": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure1_2",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons1",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter1_3": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure1_3",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons1",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter1_4": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure1_4",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons1",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter1_5": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure1_5",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons1",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter1_6": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure1_6",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons1",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter2_1": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure2_1",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons2",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter2_2": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure2_2",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons2",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter2_3": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure2_3",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons2",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter2_4": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure2_4",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons2",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter2_5": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure2_5",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons2",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter2_6": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure2_6",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons2",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter3_1": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure3_1",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons3",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter3_2": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure3_2",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons3",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter3_3": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure3_3",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons3",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter3_4": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure3_4",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons3",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter3_5": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure3_5",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons3",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter3_6": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure3_6",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons3",
+ "blend_mode": "overlay"
+ }
+ ],
+ "meter4": [
+ {
+ "type": "icon_state",
+ "icon_state": "meter_base",
+ "blend_mode": "overlay"
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "pressure4",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "buttons4",
+ "blend_mode": "overlay"
+ }
+ ]
+}
diff --git a/code/datums/greyscale/json_configs/thermomachine.json b/code/datums/greyscale/json_configs/thermomachine.json
new file mode 100644
index 0000000000000..37a4cbd681561
--- /dev/null
+++ b/code/datums/greyscale/json_configs/thermomachine.json
@@ -0,0 +1,41 @@
+{
+ "thermo_base": [
+ {
+ "type": "icon_state",
+ "icon_state": "temp_meter",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "thermo_base",
+ "blend_mode": "overlay"
+ }
+ ],
+ "thermo_1": [
+ {
+ "type": "icon_state",
+ "icon_state": "temp_meter_1",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "thermo_base_1",
+ "blend_mode": "overlay"
+ }
+ ],
+ "thermo-open": [
+ {
+ "type": "icon_state",
+ "icon_state": "temp_meter-o",
+ "blend_mode": "overlay",
+ "color_ids": [ 1 ]
+ },
+ {
+ "type": "icon_state",
+ "icon_state": "thermo_base-o",
+ "blend_mode": "overlay"
+ }
+ ]
+}
diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm
index ca6827ecf38bb..3a2b150c278f8 100644
--- a/code/datums/looping_sounds/machinery_sounds.dm
+++ b/code/datums/looping_sounds/machinery_sounds.dm
@@ -89,3 +89,10 @@
falloff_exponent = 5
falloff_distance = 3
volume = 150
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/datum/looping_sound/firealarm
+ mid_sounds = 'goon/sound/machinery/FireAlarm.ogg'
+ mid_length = 7 SECONDS
+ volume = 30
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 75f70585a4c3d..702e529665711 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -1121,7 +1121,7 @@
/datum/status_effect/heretic_mark/void/on_effect()
var/turf/open/turfie = get_turf(owner)
- turfie.TakeTemperature(-40)
+ turfie.take_temperature(-40)
owner.adjust_bodytemperature(-20)
if(iscarbon(owner))
var/mob/living/carbon/carbon_owner = owner
diff --git a/code/datums/wires/airalarm.dm b/code/datums/wires/airalarm.dm
index 0b1c7ebff5e56..00291609871c3 100644
--- a/code/datums/wires/airalarm.dm
+++ b/code/datums/wires/airalarm.dm
@@ -1,24 +1,20 @@
/datum/wires/airalarm
holder_type = /obj/machinery/airalarm
proper_name = "Air Alarm"
- FASTDMM_PROP(\
- set_instance_vars(\
- pixel_x = (dir & 3)? INSTANCE_VAR_DEFAULT : (dir == 4 ? -24 : 24),\
- pixel_y = (dir & 3)? (dir == 1 ? -24 : 24) : INSTANCE_VAR_DEFAULT\
- ),\
- dir_amount = 4\
- )
/datum/wires/airalarm/New(atom/holder)
wires = list(
WIRE_POWER,
WIRE_IDSCAN, WIRE_AI,
- WIRE_PANIC, WIRE_ALARM
+ WIRE_PANIC, WIRE_ALARM,
+ WIRE_SPEAKER
)
add_duds(3)
..()
/datum/wires/airalarm/interactable(mob/user)
+ if(!..())
+ return FALSE
var/obj/machinery/airalarm/A = holder
if(A.panel_open && A.buildstage == 2)
return TRUE
@@ -37,33 +33,32 @@
if(WIRE_POWER) // Short out for a long time.
if(!A.shorted)
A.shorted = TRUE
- A.update_icon()
- addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 1200)
+ A.update_appearance()
+ addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 2 MINUTES)
if(WIRE_IDSCAN) // Toggle lock.
A.locked = !A.locked
if(WIRE_AI) // Disable AI control for a while.
if(!A.aidisabled)
A.aidisabled = TRUE
- addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 100)
+ addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/airalarm, reset), wire), 10 SECONDS)
if(WIRE_PANIC) // Toggle panic siphon.
if(!A.shorted)
- if(A.mode == 1) // AALARM_MODE_SCRUB
- A.mode = 3 // AALARM_MODE_PANIC
+ if(istype(A.selected_mode, /datum/air_alarm_mode/filtering))
+ A.select_mode(usr, /datum/air_alarm_mode/panic_siphon)
else
- A.mode = 1 // AALARM_MODE_SCRUB
- A.apply_mode(usr)
+ A.select_mode(usr, /datum/air_alarm_mode/filtering)
if(WIRE_ALARM) // Clear alarms.
if(A.alarm_manager.clear_alarm(ALARM_ATMOS))
- A.post_alert(0)
- A.update_icon()
+ A.danger_level = AIR_ALARM_ALERT_NONE
+ A.update_appearance()
-/datum/wires/airalarm/on_cut(wire, mob/user, mend)
+/datum/wires/airalarm/on_cut(wire, mend, source)
var/obj/machinery/airalarm/A = holder
switch(wire)
if(WIRE_POWER) // Short out forever.
A.shock(usr, 50)
A.shorted = !mend
- A.update_icon()
+ A.update_appearance()
if(WIRE_IDSCAN)
if(!mend)
A.locked = TRUE
@@ -71,9 +66,10 @@
A.aidisabled = mend // Enable/disable AI control.
if(WIRE_PANIC) // Force panic syphon on.
if(!mend && !A.shorted)
- A.mode = 3 // AALARM_MODE_PANIC
- A.apply_mode(usr)
+ A.select_mode(usr, /datum/air_alarm_mode/panic_siphon)
if(WIRE_ALARM) // Post alarm.
if(A.alarm_manager.send_alarm(ALARM_ATMOS))
- A.post_alert(2)
- A.update_icon()
+ A.danger_level = AIR_ALARM_ALERT_HAZARD
+ A.update_appearance()
+ if(WIRE_SPEAKER)
+ A.speaker_enabled = mend
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index ac5310f19e421..4a587baa555b8 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -27,10 +27,23 @@
var/list/turf/turfs_to_uncontain = list()
///Do we have an active fire alarm?
- var/fire = null
-
+ var/fire = FALSE
+ ///A var for whether the area allows for detecting fires/etc. Disabled or enabled at a fire alarm, checked by fire locks.
+ var/fire_detect = TRUE
+ ///A list of all fire locks in this area. Used by fire alarm panels when resetting fire locks or activating all in an area
+ var/list/firedoors
+ ///A list of firelocks currently active. Used by fire alarms when setting their icons.
+ var/list/active_firelocks
+ ///A list of all fire alarms in this area. Used by firelocks and burglar alarms to change icon state.
+ var/list/firealarms = list()
///Alarm type to count of sources. Not usable for ^ because we handle fires differently
var/list/active_alarms = list()
+ /// The current alarm fault status
+ var/fault_status = AREA_FAULT_NONE
+ /// The source machinery for the area's fault status
+ var/fault_location
+ ///List of all lights in our area
+ var/list/lights = list()
///We use this just for fire alarms, because they're area based right now so one alarm going poof shouldn't prevent you from clearing your alarms listing
var/datum/alarm_handler/alarm_manager
@@ -89,13 +102,16 @@
flags_1 = CAN_BE_DIRTY_1
- var/list/firedoors
var/list/cameras
- var/list/firealarms
- var/firedoors_last_closed_on = 0
/// typecache to limit the areas that atoms in this area can smooth with, used for shuttles IIRC
var/list/canSmoothWithAreas
+ /// List of all air vents in the area
+ var/list/obj/machinery/atmospherics/components/unary/vent_pump/air_vents = list()
+
+ /// List of all air scrubbers in the area
+ var/list/obj/machinery/atmospherics/components/unary/vent_scrubber/air_scrubbers = list()
+
var/list/power_usage
var/lighting_colour_tube = "#FFF6ED"
@@ -343,81 +359,14 @@ GLOBAL_LIST_EMPTY(teleportlocs)
GLOB.areas_by_type[type] = null
GLOB.sortedAreas -= src
GLOB.areas -= src
- if(fire)
- STOP_PROCESSING(SSobj, src)
+ STOP_PROCESSING(SSobj, src)
QDEL_NULL(alarm_manager)
+ firedoors = null
+ firealarms = null
+ air_vents = null
+ air_scrubbers = null
return ..()
-/**
- * Try to close all the firedoors in the area
- */
-/area/proc/ModifyFiredoors(opening)
- if(firedoors)
- firedoors_last_closed_on = world.time
- for(var/FD in firedoors)
- var/obj/machinery/door/firedoor/D = FD
- var/cont = !D.welded
- if(cont && opening) //don't open if adjacent area is on fire
- for(var/I in D.affecting_areas)
- var/area/A = I
- if(A.fire)
- cont = FALSE
- break
- if(cont && D.is_operational)
- if(D.operating)
- D.nextstate = opening ? FIREDOOR_OPEN : FIREDOOR_CLOSED
- else if(!(D.density ^ opening))
- INVOKE_ASYNC(D, (opening ? TYPE_PROC_REF(/obj/machinery/door/firedoor, open) : TYPE_PROC_REF(/obj/machinery/door/, close)))
-
-/**
- * Generate an firealarm alert for this area
- *
- * Sends to all ai players, alert consoles, drones and alarm monitor programs in the world
- *
- * Also starts the area processing on SSobj
- */
-/area/proc/firealert(obj/source)
- if(always_unpowered == 1) //no fire alarms in space/asteroid
- return
-
- if(!fire)
- set_fire_alarm_effect()
- ModifyFiredoors(FALSE)
- for(var/item in firealarms)
- var/obj/machinery/firealarm/F = item
- F.update_appearance()
- alarm_manager.send_alarm(ALARM_FIRE, source)
- START_PROCESSING(SSobj, src)
-
-
-
-/**
- * Reset the firealarm alert for this area
- *
- * resets the alert sent to all ai players, alert consoles, drones and alarm monitor programs
- * in the world
- *
- * Also cycles the icons of all firealarms and deregisters the area from processing on SSOBJ
- */
-/area/proc/firereset(obj/source)
- if(fire)
- unset_fire_alarm_effects()
- ModifyFiredoors(TRUE)
- STOP_PROCESSING(SSobj, src)
- for(var/item in firealarms)
- var/obj/machinery/firealarm/F = item
- F.update_appearance()
- alarm_manager.clear_alarm(ALARM_FIRE, source)
- STOP_PROCESSING(SSobj, src)
-
-
-/**
- * If 100 ticks has elapsed, toggle all the firedoors closed again
- */
-/area/process()
- if(firedoors_last_closed_on + 100 < world.time) //every 10 seconds
- ModifyFiredoors(FALSE)
-
/**
* Close and lock a door passed into this proc
*
@@ -440,37 +389,25 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(always_unpowered) //no burglar alarms in space/asteroid
return
//Trigger alarm effect
- set_fire_alarm_effect()
+ set_fire_effect(TRUE)
for(var/obj/machinery/door/door in src)
close_and_lock_door(door)
/**
- * Trigger the fire alarm visual affects in an area
- *
- * Updates the fire light on fire alarms in the area and sets all lights to emergency mode
- */
-/area/proc/set_fire_alarm_effect()
- fire = TRUE
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- for(var/alarm in firealarms)
- var/obj/machinery/firealarm/F = alarm
- F.update_fire_light(fire)
- for(var/obj/machinery/light/L in src)
- L.update(TRUE, TRUE, TRUE)
-
-/**
- * unset the fire alarm visual affects in an area
- *
- * Updates the fire light on fire alarms in the area and sets all lights to emergency mode
- */
-/area/proc/unset_fire_alarm_effects()
- fire = FALSE
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- for(var/alarm in firealarms)
- var/obj/machinery/firealarm/F = alarm
- F.update_fire_light(fire)
- for(var/obj/machinery/light/L in src)
- L.update(TRUE, TRUE, TRUE)
+ * Set the fire alarm visual affects in an area
+ *
+ * Allows interested parties (lights and fire alarms) to react
+ */
+/area/proc/set_fire_effect(new_fire, fault_type, fault_source)
+ if(new_fire == fire)
+ return
+ fire = new_fire
+ fault_status = fault_type
+ if(fire)
+ fault_location = fault_source
+ else
+ fault_location = null
+ SEND_SIGNAL(src, COMSIG_AREA_FIRE_CHANGED, fire)
/area/proc/set_pressure_alarm_effect() //Just like fire alarm but blue
vacuum = TRUE
diff --git a/code/game/atom_defense.dm b/code/game/atom_defense.dm
index c51f88f08b7f6..3c478002f71bb 100644
--- a/code/game/atom_defense.dm
+++ b/code/game/atom_defense.dm
@@ -109,7 +109,8 @@
///what happens when the atom's integrity reaches zero.
/atom/proc/atom_destruction(damage_flag)
- return
+ SHOULD_CALL_PARENT(TRUE)
+ SEND_SIGNAL(src, COMSIG_ATOM_DESTRUCTION, damage_flag)
///changes max_integrity while retaining current health percentage, returns TRUE if the atom got broken.
/atom/proc/modify_max_integrity(new_max, can_break = TRUE, damage_type = BRUTE)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 66186915ee147..575ef5f0674cb 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -1944,7 +1944,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom)
/atom/proc/plasma_ignition(strength, mob/user, reagent_reaction)
var/turf/T = get_turf(src)
var/datum/gas_mixture/environment = T.return_air()
- if(environment.get_moles(GAS_O2) >= PLASMA_MINIMUM_OXYGEN_NEEDED) //Flashpoint ignition can only occur with at least this much oxygen present
+ if(GET_MOLES(/datum/gas/oxygen, environment) >= PLASMA_MINIMUM_OXYGEN_NEEDED) //Flashpoint ignition can only occur with at least this much oxygen present
//no reason to alert admins or create an explosion if there's not enough power to actually make an explosion
if(strength > 1)
if(user)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 794c52c83cf76..8c54f02d9080c 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -110,9 +110,9 @@
if(loc)
//Restore air flow if we were blocking it (movables with ATMOS_PASS_PROC will need to do this manually if necessary)
- if(((CanAtmosPass == ATMOS_PASS_DENSITY && density) || CanAtmosPass == ATMOS_PASS_NO) && isturf(loc))
- CanAtmosPass = ATMOS_PASS_YES
- air_update_turf(TRUE)
+ if(((can_atmos_pass == ATMOS_PASS_DENSITY && density) || can_atmos_pass == ATMOS_PASS_NO) && isturf(loc))
+ can_atmos_pass = ATMOS_PASS_YES
+ air_update_turf(TRUE, FALSE)
loc.handle_atom_del(src)
if(opacity)
diff --git a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
index 3217233bbeda9..ce0534a895e3d 100644
--- a/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
+++ b/code/game/gamemodes/dynamic/dynamic_rulesets_midround.dm
@@ -411,7 +411,7 @@
continue // No parent vent
// Stops Aliens getting stuck in small networks.
// See: Security, Virology
- if(length(temp_vent_parent.other_atmosmch) > 20)
+ if(length(temp_vent_parent.other_atmos_machines) > 20)
vents += temp_vent
if(!length(vents))
log_game("DYNAMIC: [ruletype] ruleset [name] ready() failed due to no valid spawn locations.")
@@ -707,7 +707,7 @@
var/datum/pipeline/temp_vent_parent = temp_vent.parents[1]
if(!temp_vent_parent)
continue // No parent vent
- if(length(temp_vent_parent.other_atmosmch) > 20)
+ if(length(temp_vent_parent.other_atmos_machines) > 20)
vents += temp_vent // Makes sure the pipeline is large enough
if(!length(vents))
log_game("DYNAMIC: [ruletype] ruleset [name] ready() failed due to no valid spawn locations.")
diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm
index 1b80a82c1e2fa..28f9b58003668 100644
--- a/code/game/gamemodes/objective_items.dm
+++ b/code/game/gamemodes/objective_items.dm
@@ -143,7 +143,8 @@
/datum/objective_item/steal/plasma/check_special_completion(obj/item/tank/T)
var/target_amount = text2num(name)
var/found_amount = 0
- found_amount += T.air_contents.get_moles(GAS_PLASMA)
+ var/datum/gas_mixture/mix = T.return_air()
+ found_amount += GET_MOLES(/datum/gas/plasma, mix)
return found_amount>=target_amount
/datum/objective_item/steal/functionalai
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index 78cbdbe27c36d..49e957192815e 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -137,14 +137,18 @@ Class Procs:
var/tgui_id // ID of TGUI interface
var/ui_style // ID of custom TGUI style (optional)
- ///Is this machine currently in the atmos machinery queue?
- var/atmos_processing = FALSE
///Is this machine currently in the atmos machinery queue, but also interacting with turf air?
var/interacts_with_air = FALSE
/// Maximum time an EMP will disable this machine for
var/emp_disable_time = 2 MINUTES
+ ///Is this machine currently in the atmos machinery queue?
+ var/atmos_processing = FALSE
+
+ /// Disables some optimizations
+ var/always_area_sensitive = FALSE
+
/obj/machinery/Initialize(mapload)
if(!armor)
armor = list(MELEE = 25, BULLET = 10, LASER = 10, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 50, ACID = 70, STAMINA = 0, BLEED = 0)
@@ -196,6 +200,61 @@ Class Procs:
QDEL_NULL(circuit)
return ..()
+/**
+ * proc to call when the machine starts to require power after a duration of not requiring power
+ * sets up power related connections to its area if it exists and becomes area sensitive
+ * does not affect power usage itself
+ *
+ * Returns TRUE if it triggered a full registration, FALSE otherwise
+ * We do this so machinery that want to sidestep the area sensitiveity optimization can
+ */
+/obj/machinery/proc/setup_area_power_relationship()
+ var/area/our_area = get_area(src)
+ if(our_area)
+ RegisterSignal(our_area, COMSIG_AREA_POWER_CHANGE, PROC_REF(power_change))
+
+ if(HAS_TRAIT_FROM(src, TRAIT_AREA_SENSITIVE, INNATE_TRAIT)) // If we for some reason have not lost our area sensitivity, there's no reason to set it back up
+ return FALSE
+
+ become_area_sensitive(INNATE_TRAIT)
+ RegisterSignal(src, COMSIG_ENTER_AREA, PROC_REF(on_enter_area))
+ RegisterSignal(src, COMSIG_EXIT_AREA, PROC_REF(on_exit_area))
+ return TRUE
+
+/**
+ * proc to call when the machine stops requiring power after a duration of requiring power
+ * saves memory by removing the power relationship with its area if it exists and loses area sensitivity
+ * does not affect power usage itself
+ */
+/obj/machinery/proc/remove_area_power_relationship()
+ var/area/our_area = get_area(src)
+ if(our_area)
+ UnregisterSignal(our_area, COMSIG_AREA_POWER_CHANGE)
+
+ if(always_area_sensitive)
+ return
+
+ lose_area_sensitivity(INNATE_TRAIT)
+ UnregisterSignal(src, COMSIG_ENTER_AREA)
+ UnregisterSignal(src, COMSIG_EXIT_AREA)
+
+/obj/machinery/proc/on_enter_area(datum/source, area/area_to_register)
+ SIGNAL_HANDLER
+ // If we're always area sensitive, and this is called while we have no power usage, do nothing and return
+ if(always_area_sensitive && use_power == NO_POWER_USE)
+ return
+ update_current_power_usage()
+ power_change()
+ RegisterSignal(area_to_register, COMSIG_AREA_POWER_CHANGE, PROC_REF(power_change))
+
+/obj/machinery/proc/on_exit_area(datum/source, area/area_to_unregister)
+ SIGNAL_HANDLER
+ // If we're always area sensitive, and this is called while we have no power usage, do nothing and return
+ if(always_area_sensitive && use_power == NO_POWER_USE)
+ return
+ unset_static_power()
+ UnregisterSignal(area_to_unregister, COMSIG_AREA_POWER_CHANGE)
+
/obj/machinery/proc/locate_machinery()
return
@@ -360,7 +419,7 @@ Class Procs:
/obj/machinery/can_interact(mob/user)
var/silicon = issilicon(user)
var/admin_ghost = IsAdminGhost(user)
- var/living = ishuman(user) // /mob/living/carbon/HUMANS, not /mob/living.
+ var/living = isliving(user) // /mob/living/carbon/HUMANS, not /mob/living.
if((machine_stat & (NOPOWER|BROKEN)) && !(interaction_flags_machine & INTERACT_MACHINE_OFFLINE)) // Check if the machine is broken, and if we can still interact with it if so
return FALSE
@@ -373,7 +432,13 @@ Class Procs:
if(!(interaction_flags_machine & INTERACT_MACHINE_ALLOW_SILICON))
return FALSE
- else if(living) // If we are a living human
+ var/is_dextrous = FALSE
+ if(isanimal(user))
+ var/mob/living/simple_animal/user_as_animal = user
+ if (user_as_animal.dextrous)
+ is_dextrous = TRUE
+
+ if(is_dextrous || user.can_hold_items()) // If we are a living mob with hand slots or a dextrous simple animal.
var/mob/living/L = user
if(interaction_flags_machine & INTERACT_MACHINE_REQUIRES_SILICON) // First make sure the machine doesn't require silicon interaction
@@ -558,7 +623,6 @@ Class Procs:
transfer_fingerprints_to(new_frame)
/obj/machinery/atom_break(damage_flag)
- SHOULD_CALL_PARENT(TRUE)
. = ..()
if(!(machine_stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1))
set_machine_stat(machine_stat | BROKEN)
diff --git a/code/game/machinery/airlock_control.dm b/code/game/machinery/airlock_control.dm
index 76100cebd76c3..12e9827196291 100644
--- a/code/game/machinery/airlock_control.dm
+++ b/code/game/machinery/airlock_control.dm
@@ -3,85 +3,24 @@
// This code allows for airlocks to be controlled externally by setting an id_tag and comm frequency (disables ID access)
/obj/machinery/door/airlock
var/frequency
- var/datum/radio_frequency/radio_connection
smoothing_groups = list(SMOOTH_GROUP_AIRLOCK)
-/obj/machinery/door/airlock/receive_signal(datum/signal/signal)
- if(!signal)
- return
-
- if(id_tag != signal.data["tag"] || !signal.data["command"])
- return
-
- switch(signal.data["command"])
- if("open")
- open(1)
-
- if("close")
- close(1)
-
- if("unlock")
- locked = FALSE
- update_icon()
-
- if("lock")
- locked = TRUE
- update_icon()
-
- if("secure_open")
- locked = FALSE
- update_icon()
-
- sleep(2)
- open(1)
-
- locked = TRUE
- update_icon()
-
- if("secure_close")
- locked = FALSE
- close(1)
-
- locked = TRUE
- sleep(2)
- update_icon()
-
- send_status()
-
-
-/obj/machinery/door/airlock/proc/send_status()
- if(radio_connection)
- var/datum/signal/signal = new(list(
- "tag" = id_tag,
- "timestamp" = world.time,
- "door_status" = density ? "closed" : "open",
- "lock_status" = locked ? "locked" : "unlocked"
- ))
- radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
-
-
-/obj/machinery/door/airlock/open(surpress_send)
- . = ..()
- if(!surpress_send)
- send_status()
-
-
-/obj/machinery/door/airlock/close(surpress_send)
- . = ..()
- if(!surpress_send)
- send_status()
-
-
-/obj/machinery/door/airlock/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- if(new_frequency)
- frequency = new_frequency
- radio_connection = SSradio.add_object(src, frequency, RADIO_AIRLOCK)
-
-/obj/machinery/door/airlock/Destroy()
- if(frequency)
- SSradio.remove_object(src,frequency)
- return ..()
+/// Forces the airlock to unbolt and open
+/obj/machinery/door/airlock/proc/secure_open()
+ locked = FALSE
+ update_icon()
+ stoplag(0.2 SECONDS)
+ open(forced = TRUE)
+ locked = TRUE
+ update_icon()
+
+/// Forces the airlock to close and bolt
+/obj/machinery/door/airlock/proc/secure_close()
+ locked = FALSE
+ close(forced = TRUE)
+ locked = TRUE
+ stoplag(0.2 SECONDS)
+ update_icon()
/obj/machinery/airlock_sensor
icon = 'icons/obj/airlock_machines.dmi'
@@ -92,9 +31,6 @@
power_channel = AREA_USAGE_ENVIRON
var/master_tag
- var/frequency = FREQ_AIRLOCK_CONTROL
-
- var/datum/radio_frequency/radio_connection
var/on = TRUE // Reviewer: I can't find any way to turn this thing off but it stays
var/alert = FALSE
@@ -124,12 +60,10 @@
. = ..()
if(.)
return
- var/datum/signal/signal = new(list(
- "tag" = master_tag,
- "command" = "cycle"
- ))
- radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
+ var/obj/machinery/airlock_controller/airlock_controller = GLOB.objects_by_id_tag[master_tag]
+ airlock_controller?.cycle()
+
flick("airlock_sensor_cycle", src)
/obj/machinery/airlock_sensor/process()
@@ -140,25 +74,4 @@
alert = !alert
update_icon()
- var/datum/signal/signal = new(list(
- "tag" = id_tag,
- "timestamp" = world.time,
- "pressure" = num2text(pressure)
- ))
-
- radio_connection.post_signal(src, signal, range = AIRLOCK_CONTROL_RANGE, filter = RADIO_AIRLOCK)
-
-/obj/machinery/airlock_sensor/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = SSradio.add_object(src, frequency, RADIO_AIRLOCK)
-
-/obj/machinery/airlock_sensor/Initialize(mapload)
- . = ..()
- set_frequency(frequency)
-
-/obj/machinery/airlock_sensor/Destroy()
- SSradio.remove_object(src,frequency)
- return ..()
-
#undef AIRLOCK_CONTROL_RANGE
diff --git a/code/game/machinery/airlock_cycle_control.dm b/code/game/machinery/airlock_cycle_control.dm
index 8496516b8090a..94925b4fe478e 100644
--- a/code/game/machinery/airlock_cycle_control.dm
+++ b/code/game/machinery/airlock_cycle_control.dm
@@ -549,7 +549,7 @@
for(var/I = 1; I <= turfs.len; I++)
var/turf/open/T = turfs[I]
if(assume_roles)
- T.ImmediateCalculateAdjacentTurfs()
+ T.immediate_calculate_adjacent_turfs()
for(var/turf/open/T2 in T.atmos_adjacent_turfs)
if(get_dist(initial_turf, T2) > 5)
config_error_str = "Airlock too big"
@@ -813,7 +813,7 @@
playsound(src, "sparks", 50, 1)
/obj/machinery/advanced_airlock_controller/atom_break(damage_flag)
- ..()
+ . = ..()
update_icon()
/obj/machinery/advanced_airlock_controller/deconstruct(disassembled = TRUE)
diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm
index 98ca8c0d0d025..6c1aea0236e4f 100644
--- a/code/game/machinery/computer/atmos_alert.dm
+++ b/code/game/machinery/computer/atmos_alert.dm
@@ -6,20 +6,9 @@
icon_keyboard = "atmos_key"
var/list/priority_alarms = list()
var/list/minor_alarms = list()
- var/receive_frequency = FREQ_ATMOS_ALARMS
- var/datum/radio_frequency/radio_connection
light_color = LIGHT_COLOR_CYAN
-/obj/machinery/computer/atmos_alert/Initialize(mapload)
- . = ..()
- set_frequency(receive_frequency)
-
-/obj/machinery/computer/atmos_alert/Destroy()
- SSradio.remove_object(src, receive_frequency)
- return ..()
-
-
/obj/machinery/computer/atmos_alert/ui_state(mob/user)
return GLOB.default_state
@@ -58,30 +47,29 @@
if(.)
update_icon()
-/obj/machinery/computer/atmos_alert/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, receive_frequency)
- receive_frequency = new_frequency
- radio_connection = SSradio.add_object(src, receive_frequency, RADIO_ATMOSIA)
-
-/obj/machinery/computer/atmos_alert/receive_signal(datum/signal/signal)
- if(!signal)
- return
-
- var/zone = signal.data["zone"]
- var/severity = signal.data["alert"]
-
- if(!zone || !severity)
- return
-
- minor_alarms -= zone
- priority_alarms -= zone
- if(severity == "severe")
- priority_alarms += zone
- else if (severity == "minor")
- minor_alarms += zone
- update_icon()
- ui_update()
- return
+/obj/machinery/computer/atmos_alert/process()
+ . = ..()
+ if (!.)
+ return FALSE
+ var/alarm_count = priority_alarms.len + minor_alarms.len
+ priority_alarms.Cut()
+ minor_alarms.Cut()
+ for (var/obj/machinery/airalarm/air_alarm as anything in GLOB.air_alarms)
+ if (air_alarm.z != z)
+ continue
+ switch (air_alarm.danger_level)
+ if (AIR_ALARM_ALERT_NONE)
+ continue
+ if (AIR_ALARM_ALERT_MINOR)
+ minor_alarms += get_area_name(air_alarm, format_text = TRUE)
+ if (AIR_ALARM_ALERT_SEVERE)
+ priority_alarms += get_area_name(air_alarm, format_text = TRUE)
+
+ // Either we got new alarms, or we have no alarms anymore
+ if ((alarm_count == 0) != (minor_alarms.len + priority_alarms.len == 0))
+ update_appearance(UPDATE_ICON)
+
+ return TRUE
/obj/machinery/computer/atmos_alert/update_icon()
..()
diff --git a/code/game/machinery/computer/atmos_computers/_air_sensor.dm b/code/game/machinery/computer/atmos_computers/_air_sensor.dm
new file mode 100644
index 0000000000000..65b0c4506e719
--- /dev/null
+++ b/code/game/machinery/computer/atmos_computers/_air_sensor.dm
@@ -0,0 +1,188 @@
+/// Gas tank air sensor.
+/// These always hook to monitors, be mindful of them
+/obj/machinery/air_sensor
+ name = "gas sensor"
+ icon = 'icons/obj/wallmounts.dmi'
+ icon_state = "gsensor1"
+ resistance_flags = FIRE_PROOF
+ power_channel = AREA_USAGE_ENVIRON
+ active_power_usage = 1
+ var/on = TRUE
+
+ /// The unique string that represents which atmos chamber to associate with.
+ var/chamber_id
+ /// The inlet[injector] controlled by this sensor
+ var/inlet_id
+ /// The outlet[vent pump] controlled by this sensor
+ var/outlet_id
+ /// The air alarm connected to this sensor
+ var/obj/machinery/airalarm/connected_airalarm
+
+/obj/machinery/air_sensor/Initialize(mapload)
+ id_tag = assign_random_name()
+
+ //this global list of air sensors is available to all station monitering consoles round start and to new consoles made during the round
+ if(mapload)
+ GLOB.map_loaded_sensors[chamber_id] = id_tag
+ inlet_id = CHAMBER_INPUT_FROM_ID(chamber_id)
+ outlet_id = CHAMBER_OUTPUT_FROM_ID(chamber_id)
+
+ return ..()
+
+/obj/machinery/air_sensor/Destroy()
+ reset()
+ return ..()
+
+/obj/machinery/air_sensor/return_air()
+ if(!on)
+ return
+ . = ..()
+
+/obj/machinery/air_sensor/process()
+ //update appearance according to power state
+ if(machine_stat & NOPOWER)
+ if(on)
+ on = FALSE
+ update_appearance()
+ else if(!on)
+ on = TRUE
+ update_appearance()
+
+/obj/machinery/air_sensor/examine(mob/user)
+ . = ..()
+ . += "Use a multitool to link it to an injector, vent, or air alarm, or reset its ports."
+ . += "Click with hand to turn it off."
+
+/obj/machinery/air_sensor/attack_hand(mob/living/user, list/modifiers)
+ . = ..()
+
+ //switched off version of this air sensor but still anchored to the ground
+ var/obj/item/air_sensor/sensor = new(drop_location(), inlet_id, outlet_id)
+ sensor.set_anchored(TRUE)
+ sensor.balloon_alert(user, "sensor turned off")
+
+ //delete self
+ qdel(src)
+
+/obj/machinery/air_sensor/update_icon_state()
+ icon_state = "gsensor[on]"
+ return ..()
+
+/obj/machinery/air_sensor/proc/reset()
+ inlet_id = null
+ outlet_id = null
+ if(connected_airalarm)
+ connected_airalarm.disconnect_sensor()
+ // if air alarm and sensor were linked at roundstart we allow them to link to new devices
+ connected_airalarm.allow_link_change = TRUE
+ connected_airalarm = null
+
+///right click with multi tool to disconnect everything
+/obj/machinery/air_sensor/multitool_act_secondary(mob/living/user, obj/item/tool)
+ balloon_alert(user, "reset ports")
+ reset()
+ return TRUE
+
+REGISTER_BUFFER_HANDLER(/obj/machinery/air_sensor)
+
+DEFINE_BUFFER_HANDLER(/obj/machinery/air_sensor)
+ if (TRY_STORE_IN_BUFFER(buffer_parent, src))
+ to_chat(user, "You register [src] in [buffer_parent]'s buffer.")
+ return COMPONENT_BUFFER_RECEIVED
+ return NONE
+
+/**
+ * A portable version of the /obj/machinery/air_sensor
+ * Wrenching it & turning it on will convert it back to /obj/machinery/air_sensor
+ * Unwelding /obj/machinery/air_sensor will turn it back to /obj/item/air_sensor
+ * The logic is same as meters
+ */
+/obj/item/air_sensor
+ name = "Air Sensor"
+ desc = "A device designed to detect gases and their concentration in an area."
+ icon = 'icons/obj/wallmounts.dmi'
+ icon_state = "gsensor0"
+ custom_materials = list(/datum/material/iron = 100, /datum/material/glass = 100)
+ /// The injector linked with this sensor
+ var/input_id
+ /// The vent pump linked with this sensor
+ var/output_id
+
+/obj/item/air_sensor/Initialize(mapload, inlet, outlet)
+ . = ..()
+ input_id = inlet
+ output_id = outlet
+
+/obj/item/air_sensor/examine(mob/user)
+ . = ..()
+ if(anchored)
+ . += "It's wrenched in place"
+ else
+ . += "It should be wrenched in place to turn it on."
+ . += "It could be welded apart."
+ . += "Click with hand to turn it on."
+
+/obj/item/air_sensor/attack_hand(mob/user, list/modifiers)
+ . = ..()
+ if(!anchored)
+ return
+
+ //List of air sensor's by name
+ var/list/available_sensors = list()
+ for(var/chamber_id in GLOB.station_gas_chambers)
+ //don't let it conflict with existing distro & waste moniter meter's
+ if(chamber_id == ATMOS_GAS_MONITOR_DISTRO)
+ continue
+ if(chamber_id == ATMOS_GAS_MONITOR_WASTE)
+ continue
+ available_sensors += GLOB.station_gas_chambers[chamber_id]
+
+ //make the choice
+ var/chamber_name = tgui_input_list(user, "Select Sensor Purpose", "Select Sensor ID", available_sensors)
+ if(isnull(chamber_name))
+ return
+
+ //map chamber name back to id
+ var/target_chamber
+ for(var/chamber_id in GLOB.station_gas_chambers)
+ if(GLOB.station_gas_chambers[chamber_id] != chamber_name)
+ continue
+ target_chamber = chamber_id
+ break
+
+ //build the sensor from the subtypes of sensor's available
+ var/static/list/chamber_subtypes = null
+ if(isnull(chamber_subtypes))
+ chamber_subtypes = subtypesof(/obj/machinery/air_sensor)
+ for(var/obj/machinery/air_sensor/sensor as anything in chamber_subtypes)
+ if(initial(sensor.chamber_id) != target_chamber)
+ continue
+
+ //make real air sensor in its place
+ var/obj/machinery/air_sensor/new_sensor = new sensor(get_turf(src))
+ new_sensor.inlet_id = input_id
+ new_sensor.outlet_id = output_id
+ new_sensor.balloon_alert(user, "sensor turned on")
+ qdel(src)
+
+ break
+
+/obj/item/air_sensor/wrench_act(mob/living/user, obj/item/tool)
+ if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN)
+ return TRUE
+
+/obj/item/air_sensor/welder_act(mob/living/user, obj/item/tool)
+ if(!tool.tool_start_check(user, amount = 1))
+ return TRUE
+
+ loc.balloon_alert(user, "dismantling sensor")
+ if(!tool.use_tool(src, user, 2 SECONDS, volume = 30, amount = 1))
+ return TRUE
+ loc.balloon_alert(user, "sensor dismanteled")
+
+ deconstruct(TRUE)
+ return TRUE
+
+/obj/item/air_sensor/atom_deconstruct(disassembled)
+ new /obj/item/analyzer(loc)
+ new /obj/item/stack/sheet/iron(loc, 1)
diff --git a/code/game/machinery/computer/atmos_computers/_atmos_control.dm b/code/game/machinery/computer/atmos_computers/_atmos_control.dm
new file mode 100644
index 0000000000000..ff3753248da3e
--- /dev/null
+++ b/code/game/machinery/computer/atmos_computers/_atmos_control.dm
@@ -0,0 +1,181 @@
+
+/////////////////////////////////////////////////////////////
+// GENERAL AIR CONTROL (a.k.a atmos computer)
+/////////////////////////////////////////////////////////////
+/obj/machinery/computer/atmos_control
+ name = "atmospherics monitoring"
+ desc = "Used to monitor the station's atmospherics sensors."
+ icon_screen = "tank"
+ icon_keyboard = "atmos_key"
+ circuit = /obj/item/circuitboard/computer/atmos_control
+ light_color = LIGHT_COLOR_CYAN
+
+ /// Which sensors do we want to listen to.
+ /// Assoc of list[chamber_id] = readable_chamber_name
+ var/list/atmos_chambers
+
+ /// Whether we can actually adjust the chambers or not.
+ var/control = TRUE
+ /// Whether we are allowed to reconnect.
+ var/reconnecting = TRUE
+
+ /// Was this computer multitooled before. If so copy the list connected_sensors as it now maintain's its own sensors independent of the map loaded one's
+ var/was_multi_tooled = FALSE
+
+ /// list of all sensors[key is chamber id, value is id of air sensor linked to this chamber] monitered by this computer
+ var/list/connected_sensors
+
+/obj/machinery/computer/atmos_control/Initialize(mapload)
+ . = ..()
+ AddComponent(/datum/component/buffer)
+
+/// Reconnect only works for station based chambers.
+/obj/machinery/computer/atmos_control/proc/reconnect(mob/user)
+ if(!reconnecting)
+ return FALSE
+
+ // We only prompt the user with the sensors that are actually available.
+ var/available_devices = list()
+
+ for (var/chamber_identifier in GLOB.station_gas_chambers)
+ if (!("[chamber_identifier]_in" in GLOB.objects_by_id_tag) && !("[chamber_identifier]_out" in GLOB.objects_by_id_tag))
+ continue
+
+ available_devices[GLOB.station_gas_chambers[chamber_identifier]] = chamber_identifier
+
+ // As long as we dont put any funny chars in the strings it should match.
+ var/new_name = tgui_input_list(user, "Select the device set", "Reconnect", available_devices)
+ var/new_id = available_devices[new_name]
+ if(isnull(new_id))
+ return FALSE
+
+ atmos_chambers = list()
+ atmos_chambers[new_id] = new_name
+ name = new_name + (control ? " Control" : " Monitor")
+
+ return TRUE
+
+
+
+REGISTER_BUFFER_HANDLER(/obj/machinery/computer/atmos_control)
+
+DEFINE_BUFFER_HANDLER(/obj/machinery/computer/atmos_control)
+ if (istype(buffer,/obj/machinery/air_sensor))
+ var/obj/machinery/air_sensor/sensor = buffer
+ to_chat(user, "You link [src] with [buffer] in [buffer_parent] buffer.")
+ connected_sensors = connected_sensors.Copy()
+ was_multi_tooled = TRUE
+ //register the sensor's unique ID with its assositated chamber
+ connected_sensors[sensor.chamber_id] = sensor.id_tag
+ ui_update()
+ return COMPONENT_BUFFER_RECEIVED
+ return NONE
+
+
+/obj/machinery/computer/atmos_control/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "AtmosControlConsole")
+ ui.open()
+ ui.set_autoupdate(TRUE) // Gas sensors
+
+/obj/machinery/computer/atmos_control/ui_static_data(mob/user)
+ var/data = list()
+ data["maxInput"] = MAX_TRANSFER_RATE
+ data["maxOutput"] = MAX_OUTPUT_PRESSURE
+ data["control"] = control
+ data["reconnecting"] = reconnecting
+ return data
+
+/obj/machinery/computer/atmos_control/ui_data(mob/user)
+ var/data = list()
+
+ data["chambers"] = list()
+ for(var/chamber_id in atmos_chambers)
+ var/list/chamber_info = list()
+ chamber_info["id"] = chamber_id
+ chamber_info["name"] = atmos_chambers[chamber_id]
+
+ var/obj/machinery/sensor = GLOB.objects_by_id_tag["[chamber_id]_sensor"]
+ if(!QDELETED(sensor))
+ chamber_info["gasmix"] = gas_mixture_parser(sensor.return_air())
+
+ if(istype(sensor, /obj/machinery/air_sensor)) //distro & waste loop are not air sensors and don't have these functions
+
+ var/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/input = GLOB.objects_by_id_tag["[chamber_id]_in"]
+ if (!QDELETED(input))
+ chamber_info["input_info"] = list(
+ "active" = input.on,
+ "amount" = input.volume_rate,
+ )
+
+ var/obj/machinery/atmospherics/components/unary/vent_pump/output = GLOB.objects_by_id_tag["[chamber_id]_out"]
+ if (!QDELETED(output))
+ chamber_info["output_info"] = list(
+ "active" = output.on,
+ "amount" = output.internal_pressure_bound,
+ )
+
+ data["chambers"] += list(chamber_info)
+ return data
+/obj/machinery/computer/atmos_control/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(. || !(control || reconnecting))
+ return
+
+ var/chamber = params["chamber"]
+
+ switch(action)
+ if("toggle_input")
+ if (!(chamber in atmos_chambers))
+ return TRUE
+
+ var/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/input = GLOB.objects_by_id_tag["[chamber]_in"]
+ input?.on = !input.on
+ input.update_icon()
+ if("toggle_output")
+ if (!(chamber in atmos_chambers))
+ return TRUE
+
+ var/obj/machinery/atmospherics/components/unary/vent_pump/output = GLOB.objects_by_id_tag["[chamber]_out"]
+ output?.on = !output.on
+ output.update_icon()
+ if("adjust_input")
+ if (!(chamber in atmos_chambers))
+ return TRUE
+
+ var/target = text2num(params["rate"])
+ if(isnull(target))
+ return TRUE
+ target = clamp(target, 0, MAX_TRANSFER_RATE)
+ var/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/input = GLOB.objects_by_id_tag["[chamber]_in"]
+ input?.volume_rate = clamp(target, 0, min(input.airs[1].volume, MAX_TRANSFER_RATE))
+ if("adjust_output")
+ var/target = text2num(params["rate"])
+ if(isnull(target))
+ return TRUE
+
+ var/obj/machinery/atmospherics/components/unary/vent_pump/output = GLOB.objects_by_id_tag["[chamber]_out"]
+ output?.internal_pressure_bound = clamp(target, 0, ATMOS_PUMP_MAX_PRESSURE)
+ if("reconnect")
+ reconnect(usr)
+
+ return TRUE
+
+/////////////////////////////////////////////////////////////
+// LARGE TANK CONTROL
+/////////////////////////////////////////////////////////////
+
+/obj/machinery/computer/atmos_control/nocontrol
+ control = FALSE
+ circuit = /obj/item/circuitboard/computer/atmos_control/nocontrol
+
+/obj/machinery/computer/atmos_control/noreconnect
+ reconnecting = FALSE
+ circuit = /obj/item/circuitboard/computer/atmos_control/noreconnect
+
+/// Vegetable
+/obj/machinery/computer/atmos_control/fixed
+ control = FALSE
+ reconnecting = FALSE
+ circuit = /obj/item/circuitboard/computer/atmos_control/fixed
diff --git a/code/game/machinery/computer/atmos_computers/_identifiers.dm b/code/game/machinery/computer/atmos_computers/_identifiers.dm
new file mode 100644
index 0000000000000..b176d3a3c0502
--- /dev/null
+++ b/code/game/machinery/computer/atmos_computers/_identifiers.dm
@@ -0,0 +1,54 @@
+// ATMOSIA GAS MONITOR SUITE TAGS
+// Things that use these include atmos control monitors, sensors, inputs, and outlets.
+// They last three adds _sensor, _in, and _out respectively to the id_tag variable.
+// Dont put underscores here, we use them as delimiters.
+
+#define ATMOS_GAS_MONITOR_O2 GAS_O2
+#define ATMOS_GAS_MONITOR_PLAS GAS_PLASMA
+#define ATMOS_GAS_MONITOR_AIR GAS_AIR
+#define ATMOS_GAS_MONITOR_MIX "mix"
+#define ATMOS_GAS_MONITOR_N2O GAS_N2O
+#define ATMOS_GAS_MONITOR_N2 GAS_N2
+#define ATMOS_GAS_MONITOR_CO2 GAS_CO2
+#define ATMOS_GAS_MONITOR_BZ GAS_BZ
+#define ATMOS_GAS_MONITOR_H2 GAS_HYDROGEN
+#define ATMOS_GAS_MONITOR_HYPERNOBLIUM GAS_HYPER_NOBLIUM
+#define ATMOS_GAS_MONITOR_PLUOXIUM GAS_PLUOXIUM
+#define ATMOS_GAS_MONITOR_TRITIUM GAS_TRITIUM
+#define ATMOS_GAS_MONITOR_H2O GAS_WATER_VAPOR
+#define ATMOS_GAS_MONITOR_INCINERATOR "incinerator"
+#define ATMOS_GAS_MONITOR_ORDNANCE_BURN "ordnanceburn"
+#define ATMOS_GAS_MONITOR_ORDNANCE_FREEZER "ordnancefreezer"
+#define ATMOS_GAS_MONITOR_DISTRO "distro"
+#define ATMOS_GAS_MONITOR_WASTE "waste"
+#define ATMOS_GAS_MONITOR_ENGINE "engine"
+
+///maps an air sensor's chamber id to its input valve[ i.e. outlet_injector] id
+#define CHAMBER_INPUT_FROM_ID(chamber_id) ((chamber_id) + "_in")
+///maps an air sensor's chamber id to its output valve[i.e. vent pump] id
+#define CHAMBER_OUTPUT_FROM_ID(chamber_id) ((chamber_id) + "_out")
+
+///list of all air sensor's created round start
+GLOBAL_LIST_EMPTY(map_loaded_sensors)
+
+// Human-readble names of these funny tags.
+GLOBAL_LIST_INIT(station_gas_chambers, list(
+ ATMOS_GAS_MONITOR_O2 = "Oxygen Supply",
+ ATMOS_GAS_MONITOR_PLAS = "Plasma Supply",
+ ATMOS_GAS_MONITOR_AIR = "Mixed Air Supply",
+ ATMOS_GAS_MONITOR_N2O = "Nitrous Oxide Supply",
+ ATMOS_GAS_MONITOR_N2 = "Nitrogen Supply",
+ ATMOS_GAS_MONITOR_CO2 = "Carbon Dioxide Supply",
+ ATMOS_GAS_MONITOR_BZ = "BZ Supply",
+ ATMOS_GAS_MONITOR_HYPERNOBLIUM = "Hypernoblium Supply",
+ ATMOS_GAS_MONITOR_NITRYL = "Nitryl Supply",
+ ATMOS_GAS_MONITOR_PLUOXIUM = "Pluoxium Supply",
+ ATMOS_GAS_MONITOR_TRITIUM = "Tritium Supply",
+ ATMOS_GAS_MONITOR_H2O = "Water Vapor Supply",
+ ATMOS_GAS_MONITOR_MIX = "Mix Chamber",
+ ATMOS_GAS_MONITOR_INCINERATOR = "Incinerator Chamber",
+ ATMOS_GAS_MONITOR_ORDNANCE_LAB = "Ordnance Chamber",
+ ATMOS_GAS_MONITOR_DISTRO = "Distribution Loop",
+ ATMOS_GAS_MONITOR_WASTE = "Waste Loop",
+ ATMOS_GAS_MONITOR_ENGINE = "Supermatter Engine Chamber",
+))
diff --git a/code/game/machinery/computer/atmos_computers/air_sensors.dm b/code/game/machinery/computer/atmos_computers/air_sensors.dm
new file mode 100644
index 0000000000000..ce3a5bad28d59
--- /dev/null
+++ b/code/game/machinery/computer/atmos_computers/air_sensors.dm
@@ -0,0 +1,67 @@
+/obj/machinery/air_sensor/plasma_tank
+ name = "plasma tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_PLAS
+
+/obj/machinery/air_sensor/oxygen_tank
+ name = "oxygen tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_O2
+
+/obj/machinery/air_sensor/nitrogen_tank
+ name = "nitrogen tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_N2
+
+/obj/machinery/air_sensor/mix_tank
+ name = "mix tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_MIX
+
+/obj/machinery/air_sensor/nitrous_tank
+ name = "nitrous oxide tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_N2O
+
+/obj/machinery/air_sensor/air_tank
+ name = "air mix tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_AIR
+
+/obj/machinery/air_sensor/carbon_tank
+ name = "carbon dioxide tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_CO2
+
+/obj/machinery/air_sensor/bz_tank
+ name = "bz tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_BZ
+
+/obj/machinery/air_sensor/hypernoblium_tank
+ name = "hypernoblium tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_HYPERNOBLIUM
+
+/obj/machinery/air_sensor/nitryl_tank
+ name = "nitryl tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_NITRYL
+
+/obj/machinery/air_sensor/pluoxium_tank
+ name = "pluoxium tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_PLUOXIUM
+
+/obj/machinery/air_sensor/tritium_tank
+ name = "tritium tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_TRITIUM
+
+/obj/machinery/air_sensor/water_vapor_tank
+ name = "water vapor tank gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_H2O
+
+/obj/machinery/air_sensor/incinerator_tank
+ name = "incinerator chamber gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_INCINERATOR
+
+/obj/machinery/air_sensor/ordnance_burn_chamber
+ name = "ordnance burn chamber gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_ORDNANCE_BURN
+
+/obj/machinery/air_sensor/ordnance_freezer_chamber
+ name = "ordnance freezer chamber gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_ORDNANCE_FREEZER
+
+/obj/machinery/air_sensor/engine_chamber
+ name = "supermatter engine chamber gas sensor"
+ chamber_id = ATMOS_GAS_MONITOR_ENGINE
diff --git a/code/game/machinery/computer/atmos_computers/atmos_controls.dm b/code/game/machinery/computer/atmos_computers/atmos_controls.dm
new file mode 100644
index 0000000000000..4327d7b85c7cc
--- /dev/null
+++ b/code/game/machinery/computer/atmos_computers/atmos_controls.dm
@@ -0,0 +1,87 @@
+/obj/machinery/computer/atmos_control/nocontrol/master
+ name = "station atmospherics monitoring"
+ circuit = /obj/item/circuitboard/computer/atmos_control/nocontrol/master
+ atmos_chambers = list(ATMOS_GAS_MONITOR_DISTRO = "Distribution Loop", ATMOS_GAS_MONITOR_WASTE = "Waste Loop")
+
+/obj/machinery/computer/atmos_control/oxygen_tank
+ name = "Oxygen Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/oxygen_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_O2 = "Oxygen Supply")
+
+/obj/machinery/computer/atmos_control/plasma_tank
+ name = "Plasma Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/plasma_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_PLAS = "Plasma Supply")
+
+/obj/machinery/computer/atmos_control/air_tank
+ name = "Mixed Air Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/air_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_AIR = "Mixed Air Supply")
+
+/obj/machinery/computer/atmos_control/nitrous_tank
+ name = "Nitrous Oxide Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/nitrous_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_N2O = "Nitrous Oxide Supply")
+
+/obj/machinery/computer/atmos_control/nitrogen_tank
+ name = "Nitrogen Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/nitrogen_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_N2 = "Nitrogen Supply")
+
+/obj/machinery/computer/atmos_control/carbon_tank
+ name = "Carbon Dioxide Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/carbon_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_CO2 = "Carbon Dioxide Supply")
+
+/obj/machinery/computer/atmos_control/bz_tank
+ name = "BZ Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/bz_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_BZ = "BZ Supply")
+
+/obj/machinery/computer/atmos_control/hydrogen_tank
+ name = "Hydrogen Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/hydrogen_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_H2 = "Hydrogen Supply")
+
+/obj/machinery/computer/atmos_control/hypernoblium_tank
+ name = "Hypernoblium Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/hypernoblium_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_HYPERNOBLIUM = "Hypernoblium Supply")
+
+/obj/machinery/computer/atmos_control/nitryl_tank
+ name = "Nitrium Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/nitryl_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_NITRIUM = "Nitryl Supply")
+
+/obj/machinery/computer/atmos_control/pluoxium_tank
+ name = "Pluoxium Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/pluoxium_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_PLUOXIUM = "Pluoxium Supply")
+
+/obj/machinery/computer/atmos_control/tritium_tank
+ name = "Tritium Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/tritium_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_TRITIUM = "Tritium Supply")
+
+/obj/machinery/computer/atmos_control/water_vapor
+ name = "Water Vapor Supply Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/water_vapor
+ atmos_chambers = list(ATMOS_GAS_MONITOR_H2O = "Water Vapor Supply")
+
+/obj/machinery/computer/atmos_control/mix_tank
+ name = "Mix Chamber Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/mix_tank
+ atmos_chambers = list(ATMOS_GAS_MONITOR_MIX = "Mix Chamber")
+
+/obj/machinery/computer/atmos_control/nocontrol/incinerator
+ name = "Incinerator Chamber Monitor"
+ circuit = /obj/item/circuitboard/computer/atmos_control/nocontrol/incinerator
+ atmos_chambers = list(ATMOS_GAS_MONITOR_INCINERATOR = "Incinerator Chamber")
+
+/obj/machinery/computer/atmos_control/ordnancemix
+ name = "Ordnance Chamber Control"
+ circuit = /obj/item/circuitboard/computer/atmos_control/ordnancemix
+ atmos_chambers = list(
+ ATMOS_GAS_MONITOR_ORDNANCE_BURN = "Ordnance Burn Chamber",
+ ATMOS_GAS_MONITOR_ORDNANCE_FREEZER = "Ordnance Freezer Chamber",
+ )
diff --git a/code/game/machinery/computer/atmos_computers/inlets.dm b/code/game/machinery/computer/atmos_computers/inlets.dm
new file mode 100644
index 0000000000000..9ddde3d5c4544
--- /dev/null
+++ b/code/game/machinery/computer/atmos_computers/inlets.dm
@@ -0,0 +1,83 @@
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored
+ on = TRUE
+ volume_rate = MAX_TRANSFER_RATE
+ /// The air sensor type this injector is linked to
+ var/chamber_id
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/Initialize(mapload)
+ id_tag = chamber_id + "_in"
+ return ..()
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/layer2
+ piping_layer = 2
+ icon_state = "inje_map-2"
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/layer4
+ piping_layer = 4
+ icon_state = "inje_map-4"
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/plasma_input
+ name = "plasma tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_PLAS
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/oxygen_input
+ name = "oxygen tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_O2
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/nitrogen_input
+ name = "nitrogen tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_N2
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/mix_input
+ name = "mix tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_MIX
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/nitrous_input
+ name = "nitrous oxide tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_N2O
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/air_input
+ name = "air mix tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_AIR
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/carbon_input
+ name = "carbon dioxide tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_CO2
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/bz_input
+ name = "bz tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_BZ
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/hypernoblium_input
+ name = "hypernoblium tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_HYPERNOBLIUM
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/nitryl_input
+ name = "nitryl tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_NITRIUM
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/pluoxium_input
+ name = "pluoxium tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_PLUOXIUM
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/tritium_input
+ name = "tritium tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_TRITIUM
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/water_vapor_input
+ name = "water vapor tank input injector"
+ chamber_id = ATMOS_GAS_MONITOR_H2O
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/incinerator_input
+ name = "incinerator chamber input injector"
+ chamber_id = ATMOS_GAS_MONITOR_INCINERATOR
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/ordnance_burn_chamber_input
+ on = FALSE
+ name = "ordnance burn chamber input injector"
+ chamber_id = ATMOS_GAS_MONITOR_ORDNANCE_BURN
+
+/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/ordnance_freezer_chamber_input
+ on = FALSE
+ name = "ordnance freezer chamber input injector"
+ chamber_id = ATMOS_GAS_MONITOR_ORDNANCE_FREEZER
diff --git a/code/game/machinery/computer/atmos_computers/meters.dm b/code/game/machinery/computer/atmos_computers/meters.dm
new file mode 100644
index 0000000000000..9cfe3072a69cc
--- /dev/null
+++ b/code/game/machinery/computer/atmos_computers/meters.dm
@@ -0,0 +1,23 @@
+/obj/machinery/meter/monitored
+ /// The unique string that represents which atmos chamber to associate with.
+ var/chamber_id
+
+/obj/machinery/meter/monitored/Initialize(mapload, new_piping_layer)
+ id_tag = assign_random_name()
+ if(mapload)
+ GLOB.map_loaded_sensors[chamber_id] = id_tag
+ . = ..()
+
+/obj/machinery/meter/monitored/layer2
+ target_layer = 2
+
+/obj/machinery/meter/monitored/layer4
+ target_layer = 4
+
+/obj/machinery/meter/monitored/waste_loop
+ name = "waste loop gas flow meter"
+ chamber_id = ATMOS_GAS_MONITOR_WASTE
+
+/obj/machinery/meter/monitored/distro_loop
+ name = "distribution loop gas flow meter"
+ chamber_id = ATMOS_GAS_MONITOR_DISTRO
diff --git a/code/game/machinery/computer/atmos_computers/outlets.dm b/code/game/machinery/computer/atmos_computers/outlets.dm
new file mode 100644
index 0000000000000..057dc44af703d
--- /dev/null
+++ b/code/game/machinery/computer/atmos_computers/outlets.dm
@@ -0,0 +1,85 @@
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored
+ on = TRUE
+ icon_state = "vent_map_siphon_on-3"
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/Initialize(mapload)
+ id_tag = CHAMBER_OUTPUT_FROM_ID(chamber_id)
+ . = ..()
+ //we dont want people messing with these special vents using the air alarm interface
+ disconnect_from_area()
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/plasma_output
+ name = "plasma tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_PLAS
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/oxygen_output
+ name = "oxygen tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_O2
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/nitrogen_output
+ name = "nitrogen tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_N2
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/mix_output
+ name = "mix tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_MIX
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/nitrous_output
+ name = "nitrous oxide tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_N2O
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/carbon_output
+ name = "carbon dioxide tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_CO2
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/bz_output
+ name = "bz tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_BZ
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/hypernoblium_output
+ name = "hypernoblium tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_HYPERNOBLIUM
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/nitryl_output
+ name = "nitryl tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_NITRYL
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/pluoxium_output
+ name = "pluoxium tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_PLUOXIUM
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/tritium_output
+ name = "tritium tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_TRITIUM
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/water_vapor_output
+ name = "water vapor tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_H2O
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/incinerator_output
+ name = "incinerator chamber output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_INCINERATOR
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/ordnance_burn_chamber_output
+ name = "ordnance burn chamber output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_ORDNANCE_BURN
+
+/obj/machinery/atmospherics/components/unary/vent_pump/siphon/monitored/ordnance_freezer_chamber_output
+ name = "ordnance freezer chamber output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_ORDNANCE_FREEZER
+
+/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/siphon/monitored
+ on = TRUE
+ icon_state = "vent_map_siphon_on-3"
+ var/chamber_id
+
+// Same as the rest, but bigger volume.
+/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/siphon/monitored/Initialize(mapload)
+ id_tag = CHAMBER_OUTPUT_FROM_ID(chamber_id)
+ . = ..()
+ //we dont want people messing with these special vents using the air alarm interface
+ disconnect_from_area()
+
+/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/siphon/monitored/air_output
+ name = "air mix tank output inlet"
+ chamber_id = ATMOS_GAS_MONITOR_AIR
diff --git a/code/game/machinery/computer/atmos_control.dm b/code/game/machinery/computer/atmos_control.dm
deleted file mode 100644
index 5b4734f272836..0000000000000
--- a/code/game/machinery/computer/atmos_control.dm
+++ /dev/null
@@ -1,382 +0,0 @@
-/////////////////////////////////////////////////////////////
-// AIR SENSOR (found in gas tanks)
-/////////////////////////////////////////////////////////////
-
-/obj/machinery/air_sensor
- name = "gas sensor"
- icon = 'icons/obj/stationobjs.dmi'
- icon_state = "gsensor1"
- resistance_flags = FIRE_PROOF
- interacts_with_air = TRUE
-
- var/on = TRUE
- var/frequency = FREQ_ATMOS_STORAGE
- var/datum/radio_frequency/radio_connection
-
-/obj/machinery/air_sensor/atmos/plasma_tank
- name = "plasma tank gas sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_PLASMA
-/obj/machinery/air_sensor/atmos/toxins_mixing_tank
- name = "toxins mixing gas sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_TOXINS_LAB
-/obj/machinery/air_sensor/atmos/oxygen_tank
- name = "oxygen tank gas sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_O2
-/obj/machinery/air_sensor/atmos/nitrogen_tank
- name = "nitrogen tank gas sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_N2
-/obj/machinery/air_sensor/atmos/mix_tank
- name = "mix tank gas sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_MIX
-/obj/machinery/air_sensor/atmos/nitrous_tank
- name = "nitrous oxide tank gas sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_N2O
-/obj/machinery/air_sensor/atmos/air_tank
- name = "air mix tank gas sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_AIR
-/obj/machinery/air_sensor/atmos/carbon_tank
- name = "carbon dioxide tank gas sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_CO2
-/obj/machinery/air_sensor/atmos/incinerator_tank
- name = "incinerator chamber gas sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_INCINERATOR
-/obj/machinery/air_sensor/atmos/toxins_waste
- name = "toxins waste sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_TOXINS_WASTE
-/obj/machinery/air_sensor/atmos/sm_core
- name = "supermatter gas sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_SM
-/obj/machinery/air_sensor/atmos/sm_waste
- name = "supermatter waste sensor"
- id_tag = ATMOS_GAS_MONITOR_SENSOR_SM_WASTE
-
-/obj/machinery/air_sensor/update_icon()
- icon_state = "gsensor[on]"
-
-/obj/machinery/air_sensor/process_atmos()
- if(on)
- var/datum/gas_mixture/air_sample = return_air()
-
- var/datum/signal/signal = new(list(
- "sigtype" = "status",
- "id_tag" = id_tag,
- "timestamp" = world.time,
- "pressure" = air_sample.return_pressure(),
- "temperature" = air_sample.return_temperature(),
- "gases" = list()
- ))
- var/total_moles = air_sample.total_moles()
- if(total_moles)
- for(var/gas_id in air_sample.get_gases())
- var/gas_name = GLOB.gas_data.names[gas_id]
- signal.data["gases"][gas_name] = air_sample.get_moles(gas_id) / total_moles * 100
-
- radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
-
-
-/obj/machinery/air_sensor/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
-
-/obj/machinery/air_sensor/Initialize(mapload)
- . = ..()
- SSair.start_processing_machine(src)
- set_frequency(frequency)
-
-/obj/machinery/air_sensor/Destroy()
- SSair.stop_processing_machine(src)
- SSradio.remove_object(src, frequency)
- return ..()
-
-/////////////////////////////////////////////////////////////
-// GENERAL AIR CONTROL (a.k.a atmos computer)
-/////////////////////////////////////////////////////////////
-GLOBAL_LIST_EMPTY(atmos_air_controllers)
-
-/obj/machinery/computer/atmos_control
- name = "atmospherics monitoring"
- desc = "Used to monitor the station's atmospherics sensors."
- icon_screen = "tank"
- icon_keyboard = "atmos_key"
- circuit = /obj/item/circuitboard/computer/atmos_control
-
-
-
- var/frequency = FREQ_ATMOS_STORAGE
- var/list/sensors = list(
- ATMOS_GAS_MONITOR_SENSOR_N2 = "Nitrogen Tank",
- ATMOS_GAS_MONITOR_SENSOR_O2 = "Oxygen Tank",
- ATMOS_GAS_MONITOR_SENSOR_CO2 = "Carbon Dioxide Tank",
- ATMOS_GAS_MONITOR_SENSOR_PLASMA = "Plasma Tank",
- ATMOS_GAS_MONITOR_SENSOR_N2O = "Nitrous Oxide Tank",
- ATMOS_GAS_MONITOR_SENSOR_AIR = "Mixed Air Tank",
- ATMOS_GAS_MONITOR_SENSOR_MIX = "Mix Tank",
- ATMOS_GAS_MONITOR_LOOP_DISTRIBUTION = "Distribution Loop",
- ATMOS_GAS_MONITOR_LOOP_ATMOS_WASTE = "Atmos Waste Loop",
- ATMOS_GAS_MONITOR_SENSOR_INCINERATOR = "Incinerator Chamber",
- ATMOS_GAS_MONITOR_SENSOR_TOXINS_LAB = "Toxins Mixing Chamber",
- ATMOS_GAS_MONITOR_SENSOR_TOXINS_WASTE = "Toxins Waste Tank",
- ATMOS_GAS_MONITOR_SENSOR_SM = "Supermatter Core",
- ATMOS_GAS_MONITOR_SENSOR_SM_WASTE = "Supermatter Waste Tank",
- )
- var/list/sensor_information = list()
- var/datum/radio_frequency/radio_connection
-
- light_color = LIGHT_COLOR_CYAN
-
-/obj/machinery/computer/atmos_control/Initialize(mapload)
- . = ..()
- GLOB.atmos_air_controllers += src
- set_frequency(frequency)
-
-/obj/machinery/computer/atmos_control/Destroy()
- GLOB.atmos_air_controllers -= src
- SSradio.remove_object(src, frequency)
- return ..()
-
-
-/obj/machinery/computer/atmos_control/ui_state(mob/user)
- return GLOB.default_state
-
-/obj/machinery/computer/atmos_control/ui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "AtmosControlConsole")
- ui.open()
- ui.set_autoupdate(TRUE) // Gas sensors
-
-/obj/machinery/computer/atmos_control/ui_data(mob/user)
- var/data = list()
-
- data["sensors"] = list()
- for(var/id_tag in sensors)
- var/long_name = sensors[id_tag]
- var/list/info = sensor_information[id_tag]
- if(!info)
- continue
- data["sensors"] += list(list(
- "id_tag" = id_tag,
- "long_name" = sanitize(long_name),
- "pressure" = info["pressure"],
- "temperature" = info["temperature"],
- "gases" = info["gases"]
- ))
- return data
-
-/obj/machinery/computer/atmos_control/receive_signal(datum/signal/signal)
- if(!signal)
- return
-
- var/id_tag = signal.data["id_tag"]
- if(!id_tag || !sensors.Find(id_tag))
- return
-
- sensor_information[id_tag] = signal.data
-
-/obj/machinery/computer/atmos_control/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
-
-/////////////////////////////////////////////////////////////
-// LARGE TANK CONTROL
-/////////////////////////////////////////////////////////////
-
-/obj/machinery/computer/atmos_control/tank
- var/input_tag
- var/output_tag
- frequency = FREQ_ATMOS_STORAGE
- circuit = /obj/item/circuitboard/computer/atmos_control/tank
-
- var/list/input_info
- var/list/output_info
-
-
-
-
-/obj/machinery/computer/atmos_control/tank/oxygen_tank
- name = "Oxygen Supply Control"
- input_tag = ATMOS_GAS_MONITOR_INPUT_O2
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_O2
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_O2 = "Oxygen Tank")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/oxygen_tank
-
-/obj/machinery/computer/atmos_control/tank/plasma_tank
- name = "Plasma Supply Control"
- input_tag = ATMOS_GAS_MONITOR_INPUT_PLASMA
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_PLASMA
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_PLASMA = "Plasma Tank")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/plasma_tank
-
-/obj/machinery/computer/atmos_control/tank/air_tank
- name = "Mixed Air Supply Control"
- input_tag = ATMOS_GAS_MONITOR_INPUT_AIR
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_AIR
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_AIR = "Air Mix Tank")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/air_tank
-
-/obj/machinery/computer/atmos_control/tank/mix_tank
- name = "Gas Mix Tank Control"
- input_tag = ATMOS_GAS_MONITOR_INPUT_MIX
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_MIX
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_MIX = "Gas Mix Tank")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/mix_tank
-
-/obj/machinery/computer/atmos_control/tank/nitrous_tank
- name = "Nitrous Oxide Supply Control"
- input_tag = ATMOS_GAS_MONITOR_INPUT_N2O
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_N2O
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_N2O = "Nitrous Oxide Tank")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/nitrous_tank
-
-/obj/machinery/computer/atmos_control/tank/nitrogen_tank
- name = "Nitrogen Supply Control"
- input_tag = ATMOS_GAS_MONITOR_INPUT_N2
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_N2
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_N2 = "Nitrogen Tank")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/nitrogen_tank
-
-/obj/machinery/computer/atmos_control/tank/carbon_tank
- name = "Carbon Dioxide Supply Control"
- input_tag = ATMOS_GAS_MONITOR_INPUT_CO2
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_CO2
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_CO2 = "Carbon Dioxide Tank")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/carbon_tank
-
-/obj/machinery/computer/atmos_control/tank/incinerator
- name = "Incinerator Air Control"
- input_tag = ATMOS_GAS_MONITOR_INPUT_INCINERATOR
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_INCINERATOR
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_INCINERATOR = "Incinerator Chamber")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/incinerator
-
-/obj/machinery/computer/atmos_control/tank/sm
- name = "Supermatter Air Monitor"
- input_tag = ATMOS_GAS_MONITOR_INPUT_SM
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_SM
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_SM = "Supermatter Core")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/incinerator
-
-/obj/machinery/computer/atmos_control/tank/sm_waste
- name = "Supermatter Air Monitor"
- input_tag = ATMOS_GAS_MONITOR_INPUT_SM_WASTE
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_SM_WASTE
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_SM_WASTE = "Supermatter Waste")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/sm_waste
-
-/obj/machinery/computer/atmos_control/tank/toxins_mixing_tank
- name = "Toxin Chamber Air Monitor"
- input_tag = ATMOS_GAS_MONITOR_INPUT_TOXINS_LAB
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_TOXINS_LAB
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_TOXINS_LAB = "Toxins Mixing Chamber")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/incinerator
-
-/obj/machinery/computer/atmos_control/tank/toxins_waste_tank
- name = "Toxin Waste Air Monitor"
- input_tag = ATMOS_GAS_MONITOR_INPUT_TOXINS_WASTE
- output_tag = ATMOS_GAS_MONITOR_OUTPUT_TOXINS_WASTE
- sensors = list(ATMOS_GAS_MONITOR_SENSOR_TOXINS_WASTE = "Toxins Waste Chamber")
- circuit = /obj/item/circuitboard/computer/atmos_control/tank/toxins_waste
-
-// This hacky madness is the evidence of the fact that a lot of machines were never meant to be constructable, im so sorry you had to see this
-/obj/machinery/computer/atmos_control/tank/proc/reconnect(mob/user)
- var/list/IO = list()
- var/datum/radio_frequency/freq = SSradio.return_frequency(frequency)
-
- var/list/devices = list()
- var/list/device_refs = freq.devices["_default"]
- for(var/datum/weakref/device_ref as anything in device_refs)
- var/atom/device = device_ref.resolve()
- if(!device)
- device_refs -= device_ref
- continue
- devices += device
-
- for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in devices)
- var/list/text = splittext(U.id_tag, "_")
- IO |= text[1]
- for(var/obj/machinery/atmospherics/components/unary/outlet_injector/U in devices)
- var/list/text = splittext(U.id, "_")
- IO |= text[1]
- if(!IO.len)
- to_chat(user, "No machinery detected.")
- var/S = input("Select the device set: ", "Selection", IO[1]) as anything in sort_list(IO)
- if(src)
- src.input_tag = "[S]_in"
- src.output_tag = "[S]_out"
- name = "[uppertext(S)] Supply Control"
- var/list/new_devices = freq.devices["atmosia"]
- sensors.Cut()
- for(var/obj/machinery/air_sensor/U in new_devices)
- var/list/text = splittext(U.id_tag, "_")
- if(text[1] == S)
- sensors = list("[S]_sensor" = "[S] Tank")
- break
-
- for(var/obj/machinery/atmospherics/components/unary/outlet_injector/U in devices)
- U.broadcast_status()
- for(var/obj/machinery/atmospherics/components/unary/vent_pump/U in devices)
- U.broadcast_status()
-
-/obj/machinery/computer/atmos_control/tank/ui_state(mob/user)
- return GLOB.default_state
-
-/obj/machinery/computer/atmos_control/tank/ui_interact(mob/user, datum/tgui/ui = null)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "AtmosControlConsole")
- ui.set_autoupdate(TRUE) // Gas sensors
- ui.open()
-
-/obj/machinery/computer/atmos_control/tank/ui_data(mob/user)
- var/list/data = ..()
- data["tank"] = TRUE
- data["inputting"] = input_info ? input_info["power"] : FALSE
- data["inputRate"] = input_info ? input_info["volume_rate"] : 0
- data["maxInputRate"] = input_info ? MAX_TRANSFER_RATE : 0
- data["outputting"] = output_info ? output_info["power"] : FALSE
- data["outputPressure"] = output_info ? output_info["internal"] : 0
- data["maxOutputPressure"] = output_info ? MAX_OUTPUT_PRESSURE : 0
- return data
-
-/obj/machinery/computer/atmos_control/tank/ui_act(action, params)
- if(..() || !radio_connection)
- return
- var/datum/signal/signal = new(list("sigtype" = "command", "user" = usr))
- switch(action)
- if("reconnect")
- reconnect(usr)
- . = TRUE
- if("input")
- signal.data += list("tag" = input_tag, "power_toggle" = TRUE)
- . = TRUE
- if("rate")
- var/target = text2num(params["rate"])
- if(!isnull(target))
- target = clamp(target, 0, MAX_TRANSFER_RATE)
- signal.data += list("tag" = input_tag, "set_volume_rate" = target)
- . = TRUE
- if("output")
- signal.data += list("tag" = output_tag, "power_toggle" = TRUE)
- . = TRUE
- if("pressure")
- var/target = text2num(params["pressure"])
- if(!isnull(target))
- target = clamp(target, 0, MAX_OUTPUT_PRESSURE)
- signal.data += list("tag" = output_tag, "set_internal_pressure" = target)
- . = TRUE
- radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
-
-/obj/machinery/computer/atmos_control/tank/receive_signal(datum/signal/signal)
- if(!signal)
- return
-
- var/id_tag = signal.data["tag"]
-
- if(input_tag == id_tag)
- input_info = signal.data
- else if(output_tag == id_tag)
- output_info = signal.data
- else
- ..(signal)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 3aeb15a6cc0da..671b9f6beeacc 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -84,6 +84,10 @@
var/airlock_material //material of inner filling; if its an airlock with glass, this should be set to "glass"
var/overlays_file = 'icons/obj/doors/airlocks/station/overlays.dmi'
var/note_overlay_file = 'icons/obj/doors/airlocks/station/overlays.dmi' //Used for papers and photos pinned to the airlock
+
+ /// Airlock pump that overrides airlock controlls when set up for cycling
+ var/obj/machinery/atmospherics/components/unary/airlock_pump/cycle_pump
+
/* Note mask_file needed some change due to the change from 513 to 514(the behavior of alpha filters seems to have changed) thats the reason why the mask
dmi file for normal airlocks is not 32x32 but 64x64 and for the large airlocks instead of 64x32 its now 96x64 due to the fix to this problem*/
var/mask_file = 'icons/obj/doors/mask_32x32_doors.dmi' // because filters aren't allowed to have icon_states :(
@@ -117,8 +121,6 @@
wire_security_level = max(wire_security_level, A.airlock_hack_difficulty)
wires = set_wires(wire_security_level)
- if(frequency)
- set_frequency(frequency)
if(glass)
airlock_material = "glass"
if(security_level > AIRLOCK_SECURITY_IRON)
@@ -375,9 +377,6 @@
for(var/obj/machinery/door/airlock/otherlock as anything in close_others)
otherlock.close_others -= src
close_others.Cut()
- if(id_tag)
- for(var/obj/machinery/doorButtons/D in GLOB.machines)
- D.removeMe(src)
qdel(note)
for(var/datum/atom_hud/data/diagnostic/diag_hud in GLOB.huds)
diag_hud.remove_from_hud(src)
@@ -1226,7 +1225,7 @@
sleep(open_speed - 1)
density = FALSE
z_flags &= ~(Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP)
- air_update_turf(1)
+ air_update_turf(TRUE, FALSE)
sleep(1)
layer = OPEN_DOOR_LAYER
update_icon(AIRLOCK_OPEN, 1)
@@ -1271,12 +1270,12 @@
if(air_tight)
set_density(TRUE)
z_flags |= (Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP)
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
sleep(1)
if(!air_tight)
set_density(TRUE)
z_flags |= (Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP)
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
sleep(open_speed - 1)
if(!safe)
crush()
@@ -1667,3 +1666,13 @@
/obj/machinery/door/airlock/proc/set_wires(wire_security_level)
return new /datum/wires/airlock(src, wire_security_level)
+/obj/machinery/door/airlock/proc/set_cycle_pump(obj/machinery/atmospherics/components/unary/airlock_pump/pump)
+ RegisterSignal(pump, COMSIG_PARENT_QDELETING, PROC_REF(unset_cycle_pump))
+ cycle_pump = pump
+
+/obj/machinery/door/airlock/proc/unset_cycle_pump()
+ SIGNAL_HANDLER
+ if(locked)
+ unbolt()
+ say("Link broken, unbolting.")
+ cycle_pump = null
diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm
index b19a591943781..caacaba7c20d2 100644
--- a/code/game/machinery/doors/airlock_types.dm
+++ b/code/game/machinery/doors/airlock_types.dm
@@ -69,7 +69,6 @@
/obj/machinery/door/airlock/glass/incinerator
autoclose = FALSE
- frequency = FREQ_AIRLOCK_CONTROL
heat_proof = TRUE
req_access = list(ACCESS_SYNDICATE)
@@ -108,7 +107,6 @@
/obj/machinery/door/airlock/research/glass/incinerator
autoclose = FALSE
- frequency = FREQ_AIRLOCK_CONTROL
heat_proof = TRUE
req_access = list(ACCESS_TOX)
@@ -219,16 +217,20 @@
icon = 'icons/obj/doors/airlocks/station/plasma.dmi'
assemblytype = /obj/structure/door_assembly/door_assembly_plasma
-/obj/machinery/door/airlock/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
- if(plasma_ignition(6))
- PlasmaBurn()
+/obj/machinery/door/airlock/plasma/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
/obj/machinery/door/airlock/plasma/bullet_act(obj/projectile/Proj)
if(!(Proj.nodamage) && Proj.damage_type == BURN)
if(plasma_ignition(6, Proj?.firer))
PlasmaBurn()
. = ..()
+/obj/machinery/door/airlock/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return (exposed_temperature > 300)
+
+/obj/machinery/door/airlock/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ PlasmaBurn()
/obj/machinery/door/airlock/plasma/proc/PlasmaBurn()
var/obj/structure/door_assembly/DA
@@ -240,7 +242,7 @@
DA.update_icon()
DA.update_name()
-/obj/machinery/door/airlock/plasma/BlockThermalConductivity() //we don't stop the heat~
+/obj/machinery/door/airlock/plasma/block_superconductivity() //we don't stop the heat~
return 0
/obj/machinery/door/airlock/plasma/attackby(obj/item/C, mob/user, params)
@@ -326,7 +328,6 @@
/obj/machinery/door/airlock/public/glass/incinerator
autoclose = FALSE
- frequency = FREQ_AIRLOCK_CONTROL
heat_proof = TRUE
req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_MAINT_TUNNELS)
diff --git a/code/game/machinery/doors/alarmlock.dm b/code/game/machinery/doors/alarmlock.dm
deleted file mode 100644
index 4e0fe2b2f3caa..0000000000000
--- a/code/game/machinery/doors/alarmlock.dm
+++ /dev/null
@@ -1,43 +0,0 @@
-/obj/machinery/door/airlock/alarmlock
- name = "glass alarm airlock"
- icon = 'icons/obj/doors/airlocks/station2/glass.dmi'
- overlays_file = 'icons/obj/doors/airlocks/station2/overlays.dmi'
- opacity = FALSE
- assemblytype = /obj/structure/door_assembly/door_assembly_public
- glass = TRUE
-
- var/datum/radio_frequency/air_connection
- var/air_frequency = FREQ_ATMOS_ALARMS
- autoclose = FALSE
-
-/obj/machinery/door/airlock/alarmlock/Initialize(mapload)
- . = ..()
- air_connection = new
-
-/obj/machinery/door/airlock/alarmlock/Destroy()
- SSradio.remove_object(src,air_frequency)
- air_connection = null
- return ..()
-
-/obj/machinery/door/airlock/alarmlock/Initialize(mapload)
- . = ..()
- SSradio.remove_object(src, air_frequency)
- air_connection = SSradio.add_object(src, air_frequency, RADIO_TO_AIRALARM)
- open()
-
-/obj/machinery/door/airlock/alarmlock/receive_signal(datum/signal/signal)
- ..()
- if(machine_stat & (NOPOWER|BROKEN))
- return
-
- var/alarm_area = signal.data["zone"]
- var/alert = signal.data["alert"]
-
- if(alarm_area == get_area_name(src))
- switch(alert)
- if("severe")
- autoclose = TRUE
- close()
- if("minor", "clear")
- autoclose = FALSE
- open()
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index c2c178a990861..d9bbaa4101831 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -13,7 +13,7 @@
z_flags = Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP
max_integrity = 350
armor = list(MELEE = 30, BULLET = 30, LASER = 20, ENERGY = 20, BOMB = 10, BIO = 100, RAD = 100, FIRE = 80, ACID = 70, STAMINA = 0, BLEED = 0)
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
flags_1 = PREVENT_CLICK_UNDER_1
ricochet_chance_mod = 0.8
damage_deflection = 10
@@ -46,7 +46,7 @@
. = ..()
set_init_door_layer()
update_freelook_sight()
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
GLOB.airlocks += src
spark_system = new /datum/effect_system/spark_spread
spark_system.set_up(2, 1, src)
@@ -82,6 +82,7 @@
if(spark_system)
qdel(spark_system)
spark_system = null
+ air_update_turf(TRUE, FALSE)
return ..()
/obj/machinery/door/Bumped(atom/movable/AM)
@@ -117,7 +118,8 @@
/obj/machinery/door/Move()
var/turf/T = loc
. = ..()
- move_update_air(T)
+ if(density) //Gotta be closed my friend
+ move_update_air(T)
/obj/machinery/door/CanAllowThrough(atom/movable/mover, border_dir)
. = ..()
@@ -199,7 +201,7 @@
var/max_moles = min_moles
// okay this is a bit hacky. First, we set density to 0 and recalculate our adjacent turfs
density = FALSE
- T.ImmediateCalculateAdjacentTurfs()
+ T.immediate_calculate_adjacent_turfs()
// then we use those adjacent turfs to figure out what the difference between the lowest and highest pressures we'd be holding is
for(var/turf/open/T2 in T.atmos_adjacent_turfs)
if((flags_1 & ON_BORDER_1) && get_dir(src, T2) != dir)
@@ -210,7 +212,7 @@
if(moles > max_moles)
max_moles = moles
density = TRUE
- T.ImmediateCalculateAdjacentTurfs() // alright lets put it back
+ T.immediate_calculate_adjacent_turfs() // alright lets put it back
return max_moles - min_moles > 20
/obj/machinery/door/attackby(obj/item/I, mob/user, params)
@@ -295,7 +297,7 @@
update_appearance()
set_opacity(0)
operating = FALSE
- air_update_turf(1)
+ air_update_turf(TRUE, FALSE)
update_freelook_sight()
if(autoclose)
spawn(autoclose)
@@ -329,7 +331,7 @@
if(visible && !glass)
set_opacity(1)
operating = FALSE
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
update_freelook_sight()
if(safe)
CheckForMobs()
@@ -387,7 +389,7 @@
if(!glass && GLOB.cameranet)
GLOB.cameranet.updateVisibility(src, 0)
-/obj/machinery/door/BlockThermalConductivity() // All non-glass airlocks block heat, this is intended.
+/obj/machinery/door/block_superconductivity() // All non-glass airlocks block heat, this is intended.
if(opacity || heat_proof)
return 1
return 0
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 0a2f1083bbc60..df094451568d6 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -341,7 +341,7 @@
if(reconsider_immediately)
var/turf/open/T = FD.loc
if(istype(T))
- T.ImmediateCalculateAdjacentTurfs()
+ T.immediate_calculate_adjacent_turfs()
/obj/machinery/door/firedoor/proc/emergency_pressure_stop(consider_timer = TRUE)
set waitfor = 0
@@ -377,7 +377,7 @@
/obj/machinery/door/firedoor/border_only
icon = 'icons/obj/doors/firelocks/edge_Doorfire.dmi'
flags_1 = ON_BORDER_1
- CanAtmosPass = ATMOS_PASS_PROC
+ can_atmos_pass = ATMOS_PASS_PROC
assemblytype = /obj/structure/firelock_frame/border
/obj/machinery/door/firedoor/border_only/Initialize(mapload)
@@ -468,7 +468,7 @@
leaving.Bump(src)
return COMPONENT_ATOM_BLOCK_EXIT
-/obj/machinery/door/firedoor/border_only/CanAtmosPass(turf/T)
+/obj/machinery/door/firedoor/border_only/can_atmos_pass(turf/T, vertical = FALSE)
if(get_dir(loc, T) == dir)
return !density
else
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 044eb5c6069bd..287bf5ce0c426 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -14,7 +14,7 @@
flags_1 = ON_BORDER_1
opacity = FALSE
pass_flags_self = PASSTRANSPARENT
- CanAtmosPass = ATMOS_PASS_PROC
+ can_atmos_pass = ATMOS_PASS_PROC
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN
network_id = NETWORK_DOOR_AIRLOCKS
z_flags = NONE // reset zblock
@@ -57,6 +57,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/door/window)
/obj/machinery/door/window/ComponentInitialize()
. = ..()
+ AddElement(/datum/element/atmos_sensitive)
AddComponent(/datum/component/ntnet_interface)
/obj/machinery/door/window/Destroy()
@@ -65,6 +66,8 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/door/window)
if(atom_integrity == 0)
playsound(src, "shatter", 70, 1)
electronics = null
+ var/turf/floor = get_turf(src)
+ floor.air_update_turf(TRUE, FALSE)
return ..()
/obj/machinery/door/window/update_icon()
@@ -132,7 +135,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/door/window)
return TRUE
-/obj/machinery/door/window/CanAtmosPass(turf/T)
+/obj/machinery/door/window/can_atmos_pass(turf/T, vertical = FALSE)
if(get_dir(loc, T) == dir)
return !density
else
@@ -178,7 +181,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/door/window)
icon_state ="[base_state]open"
sleep(operationdelay)
set_density(FALSE)
- air_update_turf(1)
+ air_update_turf(TRUE, FALSE)
update_freelook_sight()
if(operating == 1) //emag again
@@ -201,7 +204,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/door/window)
icon_state = base_state
set_density(TRUE)
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
update_freelook_sight()
sleep(operationdelay)
@@ -244,10 +247,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/door/window)
C.name = name
qdel(src)
-/obj/machinery/door/window/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > T0C + (reinf ? 1600 : 800))
- take_damage(round(exposed_volume / 200), BURN, 0, 0)
- ..()
+/obj/machinery/door/window/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return (exposed_temperature > T0C + (reinf ? 1600 : 800))
+
+/obj/machinery/door/window/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ take_damage(round(exposed_temperature / 200), BURN, 0, 0)
/obj/machinery/door/window/should_emag(mob/user)
// Don't allow emag if the door is currently open or moving
diff --git a/code/game/machinery/embedded_controller/airlock_controller.dm b/code/game/machinery/embedded_controller/airlock_controller.dm
index ae077f5a24374..00cc8ecca30cf 100644
--- a/code/game/machinery/embedded_controller/airlock_controller.dm
+++ b/code/game/machinery/embedded_controller/airlock_controller.dm
@@ -1,225 +1,279 @@
//States for airlock_control
-#define AIRLOCK_STATE_INOPEN -2
-#define AIRLOCK_STATE_PRESSURIZE -1
-#define AIRLOCK_STATE_CLOSED 0
-#define AIRLOCK_STATE_DEPRESSURIZE 1
-#define AIRLOCK_STATE_OUTOPEN 2
-
-/datum/computer/file/embedded_program/airlock_controller
- var/id_tag
- var/exterior_door_tag //Burn chamber facing door
- var/interior_door_tag //Station facing door
- var/airpump_tag //See: dp_vent_pump.dm
- var/sensor_tag //See: /obj/machinery/airlock_sensor
- var/sanitize_external //Before the interior airlock opens, do we first drain all gases inside the chamber and then repressurize?
-
- state = AIRLOCK_STATE_CLOSED
- var/target_state = AIRLOCK_STATE_CLOSED
- var/sensor_pressure = null
+#define AIRLOCK_STATE_INOPEN "inopen"
+#define AIRLOCK_STATE_PRESSURIZE "pressurize"
+#define AIRLOCK_STATE_CLOSED "closed"
+#define AIRLOCK_STATE_DEPRESSURIZE "depressurize"
+#define AIRLOCK_STATE_OUTOPEN "outopen"
-/datum/computer/file/embedded_program/airlock_controller/receive_signal(datum/signal/signal)
- var/receive_tag = signal.data["tag"]
- if(!receive_tag)
- return
+/obj/machinery/airlock_controller
+ icon = 'icons/obj/airlock_machines.dmi'
+ icon_state = "airlock_control_standby"
+ base_icon_state = "airlock_control"
- if(receive_tag==sensor_tag)
- if(signal.data["pressure"])
- sensor_pressure = text2num(signal.data["pressure"])
+ name = "airlock console"
+ density = FALSE
- else if(receive_tag==exterior_door_tag)
- memory["exterior_status"] = signal.data["door_status"]
+ power_channel = AREA_USAGE_ENVIRON
- else if(receive_tag==interior_door_tag)
- memory["interior_status"] = signal.data["door_status"]
+ // Setup parameters only
+ var/exterior_door_tag
+ var/interior_door_tag
+ var/airpump_tag
+ var/sensor_tag
+ var/sanitize_external
- else if(receive_tag==airpump_tag)
- if(signal.data["power"])
- memory["pump_status"] = signal.data["direction"]
- else
- memory["pump_status"] = "off"
+ var/datum/weakref/interior_door_ref
+ var/datum/weakref/exterior_door_ref
+ var/datum/weakref/pump_ref
+ var/datum/weakref/sensor_ref
- else if(receive_tag==id_tag)
- switch(signal.data["command"])
- if("cycle")
- if(state < AIRLOCK_STATE_CLOSED)
- target_state = AIRLOCK_STATE_OUTOPEN
- else
- target_state = AIRLOCK_STATE_INOPEN
+ var/last_pressure = null
-/datum/computer/file/embedded_program/airlock_controller/receive_user_command(command)
- switch(command)
- if("cycle_closed")
- target_state = AIRLOCK_STATE_CLOSED
- if("cycle_exterior")
- target_state = AIRLOCK_STATE_OUTOPEN
- if("cycle_interior")
- target_state = AIRLOCK_STATE_INOPEN
- if("abort")
- target_state = AIRLOCK_STATE_CLOSED
+ var/state = AIRLOCK_STATE_CLOSED
+ var/target_state = AIRLOCK_STATE_CLOSED
+ var/processing = FALSE
-/datum/computer/file/embedded_program/airlock_controller/process()
- var/process_again = 1
+/obj/machinery/airlock_controller/LateInitialize()
+ . = ..()
+ var/obj/machinery/door/interior_door = GLOB.objects_by_id_tag[interior_door_tag]
+ if (!isnull(interior_door_tag) && !istype(interior_door))
+ stack_trace("interior_door_tag is set to [interior_door_tag], which is not a door ([interior_door || "null"])")
+ interior_door_ref = WEAKREF(interior_door)
+ var/obj/machinery/door/exterior_door = GLOB.objects_by_id_tag[exterior_door_tag]
+ if (!isnull(exterior_door_tag) && !istype(exterior_door))
+ stack_trace("exterior_door_tag is set to [exterior_door_tag], which is not a door ([exterior_door || "null"])")
+ exterior_door_ref = WEAKREF(exterior_door)
+ var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = GLOB.objects_by_id_tag[airpump_tag]
+ if (!isnull(airpump_tag) && !istype(pump))
+ stack_trace("airpump_tag is set to [airpump_tag], which is not a pump ([pump || "null"])")
+ pump_ref = WEAKREF(pump)
+ var/obj/machinery/airlock_sensor/sensor = GLOB.objects_by_id_tag[sensor_tag]
+ if (!isnull(sensor_tag) && !istype(sensor))
+ stack_trace("sensor_tag is set to [sensor_tag], which is not a sensor ([sensor || "null"])")
+ sensor_ref = WEAKREF(sensor)
+
+/obj/machinery/airlock_controller/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "AirlockController", src)
+ ui.open()
+
+/obj/machinery/airlock_controller/process(delta_time)
+ var/process_again = TRUE
while(process_again)
- process_again = 0
+ process_again = FALSE
switch(state)
- if(AIRLOCK_STATE_INOPEN) // state -2
- if(target_state > state)
- if(memory["interior_status"] == "closed")
+ if(AIRLOCK_STATE_INOPEN)
+ if(target_state != state)
+ var/obj/machinery/door/airlock/interior_airlock = interior_door_ref.resolve()
+ if (isnull(interior_airlock))
+ continue
+
+ if(interior_airlock.density)
state = AIRLOCK_STATE_CLOSED
- process_again = 1
+ process_again = TRUE
else
- post_signal(new /datum/signal(list(
- "tag" = interior_door_tag,
- "command" = "secure_close"
- )))
+ interior_airlock.secure_close()
else
- if(memory["pump_status"] != "off")
- post_signal(new /datum/signal(list(
- "tag" = airpump_tag,
- "power" = 0,
- "sigtype" = "command"
- )))
+ var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref.resolve()
+ if(pump?.on)
+ pump.on = FALSE
+ pump.update_icon()
if(AIRLOCK_STATE_PRESSURIZE)
- if(target_state < state)
+ if(target_state == AIRLOCK_STATE_INOPEN)
+ var/sensor_pressure = sensor_pressure()
+ if (isnull(sensor_pressure))
+ continue
+
if(sensor_pressure >= ONE_ATMOSPHERE*0.95)
- if(memory["interior_status"] == "open")
- state = AIRLOCK_STATE_INOPEN
- process_again = 1
+ var/obj/machinery/door/airlock/interior_airlock = interior_door_ref.resolve()
+ if (isnull(interior_airlock))
+ continue
+
+ if(interior_airlock.density)
+ interior_airlock?.secure_open()
else
- post_signal(new /datum/signal(list(
- "tag" = interior_door_tag,
- "command" = "secure_open"
- )))
+ state = AIRLOCK_STATE_INOPEN
+ process_again = TRUE
else
- var/datum/signal/signal = new(list(
- "tag" = airpump_tag,
- "sigtype" = "command"
- ))
- if(memory["pump_status"] == "siphon")
- signal.data["stabilize"] = 1
- else if(memory["pump_status"] != "release")
- signal.data["power"] = 1
- post_signal(signal)
- else if(target_state > state)
- state = AIRLOCK_STATE_CLOSED
- process_again = 1
+ var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref.resolve()
+ if (isnull(pump))
+ continue
+
+ if(pump.pump_direction == ATMOS_DIRECTION_SIPHONING)
+ pump.pressure_checks |= ATMOS_EXTERNAL_BOUND
+ pump.pump_direction = ATMOS_DIRECTION_RELEASING
+ else if(pump.pump_direction == ATMOS_DIRECTION_RELEASING)
+ pump.on = TRUE
+ pump.update_icon()
+ else
+ state = AIRLOCK_STATE_CLOSED
+ process_again = TRUE
if(AIRLOCK_STATE_CLOSED)
- if(target_state > state)
- if(memory["interior_status"] == "closed")
+ if(target_state == AIRLOCK_STATE_OUTOPEN)
+ var/obj/machinery/door/airlock/interior_airlock = interior_door_ref.resolve()
+ if (isnull(interior_airlock))
+ continue
+
+ if(interior_airlock.density)
state = AIRLOCK_STATE_DEPRESSURIZE
- process_again = 1
+ process_again = TRUE
else
- post_signal(new /datum/signal(list(
- "tag" = interior_door_tag,
- "command" = "secure_close"
- )))
- else if(target_state < state)
- if(memory["exterior_status"] == "closed")
+ interior_airlock?.secure_close()
+ else if(target_state == AIRLOCK_STATE_INOPEN)
+ var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref.resolve()
+ if (isnull(exterior_airlock))
+ continue
+
+ if(exterior_airlock.density)
state = AIRLOCK_STATE_PRESSURIZE
- process_again = 1
+ process_again = TRUE
else
- post_signal(new /datum/signal(list(
- "tag" = exterior_door_tag,
- "command" = "secure_close"
- )))
-
+ exterior_airlock?.secure_close()
else
- if(memory["pump_status"] != "off")
- post_signal(new /datum/signal(list(
- "tag" = airpump_tag,
- "power" = 0,
- "sigtype" = "command"
- )))
+ var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref.resolve()
+ if (isnull(pump))
+ continue
+ if (!pump.on)
+ pump.on = TRUE
+ pump.update_appearance(UPDATE_ICON)
if(AIRLOCK_STATE_DEPRESSURIZE)
var/target_pressure = ONE_ATMOSPHERE*0.05
if(sanitize_external)
target_pressure = ONE_ATMOSPHERE*0.01
+ var/sensor_pressure = sensor_pressure()
+ if (isnull(sensor_pressure))
+ continue
+
if(sensor_pressure <= target_pressure)
- if(target_state > state)
- if(memory["exterior_status"] == "open")
- state = AIRLOCK_STATE_OUTOPEN
+ if(target_state == AIRLOCK_STATE_OUTOPEN)
+ var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref.resolve()
+ if (isnull(exterior_airlock))
+ continue
+
+ if(exterior_airlock.density)
+ exterior_airlock.secure_open()
else
- post_signal(new /datum/signal(list(
- "tag" = exterior_door_tag,
- "command" = "secure_open"
- )))
- else if(target_state < state)
+ state = AIRLOCK_STATE_OUTOPEN
+ else
state = AIRLOCK_STATE_CLOSED
- process_again = 1
- else if((target_state < state) && !sanitize_external)
+ process_again = TRUE
+ else if((target_state != AIRLOCK_STATE_OUTOPEN) && !sanitize_external)
state = AIRLOCK_STATE_CLOSED
- process_again = 1
+ process_again = TRUE
else
- var/datum/signal/signal = new(list(
- "tag" = airpump_tag,
- "sigtype" = "command"
- ))
- if(memory["pump_status"] == "release")
- signal.data["purge"] = 1
- else if(memory["pump_status"] != "siphon")
- signal.data["power"] = 1
- post_signal(signal)
+ var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref.resolve()
+ if (isnull(pump))
+ continue
+
+ if(pump.pump_direction == ATMOS_DIRECTION_RELEASING)
+ pump.pressure_checks &= ~ATMOS_EXTERNAL_BOUND
+ pump.pump_direction = ATMOS_DIRECTION_SIPHONING
+ pump.update_appearance(UPDATE_ICON)
if(AIRLOCK_STATE_OUTOPEN) //state 2
- if(target_state < state)
- if(memory["exterior_status"] == "closed")
+ if(target_state != AIRLOCK_STATE_OUTOPEN)
+ var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref.resolve()
+ if (isnull(exterior_airlock))
+ continue
+
+ if(exterior_airlock.density)
if(sanitize_external)
state = AIRLOCK_STATE_DEPRESSURIZE
- process_again = 1
+ process_again = TRUE
else
state = AIRLOCK_STATE_CLOSED
- process_again = 1
+ process_again = TRUE
else
- post_signal(new /datum/signal(list(
- "tag" = exterior_door_tag,
- "command" = "secure_close"
- )))
+ exterior_airlock.secure_close()
else
- if(memory["pump_status"] != "off")
- post_signal(new /datum/signal(list(
- "tag" = airpump_tag,
- "power" = 0,
- "sigtype" = "command"
- )))
+ var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref.resolve()
+ if (isnull(pump))
+ continue
+ if (pump.on)
+ pump.on = FALSE
+ pump.update_appearance(UPDATE_ICON)
+ processing = state != target_state
- memory["sensor_pressure"] = sensor_pressure
- memory["processing"] = state != target_state
- //sensor_pressure = null //not sure if we can comment this out. Uncomment in case of problems -rastaf0
+/obj/machinery/airlock_controller/ui_data(mob/user)
+ var/list/data = list()
- return 1
+ data["airlockState"] = state
+ var/sensor_pressure = sensor_pressure()
+ data["sensorPressure"] = isnull(sensor_pressure) ? "----" : round(sensor_pressure, 0.1)
-/obj/machinery/embedded_controller/radio/airlock_controller
- icon = 'icons/obj/airlock_machines.dmi'
- icon_state = "airlock_control_standby"
+ var/obj/machinery/door/airlock/interior_airlock = interior_door_ref.resolve()
+ if (isnull(interior_airlock))
+ data["interiorStatus"] = "----"
+ else
+ data["interiorStatus"] = interior_airlock.density ? "closed" : "open"
- name = "airlock console"
- density = FALSE
+ var/obj/machinery/door/airlock/exterior_airlock = exterior_door_ref.resolve()
+ if (isnull(exterior_airlock))
+ data["exteriorStatus"] = "----"
+ else
+ data["exteriorStatus"] = exterior_airlock.density ? "closed" : "open"
- frequency = FREQ_AIRLOCK_CONTROL
- power_channel = AREA_USAGE_ENVIRON
+ var/obj/machinery/atmospherics/components/binary/dp_vent_pump/pump = pump_ref.resolve()
+ switch (pump?.pump_direction)
+ if (null)
+ data["pumpStatus"] = "----"
+ if (ATMOS_DIRECTION_RELEASING)
+ data["pumpStatus"] = "release"
+ if (ATMOS_DIRECTION_SIPHONING)
+ data["pumpStatus"] = "siphon"
- // Setup parameters only
- var/exterior_door_tag
- var/interior_door_tag
- var/airpump_tag
- var/sensor_tag
- var/sanitize_external
+ return data
+
+/obj/machinery/airlock_controller/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_toxmix
+ switch(action)
+ if("cycleClosed")
+ target_state = AIRLOCK_STATE_CLOSED
+ if("cycleExterior")
+ target_state = AIRLOCK_STATE_OUTOPEN
+ if("cycleInterior")
+ target_state = AIRLOCK_STATE_INOPEN
+ if("abort")
+ target_state = AIRLOCK_STATE_CLOSED
+
+ return TRUE
+
+/// Starts an airlock cycle
+/obj/machinery/airlock_controller/proc/cycle()
+ if (state == AIRLOCK_STATE_INOPEN || state == AIRLOCK_STATE_PRESSURIZE)
+ target_state = AIRLOCK_STATE_OUTOPEN
+ else
+ target_state = AIRLOCK_STATE_INOPEN
+
+/// Returns the pressure over the pump, or null if it is deleted
+/obj/machinery/airlock_controller/proc/sensor_pressure()
+ var/obj/machinery/airlock_sensor/sensor = sensor_ref.resolve()
+ if (!isnull(sensor) && !sensor.on)
+ return last_pressure
+
+ var/datum/gas_mixture/air = sensor?.return_air()
+ last_pressure = air?.return_pressure()
+ return last_pressure
+
+/obj/machinery/airlock_controller/incinerator_ordmix
name = "Incinerator Access Console"
- airpump_tag = INCINERATOR_TOXMIX_DP_VENTPUMP
- exterior_door_tag = INCINERATOR_TOXMIX_AIRLOCK_EXTERIOR
- id_tag = INCINERATOR_TOXMIX_AIRLOCK_CONTROLLER
- interior_door_tag = INCINERATOR_TOXMIX_AIRLOCK_INTERIOR
+ airpump_tag = INCINERATOR_ORDMIX_DP_VENTPUMP
+ exterior_door_tag = INCINERATOR_ORDMIX_AIRLOCK_EXTERIOR
+ id_tag = INCINERATOR_ORDMIX_AIRLOCK_CONTROLLER
+ interior_door_tag = INCINERATOR_ORDMIX_AIRLOCK_INTERIOR
sanitize_external = TRUE
- sensor_tag = INCINERATOR_TOXMIX_AIRLOCK_SENSOR
+ sensor_tag = INCINERATOR_ORDMIX_AIRLOCK_SENSOR
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_atmos
+/obj/machinery/airlock_controller/incinerator_atmos
name = "Incinerator Access Console"
airpump_tag = INCINERATOR_ATMOS_DP_VENTPUMP
exterior_door_tag = INCINERATOR_ATMOS_AIRLOCK_EXTERIOR
@@ -228,7 +282,7 @@
sanitize_external = TRUE
sensor_tag = INCINERATOR_ATMOS_AIRLOCK_SENSOR
-/obj/machinery/embedded_controller/radio/airlock_controller/incinerator_syndicatelava
+/obj/machinery/airlock_controller/incinerator_syndicatelava
name = "Incinerator Access Console"
airpump_tag = INCINERATOR_SYNDICATELAVA_DP_VENTPUMP
exterior_door_tag = INCINERATOR_SYNDICATELAVA_AIRLOCK_EXTERIOR
@@ -237,84 +291,12 @@
sanitize_external = TRUE
sensor_tag = INCINERATOR_SYNDICATELAVA_AIRLOCK_SENSOR
-/obj/machinery/embedded_controller/radio/airlock_controller/Initialize(mapload)
- . = ..()
- if(!mapload)
- return
+/obj/machinery/airlock_controller/update_icon_state()
+ icon_state = "[base_icon_state]_[processing ? "process" : "standby"]"
+ return ..()
- var/datum/computer/file/embedded_program/airlock_controller/new_prog = new
-
- new_prog.id_tag = id_tag
- new_prog.exterior_door_tag = exterior_door_tag
- new_prog.interior_door_tag = interior_door_tag
- new_prog.airpump_tag = airpump_tag
- new_prog.sensor_tag = sensor_tag
- new_prog.sanitize_external = sanitize_external
-
- new_prog.master = src
- program = new_prog
-
-/obj/machinery/embedded_controller/radio/airlock_controller/update_icon()
- if(on && program)
- if(program.memory["processing"])
- icon_state = "airlock_control_process"
- else
- icon_state = "airlock_control_standby"
- else
- icon_state = "airlock_control_off"
-
-
-/obj/machinery/embedded_controller/radio/airlock_controller/return_text()
- var/state_options = null
-
- var/state = 0
- var/sensor_pressure = "----"
- var/exterior_status = "----"
- var/interior_status = "----"
- var/pump_status = "----"
- var/current_status = "Inactive
"
- if(program)
- state = program.state
- sensor_pressure = program.memory["sensor_pressure"] ? program.memory["sensor_pressure"] : "----"
- exterior_status = program.memory["exterior_status"] ? program.memory["exterior_status"] : "----"
- interior_status = program.memory["interior_status"] ? program.memory["interior_status"] : "----"
- pump_status = program.memory["pump_status"] ? program.memory["pump_status"] : "----"
-
- switch(state)
- if(AIRLOCK_STATE_INOPEN)
- state_options = {"Close Interior Airlock
-Cycle to Exterior Airlock
"}
- current_status = "Interior Airlock Open
Chamber Pressurized"
- if(AIRLOCK_STATE_PRESSURIZE)
- state_options = "Abort Cycling
"
- current_status = "Cycling to Interior Airlock
Chamber Pressurizing"
- if(AIRLOCK_STATE_CLOSED)
- state_options = {"Open Interior Airlock
-Open Exterior Airlock
"}
- if(AIRLOCK_STATE_DEPRESSURIZE)
- state_options = "Abort Cycling
"
- current_status = "Cycling to Exterior Airlock
Chamber Depressurizing"
- if(AIRLOCK_STATE_OUTOPEN)
- state_options = {"Cycle to Interior Airlock
-Close Exterior Airlock
"}
- current_status = "Exterior Airlock Open
Chamber Depressurized"
-
- var/output = {"
Airlock Status
-
-
Current Status:
[current_status]
-
-
\> Chamber Pressure:
[sensor_pressure] kPa
-
\> Control Pump:
[pump_status]
-
\> Interior Door:
[interior_status]
-
\> Exterior Door:
[exterior_status]
-
-
-[state_options]"}
-
- return output
-
-#undef AIRLOCK_STATE_INOPEN
-#undef AIRLOCK_STATE_PRESSURIZE
#undef AIRLOCK_STATE_CLOSED
#undef AIRLOCK_STATE_DEPRESSURIZE
+#undef AIRLOCK_STATE_INOPEN
#undef AIRLOCK_STATE_OUTOPEN
+#undef AIRLOCK_STATE_PRESSURIZE
diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm
deleted file mode 100644
index 22ddbc50a53a4..0000000000000
--- a/code/game/machinery/embedded_controller/embedded_controller_base.dm
+++ /dev/null
@@ -1,95 +0,0 @@
-/datum/computer/file/embedded_program
- var/list/memory = list()
- var/state
- var/obj/machinery/embedded_controller/master
-
-/datum/computer/file/embedded_program/Destroy()
- master = null
- . = ..()
-
-/datum/computer/file/embedded_program/proc/post_signal(datum/signal/signal, comm_line)
- if(master)
- master.post_signal(signal, comm_line)
- else
- qdel(signal)
-
-/datum/computer/file/embedded_program/proc/receive_user_command(command)
-
-/datum/computer/file/embedded_program/proc/receive_signal(datum/signal/signal)
- return null
-
-/datum/computer/file/embedded_program/process()
- return 0
-
-/obj/machinery/embedded_controller
- var/datum/computer/file/embedded_program/program
-
- name = "embedded controller"
- density = FALSE
-
- var/on = TRUE
-
-/obj/machinery/embedded_controller/Destroy()
- if(program)
- QDEL_NULL(program)
- . = ..()
-
-/obj/machinery/embedded_controller/ui_interact(mob/user)
- . = ..()
- user.set_machine(src)
- var/datum/browser/popup = new(user, "computer", name) // Set up the popup browser window
- popup.set_content(return_text())
- popup.open()
-
-/obj/machinery/embedded_controller/update_icon()
-
-/obj/machinery/embedded_controller/proc/return_text()
-
-/obj/machinery/embedded_controller/proc/post_signal(datum/signal/signal, comm_line)
- return 0
-
-/obj/machinery/embedded_controller/receive_signal(datum/signal/signal)
- if(istype(signal) && program)
- program.receive_signal(signal)
-
-/obj/machinery/embedded_controller/Topic(href, href_list)
- if(..())
- return 0
-
- if(program)
- program.receive_user_command(href_list["command"])
- addtimer(CALLBACK(program, TYPE_PROC_REF(/datum/computer/file/embedded_program, process)), 5)
-
- usr.set_machine(src)
- addtimer(CALLBACK(src, PROC_REF(updateDialog)), 5)
-
-/obj/machinery/embedded_controller/process(delta_time)
- if(program)
- program.process(delta_time)
-
- update_icon()
- src.updateDialog()
-
-/obj/machinery/embedded_controller/radio
- var/frequency
- var/datum/radio_frequency/radio_connection
-
-/obj/machinery/embedded_controller/radio/Destroy()
- SSradio.remove_object(src,frequency)
- return ..()
-
-/obj/machinery/embedded_controller/radio/Initialize(mapload)
- . = ..()
- set_frequency(frequency)
-
-/obj/machinery/embedded_controller/radio/post_signal(datum/signal/signal)
- signal.transmission_method = TRANSMISSION_RADIO
- if(radio_connection)
- return radio_connection.post_signal(src, signal)
- else
- signal = null
-
-/obj/machinery/embedded_controller/radio/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = SSradio.add_object(src, frequency)
diff --git a/code/game/machinery/embedded_controller/simple_vent_controller.dm b/code/game/machinery/embedded_controller/simple_vent_controller.dm
deleted file mode 100644
index 62fb1ad92663d..0000000000000
--- a/code/game/machinery/embedded_controller/simple_vent_controller.dm
+++ /dev/null
@@ -1,73 +0,0 @@
-/datum/computer/file/embedded_program/simple_vent_controller
-
- var/airpump_tag
-
-/datum/computer/file/embedded_program/simple_vent_controller/receive_user_command(command)
- switch(command)
- if("vent_inactive")
- post_signal(new /datum/signal(list(
- "tag" = airpump_tag,
- "sigtype" = "command",
- "power" = 0
- )))
-
- if("vent_pump")
- post_signal(new /datum/signal(list(
- "tag" = airpump_tag,
- "sigtype" = "command",
- "stabilize" = 1,
- "power" = 1
- )))
-
- if("vent_clear")
- post_signal(new /datum/signal(list(
- "tag" = airpump_tag,
- "sigtype" = "command",
- "purge" = 1,
- "power" = 1
- )))
-
-/datum/computer/file/embedded_program/simple_vent_controller/process()
- return 0
-
-
-/obj/machinery/embedded_controller/radio/simple_vent_controller
- icon = 'icons/obj/airlock_machines.dmi'
- icon_state = "airlock_control_standby"
-
- name = "vent controller"
- density = FALSE
- layer = ABOVE_WINDOW_LAYER
-
- frequency = FREQ_ATMOS_CONTROL
- power_channel = AREA_USAGE_ENVIRON
-
- // Setup parameters only
- var/airpump_tag
-
-/obj/machinery/embedded_controller/radio/simple_vent_controller/Initialize(mapload)
- . = ..()
- if(!mapload)
- return
- var/datum/computer/file/embedded_program/simple_vent_controller/new_prog = new
-
- new_prog.airpump_tag = airpump_tag
- new_prog.master = src
- program = new_prog
-
-/obj/machinery/embedded_controller/radio/simple_vent_controller/update_icon()
- if(on && program)
- icon_state = "airlock_control_standby"
- else
- icon_state = "airlock_control_off"
-
-
-/obj/machinery/embedded_controller/radio/simple_vent_controller/return_text()
- var/state_options = null
- state_options = {"Deactivate Vent
-Activate Vent / Pump
-Activate Vent / Clear
"}
- var/output = {"Vent Control Console
-[state_options]
"}
-
- return output
diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm
index 42e3e8d6c421a..bcba4e3da16c4 100644
--- a/code/game/machinery/firealarm.dm
+++ b/code/game/machinery/firealarm.dm
@@ -1,5 +1,3 @@
-#define FIREALARM_COOLDOWN 67 // Chosen fairly arbitrarily, it is the length of the audio in FireAlarm.ogg. The actual track length is 7 seconds 8ms but but the audio stops at 6s 700ms
-
/obj/item/electronics/firealarm
name = "fire alarm electronics"
custom_price = 5
@@ -34,49 +32,122 @@
light_range = 7
light_color = "#ff3232"
- var/detecting = 1
- var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
- var/last_alarm = 0
- var/area/myarea = null
- var/locked = FALSE //Are we locked?
+ //We want to use area sensitivity, let us
+ always_area_sensitive = TRUE
+ ///Buildstate for contruction steps
+ var/buildstage = FIRE_ALARM_BUILD_SECURED
+ ///Our home area, set in Init. Due to loading step order, this seems to be null very early in the server setup process, which is why some procs use `my_area?` for var or list checks.
+ var/area/my_area = null
+ ///looping sound datum for our fire alarm siren.
+ var/datum/looping_sound/firealarm/soundloop
+ //Is the fire alarm locked?
+ var/locked = FALSE
CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
/obj/machinery/firealarm/Initialize(mapload, dir, building)
. = ..()
- if (!req_access)
- req_access = list(ACCESS_ATMOSPHERICS)
+ id_tag = assign_random_name()
if(building)
- buildstage = 0
+ buildstage = FIRE_ALARM_BUILD_NO_CIRCUIT
panel_open = TRUE
- update_appearance()
- myarea = get_area(src)
- LAZYADD(myarea.firealarms, src)
+ if(name == initial(name))
+ update_name()
+ my_area = get_area(src)
+ LAZYADD(my_area.firealarms, src)
+ RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(check_security_level))
+
+ AddElement(/datum/element/atmos_sensitive, mapload)
RegisterSignal(SSsecurity_level, COMSIG_SECURITY_LEVEL_CHANGED, PROC_REF(check_security_level))
+ soundloop = new(src, FALSE)
+
+ AddComponent(/datum/component/usb_port, list(/obj/item/circuit_component/firealarm))
+ update_icon()
/obj/machinery/firealarm/Destroy()
- myarea.firereset(src)
- LAZYREMOVE(myarea.firealarms, src)
+ if(my_area)
+ LAZYREMOVE(my_area.firealarms, src)
+ my_area = null
+ QDEL_NULL(soundloop)
+ return ..()
+
+// Area sensitivity is traditionally tied directly to power use, as an optimization
+// But since we want it for fire reacting, we disregard that
+/obj/machinery/firealarm/setup_area_power_relationship()
+ . = ..()
+ if(!.)
+ return
+ var/area/our_area = get_area(src)
+ RegisterSignal(our_area, COMSIG_AREA_FIRE_CHANGED, PROC_REF(handle_fire))
+ handle_fire(our_area, our_area.fire)
+
+/obj/machinery/firealarm/on_enter_area(datum/source, area/area_to_register)
+ //were already registered to an area. exit from here first before entering into an new area
+ if(!isnull(my_area))
+ return
+ . = ..()
+
+ my_area = area_to_register
+ LAZYADD(my_area.firealarms, src)
+
+ RegisterSignal(area_to_register, COMSIG_AREA_FIRE_CHANGED, PROC_REF(handle_fire))
+ handle_fire(area_to_register, area_to_register.fire)
+ update_appearance()
+
+/obj/machinery/firealarm/update_name(updates)
+ . = ..()
+ name = "[get_area_name(my_area)] [initial(name)] [id_tag]"
+
+/obj/machinery/firealarm/on_exit_area(datum/source, area/area_to_unregister)
+ //we cannot unregister from an area we never registered to in the first place
+ if(my_area != area_to_unregister)
+ return
+ . = ..()
+
+ UnregisterSignal(area_to_unregister, COMSIG_AREA_FIRE_CHANGED)
+ LAZYREMOVE(my_area.firealarms, src)
+ my_area = null
+
+/obj/machinery/firealarm/proc/handle_fire(area/source, new_fire)
+ SIGNAL_HANDLER
+ set_status()
+
+/**
+ * Sets the sound state, and then calls update_icon()
+ *
+ * This proc exists to be called by areas and firelocks
+ * so that it may update its icon and start or stop playing
+ * the alarm sound based on the state of an area variable.
+ */
+/obj/machinery/firealarm/proc/set_status()
+ if(!(my_area.fire || LAZYLEN(my_area.active_firelocks)) || (obj_flags & EMAGGED))
+ soundloop.stop()
+ update_appearance()
+
+/obj/machinery/firealarm/update_appearance(updates)
+ . = ..()
+ if((my_area?.fire || LAZYLEN(my_area?.active_firelocks)) && !(obj_flags & EMAGGED) && !(machine_stat & (BROKEN|NOPOWER)))
+ set_light(l_range = 2.5, l_power = 1.5)
+ else
+ set_light(l_range = 1.6, l_power = 1)
+
+/obj/machinery/firealarm/update_icon_state()
+ if(panel_open)
+ icon_state = "fire_b[buildstage]"
+ return ..()
+ if(machine_stat & BROKEN)
+ icon_state = "firex"
+ return ..()
+ icon_state = "fire0"
return ..()
/obj/machinery/firealarm/update_overlays()
. = ..()
- var/area/A = src.loc
- A = A.loc
if(machine_stat & NOPOWER)
return
- . += "fire_overlay"
- if(is_station_level(z))
- . += "fire_[SSsecurity_level.get_current_level_as_number()]"
- . += mutable_appearance(icon, "fire_[SSsecurity_level.get_current_level_as_number()]")
- . += emissive_appearance(icon, "fire_[SSsecurity_level.get_current_level_as_number()]", layer, alpha = 255)
- ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY)
- else
- . += "fire_[SEC_LEVEL_GREEN]"
- . += mutable_appearance(icon, "fire_[SEC_LEVEL_GREEN]")
- . += emissive_appearance(icon, "fire_[SEC_LEVEL_GREEN]", layer, alpha = 255)
- ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY)
+ if(panel_open)
+ return
if(obj_flags & EMAGGED)
. += "fire_emagged"
@@ -84,12 +155,23 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
. += emissive_appearance(icon, "fire_emagged", layer, alpha = 255)
ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY)
return //If it's emagged, don't do anything else for overlays.
- if(locked)
- . += "fire_locked"
- . += mutable_appearance(icon, "fire_locked", layer + 1) //If we are locked, overlay that over the fire_off
- . += emissive_appearance(icon, "fire_locked", layer, alpha = 255)
- ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY)
- if(detecting && A.fire)
+ else if(!(my_area?.fire || LAZYLEN(my_area?.active_firelocks)))
+ if(my_area?.fire_detect) //If this is false, someone disabled it. Leave the light missing, a good hint to anyone paying attention.
+ if(is_station_level(z))
+ . += "fire_[SSsecurity_level.get_current_level_as_number()]"
+ . += mutable_appearance(icon, "fire_[SSsecurity_level.get_current_level_as_number()]")
+ . += emissive_appearance(icon, "fire_[SSsecurity_level.get_current_level_as_number()]", layer, alpha = 255)
+ ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY)
+ else
+ . += "fire_[SEC_LEVEL_GREEN]"
+ . += mutable_appearance(icon, "fire_[SEC_LEVEL_GREEN]")
+ . += emissive_appearance(icon, "fire_[SEC_LEVEL_GREEN]", layer, alpha = 255)
+ ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY)
+ else
+ . += mutable_appearance(icon, "fire_disabled")
+ . += emissive_appearance(icon, "fire_level_e", src, alpha = src.alpha)
+ ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY)
+ else if(my_area?.fire_detect && my_area?.fire)
. += "fire_on"
. += mutable_appearance(icon, "fire_on", layer + 2) //If we are locked and there is a fire, overlay the fire detection overlay ontop of the locked one.
. += emissive_appearance(icon, "fire_on", layer, alpha = 255)
@@ -100,6 +182,13 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
. += emissive_appearance(icon, "fire_off", layer, alpha = 255)
ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY)
+ if(locked)
+ . += "fire_locked"
+ . += mutable_appearance(icon, "fire_locked", layer + 1) //If we are locked, overlay that over the fire_off
+ . += emissive_appearance(icon, "fire_locked", layer, alpha = 255)
+ ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY)
+
+
/obj/machinery/firealarm/emp_act(severity)
. = ..()
@@ -114,7 +203,12 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
update_appearance()
user?.visible_message("Sparks fly out of [src]!",
"You emag [src], disabling its thermal sensors.")
+ if(user)
+ balloon_alert(user, "speaker disabled")
+ user.log_message("emagged [src].", LOG_ATTACK)
playsound(src, "sparks", 50, 1)
+ set_status()
+ return TRUE
/obj/machinery/firealarm/eminence_act(mob/living/simple_animal/eminence/eminence)
. = ..()
@@ -122,11 +216,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
if(do_after(eminence, 20, target=get_turf(eminence)))
attack_hand(eminence)
-/obj/machinery/firealarm/temperature_expose(datum/gas_mixture/air, temperature, volume)
- if((temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && (last_alarm+FIREALARM_COOLDOWN < world.time) && !(obj_flags & EMAGGED) && detecting && !machine_stat)
- alarm()
- try_lock(null, TRUE)
- ..()
+/obj/machinery/firealarm/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return (exposed_temperature > T0C + 200 || exposed_temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && !(obj_flags & EMAGGED) && detecting && !machine_stat
+
+/obj/machinery/firealarm/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ alarm()
/**
* Signal handler for checking if we should update fire alarm appearance accordingly to a newly set security level
@@ -141,25 +235,51 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
if(is_station_level(z))
update_appearance()
+/**
+ * Sounds the fire alarm and closes all firelocks in the area. Also tells the area to color the lights red.
+ *
+ * Arguments:
+ * * mob/user is the user that pulled the alarm.
+ */
/obj/machinery/firealarm/proc/alarm(mob/user)
- if(!is_operational || (last_alarm+FIREALARM_COOLDOWN > world.time))
+ if(!is_operational)
return
- last_alarm = world.time
- var/area/A = get_area(src)
- A.firealert(src)
- playsound(loc, 'goon/sound/machinery/FireAlarm.ogg', 75)
- update_appearance()
+
+ if(my_area.fire)
+ return //area alarm already active
+ my_area.alarm_manager.send_alarm(ALARM_FIRE, my_area)
+ // This'll setup our visual effects, so we only need to worry about the alarm
+ for(var/obj/machinery/door/firedoor/firelock in my_area.firedoors)
+ firelock.activate(FIRELOCK_ALARM_TYPE_GENERIC)
if(user)
- log_game("[user] triggered a fire alarm at [COORD(src)]")
+ balloon_alert(user, "triggered alarm!")
+ user.log_message("triggered a fire alarm.", LOG_GAME)
+ my_area.fault_status = AREA_FAULT_MANUAL
+ my_area.fault_location = name
+ soundloop.start() //Manually pulled fire alarms will make the sound, rather than the doors.
+ SEND_SIGNAL(src, COMSIG_FIREALARM_ON_TRIGGER)
+ update_use_power(ACTIVE_POWER_USE)
+/**
+ * Resets all firelocks in the area. Also tells the area to disable alarm lighting, if it was enabled.
+ *
+ * Arguments:
+ * * mob/user is the user that reset the alarm.
+ */
/obj/machinery/firealarm/proc/reset(mob/user)
if(!is_operational)
return
- var/area/A = get_area(src)
- A.firereset(src)
- update_appearance()
+ my_area.alarm_manager.clear_alarm(ALARM_FIRE, my_area)
+ // Clears all fire doors and their effects for now
+ // They'll reclose if there's a problem
+ for(var/obj/machinery/door/firedoor/firelock in my_area.firedoors)
+ firelock.crack_open()
if(user)
- log_game("[user] reset a fire alarm at [COORD(src)]")
+ balloon_alert(user, "reset alarm")
+ user.log_message("reset a fire alarm.", LOG_GAME)
+ soundloop.stop()
+ SEND_SIGNAL(src, COMSIG_FIREALARM_ON_RESET)
+ update_use_power(IDLE_POWER_USE)
/obj/machinery/firealarm/proc/try_lock(mob/user, force_lock = FALSE)
if(allowed(user) || !user || force_lock)
@@ -226,15 +346,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
switch(buildstage)
if(2)
if(W.tool_behaviour == TOOL_MULTITOOL)
- detecting = !detecting
- if (src.detecting)
- user.visible_message("[user] has reconnected [src]'s detecting unit!", "You reconnect [src]'s detecting unit.")
- else
- user.visible_message("[user] has disconnected [src]'s detecting unit!", "You disconnect [src]'s detecting unit.")
+ toggle_fire_detect(user)
return
else if(W.tool_behaviour == TOOL_WIRECUTTER)
- buildstage = 1
+ buildstage = AIR_ALARM_BUILD_NO_WIRES
W.play_tool_sound(src)
new /obj/item/stack/cable_coil(user.loc, 5)
to_chat(user, "You cut the wires from \the [src].")
@@ -255,7 +371,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
to_chat(user, "You need more cable for this!")
else
coil.use(5)
- buildstage = 2
+ buildstage = AIR_ALARM_BUILD_COMPLETE
to_chat(user, "You wire \the [src].")
update_appearance()
return
@@ -271,14 +387,14 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
else
to_chat(user, "You pry out the circuit.")
new /obj/item/electronics/firealarm(user.loc)
- buildstage = 0
+ buildstage = FIRE_ALARM_BUILD_NO_WIRES
update_appearance()
return
if(0)
if(istype(W, /obj/item/electronics/firealarm))
to_chat(user, "You insert the circuit.")
qdel(W)
- buildstage = 1
+ buildstage = FIRE_ALARM_BUILD_NO_WIRES
update_appearance()
return
@@ -288,7 +404,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
return
user.visible_message("[user] fabricates a circuit and places it into [src].", \
"You adapt a fire alarm circuit and slot it into the assembly.")
- buildstage = 1
+ buildstage = AIR_ALARM_BUILD_NO_WIRES
update_appearance()
return
@@ -303,10 +419,8 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/firealarm)
return ..()
-MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/firealarm, 26)
-
/obj/machinery/firealarm/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- if((buildstage == 0) && (the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS))
+ if((buildstage == FIRE_ALARM_BUILD_NO_CIRCUIT) && (the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS))
return list("mode" = RCD_UPGRADE_SIMPLE_CIRCUITS, "delay" = 20, "cost" = 1)
return FALSE
@@ -315,7 +429,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/firealarm, 26)
if(RCD_UPGRADE_SIMPLE_CIRCUITS)
user.visible_message("[user] fabricates a circuit and places it into [src].", \
"You adapt a fire alarm circuit and slot it into the assembly.")
- buildstage = 1
+ buildstage = FIRE_ALARM_BUILD_NO_WIRES
update_appearance()
return TRUE
return FALSE
@@ -323,7 +437,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/firealarm, 26)
/obj/machinery/firealarm/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir, armour_penetration = 0)
. = ..()
if(.) //damage received
- if(atom_integrity > 0 && !(machine_stat & BROKEN) && buildstage != 0)
+ if(atom_integrity > 0 && !(machine_stat & BROKEN) && buildstage != FIRE_ALARM_BUILD_NO_CIRCUIT)
if(prob(33))
alarm()
@@ -333,29 +447,51 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/firealarm, 26)
..()
/obj/machinery/firealarm/atom_break(damage_flag)
- if(buildstage == 0) //can't break the electronics if there isn't any inside.
+ if(buildstage == FIRE_ALARM_BUILD_NO_CIRCUIT) //can't break the electronics if there isn't any inside.
return
- . = ..()
- if(.)
- LAZYREMOVE(myarea.firealarms, src)
+ return ..()
+
/obj/machinery/firealarm/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
new /obj/item/stack/sheet/iron(loc, 1)
- if(!(machine_stat & BROKEN))
- var/obj/item/I = new /obj/item/electronics/firealarm(loc)
- if(!disassembled)
- I.update_integrity(I.max_integrity * 0.5)
- new /obj/item/stack/cable_coil(loc, 3)
+ if(buildstage > FIRE_ALARM_BUILD_NO_CIRCUIT)
+ var/obj/item/item = new /obj/item/electronics/firealarm(loc)
+ if(!disassembled)
+ item.update_integrity(item.max_integrity * 0.5)
+ if(buildstage > FIRE_ALARM_BUILD_NO_WIRES)
+ new /obj/item/stack/cable_coil(loc, 3)
qdel(src)
-/obj/machinery/firealarm/proc/update_fire_light(fire)
- if(fire == !!light_power)
- return // do nothing if we're already active
- if(fire)
- set_light(l_power = 0.8)
+
+// Allows users to examine the state of the thermal sensor
+/obj/machinery/firealarm/examine(mob/user)
+ . = ..()
+ if((my_area?.fire || LAZYLEN(my_area?.active_firelocks)))
+ . += "The local area hazard light is flashing."
+ . += "The fault location display is [my_area.fault_location] ([my_area.fault_status == AREA_FAULT_AUTOMATIC ? "Automatic Detection" : "Manual Trigger"])."
+ if(is_station_level(z))
+ . += "The station security alert level is [SSsecurity_level.get_current_level_as_text()]."
+ . += "Left-Click to activate all firelocks in this area."
+ . += "Right-Click to reset firelocks in this area."
else
- set_light(l_power = 0)
+ if(is_station_level(z))
+ . += "The station security alert level is [SSsecurity_level.get_current_level_as_text()]."
+ . += "The local area thermal detection light is [my_area.fire_detect ? "lit" : "unlit"]."
+ . += "Left-Click to activate all firelocks in this area."
+
+/obj/machinery/firealarm/proc/toggle_fire_detect(mob/user)
+ my_area.fire_detect = !my_area.fire_detect
+ for(var/obj/machinery/firealarm/fire_panel in my_area.firealarms)
+ fire_panel.update_icon()
+ // Used to force all the firelocks to update, if the zone is not manually activated
+ if (my_area.fault_status != AREA_FAULT_MANUAL)
+ reset() // Don't send user to prevent double balloon_alert() and the action is already logged in this proc.
+ if (user)
+ balloon_alert(user, "thermal sensors [my_area.fire_detect ? "enabled" : "disabled"]")
+ user.log_message("[ my_area.fire_detect ? "enabled" : "disabled" ] firelock sensors using [src].", LOG_GAME)
+
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/firealarm, 26)
/*
* Return of Party button
@@ -389,4 +525,63 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/firealarm, 26)
party_overlay = iconstate2appearance('icons/turf/areas.dmi', "party")
A.add_overlay(party_overlay)
+/////////////////////// CIRCUITS //////////////////////////////////////
+
+/obj/item/circuit_component/firealarm
+ display_name = "Fire Alarm"
+ desc = "Allows you to interface with the Fire Alarm."
+
+ var/datum/port/input/alarm_trigger
+ var/datum/port/input/reset_trigger
+
+ /// Returns a boolean value of 0 or 1 if the fire alarm is on or not.
+ var/datum/port/output/is_on
+ /// Returns when the alarm is turned on
+ var/datum/port/output/triggered
+ /// Returns when the alarm is turned off
+ var/datum/port/output/reset
+
+ var/obj/machinery/firealarm/attached_alarm
+
+/obj/item/circuit_component/firealarm/populate_ports()
+ alarm_trigger = add_input_port("Set", PORT_TYPE_SIGNAL)
+ reset_trigger = add_input_port("Reset", PORT_TYPE_SIGNAL)
+
+ is_on = add_output_port("Is On", PORT_TYPE_NUMBER)
+ triggered = add_output_port("Triggered", PORT_TYPE_SIGNAL)
+ reset = add_output_port("Reset", PORT_TYPE_SIGNAL)
+
+/obj/item/circuit_component/firealarm/register_usb_parent(atom/movable/parent)
+ . = ..()
+ if(istype(parent, /obj/machinery/firealarm))
+ attached_alarm = parent
+ RegisterSignal(parent, COMSIG_FIREALARM_ON_TRIGGER, PROC_REF(on_firealarm_triggered))
+ RegisterSignal(parent, COMSIG_FIREALARM_ON_RESET, PROC_REF(on_firealarm_reset))
+
+/obj/item/circuit_component/firealarm/unregister_usb_parent(atom/movable/parent)
+ attached_alarm = null
+ UnregisterSignal(parent, COMSIG_FIREALARM_ON_TRIGGER)
+ UnregisterSignal(parent, COMSIG_FIREALARM_ON_RESET)
+ return ..()
+
+/obj/item/circuit_component/firealarm/proc/on_firealarm_triggered(datum/source)
+ SIGNAL_HANDLER
+ is_on.set_output(1)
+ triggered.set_output(COMPONENT_SIGNAL)
+
+/obj/item/circuit_component/firealarm/proc/on_firealarm_reset(datum/source)
+ SIGNAL_HANDLER
+ is_on.set_output(0)
+ reset.set_output(COMPONENT_SIGNAL)
+
+
+/obj/item/circuit_component/firealarm/input_received(datum/port/input/port)
+ if(COMPONENT_TRIGGERED_BY(alarm_trigger, port))
+ attached_alarm?.alarm()
+
+ if(COMPONENT_TRIGGERED_BY(reset_trigger, port))
+ attached_alarm?.reset()
+
+
+
#undef FIREALARM_COOLDOWN
diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm
index dc911ee7c38f9..ec6d6748b2f11 100644
--- a/code/game/machinery/pipe/construction.dm
+++ b/code/game/machinery/pipe/construction.dm
@@ -22,6 +22,7 @@ Buildable meters
var/RPD_type
/// whether it can be painted
var/paintable = FALSE
+ var/pipe_color
/obj/item/pipe/directional
RPD_type = PIPE_UNARY
@@ -43,11 +44,12 @@ Buildable meters
CREATION_TEST_IGNORE_SUBTYPES(/obj/item/pipe)
-/obj/item/pipe/Initialize(mapload, _pipe_type, _dir, obj/machinery/atmospherics/make_from)
+/obj/item/pipe/Initialize(mapload, _pipe_type, _dir, obj/machinery/atmospherics/make_from, device_color)
if(make_from)
make_from_existing(make_from)
else
pipe_type = _pipe_type
+ pipe_color = device_color
setDir(_dir)
update()
@@ -61,6 +63,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/pipe)
add_atom_colour(make_from.color, FIXED_COLOUR_PRIORITY)
pipe_type = make_from.type
paintable = make_from.paintable
+ pipe_color = make_from.pipe_color
/obj/item/pipe/trinary/flippable/make_from_existing(obj/machinery/atmospherics/components/trinary/make_from)
..()
@@ -70,9 +73,9 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/pipe)
/obj/item/pipe/dropped()
..()
if(loc)
- setPipingLayer(piping_layer)
+ set_piping_layer(piping_layer)
-/obj/item/pipe/proc/setPipingLayer(new_layer = PIPING_LAYER_DEFAULT)
+/obj/item/pipe/proc/set_piping_layer(new_layer = PIPING_LAYER_DEFAULT)
var/obj/machinery/atmospherics/fakeA = pipe_type
if(initial(fakeA.pipe_flags) & PIPING_ALL_LAYER)
@@ -130,7 +133,17 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/pipe)
/obj/item/pipe/attack_self(mob/user)
setDir(turn(dir,-90))
-/obj/item/pipe/wrench_act(mob/living/user, obj/item/wrench/W)
+///Check if the pipe on the turf and our to be placed binary pipe are perpendicular to each other
+/obj/item/pipe/proc/check_ninety_degree_dir(obj/machinery/atmospherics/machine)
+ if(ISDIAGONALDIR(machine.dir))
+ return FALSE
+ if(EWCOMPONENT(machine.dir) && EWCOMPONENT(dir))
+ return FALSE
+ if(NSCOMPONENT(machine.dir) && NSCOMPONENT(dir))
+ return FALSE
+ return TRUE
+
+/obj/item/pipe/wrench_act(mob/living/user, obj/item/wrench/wrench)
if(!isturf(loc))
return TRUE
@@ -138,23 +151,42 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/pipe)
var/obj/machinery/atmospherics/fakeA = pipe_type
var/flags = initial(fakeA.pipe_flags)
- for(var/obj/machinery/atmospherics/M in loc)
- if((M.pipe_flags & flags & PIPING_ONE_PER_TURF)) //Only one dense/requires density object per tile, eg connectors/cryo/heater/coolers.
+ var/pipe_count = 0
+ for(var/obj/machinery/atmospherics/machine in loc)
+ if(machine.piping_layer != piping_layer)
+ continue
+ pipe_count += 1
+ for(var/obj/machinery/atmospherics/machine in loc)
+ if((machine.pipe_flags & flags & PIPING_ONE_PER_TURF)) //Only one dense/requires density object per tile, eg connectors/cryo/heater/coolers.
to_chat(user, "Something is hogging the tile!")
return TRUE
- if((M.piping_layer != piping_layer) && !((M.pipe_flags | flags) & PIPING_ALL_LAYER)) //don't continue if either pipe goes across all layers
+
+ if(pipe_count == 1 && istype(machine, /obj/machinery/atmospherics/pipe/smart) && ispath(pipe_type, /obj/machinery/atmospherics/pipe/smart) && lowertext(machine.pipe_color) != lowertext(pipe_color) && machine.connection_num < 3)
+ var/direction = machine.dir
+ if((direction & EAST|WEST || direction & SOUTH|NORTH) && !ISDIAGONALDIR(direction))
+ pipe_type = /obj/machinery/atmospherics/pipe/bridge_pipe
+ if(EWCOMPONENT(direction))
+ dir = NORTH
+ if(NSCOMPONENT(direction))
+ dir = EAST
+ continue
+
+ if(flags & PIPING_BRIDGE && !(machine.pipe_flags & PIPING_BRIDGE) && check_ninety_degree_dir(machine)) //continue if we are placing a bridge pipe over a normal pipe only (prevent duplicates)
continue
- if(M.GetInitDirections() & SSair.get_init_dirs(pipe_type, fixed_dir())) // matches at least one direction on either type of pipe
+
+ if((machine.piping_layer != piping_layer) && !((machine.pipe_flags | flags) & PIPING_ALL_LAYER)) //don't continue if either pipe goes across all layers
+ continue
+ if(machine.get_init_directions() & SSair.get_init_dirs(pipe_type, fixed_dir())) // matches at least one direction on either type of pipe
to_chat(user, "There is already a pipe at that location!")
return TRUE
// no conflicts found
- var/obj/machinery/atmospherics/A = new pipe_type(loc)
- build_pipe(A)
- A.on_construction(color, piping_layer)
- transfer_fingerprints_to(A)
+ var/obj/machinery/atmospherics/built_machine = new pipe_type(loc)
+ build_pipe(built_machine)
+ built_machine.on_construction(pipe_color, piping_layer)
+ transfer_fingerprints_to(built_machine)
- W.play_tool_sound(src)
+ wrench.play_tool_sound(src)
user.visible_message( \
"[user] fastens \the [src].", \
"You fasten \the [src].", \
@@ -164,7 +196,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/pipe)
/obj/item/pipe/proc/build_pipe(obj/machinery/atmospherics/A)
A.setDir(fixed_dir())
- A.SetInitDirections()
+ A.set_init_directions()
if(pipename)
A.name = pipename
diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm
index 6555d153e70ed..a833357a37f6e 100644
--- a/code/game/machinery/pipe/pipe_dispenser.dm
+++ b/code/game/machinery/pipe/pipe_dispenser.dm
@@ -47,7 +47,7 @@
return
var/p_dir = text2num(href_list["dir"])
var/obj/item/pipe/P = new (loc, p_type, p_dir)
- P.setPipingLayer(piping_layer)
+ P.set_piping_layer(piping_layer)
P.add_fingerprint(usr)
wait = world.time + 10
if(href_list["makemeter"])
diff --git a/code/game/machinery/portable_thermomachine.dm b/code/game/machinery/portable_thermomachine.dm
index 560d4f2191adf..d004a6f3b75e0 100644
--- a/code/game/machinery/portable_thermomachine.dm
+++ b/code/game/machinery/portable_thermomachine.dm
@@ -120,8 +120,8 @@
if(mode == HEATER_MODE_COOL)
delta_temperature *= -1
if(delta_temperature)
- environment.set_temperature(environment.return_temperature() + delta_temperature)
- air_update_turf()
+ environment.temperature = environment.return_temperature() + delta_temperature
+ air_update_turf(FALSE, FALSE)
cell.use(required_energy / efficiency)
/obj/machinery/portable_thermomachine/RefreshParts()
diff --git a/code/game/machinery/shieldgen.dm b/code/game/machinery/shieldgen.dm
index 0b18083000846..55a92f8ac7971 100644
--- a/code/game/machinery/shieldgen.dm
+++ b/code/game/machinery/shieldgen.dm
@@ -10,12 +10,16 @@
anchored = TRUE
resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
max_integrity = 200 //The shield can only take so much beating (prevents perma-prisons)
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
/obj/structure/emergency_shield/Initialize(mapload)
. = ..()
setDir(pick(GLOB.cardinals))
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
+
+/obj/structure/emergency_shield/Destroy()
+ air_update_turf(TRUE, FALSE)
+ . = ..()
/obj/structure/emergency_shield/Move()
var/turf/T = loc
@@ -60,7 +64,6 @@
max_integrity = 20
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
layer = ABOVE_MOB_LAYER
-
/obj/structure/emergency_shield/invoker/emp_act(severity)
return
@@ -653,8 +656,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/shieldwall)
icon = 'icons/effects/effects.dmi'
icon_state = "holofield"
density = FALSE
- CanAtmosPass = ATMOS_PASS_NO
- CanAtmosPassVertical = 1
+ can_atmos_pass = ATMOS_PASS_NO
hardshield = FALSE
layer = ABOVE_MOB_LAYER
light_color = "#f6e384"
diff --git a/code/game/machinery/shuttle/shuttle_engine.dm b/code/game/machinery/shuttle/shuttle_engine.dm
index df8795df27f25..91e76e84bc4eb 100644
--- a/code/game/machinery/shuttle/shuttle_engine.dm
+++ b/code/game/machinery/shuttle/shuttle_engine.dm
@@ -122,8 +122,8 @@
var/deltaTemperature = req_power / heat_cap
if(deltaTemperature < 0)
return
- env.set_temperature(env.return_temperature() + deltaTemperature)
- air_update_turf()
+ env.temperature = env.return_temperature() + deltaTemperature
+ air_update_turf(FALSE, FALSE)
/obj/machinery/shuttle/engine/attackby(obj/item/I, mob/living/user, params)
check_setup()
diff --git a/code/game/machinery/shuttle/shuttle_heater.dm b/code/game/machinery/shuttle/shuttle_heater.dm
index 1c1a9330a5d21..0b7f84cd18706 100644
--- a/code/game/machinery/shuttle/shuttle_heater.dm
+++ b/code/game/machinery/shuttle/shuttle_heater.dm
@@ -29,14 +29,14 @@
pipe_flags = PIPING_ONE_PER_TURF | PIPING_DEFAULT_LAYER_ONLY
- var/gas_type = GAS_PLASMA
+ var/gas_type = /datum/gas/plasma
var/efficiency_multiplier = 1
var/gas_capacity = 0
/obj/machinery/atmospherics/components/unary/shuttle/heater/New()
. = ..()
GLOB.custom_shuttle_machines += src
- SetInitDirections()
+ set_init_directions()
update_adjacent_engines()
updateGasStats()
@@ -47,27 +47,26 @@
/obj/machinery/atmospherics/components/unary/shuttle/heater/on_construction()
..(dir, dir)
- SetInitDirections()
+ set_init_directions()
update_adjacent_engines()
/obj/machinery/atmospherics/components/unary/shuttle/heater/default_change_direction_wrench(mob/user, obj/item/I)
if(!..())
return FALSE
- SetInitDirections()
+ set_init_directions()
var/obj/machinery/atmospherics/node = nodes[1]
if(node)
node.disconnect(src)
nodes[1] = null
if(!parents[1])
return
- nullifyPipenet(parents[1])
+ nullify_pipenet(parents[1])
- atmosinit()
+ atmos_init()
node = nodes[1]
if(node)
- node.atmosinit()
- node.addMember(src)
- build_network()
+ node.atmos_init()
+ node.add_member(src)
return TRUE
/obj/machinery/atmospherics/components/unary/shuttle/heater/RefreshParts()
@@ -84,14 +83,14 @@
/obj/machinery/atmospherics/components/unary/shuttle/heater/examine(mob/user)
. = ..()
var/datum/gas_mixture/air_contents = airs[1]
- . += "The engine heater's gas dial reads [air_contents.get_moles(gas_type)] moles of gas.
"
+ . += "The engine heater's gas dial reads [GET_MOLES(gas_type, air_contents)] moles of gas.
"
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/updateGasStats()
var/datum/gas_mixture/air_contents = airs[1]
if(!air_contents)
return
- air_contents.set_volume(gas_capacity)
- air_contents.set_temperature(T20C)
+ air_contents.volume = gas_capacity
+ air_contents.temperature = T20C
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/hasFuel(var/required)
var/datum/gas_mixture/air_contents = airs[1]
@@ -99,8 +98,7 @@
return moles >= required
/obj/machinery/atmospherics/components/unary/shuttle/heater/proc/consumeFuel(var/amount)
- var/datum/gas_mixture/air_contents = airs[1]
- air_contents.remove(amount)
+ remove_air(amount)
return
/obj/machinery/atmospherics/components/unary/shuttle/heater/attackby(obj/item/I, mob/living/user, params)
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index 1b8fb6f032f34..bf2968c7131f6 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -78,10 +78,9 @@
* Returns TRUE if there are mobs buckled to this atom and FALSE otherwise
*/
/atom/movable/proc/has_buckled_mobs()
- if(!buckled_mobs)
- return FALSE
- if(buckled_mobs.len)
+ if(length(buckled_mobs))
return TRUE
+ return FALSE
/**
* Set a mob as buckled to src
diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm
index 5ea702d1d52d5..58cfb9ad0ddb8 100644
--- a/code/game/objects/effects/effect_system/effects_foam.dm
+++ b/code/game/objects/effects/effect_system/effects_foam.dm
@@ -32,6 +32,10 @@
slippery_foam = FALSE
var/absorbed_plasma = 0
+/obj/effect/particle_effect/foam/firefighting/ComponentInitialize()
+ ..()
+ RemoveElement(/datum/element/atmos_sensitive)
+
/obj/effect/particle_effect/foam/firefighting/process()
..()
@@ -40,12 +44,12 @@
if(hotspot && istype(T) && T.air)
qdel(hotspot)
var/datum/gas_mixture/G = T.air
- var/plas_amt = min(30,G.get_moles(GAS_PLASMA)) //Absorb some plasma
- G.adjust_moles(GAS_PLASMA, -plas_amt)
+ var/plas_amt = min(30,GET_MOLES(/datum/gas/plasma, G)) //Absorb some plasma
+ REMOVE_MOLES(/datum/gas/plasma, G, plas_amt)
absorbed_plasma += plas_amt
- if(G.return_temperature() > T20C)
- G.set_temperature(max(G.return_temperature()/2,T20C))
- T.air_update_turf()
+ if(G.temperature > T20C)
+ G.temperature = max(G.return_temperature()/2,T20C)
+ T.air_update_turf(FALSE, FALSE)
/obj/effect/particle_effect/foam/firefighting/kill_foam()
STOP_PROCESSING(SSfastprocess, src)
@@ -65,9 +69,6 @@
L.adjust_fire_stacks(-2)
L.ExtinguishMob()
-/obj/effect/particle_effect/foam/firefighting/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- return
-
/obj/effect/particle_effect/foam/metal
name = "aluminium foam"
metal = ALUMINUM_FOAM
@@ -107,6 +108,7 @@
/obj/effect/particle_effect/foam/Initialize(mapload)
. = ..()
+ AddElement(/datum/element/atmos_sensitive)
create_reagents(1000) //limited by the size of the reagent holder anyway.
START_PROCESSING(SSfastprocess, src)
playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3)
@@ -191,7 +193,7 @@
/obj/effect/particle_effect/foam/proc/spread_foam()
var/turf/t_loc = get_turf(src)
- for(var/turf/T in t_loc.GetAtmosAdjacentTurfs())
+ for(var/turf/T in t_loc.get_atmos_adjacent_turfs())
var/obj/effect/particle_effect/foam/foundfoam = locate() in T //Don't spread foam where there's already foam!
if(foundfoam)
continue
@@ -207,16 +209,13 @@
F.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
F.metal = metal
+/obj/effect/particle_effect/foam/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 475
-/obj/effect/particle_effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated
+/obj/effect/particle_effect/foam/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated
kill_foam()
-
-/obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- return
-
-
///////////////////////////////////////////////
//FOAM EFFECT DATUM
/datum/effect_system/foam_spread
@@ -286,11 +285,15 @@
desc = "A lightweight foamed metal wall."
gender = PLURAL
max_integrity = 20
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
/obj/structure/foamedmetal/Initialize(mapload)
. = ..()
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
+
+/obj/structure/foamedmetal/Destroy()
+ air_update_turf(TRUE, FALSE)
+ . = ..()
/obj/structure/foamedmetal/Move()
var/turf/T = loc
@@ -333,14 +336,14 @@
O.ClearWet()
if(O.air)
var/datum/gas_mixture/G = O.air
- G.set_temperature(293.15)
+ G.temperature = 293.15
for(var/obj/effect/hotspot/H in O)
qdel(H)
- for(var/I in G.get_gases())
- if(I == GAS_O2 || I == GAS_N2)
+ for(var/I in G.gases)
+ if(I == /datum/gas/oxygen || I == /datum/gas/nitrogen)
continue
- G.set_moles(I, 0)
- O.air_update_turf()
+ SET_MOLES(I , G, 0)
+
for(var/obj/machinery/atmospherics/components/unary/U in O)
if(!U.welded)
U.welded = TRUE
diff --git a/code/game/objects/effects/effect_system/effects_smoke.dm b/code/game/objects/effects/effect_system/effects_smoke.dm
index 62922d034df1b..bef1f6710853c 100644
--- a/code/game/objects/effects/effect_system/effects_smoke.dm
+++ b/code/game/objects/effects/effect_system/effects_smoke.dm
@@ -91,7 +91,7 @@
if(!t_loc)
return
var/list/newsmokes = list()
- for(var/turf/T in t_loc.GetAtmosAdjacentTurfs(!circle))
+ for(var/turf/T in t_loc.get_atmos_adjacent_turfs(!circle))
var/obj/effect/particle_effect/smoke/foundsmoke = locate() in T //Don't spread smoke where there's already smoke!
if(foundsmoke)
continue
@@ -175,13 +175,14 @@
if(T.air)
var/datum/gas_mixture/G = T.air
if(!distcheck || get_dist(T, location) < blast) // Otherwise we'll get silliness like people using Nanofrost to kill people through walls with cold air
- G.set_temperature(temperature)
- T.air_update_turf()
+ G.temperature = temperature
+ T.air_update_turf(FALSE, FALSE)
for(var/obj/effect/hotspot/H in T)
qdel(H)
- if(G.get_moles(GAS_PLASMA))
- G.adjust_moles(GAS_N2, G.get_moles(GAS_PLASMA))
- G.set_moles(GAS_PLASMA, 0)
+ if(G.gases[/datum/gas/plasma][MOLES])
+ ADD_MOLES(/datum/gas/nitrogen, G, G.gases[/datum/gas/plasma][MOLES])
+ G.gases[/datum/gas/plasma][MOLES] = 0
+
if (weldvents)
for(var/obj/machinery/atmospherics/components/unary/U in T)
if(!isnull(U.welded) && !U.welded) //must be an unwelded vent pump or vent scrubber.
diff --git a/code/game/objects/effects/forcefields.dm b/code/game/objects/effects/forcefields.dm
index fc8577bf8a700..6e7fb59e1bcbb 100644
--- a/code/game/objects/effects/forcefields.dm
+++ b/code/game/objects/effects/forcefields.dm
@@ -5,7 +5,7 @@
anchored = TRUE
opacity = FALSE
density = TRUE
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
z_flags = Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP
var/timeleft = 300 //Set to 0 for permanent forcefields (ugh)
@@ -26,7 +26,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/forcefield)
name = "glowing wall"
icon = 'icons/effects/cult_effects.dmi'
icon_state = "cultshield"
- CanAtmosPass = ATMOS_PASS_NO
+ can_atmos_pass = ATMOS_PASS_NO
timeleft = 200
///////////Mimewalls///////////
diff --git a/code/game/objects/effects/glowshroom.dm b/code/game/objects/effects/glowshroom.dm
index 1a66796e2dae7..66b3d75e80af5 100644
--- a/code/game/objects/effects/glowshroom.dm
+++ b/code/game/objects/effects/glowshroom.dm
@@ -96,7 +96,7 @@
for(var/turf/open/floor/earth in view(3,src))
if(is_type_in_typecache(earth, blacklisted_glowshroom_turfs))
continue
- if(!ownturf.CanAtmosPass(earth))
+ if(!ownturf.can_atmos_pass(earth))
continue
if(spreadsIntoAdjacent || !locate(/obj/structure/glowshroom) in view(1,earth))
possibleLocs += earth
@@ -165,9 +165,11 @@
if(damage_type == BURN && damage_amount)
playsound(src.loc, 'sound/items/welder.ogg', 100, 1)
-/obj/structure/glowshroom/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
- take_damage(5, BURN, 0, 0)
+/obj/structure/glowshroom/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+
+/obj/structure/glowshroom/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ take_damage(5, BURN, 0, 0)
/obj/structure/glowshroom/acid_act(acidpwr, acid_volume)
. = 1
@@ -175,3 +177,7 @@
var/obj/effect/decal/cleanable/molten_object/I = new (get_turf(src))
I.desc = "Looks like this was \an [src] some time ago."
qdel(src)
+
+/obj/structure/glowshroom/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index b398597382f38..61c0671894676 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -84,6 +84,18 @@
vis_flags = VIS_INHERIT_ID
appearance_flags = KEEP_TOGETHER | LONG_GLIDE | PIXEL_SCALE
+/obj/effect/overlay/atmos_excited
+ name = "excited group"
+ icon = null
+ icon_state = null
+ anchored = TRUE // should only appear in vis_contents, but to be safe
+ appearance_flags = RESET_TRANSFORM | TILE_BOUND
+ invisibility = INVISIBILITY_ABSTRACT
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ vis_flags = VIS_INHERIT_PLANE
+ plane = ATMOS_GROUP_PLANE
+ layer = ATMOS_GROUP_LAYER
+
/obj/effect/overlay/light_cone
name = ""
icon = 'icons/effects/light_overlays/light_cone.dmi'
diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm
index 2a9ac99c7d876..64013dc498a24 100644
--- a/code/game/objects/effects/portals.dm
+++ b/code/game/objects/effects/portals.dm
@@ -1,10 +1,9 @@
-
-/proc/create_portal_pair(turf/source, turf/destination, _creator = null, _lifespan = 300, accuracy = 0, newtype = /obj/effect/portal, atmos_link_override)
+/proc/create_portal_pair(turf/source, turf/destination, _lifespan = 300, accuracy = 0, newtype = /obj/effect/portal)
if(!istype(source) || !istype(destination))
return
var/turf/actual_destination = get_teleport_turf(destination, accuracy)
- var/obj/effect/portal/P1 = new newtype(source, _creator, _lifespan, null, FALSE, null, atmos_link_override)
- var/obj/effect/portal/P2 = new newtype(actual_destination, _creator, _lifespan, P1, TRUE, null, atmos_link_override)
+ var/obj/effect/portal/P1 = new newtype(source, _lifespan, null, FALSE, null)
+ var/obj/effect/portal/P2 = new newtype(actual_destination, _lifespan, P1, TRUE, null)
if(!istype(P1)||!istype(P2))
return
P1.link_portal(P2)
@@ -138,16 +137,16 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/portal)
return FALSE
atmos_source.atmos_adjacent_turfs[atmos_destination] = TRUE
atmos_destination.atmos_adjacent_turfs[atmos_source] = TRUE
- atmos_source.air_update_turf(FALSE)
- atmos_destination.air_update_turf(FALSE)
+ atmos_source.air_update_turf(FALSE, FALSE)
+ atmos_destination.air_update_turf(FALSE, FALSE)
/obj/effect/portal/proc/unlink_atmos()
if(istype(atmos_source))
- if(istype(atmos_destination) && !atmos_source.Adjacent(atmos_destination) && !CANATMOSPASS(atmos_destination, atmos_source))
+ if(istype(atmos_destination) && !atmos_source.Adjacent(atmos_destination) && !CANATMOSPASS(atmos_destination, atmos_source, FALSE))
LAZYREMOVE(atmos_source.atmos_adjacent_turfs, atmos_destination)
atmos_source = null
if(istype(atmos_destination))
- if(istype(atmos_source) && !atmos_destination.Adjacent(atmos_source) && !CANATMOSPASS(atmos_source, atmos_destination))
+ if(istype(atmos_source) && !atmos_destination.Adjacent(atmos_source) && !CANATMOSPASS(atmos_source, atmos_destination, FALSE))
LAZYREMOVE(atmos_destination.atmos_adjacent_turfs, atmos_source)
atmos_destination = null
@@ -156,7 +155,6 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/portal)
call(creator, "on_portal_destroy")(src, src.loc)
creator = null
GLOB.portals -= src
- unlink_atmos()
if(hardlinked && !QDELETED(linked))
QDEL_NULL(linked)
else
diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm
index 04e93d4ffe2bf..774854c758c3c 100644
--- a/code/game/objects/effects/spawners/bombspawner.dm
+++ b/code/game/objects/effects/spawners/bombspawner.dm
@@ -1,6 +1,6 @@
#define CELSIUS_TO_KELVIN(T_K) ((T_K) + T0C)
-#define OPTIMAL_TEMP_K_PLA_BURN_SCALE(PRESSURE_P,PRESSURE_O,TEMP_O) (((PRESSURE_P) * GLOB.gas_data.specific_heats[GAS_PLASMA]) / (((PRESSURE_P) * GLOB.gas_data.specific_heats[GAS_PLASMA] + (PRESSURE_O) * GLOB.gas_data.specific_heats[GAS_O2]) / PLASMA_UPPER_TEMPERATURE - (PRESSURE_O) * GLOB.gas_data.specific_heats[GAS_O2] / CELSIUS_TO_KELVIN(TEMP_O)))
+#define OPTIMAL_TEMP_K_PLA_BURN_SCALE(PRESSURE_P,PRESSURE_O,TEMP_O) (((PRESSURE_P) * GLOB.meta_gas_info[/datum/gas/plasma][META_GAS_SPECIFIC_HEAT]) / (((PRESSURE_P) * GLOB.meta_gas_info[/datum/gas/plasma][META_GAS_SPECIFIC_HEAT] + (PRESSURE_O) * GLOB.meta_gas_info[/datum/gas/oxygen][META_GAS_SPECIFIC_HEAT]) / PLASMA_UPPER_TEMPERATURE - (PRESSURE_O) * GLOB.meta_gas_info[/datum/gas/oxygen][META_GAS_SPECIFIC_HEAT] / CELSIUS_TO_KELVIN(TEMP_O)))
#define OPTIMAL_TEMP_K_PLA_BURN_RATIO(PRESSURE_P,PRESSURE_O,TEMP_O) (CELSIUS_TO_KELVIN(TEMP_O) * PLASMA_OXYGEN_FULLBURN * (PRESSURE_P) / (PRESSURE_O))
/obj/effect/spawner/newbomb
@@ -16,19 +16,22 @@
/obj/effect/spawner/newbomb/Initialize(mapload)
. = ..()
var/obj/item/transfer_valve/V = new(src.loc)
- var/obj/item/tank/internals/plasma/PT = new(V)
- var/obj/item/tank/internals/oxygen/OT = new(V)
+ var/obj/item/tank/internals/plasma/plasma_tank = new(V)
+ var/obj/item/tank/internals/oxygen/oxygen_tank = new(V)
- PT.air_contents.set_moles(GAS_PLASMA, pressure_p*PT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_p)))
- PT.air_contents.set_temperature(CELSIUS_TO_KELVIN(temp_p))
+ var/datum/gas_mixture/plasma_mix = plasma_tank.return_air()
+ var/datum/gas_mixture/oxygen_mix = oxygen_tank.return_air()
- OT.air_contents.set_moles(GAS_O2, pressure_o*OT.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_o)))
- OT.air_contents.set_temperature(CELSIUS_TO_KELVIN(temp_o))
+ SET_MOLES(/datum/gas/plasma, plasma_mix, pressure_p*plasma_mix.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_p)))
+ plasma_mix.temperature = CELSIUS_TO_KELVIN(temp_p)
- V.tank_one = PT
- V.tank_two = OT
- PT.master = V
- OT.master = V
+ SET_MOLES(/datum/gas/oxygen, oxygen_mix, pressure_o*oxygen_mix.volume/(R_IDEAL_GAS_EQUATION*CELSIUS_TO_KELVIN(temp_o)))
+ oxygen_mix.temperature = CELSIUS_TO_KELVIN(temp_o)
+
+ V.tank_one = plasma_tank
+ V.tank_two = oxygen_tank
+ plasma_tank.master = V
+ oxygen_tank.master = V
if(assembly_type)
var/obj/item/assembly/A = new assembly_type(V)
diff --git a/code/game/objects/effects/spiders.dm b/code/game/objects/effects/spiders.dm
index b6e2940429b69..331d232eaaa17 100644
--- a/code/game/objects/effects/spiders.dm
+++ b/code/game/objects/effects/spiders.dm
@@ -7,7 +7,9 @@
density = FALSE
max_integrity = 15
-
+/obj/structure/spider/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
/obj/structure/spider/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
if(damage_type == BURN)//the stickiness of the web mutes all attack sounds except fire damage type
@@ -27,9 +29,11 @@
damage_amount *= 2
. = ..()
-/obj/structure/spider/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
- take_damage(5, BURN, 0, 0)
+/obj/structure/spider/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+
+/obj/structure/spider/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ take_damage(5, BURN, 0, 0)
/obj/structure/spider/stickyweb
icon_state = "stickyweb1"
@@ -127,9 +131,11 @@
else
to_chat(user, "[src] isn't ready yet!")
-/obj/structure/spider/eggcluster/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 500)
- take_damage(5, BURN, 0, 0)
+/obj/structure/spider/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+
+/obj/structure/spider/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ take_damage(5, BURN, 0, 0)
/obj/structure/spider/eggcluster/Destroy()
var/list/spawners = GLOB.mob_spawners[name]
@@ -258,7 +264,7 @@
if(get_dist(src, entry_vent) <= 1)
var/list/vents = list()
var/datum/pipeline/entry_vent_parent = entry_vent.parents[1]
- for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in entry_vent_parent.other_atmosmch)
+ for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in entry_vent_parent.other_atmos_machines)
vents.Add(temp_vent)
if(!vents.len)
entry_vent = null
diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm
index a1015199fb9ea..7345f04f1e809 100644
--- a/code/game/objects/items/RCD.dm
+++ b/code/game/objects/items/RCD.dm
@@ -925,7 +925,7 @@ GLOBAL_VAR_INIT(icon_holographic_window, init_holographic_window())
for(var/direction in GLOB.cardinals)
var/turf/C = get_step(W, direction)
var/list/dupes = checkdupes(C)
- if(start.CanAtmosPass(C) && !dupes.len)
+ if(start.can_atmos_pass(C) && !dupes.len)
candidates += C
if(!candidates.len)
to_chat(user, "Valid target not found...")
diff --git a/code/game/objects/items/RPD.dm b/code/game/objects/items/RPD.dm
index dbb91d6441ab4..6f817df7f910d 100644
--- a/code/game/objects/items/RPD.dm
+++ b/code/game/objects/items/RPD.dm
@@ -11,15 +11,14 @@ RPD
#define BUILD_MODE (1<<0)
#define WRENCH_MODE (1<<1)
#define DESTROY_MODE (1<<2)
-#define PAINT_MODE (1<<3)
GLOBAL_LIST_INIT(atmos_pipe_recipes, list(
"Pipes" = list(
- new /datum/pipe_info/pipe("Pipe", /obj/machinery/atmospherics/pipe/simple, TRUE),
- new /datum/pipe_info/pipe("Manifold", /obj/machinery/atmospherics/pipe/manifold, TRUE),
- new /datum/pipe_info/pipe("4-Way Manifold", /obj/machinery/atmospherics/pipe/manifold4w, TRUE),
+ new /datum/pipe_info/pipe("Pipe", /obj/machinery/atmospherics/pipe/smart, TRUE),
new /datum/pipe_info/pipe("Layer Adapter", /obj/machinery/atmospherics/pipe/layer_manifold, TRUE),
+ new /datum/pipe_info/pipe("Color Adapter", /obj/machinery/atmospherics/pipe/color_adapter, TRUE),
+ new /datum/pipe_info/pipe("Bridge Pipe", /obj/machinery/atmospherics/pipe/bridge_pipe, TRUE),
new /datum/pipe_info/pipe("Multi-Deck Adapter", /obj/machinery/atmospherics/pipe/multiz, TRUE),
new /datum/pipe_info/pipe("Manual Valve", /obj/machinery/atmospherics/components/binary/valve, TRUE),
new /datum/pipe_info/pipe("Digital Valve", /obj/machinery/atmospherics/components/binary/valve/digital, TRUE),
@@ -347,6 +346,10 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
ui = new(user, src, "RapidPipeDispenser")
ui.open()
+/obj/item/pipe_dispenser/ui_static_data(mob/user)
+ var/list/data = list("paint_colors" = GLOB.pipe_paint_colors)
+ return data
+
/obj/item/pipe_dispenser/ui_data(mob/user)
var/list/data = list(
"category" = category,
@@ -355,7 +358,6 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
"preview_rows" = recipe.get_preview(p_dir),
"categories" = list(),
"selected_color" = paint_color,
- "paint_colors" = GLOB.pipe_paint_colors,
"mode" = mode,
"locked" = locked
)
@@ -467,7 +469,7 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
return
//make sure what we're clicking is valid for the current category
- if(istype(attack_target, /obj/machinery/atmospherics) && ((mode & BUILD_MODE) && !(mode & PAINT_MODE))) //target turf if on buildmode so that it doesn't try painting a pipe you click on
+ if(istype(attack_target, /obj/machinery/atmospherics) && ((mode & BUILD_MODE)))
attack_target = get_turf(attack_target)
var/can_make_pipe = (isturf(attack_target) || is_type_in_typecache(attack_target, rpd_whitelist))
@@ -481,24 +483,6 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
qdel(attack_target)
return
- if(mode & PAINT_MODE)
- var/obj/machinery/atmospherics/M = attack_target
- if(istype(M) && M.paintable)
- to_chat(user, "You start painting \the [M] [paint_color]...")
- playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
- if(do_after(user, paint_speed, target = M))
- M.paint(GLOB.pipe_paint_colors[paint_color]) //paint the pipe
- user.visible_message("[user] paints \the [M] [paint_color].","You paint \the [M] [paint_color].")
- return
- var/obj/item/pipe/P = attack_target
- if(istype(P) && P.paintable)
- to_chat(user, "You start painting \the [P] [paint_color]...")
- playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
- if(do_after(user, paint_speed, target = P))
- P.add_atom_colour(GLOB.pipe_paint_colors[paint_color], FIXED_COLOUR_PRIORITY) //paint the pipe
- user.visible_message("[user] paints \the [P] [paint_color].","You paint \the [P] [paint_color].")
- return
-
if(mode & BUILD_MODE)
switch(category) //if we've gotten this var, the target is valid
if(ATMOS_CATEGORY) //Making pipes
@@ -525,7 +509,7 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
activate()
var/obj/machinery/atmospherics/path = queued_p_type
var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe
- var/obj/item/pipe/P = new pipe_item_type(get_turf(attack_target), queued_p_type, queued_p_dir)
+ var/obj/item/pipe/P = new pipe_item_type(get_turf(attack_target), queued_p_type, queued_p_dir, null, GLOB.pipe_paint_colors[paint_color])
if(queued_p_flipped && istype(P, /obj/item/pipe/trinary/flippable))
var/obj/item/pipe/trinary/flippable/F = P
@@ -533,8 +517,8 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
P.update()
P.add_fingerprint(usr)
- P.setPipingLayer(piping_layer)
- if(findtext("[queued_p_type]", "/obj/machinery/atmospherics/pipe") && !findtext("[queued_p_type]", "layer_manifold"))
+ P.set_piping_layer(piping_layer)
+ if(ispath(queued_p_type, /obj/machinery/atmospherics) && !ispath(queued_p_type, /obj/machinery/atmospherics/pipe/color_adapter))
P.add_atom_colour(GLOB.pipe_paint_colors[paint_color], FIXED_COLOUR_PRIORITY)
if(mode & WRENCH_MODE)
P.wrench_act(user, src)
@@ -668,7 +652,6 @@ GLOBAL_LIST_INIT(fluid_duct_recipes, list(
#undef BUILD_MODE
#undef DESTROY_MODE
-#undef PAINT_MODE
#undef WRENCH_MODE
/obj/item/rpd_upgrade
diff --git a/code/game/objects/items/chrono_eraser.dm b/code/game/objects/items/chrono_eraser.dm
index 01aa2723fba17..3bd6b4adbd707 100644
--- a/code/game/objects/items/chrono_eraser.dm
+++ b/code/game/objects/items/chrono_eraser.dm
@@ -266,9 +266,9 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/chrono_field)
/obj/structure/chrono_field/return_air() //we always have nominal air and temperature
var/datum/gas_mixture/GM = new
- GM.set_moles(GAS_O2, MOLES_O2STANDARD)
- GM.set_moles(GAS_N2, MOLES_N2STANDARD)
- GM.set_temperature(T20C)
+ SET_MOLES(/datum/gas/oxygen, GM, MOLES_O2STANDARD)
+ SET_MOLES(/datum/gas/nitrogen, GM, MOLES_N2STANDARD)
+ GM.temperature = T20C
return GM
/obj/structure/chrono_field/singularity_act()
diff --git a/code/game/objects/items/circuitboards/computer_circuitboards.dm b/code/game/objects/items/circuitboards/computer_circuitboards.dm
index 753d1cdf365df..c0fa5b00042ee 100644
--- a/code/game/objects/items/circuitboards/computer_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/computer_circuitboards.dm
@@ -82,53 +82,85 @@
build_path = /obj/machinery/computer/atmos_alert
/obj/item/circuitboard/computer/atmos_control
- name = "atmospheric monitor console (Computer Board)"
+ name = "Atmospheric Control"
icon_state = "engineering"
build_path = /obj/machinery/computer/atmos_control
-/obj/item/circuitboard/computer/atmos_control/tank
- name = "tank control console (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank
+/obj/item/circuitboard/computer/atmos_control/nocontrol
+ name = "Atmospheric Monitor"
+ build_path = /obj/machinery/computer/atmos_control/nocontrol
-/obj/item/circuitboard/computer/atmos_control/tank/oxygen_tank
- name = "oxygen supply control (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank/oxygen_tank
+/obj/item/circuitboard/computer/atmos_control/noreconnect
+ name = "Atmospheric Control"
+ build_path = /obj/machinery/computer/atmos_control/noreconnect
-/obj/item/circuitboard/computer/atmos_control/tank/plasma_tank
- name = "plasma supply control (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank/plasma_tank
+/obj/item/circuitboard/computer/atmos_control/fixed
+ name = "Atmospheric Monitor"
+ build_path = /obj/machinery/computer/atmos_control/fixed
-/obj/item/circuitboard/computer/atmos_control/tank/air_tank
- name = "mixed air supply control (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank/air_tank
+/obj/item/circuitboard/computer/atmos_control/nocontrol/master
+ name = "Station Atmospheric Monitor"
+ build_path = /obj/machinery/computer/atmos_control/nocontrol/master
-/obj/item/circuitboard/computer/atmos_control/tank/mix_tank
- name = "gas mix supply control (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank/mix_tank
+/obj/item/circuitboard/computer/atmos_control/nocontrol/incinerator
+ name = "Incinerator Chamber Monitor"
+ build_path = /obj/machinery/computer/atmos_control/nocontrol/incinerator
-/obj/item/circuitboard/computer/atmos_control/tank/nitrous_tank
- name = "nitrous oxide supply control (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank/nitrous_tank
+/obj/item/circuitboard/computer/atmos_control/ordnancemix
+ name = "Ordnance Chamber Control"
+ build_path = /obj/machinery/computer/atmos_control/ordnancemix
-/obj/item/circuitboard/computer/atmos_control/tank/nitrogen_tank
- name = "nitrogen supply control (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank/nitrogen_tank
+/obj/item/circuitboard/computer/atmos_control/oxygen_tank
+ name = "Oxygen Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/oxygen_tank
-/obj/item/circuitboard/computer/atmos_control/tank/carbon_tank
- name = "carbon dioxide supply control (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank/carbon_tank
+/obj/item/circuitboard/computer/atmos_control/plasma_tank
+ name = "Plasma Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/plasma_tank
-/obj/item/circuitboard/computer/atmos_control/tank/incinerator
- name = "incinerator air control (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank/incinerator
+/obj/item/circuitboard/computer/atmos_control/air_tank
+ name = "Mixed Air Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/air_tank
-/obj/item/circuitboard/computer/atmos_control/tank/sm_waste
- name = "supermatter waste control (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank/sm_waste
+/obj/item/circuitboard/computer/atmos_control/mix_tank
+ name = "Gas Mix Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/mix_tank
-/obj/item/circuitboard/computer/atmos_control/tank/toxins_waste
- name = "toxins waste control (Computer Board)"
- build_path = /obj/machinery/computer/atmos_control/tank/toxins_waste_tank
+/obj/item/circuitboard/computer/atmos_control/nitrous_tank
+ name = "Nitrous Oxide Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/nitrous_tank
+
+/obj/item/circuitboard/computer/atmos_control/nitrogen_tank
+ name = "Nitrogen Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/nitrogen_tank
+
+/obj/item/circuitboard/computer/atmos_control/carbon_tank
+ name = "Carbon Dioxide Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/carbon_tank
+
+/obj/item/circuitboard/computer/atmos_control/bz_tank
+ name = "BZ Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/bz_tank
+
+/obj/item/circuitboard/computer/atmos_control/hypernoblium_tank
+ name = "Hypernoblium Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/hypernoblium_tank
+
+/obj/item/circuitboard/computer/atmos_control/nitryl_tank
+ name = "Nitryl Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/nitryl_tank
+
+/obj/item/circuitboard/computer/atmos_control/pluoxium_tank
+ name = "Pluoxium Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/pluoxium_tank
+
+/obj/item/circuitboard/computer/atmos_control/tritium_tank
+ name = "Tritium Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/tritium_tank
+
+/obj/item/circuitboard/computer/atmos_control/water_vapor
+ name = "Water Vapor Supply Control"
+ build_path = /obj/machinery/computer/atmos_control/water_vapor
/obj/item/circuitboard/computer/auxillary_base
name = "auxillary base management console (Computer Board)"
diff --git a/code/game/objects/items/devices/forcefieldprojector.dm b/code/game/objects/items/devices/forcefieldprojector.dm
index 8f93c94e7dc9f..ff72b5a63cf8a 100644
--- a/code/game/objects/items/devices/forcefieldprojector.dm
+++ b/code/game/objects/items/devices/forcefieldprojector.dm
@@ -86,7 +86,7 @@
z_flags = Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP
mouse_opacity = MOUSE_OPACITY_OPAQUE
resistance_flags = INDESTRUCTIBLE
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
armor = list(MELEE = 0, BULLET = 25, LASER = 50, ENERGY = 50, BOMB = 25, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0)
var/obj/item/forcefield_projector/generator
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index c108bb13bf0c3..f91bf211bb7e9 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -655,9 +655,9 @@ GENE SCANNER
message += "Volume: [volume] L"
message += "Pressure: [round(pressure,0.01)] kPa"
- for(var/id in air_contents.get_gases())
- var/gas_concentration = air_contents.get_moles(id)/total_moles
- message += "[GLOB.gas_data.names[id]]: [round(gas_concentration*100, 0.01)] % ([round(air_contents.get_moles(id), 0.01)] mol)"
+ for(var/id in air_contents.gases)
+ var/gas_concentration = GET_MOLES(id,air_contents)/total_moles
+ message += "[air_contents.gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] % ([round(GET_MOLES(id, air_contents), 0.01)] mol)"
message += "Temperature: [round(temperature - T0C,0.01)] °C ([round(temperature, 0.01)] K)"
else
@@ -691,37 +691,37 @@ GENE SCANNER
else
message += "Pressure: [round(pressure, 0.01)] kPa"
if(total_moles)
- var/o2_concentration = environment.get_moles(GAS_O2)/total_moles
- var/n2_concentration = environment.get_moles(GAS_N2)/total_moles
- var/co2_concentration = environment.get_moles(GAS_CO2)/total_moles
- var/plasma_concentration = environment.get_moles(GAS_PLASMA)/total_moles
+ var/o2_concentration = GET_MOLES(/datum/gas/oxygen, environment)/total_moles
+ var/n2_concentration = GET_MOLES(/datum/gas/nitrogen, environment)/total_moles
+ var/co2_concentration = GET_MOLES(/datum/gas/carbon_dioxide, environment)/total_moles
+ var/plasma_concentration = GET_MOLES(/datum/gas/plasma, environment)/total_moles
if(abs(n2_concentration - N2STANDARD) < 20)
- message += "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(environment.get_moles(GAS_N2), 0.01)] mol)"
+ message += "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(n2_concentration*total_moles, 0.01)] mol)"
else
- message += "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(environment.get_moles(GAS_N2), 0.01)] mol)"
+ message += "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(n2_concentration*total_moles, 0.01)] mol)"
if(abs(o2_concentration - O2STANDARD) < 2)
- message += "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(environment.get_moles(GAS_O2), 0.01)] mol)"
+ message += "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(o2_concentration*total_moles, 0.01)] mol)"
else
- message += "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(environment.get_moles(GAS_O2), 0.01)] mol)"
+ message += "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(o2_concentration*total_moles, 0.01)] mol)"
if(co2_concentration > 0.01)
- message += "CO2: [round(co2_concentration*100, 0.01)] % ([round(environment.get_moles(GAS_CO2), 0.01)] mol)"
+ message += "CO2: [round(co2_concentration*100, 0.01)] % ([round(co2_concentration*total_moles, 0.01)] mol)"
else
- message += "CO2: [round(co2_concentration*100, 0.01)] % ([round(environment.get_moles(GAS_CO2), 0.01)] mol)"
+ message += "CO2: [round(co2_concentration*100, 0.01)] % ([round(co2_concentration*total_moles, 0.01)] mol)"
if(plasma_concentration > 0.005)
- message += "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(environment.get_moles(GAS_PLASMA), 0.01)] mol)"
+ message += "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(plasma_concentration*total_moles, 0.01)] mol)"
else
- message += "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(environment.get_moles(GAS_PLASMA), 0.01)] mol)"
+ message += "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(plasma_concentration*total_moles, 0.01)] mol)"
- for(var/id in environment.get_gases())
+ for(var/id in environment.gases)
if(id in GLOB.hardcoded_gases)
continue
- var/gas_concentration = environment.get_moles(id)/total_moles
- message += "[GLOB.gas_data.names[id]]: [round(gas_concentration*100, 0.01)] % ([round(environment.get_moles(id), 0.01)] mol)"
- message += "Temperature: [round(environment.return_temperature()-T0C, 0.01)] °C ([round(environment.return_temperature(), 0.01)] K)"
+ var/gas_concentration = GET_MOLES(id, environment)/total_moles
+ message += "[environment.gases[id][GAS_META][META_GAS_NAME]]: [round(gas_concentration*100, 0.01)] % ([round(gas_concentration*total_moles, 0.01)] mol)"
+ message += "Temperature: [round(environment.temperature-T0C, 0.01)] °C ([round(environment.temperature, 0.01)] K)"
to_chat(user, EXAMINE_BLOCK(jointext(message, "\n")))
/obj/item/analyzer/ranged
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index 24914e3ff031e..b0b6b7f58f44e 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -128,24 +128,34 @@
/obj/item/transfer_valve/proc/merge_gases(datum/gas_mixture/target, change_volume = TRUE)
var/target_self = FALSE
- if(!target || (target == tank_one.air_contents))
- target = tank_two.air_contents
- if(target == tank_two.air_contents)
+ var/datum/gas_mixture/mix_one = tank_one.return_air()
+ var/datum/gas_mixture/mix_two = tank_two.return_air()
+ if(!target || (target == mix_one))
+ target = mix_two
+ if(target == mix_two)
target_self = TRUE
if(change_volume)
if(!target_self)
- target.set_volume(target.return_volume() + tank_two.air_contents.return_volume())
- target.set_volume(target.return_volume() + tank_one.air_contents.return_volume())
- tank_one.air_contents.transfer_ratio_to(target, 1)
+ target.volume += tank_two.volume
+ target.volume += mix_one.volume
+ var/datum/gas_mixture/temp
+ temp = mix_one.remove_ratio(1)
+ target.merge(temp)
if(!target_self)
- tank_two.air_contents.transfer_ratio_to(target, 1)
+ temp = mix_two.remove_ratio(1)
+ target.merge(temp)
/obj/item/transfer_valve/proc/split_gases()
if (!valve_open || !tank_one || !tank_two)
return
- var/ratio1 = tank_one.air_contents.return_volume()/tank_two.air_contents.return_volume()
- tank_two.air_contents.transfer_ratio_to(tank_one.air_contents, ratio1)
- tank_two.air_contents.set_volume(tank_two.air_contents.return_volume() - tank_one.air_contents.return_volume())
+ var/datum/gas_mixture/mix_one = tank_one.return_air()
+ var/datum/gas_mixture/mix_two = tank_two.return_air()
+
+ var/volume_ratio = mix_one.volume/mix_two.volume
+ var/datum/gas_mixture/temp
+ temp = mix_two.remove_ratio(volume_ratio)
+ mix_one.merge(temp)
+ mix_two.volume -= mix_one.volume
/*
Exadv1: I know this isn't how it's going to work, but this was just to check
diff --git a/code/game/objects/items/flamethrower.dm b/code/game/objects/items/flamethrower.dm
index 9499d02af4e8c..9d9fe6a1e3aca 100644
--- a/code/game/objects/items/flamethrower.dm
+++ b/code/game/objects/items/flamethrower.dm
@@ -79,6 +79,9 @@
if(ishuman(user))
if(!can_trigger_gun(user))
return
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ to_chat(user, "You can't bring yourself to fire \the [src]! You don't want to risk harming anyone...")
+ return
if(user && user.get_active_held_item() == src) // Make sure our user is still holding us
var/turf/target_turf = get_turf(target)
if(target_turf)
@@ -196,7 +199,7 @@
for(var/turf/T in turflist)
if(T == previousturf)
continue //so we don't burn the tile we be standin on
- var/list/turfs_sharing_with_prev = previousturf.GetAtmosAdjacentTurfs(alldir=1)
+ var/list/turfs_sharing_with_prev = previousturf.get_atmos_adjacent_turfs(alldir=1)
if(!(T in turfs_sharing_with_prev))
break
if(igniter)
@@ -206,7 +209,7 @@
sleep(1)
previousturf = T
operating = FALSE
- for(var/mob/M as() in viewers(1, loc))
+ for(var/mob/M in viewers(1, loc))
if((M.client && M.machine == src))
attack_self(M)
@@ -214,14 +217,16 @@
/obj/item/flamethrower/proc/default_ignite(turf/target, release_amount = 0.05)
//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)
- air_transfer.set_moles(GAS_PLASMA, air_transfer.get_moles(GAS_PLASMA) * 5)
+ var/datum/gas_mixture/tank_mix = ptank.return_air()
+ var/datum/gas_mixture/air_transfer = tank_mix.remove_ratio(release_amount)
+
+ if(air_transfer.gases[/datum/gas/plasma])
+ air_transfer.gases[/datum/gas/plasma][MOLES] *= 5 //Suffering
target.assume_air(air_transfer)
//Burn it based on transfered gas
- target.hotspot_expose((ptank.air_contents.return_temperature()*2) + 380,500)
+ target.hotspot_expose((tank_mix.temperature*2) + 380,500)
//location.hotspot_expose(1000,500,1)
-
/obj/item/flamethrower/Initialize(mapload)
. = ..()
if(create_full)
diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm
index ca61f9fe5f675..aaad02b4a8230 100644
--- a/code/game/objects/items/latexballoon.dm
+++ b/code/game/objects/items/latexballoon.dm
@@ -45,9 +45,12 @@
burst()
return ..()
-/obj/item/latexballon/temperature_expose(datum/gas_mixture/air, temperature, volume)
- if(temperature > T0C+100)
- burst()
+/obj/item/latexballon/should_atmos_process(datum/gas_mixture/air, temperature)
+ return temperature > T0C+100
+
+/obj/item/latexballon/atmos_expose(datum/gas_mixture/air, temperature)
+ burst()
+
/obj/item/latexballon/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/tank))
diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm
index 283f276ab0567..9e00761a633a4 100644
--- a/code/game/objects/items/melee/misc.dm
+++ b/code/game/objects/items/melee/misc.dm
@@ -701,7 +701,7 @@
T.visible_message("[T] smacks into [src] and rapidly flashes to ash.",\
"You hear a loud crack as you are washed with a wave of heat.")
shard.Consume()
- CALCULATE_ADJACENT_TURFS(T)
+ CALCULATE_ADJACENT_TURFS(T, MAKE_ACTIVE)
/obj/item/melee/supermatter_sword/add_blood_DNA(list/blood_dna)
return FALSE
diff --git a/code/game/objects/items/peppercloud.dm b/code/game/objects/items/peppercloud.dm
index 27c1ecf3bf5d1..7b6fd8de8b06c 100644
--- a/code/game/objects/items/peppercloud.dm
+++ b/code/game/objects/items/peppercloud.dm
@@ -69,7 +69,7 @@
var/turf/previous = get_turf(user)
var/turf/next = get_step(user, direction)
for (var/i in 1 to 2)
- if (!CANATMOSPASS(next, previous))
+ if (!CANATMOSPASS(next, previous, FALSE))
break
previous = next
next = get_step(previous, direction)
diff --git a/code/game/objects/items/pneumaticCannon.dm b/code/game/objects/items/pneumaticCannon.dm
index 9b47f6b89cce0..0a5fc3cd38e69 100644
--- a/code/game/objects/items/pneumaticCannon.dm
+++ b/code/game/objects/items/pneumaticCannon.dm
@@ -152,7 +152,7 @@
if(!tank && checktank)
to_chat(user, "\The [src] can't fire without a source of gas.")
return
- if(tank && !tank.air_contents.remove(gasPerThrow * pressureSetting))
+ if(tank && !tank.remove_air(gasPerThrow * pressureSetting))
to_chat(user, "\The [src] lets out a weak hiss and doesn't react!")
return
if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(75) && clumsyCheck && iscarbon(user))
diff --git a/code/game/objects/items/powerfist.dm b/code/game/objects/items/powerfist.dm
index f558447a11618..f4bea664b02a3 100644
--- a/code/game/objects/items/powerfist.dm
+++ b/code/game/objects/items/powerfist.dm
@@ -78,7 +78,7 @@
if(!tank)
to_chat(user, "\The [src] can't operate without a source of gas!")
return
- var/datum/gas_mixture/gasused = tank.air_contents.remove(gasperfist * fisto_setting)
+ var/datum/gas_mixture/gasused = tank.remove_air(gasperfist * fisto_setting)
var/turf/T = get_turf(src)
if(!T)
return
@@ -96,7 +96,6 @@
return ..()
if(gasused.total_moles() < gasperfist * fisto_setting)
T.assume_air(gasused)
- T.air_update_turf()
to_chat(user, "\The [src]'s piston-ram lets out a weak hiss, it needs more gas!")
playsound(loc, 'sound/weapons/punch4.ogg', 50, 1)
force = (baseforce / 2)
@@ -114,7 +113,6 @@
var/mob/living/carbon/human/H = target
if(H.check_shields(src, force))
T.assume_air(gasused)
- T.air_update_turf()
return
target.visible_message("[user]'s powerfist lets out a loud hiss as [user.p_they()] punch[user.p_es()] [target.name]!", \
"You cry out in pain as [user]'s punch flings you backwards!", ignored_mobs = list(user))
@@ -131,6 +129,6 @@
user.changeNext_move(CLICK_CD_MELEE * click_delay)
T.assume_air(gasused)
- T.air_update_turf()
+ T.air_update_turf(FALSE, FALSE)
return ..()
diff --git a/code/game/objects/items/stacks/sheets/mineral/materials.dm b/code/game/objects/items/stacks/sheets/mineral/materials.dm
index 8ce8b3e34c4d8..cad2e6eeae939 100644
--- a/code/game/objects/items/stacks/sheets/mineral/materials.dm
+++ b/code/game/objects/items/stacks/sheets/mineral/materials.dm
@@ -99,9 +99,11 @@ Mineral Sheets
else
return ..()
-/obj/item/stack/sheet/mineral/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
- plasma_ignition(amount/5)
+/obj/item/stack/sheet/mineral/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+
+/obj/item/stack/sheet/mineral/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ plasma_ignition(amount/5)
/obj/item/stack/sheet/mineral/plasma/bullet_act(obj/projectile/Proj)
if(!(Proj.nodamage) && Proj.damage_type == BURN)
diff --git a/code/game/objects/items/stacks/sheets/organic/leather.dm b/code/game/objects/items/stacks/sheets/organic/leather.dm
index fdd63ac72fbc9..0de8f6c8abea8 100644
--- a/code/game/objects/items/stacks/sheets/organic/leather.dm
+++ b/code/game/objects/items/stacks/sheets/organic/leather.dm
@@ -38,6 +38,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/stack/sheet/leather/wetleather)
. = ..()
AddElement(/datum/element/dryable, /obj/item/stack/sheet/leather)
+
+/obj/item/stack/sheet/leather/wetleather/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
//Step two to make leather - washing
/obj/item/stack/sheet/leather/hairlesshide/machine_wash(obj/machinery/washing_machine/WM)
@@ -46,14 +51,15 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/stack/sheet/leather/wetleather)
//Step three to make leather - drying, either naturally or... in a more induced way.
-/obj/item/stack/sheet/leather/wetleather/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- ..()
- if(exposed_temperature >= drying_threshold_temperature)
- wetness--
- if(wetness == 0)
- new /obj/item/stack/sheet/leather(drop_location(), 1)
- wetness = initial(wetness)
- use(1)
+/obj/item/stack/sheet/leather/wetleather/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return (exposed_temperature > drying_threshold_temperature)
+
+/obj/item/stack/sheet/leather/wetleather/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ wetness--
+ if(wetness == 0)
+ new /obj/item/stack/sheet/leather(drop_location(), 1)
+ wetness = initial(wetness)
+ use(1)
/obj/item/stack/sheet/leather/wetleather/microwave_act(obj/machinery/microwave/MW)
..()
diff --git a/code/game/objects/items/tanks/jetpack.dm b/code/game/objects/items/tanks/jetpack.dm
index 072351d11c440..6b16d97ab3f59 100644
--- a/code/game/objects/items/tanks/jetpack.dm
+++ b/code/game/objects/items/tanks/jetpack.dm
@@ -8,7 +8,7 @@
w_class = WEIGHT_CLASS_BULKY
distribute_pressure = ONE_ATMOSPHERE * O2STANDARD
actions_types = list(/datum/action/item_action/set_internals, /datum/action/item_action/toggle_jetpack, /datum/action/item_action/jetpack_stabilization)
- var/gas_type = GAS_O2
+ var/gas_type = /datum/gas/oxygen
var/on = FALSE
var/stabilizers = FALSE
var/full_speed = TRUE // If the jetpack will have a speedboost in space/nograv or not
@@ -29,7 +29,7 @@
/obj/item/tank/jetpack/populate_gas()
if(gas_type)
- air_contents.set_moles(gas_type, ((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)))
+ SET_MOLES(gas_type, air_contents, ((6 * ONE_ATMOSPHERE * volume / (R_IDEAL_GAS_EQUATION * T20C))))
/obj/item/tank/jetpack/ui_action_click(mob/user, action)
if(istype(action, /datum/action/item_action/toggle_jetpack))
@@ -335,8 +335,11 @@
/obj/item/tank/jetpack/combustion/populate_gas()
var/moles_full = ((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
var/ideal_o2_percent = (1 / PLASMA_OXYGEN_FULLBURN) * 2
- air_contents.set_moles(GAS_PLASMA, moles_full * (1 - ideal_o2_percent))
- air_contents.set_moles(GAS_O2, moles_full * ideal_o2_percent)
+ var/datum/gas_mixture/temp_air_contents = return_air()
+
+ SET_MOLES(/datum/gas/plasma, temp_air_contents, moles_full*(1-ideal_o2_percent))
+ SET_MOLES(/datum/gas/oxygen, temp_air_contents, moles_full*ideal_o2_percent)
+
/obj/item/tank/jetpack/combustion/allow_thrust(num, mob/living/user, use_fuel = TRUE)
if(!on || !known_user)
@@ -346,16 +349,17 @@
return
var/potential_energy = 0
+ var/datum/gas_mixture/our_mix = return_air()
// Minified version of plasmafire burn reaction, with a "controlled" burnrate adjustment due to the high energy output of the reaction
// Also produces no waste products (CO2/Trit)
var/oxygen_burn_rate = (OXYGEN_BURN_RATE_BASE - 1)
var/plasma_burn_rate = 0
- if(air_contents.get_moles(GAS_O2) > air_contents.get_moles(GAS_PLASMA)*PLASMA_OXYGEN_FULLBURN)
- plasma_burn_rate = air_contents.get_moles(GAS_PLASMA)/PLASMA_BURN_RATE_DELTA
+ if(GET_MOLES(/datum/gas/oxygen, our_mix) > GET_MOLES(/datum/gas/plasma, our_mix) * PLASMA_OXYGEN_FULLBURN)
+ plasma_burn_rate = GET_MOLES(/datum/gas/plasma, our_mix)/PLASMA_BURN_RATE_DELTA
else
- plasma_burn_rate = (air_contents.get_moles(GAS_O2)/PLASMA_OXYGEN_FULLBURN)/PLASMA_BURN_RATE_DELTA
+ plasma_burn_rate = (GET_MOLES(/datum/gas/plasma, our_mix)/PLASMA_OXYGEN_FULLBURN)/PLASMA_BURN_RATE_DELTA
if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
- plasma_burn_rate = min(plasma_burn_rate,air_contents.get_moles(GAS_PLASMA),air_contents.get_moles(GAS_O2)/oxygen_burn_rate) //Ensures matter is conserved properly
+ plasma_burn_rate = min(plasma_burn_rate,GET_MOLES(/datum/gas/plasma, our_mix),GET_MOLES(/datum/gas/oxygen, our_mix)/oxygen_burn_rate) //Ensures matter is conserved properly
potential_energy = FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
// Normalize thrust volume to joules
@@ -369,8 +373,8 @@
// Consume
if(use_fuel)
- air_contents.set_moles(GAS_PLASMA, QUANTIZE(air_contents.get_moles(GAS_PLASMA) - plasma_burn_rate))
- air_contents.set_moles(GAS_O2, QUANTIZE(air_contents.get_moles(GAS_O2) - (plasma_burn_rate * oxygen_burn_rate)))
+ SET_MOLES(/datum/gas/plasma, our_mix, QUANTIZE(GET_MOLES(/datum/gas/plasma, our_mix) - plasma_burn_rate))
+ SET_MOLES(/datum/gas/oxygen, our_mix, QUANTIZE(GET_MOLES(/datum/gas/oxygen, our_mix) - (plasma_burn_rate * oxygen_burn_rate)))
update_fade(15)
update_lifespan(4)
@@ -382,7 +386,7 @@
icon_state = "jetpack-black"
item_state = "jetpack-black"
distribute_pressure = 0
- gas_type = GAS_CO2
+ gas_type = /datum/gas/carbon_dioxide
// Integrated suit jetpacks
// These use the tanks of a suit's suit storage instead of an internal tank, and their parent hardsuit assigns their known user.
@@ -430,7 +434,7 @@
return
var/mob/living/carbon/human/H = user
tank = H.s_store
- air_contents = tank.air_contents
+ air_contents = tank.return_air()
RegisterSignals(tank, list(COMSIG_ITEM_DROPPED, COMSIG_PARENT_QDELETING), PROC_REF(on_tank_drop))
START_PROCESSING(SSobj, src)
..()
diff --git a/code/game/objects/items/tanks/tank_types.dm b/code/game/objects/items/tanks/tank_types.dm
index f7a4ffdcd7397..3476feb96df2e 100644
--- a/code/game/objects/items/tanks/tank_types.dm
+++ b/code/game/objects/items/tanks/tank_types.dm
@@ -30,7 +30,7 @@
/obj/item/tank/internals/oxygen/populate_gas()
- air_contents.set_moles(GAS_O2, (6*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
+ SET_MOLES(/datum/gas/oxygen, air_contents, (6*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
/obj/item/tank/internals/oxygen/yellow
desc = "A tank of oxygen, this one is yellow."
@@ -56,8 +56,8 @@
force = 10
/obj/item/tank/internals/anesthetic/populate_gas()
- air_contents.set_moles(GAS_O2, (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) * O2STANDARD)
- air_contents.set_moles(GAS_NITROUS, (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) * N2STANDARD)
+ SET_MOLES(/datum/gas/oxygen, air_contents, (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) * O2STANDARD)
+ SET_MOLES(/datum/gas/nitrous_oxide, air_contents, (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) * N2STANDARD)
/*
* Air
@@ -71,8 +71,8 @@
dog_fashion = /datum/dog_fashion/back
/obj/item/tank/internals/air/populate_gas()
- air_contents.set_moles(GAS_O2, (6*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) * O2STANDARD)
- air_contents.set_moles(GAS_N2, (6*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) * N2STANDARD)
+ SET_MOLES(/datum/gas/oxygen, air_contents, (6*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) * O2STANDARD)
+ SET_MOLES(/datum/gas/nitrogen, air_contents, (6*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) * N2STANDARD)
/*
* Plasma
@@ -87,7 +87,7 @@
/obj/item/tank/internals/plasma/populate_gas()
- air_contents.set_moles(GAS_PLASMA, (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
+ SET_MOLES(/datum/gas/plasma, air_contents, (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
/obj/item/tank/internals/plasma/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/flamethrower))
@@ -103,7 +103,7 @@
return ..()
/obj/item/tank/internals/plasma/full/populate_gas()
- air_contents.set_moles(GAS_PLASMA, (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
+ SET_MOLES(/datum/gas/plasma, air_contents, (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
/obj/item/tank/internals/plasma/empty/populate_gas()
return
@@ -122,10 +122,10 @@
distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE
/obj/item/tank/internals/plasmaman/populate_gas()
- air_contents.set_moles(GAS_PLASMA, (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
+ SET_MOLES(/datum/gas/plasma, air_contents, (3*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
/obj/item/tank/internals/plasmaman/full/populate_gas()
- air_contents.set_moles(GAS_PLASMA, (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
+ SET_MOLES(/datum/gas/plasma, air_contents, (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
/obj/item/tank/internals/plasmaman/empty/populate_gas()
return
@@ -143,7 +143,7 @@
w_class = WEIGHT_CLASS_SMALL //thanks i forgot this
/obj/item/tank/internals/plasmaman/belt/full/populate_gas()
- air_contents.set_moles(GAS_PLASMA, (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
+ SET_MOLES(/datum/gas/plasma, air_contents, (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
/obj/item/tank/internals/plasmaman/belt/empty/populate_gas()
return
@@ -166,11 +166,11 @@
w_class = WEIGHT_CLASS_SMALL
force = 4
distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE
- volume = 1 //Tiny. Real life equivalents only have 21 breaths of oxygen in them. They're EMERGENCY tanks anyway -errorage (dangercon 2011)
+ 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.set_moles(GAS_O2, (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
+ SET_MOLES(/datum/gas/oxygen, air_contents, (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
/obj/item/tank/internals/emergency_oxygen/empty/populate_gas()
return
@@ -180,7 +180,7 @@
icon_state = "emergency_engi"
worn_icon_state = "emergency_engi"
worn_icon = null
- volume = 2 // should last a bit over 30 minutes if full
+ volume = 6 // should last a bit over 30 minutes if full
/obj/item/tank/internals/emergency_oxygen/engi/empty/populate_gas()
return
@@ -189,7 +189,7 @@
name = "double emergency oxygen tank"
icon_state = "emergency_double"
worn_icon_state = "emergency_engi"
- volume = 8
+ volume = 12
/obj/item/tank/internals/emergency_oxygen/double/empty/populate_gas()
return
@@ -214,5 +214,5 @@
volume = 1
/obj/item/tank/internals/emergency_oxygen/clown/populate_gas()
- air_contents.set_moles(GAS_O2, (9.99*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
- air_contents.set_moles(GAS_NITROUS, (0.01*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C))
+ SET_MOLES(/datum/gas/oxygen, air_contents, (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C)* 0.95)
+ SET_MOLES(/datum/gas/nitrous_oxide, air_contents, (10*ONE_ATMOSPHERE)*volume/(R_IDEAL_GAS_EQUATION*T20C) * 0.05)
diff --git a/code/game/objects/items/tanks/tanks.dm b/code/game/objects/items/tanks/tanks.dm
index bffb7ab089494..725bd1deda5f2 100644
--- a/code/game/objects/items/tanks/tanks.dm
+++ b/code/game/objects/items/tanks/tanks.dm
@@ -70,7 +70,7 @@
. = ..()
air_contents = new(volume) //liters
- air_contents.set_temperature(T20C)
+ air_contents.temperature = T20C
populate_gas()
@@ -98,7 +98,7 @@
. += "The gauge reads [round(air_contents.total_moles(), 0.01)] mol at [round(src.air_contents.return_pressure(),0.01)] kPa." //yogs can read mols
- var/celsius_temperature = src.air_contents.return_temperature()-T0C
+ var/celsius_temperature = air_contents.return_temperature()-T0C
var/descriptive
if (celsius_temperature < 20)
@@ -117,10 +117,10 @@
. += "It feels [descriptive]."
/obj/item/tank/deconstruct(disassembled = TRUE)
- var/turf/location = get_turf(src)
- if(location)
- location.assume_air(air_contents)
- location.air_update_turf(FALSE, FALSE)
+ if(!disassembled)
+ var/turf/location = get_turf(src)
+ if(location)
+ location.assume_air(air_contents)
playsound(location, 'sound/effects/spray.ogg', 10, TRUE, -3)
return ..()
@@ -203,31 +203,34 @@
distribute_pressure = clamp(round(pressure), TANK_MIN_RELEASE_PRESSURE, TANK_MAX_RELEASE_PRESSURE)
/obj/item/tank/remove_air(amount)
+ START_PROCESSING(SSobj, src)
return air_contents.remove(amount)
/obj/item/tank/remove_air_ratio(ratio)
- return air_contents.remove_ratio(ratio)
+ return remove_air_ratio(ratio)
/obj/item/tank/return_air()
+ START_PROCESSING(SSobj, src)
return air_contents
/obj/item/tank/return_analyzable_air()
return air_contents
/obj/item/tank/assume_air(datum/gas_mixture/giver)
+ START_PROCESSING(SSobj, src)
air_contents.merge(giver)
handle_tolerances(ASSUME_AIR_DT_FACTOR)
return TRUE
/obj/item/tank/assume_air_moles(datum/gas_mixture/giver, moles)
+ START_PROCESSING(SSobj, src)
giver.transfer_to(air_contents, moles)
-
handle_tolerances(ASSUME_AIR_DT_FACTOR)
return TRUE
/obj/item/tank/assume_air_ratio(datum/gas_mixture/giver, ratio)
+ START_PROCESSING(SSobj, src)
giver.transfer_ratio_to(air_contents, ratio)
-
handle_tolerances(ASSUME_AIR_DT_FACTOR)
return TRUE
@@ -243,25 +246,28 @@
return remove_air(moles_needed)
+
/obj/item/tank/process(delta_time)
if(!air_contents)
return
//Allow for reactions
- air_contents.react(src)
- handle_tolerances(delta_time)
- if(QDELETED(src) || !leaking || !air_contents)
+
+ if(!(air_contents.react(src) || handle_tolerances(delta_time) || leaking))
+ STOP_PROCESSING(SSobj, src)
+
+ if(QDELETED(src) || !air_contents || !leaking)
return
- var/turf/location = get_turf(src)
+ var/atom/location = loc
if(!location)
return
var/datum/gas_mixture/leaked_gas = air_contents.remove_ratio(0.25)
location.assume_air(leaked_gas)
- location.air_update_turf(FALSE, FALSE)
/**
* Handles the minimum and maximum pressure tolerances of the tank.
*
+ * Returns true if it did anything of significance, false otherwise
* Arguments:
* - delta_time: How long has passed between ticks.
*/
@@ -280,7 +286,8 @@
if(pressure >= TANK_LEAK_PRESSURE)
var/pressure_damage_ratio = (pressure - TANK_LEAK_PRESSURE) / (TANK_RUPTURE_PRESSURE - TANK_LEAK_PRESSURE)
take_damage(max_integrity * pressure_damage_ratio * delta_time, BRUTE, BOMB, FALSE, NONE)
- return TRUE
+ return TRUE
+ return FALSE
/// Handles the tank springing a leak.
/obj/item/tank/atom_break(damage_flag)
@@ -289,6 +296,9 @@
return
leaking = TRUE
+
+ START_PROCESSING(SSobj, src)
+
if(atom_integrity < 0) // So we don't play the alerts while we are exploding or rupturing.
return
visible_message("[src] springs a leak!")
diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm
index 85177a5e04007..8838f4d6cff8b 100644
--- a/code/game/objects/obj_defense.dm
+++ b/code/game/objects/obj_defense.dm
@@ -196,6 +196,7 @@ GLOBAL_DATUM_INIT(acid_overlay, /mutable_appearance, mutable_appearance('icons/e
//what happens when the obj's integrity reaches zero.
/obj/atom_destruction(damage_flag)
+ . = ..()
if(damage_flag == ACID)
acid_melt()
else if(damage_flag == FIRE)
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index b76b9ac15ac60..ae71c6fc546fc 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -109,10 +109,20 @@ CREATION_TEST_IGNORE_SELF(/obj)
AddComponent(/datum/component/ntnet_interface, network_id, id_tag)
/// Needs to run before as ComponentInitialize runs after this statement...why do we have ComponentInitialize again?
+// A list of all /obj by their id_tag
+GLOBAL_LIST_EMPTY(objects_by_id_tag)
+
+/obj/Initialize(mapload)
+ . = ..()
+
+ if (id_tag)
+ GLOB.objects_by_id_tag[id_tag] = src
+
/obj/Destroy(force=FALSE)
if(!ismachinery(src) && (datum_flags & DF_ISPROCESSING))
STOP_PROCESSING(SSobj, src)
SStgui.close_uis(src)
+ GLOB.objects_by_id_tag -= id_tag
. = ..()
diff --git a/code/game/objects/structures/aliens.dm b/code/game/objects/structures/aliens.dm
index cb218efabd838..36940ccb4454c 100644
--- a/code/game/objects/structures/aliens.dm
+++ b/code/game/objects/structures/aliens.dm
@@ -63,12 +63,16 @@
anchored = TRUE
max_integrity = 200
var/resintype = null
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
/obj/structure/alien/resin/Initialize(mapload)
. = ..()
- air_update_turf(TRUE)
+ air_update_turf(TRUE, TRUE)
+
+/obj/structure/alien/resin/Destroy()
+ air_update_turf(TRUE, FALSE)
+ . = ..()
/obj/structure/alien/resin/Move()
var/turf/T = loc
@@ -84,7 +88,7 @@
smoothing_groups = list(SMOOTH_GROUP_ALIEN_RESIN, SMOOTH_GROUP_ALIEN_WALLS)
canSmoothWith = list(SMOOTH_GROUP_ALIEN_WALLS)
-/obj/structure/alien/resin/wall/BlockThermalConductivity()
+/obj/structure/alien/resin/wall/block_superconductivity()
return 1
/obj/structure/alien/resin/membrane
@@ -171,13 +175,17 @@
icon = 'icons/obj/smooth_structures/alien/weeds3.dmi'
base_icon_state = "weeds3"
+/obj/structure/alien/weeds/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
/obj/structure/alien/weeds/proc/expand()
var/turf/U = get_turf(src)
if(is_type_in_typecache(U, blacklisted_turfs))
qdel(src)
return FALSE
- for(var/turf/T in U.GetAtmosAdjacentTurfs())
+ for(var/turf/T in U.get_atmos_adjacent_turfs())
if((locate(/obj/structure/alien/weeds) in T))
continue
@@ -187,9 +195,11 @@
new /obj/structure/alien/weeds(T)
return TRUE
-/obj/structure/alien/weeds/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
- take_damage(5, BURN, 0, 0)
+/obj/structure/alien/weeds/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+
+/obj/structure/alien/weeds/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ take_damage(5, BURN, 0, 0)
//Weed nodes
/obj/structure/alien/weeds/node
@@ -260,6 +270,10 @@
if(status == BURST)
atom_integrity = integrity_failure * max_integrity
+/obj/structure/alien/egg/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
/obj/structure/alien/egg/update_icon()
..()
switch(status)
@@ -337,10 +351,11 @@
if(status != BURST)
Burst(kill=TRUE)
-/obj/structure/alien/egg/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 500)
- take_damage(5, BURN, 0, 0)
+/obj/structure/alien/egg/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 500
+/obj/structure/alien/egg/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ take_damage(5, BURN, 0, 0)
/obj/structure/alien/egg/HasProximity(atom/movable/AM)
if(status == GROWN)
diff --git a/code/game/objects/structures/crates_lockers/crates/critter.dm b/code/game/objects/structures/crates_lockers/crates/critter.dm
index 2fda6f1ebc050..bae75aa791f76 100644
--- a/code/game/objects/structures/crates_lockers/crates/critter.dm
+++ b/code/game/objects/structures/crates_lockers/crates/critter.dm
@@ -69,7 +69,7 @@
/obj/structure/closet/crate/critter/return_air()
if(tank)
- return tank.air_contents
+ return tank.return_air()
else
return loc.return_air()
diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm
index deaa9387817f0..460a2a0e2e916 100644
--- a/code/game/objects/structures/false_walls.dm
+++ b/code/game/objects/structures/false_walls.dm
@@ -16,7 +16,7 @@
opacity = TRUE
max_integrity = 100
can_be_unanchored = FALSE
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
rad_insulation = RAD_MEDIUM_INSULATION
var/mineral = /obj/item/stack/sheet/iron
@@ -28,7 +28,7 @@
/obj/structure/falsewall/Initialize(mapload)
. = ..()
- air_update_turf(TRUE)
+ air_update_turf(TRUE, TRUE)
/obj/structure/falsewall/ratvar_act()
new /obj/structure/falsewall/brass(loc)
@@ -57,7 +57,7 @@
z_flags &= density ? (Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP) : ~(Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP)
opening = FALSE
update_icon()
- air_update_turf(TRUE)
+ air_update_turf(TRUE, !density)
/obj/structure/falsewall/update_icon()//Calling icon_update will refresh the smoothwalls if it's closed, otherwise it will make sure the icon is correct if it's open
if(opening)
@@ -261,6 +261,10 @@
mineral = /obj/item/stack/sheet/mineral/plasma
walltype = /turf/closed/wall/mineral/plasma
+/obj/structure/falsewall/plasma/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
/obj/structure/falsewall/plasma/attackby(obj/item/W, mob/user, params)
if(W.is_hot() > 300)
if(plasma_ignition(6, user))
@@ -269,11 +273,12 @@
else
return ..()
-/obj/structure/falsewall/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
- if(plasma_ignition(6))
- new /obj/structure/girder/displaced(loc)
+/obj/structure/falsewall/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+/obj/structure/falsewall/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ if(plasma_ignition(6))
+ new /obj/structure/girder/displaced(loc)
/obj/structure/falsewall/plasma/bullet_act(obj/projectile/Proj)
if(!(Proj.nodamage) && Proj.damage_type == BURN)
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index fe5d05fc53efa..1151469073da5 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -25,6 +25,10 @@
pipe_astar_cost = 1\
)
+/obj/structure/grille/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
/obj/structure/grille/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir, armour_penetration = 0)
. = ..()
update_appearance()
@@ -326,11 +330,11 @@
return FALSE
return FALSE
-/obj/structure/grille/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(!broken)
- if(exposed_temperature > T0C + 1500)
- take_damage(1, BURN, 0, 0)
- ..()
+/obj/structure/grille/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > T0C + 1500 && !broken
+
+/obj/structure/grille/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ take_damage(1, BURN, 0, 0)
/obj/structure/grille/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
if(isobj(AM))
diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm
index e4704b0e9e266..0252988e0836c 100644
--- a/code/game/objects/structures/holosign.dm
+++ b/code/game/objects/structures/holosign.dm
@@ -91,7 +91,7 @@
icon_state = "holo_firelock"
density = FALSE
anchored = TRUE
- CanAtmosPass = ATMOS_PASS_NO
+ can_atmos_pass = ATMOS_PASS_NO
alpha = 150
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
rad_insulation = RAD_LIGHT_INSULATION
@@ -107,11 +107,12 @@
. = ..()
var/turf/local = get_turf(loc)
ADD_TRAIT(local, TRAIT_FIREDOOR_STOP, TRAIT_GENERIC)
- air_update_turf(TRUE)
+ air_update_turf(TRUE, TRUE)
/obj/structure/holosign/barrier/atmos/Destroy()
var/turf/local = get_turf(loc)
REMOVE_TRAIT(local, TRAIT_FIREDOOR_STOP, TRAIT_GENERIC)
+ air_update_turf(TRUE, FALSE)
return ..()
/obj/structure/holosign/barrier/atmos/Move(atom/newloc, direct)
diff --git a/code/game/objects/structures/mineral_doors.dm b/code/game/objects/structures/mineral_doors.dm
index e47a0f3c8afb4..b7cdc25273d3c 100644
--- a/code/game/objects/structures/mineral_doors.dm
+++ b/code/game/objects/structures/mineral_doors.dm
@@ -12,7 +12,7 @@
icon_state = "metal"
max_integrity = 200
armor = list(MELEE = 10, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 50, ACID = 50, STAMINA = 0, BLEED = 0)
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
rad_insulation = RAD_MEDIUM_INSULATION
@@ -28,12 +28,18 @@
/obj/structure/mineral_door/Initialize(mapload)
. = ..()
- air_update_turf(TRUE)
+ air_update_turf(TRUE, TRUE)
+
+/obj/structure/mineral_door/Destroy()
+ if(!door_opened)
+ air_update_turf(TRUE, FALSE)
+ . = ..()
/obj/structure/mineral_door/Move()
var/turf/T = loc
. = ..()
- move_update_air(T)
+ if(!door_opened)
+ move_update_air(T)
/obj/structure/mineral_door/Bumped(atom/movable/AM)
..()
@@ -91,7 +97,7 @@
set_density(FALSE)
z_flags &= ~(Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP)
door_opened = TRUE
- air_update_turf(1)
+ air_update_turf(TRUE, FALSE)
update_appearance()
isSwitchingStates = FALSE
@@ -112,7 +118,7 @@
z_flags |= (Z_BLOCK_IN_DOWN | Z_BLOCK_IN_UP)
set_opacity(TRUE)
door_opened = FALSE
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
update_appearance()
isSwitchingStates = FALSE
@@ -131,7 +137,7 @@
/obj/structure/mineral_door/set_anchored(anchorvalue) //called in default_unfasten_wrench() chain
. = ..()
set_opacity(anchored ? !door_opened : FALSE)
- air_update_turf(TRUE)
+ air_update_turf(TRUE, anchorvalue)
/obj/structure/mineral_door/wrench_act(mob/living/user, obj/item/I)
default_unfasten_wrench(user, I, 40)
@@ -247,7 +253,8 @@
sheetType = /obj/item/stack/sheet/mineral/plasma
/obj/structure/mineral_door/transparent/plasma/ComponentInitialize()
- return
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
/obj/structure/mineral_door/transparent/plasma/welder_act(mob/living/user, obj/item/I)
return
@@ -258,9 +265,11 @@
else
return ..()
-/obj/structure/mineral_door/transparent/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
- plasma_ignition(6)
+/obj/structure/mineral_door/transparent/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+
+/obj/structure/mineral_door/transparent/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ plasma_ignition(6)
/obj/structure/mineral_door/transparent/plasma/bullet_act(obj/projectile/Proj)
if(!(Proj.nodamage) && Proj.damage_type == BURN)
diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm
index 8543dc4e95d7e..4f1f01701af42 100644
--- a/code/game/objects/structures/mirror.dm
+++ b/code/game/objects/structures/mirror.dm
@@ -264,14 +264,14 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/mirror)
if(P.starting)
var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
- var/turf/curloc = get_turf(src)
+ var/turf/current_location = get_turf(src)
// redirect the projectile
P.original = locate(new_x, new_y, P.z)
- P.starting = curloc
+ P.starting = current_location
P.firer = src
- P.yo = new_y - curloc.y
- P.xo = new_x - curloc.x
+ P.yo = new_y - current_location.y
+ P.xo = new_x - current_location.x
var/new_angle_s = P.Angle + 180
while(new_angle_s > 180) // Translate to regular projectile degrees
new_angle_s -= 360
diff --git a/code/game/objects/structures/plasticflaps.dm b/code/game/objects/structures/plasticflaps.dm
index ac850ce157a0d..fe0755830c57c 100644
--- a/code/game/objects/structures/plasticflaps.dm
+++ b/code/game/objects/structures/plasticflaps.dm
@@ -7,7 +7,7 @@
density = FALSE
anchored = TRUE
layer = BELOW_OBJ_LAYER
- CanAtmosPass = ATMOS_PASS_NO
+ can_atmos_pass = ATMOS_PASS_NO
/obj/structure/plasticflaps/opaque
opacity = TRUE
@@ -105,4 +105,10 @@
/obj/structure/plasticflaps/Initialize(mapload)
. = ..()
- air_update_turf(TRUE)
+ air_update_turf(TRUE, TRUE)
+
+/obj/structure/plasticflaps/Destroy()
+ var/atom/oldloc = loc
+ . = ..()
+ if (oldloc)
+ oldloc.air_update_turf(TRUE, FALSE)
diff --git a/code/game/objects/structures/statues.dm b/code/game/objects/structures/statues.dm
index fd1aa3564fc91..e6029035d64dc 100644
--- a/code/game/objects/structures/statues.dm
+++ b/code/game/objects/structures/statues.dm
@@ -7,10 +7,10 @@
density = TRUE
anchored = FALSE
max_integrity = 100
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
var/oreAmount = 5
var/material_drop_type = /obj/item/stack/sheet/iron
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
material_modifier = 0.5
material_flags = MATERIAL_EFFECTS | MATERIAL_AFFECT_STATISTICS
/// Beauty component mood modifier
@@ -109,8 +109,14 @@
name = "statue of a scientist"
icon_state = "sci"
-/obj/structure/statue/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
+/obj/structure/statue/plasma/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
+/obj/structure/statue/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+
+/obj/structure/statue/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature)
plasma_ignition(6)
diff --git a/code/game/objects/structures/transit_tubes/station.dm b/code/game/objects/structures/transit_tubes/station.dm
index 8bd3f81253726..6f7c3af18be4d 100644
--- a/code/game/objects/structures/transit_tubes/station.dm
+++ b/code/game/objects/structures/transit_tubes/station.dm
@@ -152,9 +152,10 @@
sleep(OPEN_DURATION + 2)
pod_moving = 0
if(!QDELETED(pod))
- var/datum/gas_mixture/floor_mixture = loc.return_air()
- equalize_all_gases_in_list(list(pod.air_contents,floor_mixture))
- air_update_turf()
+ return
+ var/datum/gas_mixture/floor_mixture = loc.return_air()
+ pod.air_contents.equalize(floor_mixture)
+ air_update_turf(FALSE, FALSE)
/obj/structure/transit_tube/station/init_tube_dirs()
switch(dir)
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 5fc6a029507de..7beb06367ae35 100644
--- a/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
+++ b/code/game/objects/structures/transit_tubes/transit_tube_pod.dm
@@ -13,9 +13,10 @@
/obj/structure/transit_tube_pod/Initialize(mapload)
. = ..()
- air_contents.set_moles(GAS_O2, MOLES_O2STANDARD)
- air_contents.set_moles(GAS_N2, MOLES_N2STANDARD)
- air_contents.set_temperature(T20C)
+ air_contents.add_gases(/datum/gas/oxygen, /datum/gas/nitrogen)
+ air_contents.gases[/datum/gas/oxygen][MOLES] = MOLES_O2STANDARD
+ air_contents.gases[/datum/gas/nitrogen][MOLES] = MOLES_N2STANDARD
+ air_contents.temperature = T20C
/obj/structure/transit_tube_pod/Destroy()
@@ -162,24 +163,9 @@
/obj/structure/transit_tube_pod/assume_air(datum/gas_mixture/giver)
return air_contents.merge(giver)
-/obj/structure/transit_tube_pod/assume_air_moles(datum/gas_mixture/giver, moles)
- return giver.transfer_to(air_contents, moles)
-
-/obj/structure/transit_tube_pod/assume_air_ratio(datum/gas_mixture/giver, ratio)
- return giver.transfer_ratio_to(air_contents, ratio)
-
/obj/structure/transit_tube_pod/remove_air(amount)
return air_contents.remove(amount)
-/obj/structure/transit_tube_pod/remove_air_ratio(ratio)
- return air_contents.remove_ratio(ratio)
-
-/obj/structure/transit_tube_pod/transfer_air(datum/gas_mixture/taker, moles)
- return air_contents.transfer_to(taker, moles)
-
-/obj/structure/transit_tube_pod/transfer_air_ratio(datum/gas_mixture/taker, ratio)
- return air_contents.transfer_ratio_to(taker, ratio)
-
/obj/structure/transit_tube_pod/relaymove(mob/living/user, direction)
if(!user.client || moving)
@@ -208,7 +194,7 @@
return
/obj/structure/transit_tube_pod/return_temperature()
- return air_contents.return_temperature()
+ return air_contents.temperature
#undef MOVE_ANIMATION_STAGE_ONE
#undef MOVE_ANIMATION_STAGE_TWO
diff --git a/code/game/objects/structures/windoor_assembly.dm b/code/game/objects/structures/windoor_assembly.dm
index 71687e38f612c..b963a5876cfea 100644
--- a/code/game/objects/structures/windoor_assembly.dm
+++ b/code/game/objects/structures/windoor_assembly.dm
@@ -18,7 +18,7 @@
density = FALSE
layer = ABOVE_OBJ_LAYER //Just above doors
anchored = FALSE
- CanAtmosPass = ATMOS_PASS_PROC
+ can_atmos_pass = ATMOS_PASS_PROC
dir = NORTH
set_dir_on_move = FALSE
@@ -37,7 +37,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/windoor_assembly)
. = ..()
if(set_dir)
setDir(set_dir)
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
var/static/list/loc_connections = list(
COMSIG_ATOM_EXIT = PROC_REF(on_exit),
@@ -47,7 +47,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/windoor_assembly)
/obj/structure/windoor_assembly/Destroy()
set_density(FALSE)
- air_update_turf(1)
+ air_update_turf(TRUE, FALSE)
return ..()
/obj/structure/windoor_assembly/Move()
@@ -73,11 +73,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/windoor_assembly)
return TRUE
-/obj/structure/windoor_assembly/CanAtmosPass(turf/T)
+/obj/structure/windoor_assembly/can_atmos_pass(turf/T, vertical = FALSE)
if(get_dir(loc, T) == dir)
return !density
else
- return 1
+ return TRUE
/obj/structure/windoor_assembly/proc/on_exit(datum/source, atom/movable/leaving, direction)
SIGNAL_HANDLER
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 55de8fdee8216..cf69d2d0979a7 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -11,7 +11,7 @@
can_be_unanchored = TRUE
resistance_flags = ACID_PROOF
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 100, STAMINA = 0, BLEED = 0)
- CanAtmosPass = ATMOS_PASS_PROC
+ can_atmos_pass = ATMOS_PASS_PROC
rad_insulation = RAD_VERY_LIGHT_INSULATION
rad_flags = RAD_PROTECT_CONTENTS
pass_flags_self = PASSTRANSPARENT
@@ -60,7 +60,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/window)
state = WINDOW_SCREWED_TO_FRAME
ini_dir = dir
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
if(fulltile)
setDir()
@@ -79,6 +79,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/window)
/obj/structure/window/ComponentInitialize()
. = ..()
AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS ,null,CALLBACK(src, PROC_REF(can_be_rotated)),CALLBACK(src, PROC_REF(after_rotation)))
+ AddElement(/datum/element/atmos_sensitive)
/obj/structure/window/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
if(the_rcd.mode == RCD_DECONSTRUCT)
@@ -242,7 +243,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/window)
/obj/structure/window/set_anchored(anchorvalue)
..()
- air_update_turf(TRUE)
+ air_update_turf(TRUE, anchorvalue)
update_nearby_icons()
/obj/structure/window/proc/check_state(checked_state)
@@ -319,11 +320,12 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/window)
return TRUE
/obj/structure/window/proc/after_rotation(mob/user,rotation_type)
+ air_update_turf(TRUE, FALSE)
ini_dir = dir
add_fingerprint(user)
/obj/structure/window/Destroy()
- set_density(FALSE)
+ air_update_turf(TRUE, FALSE)
air_update_turf(1)
update_nearby_icons()
return ..()
@@ -334,7 +336,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/window)
. = ..()
move_update_air(T)
-/obj/structure/window/CanAtmosPass(turf/T)
+/obj/structure/window/can_atmos_pass(turf/T, vertical = FALSE)
if(!anchored || !density)
return TRUE
return !(fulltile || dir == get_dir(loc, T))
@@ -363,11 +365,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/window)
crack_overlay = mutable_appearance('icons/obj/structures.dmi', "damage[ratio]", -(layer+0.1))
add_overlay(crack_overlay)
-/obj/structure/window/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+/obj/structure/window/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > T0C + heat_resistance
- if(exposed_temperature > (T0C + heat_resistance))
- take_damage(round(exposed_volume / 100), BURN, 0, 0)
- ..()
+/obj/structure/window/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ take_damage(round(air.return_volume() / 100), BURN, 0, 0)
/obj/structure/window/get_dumping_location(obj/item/storage/source,mob/user)
return null
@@ -431,6 +433,10 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/window)
glass_type = /obj/item/stack/sheet/plasmaglass
rad_insulation = RAD_NO_INSULATION
+/obj/structure/window/plasma/ComponentInitialize()
+ . = ..()
+ RemoveElement(/datum/element/atmos_sensitive)
+
/obj/structure/window/plasma/spawnDebris(location)
. = list()
. += new /obj/item/shard/plasma(location)
@@ -676,7 +682,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/window)
glass_type = /obj/item/stack/sheet/paperframes
heat_resistance = 233
decon_speed = 10
- CanAtmosPass = ATMOS_PASS_YES
+ can_atmos_pass = ATMOS_PASS_YES
resistance_flags = FLAMMABLE
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 0, ACID = 0, STAMINA = 0, BLEED = 0)
breaksound = 'sound/items/poster_ripped.ogg'
diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm
index c4e3061cc1862..8a09a5c6661ef 100644
--- a/code/game/turfs/change_turf.dm
+++ b/code/game/turfs/change_turf.dm
@@ -15,7 +15,8 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
if(turf_type)
var/turf/newT = ChangeTurf(turf_type, baseturf_type, flags)
- CALCULATE_ADJACENT_TURFS(newT)
+ SSair.remove_from_active(newT)
+ CALCULATE_ADJACENT_TURFS(newT, KILL_EXCITED)
/turf/proc/copyTurf(turf/T)
if(T.type != type)
@@ -98,6 +99,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
blueprint_data = null
var/list/old_baseturfs = baseturfs
+ var/old_type = type
var/list/post_change_callbacks = list()
SEND_SIGNAL(src, COMSIG_TURF_CHANGE, path, new_baseturfs, flags, post_change_callbacks)
@@ -131,7 +133,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
new_turf.explosion_level = old_exl
if(!(flags & CHANGETURF_DEFER_CHANGE))
- new_turf.AfterChange(flags)
+ new_turf.AfterChange(flags, old_type)
new_turf.blueprint_data = old_bp
new_turf.rcd_memory = old_rcd_memory
@@ -165,25 +167,29 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
if ((flags & CHANGETURF_INHERIT_AIR) && ispath(path, /turf/open))
var/datum/gas_mixture/stashed_air = new()
stashed_air.copy_from(air)
+ var/stashed_state = excited
+ var/datum/excited_group/stashed_group = excited_group
. = ..()
if (!.) // changeturf failed or didn't do anything
QDEL_NULL(stashed_air)
return
var/turf/open/newTurf = .
newTurf.air.copy_from(stashed_air)
- update_air_ref(planetary_atmos ? 1 : 2)
QDEL_NULL(stashed_air)
+ newTurf.excited = stashed_state
+ newTurf.excited_group = stashed_group
+ #ifdef VISUALIZE_ACTIVE_TURFS
+ if(stashed_state)
+ newTurf.add_atom_colour(COLOR_VIBRANT_LIME, TEMPORARY_COLOUR_PRIORITY)
+ #endif
+ if(stashed_group)
+ if(stashed_group.should_display || SSair.display_all_groups)
+ stashed_group.display_turf(newTurf)
else
+ SSair.remove_from_active(src) //Clean up wall excitement, and refresh excited groups
if(ispath(path,/turf/closed))
flags |= CHANGETURF_RECALC_ADJACENT
- update_air_ref(-1)
- . = ..()
- else
- . = ..()
- if(flags & CHANGETURF_SKIP) // don't init air before the air subsystem runs
- return
- if(!istype(air,/datum/gas_mixture))
- Initalize_Atmos(0)
+ . = ..()
/turf/closed/ChangeTurf(path, list/new_baseturfs, flags)
if(ispath(path,/turf/open))
@@ -308,12 +314,14 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
//If you modify this function, ensure it works correctly with lateloaded map templates.
-/turf/proc/AfterChange(flags) //called after a turf has been replaced in ChangeTurf()
+/turf/proc/AfterChange(flags, oldType) //called after a turf has been replaced in ChangeTurf()
levelupdate()
if(flags & CHANGETURF_RECALC_ADJACENT)
- ImmediateCalculateAdjacentTurfs()
- else
- CALCULATE_ADJACENT_TURFS(src)
+ immediate_calculate_adjacent_turfs()
+ if(ispath(oldType, /turf/closed) && istype(src, /turf/open))
+ SSair.add_to_active(src)
+ else //In effect, I want closed turfs to make their tile active when sheered, but we need to queue it since they have no adjacent turfs
+ CALCULATE_ADJACENT_TURFS(src, (!(ispath(oldType, /turf/closed) && istype(src, /turf/open)) ? NORMAL_TURF : MAKE_ACTIVE))
//update firedoor adjacency
var/list/turfs_to_check = get_adjacent_open_turfs(src) | src
@@ -329,7 +337,7 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
if(above)
above.update_mimic()
-/turf/open/AfterChange(flags)
+/turf/open/AfterChange(flags, oldType)
..()
RemoveLattice()
if(!(flags & (CHANGETURF_IGNORE_AIR | CHANGETURF_INHERIT_AIR)))
@@ -338,18 +346,41 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
//////Assimilate Air//////
/turf/open/proc/Assimilate_Air()
var/turf_count = LAZYLEN(atmos_adjacent_turfs)
- if(isclosedturf(src) || !turf_count) //if there weren't any open turfs, no need to update.
+ if(blocks_air || !turf_count) //if there weren't any open turfs, no need to update.
return
var/datum/gas_mixture/total = new//Holders to assimilate air from nearby turfs
-
- for(var/T in atmos_adjacent_turfs)
- var/turf/open/S = T
- if(!S.air)
- continue
- total.merge(S.air)
-
- air.copy_from(total.remove_ratio(1/turf_count))
+ var/list/total_gases = total.gases
+ //Stolen blatently from self_breakdown
+ var/list/turf_list = atmos_adjacent_turfs + src
+ var/turflen = turf_list.len
+ var/energy = 0
+ var/heat_cap = 0
+
+ for(var/t in turf_list)
+ var/turf/open/T = t
+ //Cache?
+ var/datum/gas_mixture/turf/mix = T.air
+ //"borrowing" this code from merge(), I need to play with the temp portion. Lets expand it out
+ //temperature = (giver.temperature * giver_heat_capacity + temperature * self_heat_capacity) / combined_heat_capacity
+ var/capacity = mix.heat_capacity()
+ energy += mix.temperature * capacity
+ heat_cap += capacity
+
+ var/list/giver_gases = mix.gases
+ for(var/giver_id in giver_gases)
+ ASSERT_GAS_IN_LIST(giver_id, total_gases)
+ total_gases[giver_id][MOLES] += giver_gases[giver_id][MOLES]
+
+ total.temperature = energy / heat_cap
+ for(var/id in total_gases)
+ total_gases[id][MOLES] /= turflen
+
+ for(var/t in turf_list)
+ var/turf/open/T = t
+ T.air.copy_from(total)
+ T.update_visuals()
+ SSair.add_to_active(T)
/turf/proc/ReplaceWithLattice()
ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
diff --git a/code/game/turfs/closed/_closed.dm b/code/game/turfs/closed/_closed.dm
index b58f97fde3f99..44199b70641b9 100644
--- a/code/game/turfs/closed/_closed.dm
+++ b/code/game/turfs/closed/_closed.dm
@@ -5,7 +5,9 @@ CREATION_TEST_IGNORE_SELF(/turf/closed)
opacity = TRUE
density = TRUE
init_air = FALSE
+ blocks_air = TRUE
rad_flags = RAD_PROTECT_CONTENTS | RAD_NO_CONTAMINATE
+ init_air = FALSE
rad_insulation = RAD_MEDIUM_INSULATION
pass_flags_self = PASSCLOSEDTURF
diff --git a/code/game/turfs/closed/minerals.dm b/code/game/turfs/closed/minerals.dm
index 74797a4cfe51c..6d655a78c8b7f 100644
--- a/code/game/turfs/closed/minerals.dm
+++ b/code/game/turfs/closed/minerals.dm
@@ -15,7 +15,7 @@
opacity = TRUE
density = TRUE
layer = EDGED_TURF_LAYER
- initial_temperature = 293.15
+ temperature = 293.15
max_integrity = 200
var/environment_type = "asteroid"
var/turf/open/floor/plating/turf_type = /turf/open/floor/plating/asteroid/airless
@@ -91,11 +91,33 @@
for(var/obj/effect/temp_visual/mining_overlay/M in src)
qdel(M)
var/flags = NONE
+ var/old_type = type
if(defer_change) // TODO: make the defer change var a var for any changeturf flag
flags = CHANGETURF_DEFER_CHANGE
- ScrapeAway(null, flags)
- addtimer(CALLBACK(src, PROC_REF(AfterChange)), 1, TIMER_UNIQUE)
- playsound(src, 'sound/effects/break_stone.ogg', 50, 1) //beautiful destruction
+ var/turf/open/mined = ScrapeAway(null, flags)
+ addtimer(CALLBACK(src, PROC_REF(AfterChange), flags, old_type), 1, TIMER_UNIQUE)
+ playsound(src, 'sound/effects/break_stone.ogg', 50, TRUE) //beautiful destruction
+ mined.update_visuals()
+
+/turf/closed/mineral/attack_animal(mob/living/simple_animal/user, list/modifiers)
+ if((user.environment_smash & ENVIRONMENT_SMASH_WALLS) || (user.environment_smash & ENVIRONMENT_SMASH_RWALLS))
+ gets_drilled(user)
+ ..()
+
+/turf/closed/mineral/attack_alien(mob/living/carbon/alien/user, list/modifiers)
+ to_chat(user, "You start digging into the rock...")
+ playsound(src, 'sound/effects/break_stone.ogg', 50, TRUE)
+ if(do_after(user, 4 SECONDS, target = src))
+ to_chat(user, "You tunnel into the rock.")
+ gets_drilled(user)
+
+/turf/closed/mineral/attack_hulk(mob/living/carbon/human/H)
+ ..()
+ if(do_after(H, 50, target = src))
+ playsound(src, 'sound/effects/meteorimpact.ogg', 100, TRUE)
+ H.say(pick(";RAAAAAAAARGH!", ";HNNNNNNNNNGGGGGGH!", ";GWAAAAAAAARRRHHH!", "NNNNNNNNGGGGGGGGHH!", ";AAAAAAARRRGH!" ), forced = "hulk")
+ gets_drilled(H)
+ return TRUE
/turf/closed/mineral/Bumped(atom/movable/AM)
..()
diff --git a/code/game/turfs/closed/wall/mineral_walls.dm b/code/game/turfs/closed/wall/mineral_walls.dm
index 4a9f4d54a846e..0dda9542c8dce 100644
--- a/code/game/turfs/closed/wall/mineral_walls.dm
+++ b/code/game/turfs/closed/wall/mineral_walls.dm
@@ -147,10 +147,11 @@
new /obj/structure/girder/displaced(loc)
..()
-/turf/closed/wall/mineral/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)//Doesn't fucking work because walls don't interact with air :(
- if(exposed_temperature > 300)
- if(plasma_ignition(6))
- new /obj/structure/girder/displaced(loc)
+/turf/closed/wall/mineral/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+/turf/closed/wall/mineral/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ if(plasma_ignition(6))
+ new /obj/structure/girder/displaced(loc)
/turf/closed/wall/mineral/plasma/bullet_act(obj/projectile/Proj)
if(!(Proj.nodamage) && Proj.damage_type == BURN)
diff --git a/code/game/turfs/closed/walls.dm b/code/game/turfs/closed/walls.dm
index b6296fa9f14d4..60d6a14898538 100644
--- a/code/game/turfs/closed/walls.dm
+++ b/code/game/turfs/closed/walls.dm
@@ -47,6 +47,7 @@
underlays += underlay_appearance
/turf/closed/wall/atom_destruction(damage_flag)
+ . = ..()
dismantle_wall(TRUE, FALSE)
/turf/closed/wall/Destroy()
diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm
index 6b0f5a24a69ef..d33702d8dd809 100644
--- a/code/game/turfs/open/_open.dm
+++ b/code/game/turfs/open/_open.dm
@@ -32,13 +32,6 @@ CREATION_TEST_IGNORE_SELF(/turf/open)
///Is this floor no-slip?
var/traction = FALSE
-/turf/open/Initialize(mapload)
- . = ..()
- if(broken)
- break_tile(TRUE)
- if(burnt)
- burn_tile(TRUE)
-
/turf/open/ComponentInitialize()
. = ..()
if(wet)
@@ -128,6 +121,7 @@ CREATION_TEST_IGNORE_SELF(/turf/open)
icon = 'icons/turf/boss_floors.dmi'
icon_state = "boss"
baseturfs = /turf/open/indestructible/boss
+ planetary_atmos = TRUE
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
/turf/open/indestructible/boss/air
@@ -135,6 +129,7 @@ CREATION_TEST_IGNORE_SELF(/turf/open)
/turf/open/indestructible/hierophant
icon = 'icons/turf/floors/hierophant_floor.dmi'
+ planetary_atmos = TRUE
initial_gas_mix = LAVALAND_DEFAULT_ATMOS
baseturfs = /turf/open/indestructible/hierophant
tiled_dirt = FALSE
@@ -157,7 +152,7 @@ CREATION_TEST_IGNORE_SELF(/turf/open)
/turf/open/indestructible/binary
name = "tear in the fabric of reality"
- CanAtmosPass = ATMOS_PASS_NO
+ can_atmos_pass = ATMOS_PASS_NO
baseturfs = /turf/open/indestructible/binary
icon_state = "binary"
footstep = FOOTSTEP_PLATING
@@ -168,30 +163,30 @@ CREATION_TEST_IGNORE_SELF(/turf/open)
/turf/open/indestructible/airblock
icon_state = "bluespace"
+ blocks_air = TRUE
+ init_air = FALSE
baseturfs = /turf/open/indestructible/airblock
- CanAtmosPass = ATMOS_PASS_NO
init_air = FALSE
-/turf/open/Initalize_Atmos(times_fired)
- if(!istype(air, /datum/gas_mixture/turf))
- air = new(2500,src)
- air.copy_from_turf(src)
- update_air_ref(planetary_atmos ? 1 : 2)
-
- update_visuals()
-
- ImmediateCalculateAdjacentTurfs()
+/turf/open/Initalize_Atmos(time)
+ excited = FALSE
+ if(!blocks_air)
+ if(!istype(air,/datum/gas_mixture/turf))
+ air = new(2500,src)
+ air.copy_from_turf(src)
+ current_cycle = time
+ init_immediate_calculate_adjacent_turfs()
-/turf/open/proc/GetHeatCapacity()
+/turf/open/get_heat_capacity()
. = air.heat_capacity()
-/turf/open/proc/GetTemperature()
+/turf/open/get_temperature()
. = air.return_temperature()
-/turf/open/proc/TakeTemperature(temp)
- air.set_temperature(air.return_temperature() + temp)
- air_update_turf()
+/turf/open/take_temperature(temp)
+ air.temperature = air.return_temperature() + temp
+ air_update_turf(FALSE, FALSE)
/turf/open/proc/freeze_turf()
for(var/obj/I in contents)
@@ -279,11 +274,11 @@ CREATION_TEST_IGNORE_SELF(/turf/open)
/turf/open/rad_act(pulse_strength)
. = ..()
- if (air.get_moles(GAS_CO2) && air.get_moles(GAS_O2))
- pulse_strength = min(pulse_strength,air.get_moles(GAS_CO2)*1000,air.get_moles(GAS_O2)*2000) //Ensures matter is conserved properly
- air.set_moles(GAS_CO2, max(air.get_moles(GAS_CO2)-(pulse_strength/1000),0))
- air.set_moles(GAS_O2, max(air.get_moles(GAS_O2)-(pulse_strength/2000),0))
- air.adjust_moles(GAS_PLUOXIUM, pulse_strength/4000)
+ if (air.gases[/datum/gas/carbon_dioxide] && air.gases[/datum/gas/oxygen])
+ pulse_strength = min(pulse_strength,air.gases[/datum/gas/carbon_dioxide][MOLES]*1000,air.gases[/datum/gas/oxygen][MOLES]*2000) //Ensures matter is conserved properly
+ REMOVE_MOLES(/datum/gas/carbon_dioxide, air, (pulse_strength/1000))
+ REMOVE_MOLES(/datum/gas/oxygen, air, (pulse_strength/2000))
+ ADJUST_MOLES(/datum/gas/pluoxium, air, pulse_strength/4000)
/turf/open/proc/break_tile(force, allow_base)
LAZYINITLIST(damage_overlays)
@@ -334,7 +329,7 @@ CREATION_TEST_IGNORE_SELF(/turf/open)
return GLOB.default_turf_damage
/turf/open/proc/burnt_states()
- return GLOB.default_turf_burn
+ return GLOB.default_burn_turf
/turf/open/proc/make_traction(add_visual = TRUE)
if(add_visual)
diff --git a/code/game/turfs/open/floor.dm b/code/game/turfs/open/floor.dm
index 9c8552f78b58f..50e1747df4747 100644
--- a/code/game/turfs/open/floor.dm
+++ b/code/game/turfs/open/floor.dm
@@ -16,7 +16,7 @@
smoothing_groups = list(SMOOTH_GROUP_TURF_OPEN, SMOOTH_GROUP_OPEN_FLOOR)
canSmoothWith = list(SMOOTH_GROUP_TURF_OPEN, SMOOTH_GROUP_OPEN_FLOOR)
- thermal_conductivity = 0.04
+ thermal_conductivity = 0.02
heat_capacity = 10000
tiled_dirt = TRUE
diff --git a/code/game/turfs/open/floor/fancy_floor.dm b/code/game/turfs/open/floor/fancy_floor.dm
index 212a1c61c6fff..47b56e50b71cd 100644
--- a/code/game/turfs/open/floor/fancy_floor.dm
+++ b/code/game/turfs/open/floor/fancy_floor.dm
@@ -100,7 +100,7 @@
return make_plating()
/turf/open/floor/wood/cold
- initial_temperature = 255.37
+ temperature = 255.37
/turf/open/floor/wood/airless
initial_gas_mix = AIRLESS_ATMOS
diff --git a/code/game/turfs/open/floor/mineral_floor.dm b/code/game/turfs/open/floor/mineral_floor.dm
index 99d133c7ed1f8..956c640f7749c 100644
--- a/code/game/turfs/open/floor/mineral_floor.dm
+++ b/code/game/turfs/open/floor/mineral_floor.dm
@@ -40,8 +40,10 @@
icons = list("plasma","plasma_dam")
max_integrity = 200
-/turf/open/floor/mineral/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
+/turf/open/floor/mineral/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+
+/turf/open/floor/mineral/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature)
PlasmaBurn(exposed_temperature)
/turf/open/floor/mineral/plasma/attackby(obj/item/W, mob/user, params)
diff --git a/code/game/turfs/open/floor/plating/asteroid.dm b/code/game/turfs/open/floor/plating/asteroid.dm
index cca192f99f6f2..5dbe2ae845fc2 100644
--- a/code/game/turfs/open/floor/plating/asteroid.dm
+++ b/code/game/turfs/open/floor/plating/asteroid.dm
@@ -91,7 +91,6 @@
GM = new
. = ..()
air = GM
- update_air_ref(2)
return
/turf/open/floor/plating/lavaland_baseturf
@@ -149,7 +148,6 @@
GM = new
. = ..()
air = GM
- update_air_ref(2)
return
/turf/open/floor/plating/asteroid/airless
diff --git a/code/game/turfs/open/floor/plating/misc_plating.dm b/code/game/turfs/open/floor/plating/misc_plating.dm
index 9b5051e161135..dbd89b785cda3 100644
--- a/code/game/turfs/open/floor/plating/misc_plating.dm
+++ b/code/game/turfs/open/floor/plating/misc_plating.dm
@@ -132,7 +132,6 @@
GM = new
. = ..()
air = GM
- update_air_ref(2)
return
/turf/open/floor/plating/beach
@@ -329,7 +328,7 @@
icon = 'icons/turf/floors/ice_turf.dmi'
icon_state = "ice-0"
initial_gas_mix = FROZEN_ATMOS
- initial_temperature = 180
+ temperature = 180
planetary_atmos = TRUE
baseturfs = /turf/open/floor/plating/ice
slowdown = 1
@@ -360,10 +359,10 @@
base_icon_state = "red_ice"
/turf/open/floor/plating/ice/colder
- initial_temperature = 140
+ temperature = 140
/turf/open/floor/plating/ice/temperate
- initial_temperature = 255.37
+ temperature = 255.37
/turf/open/floor/plating/ice/break_tile()
return
@@ -378,7 +377,7 @@
icon = 'icons/turf/snow.dmi'
icon_state = "snowplating"
initial_gas_mix = FROZEN_ATMOS
- initial_temperature = 180
+ temperature = 180
attachment_holes = FALSE
planetary_atmos = TRUE
footstep = FOOTSTEP_SAND
@@ -399,10 +398,10 @@
canSmoothWith = list(SMOOTH_GROUP_FLOOR_SNOWED)
/turf/open/floor/plating/snowed/colder
- initial_temperature = 140
+ temperature = 140
/turf/open/floor/plating/snowed/temperatre
- initial_temperature = 255.37
+ temperature = 255.37
/turf/open/floor/plating/elevatorshaft
name = "elevator shaft"
diff --git a/code/game/turfs/open/floor/reinf_floor.dm b/code/game/turfs/open/floor/reinf_floor.dm
index e59930ab35da0..3ee50555a0f3a 100644
--- a/code/game/turfs/open/floor/reinf_floor.dm
+++ b/code/game/turfs/open/floor/reinf_floor.dm
@@ -4,7 +4,7 @@
desc = "Extremely sturdy."
icon_state = "engine"
holodeck_compatible = TRUE
- thermal_conductivity = 0.025
+ thermal_conductivity = 0.01
heat_capacity = INFINITY
floor_tile = /obj/item/stack/sheet/iron
footstep = FOOTSTEP_PLATING
@@ -130,8 +130,7 @@
icon_state = "plating"
floor_tile = null
var/obj/effect/clockwork/overlay/floor/bloodcult/realappearance
- CanAtmosPass = ATMOS_PASS_NO
- CanAtmosPassVertical = ATMOS_PASS_NO
+ can_atmos_pass = ATMOS_PASS_NO
/turf/open/floor/engine/cult/Initialize(mapload)
diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm
index a31ddf285f808..3caa78f5dba12 100644
--- a/code/game/turfs/open/lava.dm
+++ b/code/game/turfs/open/lava.dm
@@ -75,13 +75,13 @@
underlay_appearance.icon_state = "basalt"
return TRUE
-/turf/open/lava/GetHeatCapacity()
+/turf/open/lava/get_heat_capacity()
. = 700000
-/turf/open/lava/GetTemperature()
+/turf/open/lava/get_temperature()
. = 5000
-/turf/open/lava/TakeTemperature(temp)
+/turf/open/lava/take_temperature(temp)
/turf/open/lava/proc/is_safe()
diff --git a/code/game/turfs/open/openspace.dm b/code/game/turfs/open/openspace.dm
index 4cef4cfdf32af..e2a19f3f905e5 100644
--- a/code/game/turfs/open/openspace.dm
+++ b/code/game/turfs/open/openspace.dm
@@ -5,7 +5,6 @@ CREATION_TEST_IGNORE_SUBTYPES(/turf/open/openspace)
desc = "Watch your step!"
icon_state = "invisible"
baseturfs = /turf/open/openspace
- CanAtmosPassVertical = ATMOS_PASS_YES
overfloor_placed = FALSE
underfloor_accessibility = UNDERFLOOR_INTERACTABLE
allow_z_travel = TRUE
diff --git a/code/game/turfs/open/space/space.dm b/code/game/turfs/open/space/space.dm
index d4e29778c1bab..be90a2b4c867b 100644
--- a/code/game/turfs/open/space/space.dm
+++ b/code/game/turfs/open/space/space.dm
@@ -13,8 +13,8 @@
allow_z_travel = TRUE
- initial_temperature = TCMB
- thermal_conductivity = 0
+ temperature = TCMB
+ thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
heat_capacity = 700000
// Since we have a lighting layer that extends further than the turf, make this turf
@@ -25,9 +25,10 @@
var/destination_x
var/destination_y
- var/static/datum/gas_mixture/immutable/space/space_gas
+ var/static/datum/gas_mixture/immutable/space/space_gas = new
// We do NOT want atmos adjacent turfs
init_air = FALSE
+ run_later = TRUE
plane = PLANE_SPACE
layer = SPACE_LAYER
light_power = 0.25
@@ -60,7 +61,6 @@
if(!space_gas)
space_gas = new
air = space_gas
- update_air_ref(0)
if(flags_1 & INITIALIZED_1)
stack_trace("Warning: [src]([type]) initialized multiple times!")
@@ -70,6 +70,9 @@
if(IS_DYNAMIC_LIGHTING(A))
overlays += GLOB.starlight_overlay
+ if(requires_activation)
+ SSair.add_to_active(src, TRUE)
+
return INITIALIZE_HINT_NORMAL
/turf/open/space/Destroy()
@@ -86,7 +89,7 @@
var/turf/T = locate(destination_x, destination_y, destination_z)
user.forceMove(T)
-/turf/open/space/TakeTemperature(temp)
+/turf/open/space/take_temperature(temp)
/turf/open/space/RemoveLattice()
return
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index d4fd9cea32f72..65d850511de67 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -23,7 +23,7 @@ CREATION_TEST_IGNORE_SELF(/turf)
var/list/baseturfs = /turf/baseturf_bottom
/// How hot the turf is, in kelvin
- var/initial_temperature = T20C
+ var/temperature = T20C
/// Used for fire, if a melting temperature was reached, it will be destroyed
var/to_be_destroyed = 0
@@ -36,6 +36,10 @@ CREATION_TEST_IGNORE_SELF(/turf)
//If true, turf will allow users to float up and down in 0 grav.
var/allow_z_travel = FALSE
+ /// Whether the turf blocks atmos from passing through it or not
+ var/blocks_air = FALSE
+
+
flags_1 = CAN_BE_DIRTY_1
/// For the station blueprints, images of objects eg: pipes
@@ -124,7 +128,7 @@ CREATION_TEST_IGNORE_SELF(/turf)
add_overlay(GLOB.fullbright_overlay)
if(requires_activation)
- CALCULATE_ADJACENT_TURFS(src)
+ CALCULATE_ADJACENT_TURFS(src, KILL_EXCITED)
if(color)
add_atom_colour(color, FIXED_COLOUR_PRIORITY)
@@ -157,13 +161,6 @@ CREATION_TEST_IGNORE_SELF(/turf)
else if (!armor)
armor = getArmor()
- if(isopenturf(src))
- var/turf/open/O = src
- __auxtools_update_turf_temp_info(isspaceturf(get_z_base_turf()) && !O.planetary_atmos)
- else
- update_air_ref(-1)
- __auxtools_update_turf_temp_info(isspaceturf(get_z_base_turf()))
-
//Handle turf texture
var/datum/turf_texture/TT = get_turf_texture()
if(TT)
@@ -171,15 +168,9 @@ CREATION_TEST_IGNORE_SELF(/turf)
return INITIALIZE_HINT_NORMAL
-/turf/proc/__auxtools_update_turf_temp_info()
-
-/turf/return_temperature()
-
-/turf/proc/set_temperature()
-
/// Initializes our adjacent turfs. If you want to avoid this, do not override it, instead set init_air to FALSE
-/turf/proc/Initalize_Atmos(times_fired)
- CALCULATE_ADJACENT_TURFS(src)
+/turf/proc/Initalize_Atmos(time)
+ CALCULATE_ADJACENT_TURFS(src, NORMAL_TURF)
/turf/Destroy(force)
. = QDEL_HINT_IWILLGC
@@ -531,6 +522,15 @@ CREATION_TEST_IGNORE_SELF(/turf)
continue
. += turf_to_check
+/turf/proc/get_heat_capacity()
+ . = heat_capacity
+
+/turf/proc/get_temperature()
+ . = temperature
+
+/turf/proc/take_temperature(temp)
+ temperature += temp
+
/turf/proc/generate_fake_pierced_realities(centered = TRUE, max_amount = 2)
if(max_amount <= 0)
return
diff --git a/code/game/world.dm b/code/game/world.dm
index 1ab3064883a49..fb5fb13f99482 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -32,7 +32,6 @@ GLOBAL_VAR(restart_counter)
*/
/world/proc/Genesis()
// auxtools has to go BEFORE tracy, otherwise tracy will clobber its hook addresses
- AUXTOOLS_CHECK(AUXMOS)
#ifdef USE_BYOND_TRACY
#warn USE_BYOND_TRACY is enabled
init_byond_tracy()
@@ -346,13 +345,11 @@ GLOBAL_VAR(restart_counter)
log_world("World rebooted at [time_stamp()]")
shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss.
- AUXTOOLS_SHUTDOWN(AUXMOS)
..()
#endif
/world/Del()
shutdown_logging() // makes sure the thread is closed before end, else we terminate
- AUXTOOLS_SHUTDOWN(AUXMOS)
var/debug_server = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL")
if (debug_server)
LIBCALL(debug_server, "auxtools_shutdown")()
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index 26b46dab28dcb..c6403a8e74128 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -187,9 +187,9 @@ GLOBAL_PROTECT(admin_verbs_debug)
/client/proc/cmd_display_init_log,
/client/proc/cmd_display_overlay_log,
/client/proc/reload_configuration,
+ /client/proc/atmos_control,
/client/proc/give_all_spells,
/datum/admins/proc/create_or_modify_area,
- /datum/admins/proc/fixcorruption,
#ifdef TESTING
/client/proc/check_missing_sprites,
/client/proc/run_dynamic_simulations,
@@ -627,6 +627,13 @@ GLOBAL_PROTECT(admin_verbs_hideable)
log_admin("[key_name(usr)] has modified Dynamic Explosion Scale: [ex_scale]")
message_admins("[key_name_admin(usr)] has modified Dynamic Explosion Scale: [ex_scale]")
+/client/proc/atmos_control()
+ set name = "Atmos Control Panel"
+ set category = "Debug"
+ if(!check_rights(R_DEBUG))
+ return
+ SSair.ui_interact(mob)
+
/client/proc/give_spell(mob/T in GLOB.mob_list)
set category = "Fun"
set name = "Give Spell"
@@ -812,6 +819,9 @@ GLOBAL_PROTECT(admin_verbs_hideable)
var/datum/gas_mixture/GM = new
for(var/turf/open/F in view())
+ if(F.blocks_air)
+ //skip walls
+ continue
GM.parse_gas_string(F.initial_gas_mix)
F.copy_air(GM)
F.update_visuals()
diff --git a/code/modules/admin/verbs/atmosdebug.dm b/code/modules/admin/verbs/atmosdebug.dm
index 0a4abfd033111..36bdc70329f1e 100644
--- a/code/modules/admin/verbs/atmosdebug.dm
+++ b/code/modules/admin/verbs/atmosdebug.dm
@@ -12,22 +12,15 @@
to_chat(usr, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]")
//Manifolds
- for(var/obj/machinery/atmospherics/pipe/manifold/pipe in GLOB.machines)
+ for(var/obj/machinery/atmospherics/pipe/smart/manifold4w/pipe in GLOB.machines)
if(pipe.z && (!pipe.nodes || !pipe.nodes.len || (null in pipe.nodes)))
to_chat(usr, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]")
//Pipes
- for(var/obj/machinery/atmospherics/pipe/simple/pipe in GLOB.machines)
+ for(var/obj/machinery/atmospherics/pipe/smart/manifold4w/pipe in GLOB.machines)
if(pipe.z && (!pipe.nodes || !pipe.nodes.len || (null in pipe.nodes)))
to_chat(usr, "Unconnected [pipe.name] located at [ADMIN_VERBOSEJMP(pipe)]")
- //Erroneous Connections, e.g. duplicate pipes
- //This uses pipeline_expansion(), so you can detect some atmos machineries causing problems at pipenet code.
- for (var/obj/machinery/atmospherics/AM in GLOB.machines)
- for (var/obj/machinery/atmospherics/AMT in AM.pipeline_expansion())
- if (!(AM in AMT.pipeline_expansion()))
- to_chat(usr, "Errorneous connections around [AM.name]. Duplicate or rogue pipes suspected at or around [ADMIN_VERBOSEJMP(AM)]")
-
/client/proc/powerdebug()
set category = "Mapping"
set name = "Check Power"
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index de8984cee7b1c..74898906d2ba1 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -272,42 +272,6 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
log_admin("[key_name(usr)] gave away direct control of [M] to [newkey].")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Give Direct Control") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
-/client/proc/cmd_admin_test_atmos_controllers()
- set category = "Mapping"
- set name = "Test Atmos Monitoring Consoles"
-
- var/list/dat = list()
-
- if(SSticker.current_state == GAME_STATE_STARTUP)
- to_chat(usr, "Game still loading, please hold!")
- return
-
- message_admins("[key_name_admin(usr)] used the Test Atmos Monitor debug command.")
- log_admin("[key_name(usr)] used the Test Atmos Monitor debug command.")
-
- var/bad_shit = 0
- for(var/obj/machinery/computer/atmos_control/tank/console in GLOB.atmos_air_controllers)
- dat += "[console] at [AREACOORD(console)]:
"
- if(console.input_tag == console.output_tag)
- dat += "Error: input_tag is the same as the output_tag, \"[console.input_tag]\"!
"
- bad_shit++
- if(!LAZYLEN(console.input_info))
- dat += "Failed to find a valid outlet injector as an input with the tag [console.input_tag].
"
- bad_shit++
- if(!LAZYLEN(console.output_info))
- dat += "Failed to find a valid siphon pump as an outlet with the tag [console.output_tag].
"
- bad_shit++
- if(!bad_shit)
- dat += "STATUS: NORMAL"
- else
- bad_shit = 0
- dat += "
"
- CHECK_TICK
-
- var/datum/browser/popup = new(usr, "testatmoscontroller", "Test Atmos Monitoring Consoles", 500, 750)
- popup.set_content(dat.Join())
- popup.open()
-
/client/proc/cmd_admin_areatest(on_station)
set category = "Mapping"
set name = "Test Areas"
@@ -591,7 +555,9 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
if(Rad.anchored)
if(!Rad.loaded_tank)
var/obj/item/tank/internals/plasma/Plasma = new/obj/item/tank/internals/plasma(Rad)
- Plasma.air_contents.set_moles(GAS_PLASMA, 70)
+ var/datum/gas_mixture/plasma_air = Plasma.return_air()
+ SET_MOLES(/datum/gas/plasma, plasma_air, 70)
+
Rad.drainratio = 0
Rad.loaded_tank = Plasma
Plasma.forceMove(Rad)
@@ -916,13 +882,15 @@ But you can call procs that are of type /mob/living/carbon/human/proc/ for that
if(!check_rights(R_DEBUG) || !C)
return
- var/gas_to_add = input(usr, "Choose a gas to modify.", "Choose a gas.") as null|anything in GLOB.gas_data.ids
+ var/gas_to_add = input(usr, "Choose a gas to modify.", "Choose a gas.") as null|anything in subtypesof(/datum/gas)
var/amount = input(usr, "Choose the amount of moles.", "Choose the amount.", 0) as num
var/temp = input(usr, "Choose the temperature (Kelvin).", "Choose the temp (K).", 0) as num
+ var/datum/gas_mixture/C_air = C.return_air()
+
+ SET_MOLES(gas_to_add, C_air, amount)
- C.air_contents.set_moles(gas_to_add, amount)
- C.air_contents.set_temperature(temp)
+ C_air.temperature = (temp)
C.update_icon()
message_admins("[key_name_admin(src)] modified \the [C.name] at [AREACOORD(C)] - Gas: [gas_to_add], Moles: [amount], Temp: [temp].")
diff --git a/code/modules/admin/verbs/fix_air.dm b/code/modules/admin/verbs/fix_air.dm
new file mode 100644
index 0000000000000..0550c3f66788c
--- /dev/null
+++ b/code/modules/admin/verbs/fix_air.dm
@@ -0,0 +1,20 @@
+// Proc taken from yogstation, credit to nichlas0010 for the original
+/client/proc/fix_air(turf/open/T in world)
+ set name = "Fix Air"
+ set category = "Admin.Game"
+ set desc = "Fixes air in specified radius."
+
+ if(!holder)
+ to_chat(src, "Only administrators may use this command.")
+ return
+ if(check_rights(R_ADMIN,1))
+ var/range=input("Enter range:","Num",2) as num
+ message_admins("[key_name_admin(usr)] fixed air with range [range] in area [T.loc.name]")
+ usr.log_message("fixed air with range [range] in area [T.loc.name]", LOG_ADMIN)
+ for(var/turf/open/F in range(range,T))
+ if(F.blocks_air)
+ //skip walls
+ continue
+ var/datum/gas_mixture/GM = SSair.parse_gas_string(F.initial_gas_mix)
+ F.copy_air(GM)
+ F.update_visuals()
diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm
index 36dc95bc3aaec..78d0d33cbe55a 100644
--- a/code/modules/admin/verbs/mapping.dm
+++ b/code/modules/admin/verbs/mapping.dm
@@ -39,7 +39,6 @@ GLOBAL_LIST_INIT(admin_verbs_debug_mapping, list(
#ifdef TESTING
/client/proc/see_dirty_varedits,
#endif
- /client/proc/cmd_admin_test_atmos_controllers,
/client/proc/cmd_admin_rejuvenate,
/datum/admins/proc/show_traitor_panel,
/client/proc/disable_communication,
diff --git a/code/modules/antagonists/blob/structures/_blob.dm b/code/modules/antagonists/blob/structures/_blob.dm
index 8836bba8305f8..88e3156fe3038 100644
--- a/code/modules/antagonists/blob/structures/_blob.dm
+++ b/code/modules/antagonists/blob/structures/_blob.dm
@@ -9,7 +9,7 @@
anchored = TRUE
layer = BELOW_MOB_LAYER
pass_flags_self = PASSBLOB
- CanAtmosPass = ATMOS_PASS_PROC
+ can_atmos_pass = ATMOS_PASS_PROC
var/point_return = 0 //How many points the blob gets back when it removes a blob of that type. If less than 0, blob cannot be removed.
max_integrity = 30
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 80, ACID = 70, STAMINA = 0, BLEED = 0)
@@ -34,7 +34,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/blob)
setDir(pick(GLOB.cardinals))
update_icon()
if(atmosblock)
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
ConsumeTile()
/obj/structure/blob/proc/creation_action() //When it's created by the overmind, do this.
@@ -43,7 +43,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/blob)
/obj/structure/blob/Destroy()
if(atmosblock)
atmosblock = FALSE
- air_update_turf(1)
+ air_update_turf(TRUE, FALSE)
if(overmind)
overmind.blobs_legit -= src //if it was in the legit blobs list, it isn't now
GLOB.blobs -= src //it's no longer in the all blobs list either
@@ -67,10 +67,10 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/structure/blob)
result++
. -= result - 1
-/obj/structure/blob/BlockThermalConductivity()
+/obj/structure/blob/block_superconductivity()
return atmosblock
-/obj/structure/blob/CanAtmosPass(turf/T)
+/obj/structure/blob/can_atmos_pass(turf/T, vertical = FALSE)
return !atmosblock
/obj/structure/blob/update_icon() //Updates color based on overmind color if we have an overmind.
diff --git a/code/modules/antagonists/blob/structures/shield.dm b/code/modules/antagonists/blob/structures/shield.dm
index 2246e8ba44c8e..2eb6b4cc3b82f 100644
--- a/code/modules/antagonists/blob/structures/shield.dm
+++ b/code/modules/antagonists/blob/structures/shield.dm
@@ -31,7 +31,7 @@
. = ..()
if(. && atom_integrity > 0)
atmosblock = atom_integrity < (max_integrity * 0.5)
- air_update_turf(TRUE)
+ air_update_turf(TRUE, atmosblock)
/obj/structure/blob/shield/update_icon_state()
icon_state = "[initial(icon_state)][(atom_integrity < (max_integrity * 0.5)) ? "_damaged" : null]"
diff --git a/code/modules/antagonists/clock_cult/clockwork_turfs.dm b/code/modules/antagonists/clock_cult/clockwork_turfs.dm
index 67406d57e8c28..a07f3b9a078f2 100644
--- a/code/modules/antagonists/clock_cult/clockwork_turfs.dm
+++ b/code/modules/antagonists/clock_cult/clockwork_turfs.dm
@@ -343,7 +343,7 @@
damage_deflection = 30
normal_integrity = 240
air_tight = FALSE
- CanAtmosPass = ATMOS_PASS_YES
+ can_atmos_pass = ATMOS_PASS_YES
var/construction_state = GEAR_SECURE //Pinion airlocks have custom deconstruction
allow_repaint = FALSE
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 7bc21a124e288..b702ed440189b 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -674,7 +674,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/rune/narsie)
invocation = "Khari'd! Eske'te tannin!"
icon_state = "4"
color = RUNE_COLOR_DARKRED
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
var/datum/timedevent/density_timer
var/recharging = FALSE
@@ -694,7 +694,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/rune/wall)
GLOB.wall_runes -= src
return ..()
-/obj/effect/rune/wall/BlockThermalConductivity()
+/obj/effect/rune/wall/block_superconductivity()
return density
/obj/effect/rune/wall/invoke(var/list/invokers)
diff --git a/code/modules/antagonists/heretic/knowledge/void_lore.dm b/code/modules/antagonists/heretic/knowledge/void_lore.dm
index e3ae1b7644442..f5b51a8dc7223 100644
--- a/code/modules/antagonists/heretic/knowledge/void_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/void_lore.dm
@@ -59,7 +59,7 @@
return FALSE
var/turf/open/our_turf = loc
- if(our_turf.GetTemperature() > T0C)
+ if(our_turf.get_temperature() > T0C)
loc.balloon_alert(user, "ritual failed, not cold enough!")
return FALSE
@@ -88,7 +88,7 @@
var/mob/living/carbon/carbon_target = target
var/turf/open/target_turf = get_turf(carbon_target)
- target_turf.TakeTemperature(-20)
+ target_turf.take_temperature(-20)
carbon_target.adjust_bodytemperature(-40)
carbon_target.silent += 4
@@ -248,7 +248,7 @@
return FALSE
var/turf/open/our_turf = loc
- if(our_turf.GetTemperature() > T0C)
+ if(our_turf.get_temperature() > T0C)
loc.balloon_alert(user, "ritual failed, not cold enough!")
return FALSE
@@ -288,7 +288,7 @@
var/turf/open/source_turf = get_turf(source)
if(!isopenturf(source_turf))
return
- source_turf.TakeTemperature(-20)
+ source_turf.take_temperature(-20)
var/area/source_area = get_area(source)
diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
index 39399d9e8064a..4720a743edc0a 100644
--- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
+++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm
@@ -13,7 +13,24 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list(
/obj/machinery/syndicatebomb/badmin/clown,
/obj/machinery/syndicatebomb/empty,
/obj/machinery/syndicatebomb/self_destruct,
- /obj/machinery/syndicatebomb/training
+ /obj/machinery/syndicatebomb/training,
+ /obj/machinery/atmospherics/pipe/layer_manifold,
+ /obj/machinery/atmospherics/pipe/multiz,
+ /obj/machinery/atmospherics/pipe/smart,
+ /obj/machinery/atmospherics/pipe/smart/manifold, //mapped one
+ /obj/machinery/atmospherics/pipe/smart/manifold4w, //mapped one
+ /obj/machinery/atmospherics/pipe/color_adapter,
+ /obj/machinery/atmospherics/pipe/bridge_pipe,
+ /obj/machinery/atmospherics/pipe/heat_exchanging/simple,
+ /obj/machinery/atmospherics/pipe/heat_exchanging/junction,
+ /obj/machinery/atmospherics/pipe/heat_exchanging/manifold,
+ /obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w,
+ /obj/machinery/atmospherics/components/tank,
+ /obj/machinery/atmospherics/components/unary/portables_connector,
+ /obj/machinery/atmospherics/components/unary/passive_vent,
+ /obj/machinery/atmospherics/components/unary/heat_exchanger,
+ /obj/machinery/atmospherics/components/binary/valve,
+ /obj/machinery/portable_atmospherics/canister,
)))
//The malf AI action subtype. All malf actions are subtypes of this.
diff --git a/code/modules/atmospherics/Atmospherics.md b/code/modules/atmospherics/Atmospherics.md
new file mode 100644
index 0000000000000..f0ebe8ba0041c
--- /dev/null
+++ b/code/modules/atmospherics/Atmospherics.md
@@ -0,0 +1,528 @@
+# Atmospherics
+## 1. Preamble
+
+This file will be written in the first person in the interest of having a laid back style, as some of the concepts here would be ass to read as technical writing. Understand that this isn't the work of one person, but the combined efforts of several contributors. It is a living document, and one you should strive to keep up to date.
+
+I have ~~stolen~~ adapted this document from the work of duncathan, an off and on maintainer who is responsible for the majority of the quality of the current atmos system. He pushed through several code cleanliness and sanity refactors to the system, and wrote the rundown of gas mixtures you'll find in this document. See the [original](https://gist.github.com/duncathan/77d918748d153b4f31a8f76f6085b91a) for his draft.
+
+Now, the purpose of this bit of documentation.
+
+Over the history of /tg/ there have been several periods where one or no active coders understood how atmospherics works, or even how it was intended to work. We've lost several major pieces of functionality, not because none knew how they worked, but because none knew that they should work, or even that they existed.
+
+Atmospherics tends to be a somewhat cloudy corner of our codebase, unless you know exactly what to look for noticing that something is broken can be a feat in and of itself.
+
+My goal here is to solve that problem once and for all. Not everything will be documented in this file, I won't go line by line. I will however describe how things ought to work, and how some of the more complex stuff is meant to run.
+
+Atmospherics is a very complicated and intimidating system of SS13, and as such very few contributors have ever made changes to it. Even fewer is the number of contributors who have made changes to the more fundamental aspects of atmos, such as Environmental Atmos or gas mixtures. There are several other factors for this, of course. In the case of Environmental, its arcane nature coupled with its extremely important gameplay effects leave it a very undesirable target for even the least sane coder. As for gas mixtures, they were virtually untouchable without extensive reworks of the code. This [paste-bin](https://pastebin.com/bwy4KpBE) is a good example; it lists all the files one would need to make changes in order to add a new type of gas in the old system. As you can imagine, the sheer bulk of work one would need to do to accomplish this essentially invalidated any such attempts. However, my primary goal is to bring atmos to a state where any coder will be able to understand how and why it works, as well as cleanly and relatively easily make changes or additions to the system. While much progress to this end has been achieved, still very few have taken advantage of the new frameworks to try to implement meaningful features or changes. The purpose of this document is to lay out the inner workings of the entire atmos system, such that someone who does not have an intimate understand of the system like myself will be able to contribute to the system nonetheless.
+
+Recognizing this desire, I hope and believe that you who are reading this are willing to learn and contribute.
+
+Thank you.
+
+## 2. Introduction to Atmos
+
+Hello! So glad you could join us.
+
+Atmospherics is the system we use to simulate gases. Might as well get that out of the way. It is made up of several major parts, and a few more minor ones. We'll be covering the air subsystem, gas mixtures, reactions, environmental flow, and pipenets in the document.
+
+If you'd like to understand more about how environmental atmos works after reading the relevant subsection, go to Appendix B. It discusses how to properly visualize the system, and what different behavior looks like.
+
+Now then, into the breach.
+
+## 3. The Air Controller
+
+![Cyclical graph of one atmos tick](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/Cycle.png)
+
+*Figure 3.1: The structure of one air controller tick. Not totally accurate, but it will do*
+
+ The air controller is, at its core, quite simple, yet it is absolutely fundamental to the atmospheric system. The air controller is the clock which triggers all continuous actions within the atmos system, such as vents distributing air or gas moving between tiles. The actions taken by the air controller are quite simple, and will be enumerated here. Much of the substance of the air ticker is due to the game's master controller, whose intricacies I will not delve into for this document. I will however go into more detail about how SSAir in particular works in Chapter 6. In any case, this is a simplified list of the air controller's actions in a single tick:
+1. Rebuild Pipenets
+ - Runs each time SSAir processes, sometimes out of order. It ensures that no pipeline sit unresolved or unbuilt
+ - Processes the `rebuild_queue` list into the `expansion_queue` list, and then builds a full pipeline piecemeal. We do a ton of fenagling here to reduce overrun
+2. Pipenets
+ - Updates the internal gasmixes of attached pipe machinery, and reacts the gases in a pipeline
+ - Calls `process()` on each `/datum/pipenet` in the `networks` list
+3. Machinery
+ - Handles machines that effect atmospherics, think vents, the supermatter, pumps, all that
+ - Calls `process_atmos()` on each `/obj/machinery` (typically `/obj/machinery/atmospherics`) in the `atmos_machinery` list
+ - May remove the machinery from said list if `process_atmos()` returns `PROCESS_KILL`
+4. Active turfs
+ - This is the heart and soul of environmental atmos, see more details below
+ - All you need to know right now is it manages moving gas from tile to tile
+ - Calls `process_cell()` on each `/turf/open` in the `active_turfs` list
+5. Excited groups
+ - Manages excited groups, which are core to working flow simulation
+ - More details to come, they handle differences between gasmixtures when active turfs can't do the job
+ - Increases the `breakdown_cooldown` and `dismantle_cooldown` for each `/datum/excited_group` in the `excited_groups` list
+ - If either cooldown for a given excited group has passed its threshold
+ - Calls `self_breakdown()` or `dismantle()` appropriately on the excited group.
+6. High pressure deltas
+ - Takes the gas movement from Active Turfs and uses it to move objects on said turfs
+ - Calls `high_pressure_movements()` on each `/turf/open` in the `high_pressure_delta` list.
+ - Sets each turf's `pressure_difference` to 0
+7. Hotspots
+ - These are what you might know as fire, at least the effect of it.
+ - They deal with burning things, and color calculations, lots of color calculations
+ - Calls `process()` on each `/obj/effect/hotspot` in the `hotspots` list
+8. Superconductivity
+ - Moves heat through turfs that don't allow gas to pass
+ - Deals with heating up the floor below windows, and some other more painful heat stuff
+ - Calls `super_conduct()` on each `/turf` in the `active_super_conductivity` list
+9. Atoms
+ - Processes things in the world that should know about gas changes, used to account for turfs sleeping, I'll get more into that in a bit
+ - Calls `process_exposure()` on each `/atom` in the `atom_process` list
+
+## 4. Gas Mixtures
+If the air controller is the heart of atmos, then gas mixtures make up its blood. The bulk of all atmos calculations are performed within a given gas mixture datum (an instance of `/datum/gas_mixture`), be it within a turf or within an emergency oxygen tank or within a pipe. In particular, `/datum/gas_mixture/proc/share()` is the cornerstone of atmos simulation, as it and its stack perform all the calculations for equalizing two gas mixtures.
+
+Gas mixtures contain some of the oldest code still in our codebase, and it is remarkable that overall, the logic behind the majority of gas mixture procs has gone unchanged since the days of Exadv1. Despite being in some sense "oldcode", the logic itself is quite robust and based in real world physics. Thankfully, gas mixtures already are quite well documented in terms of their behavior. Their file is well commented and kept up to date. I will, however, elaborate on some of the less obvious operations here. Additionally, I will document the structure of gas lists, and how one should interface with a gas mixture should you choose to use one in other code.
+
+Now don't be scared by the code mind, it's SPOOKY PHYSICS but it's not the devil, we can break it down into component parts to understand it.
+
+```DM
+//transfer of thermal energy (via changed heat capacity) between self and sharer
+ 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
+```
+*Snippet 4.1: excerpt from `/datum/gas_mixture/proc/share()`*
+
+The snippet above is an example of one particularly strange looking calculation. This part of share() is updating the temperature of a gas mixture to account for lost or gained thermal energy as gas moves to/from the mixture, since gases themselves carry heat. To understand this snippet, it is important to understand the difference between heat and temperature. For the most part, the average coder need only concern himself with temperature, as it is a familiar experience for anybody. However, internally in atmos, heat (thermal energy) is the truly important quantity. Heat is defined as temperature multiplied by heat capacity, and is measured in joules. Typically within atmos, we are more concerned with manipulating heat than temperature; however, temperature is tracked rather than heat largely to make interfacing with the system simpler for the average coder. Thus, this snippet modifies heat in terms of temperature - it adds/subtracts three terms, each of which measure heat, to determine the new heat in the gas mixture. This heat is then divided by the mixture's heat capacity in order to determine temperature.
+
+One trick to understanding passages like this is to do some simple dimensional analysis. Look only at the units, and ensure that whenever a variable is assigned that it is being assigned the appropriate unit. The snippet previously discussed can be represented with the following units: `temperature = ((J/K)*K - (J/K)*K + (J/K)*K)/(J/K)`. Simplified, you get `(J-J+J)*K/J` and then simply `J*K/J` and `K`, verifying that temperature is being set to a value in kelvins. This trick has proven invaluable to me when debugging the inner workings of gas mixtures.
+
+### Gases
+
+The true beauty of the gas mixture datum is how it represents the gases it contains. A bit of history: gas mixtures used to represent gas in two ways - there were the four primary gases (oxygen, nitrogen, carbon dioxide, and plasma) which were hardcoded. Each gas mixture had two vars (moles and archived moles, a concept to be explained later) to represent each of these gases. Calculations such as thermal energy made use of predefined constants for these hardcoded gases. The benefit of this was that they were extremely quick - only a single datum var access was needed for each one. In contrast, there were trace gases, for which there were a list of gas datums. The only trace gas available in normal gameplay was nitrous oxide (N2O or sleeping agent), though through adminnery it was possible to create oxygen agent B and volatile fuel, curious gases which will be described later for historical reasons. Trace gases, in contrast to hardcoded gases, were quite modular. To add a new trace gas one needed only to define a new subtype of /datum/gas and add appropriate behavior wherever desired, such as breath code. Unfortunately, of course, trace gases were slooooow. Calculations on trace gases were significantly more costly than hardcoded gases. The problem was obvious - it seemed impossible to have a gas definition which shared the modularity of trace gases without sacrificing too much of the performance of the hardcoded gases.
+
+What then to do? There was no option to port an improvement from another codebase. As far as I am aware, there have been no significant downstream improvements to gas mixtures. The other major upstream codebase, Baystation12, uses a very different atmos system; in particular, their XGM gas mixtures have their own solution to this problem. To summarize XGM, there is a singleton which has associative lists of gas metadata (information such as specific heat, or which overlay to display when the gas is present) which gets accessed whenever such information is needed. To count moles, each gas mixture has an associative list of gas ids mapped to mole counts. There were a couple of problems with this approach: 1. There was no measure of archived moles. While it would be easy to simply add a second associative list, this has non-trivial memory implications as well as a potential increase to total datum var accesses within internal atmos calculations. 2. The singleton used for storing metadata helps with the memory impact that using full datums would have, but does not properly address the cost of datum var accesses, as to access metadata you must still access a datum var on the singleton.
+
+For some time, without a clear solution, we simply stuck to the status quo and left gases non-modular. Eventually, however, there was an idea.
+
+Enter Listmos.
+
+### The Gas List
+The solution we came to was beautifully simple, but founded on some unintuitive principles. While datum var accesses are quite slow, proc var accesses are acceptable. If we use a reference for a given var, this can be exploited by "caching" the reference inside of a proc var. How can we take advantage of this without using a datum, thus nullifying the benefit?
+
+The answer was to use a list. The critical realization was that a gas datum functioned more so as a struct than as a class. There were no procs attached to gas datums; only vars. While DM lacks a true struct with quick lookup times, a list works very well to perform the same function. Thus, the current structure of gas was created, under the name Listmos.
+
+Each gas mixture has an associative list, gases, which maps according to a key to a particular gas. This gas is itself a list (not an associative list, mind) with three elements; these elements correspond to the moles, archived moles, and to another list. This final list is a singleton - only one instance of it exists per gas, and all gas instances of a particular type point to this same list as their third element. The final list contains the metadata for the gas, such as specific heat or the name of the gas. The structure of the metadata list varies according to how many attributes are defined overall for all gases, but it is also non-associative since the structure can never change post-compile, so we save a little bit of performance by avoiding associative lookups.
+
+Each type of gas is defined by defining a new subtype of /datum/gas. These datums do not get instantiated; they merely serve as a convenient and familiar means for a coder unfamiliar with the inner workings of listmos to define a new gas. Additionally, the type paths serve a second use as the keys used to access a particular gas within the gases list. It is easiest to demonstrate the manipulation of gas, including these list accesses, with an example.
+
+### Interfacing with a Gas Mixture
+
+```DM
+var/datum/gas_mixture/air = new
+air.assert_gas(/datum/gas/oxygen)
+air.gases[/datum/gas/oxygen][MOLES] = 100
+world << air.gases[/datum/gas/oxygen][GAS_META][META_GAS_NAME] //outputs "Oxygen"
+world << air.gases.heat_capacity() //outputs 2000 (100 mol * 20 J/K/mol)
+air.gases[/datum/gas/oxygen][MOLES] -= 110
+air.garbage_collect() //oxygen is now removed from the gases list, since it was empty
+```
+*Snippet 4.2: gas mixture usage examples*
+
+Of particular note in this snippet are the two procs assert_gas() and garbage_collect(). These procs are very important while interfacing with gas mixtures. If you are uncertain about whether a given mixture has a particular gas, you must use assert_gas() before any reads or writes from the gas. If you fail to use assert_gas() then there will be runtime errors when you try to access the inner lists. When you remove any number of moles from a given gas, be sure to call garbage_collect(). This proc removes all gases which have mole counts less than or equal to 0. This is a memory and performance enhancement for list accesses achieved by reducing the size of the list, and also saves us from having to do sanity checks for negative moles whenever gas is removed. As a quick reference, here is a list of common procs/vars/list indices which the average coder may wish to use when interfacing with a gas mixture.
+
+##### Gas Mixture Datum
+* *`/datum/gas_mixture/proc/assert_gas()`* - Used before accessing a particular type of gas.
+* *`/datum/gas_mixture/proc/assert_gases()`* - Shorthand for calling assert_gas() multiple times.
+* *`/datum/gas_mixture/proc/garbage_collect()`* - Used after removing any number of moles from a mixture.
+* *`/datum/gas_mixture/proc/return_pressure()`* - Pressure is what should be displayed to players to quantify gas; measured in kilopascals.
+* *`/datum/gas_mixture/var/temperature`* - Measured in kelvins. Useful constants are T0C and T20C for 0 and 20 degrees Celsius respectively, and TCMB,the temperature of space and the lower bound for temperature in atmos.
+* *`/datum/gas_mixture/var/volume`* - Measured in liters.
+
+While we're on the subject, `/datum/gas_mixture` has two subtypes.
+The first is `/datum/gas_mixture/turf`, which exists for literally one purpose. When a turf is empty, we want it to have the same heat capacity as space. This lets us achieve that by overriding `heat_capacity()`
+
+The second is `/datum/gas_mixture/immutable`, which itself has two subtypes.
+The type is built to allow for gasmixtures that serve as infinite sources of "something", which can't be changed or mutated.
+It's used by `/datum/gas_mixture/immutable/space`, which implements some particular things for `heat_capacity()` and some optimizations for gas operations.
+It's also implemented by `/datum/gas_mixture/immutable/planetary`, which is used for planetary turfs, and has some code that makes actually having a gasmix possible.
+
+
+##### Gas List
+* *`gases[path][MOLES]`* - Quantity of a particular gas within a mixture.
+* *`gases[path][GAS_META][META_GAS_NAME]`* - The long name of a gas, ex. "Oxygen" or "Hyper-noblium"
+* *`gases[path][GAS_META][META_GAS_ID]`* - The internal ID of a given gas, ex. "o2" or "nob"
+
+### Reactions
+While defining a new gas on its own is very simple, there is no gas-specific behavior defined within /datum/gas. This behavior gets defined in a few places, notably breath code (to be discussed later) and in reactions. The most important and well known reaction in SS13 is fire - the combustion of plasma. Reactions are used for several things - in particular, it is conventional (though by no means enforced) that to form a gas, a reaction must occur. Creating a new reaction is fairly simple, this is the area of atmos that has received the most attention over the last few years, and the best place to start. Don't be scared of the size of reactions.dm, it's not that complex.
+
+There are two procs needed when defining a new reaction, /datum/gas_reaction/proc/init_reqs() and /datum/gas_reaction/proc/react(). init_reqs() initializes the requirements for the reaction to occur. There is a list, min_requirements, which maps gas paths to required amount of moles. It also maps three specific strings ("TEMP", "MAX_TEMP" and "ENER") to temperature in kelvins and thermal energy in joules. More behavior could easily be added here, but it hasn't yet for performance reasons because no reactions have need of it.
+
+As for react(), it is where all the behavior of the reaction is defined. The proc must return one of NO_REACTION, REACTING, or STOP_REACTIONS. The proc takes one or optionally two arguments. The first, mandatory, argument is a gas mixture on which to perform calculations; this mixture is what is reacting. The second, optional, argument is a turf or pipenet, specifically the thing which contains the gas mixture. You may choose for the reaction to affect the object in some way. Note that it is conventional for constants within reactions to be #define'd at the top of the file and #undef'd at the end.
+
+## 5. Environmental Atmos
+
+This is a rather large subject, we will need to cover gas flow, turf sleeping, superconduction, and much more. Strap in and enjoy the ride!
+
+### A Word On `Share()`
+
+Each pair of turfs will only ever call `share()` on each other once. They use an archived cycle to keep track of
+this ordering
+
+That means turf A calling share on turf B should work the same as turf B calling share on turf A
+
+The key idea of FEA, the core sharing system we use is that neighboring cells should effectively equalize with each other.
+So taken on a line, you'd have two sharing partners, the cells to your left and right. The end goal of the simulation is for all the tiles on the line to have the same mix. But we can't just jump to that. So each "tick" we take our mix and average it with the mixes of the two tiles next to us.
+
+There's an equation for this that's considered standard in heat simulation. (Watch this video: https://www.youtube.com/watch?v=ly4S0oi3Yz8)
+We can't use it because means each pair of turfs needs to talk to each other twice, which is pain expensive. That and I'm pretty sure it would prevent us from yielding
+
+So instead of a complex form of averaging, we portion up tiles. So if you have two neighbors and you have something they don't, you can give them each a third. Have to keep one for ourselves mind, because otherwise we'll run out of gas. They can then act on this portion however they like, and we can likewise act on a portion of them to our liking.
+
+We know how much gas a tile had at the outset because of the archived moles list index. If we take more then we're owed in any shares before all other turfs have had their say, we could end up with negative moles. We expend a lot of effort to avoid this.
+
+The math for this looks like (totaldeltagas)/(neighborcount + 1)
+
+You may notice something like this in `process_cell()`. It's not quite the same though.
+
+Back in the old FEA days, neighbor count was hardcoded to 4 (Likely because this is what cell sharing on an infinite grid would look like). This means that turf A -> turf B is the same as turf B -> turf A, because they're each portioning up the gas in the same way.
+
+But when we moved to LINDA, we started using the length of our atmos_adjacent_turfs list (or an analog).
+We need this so things like multiz can work, and so tiles in a corner share in a way that makes sense.
+
+Because of this, turf A -> turf B was no longer the same as turf B -> turf A, assuming one of those turfs had a different neighbor count, from I DON'T KNOW WALLS?
+
+The fix for this was to use our neighbor count when moving gas from our tile to someone else's, and use the sharer's neighbor count when taking from it.
+
+This makes sense intuitively if you think of it like portioning up a tile, but I've included a rundown to make
+it a bit easier to prove to yourself.
+
+
+Take a look
+
+I have 10
+You have 20
+let's share
+I've got 2 partners
+you've got 3 partners
+so you want to give me 1/4th of your gas
+I want to give you 1/3rd of my gas
+
+the total gas diff between me and you is -10
+since it's negative you get to decide how to portion it
+so the total amount to share is -2.5
+I end up with 12.5
+you end up with 17.5
+
+again
+
+total diff is -5
+to share is 1.25
+I end up with 13.75
+you end up with 16.25
+
+again
+
+total diff is -2.5
+to share is 0.3125
+I end up with 14.0625
+you end up with 15.9375
+
+
+
+We need to do this because if the portions get mixed up, our archived gas list ends up lying about how much of each gas type we have available to share.
+This can lead to negative moles, which the system is not prepared for.
+
+This is also why we queue space's sucking till the end of a tile's `process_cell()` btw, by that point we can ensure that no other tile will need to check for our mix, so we can freely violate our portioning.
+
+
+### Active Turfs
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/FlowVisuals.png)
+
+*Figure 5.1: A visual of the algorithm `process_cell()` implements, ignoring our optimizations*
+
+Active turfs are the backbone of how gas moves from tile to tile. While most of `process_cell()` should be easy enough to understand, I am going to go into some detail about archiving, since I think it's a common source of hiccups.
+
+* *`archived_cycle`* this var stores the last cycle of the atmos loop that the turf processed on. The key point to notice here is that when processing a turf, we don't share with all its neighbors, we only talk to those who haven't processed yet. This is because the remainder of `process_cell()` and especially `share()` are like addition. We can add in any order we like, and we only need to add once. This is what archived gases are for by the way, they store the state of the relevant tile before any processing occurs.
+
+Alright then, with that out of the way, what is an active turf.
+
+This is actually the main success of LINDA, the math for gas movement is r4407 goon code or older, but that implementation (FEA) had a glaring issue. All turfs processed, or rather, all `/simulated` turfs processed. There was a separate type for `/unsimulated` turfs, but that was mostly used for things like centcom or space. Aside from that all the turfs that could in theory have gas on them needed to process each tick. `process_cell()` didn't quite look how it does now mind, but this was still a horrible state of affairs.
+
+The major difference between then and now is our turfs will stop processing. They sit idle most of the round, wake up when something changes around them, process until no major changes are happening, and then go to sleep.
+
+Active turfs also poke all the listening objects sitting on them, and start to process them so they can react to heat or gas changes. We do this so objects don't need to process when nothing has changed, but they also can operate through a turf sleeping. In essence this is like waking up things that ought to be listening to us.
+
+If we just used active turfs sleeping would be easy as pie, we could do it turf by turf. But we don't.
+
+### Excited Groups
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/Unsettled.png)
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/Settled.png)
+
+*Figure 5.2.1-5.2.2: Settled VS Unsettled gases, this is what excited groups do*
+
+I didn't mention this above, but active turf processing, or really `share()`, has a fatal flaw. The amount of gas moved per tick goes down exponentially the further away a turf is from the source of changes, or diffs.
+
+With only active turfs breaches would never settle, and as soon as a tile becomes active it would never rest again. (This is one of the reasons I wrote this document by the way, excited groups nearly totally broke around about 2016, and none at the time noticed because the code was so twisted none knew how it ought to work, so it persisted for 4 years past that)
+
+So active turfs are bad at evening out diffs. What can we do to solve this?
+
+Enter the excited group. We hold a list of all the turfs that have talked to each other, then we keep track of how active those turfs are. When they start to wind down, we spread all the gas out evenly between them, and the group starts to spread again. They tend to fill the space given to them, so be careful with open plan stations.
+
+This is `self_breakdown()`, our equalization step. It cuts down on churn, and keeps things flowing smoothly.
+
+I've been talking kinda abstractly about turfs sleeping. That's because turfs on their own don't stop waiting to process once they have an excited group. Groups have secondary roles as the grim reaper of active turfs. When a group is totally inactive, and nothing whatsoever is going on, it will `dismantle()`, putting all of the turfs inside it to sleep, and killing itself.
+
+### A brief romp to talk about excited groups and LAST_SHARE_CHECK
+
+Excited groups can tell the amount of diff being shared by hooking into a value `share()` sets on gasmixes, the absolute amount of gas shared by each tile. The issue is this isn't pressure, it's molar count. So heat being shared in a sealed room causes excited groups to break down, then reform from sources. This isn't a major issue due to how breakdown evens things out, but it's worth knowing.
+
+### Back to the main thread
+
+Now this would all be fine, but as I'm sure you've noticed, there's a crouching pile of lag hiding here. What happens if the excited group has turfs with a fire on them over in cargo, but the flow of gas started in medical? There's no point processing the majority of the tiles, but we still want to keep the group alive for equalization.
+
+### Turfs can have a little nap
+
+Originally LINDA only had the above 2 constructions, but we ran into a problem when making planetary turfs. The old implementation was mutable, but shared with a copy of its initial mix each tick. This lead to problems. In essence, the groups never stopped spreading so long as a source of diffs existed. This is because the job of excited groups is to move the diffs from the source, to the edges of the group. But we put these mixes on huge open planets. Doesn't really work out so well.
+
+To combat this, a timer was added to each turf. It reset when a significant share was made, but otherwise if enough time passed the turf was forcibly removed from the active_turfs list. Unfortunately for us, this had unintended side effects.
+
+When a turf is removed from active, the excited group is broken down, as it's assumed that the proc will only be called when the landscape of the map itself has changed. You begin to see the issue. With large enough space, excited groups broke, totally. Constant rebuilds into dismantles, cycling forever.
+
+Now this issue here is we'd like to keep this napping, but we don't want to `garbage_collect()` the excited group constantly.
+
+So, a new proc was added, `sleep_active_turf()`. It removes the active turf from processing, but doesn't `garbage_collect()` the group.
+
+You'd think this would cause issues with maintaining the shape of an excited group, however this isn't actually a priority, since `garbage_collect()` and the subsequent rebuild in `process_cell()` causes turfs that are actually active to reform, just as it always has. This has benefits, as it lessens the tendency of one group to cover a huge space, equalize all at once, and fuck with things.
+
+There's another issue here however, how do we deal with things that react to heat? A firelock shouldn't just open because the turf that the alarm is on went to sleep. Thus, atom_process, as I mentioned before, a list of atoms with requirements and things to do. It processes them until their requirements are not met, then it removes them from its list them.
+
+There's one more major aspect of environmental atmos to cover, and while it's not the most misunderstood, it is the code with the worst set dressing.
+
+### Superconduction, or why var names really matter
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/Superconduction.png)
+
+*Figure 5.3: The death of a pug, and a visual description of what superconduction does*
+
+Superconduction, an odd name really, it doesn't really describe much of anything aside from something to do with heat. It gets worse, trust me.
+
+Superconduction is the system that makes heat move through solid objects, so in theory walls, windows, airlocks, so on. This is another one that just broke one day, and none noticed cause none knew what it was meant to do.
+
+There's another issue with it, the var names don't mean what you think, and it is very old code, so it's hard to grasp. You can do it, you've made it this far.
+
+So then, what does superconduction do, and what do all these damn vars mean.
+
+### What does superconduction do?
+
+As I mentioned above, superconduction shares heat where heat can't normally travel. It does this by heating up the turf the heat is in, not the gasmix, the turf itself. This temperature is then shared with adjacent turfs, based on `thermal_conductivity`, a value between 0 and 1 that slows the heat share. Turfs also have a `heat_capacity`, which is how hard it is to heat, along with providing a threshold for the lowest temperature that can melt the turf.
+
+There's one more, and it's a doozy. `atmos_superconductivity` is a set of directions that we cannot share with. I know. It's set in can_atmos_pass(), a rather heady set of procs that build `atmos_adjacent_turfs`, and also modify `atmos_superconductivity`.
+
+So then, a review.
+
+* *`thermal_conductivity`* Ranges from 0 to 1, effects how easy it is for a turf to receive heat
+* *`heat_capacity`* Large numbers mean it's harder to heat, but holds more heat. You get it. Also used for turf melting
+* *`atmos_supeconductivity`* Bitfield of directions we **can't** share in, this is often set by firelocks and such
+
+One more thing, turfs will superconduct until they either run out of energy, or temperature. This is a stable system because turfs "conduct" with space, which is why floods of heat will equalize to about 690k over time.
+
+## 6. Processing time, Dynamic scaling, and what slows us down the most
+
+This will require/impart a light understanding of the master controller, I will go over what makes the atmos subsystem slow, what can be done, and what it effects.
+
+First, some new vocab.
+
+* *`wait`* Subsystem var, it is the amount of time to "wait" between each fire, or process. Measured in deciseconds.
+* *`MC_TICK_CHECK`* A define that checks to see if the subsystem has taken more then it's allotted time. In the case of SSAir we use it to allow for dynamic scaling
+
+The MC entry for SSAir is very helpful for debugging, and it is good to understand before I talk about cost.
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/SSAirAtRest.png)
+
+*Figure 6.1: SSAir sitting doing little to nothing turf wise, only processing pipenets and atmos machines*
+
+As you can see here, SSAir is a bit of a jumble, don't worry, it'll make sense in a second. The first line is in this order: cost, tick_usage, tick_overrun, ticks.
+All of these are averages by the way.
+
+* *`cost`* Cost is the raw time spent running the subsystem in milliseconds
+* *`tick_usage`* The percent of each byond tick the last fire() took. Tends to be twice cost, good for comparing with overrun.
+* *`tick_overrun`* A percentage of how far past our allotted time we ran. This is what causes Time Dilation, it's bad.
+* *`ticks`* The amount of subsystem fires it takes to run through all the subprocesses once.
+
+The second line is the cost each subprocess contributed per full cycle, this is a rolling average. It'll give you a good feel for what is misbehaving. (The only exception to this is pipenet rebuilds, the last entry. Because of its nature as something that can happen at any time, it doesn't have a rolling average, instead it just displays the time it used last process)
+
+The third line is the amount of "whatever" in each subprocess. Handy for noticing dupe bugs and crying at active turf cost. Speaking of, the last entry is the active turfs per overall cost. Not a great metric, but larger is better.
+
+Now then, what the hell is going on in that image.
+
+### Dynamic scaling
+
+SSAir has a wait of 5 deciseconds, or 500ms. This means it wants to fire roughly twice a second. You'll see in a moment why this hardly ever happens.
+
+See that image from before? Notice how the cost of SSAir at rest is about 40ms? yeahhhhh.
+
+The atmos subsystem was used as a testing ground for the robustness of the master-controller. It used to have a wait of 2 seconds, but that was lowered to 0.5 as it was thought that the system could handle it. It can! But this can have annoying side effects. As you know, we edge right up against 1/10th of the wait when sitting at rest, and if we start to make diffs...
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/GasTypes.png)
+
+*Figure 6.2: SSAir when a high amount of active turfs are operating, with a large selection of gastypes for each tile*
+
+As you can see, active turfs can be really slow. Oh but it gets so much worse.
+
+Active turf cost is mostly held up in `react()`, `share()` and `compare()`. `react()` and `share()` scale directly with the amount of gas in the air. `compare()` does better, but none of them do that great.
+
+For this reason, and because excited groups spread gas out so much, we want to keep the variation of gastypes in the air relatively low.
+
+react() is called for every active turf, and every pipenet. On each react call for reasons I don't want to go into right now, we need to iterate over every reaction and do a preliminary test. Therefor, the more datum reactions we have, the slower those two processes go.
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/LargeExcitedGroup.png)
+
+*Figure 6.3: The effects of a large excited group on overtime*
+
+It's hard to tell here because I took the picture right as it happen, but when large excited groups go through `self_breakdown()` they can overtime by a significant deal. This is because `self_breakdown()` can't be delayed, or done in two parts. We can't let an older gasmix that's already been collected have say 1000 mols of plasma added, then go into breakdown and delete it all. Thus, the overtime cost. This was with a excited group 900 tiles large though, so it isn't nearly ever this bad. It also scales with the amount of gases in the same way that `share()` does.
+
+On the whole excited groups are the only major source of overrun, consider this a treatise on why that 900ms cost number next to atmos isn't making the server die. It's really that excited group mass equalizing constantly.
+
+## 7. What we want atmos code to be
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/DiffsSettling.png)
+
+*Figure 7.1: Diffs settling out as they should, around their sources*
+
+Our goal is not to simulate real life atmospherics. It is instead to put on a show of doing so. To sleep wherever we can, and fake it as hard as possible.
+
+This is matters the most with environmental stuff, but it's everywhere you look.
+
+The goal of active turfs, excited groups, and sleeping is to isolate the processing that needs to happen, and move diffs from their source to a consumer as much as we can. We don't simulate every tile, and most of the changes to LINDA have been directed at simulating as little as we can get away with.
+
+Hell, space being cold is a hack we use to make gameplay interesting. There's a lot more stuff like this, because this isn't a simulator, it's a theater production.
+
+Performance and gameplay are much more important then realism. In all your work on the subsystem, keep this in mind, and you'll build fast and quality code.
+
+## 8. Pipelines and pipeline machinery
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/PipelineVisuals.png)
+
+*Figure 8.1: The structure of pipelines shown in color, components are a mix*
+
+`/datum/pipeline` handles the simulation of piping and such. It has 2 main actions, one of which you should know very well. The other is slightly more of a hurdle.
+
+To understand pipelines you'll first need to understand how we process things like pumps or vents, atmos components that is.
+To start with, a set of pipes is treated as one gas mixture, however several different components draw from this mix. Think pumps, heaters, mixers, vents, etc.
+
+Since these components change the mix itself, we can't just let them all act on the mix at once, because that would cause concerns around the order in which things process, and so on.
+We don't want canisters that blow up half the time, and the other half of the time don't. Better then to give each component its own gas mix that it alone can act on, that will be shared with the pipeline as a whole. Pipelines do something similar to active turfs by the way, they won't re-equalize their mix if nothing about the state of things has changed.
+
+We do this sharing based on the proportion of volume between all the components. So if you want a component to consume more gas, give it a higher volume.
+
+On that note, I'd like to be clear about something. In lines of connected pipes, each pipe doesn't have its own gasmix, they instead share mixes, as the pipes themselves won't have any effect on the state of the mix.
+
+Oh, and pipelines react the gas mixture inside them, thought I should mention that.
+
+### A short note on rebuilding
+
+Everything that needs a pipeline should have it before it's allowed to do any processing. This is to prevent runtimes and shitcode related things.
+
+The act of rebuilding a pipeline is quite expensive however, since it involves iterating over all the connected pipes/components.
+That's why we go to such great pains to make sure no large amount of work is allowed to happen at once. It's in an attempt to avoid the excited group settling type of lag I discussed above. It's ok for atmos to lock up for a short period if the system isn't killing the game as a whole.
+
+
+All the other behavior of pipes and pipe components are handled by atmos machinery. I'll give a brief rundown of how they're classified, but the details of each machine are left as an exercise to the reader.
+
+
+#### Pipes
+
+The raw pipes. They have some amount of nuance, mostly around layers, but it's not too tricky to deal with.
+
+##### Heat Exchange
+
+The HE pipes, used to transfer heat from the pipe to the turf it's sitting on. These work directly with the pipeline's mix, which is ehhhh? Might need some touching up, perhaps making them subnets that do one heat transfer. Not too big a deal in any case, since they're the only thing that acts directly on a pipeline mix. They have some other behavior, like glowing when hot, but it's minor.
+
+#### Components
+
+These are the components I described above, they have some sort of internal gas mix that they act on in some manner.
+
+The following classifications are very simple, but I'll run them over anyhow
+
+##### Unary
+
+Unary devices can only interact with one pipeline, aside from some exceptions, like the heat exchanger. The type path comes from the amount of pipelines a device expects gas-mixtures from. I'm sure you can see where this is going.
+
+##### Binary
+
+Binary devices connect to 2 pipelines.
+
+##### Trinary
+
+Trinary devices connect to 3 p- Listen you get it already.
+
+##### Fusion
+
+Finally something more interesting. Unfortunately I'm not familiar with the inner workings of this machine, but this folder deals with hypertorus code.
+
+#### Other
+
+This is for the oddballs, the one offs, the half useless things. Things that are tied to the module, but that we don't have a better spot for. Think meters, stuff like that.
+
+#### Portable
+
+These are the atmos machines you can move around. They interface with connectors to talk to pipelines, and can contain tanks. Not a whole lot more to discuss here.
+
+## 9. A word on processing
+
+You may have noticed that a large portion of the optimizations we do are focused around not checking to see if we need to do work.
+
+This is essentially what active turfs are built around, and it's a somewhat unfinished project. There's still quite a few things in atmos, mostly machinery, that check each fire to see if they should be doing work. There's a general pattern to solving this sort of thing by the way, centralize the ways a bit of outside code can interact with a "thing", and then when the outside code does something that might warrant processing, start processing.
+
+This attitude needs to be applied to a few large targets, and you may see it crop up when reading through the code. Keep this in mind, and make sure to respect the rules that describe how to work with the object, or things will go to shit.
+
+## Appendix A - Glossary
+
+* *LINDA* - Our environmental gas system, created by Aranclanos, Beautiful in Spanish
+* *Naps* - A healthy pastime
+* *Gas mixtures* - The datums that store gas information, key to listmos and our underlying method of handling well gas
+* *Diffs* - The differences between gasmixes. We want to get rid of these over time, and clump them up with their sources so we don't need to process too many turfs
+* *FEA* - Finite Element Analysis, the underlying system our atmos is built on top of. Ugly in Spanish
+* *Pipelines* - The datum that represents and handles the gasmixtures of a set of pipes and their components
+* *Components* - Atmos machines that act on pipelines, modifying their mix
+* *Active Turfs* - An optimization of FEA implemented in LINDA that causes processing to only occur when differences are equalizing
+* *Excited Groups* - Evens out groups of active turfs to compensate for the way `share()` works
+* *Carbon dioxide* - What the fuck is this?]
+* *MC* - The master controller, makes sure all subsystems get the time they need to process, prevents lockups from one subsystem having a lot of work
+
+## Appendix B - How to test environmental atmos
+If you really want to get a feeling for how flow works you'll need to load up the game and make some diffs. What follows is a short description of how to set up testing.
+
+To start with, you should enable the `TESTING` define in compile_options.dm, this toggles `VISUALIZE_ACTIVE_TURFS` and `TRACK_MAX_SHARE`. These two debug methods are very helpful for understanding flow, but they aren't cheap, so we make them a compile time option. Active turfs will show up as green, don't worry about the second define, it's coming right up.
+
+Past that you'll want to turn on excited group highlighting, to do this open the atmos control panel in the debug tab and toggle both personal view and display all. Display all makes turfs display their group and personal view shows/hides the groups from you, it's faster to toggle this, and this way you don't piss off the other debuggers on live.
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/AtmosControlPanel.png)
+
+*Figure B.1: The atmospherics control panel*
+
+To go into more detail about the control panel, it is split into two parts. At the top there's a readout of some relevant stats, the amount of active turfs, how many times the subsystem has fired, etc. You can get the same information from the SSAir MC entry, but it's a bit harder to read. I detail this in the section on performance in environmental atmos. There's a button that turns the subsystem on/off in the top left, it's handy for debugging and seeing how things work step by step. Use it if you need to slow things down.
+
+The rest of the panel is where things get more interesting, it's a readout of excited groups, sorted by area name. Most of it ought to be obvious, this is where `TRACK_MAX_SHARE` comes into effect. If it's defined, excited groups will have an extra entry which displays the largest molar diff in the group. This is useful for diagnosing group breakdown issues, and getting a feel for when a group will next breakdown. You can also toggle the visibility of each individual group here, and teleport to the group by clicking on the area name.
+
+### What to look for
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/StartingOut.png)
+
+An excited group can contain 2 things, sources of diffs, and dead tiles.
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/MovingForward.png)
+
+Of course, if left unchecked active turfs will spread further and further out, slowly lowering the amount of dead tiles.
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/SleepWorking.png)
+
+Excited group breakdown causes them to recede and wrap around the things causing them
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/CleanupTroubles.png)
+
+Cleanup causes a major recession due to turfs becoming suddenly no longer having an excited group
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/StrangeGrowth.png)
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/OddGrowth%2BMonkey.png)
+
+Due to how process_cell() works, active turfs will spread strangely when low on diffs
+
+![](https://raw.githubusercontent.com/LemonInTheDark/documentation-assets/atmos-pics/atmos/Flickering.png)
+
+They will also occasionally nap, then immediately wake back up. This is either because of a discrepancy between `compare()` and `LAST_SHARE_CHECK`, or just the result of sleeping being a thing.
diff --git a/code/modules/atmospherics/auxgm/gas_types.dm b/code/modules/atmospherics/auxgm/gas_types.dm
deleted file mode 100644
index a5e7c8ec7a73a..0000000000000
--- a/code/modules/atmospherics/auxgm/gas_types.dm
+++ /dev/null
@@ -1,128 +0,0 @@
-/datum/gas/oxygen
- id = GAS_O2
- specific_heat = 20
- name = "Oxygen"
- oxidation_temperature = T0C - 100 // it checks max of this and fire temperature, so rarely will things spontaneously combust
-
-/datum/gas/nitrogen
- id = GAS_N2
- specific_heat = 20
- breath_alert_info = list(
- not_enough_alert = list(
- alert_category = "not_enough_nitro",
- alert_type = /atom/movable/screen/alert/not_enough_nitro
- ),
- too_much_alert = list(
- alert_category = "too_much_nitro",
- alert_type = /atom/movable/screen/alert/too_much_nitro
- )
- )
- name = "Nitrogen"
-
-/datum/gas/carbon_dioxide //what the fuck is this?
- id = GAS_CO2
- specific_heat = 30
- name = "Carbon Dioxide"
- breath_results = GAS_O2
- breath_alert_info = list(
- not_enough_alert = list(
- alert_category = "not_enough_co2",
- alert_type = /atom/movable/screen/alert/not_enough_co2
- ),
- too_much_alert = list(
- alert_category = "too_much_co2",
- alert_type = /atom/movable/screen/alert/too_much_co2
- )
- )
- fusion_power = 3
- enthalpy = -393500
-
-/datum/gas/plasma
- id = GAS_PLASMA
- specific_heat = 200
- name = "Plasma"
- gas_overlay = "plasma"
- moles_visible = MOLES_GAS_VISIBLE
- flags = GAS_FLAG_DANGEROUS
- // no fire info cause it has its own bespoke reaction for trit generation reasons
- enthalpy = FIRE_PLASMA_ENERGY_RELEASED // 3000000, 3 megajoules, 3000 kj
-
-/datum/gas/water_vapor
- id = GAS_H2O
- specific_heat = 40
- name = "Water Vapor"
- gas_overlay = "water_vapor"
- moles_visible = MOLES_GAS_VISIBLE
- fusion_power = 8
- breath_reagent = /datum/reagent/water
- enthalpy = -241800 // FIRE_HYDROGEN_ENERGY_RELEASED is actually what this was supposed to be
-
-/datum/gas/hypernoblium
- id = GAS_HYPERNOB
- specific_heat = 2000
- name = "Hyper-noblium"
- gas_overlay = "freon"
- moles_visible = MOLES_GAS_VISIBLE
-
-/datum/gas/nitrous_oxide
- id = GAS_NITROUS
- specific_heat = 40
- name = "Nitrous Oxide"
- gas_overlay = "nitrous_oxide"
- moles_visible = MOLES_GAS_VISIBLE * 2
- flags = GAS_FLAG_DANGEROUS
- fire_products = list(GAS_N2 = 1)
- oxidation_rate = 0.5
- oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST + 100
- enthalpy = 81600
-
-/datum/gas/nitryl
- id = GAS_NITRYL
- specific_heat = 20
- name = "Nitryl"
- gas_overlay = "nitryl"
- moles_visible = MOLES_GAS_VISIBLE
- flags = GAS_FLAG_DANGEROUS
- fusion_power = 15
- fire_products = list(GAS_N2 = 0.5)
- oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
- enthalpy = 33200
-
-/datum/gas/tritium
- id = GAS_TRITIUM
- specific_heat = 10
- name = "Tritium"
- gas_overlay = "tritium"
- moles_visible = MOLES_GAS_VISIBLE
- flags = GAS_FLAG_DANGEROUS
- fusion_power = 1
- /*
- these are for when we add hydrogen, trit gets to keep its hardcoded fire for legacy reasons
- fire_provides = list(GAS_H2O = 2)
- fire_burn_rate = 2
- enthalpy = FIRE_HYDROGEN_ENERGY_RELEASED
- fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
- */
-
-/datum/gas/bz
- id = GAS_BZ
- specific_heat = 20
- name = "BZ"
- flags = GAS_FLAG_DANGEROUS
- fusion_power = 8
- enthalpy = FIRE_CARBON_ENERGY_RELEASED // it is a mystery
-
-/datum/gas/stimulum
- id = GAS_STIMULUM
- specific_heat = 5
- name = "Stimulum"
- fusion_power = 7
-
-/datum/gas/pluoxium
- id = GAS_PLUOXIUM
- specific_heat = 80
- name = "Pluoxium"
- fusion_power = 10
- oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST * 1000 // it is VERY stable
- oxidation_rate = 8
- enthalpy = -50000 // but it reduces the heat output a bit
diff --git a/code/modules/atmospherics/environmental/LINDA_fire.dm b/code/modules/atmospherics/environmental/LINDA_fire.dm
index 8dd811cc64e8f..ba58e4a7c70c0 100644
--- a/code/modules/atmospherics/environmental/LINDA_fire.dm
+++ b/code/modules/atmospherics/environmental/LINDA_fire.dm
@@ -8,26 +8,47 @@
/turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
return
+/**
+ * Handles the creation of hotspots and initial activation of turfs.
+ * Setting the conditions for the reaction to actually happen for gasmixtures
+ * is handled by the hotspot itself, specifically perform_exposure().
+ */
/turf/open/hotspot_expose(exposed_temperature, exposed_volume, soh)
- if(!air)
+ //If the air doesn't exist we just return false
+ var/list/air_gases = air?.gases
+ if(!air_gases)
return
- if (air.get_oxidation_power(exposed_temperature) < 0.5)
+ . = air_gases[/datum/gas/oxygen]
+ var/oxy = . ? .[MOLES] : 0
+ if (oxy < 0.5)
return
- var/has_fuel = air.get_moles(GAS_PLASMA) > 0.5 || air.get_moles(GAS_TRITIUM) > 0.5 || air.get_fuel_amount(exposed_temperature) > 0.5
+ . = air_gases[/datum/gas/plasma]
+ var/tox = . ? .[MOLES] : 0
+ . = air_gases[/datum/gas/tritium]
+ var/trit = . ? .[MOLES] : 0
if(active_hotspot)
if(soh)
- if(has_fuel)
+ if(tox > 0.5 || trit > 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
- if((exposed_temperature > PLASMA_MINIMUM_BURN_TEMPERATURE) && has_fuel)
+ if((exposed_temperature > PLASMA_MINIMUM_BURN_TEMPERATURE) && (tox > 0.5 || trit > 0.5 ))
+
active_hotspot = new /obj/effect/hotspot(src, exposed_volume*25, exposed_temperature)
-//This is the icon for fire on turfs, also helps for nurturing small fires until they are full tile
+ active_hotspot.just_spawned = (current_cycle < SSair.times_fired)
+ //remove just_spawned protection if no longer processing this cell
+ SSair.add_to_active(src)
+
+
+/**
+ * Hotspot objects interfaces with the temperature of turf gasmixtures while also providing visual effects.
+ * One important thing to note about hotspots are that they can roughly be divided into two categories based on the bypassing variable.
+ */
/obj/effect/hotspot
anchored = TRUE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
@@ -37,15 +58,22 @@
blend_mode = BLEND_ADD
light_system = MOVABLE_LIGHT
light_range = LIGHT_RANGE_FIRE
- // increase power for more bloom
- light_power = 4
+ light_power = 1
light_color = LIGHT_COLOR_FIRE
+ /**
+ * Volume is the representation of how big and healthy a fire is.
+ * Hotspot volume will be divided by turf volume to get the ratio for temperature setting on non bypassing mode.
+ * Also some visual stuffs for fainter fires.
+ */
var/volume = 125
+ /// Temperature handles the initial ignition and the colouring.
var/temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
+ /// Whether the hotspot is new or not. Used for bypass logic.
+ var/just_spawned = TRUE
+ /// Whether the hotspot becomes passive and follows the gasmix temp instead of changing it.
var/bypassing = FALSE
var/visual_update_tick = 0
- var/first_cycle = TRUE
CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/hotspot)
@@ -59,12 +87,21 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/hotspot)
temperature = starting_temperature
perform_exposure()
setDir(pick(GLOB.cardinals))
- air_update_turf()
- var/static/list/loc_connections = list(
- COMSIG_ATOM_ENTERED = PROC_REF(on_entered),
- )
- AddElement(/datum/element/connect_loc, loc_connections)
-
+ air_update_turf(FALSE, FALSE)
+
+/**
+ * Perform interactions between the hotspot and the gasmixture.
+ *
+ * For the first tick, hotspots will take a sample of the air in the turf,
+ * set the temperature equal to a certain amount, and then reacts it.
+ * In some implementations the ratio comes out to around 1, so all of the air in the turf.
+ *
+ * Afterwards if the reaction is big enough it mostly just tags along the fire,
+ * copying the temperature and handling the colouring.
+ * If the reaction is too small it will perform like the first tick.
+ *
+ * Also calls fire_act() which handles burning.
+ */
/obj/effect/hotspot/proc/perform_exposure()
var/turf/open/location = loc
if(!istype(location) || !(location.air))
@@ -72,28 +109,30 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/hotspot)
location.active_hotspot = src
- bypassing = !first_cycle && volume > CELL_VOLUME*0.95 || location.air.return_temperature() > FUSION_TEMPERATURE_THRESHOLD
- if(first_cycle)
- first_cycle = FALSE
+ bypassing = !just_spawned && (volume > CELL_VOLUME*0.95)
+ //Passive mode
if(bypassing)
volume = location.air.reaction_results["fire"]*FIRE_GROWTH_RATE
- temperature = location.air.return_temperature()
+ temperature = location.air.temperature
+ //Active mode
else
- var/datum/gas_mixture/affected = location.air.remove_ratio(volume/location.air.return_volume())
+ var/datum/gas_mixture/affected = location.air.remove_ratio(volume/location.air.volume)
if(affected) //in case volume is 0
- affected.set_temperature(temperature)
+ affected.temperature = temperature
affected.react(src)
- temperature = affected.return_temperature()
+ temperature = affected.temperature
volume = affected.reaction_results["fire"]*FIRE_GROWTH_RATE
location.assume_air(affected)
+ // Handles the burning of atoms.
for(var/A in location)
var/atom/AT = A
- if(!QDELETED(AT) && AT != src) // It's possible that the item is deleted in temperature_expose
+ if(!QDELETED(AT) && AT != src)
AT.fire_act(temperature, volume)
return
+/// Mathematics to be used for color calculation.
/obj/effect/hotspot/proc/gauss_lerp(x, x1, x2)
var/b = (x1 + x2) * 0.5
var/c = (x2 - x1) / 6
@@ -115,22 +154,18 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/hotspot)
heat_b = LERP(heat_b,255,normal_amt)
heat_a -= gauss_lerp(temperature, -5000, 5000) * 128
greyscale_fire -= normal_amt
- light_power = 4
if(temperature > 40000) //Past this temperature the fire will gradually turn a bright purple
var/purple_amt = temperature < LERP(40000,200000,0.5) ? gauss_lerp(temperature, 40000, 200000) : 1
heat_r = LERP(heat_r,255,purple_amt)
- light_power = 5
if(temperature > 200000 && temperature < 500000) //Somewhere at this temperature nitryl happens.
var/sparkle_amt = gauss_lerp(temperature, 200000, 500000)
var/mutable_appearance/sparkle_overlay = mutable_appearance('icons/effects/effects.dmi', "shieldsparkles")
sparkle_overlay.blend_mode = BLEND_ADD
sparkle_overlay.alpha = sparkle_amt * 255
- light_power = 6
add_overlay(sparkle_overlay)
if(temperature > 400000 && temperature < 1500000) //Lightning because very anime.
var/mutable_appearance/lightning_overlay = mutable_appearance(icon, "overcharged")
lightning_overlay.blend_mode = BLEND_ADD
- light_power = 6
add_overlay(lightning_overlay)
if(temperature > 4500000) //This is where noblium happens. Some fusion-y effects.
var/fusion_amt = temperature < LERP(4500000,12000000,0.5) ? gauss_lerp(temperature, 4500000, 12000000) : 1
@@ -146,7 +181,6 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/hotspot)
heat_b = LERP(heat_b,150,fusion_amt)
add_overlay(fusion_overlay)
add_overlay(rainbow_overlay)
- light_power = 8
set_light_color(rgb(LERP(250, heat_r, greyscale_fire), LERP(160, heat_g, greyscale_fire), LERP(25, heat_b, greyscale_fire)))
@@ -157,19 +191,34 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/hotspot)
color = list(LERP(0.3, 1, 1-greyscale_fire) * heat_r,0.3 * heat_g * greyscale_fire,0.3 * heat_b * greyscale_fire, 0.59 * heat_r * greyscale_fire,LERP(0.59, 1, 1-greyscale_fire) * heat_g,0.59 * heat_b * greyscale_fire, 0.11 * heat_r * greyscale_fire,0.11 * heat_g * greyscale_fire,LERP(0.11, 1, 1-greyscale_fire) * heat_b, 0,0,0)
alpha = heat_a
-#define INSUFFICIENT(path) (location.air.get_moles(path) < 0.5)
+#define INSUFFICIENT(path) (!location.air.gases[path] || location.air.gases[path][MOLES] < 0.5)
+
+/**
+ * Regular process proc for hotspots governed by the controller.
+ * Handles the calling of perform_exposure() which handles the bulk of temperature processing.
+ * Burning or fire_act() are also called by perform_exposure().
+ * Also handles the dying and qdeletion of the hotspot and hotspot creations on adjacent cardinal turfs.
+ * And some visual stuffs too! Colors and fainter icons for specific conditions.
+ */
/obj/effect/hotspot/process()
+ if(just_spawned)
+ just_spawned = FALSE
+ return
+
var/turf/open/location = loc
if(!istype(location))
qdel(src)
return
- location.eg_reset_cooldowns()
+ if(location.excited_group)
+ location.excited_group.reset_cooldowns()
if((temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) || (volume <= 1))
qdel(src)
return
- if(!location.air || location.air.get_oxidation_power() < 0.5 || (INSUFFICIENT(GAS_PLASMA) && INSUFFICIENT(GAS_TRITIUM) && location.air.get_fuel_amount() < 0.5))
+
+ //Not enough / nothing to burn
+ if(!location.air || (INSUFFICIENT(/datum/gas/plasma) && INSUFFICIENT(/datum/gas/tritium)) || INSUFFICIENT(/datum/gas/oxygen))
qdel(src)
return
@@ -179,9 +228,9 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/hotspot)
icon_state = "3"
location.burn_tile()
- //Possible spread due to radiated heat
- if(location.air.return_temperature() > FIRE_MINIMUM_TEMPERATURE_TO_SPREAD)
- var/radiated_temperature = location.air.return_temperature()*FIRE_SPREAD_RADIOSITY_SCALE
+ //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/t in location.atmos_adjacent_turfs)
var/turf/open/T = t
if(!T.active_hotspot)
@@ -196,11 +245,6 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/hotspot)
if((visual_update_tick++ % 7) == 0)
update_color()
- if(temperature > location.max_fire_temperature_sustained)
- location.max_fire_temperature_sustained = temperature
-
- if(location.heat_capacity && temperature > location.heat_capacity)
- location.to_be_destroyed = TRUE
return TRUE
/obj/effect/hotspot/Destroy()
@@ -208,27 +252,10 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/hotspot)
var/turf/open/T = loc
if(istype(T) && T.active_hotspot == src)
T.active_hotspot = null
- DestroyTurf()
return ..()
-/obj/effect/hotspot/proc/DestroyTurf()
- if(isturf(loc))
- var/turf/T = loc
- if(T.to_be_destroyed && !T.changing_turf)
- var/chance_of_deletion
- if (T.heat_capacity) //beware of division by zero
- chance_of_deletion = T.max_fire_temperature_sustained / T.heat_capacity * 8 //there is no problem with prob(23456), min() was redundant --rastaf0
- else
- chance_of_deletion = 100
- if(prob(chance_of_deletion))
- T.Melt()
- else
- T.to_be_destroyed = FALSE
- T.max_fire_temperature_sustained = 0
-
/obj/effect/hotspot/proc/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
SIGNAL_HANDLER
-
if(isliving(arrived))
var/mob/living/immolated = arrived
immolated.fire_act(temperature, volume)
diff --git a/code/modules/atmospherics/environmental/LINDA_system.dm b/code/modules/atmospherics/environmental/LINDA_system.dm
index 0e8fbf2666760..30e97e4ba7d26 100644
--- a/code/modules/atmospherics/environmental/LINDA_system.dm
+++ b/code/modules/atmospherics/environmental/LINDA_system.dm
@@ -1,69 +1,97 @@
-/atom/var/CanAtmosPass = ATMOS_PASS_YES
-/atom/var/CanAtmosPassVertical = ATMOS_PASS_YES
+/atom
+ ///Check if atmos can pass in this atom (ATMOS_PASS_YES, ATMOS_PASS_NO, ATMOS_PASS_DENSITY, ATMOS_PASS_PROC)
+ var/can_atmos_pass = ATMOS_PASS_YES
-/atom/proc/CanAtmosPass(turf/T)
- switch (CanAtmosPass)
+/atom/proc/can_atmos_pass(turf/target_turf, vertical = FALSE)
+ switch (can_atmos_pass)
if (ATMOS_PASS_PROC)
return ATMOS_PASS_YES
if (ATMOS_PASS_DENSITY)
return !density
else
- return CanAtmosPass
-
-/turf/CanAtmosPass = ATMOS_PASS_NO
-/turf/CanAtmosPassVertical = ATMOS_PASS_NO
-
-/turf/open/CanAtmosPass = ATMOS_PASS_PROC
-/turf/open/CanAtmosPassVertical = ATMOS_PASS_PROC
-
-/turf/open/CanAtmosPass(turf/T, vertical = FALSE)
- var/dir = vertical ? get_dir_multiz(src, T) : get_dir(src, T)
- var/opp = REVERSE_DIR(dir)
- . = TRUE
- if(vertical && !(zAirOut(dir, T) && T.zAirIn(dir, src)))
- . = FALSE
- if(isclosedturf(src) || isclosedturf(T))
- . = FALSE
- if (T == src)
- return .
- for(var/obj/O in contents+T.contents)
- var/turf/other = (O.loc == src ? T : src)
- if(!(vertical? (CANVERTICALATMOSPASS(O, other)) : (CANATMOSPASS(O, other))))
- . = FALSE
- if(O.BlockThermalConductivity()) //the direction and open/closed are already checked on CanAtmosPass() so there are no arguments
- conductivity_blocked_directions |= dir
- T.conductivity_blocked_directions |= opp
- if(!.)
- return .
-
-/atom/movable/proc/BlockThermalConductivity() // Objects that don't let heat through.
+ return can_atmos_pass
+
+/turf
+ can_atmos_pass = ATMOS_PASS_NO
+
+/turf/open
+ can_atmos_pass = ATMOS_PASS_PROC
+
+///Do NOT use this to see if 2 turfs are connected, it mutates state, and we cache that info anyhow.
+///Use TURFS_CAN_SHARE or TURF_SHARES depending on your usecase
+/turf/open/can_atmos_pass(turf/target_turf, vertical = FALSE)
+ var/can_pass = TRUE
+ var/direction = vertical ? get_dir_multiz(src, target_turf) : get_dir(src, target_turf)
+ var/opposite_direction = REVERSE_DIR(direction)
+ if(vertical && !(zAirOut(direction, target_turf) && target_turf.zAirIn(direction, src)))
+ can_pass = FALSE
+ if(blocks_air || target_turf.blocks_air)
+ can_pass = FALSE
+ //This path is a bit weird, if we're just checking with ourselves no sense asking objects on the turf
+ if (target_turf == src)
+ return can_pass
+
+ //Can't just return if canpass is false here, we need to set superconductivity
+ for(var/obj/checked_object in contents + target_turf.contents)
+ var/turf/other = (checked_object.loc == src ? target_turf : src)
+ if(CANATMOSPASS(checked_object, other, vertical))
+ continue
+ can_pass = FALSE
+ //the direction and open/closed are already checked on can_atmos_pass() so there are no arguments
+ if(checked_object.block_superconductivity())
+ atmos_supeconductivity |= direction
+ target_turf.atmos_supeconductivity |= opposite_direction
+ return FALSE //no need to keep going, we got all we asked (Is this even faster? fuck you it's soul)
+
+ //Superconductivity is a bitfield of directions we can't conduct with
+ //Yes this is really weird. Fuck you
+ atmos_supeconductivity &= ~direction
+ target_turf.atmos_supeconductivity &= ~opposite_direction
+
+ return can_pass
+
+/atom/movable/proc/block_superconductivity() // objects that block air and don't let superconductivity act. Only firelocks atm.
return FALSE
-/turf/proc/ImmediateCalculateAdjacentTurfs()
- if(SSair.thread_running())
- CALCULATE_ADJACENT_TURFS(src)
- return
+/// This proc is a more deeply optimized version of immediate_calculate_adjacent_turfs
+/// It contains dumbshit, and also stuff I just can't do at runtime
+/// If you're not editing behavior, just read that proc. It's less bad
+/turf/proc/init_immediate_calculate_adjacent_turfs()
+ //Basic optimization, if we can't share why bother asking other people ya feel?
+ // You know it's gonna be stupid when they include a unit test in the atmos code
+ // Yes, inlining the string concat does save 0.1 seconds
+ #ifdef UNIT_TESTS
+ ASSERT(UP == 16)
+ ASSERT(DOWN == 32)
+ #endif
LAZYINITLIST(src.atmos_adjacent_turfs)
- var/is_closed = isclosedturf(src)
var/list/atmos_adjacent_turfs = src.atmos_adjacent_turfs
- var/canpass = CANATMOSPASS(src, src)
- var/canvpass = CANVERTICALATMOSPASS(src, src)
+ var/canpass = CANATMOSPASS(src, src, FALSE)
// I am essentially inlineing two get_dir_multizs here, because they're way too slow on their own. I'm sorry brother
var/list/z_traits = SSmapping.multiz_levels[z]
for(var/direction in GLOB.cardinals_multiz)
// Yes this is a reimplementation of get_step_mutliz. It's faster tho. fuck you
+ // Oh also yes UP and DOWN do just point to +1 and -1 and not z offsets
+ // Multiz is shitcode welcome home
var/turf/current_turf = (direction & (UP|DOWN)) ? \
(direction & UP) ? \
- (z_traits[Z_LEVEL_UP]) ? \
+ (z_traits["16"]) ? \
(get_step(locate(x, y, z + 1), NONE)) : \
(null) : \
- (z_traits[Z_LEVEL_DOWN]) ? \
+ (z_traits["32"]) ? \
(get_step(locate(x, y, z - 1), NONE)) : \
(null) : \
(get_step(src, direction))
- if(!isopenturf(current_turf))
+ if(!isopenturf(current_turf)) // not interested in you brother
continue
- if(!is_closed && ((direction & (UP|DOWN)) ? (canvpass && CANVERTICALATMOSPASS(current_turf, src)) : (canpass && CANATMOSPASS(current_turf, src))))
+ // The assumption is that ONLY DURING INIT if two tiles have the same cycle, there's no way canpass(a->b) will be different then canpass(b->a), so this is faster
+ // Saves like 1.2 seconds
+ if(current_turf.current_cycle >= current_cycle)
+ continue
+
+ //Can you and me form a deeper relationship, or is this just a passing wind
+ // (direction & (UP | DOWN)) is just "is this vertical" by the by
+ if(canpass && CANATMOSPASS(current_turf, src, (direction & (UP|DOWN))) && !(blocks_air || current_turf.blocks_air))
LAZYINITLIST(current_turf.atmos_adjacent_turfs)
atmos_adjacent_turfs[current_turf] = TRUE
current_turf.atmos_adjacent_turfs[src] = TRUE
@@ -72,48 +100,42 @@
if (current_turf.atmos_adjacent_turfs)
current_turf.atmos_adjacent_turfs -= src
UNSETEMPTY(current_turf.atmos_adjacent_turfs)
- current_turf.set_sleeping(isclosedturf(current_turf))
- current_turf.__update_auxtools_turf_adjacency_info()
+ SEND_SIGNAL(current_turf, COMSIG_TURF_CALCULATED_ADJACENT_ATMOS)
+
UNSETEMPTY(atmos_adjacent_turfs)
src.atmos_adjacent_turfs = atmos_adjacent_turfs
- set_sleeping(is_closed)
- __update_auxtools_turf_adjacency_info()
+ SEND_SIGNAL(src, COMSIG_TURF_CALCULATED_ADJACENT_ATMOS)
-/turf/proc/ImmediateDisableAdjacency(disable_adjacent = TRUE)
- if(SSair.thread_running())
- SSadjacent_air.disable_queue[src] = disable_adjacent
- return
- if(disable_adjacent)
- // I am essentially inlineing two get_dir_multizs here, because they're way too slow on their own. I'm sorry brother
- var/list/z_traits = SSmapping.multiz_levels[z]
- for(var/direction in GLOB.cardinals_multiz)
- // Yes this is a reimplementation of get_step_mutliz. It's faster tho.
- var/turf/current_turf = (direction & (UP|DOWN)) ? \
- (direction & UP) ? \
- (z_traits[Z_LEVEL_UP]) ? \
- (get_step(locate(x, y, z + 1), NONE)) : \
- (null) : \
- (z_traits[Z_LEVEL_DOWN]) ? \
- (get_step(locate(x, y, z - 1), NONE)) : \
- (null) : \
- (get_step(src, direction))
- if(!istype(current_turf))
- continue
+/turf/proc/immediate_calculate_adjacent_turfs()
+ LAZYINITLIST(src.atmos_adjacent_turfs)
+ var/list/atmos_adjacent_turfs = src.atmos_adjacent_turfs
+ var/canpass = CANATMOSPASS(src, src, FALSE)
+ for(var/direction in GLOB.cardinals_multiz)
+ var/turf/current_turf = get_step_multiz(src, direction)
+ if(!isopenturf(current_turf)) // not interested in you brother
+ continue
+
+ //Can you and me form a deeper relationship, or is this just a passing wind
+ // (direction & (UP | DOWN)) is just "is this vertical" by the by
+ if(canpass && CANATMOSPASS(current_turf, src, (direction & (UP|DOWN))) && !(blocks_air || current_turf.blocks_air))
+ LAZYINITLIST(current_turf.atmos_adjacent_turfs)
+ atmos_adjacent_turfs[current_turf] = TRUE
+ current_turf.atmos_adjacent_turfs[src] = TRUE
+ else
+ atmos_adjacent_turfs -= current_turf
if (current_turf.atmos_adjacent_turfs)
current_turf.atmos_adjacent_turfs -= src
UNSETEMPTY(current_turf.atmos_adjacent_turfs)
- current_turf.__update_auxtools_turf_adjacency_info()
- LAZYCLEARLIST(atmos_adjacent_turfs)
- __update_auxtools_turf_adjacency_info()
+ SEND_SIGNAL(current_turf, COMSIG_TURF_CALCULATED_ADJACENT_ATMOS)
-/turf/proc/set_sleeping(should_sleep)
+ UNSETEMPTY(atmos_adjacent_turfs)
+ src.atmos_adjacent_turfs = atmos_adjacent_turfs
-/turf/proc/__update_auxtools_turf_adjacency_info()
//returns a list of adjacent turfs that can share air with this one.
//alldir includes adjacent diagonal tiles that can share
// air with both of the related adjacent cardinal tiles
-/turf/proc/GetAtmosAdjacentTurfs(alldir = 0)
+/turf/proc/get_atmos_adjacent_turfs(alldir = 0)
var/adjacent_turfs
if (atmos_adjacent_turfs)
adjacent_turfs = atmos_adjacent_turfs.Copy()
@@ -123,61 +145,79 @@
if (!alldir)
return adjacent_turfs
- var/turf/curloc = src
+ var/turf/current_location = src
for (var/direction in GLOB.diagonals_multiz)
- var/matchingDirections = 0
- var/turf/S = get_step_multiz(curloc, direction)
- if(!S)
+ var/matching_directions = 0
+ var/turf/checked_turf = get_step_multiz(current_location, direction)
+ if(!checked_turf)
continue
- for (var/checkDirection in GLOB.cardinals_multiz)
- var/turf/checkTurf = get_step(S, checkDirection)
- if(!S.atmos_adjacent_turfs || !S.atmos_adjacent_turfs[checkTurf])
+ for (var/check_direction in GLOB.cardinals_multiz)
+ var/turf/secondary_turf = get_step(checked_turf, check_direction)
+ if(!checked_turf.atmos_adjacent_turfs || !checked_turf.atmos_adjacent_turfs[secondary_turf])
continue
- if (adjacent_turfs[checkTurf])
- matchingDirections++
+ if (adjacent_turfs[secondary_turf])
+ matching_directions++
- if (matchingDirections >= 2)
- adjacent_turfs += S
+ if (matching_directions >= 2)
+ adjacent_turfs += checked_turf
break
return adjacent_turfs
-/**
- * For the love of all that is holy, DO NOT SET `command` TO TRUE ON HOTCODE. This will cause atmos to freeze up for considerable amounts at a time.
- * In fact- please just refrain from using this if you're not changing how atmos flows turf to turf
- */
-/atom/proc/air_update_turf(command = 0)
- if(!SSair.initialized) // I'm sorry for polutting user code, I'll do 10 hail giacom's
- return
- if(!isturf(loc) && command)
+/atom/proc/air_update_turf(update = FALSE, remove = FALSE)
+ var/turf/local_turf = get_turf(loc)
+ if(!local_turf)
return
- var/turf/T = get_turf(loc)
- T.air_update_turf(command)
+ local_turf.air_update_turf(update, remove)
-/turf/air_update_turf(command = 0)
- if(!SSair.initialized) // I'm sorry for polutting user code, I'll do 10 hail giacom's
- return
- if(command)
- ImmediateCalculateAdjacentTurfs()
+/**
+ * A helper proc for dealing with atmos changes
+ *
+ * Ok so this thing is pretty much used as a catch all for all the situations someone might wanna change something
+ * About a turfs atmos. It's real clunky, and someone needs to clean it up, but not today.
+ * Arguments:
+ * * update - Has the state of the structures in the world changed? If so, update our adjacent atmos turf list, if not, don't.
+ * * remove - Are you removing an active turf (Read wall), or adding one
+*/
+/turf/air_update_turf(update = FALSE, remove = FALSE)
+ if(update)
+ immediate_calculate_adjacent_turfs()
+ if(remove)
+ SSair.remove_from_active(src)
+ else
+ SSair.add_to_active(src)
-/atom/movable/proc/move_update_air(turf/T)
- if(isturf(T))
- T.air_update_turf(1)
- air_update_turf(1)
+/atom/movable/proc/move_update_air(turf/target_turf)
+ if(isturf(target_turf))
+ target_turf.air_update_turf(TRUE, FALSE) //You're empty now
+ air_update_turf(TRUE, TRUE) //You aren't
/atom/proc/atmos_spawn_air(text) //because a lot of people loves to copy paste awful code lets just make an easy proc to spawn your plasma fires
- var/turf/open/T = get_turf(src)
- if(!istype(T))
+ var/turf/open/local_turf = get_turf(src)
+ if(!istype(local_turf))
return
- T.atmos_spawn_air(text)
+ local_turf.atmos_spawn_air(text)
/turf/open/atmos_spawn_air(text)
if(!text || !air)
return
- var/datum/gas_mixture/G = new
- G.parse_gas_string(text)
- assume_air(G)
+ var/datum/gas_mixture/turf_mixture = SSair.parse_gas_string(text)
+
+ air.merge(turf_mixture)
+ archive()
+ SSair.add_to_active(src)
+
+/turf/proc/immediate_disable_adjacency(disable_adjacent = TRUE)
+ if(disable_adjacent)
+ for(var/direction in GLOB.cardinals_multiz)
+ var/turf/T = get_step_multiz(src, direction)
+ if(!istype(T))
+ continue
+ if (T.atmos_adjacent_turfs)
+ T.atmos_adjacent_turfs -= src
+ UNSETEMPTY(T.atmos_adjacent_turfs)
+ LAZYCLEARLIST(atmos_adjacent_turfs)
diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
index 5af7263477686..9ba01f46dd86f 100644
--- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
+++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm
@@ -1,123 +1,107 @@
/turf
- //conductivity is divided by 10 when interacting with air for balance purposes
+ //used for temperature calculations in superconduction
var/thermal_conductivity = 0.05
- var/heat_capacity = 1
+ var/heat_capacity = INFINITY //This should be opt in rather then opt out
+ var/temperature_archived
- //list of open turfs adjacent to us
+ ///list of turfs adjacent to us that air can flow onto
var/list/atmos_adjacent_turfs
- //bitfield of dirs in which we thermal conductivity is blocked
- var/conductivity_blocked_directions = NONE
-
- //used for mapping and for breathing while in walls (because that's a thing that needs to be accounted for...)
- //string parsed by /datum/gas/proc/copy_from_turf
+ ///bitfield of dirs in which we are superconducitng
+ var/atmos_supeconductivity = NONE
+
+ //used to determine whether we should archive
+ var/archived_cycle = 0
+ var/current_cycle = 0
+
+ /**
+ * used for mapping and for breathing while in walls (because that's a thing that needs to be accounted for...)
+ * string parsed by /datum/gas/proc/copy_from_turf
+ * approximation of MOLES_O2STANDARD and MOLES_N2STANDARD pending byond allowing constant expressions to be embedded in constant strings
+ * If someone will place 0 of some gas there, SHIT WILL BREAK. Do not do that.
+ **/
var/initial_gas_mix = OPENTURF_DEFAULT_ATMOS
//approximation of MOLES_O2STANDARD and MOLES_N2STANDARD pending byond allowing constant expressions to be embedded in constant strings
// If someone will place 0 of some gas there, SHIT WILL BREAK. Do not do that.
/turf/open
//used for spacewind
+ ///Pressure difference between two turfs
var/pressure_difference = 0
+ ///Where the difference come from (from higher pressure to lower pressure)
var/pressure_direction = 0
- var/turf/pressure_specific_target
+ ///Excited group we are part of
+ var/datum/excited_group/excited_group
+ ///Are we active?
+ var/excited = FALSE
+ ///Our gas mix
var/datum/gas_mixture/turf/air
+ ///If there is an active hotspot on us store a reference to it here
var/obj/effect/hotspot/active_hotspot
- var/planetary_atmos = FALSE //air will revert to initial_gas_mix over time
-
- var/list/atmos_overlay_types //gas IDs of current active gas overlays
+ /// air will slowly revert to initial_gas_mix
+ var/planetary_atmos = FALSE
+ /// once our paired turfs are finished with all other shares, do one 100% share
+ /// exists so things like space can ask to take 100% of a tile's gas
+ var/run_later = FALSE
+
+ ///gas IDs of current active gas overlays
+ var/list/atmos_overlay_types
+ var/significant_share_ticker = 0
+ #ifdef TRACK_MAX_SHARE
+ var/max_share = 0
+ #endif
/turf/open/Initialize(mapload)
- if (planetary_atmos && Debugger?.enabled)
- var/static/list/planet_atmos_types = list()
- if(planet_atmos_types[type])
- air = planet_atmos_types[type]
- else
- air = new(2500,src)
- air.copy_from_turf(src)
- update_air_ref(1)
- planet_atmos_types[type] = air
- else
- air = new(2500,src)
- air.copy_from_turf(src)
- update_air_ref(planetary_atmos ? 1 : 2)
- . = ..()
+ if(!blocks_air)
+ air = create_gas_mixture()
+ if(planetary_atmos)
+ if(!SSair.planetary[initial_gas_mix])
+ var/datum/gas_mixture/immutable/planetary/mix = new
+ mix.parse_string_immutable(initial_gas_mix)
+ SSair.planetary[initial_gas_mix] = mix
+ return ..()
/turf/open/Destroy()
if(active_hotspot)
QDEL_NULL(active_hotspot)
+ // Adds the adjacent turfs to the current atmos processing
+ for(var/near_turf in atmos_adjacent_turfs)
+ SSair.add_to_active(near_turf)
return ..()
-/turf/proc/update_air_ref()
-
/////////////////GAS MIXTURE PROCS///////////////////
-/turf/open/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air
- return assume_air_ratio(giver, 1)
-
-/turf/open/assume_air_moles(datum/gas_mixture/giver, moles)
- if(!giver)
- return FALSE
- if(SSair.thread_running())
- var giver_moles = giver.total_moles()
- if(giver_moles > 0)
- SSair.deferred_airs += list(list(giver, air, moles / giver_moles))
- else
- SSair.deferred_airs += list(list(giver, air, 0))
- else
- giver.transfer_to(air, moles)
- update_visuals()
- return TRUE
+///Copies all gas info from the turf into a new gas_mixture, along with our temperature
+///Returns the created gas_mixture
+/turf/proc/create_gas_mixture()
+ var/datum/gas_mixture/mix = SSair.parse_gas_string(initial_gas_mix)
-/turf/open/assume_air_ratio(datum/gas_mixture/giver, ratio)
- if(!giver)
- return FALSE
- if(SSair.thread_running())
- SSair.deferred_airs += list(list(giver, air, ratio))
- else
- giver.transfer_ratio_to(air, ratio)
- update_visuals()
- return TRUE
+ //acounts for changes in temperature
+ var/turf/parent = parent_type
+ if(temperature != initial(temperature) || temperature != initial(parent.temperature))
+ mix.temperature = temperature
-/turf/open/transfer_air(datum/gas_mixture/taker, moles)
- if(!taker || !return_air()) // shouldn't transfer from space
- return FALSE
- if(SSair.thread_running())
- var air_moles = air.total_moles()
- if(air_moles > 0)
- SSair.deferred_airs += list(list(air, taker, moles / air_moles))
- else
- SSair.deferred_airs += list(list(air, taker, 0))
- else
- air.transfer_to(taker, moles)
- update_visuals()
- return TRUE
+ return mix
-/turf/open/transfer_air_ratio(datum/gas_mixture/taker, ratio)
- if(!taker || !return_air())
+/turf/open/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air
+ if(!giver)
return FALSE
- if(SSair.thread_running())
- SSair.deferred_airs += list(list(air, taker, ratio))
- else
- air.transfer_ratio_to(taker, ratio)
- update_visuals()
+ air.merge(giver)
+ update_visuals()
+ air_update_turf(FALSE, FALSE)
return TRUE
/turf/open/remove_air(amount)
var/datum/gas_mixture/ours = return_air()
var/datum/gas_mixture/removed = ours.remove(amount)
update_visuals()
+ air_update_turf(FALSE, FALSE)
return removed
-/turf/open/remove_air_ratio(ratio)
- var/datum/gas_mixture/ours = return_air()
- var/datum/gas_mixture/removed = ours.remove_ratio(ratio)
- update_visuals()
- return removed
-
-/turf/open/proc/copy_air_with_tile(turf/open/T)
- if(istype(T))
- air.copy_from(T.air)
+/turf/open/proc/copy_air_with_tile(turf/open/target_turf)
+ if(istype(target_turf))
+ air.copy_from(target_turf.air)
/turf/open/proc/copy_air(datum/gas_mixture/copy)
if(copy)
@@ -125,9 +109,8 @@
/turf/return_air()
RETURN_TYPE(/datum/gas_mixture)
- var/datum/gas_mixture/GM = new
- GM.copy_from_turf(src)
- return GM
+ var/datum/gas_mixture/copied_mixture = create_gas_mixture()
+ return copied_mixture
/turf/open/return_air()
RETURN_TYPE(/datum/gas_mixture)
@@ -136,24 +119,48 @@
/turf/open/return_analyzable_air()
return return_air()
-/turf/temperature_expose()
- if(return_temperature() > heat_capacity)
+/turf/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return (exposed_temperature >= heat_capacity || to_be_destroyed)
+
+/turf/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ if(exposed_temperature >= heat_capacity)
to_be_destroyed = TRUE
+ if(to_be_destroyed && exposed_temperature >= max_fire_temperature_sustained)
+ max_fire_temperature_sustained = min(exposed_temperature, max_fire_temperature_sustained + heat_capacity / 4) //Ramp up to 100% yeah?
+ if(to_be_destroyed && !changing_turf)
+ burn_turf()
+
+/turf/proc/burn_turf()
+ burn_tile()
+ var/chance_of_deletion
+ if (heat_capacity) //beware of division by zero
+ chance_of_deletion = max_fire_temperature_sustained / heat_capacity * 8 //there is no problem with prob(23456), min() was redundant --rastaf0
+ else
+ chance_of_deletion = 100
+ if(prob(chance_of_deletion))
+ Melt()
+ max_fire_temperature_sustained = 0
+ else
+ to_be_destroyed = FALSE
+
+/turf/temperature_expose(datum/gas_mixture/air, exposed_temperature)
+ atmos_expose(air, exposed_temperature)
+/turf/open/temperature_expose(datum/gas_mixture/air, exposed_temperature)
+ SEND_SIGNAL(src, COMSIG_TURF_EXPOSE, air, exposed_temperature)
+ check_atmos_process(src, air, exposed_temperature) //Manually do this to avoid needing to use elements, don't want 200 second atom init times
-/turf/open/proc/eg_reset_cooldowns()
-/turf/open/proc/eg_garbage_collect()
-/turf/open/proc/get_excited()
-/turf/open/proc/set_excited()
+/turf/proc/archive()
+ temperature_archived = temperature
+
+/turf/open/archive()
+ LINDA_CYCLE_ARCHIVE(src)
/////////////////////////GAS OVERLAYS//////////////////////////////
/turf/open/proc/update_visuals()
-
var/list/atmos_overlay_types = src.atmos_overlay_types // Cache for free performance
- var/list/new_overlay_types = list()
- var/static/list/nonoverlaying_gases = typecache_of_gases_with_no_overlays()
if(!air) // 2019-05-14: was not able to get this path to fire in testing. Consider removing/looking at callers -Naksu
if (atmos_overlay_types)
@@ -162,13 +169,10 @@
src.atmos_overlay_types = null
return
+ var/list/gases = air.gases
- for(var/id in air.get_gases())
- if (nonoverlaying_gases[id])
- continue
- var/gas_overlay = GLOB.gas_data.overlays[id]
- if(gas_overlay && air.get_moles(id) > GLOB.gas_data.visibility[id])
- new_overlay_types += gas_overlay[min(FACTOR_GAS_VISIBLE_MAX, CEILING(air.get_moles(id) / MOLES_GAS_VISIBLE_STEP, 1))]
+ var/list/new_overlay_types
+ GAS_OVERLAYS(gases, new_overlay_types)
if (atmos_overlay_types)
for(var/overlay in atmos_overlay_types-new_overlay_types) //doesn't remove overlays that would only be added
@@ -183,108 +187,507 @@
UNSETEMPTY(new_overlay_types)
src.atmos_overlay_types = new_overlay_types
-/turf/open/proc/set_visuals(list/new_overlay_types)
- if (atmos_overlay_types)
- for(var/overlay in atmos_overlay_types-new_overlay_types) //doesn't remove overlays that would only be added
- vis_contents -= overlay
-
- if (length(new_overlay_types))
- if (atmos_overlay_types)
- vis_contents += new_overlay_types - atmos_overlay_types //don't add overlays that already exist
- else
- vis_contents += new_overlay_types
- UNSETEMPTY(new_overlay_types)
- src.atmos_overlay_types = new_overlay_types
-
/proc/typecache_of_gases_with_no_overlays()
. = list()
for (var/gastype in subtypesof(/datum/gas))
var/datum/gas/gasvar = gastype
if (!initial(gasvar.gas_overlay))
- .[initial(gasvar.id)] = TRUE
+ .[gastype] = TRUE
/////////////////////////////SIMULATION///////////////////////////////////
+#ifdef TRACK_MAX_SHARE
+#define LAST_SHARE_CHECK \
+ var/last_share = our_air.last_share;\
+ max_share = max(last_share, max_share);\
+ if(last_share > MINIMUM_AIR_TO_SUSPEND){\
+ our_excited_group.reset_cooldowns();\
+ cached_ticker = 0;\
+ enemy_tile.significant_share_ticker = 0;\
+ } else if(last_share > MINIMUM_MOLES_DELTA_TO_MOVE) {\
+ our_excited_group.dismantle_cooldown = 0;\
+ cached_ticker = 0;\
+ enemy_tile.significant_share_ticker = 0;\
+ }
+#else
+#define LAST_SHARE_CHECK \
+ var/last_share = our_air.last_share;\
+ if(last_share > MINIMUM_AIR_TO_SUSPEND){\
+ our_excited_group.reset_cooldowns();\
+ cached_ticker = 0;\
+ enemy_tile.significant_share_ticker = 0;\
+ } else if(last_share > MINIMUM_MOLES_DELTA_TO_MOVE) {\
+ our_excited_group.dismantle_cooldown = 0;\
+ cached_ticker = 0;\
+ enemy_tile.significant_share_ticker = 0;\
+ }
+#endif
+#ifdef TRACK_MAX_SHARE
+#define PLANET_SHARE_CHECK \
+ var/last_share = our_air.last_share;\
+ max_share = max(last_share, max_share);\
+ if(last_share > MINIMUM_AIR_TO_SUSPEND){\
+ our_excited_group.reset_cooldowns();\
+ cached_ticker = 0;\
+ } else if(last_share > MINIMUM_MOLES_DELTA_TO_MOVE) {\
+ our_excited_group.dismantle_cooldown = 0;\
+ cached_ticker = 0;\
+ }
+#else
+#define PLANET_SHARE_CHECK \
+ var/last_share = our_air.last_share;\
+ if(last_share > MINIMUM_AIR_TO_SUSPEND){\
+ our_excited_group.reset_cooldowns();\
+ cached_ticker = 0;\
+ } else if(last_share > MINIMUM_MOLES_DELTA_TO_MOVE) {\
+ our_excited_group.dismantle_cooldown = 0;\
+ cached_ticker = 0;\
+ }
+#endif
/turf/proc/process_cell(fire_count)
+ SSair.remove_from_active(src)
-/turf/open/proc/equalize_pressure_in_zone(cyclenum)
-/turf/open/proc/consider_firelocks(turf/T2)
- var/reconsider_adj = FALSE
- for(var/obj/machinery/door/firedoor/FD in T2)
- if((FD.flags_1 & ON_BORDER_1) && get_dir(T2, src) != FD.dir)
- continue
- FD.emergency_pressure_stop()
- reconsider_adj = TRUE
- for(var/obj/machinery/door/firedoor/FD in src)
- if((FD.flags_1 & ON_BORDER_1) && get_dir(src, T2) != FD.dir)
+/turf/open/process_cell(fire_count)
+ if(archived_cycle < fire_count) //archive self if not already done
+ LINDA_CYCLE_ARCHIVE(src)
+
+ current_cycle = fire_count
+ var/cached_ticker = significant_share_ticker
+ cached_ticker += 1
+
+ //cache for sanic speed
+ var/list/adjacent_turfs = atmos_adjacent_turfs
+ var/datum/excited_group/our_excited_group = excited_group
+ var/our_share_coeff = 1/(LAZYLEN(adjacent_turfs) + 1)
+
+ var/datum/gas_mixture/our_air = air
+
+ var/list/share_end
+
+ #ifdef TRACK_MAX_SHARE
+ max_share = 0 //Gotta reset our tracker
+ #endif
+
+ for(var/turf/open/enemy_tile as anything in adjacent_turfs)
+ #ifdef UNIT_TESTS
+ if(!istype(enemy_tile))
+ stack_trace("closed turf inside of adjacent turfs")
continue
- FD.emergency_pressure_stop()
- reconsider_adj = TRUE
- if(reconsider_adj)
- T2.ImmediateCalculateAdjacentTurfs() // We want those firelocks closed yesterday.
+ #endif
-/turf/proc/handle_decompression_floor_rip()
-/turf/open/floor/handle_decompression_floor_rip(sum)
- if(sum > 20 && prob(clamp(sum / 20, 0, 15)))
- if(floor_tile)
- new floor_tile(src)
- make_plating()
+ // This var is only rarely set, exists so turfs can request to share at the end of our sharing
+ // We need this so we can assume share is communative, which we need to do to avoid a hellish amount of garbage_collect()s
+ if(enemy_tile.run_later)
+ LAZYADD(share_end, enemy_tile)
-/turf/open/floor/plating/handle_decompression_floor_rip()
- return
+ if(fire_count <= enemy_tile.current_cycle)
+ continue
+ LINDA_CYCLE_ARCHIVE(enemy_tile)
+
+ /******************* GROUP HANDLING START *****************************************************************/
+
+ var/should_share_air = FALSE
+ var/datum/gas_mixture/enemy_air = enemy_tile.air
+
+ //cache for sanic speed
+ var/datum/excited_group/enemy_excited_group = enemy_tile.excited_group
+ //If we are both in an excited group, and they aren't the same, merge.
+ //If we are both in an excited group, and you're active, share
+ //If we pass compare, and if we're not already both in a group, lets join up
+ //If we both pass compare, add to active and share
+ if(our_excited_group && 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
+ if(our_excited_group && enemy_excited_group && enemy_tile.excited) //If you're both excited, no need to compare right?
+ should_share_air = TRUE
+ else if(our_air.compare(enemy_air)) //Lets see if you're up for it
+ SSair.add_to_active(enemy_tile) //Add yourself young man
+ var/datum/excited_group/existing_group = our_excited_group || enemy_excited_group || new
+ if(!our_excited_group)
+ existing_group.add_turf(src)
+ if(!enemy_excited_group)
+ existing_group.add_turf(enemy_tile)
+ our_excited_group = excited_group
+ should_share_air = TRUE
+
+ //air sharing
+ if(should_share_air)
+ var/difference = our_air.share(enemy_air, our_share_coeff, 1 / (LAZYLEN(enemy_tile.atmos_adjacent_turfs) + 1))
+ if(difference)
+ if(difference > 0)
+ consider_pressure_difference(enemy_tile, difference)
+ else
+ enemy_tile.consider_pressure_difference(src, -difference)
+ //This acts effectivly as a very slow timer, the max deltas of the group will slowly lower until it breaksdown, they then pop up a bit, and fall back down until irrelevant
+ LAST_SHARE_CHECK
+
+
+ /******************* GROUP HANDLING FINISH *********************************************************************/
+
+ if (planetary_atmos) //share our air with the "atmosphere" "above" the turf
+ var/datum/gas_mixture/planetary_mix = SSair.planetary[initial_gas_mix]
+ // archive ourself again so we don't accidentally share more gas than we currently have
+ LINDA_CYCLE_ARCHIVE(src)
+ if(our_air.compare(planetary_mix))
+ if(!our_excited_group)
+ var/datum/excited_group/new_group = new
+ new_group.add_turf(src)
+ our_excited_group = excited_group
+ // shares 4/5 of our difference in moles with the atmosphere
+ our_air.share(planetary_mix, 0.8, 0.8)
+ // temperature share with the atmosphere with an inflated heat capacity to simulate faster sharing with a large atmosphere
+ our_air.temperature_share(planetary_mix, OPEN_HEAT_TRANSFER_COEFFICIENT, planetary_mix.temperature_archived, planetary_mix.heat_capacity() * 5)
+ planetary_mix.garbage_collect()
+ PLANET_SHARE_CHECK
+
+ for(var/turf/open/enemy_tile as anything in share_end)
+ var/datum/gas_mixture/enemy_mix = enemy_tile.air
+ LINDA_CYCLE_ARCHIVE(src)
+ // We share 100% of our mix in this step. Let's jive
+ var/difference = our_air.share(enemy_mix, 1, 1)
+ LAST_SHARE_CHECK
+ if(!difference)
+ continue
+ if(difference > 0)
+ consider_pressure_difference(enemy_tile, difference)
+ else
+ enemy_tile.consider_pressure_difference(src, difference)
-/turf/open/floor/engine/handle_decompression_floor_rip()
- return
+ var/reacting = our_air.react(src)
+ if(our_excited_group)
+ our_excited_group.turf_reactions |= reacting //Adds the flag to turf_reactions so excited groups can check for them before dismantling.
-/turf/open/process_cell(fire_count)
+ update_visuals()
+ if(!consider_superconductivity(starting = TRUE) && !active_hotspot && !(reacting & (REACTING | STOP_REACTIONS)))
+ if(!our_excited_group) //If nothing of interest is happening, kill the active turf
+ SSair.remove_from_active(src) //This will kill any connected excited group, be careful (This broke atmos for 4 years)
+ if(cached_ticker > EXCITED_GROUP_DISMANTLE_CYCLES) //If you're stalling out, take a rest
+ SSair.sleep_active_turf(src)
-//////////////////////////SPACEWIND/////////////////////////////
+ significant_share_ticker = cached_ticker //Save our changes
+ temperature_expose(our_air, our_air.temperature)
-/turf/proc/consider_pressure_difference()
- return
+//////////////////////////SPACEWIND/////////////////////////////
-/turf/open/consider_pressure_difference(turf/T, difference)
+/turf/open/proc/consider_pressure_difference(turf/target_turf, difference)
SSair.high_pressure_delta |= src
if(difference > pressure_difference)
- pressure_direction = get_dir(src, T)
+ pressure_direction = get_dir(src, target_turf)
pressure_difference = difference
/turf/open/proc/high_pressure_movements()
- var/atom/movable/M
- var/multiplier = 1
- if(locate(/obj/structure/rack) in src)
- multiplier *= 0.1
- else if(locate(/obj/structure/table) in src)
- multiplier *= 0.2
+ var/atom/movable/moving_atom
for(var/thing in src)
- M = thing
- if (!M.anchored && !M.pulledby && M.last_high_pressure_movement_air_cycle < SSair.times_fired)
- M.experience_pressure_difference(pressure_difference * multiplier, pressure_direction, 0, pressure_specific_target)
+ moving_atom = thing
+ if (!moving_atom.anchored && !moving_atom.pulledby && moving_atom.last_high_pressure_movement_air_cycle < SSair.times_fired)
+ moving_atom.experience_pressure_difference(pressure_difference, pressure_direction)
-/atom/movable/var/pressure_resistance = 10
-/atom/movable/var/last_high_pressure_movement_air_cycle = 0
+/atom/movable
+ ///How much delta pressure is needed for us to move
+ var/pressure_resistance = 10
+ var/last_high_pressure_movement_air_cycle = 0
-/atom/movable/proc/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0, throw_target)
+/atom/movable/proc/experience_pressure_difference(pressure_difference, direction, pressure_resistance_prob_delta = 0)
set waitfor = FALSE
if(SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_PRESSURE_PUSH) & COMSIG_MOVABLE_BLOCKS_PRESSURE)
return
-
- var/const/PROBABILITY_OFFSET = 40
- var/const/PROBABILITY_BASE_PRECENT = 10
- var/max_force = sqrt(pressure_difference)*(MOVE_FORCE_DEFAULT / 5)
+ var/const/PROBABILITY_OFFSET = 25
+ var/const/PROBABILITY_BASE_PRECENT = 75
+ var/max_force = sqrt(pressure_difference) * (MOVE_FORCE_DEFAULT / 5)
var/move_prob = 100
- if(pressure_resistance > 0)
- move_prob = (pressure_difference/pressure_resistance*PROBABILITY_BASE_PRECENT)-PROBABILITY_OFFSET
+ if (pressure_resistance > 0)
+ 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/move_force = max_force * clamp(move_prob, 0, 100) / 100
- if(move_force > 6000)
- // WALLSLAM HELL TIME OH BOY
- var/turf/throw_turf = get_ranged_target_turf(get_turf(src), direction, round(move_force / 2000))
- if(throw_target && (get_dir(src, throw_target) & direction))
- throw_turf = get_turf(throw_target)
- var/throw_speed = clamp(round(move_force / 3000), 1, 10)
- throw_at(throw_turf, move_force / 3000, throw_speed)
- else
- step(src, direction)
+ 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))))
+ step(src, direction)
last_high_pressure_movement_air_cycle = SSair.times_fired
+
+///////////////////////////EXCITED GROUPS/////////////////////////////
+
+/datum/excited_group
+ ///Stores a reference to the turfs we are controlling
+ var/list/turf_list = list()
+ ///If this is over EXCITED_GROUP_BREAKDOWN_CYCLES we call self_breakdown()
+ var/breakdown_cooldown = 0
+ ///If this is over EXCITED_GROUP_DISMANTLE_CYCLES we call dismantle()
+ var/dismantle_cooldown = 0
+ ///Used for debug to show the excited groups active and their turfs
+ var/should_display = FALSE
+ ///Id of the index color of the displayed group
+ var/display_id = 0
+ ///Wrapping loop of the index colors
+ var/static/wrapping_id = 0
+ ///All turf reaction flags we have received.
+ var/turf_reactions = NONE
+
+/datum/excited_group/New()
+ SSair.excited_groups += src
+
+/datum/excited_group/proc/add_turf(turf/open/target_turf)
+ turf_list += target_turf
+ target_turf.excited_group = src
+ dismantle_cooldown = 0
+ if(should_display || SSair.display_all_groups)
+ display_turf(target_turf)
+
+/datum/excited_group/proc/merge_groups(datum/excited_group/target_group)
+ if(turf_list.len > target_group.turf_list.len)
+ SSair.excited_groups -= target_group
+ for(var/turf/open/group_member as anything in target_group.turf_list)
+ group_member.excited_group = src
+ turf_list += group_member
+ should_display = target_group.should_display | should_display
+ if(should_display || SSair.display_all_groups)
+ target_group.hide_turfs()
+ display_turfs()
+ breakdown_cooldown = min(breakdown_cooldown, target_group.breakdown_cooldown) //Take the smaller of the two options
+ dismantle_cooldown = 0
+ else
+ SSair.excited_groups -= src
+ for(var/turf/open/group_member as anything in turf_list)
+ group_member.excited_group = target_group
+ target_group.turf_list += group_member
+ target_group.should_display = target_group.should_display | should_display
+ if(target_group.should_display || SSair.display_all_groups)
+ hide_turfs()
+ target_group.display_turfs()
+ target_group.breakdown_cooldown = min(breakdown_cooldown, target_group.breakdown_cooldown)
+ target_group.dismantle_cooldown = 0
+
+
+/datum/excited_group/proc/reset_cooldowns()
+ breakdown_cooldown = 0
+ dismantle_cooldown = 0
+
+
+/datum/excited_group/proc/self_breakdown(roundstart = FALSE, poke_turfs = FALSE)
+ var/datum/gas_mixture/shared_mix = new
+
+ //make local for sanic speed
+ var/list/shared_gases = shared_mix.gases
+ var/list/turf_list = src.turf_list
+ var/turflen = turf_list.len
+ var/imumutable_in_group = FALSE
+ var/energy = 0
+ var/heat_cap = 0
+
+ for(var/turf/open/group_member as anything in turf_list)
+ //Cache?
+ var/datum/gas_mixture/turf/mix = group_member.air
+ if (roundstart)
+ if(istype(group_member.air, /datum/gas_mixture/immutable))
+ imumutable_in_group = TRUE
+ shared_mix.copy_from(group_member.air) //This had better be immutable young man
+ shared_gases = shared_mix.gases //update the cache
+ break
+ // If we're planetary use THAT mix, and stop here
+ if(group_member.planetary_atmos)
+ imumutable_in_group = TRUE
+ var/datum/gas_mixture/planetary_mix = SSair.planetary[group_member.initial_gas_mix]
+ shared_mix.copy_from(planetary_mix)
+ shared_gases = shared_mix.gases // Cache update
+ break
+ //"borrowing" this code from merge(), I need to play with the temp portion. Lets expand it out
+ //temperature = (giver.temperature * giver_heat_capacity + temperature * self_heat_capacity) / combined_heat_capacity
+ var/capacity = mix.heat_capacity()
+ energy += mix.temperature * capacity
+ heat_cap += capacity
+
+ var/list/giver_gases = mix.gases
+ for(var/giver_id in giver_gases)
+ ASSERT_GAS_IN_LIST(giver_id, shared_gases)
+ shared_gases[giver_id][MOLES] += giver_gases[giver_id][MOLES]
+
+ if(!imumutable_in_group)
+ shared_mix.temperature = energy / heat_cap
+ for(var/id in shared_gases)
+ shared_gases[id][MOLES] /= turflen
+ shared_mix.garbage_collect()
+
+ for(var/turf/open/group_member as anything in turf_list)
+ if(group_member.planetary_atmos) //We do this as a hack to try and minimize unneeded excited group spread over planetary turfs
+ group_member.air.copy_from(SSair.planetary[group_member.initial_gas_mix]) //Comes with a cost of "slower" drains, but it's worth it
+ else
+ group_member.air.copy_from(shared_mix) //Otherwise just set the mix to a copy of our equalized mix
+ group_member.update_visuals()
+ if(poke_turfs) //Because we only activate all these once every breakdown, in event of lag due to this code and slow space + vent things, increase the wait time for breakdowns
+ SSair.add_to_active(group_member)
+ group_member.significant_share_ticker = EXCITED_GROUP_DISMANTLE_CYCLES //Max out the ticker, if they don't share next tick, nuke em
+
+ breakdown_cooldown = 0
+
+///Dismantles the excited group, puts allll the turfs to sleep
+/datum/excited_group/proc/dismantle()
+ for(var/turf/open/current_turf as anything in turf_list)
+ current_turf.excited = FALSE
+ current_turf.significant_share_ticker = 0
+ SSair.active_turfs -= current_turf
+ #ifdef VISUALIZE_ACTIVE_TURFS //Use this when you want details about how the turfs are moving, display_all_groups should work for normal operation
+ current_turf.remove_atom_colour(TEMPORARY_COLOUR_PRIORITY, COLOR_VIBRANT_LIME)
+ #endif
+ garbage_collect()
+
+//Breaks down the excited group, this doesn't sleep the turfs mind, just removes them from the group
+/datum/excited_group/proc/garbage_collect()
+ if(display_id) //If we ever did make those changes
+ hide_turfs()
+ for(var/turf/open/current_turf as anything in turf_list)
+ current_turf.excited_group = null
+ turf_list.Cut()
+ SSair.excited_groups -= src
+ if(SSair.currentpart == SSAIR_EXCITEDGROUPS)
+ SSair.currentrun -= src
+
+/datum/excited_group/proc/display_turfs()
+ if(display_id == 0) //Hasn't been shown before
+ wrapping_id = wrapping_id % GLOB.colored_turfs.len
+ wrapping_id++ //We do this after because lists index at 1
+ display_id = wrapping_id
+ for(var/thing in turf_list)
+ var/turf/display = thing
+ display.vis_contents += GLOB.colored_turfs[display_id]
+
+/datum/excited_group/proc/hide_turfs()
+ for(var/thing in turf_list)
+ var/turf/display = thing
+ display.vis_contents -= GLOB.colored_turfs[display_id]
+ display_id = 0
+
+/datum/excited_group/proc/display_turf(turf/thing)
+ if(display_id == 0) //Hasn't been shown before
+ wrapping_id = wrapping_id % GLOB.colored_turfs.len
+ wrapping_id++ //We do this after because lists index at 1
+ display_id = wrapping_id
+ thing.vis_contents += GLOB.colored_turfs[display_id]
+
+////////////////////////SUPERCONDUCTIVITY/////////////////////////////
+
+/**
+ALLLLLLLLLLLLLLLLLLLLRIGHT HERE WE GOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
+
+Read the code for more details, but first, a brief concept discussion/area
+
+Our goal here is to "model" heat moving through solid objects, so walls, windows, and sometimes doors.
+We do this by heating up the floor itself with the heat of the gasmix ontop of it, this is what the coeffs are for here, they slow that movement
+Then we go through the process below.
+
+If an active turf is fitting, we add it to processing, conduct with any covered tiles, (read windows and sometimes walls)
+Then we space some of our heat, and think about if we should stop conducting.
+**/
+
+/turf/proc/conductivity_directions()
+ if(archived_cycle < SSair.times_fired)
+ archive()
+ return ALL_CARDINALS
+
+///Returns a set of directions that we should be conducting in, NOTE, atmos_supeconductivity is ACTUALLY inversed, don't worrry about it
+/turf/open/conductivity_directions()
+ if(blocks_air)
+ return ..()
+ for(var/direction in GLOB.cardinals)
+ var/turf/checked_turf = get_step(src, direction)
+ if(!(checked_turf in atmos_adjacent_turfs) && !(atmos_supeconductivity & direction))
+ . |= direction
+
+///These two procs are a bit of a web, I belive in you
+/turf/proc/neighbor_conduct_with_src(turf/open/other)
+ if(!other.blocks_air) //Solid but neighbor is open
+ other.temperature_share_open_to_solid(src)
+ else //Both tiles are solid
+ other.share_temperature_mutual_solid(src, thermal_conductivity)
+ temperature_expose(null, temperature)
+
+/turf/open/neighbor_conduct_with_src(turf/other)
+ if(blocks_air)
+ return ..()
+
+ if(!other.blocks_air) //Both tiles are open
+ var/turf/open/open_other = other
+ open_other.air.temperature_share(air, WINDOW_HEAT_TRANSFER_COEFFICIENT)
+ else //Open but neighbor is solid
+ temperature_share_open_to_solid(other)
+ SSair.add_to_active(src)
+
+/turf/proc/super_conduct()
+ var/conductivity_directions = conductivity_directions()
+
+ if(conductivity_directions)
+ //Conduct with tiles around me
+ for(var/direction in GLOB.cardinals)
+ if(!(conductivity_directions & direction))
+ continue
+ var/turf/neighbor = get_step(src, direction)
+
+ if(!neighbor.thermal_conductivity)
+ continue
+
+ if(neighbor.archived_cycle < SSair.times_fired)
+ neighbor.archive()
+
+ neighbor.neighbor_conduct_with_src(src)
+
+ neighbor.consider_superconductivity()
+
+ radiate_to_spess()
+
+ finish_superconduction()
+
+/turf/proc/finish_superconduction(temp = temperature)
+ //Make sure still hot enough to continue conducting heat
+ if(temp < MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION)
+ SSair.active_super_conductivity -= src
+ return FALSE
+
+/turf/open/finish_superconduction()
+ //Conduct with air on my tile if I have it
+ if(!blocks_air)
+ temperature = air.temperature_share(null, thermal_conductivity, temperature, heat_capacity)
+ ..((blocks_air ? temperature : air.temperature))
+
+///Should we attempt to superconduct?
+/turf/proc/consider_superconductivity(starting)
+ if(!thermal_conductivity)
+ return FALSE
+
+ SSair.active_super_conductivity |= src
+ return TRUE
+
+/turf/open/consider_superconductivity(starting)
+ if(air.temperature < (starting?MINIMUM_TEMPERATURE_START_SUPERCONDUCTION:MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION))
+ return FALSE
+ 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 FALSE
+ return ..()
+
+/turf/closed/consider_superconductivity(starting)
+ if(temperature < (starting?MINIMUM_TEMPERATURE_START_SUPERCONDUCTION:MINIMUM_TEMPERATURE_FOR_SUPERCONDUCTION))
+ return FALSE
+ return ..()
+
+/turf/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
+ return
+ var/delta_temperature = (temperature_archived - TCMB) //hardcoded space temperature
+ // Because we keep losing energy, makes more sense for us to be the T2 here.
+ if(heat_capacity <= 0 || abs(delta_temperature) <= MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ return
+ // Heat should be positive in most cases
+ // coefficient applied first because some turfs have very big heat caps.
+ var/heat = CALCULATE_CONDUCTION_ENERGY(thermal_conductivity * delta_temperature, HEAT_CAPACITY_VACUUM, heat_capacity)
+ temperature -= heat / heat_capacity
+
+/turf/open/proc/temperature_share_open_to_solid(turf/sharer)
+ sharer.temperature = air.temperature_share(null, sharer.thermal_conductivity, sharer.temperature, sharer.heat_capacity)
+
+/turf/proc/share_temperature_mutual_solid(turf/sharer, conduction_coefficient) //This is all just heat sharing, don't get freaked out
+ var/delta_temperature = sharer.temperature_archived - temperature_archived
+ if(abs(delta_temperature) <= MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER || !heat_capacity || !sharer.heat_capacity)
+ return
+ var/heat = conduction_coefficient * CALCULATE_CONDUCTION_ENERGY(delta_temperature, heat_capacity, sharer.heat_capacity)
+ temperature += heat / heat_capacity //The higher your own heat cap the less heat you get from this arrangement
+ sharer.temperature -= heat / sharer.heat_capacity
+
+#undef LAST_SHARE_CHECK
+#undef PLANET_SHARE_CHECK
diff --git a/code/modules/atmospherics/gasmixtures/auxgm.dm b/code/modules/atmospherics/gasmixtures/auxgm.dm
deleted file mode 100644
index 25e58dd50e898..0000000000000
--- a/code/modules/atmospherics/gasmixtures/auxgm.dm
+++ /dev/null
@@ -1,130 +0,0 @@
-GLOBAL_LIST_INIT(hardcoded_gases, list(GAS_O2, GAS_N2, GAS_CO2, GAS_PLASMA)) //the main four gases, which were at one time hardcoded
-GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GAS_PLUOXIUM, GAS_STIMULUM, GAS_NITRYL))) //unable to react amongst themselves
-
-// Auxgm
-// It's a send-up of XGM, like what baystation got.
-// It's got the same architecture as XGM, but it's structured
-// differently to make it more convenient for auxmos.
-
-// Most important compared to TG is that it does away with hardcoded typepaths,
-// which lead to problems on the auxmos end anyway. We cache the string value
-// references on the Rust end, so no performance is lost here.
-
-// Also allows you to add new gases at runtime
-
-/proc/_auxtools_register_gas(datum/gas/gas) // makes sure auxtools knows stuff about this gas
-
-/datum/auxgm
- var/list/datums = list()
- var/list/specific_heats = list()
- var/list/names = list()
- var/list/visibility = list()
- var/list/overlays = list()
- var/list/flags = list()
- var/list/ids = list()
- var/list/typepaths = list()
- var/list/fusion_powers = list()
- var/list/breathing_classes = list()
- var/list/breath_results = list()
- var/list/breath_reagents = list()
- var/list/breath_reagents_dangerous = list()
- var/list/breath_alert_info = list()
- var/list/oxidation_temperatures = list()
- var/list/oxidation_rates = list()
- var/list/fire_temperatures = list()
- var/list/enthalpies = list()
- var/list/fire_products = list()
- var/list/fire_burn_rates = list()
-
-
-/datum/gas
- var/id = ""
- var/specific_heat = 0
- var/name = ""
- var/gas_overlay = "" //icon_state in icons/effects/atmospherics.dmi
- var/moles_visible = null
- var/flags = NONE //currently used by canisters
- var/fusion_power = 0 // How much the gas destabilizes a fusion reaction
- var/breath_results = GAS_CO2 // what breathing this breathes out
- var/breath_reagent = null // what breathing this adds to your reagents
- var/breath_reagent_dangerous = null // what breathing this adds to your reagents IF it's above a danger threshold
- var/list/breath_alert_info = null // list for alerts that pop up when you have too much/not enough of something
- var/oxidation_temperature = null // temperature above which this gas is an oxidizer; null for none
- var/oxidation_rate = 1 // how many moles of this can oxidize how many moles of material
- var/fire_temperature = null // temperature above which gas may catch fire; null for none
- var/list/fire_products = null // what results when this gas is burned (oxidizer or fuel); null for none
- var/enthalpy = 0 // how much energy is released per mole of fuel burned
- var/fire_burn_rate = 1 // how many moles are burned per product released
-
-/datum/gas/proc/breath(partial_pressure, light_threshold, heavy_threshold, moles, mob/living/carbon/C, obj/item/organ/lungs/lungs)
- // This is only called on gases with the GAS_FLAG_BREATH_PROC flag. When possible, do NOT use this--
- // greatly prefer just adding a reagent. This is mostly around for legacy reasons.
- return null
-
-/datum/auxgm/proc/add_gas(datum/gas/gas)
- var/g = gas.id
- if(g)
- datums[g] = gas
- specific_heats[g] = gas.specific_heat
- names[g] = gas.name
- if(gas.moles_visible)
- visibility[g] = gas.moles_visible
- overlays[g] = new /list(FACTOR_GAS_VISIBLE_MAX)
- for(var/i in 1 to FACTOR_GAS_VISIBLE_MAX)
- overlays[g][i] = new /obj/effect/overlay/gas(gas.gas_overlay, i * 255 / FACTOR_GAS_VISIBLE_MAX)
- else
- visibility[g] = 0
- overlays[g] = 0
- flags[g] = gas.flags
- ids[g] = g
- typepaths[g] = gas.type
- fusion_powers[g] = gas.fusion_power
-
- if(gas.breath_alert_info)
- breath_alert_info[g] = gas.breath_alert_info
- breath_results[g] = gas.breath_results
- if(gas.breath_reagent)
- breath_reagents[g] = gas.breath_reagent
- if(gas.breath_reagent_dangerous)
- breath_reagents_dangerous[g] = gas.breath_reagent_dangerous
-
- if(gas.oxidation_temperature)
- oxidation_temperatures[g] = gas.oxidation_temperature
- oxidation_rates[g] = gas.oxidation_rate
- if(gas.fire_products)
- fire_products[g] = gas.fire_products
- enthalpies[g] = gas.enthalpy
- else if(gas.fire_temperature)
- fire_temperatures[g] = gas.fire_temperature
- fire_burn_rates[g] = gas.fire_burn_rate
- if(gas.fire_products)
- fire_products[g] = gas.fire_products
- enthalpies[g] = gas.enthalpy
-
- _auxtools_register_gas(gas)
-
-/proc/finalize_gas_refs()
-
-/datum/auxgm/New()
- for(var/gas_path in subtypesof(/datum/gas))
- var/datum/gas/gas = new gas_path
- add_gas(gas)
- for(var/breathing_class_path in subtypesof(/datum/breathing_class))
- var/datum/breathing_class/class = new breathing_class_path
- breathing_classes[breathing_class_path] = class
- finalize_gas_refs()
-
-GLOBAL_DATUM_INIT(gas_data, /datum/auxgm, new)
-
-/obj/effect/overlay/gas
- icon = 'icons/effects/atmospherics.dmi'
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- anchored = TRUE // should only appear in vis_contents, but to be safe
- layer = FLY_LAYER
- appearance_flags = TILE_BOUND
- vis_flags = NONE
-
-/obj/effect/overlay/gas/New(state, alph)
- . = ..()
- icon_state = state
- alpha = alph
diff --git a/code/modules/atmospherics/auxgm/breathing_classes.dm b/code/modules/atmospherics/gasmixtures/breathing_classes.dm
similarity index 67%
rename from code/modules/atmospherics/auxgm/breathing_classes.dm
rename to code/modules/atmospherics/gasmixtures/breathing_classes.dm
index cfc82adbffa16..57d557a89612c 100644
--- a/code/modules/atmospherics/auxgm/breathing_classes.dm
+++ b/code/modules/atmospherics/gasmixtures/breathing_classes.dm
@@ -17,27 +17,36 @@
/datum/breathing_class/proc/get_effective_pp(datum/gas_mixture/breath)
var/mol = 0
for(var/gas in gases)
- mol += breath.get_moles(gas) * gases[gas]
+ mol += GET_MOLES(gas,breath) * gases[gas]
return (mol/breath.total_moles()) * breath.return_pressure()
/datum/breathing_class/oxygen
gases = list(
- GAS_O2 = 1,
- GAS_PLUOXIUM = 8,
- GAS_CO2 = -0.7, // CO2 isn't actually toxic, just an asphyxiant
+ /datum/gas/oxygen = 1,
+ /datum/gas/pluoxium = 8,
+ /datum/gas/carbon_dioxide = -0.7, // CO2 isn't actually toxic, just an asphyxiant
)
products = list(
- GAS_CO2 = 1,
+ /datum/gas/carbon_dioxide = 1,
)
/datum/breathing_class/plasma
gases = list(
- GAS_PLASMA = 1
+ /datum/gas/plasma = 1
)
products = list(
- GAS_CO2 = 1
+ /datum/gas/carbon_dioxide = 1
)
low_alert_category = "not_enough_tox"
low_alert_datum = /atom/movable/screen/alert/not_enough_tox
high_alert_category = "too_much_tox"
high_alert_datum = /atom/movable/screen/alert/too_much_tox
+
+/proc/breathing_class_list()
+ var/list/breathing_classes = list()
+ for(var/breathing_class_path in subtypesof(/datum/breathing_class))
+ var/datum/breathing_class/class = new breathing_class_path
+ breathing_classes[breathing_class_path] = class
+ return breathing_classes
+
+GLOBAL_LIST_INIT(breathing_class_info, breathing_class_list())
diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
index a98e8ab5df44d..b7992759581c0 100644
--- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
@@ -1,306 +1,742 @@
+/**
+ *I feel the need to document what happens here. Basically this is used
+ *catch rounding errors, and make gas go away in small portions.
+ *People have raised it to higher levels in the past, do not do this. Consider this number a soft limit
+ *If you're making gasmixtures that have unexpected behavior related to this value, you're doing something wrong.
+ *
+ *On an unrelated note this may cause a bug that creates negative gas, related to round(). When it has a second arg it will round up.
+ *So for instance round(0.5, 1) == 1. I've hardcoded a fix for this into share, by forcing the garbage collect.
+ *Any other attempts to fix it just killed atmos. I leave this to a greater man then I
+ */
+GLOBAL_LIST_INIT(meta_gas_info, meta_gas_list()) //see ATMOSPHERICS/gas_types.dm
+GLOBAL_LIST_INIT(gaslist_cache, init_gaslist_cache())
+
+/proc/init_gaslist_cache()
+ . = list()
+ for(var/id in GLOB.meta_gas_info)
+ var/list/cached_gas = new(3)
+
+ .[id] = cached_gas
+
+ cached_gas[MOLES] = 0
+ cached_gas[ARCHIVE] = 0
+ cached_gas[GAS_META] = GLOB.meta_gas_info[id]
+
/datum/gas_mixture
- /// Never ever set this variable, hooked into vv_get_var for view variables viewing.
- var/gas_list_view_only
- var/initial_volume = CELL_VOLUME //liters
+ var/list/gases
+ var/temperature = 0 //kelvins
+ var/tmp/temperature_archived = 0
+ var/volume = CELL_VOLUME //liters
+ var/last_share = 0
+ /// The fire key contains information that might determine the volume of hotspots.
var/list/reaction_results
- var/list/analyzer_results //used for analyzer feedback - not initialized until its used
- var/_extools_pointer_gasmixture // Contains the index in the gas vector for this gas mixture in rust land. Don't. Touch. This. Var.
-
-GLOBAL_LIST_INIT(auxtools_atmos_initialized, FALSE)
-
-/proc/auxtools_atmos_init()
+ /// Used for analyzer feedback - not initialized until its used
+ var/list/analyzer_results
+ /// Whether to call garbage_collect() on the sharer during shares, used for immutable mixtures
+ var/gc_share = FALSE
+ /// When this gas mixture was last touched by pipeline processing
+ /// I am sorry
+ var/pipeline_cycle = -1
/datum/gas_mixture/New(volume)
+ gases = new
if (!isnull(volume))
- initial_volume = volume
- AUXTOOLS_CHECK(AUXMOS)
- if(!GLOB.auxtools_atmos_initialized && auxtools_atmos_init())
- GLOB.auxtools_atmos_initialized = TRUE
- __gasmixture_register()
+ src.volume = volume
reaction_results = new
-/*
-we use a hook instead
-/datum/gas_mixture/Del()
- __gasmixture_unregister()
- . = ..()
-*/
-
-/datum/gas_mixture/vv_edit_var(var_name, var_value)
- if(var_name == "_extools_pointer_gasmixture")
- return FALSE // please no. segfaults bad.
- if(var_name == "gas_list_view_only")
- return FALSE
- return ..()
-
-/datum/gas_mixture/vv_get_var(var_name)
- . = ..()
- if(var_name == "gas_list_view_only")
- var/list/dummy = get_gases()
- for(var/gas in dummy)
- dummy[gas] = get_moles(gas)
- dummy["CAP [gas]"] = partial_heat_capacity(gas)
- dummy["TEMP"] = return_temperature()
- dummy["PRESSURE"] = return_pressure()
- dummy["HEAT CAPACITY"] = heat_capacity()
- dummy["TOTAL MOLES"] = total_moles()
- dummy["VOLUME"] = return_volume()
- dummy["THERMAL ENERGY"] = thermal_energy()
- return debug_variable("gases (READ ONLY)", dummy, 0, src)
-
-/datum/gas_mixture/vv_get_dropdown()
- . = ..()
- VV_DROPDOWN_OPTION("", "---")
- VV_DROPDOWN_OPTION(VV_HK_PARSE_GASSTRING, "Parse Gas String")
- VV_DROPDOWN_OPTION(VV_HK_EMPTY, "Empty")
- VV_DROPDOWN_OPTION(VV_HK_SET_MOLES, "Set Moles")
- VV_DROPDOWN_OPTION(VV_HK_SET_TEMPERATURE, "Set Temperature")
- VV_DROPDOWN_OPTION(VV_HK_SET_VOLUME, "Set Volume")
-
-/datum/gas_mixture/vv_do_topic(list/href_list)
- . = ..()
+//listmos procs
+//use the macros in performance intensive areas. for their definitions, refer to code/__DEFINES/atmospherics.dm
+
+ ///assert_gas(gas_id) - used to guarantee that the gas list for this id exists in gas_mixture.gases.
+ //Must be used before adding to a gas. May be used before reading from a gas.
+/datum/gas_mixture/proc/assert_gas(gas_id)
+ ASSERT_GAS(gas_id, src)
+
+ ///assert_gases(args) - shorthand for calling ASSERT_GAS() once for each gas type.
+/datum/gas_mixture/proc/assert_gases(...)
+ for(var/id in args)
+ ASSERT_GAS(id, src)
+
+ ///add_gas(gas_id) - similar to assert_gas(), but does not check for an existing gas list for this id. This can clobber existing gases.
+ ///Used instead of assert_gas() when you know the gas does not exist. Faster than assert_gas().
+/datum/gas_mixture/proc/add_gas(gas_id)
+ ADD_GAS(gas_id, gases)
+
+ ///add_gases(args) - shorthand for calling add_gas() once for each gas_type.
+/datum/gas_mixture/proc/add_gases(...)
+ var/cached_gases = gases
+ for(var/id in args)
+ ADD_GAS(id, cached_gases)
+
+ ///garbage_collect() - removes any gas list which is empty.
+ ///If called with a list as an argument, only removes gas lists with IDs from that list.
+ ///Must be used after subtracting from a gas. Must be used after assert_gas()
+ ///if assert_gas() was called only to read from the gas.
+ ///By removing empty gases, processing speed is increased.
+/datum/gas_mixture/proc/garbage_collect(list/tocheck)
+ var/list/cached_gases = gases
+ for(var/id in (tocheck || cached_gases))
+ if(QUANTIZE(cached_gases[id][MOLES]) <= 0)
+ cached_gases -= id
+
+ //PV = nRT
+
+ ///joules per kelvin
+/datum/gas_mixture/proc/heat_capacity(data = MOLES)
+ var/list/cached_gases = gases
+ . = 0
+ for(var/id in cached_gases)
+ var/gas_data = cached_gases[id]
+ . += gas_data[data] * gas_data[GAS_META][META_GAS_SPECIFIC_HEAT]
+
+ /// Same as above except vacuums return HEAT_CAPACITY_VACUUM
+/datum/gas_mixture/turf/heat_capacity(data = MOLES)
+ var/list/cached_gases = gases
+ . = 0
+ for(var/id in cached_gases)
+ var/gas_data = cached_gases[id]
+ . += gas_data[data] * gas_data[GAS_META][META_GAS_SPECIFIC_HEAT]
if(!.)
- return
- if(href_list[VV_HK_PARSE_GASSTRING])
- var/gasstring = input(usr, "Input Gas String (WARNING: Advanced. Don't use this unless you know how these work.", "Gas String Parse") as text|null
- if(!istext(gasstring))
- return
- log_admin("[key_name(usr)] modified gas mixture [REF(src)]: Set to gas string [gasstring].")
- message_admins("[key_name(usr)] modified gas mixture [REF(src)]: Set to gas string [gasstring].")
- parse_gas_string(gasstring)
- if(href_list[VV_HK_EMPTY])
- log_admin("[key_name(usr)] emptied gas mixture [REF(src)].")
- message_admins("[key_name(usr)] emptied gas mixture [REF(src)].")
- clear()
- if(href_list[VV_HK_SET_MOLES])
- var/list/gases = get_gases()
- for(var/gas in gases)
- gases[gas] = get_moles(gas)
- var/gasid = input(usr, "What kind of gas?", "Set Gas") as null|anything in GLOB.gas_data.ids
- if(!gasid)
- return
- var/amount = input(usr, "Input amount", "Set Gas", gases[gasid] || 0) as num|null
- if(!isnum(amount))
- return
- amount = max(0, amount)
- log_admin("[key_name(usr)] modified gas mixture [REF(src)]: Set gas [gasid] to [amount] moles.")
- message_admins("[key_name(usr)] modified gas mixture [REF(src)]: Set gas [gasid] to [amount] moles.")
- set_moles(gasid, amount)
- if(href_list[VV_HK_SET_TEMPERATURE])
- var/temp = input(usr, "Set the temperature of this mixture to?", "Set Temperature", return_temperature()) as num|null
- if(!isnum(temp))
- return
- temp = max(2.7, temp)
- log_admin("[key_name(usr)] modified gas mixture [REF(src)]: Changed temperature to [temp].")
- message_admins("[key_name(usr)] modified gas mixture [REF(src)]: Changed temperature to [temp].")
- set_temperature(temp)
- if(href_list[VV_HK_SET_VOLUME])
- var/volume = input(usr, "Set the volume of this mixture to?", "Set Volume", return_volume()) as num|null
- if(!isnum(volume))
- return
- volume = max(0, volume)
- log_admin("[key_name(usr)] modified gas mixture [REF(src)]: Changed volume to [volume].")
- message_admins("[key_name(usr)] modified gas mixture [REF(src)]: Changed volume to [volume].")
- set_volume(volume)
-
-/datum/gas_mixture/proc/__gasmixture_unregister()
-/datum/gas_mixture/proc/__gasmixture_register()
-
-/proc/gas_types()
- var/list/L = subtypesof(/datum/gas)
- for(var/gt in L)
- var/datum/gas/G = gt
- L[gt] = initial(G.specific_heat)
- return L
-
-/datum/gas_mixture/proc/heat_capacity() //joules per kelvin
-
-/datum/gas_mixture/proc/partial_heat_capacity(gas_type)
+ . += HEAT_CAPACITY_VACUUM //we want vacuums in turfs to have the same heat capacity as space
+ /// Calculate moles
/datum/gas_mixture/proc/total_moles()
+ var/cached_gases = gases
+ TOTAL_MOLES(cached_gases, .)
+
+/// Checks to see if gas amount exists in mixture.
+/// Do NOT use this in code where performance matters!
+/// It's better to batch calls to garbage_collect(), especially in places where you're checking many gastypes
+/datum/gas_mixture/proc/has_gas(gas_id, amount=0)
+ ASSERT_GAS(gas_id, src)
+ var/is_there_gas = amount < gases[gas_id][MOLES]
+ garbage_collect()
+ return is_there_gas
+
+/// Calculate pressure in kilopascals
+/datum/gas_mixture/proc/return_pressure()
+ if(volume) // to prevent division by zero
+ var/cached_gases = gases
+ TOTAL_MOLES(cached_gases, .)
+ . *= R_IDEAL_GAS_EQUATION * temperature / volume
+ return
+ return 0
-/datum/gas_mixture/proc/return_pressure() //kilopascals
+ /// Calculate temperature in kelvins
+/datum/gas_mixture/proc/return_temperature()
+ return temperature
-/datum/gas_mixture/proc/return_temperature() //kelvins
+ /// Calculate volume in liters
+/datum/gas_mixture/proc/return_volume()
+ return max(0, volume)
-/datum/gas_mixture/proc/set_min_heat_capacity(n)
-/datum/gas_mixture/proc/set_temperature(new_temp)
-/datum/gas_mixture/proc/set_volume(new_volume)
-/datum/gas_mixture/proc/get_moles(gas_type)
-/datum/gas_mixture/proc/get_by_flag(flag)
-/datum/gas_mixture/proc/set_moles(gas_type, moles)
-/datum/gas_mixture/proc/scrub_into(datum/gas_mixture/target, ratio, list/gases)
-/datum/gas_mixture/proc/mark_immutable()
-/datum/gas_mixture/proc/get_gases()
-/datum/gas_mixture/proc/add(amt)
-/datum/gas_mixture/proc/subtract(amt)
-/datum/gas_mixture/proc/multiply(factor)
-/datum/gas_mixture/proc/divide(factor)
-/datum/gas_mixture/proc/get_last_share()
-/datum/gas_mixture/proc/clear()
+ /// Calculate thermal energy in joules
+/datum/gas_mixture/proc/thermal_energy()
+ return THERMAL_ENERGY(src) //see code/__DEFINES/atmospherics.dm; use the define in performance critical areas
-/datum/gas_mixture/proc/adjust_moles(gas_type, amt = 0)
- set_moles(gas_type, clamp(get_moles(gas_type) + amt,0,INFINITY))
+ ///Update archived versions of variables. Returns: 1 in all cases
+/datum/gas_mixture/proc/archive()
+ var/list/cached_gases = gases
-/datum/gas_mixture/proc/adjust_moles_temp(gas_type, amt, temperature)
+ temperature_archived = temperature
+ for(var/id in cached_gases)
+ cached_gases[id][ARCHIVE] = cached_gases[id][MOLES]
-/datum/gas_mixture/proc/adjust_multi()
+ return TRUE
-/datum/gas_mixture/proc/return_volume() //liters
+ ///Merges all air from giver into self. Deletes giver. Returns: 1 if we are mutable, 0 otherwise
+/datum/gas_mixture/proc/merge(datum/gas_mixture/giver)
+ if(!giver)
+ return FALSE
-/datum/gas_mixture/proc/thermal_energy() //joules
+ //heat transfer
+ if(abs(temperature - giver.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)
+ temperature = (giver.temperature * giver_heat_capacity + temperature * self_heat_capacity) / combined_heat_capacity
+
+ var/list/cached_gases = gases //accessing datum vars is slower than proc vars
+ var/list/giver_gases = giver.gases
+ //gas transfer
+ for(var/giver_id in giver_gases)
+ ASSERT_GAS_IN_LIST(giver_id, cached_gases)
+ cached_gases[giver_id][MOLES] += giver_gases[giver_id][MOLES]
+
+ return TRUE
+
+ ///Proportionally removes amount of gas from the gas_mixture.
+ ///Returns: gas_mixture with the gases removed
+/datum/gas_mixture/proc/remove(amount)
+ var/sum
+ var/list/cached_gases = gases
+ TOTAL_MOLES(cached_gases, sum)
+ amount = min(amount, sum) //Can not take more air than tile has!
+ if(amount <= 0)
+ return null
+ var/ratio = amount / sum
+ var/datum/gas_mixture/removed = new type
+ var/list/removed_gases = removed.gases //accessing datum vars is slower than proc vars
-/datum/gas_mixture/proc/archive()
- //Update archived versions of variables
- //Returns: 1 in all cases
+ removed.temperature = temperature
+ for(var/id in cached_gases)
+ ADD_GAS(id, removed.gases)
+ removed_gases[id][MOLES] = QUANTIZE(cached_gases[id][MOLES] * ratio)
+ cached_gases[id][MOLES] -= removed_gases[id][MOLES]
+ garbage_collect()
-/datum/gas_mixture/proc/merge(datum/gas_mixture/giver)
- //Merges all air from giver into self. Does NOT delete the giver.
- //Returns: 1 if we are mutable, 0 otherwise
+ return removed
-/datum/gas_mixture/proc/remove(amount)
- //Proportionally removes amount of gas from the gas_mixture
- //Returns: gas_mixture with the gases removed
+ ///Proportionally removes amount of gas from the gas_mixture.
+ ///Returns: gas_mixture with the gases removed
+/datum/gas_mixture/proc/remove_ratio(ratio)
+ if(ratio <= 0)
+ return null
+ ratio = min(ratio, 1)
-/datum/gas_mixture/proc/remove_by_flag(flag, amount)
- //Removes amount of gas from the gas mixture by flag
- //Returns: gas_mixture with gases that match the flag removed
+ var/list/cached_gases = gases
+ var/datum/gas_mixture/removed = new type
+ var/list/removed_gases = removed.gases //accessing datum vars is slower than proc vars
-/datum/gas_mixture/proc/transfer_to(datum/gas_mixture/target, amount)
+ removed.temperature = temperature
+ for(var/id in cached_gases)
+ ADD_GAS(id, removed.gases)
+ removed_gases[id][MOLES] = QUANTIZE(cached_gases[id][MOLES] * ratio)
+ cached_gases[id][MOLES] -= removed_gases[id][MOLES]
-/datum/gas_mixture/proc/transfer_ratio_to(datum/gas_mixture/target, ratio)
- //Transfers ratio of gas to target. Equivalent to target.merge(remove_ratio(amount)) but faster.
+ garbage_collect()
-/datum/gas_mixture/proc/remove_ratio(ratio)
- //Proportionally removes amount of gas from the gas_mixture
- //Returns: gas_mixture with the gases removed
+ return removed
+
+ ///Removes an amount of a specific gas from the gas_mixture.
+ ///Returns: gas_mixture with the gas removed
+/datum/gas_mixture/proc/remove_specific(gas_id, amount)
+ var/list/cached_gases = gases
+ amount = min(amount, cached_gases[gas_id][MOLES])
+ if(amount <= 0)
+ return null
+ var/datum/gas_mixture/removed = new type
+ var/list/removed_gases = removed.gases
+ removed.temperature = temperature
+ ADD_GAS(gas_id, removed.gases)
+ removed_gases[gas_id][MOLES] = amount
+ cached_gases[gas_id][MOLES] -= amount
+
+ garbage_collect(list(gas_id))
+ return removed
+ ///Distributes the contents of two mixes equally between themselves
+ //Returns: bool indicating whether gases moved between the two mixes
+/datum/gas_mixture/proc/equalize(datum/gas_mixture/other)
+ . = FALSE
+ if(abs(return_temperature() - other.return_temperature()) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
+ . = TRUE
+ var/self_heat_cap = heat_capacity()
+ var/other_heat_cap = other.heat_capacity()
+ var/new_temp = (temperature * self_heat_cap + other.temperature * other_heat_cap) / (self_heat_cap + other_heat_cap)
+ temperature = new_temp
+ other.temperature = new_temp
+
+ var/min_p_delta = 0.1
+ var/total_volume = volume + other.volume
+ var/list/gas_list = gases | other.gases
+ for(var/gas_id in gas_list)
+ assert_gas(gas_id)
+ other.assert_gas(gas_id)
+ //math is under the assumption temperatures are equal
+ if(abs(gases[gas_id][MOLES] / volume - other.gases[gas_id][MOLES] / other.volume) > min_p_delta / (R_IDEAL_GAS_EQUATION * temperature))
+ . = TRUE
+ var/total_moles = gases[gas_id][MOLES] + other.gases[gas_id][MOLES]
+ gases[gas_id][MOLES] = total_moles * (volume/total_volume)
+ other.gases[gas_id][MOLES] = total_moles * (other.volume/total_volume)
+
+
+ ///Creates new, identical gas mixture
+ ///Returns: duplicate gas mixture
/datum/gas_mixture/proc/copy()
- //Creates new, identical gas mixture
- //Returns: duplicate gas mixture
+ // Type as /list/list to make spacemandmm happy with the inlined access we do down there
+ var/list/list/cached_gases = gases
+ var/datum/gas_mixture/copy = new type
+ var/list/copy_gases = copy.gases
+ copy.temperature = temperature
+ for(var/id in cached_gases)
+ // Sort of a sideways way of doing ADD_GAS()
+ // Faster tho, gotta save those cpu cycles
+ copy_gases[id] = cached_gases[id].Copy()
+ copy_gases[id][ARCHIVE] = 0
+
+ return copy
+
+
+///Copies variables from sample
+///Returns: TRUE if we are mutable, FALSE otherwise
/datum/gas_mixture/proc/copy_from(datum/gas_mixture/sample)
- //Copies variables from sample
- //Returns: 1 if we are mutable, 0 otherwise
+ var/list/cached_gases = gases //accessing datum vars is slower than proc vars
+ // Type as /list/list to make spacemandmm happy with the inlined access we do down there
+ var/list/list/sample_gases = sample.gases
-/datum/gas_mixture/proc/copy_from_turf(turf/model)
- //Copies all gas info from the turf into the gas list along with temperature
- //Returns: 1 if we are mutable, 0 otherwise
+ //remove all gases
+ cached_gases.Cut()
-/datum/gas_mixture/proc/parse_gas_string(gas_string)
- //Copies variables from a particularly formatted string.
- //Returns: 1 if we are mutable, 0 otherwise
+ temperature = sample.temperature
+ for(var/id in sample_gases)
+ cached_gases[id] = sample_gases[id].Copy()
+ cached_gases[id][ARCHIVE] = 0
-/datum/gas_mixture/proc/share(datum/gas_mixture/sharer)
- //Performs air sharing calculations between two gas_mixtures assuming only 1 boundary length
- //Returns: amount of gas exchanged (+ if sharer received)
+ return TRUE
-/datum/gas_mixture/proc/temperature_share(datum/gas_mixture/sharer, conduction_coefficient)
- //Performs temperature sharing calculations (via conduction) between two gas_mixtures assuming only 1 boundary length
- //Returns: new temperature of the sharer
+///Copies variables from sample, moles multiplicated by partial
+///Returns: TRUE if we are mutable, FALSE otherwise
+/datum/gas_mixture/proc/copy_from_ratio(datum/gas_mixture/sample, partial = 1)
+ var/list/cached_gases = gases //accessing datum vars is slower than proc vars
+ var/list/sample_gases = sample.gases
-/datum/gas_mixture/proc/compare(datum/gas_mixture/sample)
- //Compares sample to self to see if within acceptable ranges that group processing may be enabled
- //Returns: a string indicating what check failed, or "" if check passes
+ //remove all gases not in the sample
+ cached_gases &= sample_gases
+
+ temperature = sample.temperature
+ for(var/id in sample_gases)
+ ASSERT_GAS_IN_LIST(id, cached_gases)
+ cached_gases[id][MOLES] = sample_gases[id][MOLES] * partial
-/datum/gas_mixture/proc/react(turf/open/dump_location)
- //Performs various reactions such as combustion or fusion (LOL)
- //Returns: 1 if any reaction took place; 0 otherwise
+ return TRUE
-/datum/gas_mixture/proc/adjust_heat(amt)
- //Adjusts the thermal energy of the gas mixture, rather than having to do the full calculation.
- //Returns: null
+ ///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)
+ parse_gas_string(model.initial_gas_mix)
-/datum/gas_mixture/proc/equalize_with(datum/gas_mixture/giver)
- //Makes this mix have the same temperature and gas ratios as the giver, but with the same pressure, accounting for volume.
- //Returns: null
+ //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
-/datum/gas_mixture/proc/get_oxidation_power(temp)
- //Gets how much oxidation this gas can do, optionally at a given temperature.
+ return TRUE
-/datum/gas_mixture/proc/get_fuel_amount(temp)
- //Gets how much fuel for fires (not counting trit/plasma!) this gas has, optionally at a given temperature.
+ ///Copies variables from a particularly formatted string.
+ ///Returns: 1 if we are mutable, 0 otherwise
+/datum/gas_mixture/proc/parse_gas_string(gas_string)
+ gas_string = SSair.preprocess_gas_string(gas_string)
+
+ var/list/gases = src.gases
+ var/list/gas = params2list(gas_string)
+ if(gas["TEMP"])
+ temperature = text2num(gas["TEMP"])
+ temperature_archived = temperature
+ gas -= "TEMP"
+ else // if we do not have a temp in the new gas mix lets assume room temp.
+ temperature = T20C
+ gases.Cut()
+ for(var/id in gas)
+ var/path = id
+ if(!ispath(path))
+ path = gas_id2path(path) //a lot of these strings can't have embedded expressions (especially for mappers), so support for IDs needs to stick around
+ ADD_GAS(path, gases)
+ gases[path][MOLES] = text2num(gas[id])
+ return 1
-/proc/equalize_all_gases_in_list(list/L)
- //Makes every gas in the given list have the same pressure, temperature and gas proportions.
- //Returns: null
+/// Performs air sharing calculations between two gas_mixtures
+/// share() is communitive, which means A.share(B) needs to be the same as B.share(A)
+/// If we don't retain this, we will get negative moles. Don't do it
+/// Returns: amount of gas exchanged (+ if sharer received)
+/datum/gas_mixture/proc/share(datum/gas_mixture/sharer, our_coeff, sharer_coeff)
+ var/list/cached_gases = gases
+ var/list/sharer_gases = sharer.gases
+
+ var/list/only_in_sharer = sharer_gases - cached_gases
+ var/list/only_in_cached = cached_gases - sharer_gases
+
+ var/temperature_delta = temperature_archived - sharer.temperature_archived
+ var/abs_temperature_delta = abs(temperature_delta)
+
+ var/old_self_heat_capacity = 0
+ var/old_sharer_heat_capacity = 0
+ if(abs_temperature_delta > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ old_self_heat_capacity = heat_capacity()
+ old_sharer_heat_capacity = sharer.heat_capacity()
+
+ var/heat_capacity_self_to_sharer = 0 //heat capacity of the moles transferred from us to the sharer
+ var/heat_capacity_sharer_to_self = 0 //heat capacity of the moles transferred from the sharer to us
+
+ var/moved_moles = 0
+ var/abs_moved_moles = 0
+
+ //GAS TRANSFER
+
+ //Prep
+ for(var/id in only_in_sharer) //create gases not in our cache
+ ADD_GAS(id, cached_gases)
+ for(var/id in only_in_cached) //create gases not in the sharing mix
+ ADD_GAS(id, sharer_gases)
+
+ for(var/id in cached_gases) //transfer gases
+ var/gas = cached_gases[id]
+ var/sharergas = sharer_gases[id]
+ var/delta = QUANTIZE(gas[ARCHIVE] - sharergas[ARCHIVE]) //the amount of gas that gets moved between the mixtures
+
+ if(!delta)
+ continue
+
+ // If we have more gas then they do, gas is moving from us to them
+ // This means we want to scale it by our coeff. Vis versa for their case
+ if(delta > 0)
+ delta = delta * our_coeff
+ else
+ delta = delta * sharer_coeff
+
+ if(abs_temperature_delta > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ var/gas_heat_capacity = delta * gas[GAS_META][META_GAS_SPECIFIC_HEAT]
+ if(delta > 0)
+ heat_capacity_self_to_sharer += gas_heat_capacity
+ else
+ heat_capacity_sharer_to_self -= gas_heat_capacity //subtract here instead of adding the absolute value because we know that delta is negative.
+
+ gas[MOLES] -= delta
+ sharergas[MOLES] += delta
+ moved_moles += delta
+ abs_moved_moles += abs(delta)
+
+ last_share = abs_moved_moles
+
+ //THERMAL ENERGY TRANSFER
+ if(abs_temperature_delta > 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
+
+ //transfer of thermal energy (via changed heat capacity) between self and sharer
+ 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
+
+ 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
+ //thermal energy of the system (self and sharer) is unchanged
+
+ if(abs(old_sharer_heat_capacity) > MINIMUM_HEAT_CAPACITY)
+ if(abs(new_sharer_heat_capacity/old_sharer_heat_capacity - 1) < 0.1) // <10% change in sharer heat capacity
+ temperature_share(sharer, OPEN_HEAT_TRANSFER_COEFFICIENT)
+
+ if(length(only_in_sharer + only_in_cached)) //if all gases were present in both mixtures, we know that no gases are 0
+ garbage_collect(only_in_cached) //any gases the sharer had, we are guaranteed to have. gases that it didn't have we are not.
+ sharer.garbage_collect(only_in_sharer) //the reverse is equally true
+ else if (initial(sharer.gc_share))
+ sharer.garbage_collect()
+
+ if(temperature_delta > MINIMUM_TEMPERATURE_TO_MOVE || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
+ var/our_moles
+ TOTAL_MOLES(cached_gases,our_moles)
+ var/their_moles
+ TOTAL_MOLES(sharer_gases,their_moles)
+ return (temperature_archived*(our_moles + moved_moles) - sharer.temperature_archived*(their_moles - moved_moles)) * R_IDEAL_GAS_EQUATION / volume
+
+ ///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, sharer_temperature, sharer_heat_capacity)
+ //transfer of thermal energy (via conduction) between self and sharer
+ if(sharer)
+ sharer_temperature = sharer.temperature_archived
+ var/temperature_delta = temperature_archived - sharer_temperature
+ if(abs(temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
+ var/self_heat_capacity = heat_capacity(ARCHIVE)
+ sharer_heat_capacity = sharer_heat_capacity || sharer.heat_capacity(ARCHIVE)
+
+ if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY))
+ // coefficient applied first because some turfs have very big heat caps.
+ var/heat = CALCULATE_CONDUCTION_ENERGY(conduction_coefficient * temperature_delta, sharer_heat_capacity, self_heat_capacity)
+
+ temperature = max(temperature - heat/self_heat_capacity, TCMB)
+ sharer_temperature = max(sharer_temperature + heat/sharer_heat_capacity, TCMB)
+ if(sharer)
+ sharer.temperature = sharer_temperature
+ if (initial(sharer.gc_share))
+ sharer.garbage_collect()
+ return sharer_temperature
+ //thermal energy of the system (self and sharer) is unchanged
+
+ ///Compares sample to self to see if within acceptable ranges that group processing may be enabled
+ ///Returns: a string indicating what check failed, or "" if check passes
+/datum/gas_mixture/proc/compare(datum/gas_mixture/sample)
+ var/list/sample_gases = sample.gases //accessing datum vars is slower than proc vars
+ var/list/cached_gases = gases
+ var/moles_sum = 0
+
+ for(var/id in cached_gases | sample_gases) // compare gases from either mixture
+ // Yes this is actually fast. I too hate it here
+ var/gas_moles = cached_gases[id]?[MOLES] || 0
+ var/sample_moles = sample_gases[id]?[MOLES] || 0
+ // Brief explanation. We are much more likely to not pass this first check then pass the first and fail the second
+ // Because of this, double calculating the delta is FASTER then inserting it into a var
+ if(abs(gas_moles - sample_moles) > MINIMUM_MOLES_DELTA_TO_MOVE)
+ if(abs(gas_moles - sample_moles) > gas_moles * MINIMUM_AIR_RATIO_TO_MOVE)
+ return id
+ // similarly, we will rarely get cut off, so this is cheaper then doing it later
+ moles_sum += gas_moles
+
+ if(moles_sum > MINIMUM_MOLES_DELTA_TO_MOVE) //Don't consider temp if there's not enough mols
+ if(abs(temperature - sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND)
+ return "temp"
+
+ return ""
+
+ ///Performs various reactions such as combustion or fusion (LOL)
+ ///Returns: 1 if any reaction took place; 0 otherwise
+/datum/gas_mixture/proc/react(datum/holder)
+ . = NO_REACTION
+ var/list/cached_gases = gases
+ if(!length(cached_gases))
+ return
-/datum/gas_mixture/proc/__remove_by_flag()
+ var/list/pre_formation = list()
+ var/list/mid_formation = list()
+ var/list/post_formation = list()
+ var/list/fires = list()
+ var/list/gas_reactions = SSair.gas_reactions
+ for(var/gas_id in cached_gases)
+ var/list/reaction_set = gas_reactions[gas_id]
+ if(!reaction_set)
+ continue
+ pre_formation += reaction_set[1]
+ mid_formation += reaction_set[2]
+ post_formation += reaction_set[3]
+ fires += reaction_set[4]
+
+ var/list/reactions = pre_formation + mid_formation + post_formation + fires
+
+ if(!length(reactions))
+ return
-/datum/gas_mixture/remove_by_flag(flag, amount)
- var/datum/gas_mixture/removed = new type
- __remove_by_flag(removed, flag, amount)
+ //Fuck you
+ if(cached_gases[/datum/gas/hypernoblium] && cached_gases[/datum/gas/hypernoblium][MOLES] >= REACTION_OPPRESSION_THRESHOLD && temperature > 20)
+ return STOP_REACTIONS
- return removed
+ reaction_results = new
+ //It might be worth looking into updating these after each reaction, but that makes us care more about order of operations, so be careful
+ var/temp = temperature
+ reaction_loop:
+ for(var/datum/gas_reaction/reaction as anything in reactions)
+
+ var/list/reqs = reaction.requirements
+ if((reqs["MIN_TEMP"] && temp < reqs["MIN_TEMP"]) || (reqs["MAX_TEMP"] && temp > reqs["MAX_TEMP"]))
+ continue
+
+ for(var/id in reqs)
+ if (id == "MIN_TEMP" || id == "MAX_TEMP")
+ continue
+ if(!cached_gases[id] || cached_gases[id][MOLES] < reqs[id])
+ continue reaction_loop
+
+ //at this point, all requirements for the reaction are satisfied. we can now react()
+ . |= reaction.react(src, holder)
+
+
+ if(.) //If we changed the mix to any degree
+ garbage_collect()
+
+
+/**
+ * Takes the amount of the gas you want to PP as an argument
+ * So I don't have to do some hacky switches/defines/magic strings
+ * eg:
+ * Plas_PP = get_partial_pressure(gas_mixture.plasma)
+ * O2_PP = get_partial_pressure(gas_mixture.oxygen)
+ * get_breath_partial_pressure(gas_pp) --> gas_pp/total_moles()*breath_pp = pp
+ * get_true_breath_pressure(pp) --> gas_pp = pp/breath_pp*total_moles()
+ *
+ * 10/20*5 = 2.5
+ * 10 = 2.5/5*20
+ */
+
+/datum/gas_mixture/proc/get_breath_partial_pressure(gas_pressure)
+ return (gas_pressure * R_IDEAL_GAS_EQUATION * temperature) / BREATH_VOLUME
+///inverse
+/datum/gas_mixture/proc/get_true_breath_pressure(partial_pressure)
+ return (partial_pressure * BREATH_VOLUME) / (R_IDEAL_GAS_EQUATION * temperature)
+
+/**
+ * Counts how much pressure will there be if we impart MOLAR_ACCURACY amounts of our gas to the output gasmix.
+ * We do all of this without actually transferring it so dont worry about it changing the gasmix.
+ * Returns: Resulting pressure (number).
+ * Args:
+ * - output_air (gasmix).
+ */
+/datum/gas_mixture/proc/gas_pressure_minimum_transfer(datum/gas_mixture/output_air)
+ var/resulting_energy = output_air.thermal_energy() + (MOLAR_ACCURACY / total_moles() * thermal_energy())
+ var/resulting_capacity = output_air.heat_capacity() + (MOLAR_ACCURACY / total_moles() * heat_capacity())
+ return (output_air.total_moles() + MOLAR_ACCURACY) * R_IDEAL_GAS_EQUATION * (resulting_energy / resulting_capacity) / output_air.volume
+
+
+/** Returns the amount of gas to be pumped to a specific container.
+ * Args:
+ * - output_air. The gas mix we want to pump to.
+ * - target_pressure. The target pressure we want.
+ * - ignore_temperature. Returns a cheaper form of gas calculation, useful if the temperature difference between the two gasmixes is low or nonexistant.
+ */
+/datum/gas_mixture/proc/gas_pressure_calculate(datum/gas_mixture/output_air, target_pressure, ignore_temperature = FALSE)
+ if((total_moles() <= 0) || (temperature <= 0))
+ return FALSE
-/datum/gas_mixture/proc/__remove()
-/datum/gas_mixture/remove(amount)
- var/datum/gas_mixture/removed = new type
- __remove(removed, amount)
+ var/pressure_delta = 0
+ if((output_air.temperature <= 0) || (output_air.total_moles() <= 0))
+ ignore_temperature = TRUE
+ pressure_delta = target_pressure
+ else
+ pressure_delta = target_pressure - output_air.return_pressure()
- return removed
+ if(pressure_delta < 0.01 || gas_pressure_minimum_transfer(output_air) > target_pressure)
+ return FALSE
-/datum/gas_mixture/proc/__remove_ratio()
-/datum/gas_mixture/remove_ratio(ratio)
- var/datum/gas_mixture/removed = new type
- __remove_ratio(removed, ratio)
+ if(ignore_temperature)
+ return (pressure_delta*output_air.volume)/(temperature * R_IDEAL_GAS_EQUATION)
+
+ // Lower and upper bound for the moles we must transfer to reach the pressure. The answer is bound to be here somewhere.
+ var/pv = target_pressure * output_air.volume
+ var/rt_low = R_IDEAL_GAS_EQUATION * max(temperature, output_air.temperature) // Low refers to the resulting mole, this number is actually higher.
+ var/rt_high = R_IDEAL_GAS_EQUATION * min(temperature, output_air.temperature)
+ // These works by assuming our gas has extremely high heat capacity
+ // and the resultant gasmix will hit either the highest or lowest temperature possible.
+ var/lower_limit = max((pv / rt_low) - output_air.total_moles(), 0)
+ var/upper_limit = (pv / rt_high) - output_air.total_moles() // In theory this should never go below zero, the pressure_delta check above should account for this.
+
+ /*
+ * We have PV=nRT as a nice formula, we can rearrange it into nT = PV/R
+ * But now both n and T can change, since any incoming moles also change our temperature.
+ * So we need to unify both our n and T, somehow.
+ *
+ * We can rewrite T as (our old thermal energy + incoming thermal energy) divided by (our old heat capacity + incoming heat capacity)
+ * T = (W1 + n/N2 * W2) / (C1 + n/N2 * C2). C being heat capacity, W being work, N being total moles.
+ *
+ * In total we now have our equation be: (N1 + n) * (W1 + n/N2 * W2) / (C1 + n/N2 * C2) = PV/R
+ * Now you can rearrange this and find out that it's a quadratic equation and pretty much solvable with the formula. Will be a bit messy though.
+ *
+ * W2/N2n^2 +
+ * (N1*W2/N2)n + W1n - ((PV/R)*C2/N2)n +
+ * (-(PV/R)*C1) + N1W1 = 0
+ *
+ * We will represent each of these terms with A, B, and C. A for the n^2 part, B for the n^1 part, and C for the n^0 part.
+ * We then put this into the famous (-b +/- sqrt(b^2-4ac)) / 2a formula.
+ *
+ * Oh, and one more thing. By "our" we mean the gasmix in the argument. We are the incoming one here. We are number 2, target is number 1.
+ * If all this counting fucks up, we revert first to Newton's approximation, then the old simple formula.
+ */
+
+ // Our thermal energy and moles
+ var/w2 = thermal_energy()
+ var/n2 = total_moles()
+ var/c2 = heat_capacity()
+
+ // Target thermal energy and moles
+ var/w1 = output_air.thermal_energy()
+ var/n1 = output_air.total_moles()
+ var/c1 = output_air.heat_capacity()
+
+ /// The PV/R part in our equation.
+ var/pvr = pv / R_IDEAL_GAS_EQUATION
+
+ /// x^2 in the quadratic
+ var/a_value = w2/n2
+ /// x^1 in the quadratic
+ var/b_value = ((n1*w2)/n2) + w1 - (pvr*c2/n2)
+ /// x^0 in the quadratic
+ var/c_value = (-1*pvr*c1) + n1 * w1
+
+ . = gas_pressure_quadratic(a_value, b_value, c_value, lower_limit, upper_limit)
+ if(.)
+ return
+ . = gas_pressure_approximate(a_value, b_value, c_value, lower_limit, upper_limit)
+ if(.)
+ return
+ // Inaccurate and will probably explode but whatever.
+ return (pressure_delta*output_air.volume)/(temperature * R_IDEAL_GAS_EQUATION)
+
+/// Actually tries to solve the quadratic equation.
+/// Do mind that the numbers can get very big and might hit BYOND's single point float limit.
+/datum/gas_mixture/proc/gas_pressure_quadratic(a, b, c, lower_limit, upper_limit)
+ var/solution
+ if(!IS_INF_OR_NAN(a) && !IS_INF_OR_NAN(b) && !IS_INF_OR_NAN(c))
+ solution = max(SolveQuadratic(a, b, c))
+ if((solution > lower_limit) && (solution < upper_limit)) //SolveQuadratic can return nulls so be careful here
+ return solution
+ stack_trace("Failed to solve pressure quadratic equation. A: [a]. B: [b]. C:[c]. Current value = [solution]. Expected lower limit: [lower_limit]. Expected upper limit: [upper_limit].")
+ return FALSE
- return removed
+/// Approximation of the quadratic equation using Newton-Raphson's Method.
+/// We use the slope of an approximate value to get closer to the root of a given equation.
+/datum/gas_mixture/proc/gas_pressure_approximate(a, b, c, lower_limit, upper_limit)
+ var/solution
+ if(!IS_INF_OR_NAN(a) && !IS_INF_OR_NAN(b) && !IS_INF_OR_NAN(c))
+ /// We need to start off at a reasonably good estimate. For very big numbers the amount of moles is most likely small so better start with lower_limit.
+ solution = lower_limit
+ for (var/iteration in 1 to ATMOS_PRESSURE_APPROXIMATION_ITERATIONS)
+ var/diff = (a*solution**2 + b*solution + c) / (2*a*solution + b) // f(sol) / f'(sol)
+ solution -= diff // xn+1 = xn - f(sol) / f'(sol)
+ if(abs(diff) < MOLAR_ACCURACY && (solution > lower_limit) && (solution < upper_limit))
+ return solution
+ stack_trace("Newton's Approximation for pressure failed after [ATMOS_PRESSURE_APPROXIMATION_ITERATIONS] iterations. A: [a]. B: [b]. C:[c]. Current value: [solution]. Expected lower limit: [lower_limit]. Expected upper limit: [upper_limit].")
+ return FALSE
-/datum/gas_mixture/copy()
- var/datum/gas_mixture/copy = new type
- copy.copy_from(src)
+/datum/gas_mixture/proc/remove_specific_ratio(gas_id, ratio)
+ if(ratio <= 0)
+ return null
+ ratio = min(ratio, 1)
- return copy
+ var/list/cached_gases = gases
+ var/datum/gas_mixture/removed = new type
+ var/list/removed_gases = removed.gases //accessing datum vars is slower than proc vars
-/datum/gas_mixture/copy_from_turf(turf/model)
- set_temperature(initial(model.initial_temperature))
- parse_gas_string(model.initial_gas_mix)
- return 1
+ removed.temperature = temperature
+ ADD_GAS(gas_id, removed.gases)
+ removed_gases[gas_id][MOLES] = QUANTIZE(cached_gases[gas_id][MOLES] * ratio)
+ cached_gases[gas_id][MOLES] -= removed_gases[gas_id][MOLES]
+
+ garbage_collect(list(gas_id))
-/datum/gas_mixture/proc/__auxtools_parse_gas_string(gas_string)
+ return removed
-/datum/gas_mixture/parse_gas_string(gas_string)
- return __auxtools_parse_gas_string(gas_string)
+/// Pumps gas from src to output_air. Amount depends on target_pressure
+/datum/gas_mixture/proc/pump_gas_to(datum/gas_mixture/output_air, target_pressure, specific_gas = null, datum/gas_mixture/output_pipenet_air = null)
+ var/datum/gas_mixture/input_air = specific_gas ? remove_specific_ratio(specific_gas, 1) : src
+ var/temperature_delta = abs(input_air.temperature - output_air.temperature)
+ var/datum/gas_mixture/removed
-/datum/gas_mixture/proc/set_analyzer_results(instability)
- if(!analyzer_results)
- analyzer_results = new
- analyzer_results["fusion"] = instability
+ var/transfer_moles_output = input_air.gas_pressure_calculate(output_air, target_pressure, temperature_delta <= 5)
+ var/transfer_moles_pipenet = output_pipenet_air?.volume ? input_air.gas_pressure_calculate(output_pipenet_air, target_pressure, temperature_delta <= 5) : 0
+ var/transfer_moles = max(transfer_moles_output, transfer_moles_pipenet)
-//Mathematical proofs:
-/*
-get_breath_partial_pressure(gas_pp) --> gas_pp/total_moles()*breath_pp = pp
-get_true_breath_pressure(pp) --> gas_pp = pp/breath_pp*total_moles()
+ if(specific_gas)
+ removed = input_air.remove_specific(specific_gas, transfer_moles)
+ merge(input_air) // Merge the remaining gas back to the input node
+ else
+ removed = input_air.remove(transfer_moles)
-10/20*5 = 2.5
-10 = 2.5/5*20
-*/
+ if(!removed)
+ return FALSE
-/datum/gas_mixture/turf
+ output_air.merge(removed)
+ return removed
/// Releases gas from src to output air. This means that it can not transfer air to gas mixture with higher pressure.
-/datum/gas_mixture/proc/release_gas_to(datum/gas_mixture/output_air, target_pressure)
+/datum/gas_mixture/proc/release_gas_to(datum/gas_mixture/output_air, target_pressure, rate=1, datum/gas_mixture/output_pipenet_air = null)
var/output_starting_pressure = output_air.return_pressure()
var/input_starting_pressure = return_pressure()
- if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10))
- //No need to pump gas if target is already reached or input pressure is too low
- //Need at least 10 kPa difference to overcome friction in the mechanism
+ //Need at least 10 KPa difference to overcome friction in the mechanism
+ if(output_starting_pressure >= min(target_pressure, input_starting_pressure-10))
return FALSE
+ //Can not have a pressure delta that would cause output_pressure > input_pressure
+ target_pressure = output_starting_pressure + min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2)
+ var/temperature_delta = abs(temperature - output_air.temperature)
- //Calculate necessary moles to transfer using PV = nRT
- if((total_moles() > 0) && (return_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_output = gas_pressure_calculate(output_air, target_pressure, temperature_delta <= 5)
+ var/transfer_moles_pipenet = output_pipenet_air?.volume ? gas_pressure_calculate(output_pipenet_air, target_pressure, temperature_delta <= 5) : 0
+ var/transfer_moles = max(transfer_moles_output, transfer_moles_pipenet)
- var/transfer_moles = pressure_delta*output_air.return_volume()/(return_temperature() * R_IDEAL_GAS_EQUATION)
+ //Actually transfer the gas
+ var/datum/gas_mixture/removed = remove(transfer_moles * rate)
- //Actually transfer the gas
- var/datum/gas_mixture/removed = remove(transfer_moles)
- output_air.merge(removed)
- return TRUE
- return FALSE
+ if(!removed)
+ return FALSE
+
+ output_air.merge(removed)
+ return TRUE
-/datum/gas_mixture/proc/vv_react(datum/holder)
- return react(holder)
diff --git a/code/modules/atmospherics/gasmixtures/gas_types.dm b/code/modules/atmospherics/gasmixtures/gas_types.dm
new file mode 100644
index 0000000000000..6853d1b4252d9
--- /dev/null
+++ b/code/modules/atmospherics/gasmixtures/gas_types.dm
@@ -0,0 +1,220 @@
+GLOBAL_LIST_INIT(hardcoded_gases, list(/datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/carbon_dioxide, /datum/gas/plasma)) //the main four gases, which were at one time hardcoded
+
+/proc/meta_gas_list()
+ . = subtypesof(/datum/gas)
+ for(var/gas_path in .)
+ var/list/gas_info = new(13)
+ var/datum/gas/gas = gas_path
+
+ gas_info[META_GAS_SPECIFIC_HEAT] = initial(gas.specific_heat)
+ gas_info[META_GAS_NAME] = initial(gas.name)
+
+ gas_info[META_GAS_MOLES_VISIBLE] = initial(gas.moles_visible)
+ if(initial(gas.moles_visible) != null)
+ gas_info[META_GAS_OVERLAY] = generate_gas_overlay(gas)
+
+ gas_info[META_GAS_FUSION_POWER] = initial(gas.fusion_power)
+ gas_info[META_GAS_DANGER] = initial(gas.dangerous)
+ gas_info[META_GAS_ID] = initial(gas.id)
+ gas_info[META_GAS_DESC] = initial(gas.desc)
+ .[gas_path] = gas_info
+
+/proc/generate_gas_overlay(datum/gas/gas_type)
+ var/fill = list()
+ for(var/j in 1 to TOTAL_VISIBLE_STATES)
+ var/obj/effect/overlay/gas/gas = new (initial(gas_type.gas_overlay), log(4, (j+0.4*TOTAL_VISIBLE_STATES) / (0.35*TOTAL_VISIBLE_STATES)) * 255)
+ fill += gas
+ return fill
+
+/proc/gas_id2path(id)
+ var/list/meta_gas = GLOB.meta_gas_info
+ if(id in meta_gas)
+ return id
+ for(var/path in meta_gas)
+ if(meta_gas[path][META_GAS_ID] == id)
+ return path
+ return ""
+
+/*||||||||||||||/----------\||||||||||||||*\
+||||||||||||||||[GAS DATUMS]||||||||||||||||
+||||||||||||||||\__________/||||||||||||||||
+||||These should never be instantiated. ||||
+||||They exist only to make it easier ||||
+||||to add a new gas. They are accessed ||||
+||||only by meta_gas_list(). ||||
+\*||||||||||||||||||||||||||||||||||||||||*/
+
+/datum/gas
+ var/id = ""
+ var/specific_heat = 0
+ var/name = ""
+ ///icon_state in icons/effects/atmospherics.dmi
+ var/gas_overlay = ""
+ var/moles_visible = null
+ ///currently used by canisters
+ var/dangerous = FALSE
+ ///How much the gas accelerates a fusion reaction
+ var/fusion_power = 0
+ /// relative rarity compared to other gases, used when setting up the reactions list.
+ var/rarity = 0
+ ///Can gas of this type can purchased through cargo?
+ var/purchaseable = FALSE
+ ///How does a single mole of this gas sell for? Formula to calculate maximum value is in code\modules\cargo\exports\large_objects.dm. Doesn't matter for roundstart gasses.
+ var/base_value = 0
+ //Description
+ var/desc
+ ///RGB code for use when a generic color representing the gas is needed. Colors taken from contants.ts
+ var/primary_color
+
+/datum/gas/oxygen
+ id = GAS_O2
+ specific_heat = 20
+ name = "Oxygen"
+ rarity = 900
+ purchaseable = TRUE
+ base_value = 0.2
+ desc = "The gas most life forms need to be able to survive. Also an oxidizer."
+ primary_color = "#0000ff"
+
+/datum/gas/nitrogen
+ id = GAS_N2
+ specific_heat = 20
+ name = "Nitrogen"
+ rarity = 1000
+ purchaseable = TRUE
+ base_value = 0.1
+ desc = "A very common gas that used to pad artificial atmospheres to habitable pressure."
+ primary_color = "#ffff00"
+
+/datum/gas/carbon_dioxide //what the fuck is this?
+ id = GAS_CO2
+ specific_heat = 30
+ name = "Carbon Dioxide"
+ dangerous = TRUE
+ rarity = 700
+ purchaseable = TRUE
+ base_value = 0.2
+ desc = "What the fuck is carbon dioxide?"
+ primary_color = COLOR_GRAY
+
+/datum/gas/plasma
+ id = GAS_PLASMA
+ specific_heat = 200
+ name = "Plasma"
+ gas_overlay = "plasma"
+ moles_visible = MOLES_GAS_VISIBLE
+ dangerous = TRUE
+ rarity = 800
+ base_value = 1.5
+ desc = "A flammable gas with many other curious properties. Its research is one of NT's primary objective."
+ primary_color = "#A020F0"
+
+/datum/gas/water_vapor
+ id = GAS_WATER_VAPOR
+ specific_heat = 40
+ name = "Water Vapor"
+ gas_overlay = "water_vapor"
+ moles_visible = MOLES_GAS_VISIBLE
+ fusion_power = 8
+ rarity = 500
+ purchaseable = TRUE
+ base_value = 0.5
+ desc = "Water, in gas form. Makes things slippery."
+ primary_color = "#b0c4de"
+
+/datum/gas/hypernoblium
+ id = GAS_HYPER_NOBLIUM
+ specific_heat = 2000
+ name = "Hyper-noblium"
+ gas_overlay = "freon"
+ moles_visible = MOLES_GAS_VISIBLE
+ fusion_power = 10
+ rarity = 50
+ base_value = 2.5
+ desc = "The most noble gas of them all. High quantities of hyper-noblium actively prevents reactions from occurring."
+ primary_color = COLOR_TEAL
+
+/datum/gas/nitrous_oxide
+ id = GAS_N2O
+ specific_heat = 40
+ name = "Nitrous Oxide"
+ gas_overlay = "nitrous_oxide"
+ moles_visible = MOLES_GAS_VISIBLE * 2
+ fusion_power = 10
+ dangerous = TRUE
+ rarity = 600
+ purchaseable = TRUE
+ base_value = 1.5
+ desc = "Causes drowsiness, euphoria, and eventually unconsciousness."
+ primary_color = "#ffe4c4"
+
+/datum/gas/nitryl
+ id = GAS_NITRYL
+ specific_heat = 10
+ name = "Nitryl"
+ fusion_power = 7
+ gas_overlay = "nitryl"
+ moles_visible = MOLES_GAS_VISIBLE
+ dangerous = TRUE
+ rarity = 1
+ base_value = 6
+ desc = "An experimental performance enhancing gas. Nitryl can have amplified effects as more of it gets into your bloodstream."
+ primary_color = "#a52a2a"
+
+/datum/gas/tritium
+ id = GAS_TRITIUM
+ specific_heat = 10
+ name = "Tritium"
+ gas_overlay = "tritium"
+ moles_visible = MOLES_GAS_VISIBLE
+ dangerous = TRUE
+ fusion_power = 5
+ rarity = 300
+ base_value = 2.5
+ desc = "A highly flammable and radioactive gas."
+ primary_color = "#32cd32"
+
+/datum/gas/bz
+ id = GAS_BZ
+ specific_heat = 20
+ name = "BZ"
+ dangerous = TRUE
+ fusion_power = 8
+ rarity = 400
+ purchaseable = TRUE
+ base_value = 1.5
+ desc = "A powerful hallucinogenic nerve agent able to induce cognitive damage."
+ primary_color = "#9370db"
+
+/datum/gas/pluoxium
+ id = GAS_PLUOXIUM
+ specific_heat = 80
+ name = "Pluoxium"
+ fusion_power = -10
+ rarity = 200
+ base_value = 2.5
+ desc = "A gas that could supply even more oxygen to the bloodstream when inhaled, without being an oxidizer."
+ primary_color = "#7b68ee"
+
+/datum/gas/stimulum
+ id = GAS_STIMULUM
+ specific_heat = 80
+ name = "Stimulum"
+ rarity = 200
+ base_value = 3
+ desc = "An experimental gas that makes you stun and sleep immune and slightly regenerates stamina, but also causes suffocation the longer you've been breathing it."
+ primary_color = "#ffc0cb"
+
+
+/obj/effect/overlay/gas
+ icon = 'icons/effects/atmospherics.dmi'
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ anchored = TRUE // should only appear in vis_contents, but to be safe
+ layer = FLY_LAYER
+ appearance_flags = TILE_BOUND
+ vis_flags = NONE
+
+/obj/effect/overlay/gas/New(state, alph)
+ . = ..()
+ icon_state = state
+ alpha = alph
diff --git a/code/modules/atmospherics/gasmixtures/immutable_mixtures.dm b/code/modules/atmospherics/gasmixtures/immutable_mixtures.dm
index cd8b88d60fb49..864700f5d7ca9 100644
--- a/code/modules/atmospherics/gasmixtures/immutable_mixtures.dm
+++ b/code/modules/atmospherics/gasmixtures/immutable_mixtures.dm
@@ -2,35 +2,94 @@
//it can be changed, but any changes will ultimately be undone before they can have any effect
/datum/gas_mixture/immutable
- var/initial_temperature = 0
+ var/initial_temperature
+ gc_share = TRUE
/datum/gas_mixture/immutable/New()
..()
- set_temperature(initial_temperature)
- populate()
- mark_immutable()
+ garbage_collect()
-/datum/gas_mixture/immutable/proc/populate()
- return
+/datum/gas_mixture/immutable/garbage_collect()
+ temperature = initial_temperature
+ temperature_archived = initial_temperature
+ gases.Cut()
+
+/datum/gas_mixture/immutable/archive()
+ return TRUE //nothing changes, so we do nothing and the archive is successful
+
+/datum/gas_mixture/immutable/merge()
+ return FALSE //we're immutable.
+
+/datum/gas_mixture/immutable/share(datum/gas_mixture/sharer, our_coeff, sharer_coeff)
+ . = ..()
+ sharer.temperature = initial_temperature
+ garbage_collect()
+
+/datum/gas_mixture/immutable/react()
+ return FALSE //we're immutable.
+
+/datum/gas_mixture/immutable/copy()
+ return new type //we're immutable, so we can just return a new instance.
+
+/datum/gas_mixture/immutable/copy_from()
+ return FALSE //we're immutable.
+
+/datum/gas_mixture/immutable/copy_from_ratio()
+ return FALSE //we're immutable.
+
+/datum/gas_mixture/immutable/temperature_share(datum/gas_mixture/sharer, conduction_coefficient, sharer_temperature, sharer_heat_capacity)
+ . = ..()
+ temperature = initial_temperature
//used by space tiles
/datum/gas_mixture/immutable/space
initial_temperature = TCMB
-/datum/gas_mixture/immutable/space/populate()
- set_min_heat_capacity(HEAT_CAPACITY_VACUUM)
+/datum/gas_mixture/immutable/space/heat_capacity()
+ return HEAT_CAPACITY_VACUUM
+
+/datum/gas_mixture/immutable/space/remove()
+ return copy() //we're always empty, so we can just return a copy.
+
+/datum/gas_mixture/immutable/space/remove_ratio()
+ return copy() //we're always empty, so we can just return a copy.
//used by cloners
/datum/gas_mixture/immutable/cloner
initial_temperature = T20C
-/datum/gas_mixture/immutable/cloner/populate()
- set_moles(GAS_N2, MOLES_O2STANDARD + MOLES_N2STANDARD)
-
-//breathable planet surface
+//planet side stuff
/datum/gas_mixture/immutable/planetary
- initial_temperature = T20C
+ var/list/initial_gas = list()
+
+/datum/gas_mixture/immutable/planetary/garbage_collect()
+ ..()
+ gases.Cut()
+ for(var/id in initial_gas)
+ ADD_GAS(id, gases)
+ gases[id][MOLES] = initial_gas[id][MOLES]
+ gases[id][ARCHIVE] = initial_gas[id][ARCHIVE]
+
+/datum/gas_mixture/immutable/planetary/proc/parse_string_immutable(gas_string) //I know I know, I need this tho
+ gas_string = SSair.preprocess_gas_string(gas_string)
+
+ var/list/mix = initial_gas
+ var/list/gas = params2list(gas_string)
+ if(gas["TEMP"])
+ initial_temperature = text2num(gas["TEMP"])
+ temperature_archived = initial_temperature
+ temperature = initial_temperature
+ gas -= "TEMP"
+ mix.Cut()
+ for(var/id in gas)
+ var/path = id
+ if(!ispath(path))
+ path = gas_id2path(path) //a lot of these strings can't have embedded expressions (especially for mappers), so support for IDs needs to stick around
+ ADD_GAS(path, mix)
+ mix[path][MOLES] = text2num(gas[id])
+ mix[path][ARCHIVE] = mix[path][MOLES]
-/datum/gas_mixture/immutable/planetary/populate()
- set_moles(GAS_O2, MOLES_O2STANDARD)
- set_moles(GAS_N2, MOLES_N2STANDARD)
+ for(var/id in mix)
+ ADD_GAS(id, gases)
+ gases[id][MOLES] = mix[id][MOLES]
+ gases[id][ARCHIVE] = mix[id][MOLES]
diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm
index 476cb163fc20c..c314eb1b73dbb 100644
--- a/code/modules/atmospherics/gasmixtures/reactions.dm
+++ b/code/modules/atmospherics/gasmixtures/reactions.dm
@@ -2,36 +2,55 @@
#define SET_REACTION_RESULTS(amount) air.reaction_results[type] = amount
/proc/init_gas_reactions()
- . = list()
-
- for(var/r in subtypesof(/datum/gas_reaction))
- var/datum/gas_reaction/reaction = r
+ var/list/priority_reactions = list()
+
+ //Builds a list of gas id to reaction group
+ for(var/gas_id in GLOB.meta_gas_info)
+ priority_reactions[gas_id] = list(
+ PRIORITY_PRE_FORMATION = list(),
+ PRIORITY_FORMATION = list(),
+ PRIORITY_POST_FORMATION = list(),
+ PRIORITY_FIRE = list()
+ )
+
+ for(var/datum/gas_reaction/reaction as anything in subtypesof(/datum/gas_reaction))
if(initial(reaction.exclude))
continue
- reaction = new r
- . += reaction
- sortTim(., GLOBAL_PROC_REF(cmp_gas_reactions))
-
-/proc/cmp_gas_reactions(list/datum/gas_reaction/a, list/datum/gas_reaction/b) // compares lists of reactions by the maximum priority contained within the list
- if (!length(a) || !length(b))
- return length(b) - length(a)
- var/maxa
- var/maxb
- for (var/datum/gas_reaction/R in a)
- if (R.priority > maxa)
- maxa = R.priority
- for (var/datum/gas_reaction/R in b)
- if (R.priority > maxb)
- maxb = R.priority
- return maxb - maxa
+ reaction = new reaction
+ var/datum/gas/reaction_key
+ for (var/req in reaction.requirements)
+ if (ispath(req))
+ var/datum/gas/req_gas = req
+ if (!reaction_key || initial(reaction_key.rarity) > initial(req_gas.rarity))
+ reaction_key = req_gas
+ reaction.major_gas = reaction_key
+ priority_reactions[reaction_key][reaction.priority_group] += reaction
+
+ //Culls empty gases
+ for(var/gas_id in GLOB.meta_gas_info)
+ var/passed = FALSE
+ for(var/list/priority_grouping in priority_reactions[gas_id])
+ if(length(priority_grouping))
+ passed = TRUE
+ break
+ if(passed)
+ continue
+ priority_reactions[gas_id] = null
+
+ return priority_reactions
/datum/gas_reaction
- //regarding the requirements lists: the minimum or maximum requirements must be non-zero.
- //when in doubt, use MINIMUM_MOLE_COUNT.
- var/list/min_requirements
- var/list/max_requirements
+ /**
+ * Regarding the requirements list: the minimum or maximum requirements must be non-zero.
+ * When in doubt, use MINIMUM_MOLE_COUNT.
+ * Another thing to note is that reactions will not fire if we have any requirements outside of gas id path or MIN_TEMP or MAX_TEMP.
+ * More complex implementations will require modifications to gas_mixture.react()
+ */
+ var/list/requirements
+ var/major_gas //the highest rarity gas used in the reaction.
var/exclude = FALSE //do it this way to allow for addition/removal of reactions midmatch in the future
- var/priority = 100 //lower numbers are checked/react later than higher numbers. if two reactions have the same priority they may happen in either order
+ ///The priority group this reaction is a part of. You can think of these as processing in batches, put your reaction into the one that's most fitting
+ var/priority_group
var/name = "reaction"
var/id = "r"
@@ -43,28 +62,20 @@
/datum/gas_reaction/proc/react(datum/gas_mixture/air, atom/location)
return NO_REACTION
-/datum/gas_reaction/nobliumsupression
- priority = INFINITY
- name = "Hyper-Noblium Reaction Suppression"
- id = "nobstop"
-
/datum/gas_reaction/nobliumsupression/init_reqs()
- min_requirements = list(GAS_HYPERNOB = REACTION_OPPRESSION_THRESHOLD)
+ requirements = list(/datum/gas/hypernoblium = REACTION_OPPRESSION_THRESHOLD)
/datum/gas_reaction/nobliumsupression/react()
return STOP_REACTIONS
//water vapor: puts out fires?
/datum/gas_reaction/water_vapor
- priority = 1
+ priority_group = PRIORITY_POST_FORMATION
name = "Water Vapor"
id = "vapor"
/datum/gas_reaction/water_vapor/init_reqs()
- min_requirements = list(
- GAS_H2O = MOLES_GAS_VISIBLE,
- "MAX_TEMP" = WATER_VAPOR_CONDENSATION_POINT,
- )
+ requirements = list(/datum/gas/water_vapor = MOLES_GAS_VISIBLE)
/datum/gas_reaction/water_vapor/react(datum/gas_mixture/air, datum/holder)
. = NO_REACTION
@@ -73,7 +84,7 @@
var/turf/open/location = holder
var/consumed = 0
- switch(air.return_temperature())
+ switch(air.temperature)
if(-INFINITY to WATER_VAPOR_DEPOSITION_POINT)
if(location?.freeze_turf())
consumed = MOLES_GAS_VISIBLE
@@ -82,132 +93,136 @@
consumed = MOLES_GAS_VISIBLE
if(consumed)
- air.adjust_moles(GAS_H2O, -consumed)
+ air.gases[/datum/gas/water_vapor][MOLES] -= consumed
SET_REACTION_RESULTS(consumed)
. = REACTING
//tritium combustion: combustion of oxygen and tritium (treated as hydrocarbons). creates hotspots. exothermic
/datum/gas_reaction/nitrous_decomp
- priority = 0
+ priority_group = PRIORITY_POST_FORMATION
name = "Nitrous Oxide Decomposition"
id = "nitrous_decomp"
/datum/gas_reaction/nitrous_decomp/init_reqs()
- min_requirements = list(
- "TEMP" = N2O_DECOMPOSITION_MIN_ENERGY,
- GAS_NITROUS = MINIMUM_MOLE_COUNT
+ requirements = list(
+ /datum/gas/nitrous_oxide = MINIMUM_MOLE_COUNT,
+ "MIN_TEMP" = N2O_DECOMPOSITION_MIN_ENERGY
)
/datum/gas_reaction/nitrous_decomp/react(datum/gas_mixture/air, datum/holder)
var/energy_released = 0
- var/old_heat_capacity = air.heat_capacity() //this speeds things up because accessing datum vars is slow
- var/temperature = air.return_temperature()
+ var/old_heat_capacity = air.heat_capacity()
+ var/list/cached_gases = air.gases //this speeds things up because accessing datum vars is slow
+ var/temperature = air.temperature
var/burned_fuel = 0
- burned_fuel = max(0,0.00002*(temperature-(0.00001*(temperature**2))))*air.get_moles(GAS_NITROUS)
- air.set_moles(GAS_NITROUS, air.get_moles(GAS_NITROUS) - burned_fuel)
+ burned_fuel = max(0,0.00002 * (temperature - (0.00001 * (temperature**2)))) * cached_gases[/datum/gas/nitrous_oxide][MOLES]
+ if(cached_gases[/datum/gas/nitrous_oxide][MOLES] - burned_fuel < 0)
+ return NO_REACTION
+ cached_gases[/datum/gas/nitrous_oxide][MOLES] -= burned_fuel
if(burned_fuel)
energy_released += (N2O_DECOMPOSITION_ENERGY_RELEASED * burned_fuel)
- air.set_moles(GAS_O2, air.get_moles(GAS_O2) + burned_fuel/2)
- air.set_moles(GAS_N2, air.get_moles(GAS_N2) + burned_fuel)
+ ADD_MOLES(/datum/gas/oxygen, air, burned_fuel * 0.5)
+ ADD_MOLES(/datum/gas/nitrogen, air, burned_fuel)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.set_temperature((temperature*old_heat_capacity + energy_released)/new_heat_capacity)
+ air.temperature = (temperature * old_heat_capacity + energy_released) / new_heat_capacity
return REACTING
return NO_REACTION
+
//tritium combustion: combustion of oxygen and tritium (treated as hydrocarbons). creates hotspots. exothermic
/datum/gas_reaction/tritfire
- priority = -1 //fire should ALWAYS be last, but tritium fires happen before plasma fires
+ priority_group = PRIORITY_FIRE
name = "Tritium Combustion"
id = "tritfire"
/datum/gas_reaction/tritfire/init_reqs()
- min_requirements = list(
- "TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST,
- GAS_TRITIUM = MINIMUM_MOLE_COUNT,
- GAS_O2 = MINIMUM_MOLE_COUNT
+ requirements = list(
+ /datum/gas/tritium = MINIMUM_MOLE_COUNT,
+ /datum/gas/oxygen = MINIMUM_MOLE_COUNT,
+ "MIN_TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
)
-/proc/fire_expose(turf/open/location, datum/gas_mixture/air, temperature)
- if(istype(location) && temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
- location.hotspot_expose(temperature, CELL_VOLUME)
- for(var/I in location)
- var/atom/movable/item = I
- item.temperature_expose(air, temperature, CELL_VOLUME)
- location.temperature_expose(air, temperature, CELL_VOLUME)
-
-/proc/radiation_burn(turf/open/location, energy_released)
- if(istype(location) && prob(10))
- radiation_pulse(location, energy_released/TRITIUM_BURN_RADIOACTIVITY_FACTOR)
-
/datum/gas_reaction/tritfire/react(datum/gas_mixture/air, datum/holder)
var/energy_released = 0
var/old_heat_capacity = air.heat_capacity()
- var/temperature = air.return_temperature()
+ var/list/cached_gases = air.gases //this speeds things up because accessing datum vars is slow
+ var/temperature = air.temperature
var/list/cached_results = air.reaction_results
cached_results["fire"] = 0
var/turf/open/location = isturf(holder) ? holder : null
var/burned_fuel = 0
- var/initial_trit = air.get_moles(GAS_TRITIUM)// Yogs
- if(air.get_moles(GAS_O2) < initial_trit || MINIMUM_TRIT_OXYBURN_ENERGY > (temperature * old_heat_capacity))// Yogs -- Maybe a tiny performance boost? I'unno
- burned_fuel = air.get_moles(GAS_O2)/TRITIUM_BURN_OXY_FACTOR
- if(burned_fuel > initial_trit) burned_fuel = initial_trit //Yogs -- prevents negative moles of Tritium
- air.adjust_moles(GAS_TRITIUM, -burned_fuel)
- else
- burned_fuel = initial_trit // Yogs -- Conservation of Mass fix
- air.set_moles(GAS_TRITIUM, air.get_moles(GAS_TRITIUM) * (1 - 1/TRITIUM_BURN_TRIT_FACTOR)) // Yogs -- Maybe a tiny performance boost? I'unno
- air.adjust_moles(GAS_O2, -air.get_moles(GAS_TRITIUM))
- energy_released += (FIRE_HYDROGEN_ENERGY_RELEASED * burned_fuel * (TRITIUM_BURN_TRIT_FACTOR - 1)) // Yogs -- Fixes low-energy tritium fires
- if(burned_fuel)
- energy_released += (FIRE_HYDROGEN_ENERGY_RELEASED * burned_fuel)
- if(location && prob(10) && burned_fuel > TRITIUM_MINIMUM_RADIATION_ENERGY) //woah there let's not crash the server
- radiation_pulse(location, energy_released/TRITIUM_BURN_RADIOACTIVITY_FACTOR)
+ if(cached_gases[/datum/gas/oxygen][MOLES] < cached_gases[/datum/gas/tritium][MOLES] || MINIMUM_TRIT_OXYBURN_ENERGY > air.thermal_energy())
+ burned_fuel = cached_gases[/datum/gas/oxygen][MOLES] / TRITIUM_BURN_OXY_FACTOR
+ cached_gases[/datum/gas/tritium][MOLES] -= burned_fuel
- //oxygen+more-or-less hydrogen=H2O
- air.adjust_moles(GAS_H2O, burned_fuel )// Yogs -- Conservation of Mass
+ ADD_MOLES(/datum/gas/water_vapor, air, burned_fuel/TRITIUM_BURN_OXY_FACTOR)
+ energy_released += (FIRE_HYDROGEN_ENERGY_RELEASED * burned_fuel)
cached_results["fire"] += burned_fuel
+ else
+ burned_fuel = cached_gases[/datum/gas/tritium][MOLES]
+
+ cached_gases[/datum/gas/tritium][MOLES] -= burned_fuel / TRITIUM_BURN_TRIT_FACTOR
+ cached_gases[/datum/gas/oxygen][MOLES] -= burned_fuel
+
+ ADD_MOLES(/datum/gas/water_vapor, air, burned_fuel/TRITIUM_BURN_OXY_FACTOR)
+
+ energy_released += (FIRE_HYDROGEN_ENERGY_RELEASED * burned_fuel)
+ cached_results["fire"] += burned_fuel * 10
+
+ if(burned_fuel)
+ if(location && prob(10) && burned_fuel > TRITIUM_MINIMUM_RADIATION_ENERGY) //woah there let's not crash the server
+ radiation_pulse(location, energy_released / TRITIUM_BURN_RADIOACTIVITY_FACTOR)
+
if(energy_released > 0)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.set_temperature((temperature*old_heat_capacity + energy_released)/new_heat_capacity)
+ air.temperature = (temperature * old_heat_capacity + energy_released) / new_heat_capacity
//let the floor know a fire is happening
if(istype(location))
- temperature = air.return_temperature()
+ temperature = air.temperature
if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
location.hotspot_expose(temperature, CELL_VOLUME)
- for(var/I in location)
- var/atom/movable/item = I
- item.temperature_expose(air, temperature, CELL_VOLUME)
- location.temperature_expose(air, temperature, CELL_VOLUME)
return cached_results["fire"] ? REACTING : NO_REACTION
+/proc/fire_expose(turf/open/location, datum/gas_mixture/air, temperature)
+ if(istype(location) && temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
+ location.hotspot_expose(temperature, CELL_VOLUME)
+
+/proc/radiation_burn(turf/open/location, energy_released)
+ if(istype(location) && prob(10))
+ radiation_pulse(location, energy_released/TRITIUM_BURN_RADIOACTIVITY_FACTOR)
+
+
+
//plasma combustion: combustion of oxygen and plasma (treated as hydrocarbons). creates hotspots. exothermic
/datum/gas_reaction/plasmafire
- priority = -2 //fire should ALWAYS be last, but plasma fires happen after tritium fires
+ priority_group = PRIORITY_FIRE
name = "Plasma Combustion"
id = "plasmafire"
/datum/gas_reaction/plasmafire/init_reqs()
- min_requirements = list(
- "TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST,
- GAS_PLASMA = MINIMUM_MOLE_COUNT,
- GAS_O2 = MINIMUM_MOLE_COUNT
+ requirements = list(
+ /datum/gas/plasma = MINIMUM_MOLE_COUNT,
+ /datum/gas/oxygen = MINIMUM_MOLE_COUNT,
+ "MIN_TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
)
/datum/gas_reaction/plasmafire/react(datum/gas_mixture/air, datum/holder)
var/energy_released = 0
var/old_heat_capacity = air.heat_capacity()
- var/temperature = air.return_temperature()
+ var/list/cached_gases = air.gases //this speeds things up because accessing datum vars is slow
+ var/temperature = air.temperature
var/list/cached_results = air.reaction_results
cached_results["fire"] = 0
var/turf/open/location = isturf(holder) ? holder : null
@@ -223,122 +238,41 @@
if(temperature > PLASMA_UPPER_TEMPERATURE)
temperature_scale = 1
else
- temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
+ 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(air.get_moles(GAS_O2) / air.get_moles(GAS_PLASMA) > SUPER_SATURATION_THRESHOLD) //supersaturation. Form Tritium.
+ if(cached_gases[/datum/gas/oxygen][MOLES] / cached_gases[/datum/gas/plasma][MOLES] > SUPER_SATURATION_THRESHOLD) //supersaturation. Form Tritium.
super_saturation = TRUE
- if(air.get_moles(GAS_O2) > air.get_moles(GAS_PLASMA)*PLASMA_OXYGEN_FULLBURN)
- plasma_burn_rate = (air.get_moles(GAS_PLASMA)*temperature_scale)/PLASMA_BURN_RATE_DELTA
+ if(cached_gases[/datum/gas/oxygen][MOLES] > cached_gases[/datum/gas/plasma][MOLES] * PLASMA_OXYGEN_FULLBURN)
+ plasma_burn_rate = (cached_gases[/datum/gas/plasma][MOLES] * temperature_scale) / PLASMA_BURN_RATE_DELTA
else
- plasma_burn_rate = (temperature_scale*(air.get_moles(GAS_O2)/PLASMA_OXYGEN_FULLBURN))/PLASMA_BURN_RATE_DELTA
+ plasma_burn_rate = (temperature_scale * (cached_gases[/datum/gas/oxygen][MOLES] / PLASMA_OXYGEN_FULLBURN)) / PLASMA_BURN_RATE_DELTA
if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
- plasma_burn_rate = min(plasma_burn_rate,air.get_moles(GAS_PLASMA),air.get_moles(GAS_O2)/oxygen_burn_rate) //Ensures matter is conserved properly
- air.set_moles(GAS_PLASMA, QUANTIZE(air.get_moles(GAS_PLASMA) - plasma_burn_rate))
- air.set_moles(GAS_O2, QUANTIZE(air.get_moles(GAS_O2) - (plasma_burn_rate * oxygen_burn_rate)))
+ plasma_burn_rate = min(plasma_burn_rate, cached_gases[/datum/gas/plasma][MOLES], cached_gases[/datum/gas/oxygen][MOLES] * INVERSE(oxygen_burn_rate)) //Ensures matter is conserved properly
+ cached_gases[/datum/gas/plasma][MOLES] = QUANTIZE(cached_gases[/datum/gas/plasma][MOLES] - plasma_burn_rate)
+ cached_gases[/datum/gas/oxygen][MOLES] = QUANTIZE(cached_gases[/datum/gas/oxygen][MOLES] - (plasma_burn_rate * oxygen_burn_rate))
if (super_saturation)
- air.adjust_moles(GAS_TRITIUM, plasma_burn_rate)
+ ADD_MOLES(/datum/gas/tritium, air, plasma_burn_rate)
else
- air.adjust_moles(GAS_CO2, plasma_burn_rate)
+ ADD_MOLES(/datum/gas/carbon_dioxide, air, plasma_burn_rate*0.75)
+ ADD_MOLES(/datum/gas/water_vapor, air, plasma_burn_rate*0.25)
energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
- cached_results["fire"] += (plasma_burn_rate)*(1+oxygen_burn_rate)
+ cached_results["fire"] += (plasma_burn_rate) * (1 + oxygen_burn_rate)
if(energy_released > 0)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.set_temperature((temperature*old_heat_capacity + energy_released)/new_heat_capacity)
+ air.temperature = (temperature * old_heat_capacity + energy_released) / new_heat_capacity
//let the floor know a fire is happening
if(istype(location))
- temperature = air.return_temperature()
+ temperature = air.temperature
if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
location.hotspot_expose(temperature, CELL_VOLUME)
- for(var/I in location)
- var/atom/movable/item = I
- item.temperature_expose(air, temperature, CELL_VOLUME)
- location.temperature_expose(air, temperature, CELL_VOLUME)
-
- return cached_results["fire"] ? REACTING : NO_REACTION
-
-/datum/gas_reaction/genericfire
- priority = -3 // very last reaction
- name = "Combustion"
- id = "genericfire"
-
-/datum/gas_reaction/genericfire/init_reqs()
- var/lowest_fire_temp = INFINITY
- var/list/fire_temperatures = GLOB.gas_data.fire_temperatures
- for(var/gas in fire_temperatures)
- lowest_fire_temp = min(lowest_fire_temp, fire_temperatures[gas])
- var/lowest_oxi_temp = INFINITY
- var/list/oxidation_temperatures = GLOB.gas_data.oxidation_temperatures
- for(var/gas in oxidation_temperatures)
- lowest_oxi_temp = min(lowest_oxi_temp, oxidation_temperatures[gas])
- min_requirements = list(
- "TEMP" = max(lowest_oxi_temp, lowest_fire_temp),
- "FIRE_REAGENTS" = MINIMUM_MOLE_COUNT
- )
-// no requirements, always runs
-// bad idea? maybe
-// this is overridden by auxmos but, hey, good idea to have it readable
-
-/datum/gas_reaction/genericfire/react(datum/gas_mixture/air, datum/holder)
- var/temperature = air.return_temperature()
- var/list/oxidation_temps = GLOB.gas_data.oxidation_temperatures
- var/list/oxidation_rates = GLOB.gas_data.oxidation_rates
- var/oxidation_power = 0
- var/list/burn_results = list()
- var/list/fuels = list()
- var/list/oxidizers = list()
- var/list/fuel_rates = GLOB.gas_data.fire_burn_rates
- var/list/fuel_temps = GLOB.gas_data.fire_temperatures
- var/total_fuel = 0
- var/energy_released = 0
- for(var/G in air.get_gases())
- var/oxidation_temp = oxidation_temps[G]
- if(oxidation_temp && oxidation_temp > temperature)
- var/temperature_scale = max(0, 1-(temperature / oxidation_temp))
- var/amt = air.get_moles(G) * temperature_scale
- oxidizers[G] = amt
- oxidation_power += amt * oxidation_rates[G]
- else
- var/fuel_temp = fuel_temps[G]
- if(fuel_temp && fuel_temp > temperature)
- var/amt = (air.get_moles(G) / fuel_rates[G]) * max(0, 1-(temperature / fuel_temp))
- fuels[G] = amt // we have to calculate the actual amount we're using after we get all oxidation together
- total_fuel += amt
- if(oxidation_power <= 0 || total_fuel <= 0)
- return NO_REACTION
- var/oxidation_ratio = oxidation_power / total_fuel
- if(oxidation_ratio > 1)
- for(var/oxidizer in oxidizers)
- oxidizers[oxidizer] /= oxidation_ratio
- else if(oxidation_ratio < 1)
- for(var/fuel in fuels)
- fuels[fuel] *= oxidation_ratio
- fuels += oxidizers
- var/list/fire_products = GLOB.gas_data.fire_products
- var/list/fire_enthalpies = GLOB.gas_data.enthalpies
- for(var/fuel in fuels + oxidizers)
- var/amt = fuels[fuel]
- if(!burn_results[fuel])
- burn_results[fuel] = 0
- burn_results[fuel] -= amt
- energy_released += amt * fire_enthalpies[fuel]
- for(var/product in fire_products[fuel])
- if(!burn_results[product])
- burn_results[product] = 0
- burn_results[product] += amt
- var/final_energy = air.thermal_energy() + energy_released
- for(var/result in burn_results)
- air.adjust_moles(result, burn_results[result])
- air.set_temperature(final_energy / air.heat_capacity())
- var/list/cached_results = air.reaction_results
- cached_results["fire"] = min(total_fuel, oxidation_power) * 2
return cached_results["fire"] ? REACTING : NO_REACTION
//fusion: a terrible idea that was fun but broken. Now reworked to be less broken and more interesting. Again (and again, and again). Again!
@@ -347,16 +281,16 @@
/datum/gas_reaction/fusion
exclude = FALSE
- priority = 2
+ priority_group = PRIORITY_POST_FORMATION
name = "Plasmic Fusion"
id = "fusion"
/datum/gas_reaction/fusion/init_reqs()
- min_requirements = list(
- "TEMP" = FUSION_TEMPERATURE_THRESHOLD,
- GAS_TRITIUM = FUSION_TRITIUM_MOLES_USED,
- GAS_PLASMA = FUSION_MOLE_THRESHOLD,
- GAS_CO2 = FUSION_MOLE_THRESHOLD)
+ requirements = list(
+ "MIN_TEMP" = FUSION_TEMPERATURE_THRESHOLD,
+ /datum/gas/tritium = FUSION_TRITIUM_MOLES_USED,
+ /datum/gas/plasma = FUSION_MOLE_THRESHOLD,
+ /datum/gas/carbon_dioxide = FUSION_MOLE_THRESHOLD)
/datum/gas_reaction/fusion/react(datum/gas_mixture/air, datum/holder)
var/turf/open/location
@@ -370,18 +304,18 @@
var/list/cached_scan_results = air.analyzer_results
var/thermal_energy = air.thermal_energy()
var/reaction_energy = 0 //Reaction energy can be negative or positive, for both exothermic and endothermic reactions.
- var/initial_plasma = air.get_moles(GAS_PLASMA)
- var/initial_carbon = air.get_moles(GAS_CO2)
- var/scale_factor = max(air.return_volume() / FUSION_SCALE_DIVISOR, FUSION_MINIMAL_SCALE)
- var/temperature_scale = log(10, air.return_temperature())
+ var/initial_plasma = GET_MOLES(/datum/gas/plasma, air)
+ var/initial_carbon = GET_MOLES(/datum/gas/carbon_dioxide, air)
+ var/scale_factor = max(air.volume / FUSION_SCALE_DIVISOR, FUSION_MINIMAL_SCALE)
+ var/temperature_scale = log(10, air.temperature)
//The size of the phase space hypertorus
var/toroidal_size = TOROID_CALCULATED_THRESHOLD \
+ (temperature_scale <= FUSION_BASE_TEMPSCALE ? \
(temperature_scale-FUSION_BASE_TEMPSCALE) / FUSION_BUFFER_DIVISOR \
: 4 ** (temperature_scale-FUSION_BASE_TEMPSCALE) / FUSION_SLOPE_DIVISOR)
var/gas_power = 0
- for (var/gas_id in air.get_gases())
- gas_power += (GLOB.gas_data.fusion_powers[gas_id]*air.get_moles(gas_id))
+ for (var/gas_id in air.gases)
+ gas_power += (GLOB.meta_gas_info[gas_id][META_GAS_FUSION_POWER]*GET_MOLES(gas_id, air))
var/instability = MODULUS((gas_power*INSTABILITY_GAS_POWER_FACTOR),toroidal_size) //Instability effects how chaotic the behavior of the reaction is
cached_scan_results[id] = instability//used for analyzer feedback
@@ -392,9 +326,11 @@
plasma = MODULUS(plasma - (instability*sin(TODEGREES(carbon))), toroidal_size)
carbon = MODULUS(carbon - plasma, toroidal_size)
- air.set_moles(GAS_PLASMA, plasma*scale_factor + FUSION_MOLE_THRESHOLD )//Scales the gases back up
- air.set_moles(GAS_CO2, carbon*scale_factor + FUSION_MOLE_THRESHOLD)
- var/delta_plasma = min(initial_plasma - air.get_moles(GAS_PLASMA), toroidal_size * scale_factor * 1.5)
+ SET_MOLES(/datum/gas/plasma, air, plasma*scale_factor + FUSION_MOLE_THRESHOLD)
+//Scales the gases back up
+ SET_MOLES(/datum/gas/carbon_dioxide, air, carbon*scale_factor + FUSION_MOLE_THRESHOLD)
+
+ var/delta_plasma = min(initial_plasma - air.gases[/datum/gas/plasma][MOLES], toroidal_size * scale_factor * 1.5)
//Energy is gained or lost corresponding to the creation or destruction of mass.
//Low instability prevents endothermality while higher instability acutally encourages it.
@@ -414,169 +350,176 @@
thermal_energy = middle_energy * 10 ** log(FUSION_ENERGY_TRANSLATION_EXPONENT, (thermal_energy + bowdlerized_reaction_energy) / middle_energy)
//The reason why you should set up a tritium production line.
- air.adjust_moles(GAS_TRITIUM, -FUSION_TRITIUM_MOLES_USED)
+ REMOVE_MOLES(/datum/gas/tritium, air, FUSION_TRITIUM_MOLES_USED)
//The decay of the tritium and the reaction's energy produces waste gases, different ones depending on whether the reaction is endo or exothermic
var/standard_waste_gas_output = scale_factor * (FUSION_TRITIUM_CONVERSION_COEFFICIENT*FUSION_TRITIUM_MOLES_USED)
- delta_plasma > 0 ? air.adjust_moles(GAS_H2O, standard_waste_gas_output) : air.adjust_moles(GAS_BZ, standard_waste_gas_output)
- air.adjust_moles(GAS_O2, standard_waste_gas_output) //Oxygen is a bit touchy subject
+ if(delta_plasma > 0)
+ ADD_MOLES(/datum/gas/water_vapor, air, standard_waste_gas_output)
+ else
+ ADD_MOLES(/datum/gas/bz, air, standard_waste_gas_output)
+ ADD_MOLES(/datum/gas/oxygen, air, standard_waste_gas_output) //Oxygen is a bit touchy subject
if(reaction_energy)
if(location)
- var/standard_energy = 400 * air.get_moles(GAS_PLASMA) * air.return_temperature() //Prevents putting meaningless waste gases to achieve high rads.
+ var/standard_energy = 400 * GET_MOLES(/datum/gas/plasma, air) * air.temperature //Prevents putting meaningless waste gases to achieve high rads.
if(prob(PERCENT(((PARTICLE_CHANCE_CONSTANT)/(reaction_energy-PARTICLE_CHANCE_CONSTANT)) + 1))) //Asymptopically approaches 100% as the energy of the reaction goes up.
location.fire_nuclear_particle(customize = TRUE, custompower = standard_energy)
radiation_pulse(location, max(2000 * 3 ** (log(10,standard_energy) - FUSION_RAD_MIDPOINT), 0))
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.set_temperature(clamp(thermal_energy/new_heat_capacity, TCMB, INFINITY))
+ air.temperature = (clamp(thermal_energy/new_heat_capacity, TCMB, INFINITY))
return REACTING
else if(reaction_energy == 0 && instability <= FUSION_INSTABILITY_ENDOTHERMALITY)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.set_temperature(clamp(thermal_energy/new_heat_capacity, TCMB, INFINITY)) //THIS SHOULD STAY OR FUSION WILL EAT YOUR FACE
+ air.temperature = (clamp(thermal_energy/new_heat_capacity, TCMB, INFINITY)) //THIS SHOULD STAY OR FUSION WILL EAT YOUR FACE
return REACTING
-/datum/gas_reaction/nitrylformation //The formation of nitryl. Endothermic. Requires N2O as a catalyst.
- priority = 3
+
+/datum/gas_reaction/nitrylformation //The formation of nitryl. Endothermic. Requires bz.
+ priority_group = PRIORITY_FORMATION
name = "Nitryl formation"
id = "nitrylformation"
/datum/gas_reaction/nitrylformation/init_reqs()
- min_requirements = list(
- GAS_O2 = 20,
- GAS_N2 = 20,
- GAS_PLUOXIUM = 5, //Gates Nitryl behind pluoxium to offset N2O burning up during formation
- "TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST*60
+ requirements = list(
+ /datum/gas/oxygen = 10,
+ /datum/gas/nitrogen = 10,
+ /datum/gas/bz = 5,
+ "MIN_TEMP" = 1500,
+ "MAX_TEMP" = 10000
)
/datum/gas_reaction/nitrylformation/react(datum/gas_mixture/air)
- var/temperature = air.return_temperature()
+ var/list/cached_gases = air.gases
+ var/temperature = air.temperature
var/old_heat_capacity = air.heat_capacity()
- var/heat_efficency = min(temperature/(FIRE_MINIMUM_TEMPERATURE_TO_EXIST*60),air.get_moles(GAS_O2),air.get_moles(GAS_N2))
- var/energy_used = heat_efficency*NITRYL_FORMATION_ENERGY
- if ((air.get_moles(GAS_O2) - heat_efficency < 0 )|| (air.get_moles(GAS_N2) - heat_efficency < 0)) //Shouldn't produce gas from nothing.
+ var/heat_efficiency = min(temperature / (FIRE_MINIMUM_TEMPERATURE_TO_EXIST * 8), cached_gases[/datum/gas/oxygen][MOLES], cached_gases[/datum/gas/nitrogen][MOLES], cached_gases[/datum/gas/bz][MOLES] * INVERSE(0.05))
+ var/energy_used = heat_efficiency * NITRYL_FORMATION_ENERGY
+ if ((cached_gases[/datum/gas/oxygen][MOLES] - heat_efficiency < 0 ) || (cached_gases[/datum/gas/nitrogen][MOLES] - heat_efficiency < 0) || (cached_gases[/datum/gas/bz][MOLES] - heat_efficiency * 0.05 < 0)) //Shouldn't produce gas from nothing.
return NO_REACTION
- air.adjust_moles(GAS_O2, -heat_efficency)
- air.adjust_moles(GAS_N2, -heat_efficency)
- air.adjust_moles(GAS_NITRYL, heat_efficency*2)
+
+ cached_gases[/datum/gas/oxygen][MOLES] -= heat_efficiency
+ cached_gases[/datum/gas/nitrogen][MOLES] -= heat_efficiency
+ cached_gases[/datum/gas/bz][MOLES] -= heat_efficiency * 0.05 //bz gets consumed to balance the nitryl production and not make it too common and/or easy
+ ADD_MOLES(/datum/gas/nitryl, air, heat_efficiency)
if(energy_used > 0)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.set_temperature(max(((temperature*old_heat_capacity - energy_used)/new_heat_capacity),TCMB))
+ air.temperature = max(((temperature * old_heat_capacity - energy_used) / new_heat_capacity), TCMB) //the air cools down when reacting
return REACTING
/datum/gas_reaction/bzformation //Formation of BZ by combining plasma and tritium at low pressures. Exothermic.
- priority = 4
+ priority_group = PRIORITY_FORMATION
name = "BZ Gas formation"
id = "bzformation"
/datum/gas_reaction/bzformation/init_reqs()
- min_requirements = list(
- GAS_NITROUS = 10,
- GAS_PLASMA = 10
+ requirements = list(
+ /datum/gas/nitrous_oxide = 10,
+ /datum/gas/plasma = 10
)
-
/datum/gas_reaction/bzformation/react(datum/gas_mixture/air)
- var/temperature = air.return_temperature()
+ var/list/cached_gases = air.gases
+ var/temperature = air.temperature
var/pressure = air.return_pressure()
var/old_heat_capacity = air.heat_capacity()
- var/reaction_efficency = min(1/((pressure/(0.5*ONE_ATMOSPHERE))*(max(air.get_moles(GAS_PLASMA)/air.get_moles(GAS_NITROUS),1))),air.get_moles(GAS_NITROUS),air.get_moles(GAS_PLASMA)/2)
- var/energy_released = 2*reaction_efficency*FIRE_CARBON_ENERGY_RELEASED
- if ((air.get_moles(GAS_NITROUS) - reaction_efficency < 0 )|| (air.get_moles(GAS_PLASMA) - (2*reaction_efficency) < 0) || energy_released <= 0) //Shouldn't produce gas from nothing.
+ var/reaction_efficency = min(1 / ((pressure / (0.1 * ONE_ATMOSPHERE)) * (max(cached_gases[/datum/gas/plasma][MOLES] / cached_gases[/datum/gas/nitrous_oxide][MOLES], 1))), cached_gases[/datum/gas/nitrous_oxide][MOLES], cached_gases[/datum/gas/plasma][MOLES] * INVERSE(2))
+ var/energy_released = 2 * reaction_efficency * FIRE_CARBON_ENERGY_RELEASED
+ if ((cached_gases[/datum/gas/nitrous_oxide][MOLES] - reaction_efficency < 0 )|| (cached_gases[/datum/gas/plasma][MOLES] - (2 * reaction_efficency) < 0) || energy_released <= 0) //Shouldn't produce gas from nothing.
return NO_REACTION
- air.adjust_moles(GAS_BZ, reaction_efficency)
- if(reaction_efficency == air.get_moles(GAS_NITROUS))
- air.adjust_moles(GAS_BZ, -min(pressure,1))
- air.adjust_moles(GAS_O2, min(pressure,1))
- air.adjust_moles(GAS_NITROUS, -reaction_efficency)
- air.adjust_moles(GAS_PLASMA, -2*reaction_efficency)
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, min((reaction_efficency**2)*BZ_RESEARCH_SCALE,BZ_RESEARCH_MAX_AMOUNT))
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DISCOVERY, min((reaction_efficency**2)*BZ_RESEARCH_SCALE,BZ_RESEARCH_MAX_AMOUNT)*0.5)
+ ADD_MOLES(/datum/gas/bz, air, reaction_efficency * 2.5)
+ if(reaction_efficency == cached_gases[/datum/gas/nitrous_oxide][MOLES])
+ REMOVE_MOLES(/datum/gas/bz, air, min(pressure, 0.5))
+ ADD_MOLES(/datum/gas/oxygen, air, min(pressure, 0.5))
+ cached_gases[/datum/gas/nitrous_oxide][MOLES] -= reaction_efficency
+ cached_gases[/datum/gas/plasma][MOLES] -= 2 * reaction_efficency
if(energy_released > 0)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.set_temperature(max(((temperature*old_heat_capacity + energy_released)/new_heat_capacity),TCMB))
+ air.temperature = max(((temperature * old_heat_capacity + energy_released) / new_heat_capacity), TCMB)
return REACTING
/datum/gas_reaction/stimformation //Stimulum formation follows a strange pattern of how effective it will be at a given temperature, having some multiple peaks and some large dropoffs. Exo and endo thermic.
- priority = 5
+ priority_group = PRIORITY_FORMATION
name = "Stimulum formation"
id = "stimformation"
/datum/gas_reaction/stimformation/init_reqs()
- min_requirements = list(
- GAS_TRITIUM = 30,
- GAS_PLASMA = 10,
- GAS_BZ = 20,
- GAS_NITRYL = 30,
- "TEMP" = STIMULUM_HEAT_SCALE/2)
+ requirements = list(
+ /datum/gas/tritium = 30,
+ /datum/gas/bz = 20,
+ /datum/gas/nitryl = 30,
+ "MIN_TEMP" = 1500)
/datum/gas_reaction/stimformation/react(datum/gas_mixture/air)
+ var/list/cached_gases = air.gases
var/old_heat_capacity = air.heat_capacity()
- var/heat_scale = min(air.return_temperature()/STIMULUM_HEAT_SCALE,air.get_moles(GAS_PLASMA),air.get_moles(GAS_NITRYL))
- var/stim_energy_change = heat_scale + STIMULUM_FIRST_RISE*(heat_scale**2) - STIMULUM_FIRST_DROP*(heat_scale**3) + STIMULUM_SECOND_RISE*(heat_scale**4) - STIMULUM_ABSOLUTE_DROP*(heat_scale**5)
-
- if ((air.get_moles(GAS_PLASMA) - heat_scale < 0) || (air.get_moles(GAS_NITRYL) - heat_scale < 0) || (air.get_moles(GAS_TRITIUM) - heat_scale < 0)) //Shouldn't produce gas from nothing.
+ var/heat_scale = min(air.temperature/STIMULUM_HEAT_SCALE, cached_gases[/datum/gas/tritium][MOLES], cached_gases[/datum/gas/plasma][MOLES], cached_gases[/datum/gas/nitryl][MOLES])
+ var/stim_energy_change = heat_scale + STIMULUM_FIRST_RISE * (heat_scale ** 2) - STIMULUM_FIRST_DROP * (heat_scale ** 3) + STIMULUM_SECOND_RISE * (heat_scale ** 4) - STIMULUM_ABSOLUTE_DROP * (heat_scale ** 5)
+ if ((cached_gases[/datum/gas/tritium][MOLES] - heat_scale < 0 ) || (cached_gases[/datum/gas/nitryl][MOLES] - heat_scale < 0)) //Shouldn't produce gas from nothing.
return NO_REACTION
- air.adjust_moles(GAS_STIMULUM, heat_scale/10)
- air.adjust_moles(GAS_PLASMA, -heat_scale)
- air.adjust_moles(GAS_NITRYL, -heat_scale)
- air.adjust_moles(GAS_TRITIUM, -heat_scale)
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, STIMULUM_RESEARCH_AMOUNT*max(stim_energy_change,0))
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DISCOVERY, STIMULUM_RESEARCH_AMOUNT*max(stim_energy_change,0)*0.5)
+ cached_gases[/datum/gas/tritium][MOLES] -= heat_scale
+ cached_gases[/datum/gas/nitryl][MOLES] -= heat_scale
+ ADD_MOLES(/datum/gas/stimulum, air, heat_scale*0.75)
+
if(stim_energy_change)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.set_temperature(max(((air.return_temperature()*old_heat_capacity + stim_energy_change)/new_heat_capacity),TCMB))
+ air.temperature = max(((air.temperature * old_heat_capacity + stim_energy_change) / new_heat_capacity), TCMB)
return REACTING
/datum/gas_reaction/nobliumformation //Hyper-Noblium formation is extrememly endothermic, but requires high temperatures to start. Due to its high mass, hyper-nobelium uses large amounts of nitrogen and tritium. BZ can be used as a catalyst to make it less endothermic.
- priority = 6
+ priority_group = PRIORITY_FORMATION
name = "Hyper-Noblium condensation"
id = "nobformation"
/datum/gas_reaction/nobliumformation/init_reqs()
- min_requirements = list(
- GAS_N2 = 10,
- GAS_TRITIUM = 5,
- "TEMP" = 5000000)
+ requirements = list(
+ /datum/gas/nitrogen = 10,
+ /datum/gas/tritium = 5,
+ "MIN_TEMP" = TCMB,
+ "MAX_TEMP" = 15
+ )
/datum/gas_reaction/nobliumformation/react(datum/gas_mixture/air)
+ var/list/cached_gases = air.gases
+ air.assert_gases(/datum/gas/hypernoblium, /datum/gas/bz)
var/old_heat_capacity = air.heat_capacity()
- var/nob_formed = min((air.get_moles(GAS_N2)+air.get_moles(GAS_TRITIUM))/100,air.get_moles(GAS_TRITIUM)/10,air.get_moles(GAS_N2)/20)
- var/energy_taken = nob_formed*(NOBLIUM_FORMATION_ENERGY/(max(air.get_moles(GAS_BZ),1)))
- if ((air.get_moles(GAS_TRITIUM) - 10*nob_formed < 0) || (air.get_moles(GAS_N2) - 20*nob_formed < 0))
+ var/nob_formed = min((cached_gases[/datum/gas/nitrogen][MOLES] + cached_gases[/datum/gas/tritium][MOLES]) * 0.01, cached_gases[/datum/gas/tritium][MOLES] * INVERSE(5), cached_gases[/datum/gas/nitrogen][MOLES] * INVERSE(10))
+ var/energy_produced = nob_formed * (NOBLIUM_FORMATION_ENERGY / (max(cached_gases[/datum/gas/bz][MOLES], 1)))
+ if ((cached_gases[/datum/gas/tritium][MOLES] - 5 * nob_formed < 0) || (cached_gases[/datum/gas/nitrogen][MOLES] - 10 * nob_formed < 0))
return NO_REACTION
- air.adjust_moles(GAS_TRITIUM, -10*nob_formed)
- air.adjust_moles(GAS_N2, -20*nob_formed)
- air.adjust_moles(GAS_HYPERNOB, nob_formed)
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DEFAULT, nob_formed*NOBLIUM_RESEARCH_AMOUNT)
- SSresearch.science_tech.add_point_type(TECHWEB_POINT_TYPE_DISCOVERY, nob_formed*NOBLIUM_RESEARCH_AMOUNT*0.5)
+
+ cached_gases[/datum/gas/tritium][MOLES] -= 5 * nob_formed
+ cached_gases[/datum/gas/nitrogen][MOLES] -= 10 * nob_formed
+ cached_gases[/datum/gas/hypernoblium][MOLES] += nob_formed
if (nob_formed)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.set_temperature(max(((air.return_temperature()*old_heat_capacity - energy_taken)/new_heat_capacity),TCMB))
+ air.temperature = max(((air.temperature * old_heat_capacity + energy_produced) / new_heat_capacity), TCMB)
+ return REACTING
/datum/gas_reaction/stim_ball
- priority = 7
+ priority_group = PRIORITY_POST_FORMATION
name ="Stimulum Energy Ball"
id = "stimball"
/datum/gas_reaction/stim_ball/init_reqs()
- min_requirements = list(
- GAS_PLUOXIUM = STIM_BALL_GAS_AMOUNT,
- GAS_STIMULUM = STIM_BALL_GAS_AMOUNT,
- GAS_NITRYL = MINIMUM_MOLE_COUNT,
- GAS_PLASMA = MINIMUM_MOLE_COUNT,
- "TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
+ requirements = list(
+ /datum/gas/pluoxium = STIM_BALL_GAS_AMOUNT,
+ /datum/gas/stimulum = STIM_BALL_GAS_AMOUNT,
+ /datum/gas/nitryl = MINIMUM_MOLE_COUNT,
+ /datum/gas/plasma = MINIMUM_MOLE_COUNT,
+ "MIN_TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
)
/datum/gas_reaction/stim_ball/react(datum/gas_mixture/air, datum/holder)
@@ -587,20 +530,20 @@
location = get_turf(pick(pipenet.members))
else
location = get_turf(holder)
- var/ball_shot_angle = 180*cos(air.get_moles(GAS_H2O)/air.get_moles(GAS_NITRYL))+180
- var/stim_used = min(STIM_BALL_GAS_AMOUNT/air.get_moles(GAS_PLASMA),air.get_moles(GAS_STIMULUM))
- var/pluox_used = min(STIM_BALL_GAS_AMOUNT/air.get_moles(GAS_PLASMA),air.get_moles(GAS_PLUOXIUM))
+ var/ball_shot_angle = 180*cos(GET_MOLES(/datum/gas/water_vapor, air)/GET_MOLES(/datum/gas/nitryl, air))+180
+ var/stim_used = min(STIM_BALL_GAS_AMOUNT/GET_MOLES(/datum/gas/plasma, air),GET_MOLES(/datum/gas/stimulum, air))
+ var/pluox_used = min(STIM_BALL_GAS_AMOUNT/GET_MOLES(/datum/gas/plasma, air),GET_MOLES(/datum/gas/pluoxium, air))
var/energy_released = stim_used*STIMULUM_HEAT_SCALE//Stimulum has a lot of stored energy, and breaking it up releases some of it
location.fire_nuclear_particle(ball_shot_angle)
- air.adjust_moles(GAS_CO2, 4*pluox_used)
- air.adjust_moles(GAS_N2, 8*stim_used)
- air.adjust_moles(GAS_PLUOXIUM, -pluox_used)
- air.adjust_moles(GAS_STIMULUM, -stim_used)
- air.adjust_moles(GAS_PLASMA, max(-air.get_moles(GAS_PLASMA)/2,-30))
+ ADD_MOLES(/datum/gas/carbon_dioxide, air, 4*pluox_used)
+ ADD_MOLES(/datum/gas/nitrogen, air, 8*stim_used)
+ REMOVE_MOLES(/datum/gas/pluoxium, air, pluox_used)
+ REMOVE_MOLES(/datum/gas/stimulum, air, stim_used)
+ REMOVE_MOLES(/datum/gas/plasma, air, min(GET_MOLES(/datum/gas/plasma, air)/2,30))
if(energy_released)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
- air.set_temperature(clamp((air.return_temperature()*old_heat_capacity + energy_released)/new_heat_capacity,TCMB,INFINITY))
+ air.temperature = (clamp((air.return_temperature()*old_heat_capacity + energy_released)/new_heat_capacity,TCMB,INFINITY))
return REACTING
#undef SET_REACTION_RESULTS
diff --git a/code/modules/atmospherics/machinery/air_alarm/_airalarm.dm b/code/modules/atmospherics/machinery/air_alarm/_airalarm.dm
new file mode 100644
index 0000000000000..a05f5ed857189
--- /dev/null
+++ b/code/modules/atmospherics/machinery/air_alarm/_airalarm.dm
@@ -0,0 +1,745 @@
+#define AIRALARM_WARNING_COOLDOWN (10 SECONDS)
+
+/obj/machinery/airalarm
+ name = "air alarm"
+ desc = "A machine that monitors atmosphere levels. Goes off if the area is dangerous."
+ icon = 'icons/obj/monitors.dmi'
+ icon_state = "alarmp"
+ use_power = IDLE_POWER_USE
+ idle_power_usage = 4
+ active_power_usage = 8
+ power_channel = AREA_USAGE_ENVIRON
+ req_access = list(ACCESS_ATMOSPHERICS)
+ max_integrity = 250
+ integrity_failure = 0.33
+ armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 90, ACID = 30, STAMINA = 0, BLEED = 0)
+ resistance_flags = FIRE_PROOF
+ clicksound = 'sound/machines/terminal_select.ogg'
+ layer = ABOVE_WINDOW_LAYER
+
+ /// Current alert level of our air alarm.
+ /// [AIR_ALARM_ALERT_NONE], [AIR_ALARM_ALERT_MINOR], [AIR_ALARM_ALERT_SEVERE]
+ var/danger_level = AIR_ALARM_ALERT_NONE
+
+ /// Currently selected mode of the alarm. An instance of [/datum/air_alarm_mode].
+ var/datum/air_alarm_mode/selected_mode
+ ///A reference to the area we are in
+ var/area/my_area
+
+ /// Boolean for whether the current air alarm can be tweaked by players or not.
+ var/locked = TRUE
+ /// Boolean to prevent AI from tampering with this alarm.
+ var/aidisabled = FALSE
+ /// Boolean of whether alarm is currently shorted. Mess up some functionalities.
+ var/shorted = FALSE
+
+ /// Current build stage. [AIRALARM_BUILD_COMPLETE], [AIRALARM_BUILD_NO_WIRES], [AIRALARM_BUILD_NO_CIRCUIT]
+ var/buildstage = AIR_ALARM_BUILD_COMPLETE
+
+ ///Represents a signel source of atmos alarms, complains to all the listeners if one of our thresholds is violated
+ var/datum/alarm_handler/alarm_manager
+
+ var/static/list/atmos_connections = list(COMSIG_TURF_EXPOSE = PROC_REF(check_danger))
+
+ /// An assoc list of [datum/tlv]s, indexed by "pressure", "temperature", and [datum/gas] typepaths.
+ var/list/datum/tlv/tlv_collection
+
+ /// Used for air alarm helper called unlocked to make air alarm unlocked.
+ var/unlocked = FALSE
+ /// Used for air alarm helper called syndicate_access to make air alarm's required access syndicate_access.
+ var/syndicate_access = FALSE
+ /// Used for air alarm helper called away_general_access to make air alarm's required access away_general_access.
+ var/away_general_access = FALSE
+ /// Used for air alarm helper called engine_access to make air alarm's required access one of ACCESS_ATMOSPHERICS & ACCESS_ENGINEERING.
+ var/engine_access = FALSE
+ /// Used for air alarm helper called mixingchamber_access to make air alarm's required access one of ACCESS_ATMOSPHERICS & ACCESS_ORDNANCE.
+ var/mixingchamber_access = FALSE
+ /// Used for air alarm helper called all_access to remove air alarm's required access.
+ var/all_access = FALSE
+
+ /// Used for air alarm helper called tlv_cold_room to adjust alarm thresholds for cold room.
+ var/tlv_cold_room = FALSE
+ /// Used for air alarm helper called tlv_no_ckecks to remove alarm thresholds.
+ var/tlv_no_checks = FALSE
+
+
+ ///Warning message spoken by air alarms
+ var/warning_message = null
+
+ //Stops the air alarm from talking about their atmos problems.
+ var/speaker_enabled = TRUE
+
+ ///Cooldown on sending warning messages
+ COOLDOWN_DECLARE(warning_cooldown)
+
+ /// Used for connecting air alarm to a remote tile/zone via air sensor instead of the tile/zone of the air alarm
+ var/obj/machinery/air_sensor/connected_sensor
+ /// Used to link air alarm to air sensor via map helpers
+ var/air_sensor_chamber_id = ""
+ /// Whether it is possible to link/unlink this air alarm from a sensor
+ var/allow_link_change = TRUE
+
+GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm)
+
+/obj/machinery/airalarm/Initialize(mapload, ndir, nbuild)
+ . = ..()
+ wires = new /datum/wires/airalarm(src)
+ if(ndir)
+ setDir(ndir)
+
+ if(nbuild)
+ buildstage = AIR_ALARM_BUILD_NO_CIRCUIT
+ panel_open = TRUE
+
+ if(name == initial(name))
+ name = "[get_area_name(src)] Air Alarm"
+
+ tlv_collection = list()
+ tlv_collection["pressure"] = new /datum/tlv/pressure
+ tlv_collection["temperature"] = new /datum/tlv/temperature
+
+ var/list/cached_gas_info = GLOB.meta_gas_info
+ for(var/datum/gas/gas_path as anything in cached_gas_info)
+ if(ispath(gas_path, /datum/gas/oxygen))
+ tlv_collection[gas_path] = new /datum/tlv/oxygen
+ else if(ispath(gas_path, /datum/gas/carbon_dioxide))
+ tlv_collection[gas_path] = new /datum/tlv/carbon_dioxide
+ else if(cached_gas_info[gas_path][META_GAS_DANGER])
+ tlv_collection[gas_path] = new /datum/tlv/dangerous
+ else
+ tlv_collection[gas_path] = new /datum/tlv/no_checks
+
+ my_area = connected_sensor ? get_area(connected_sensor) : get_area(src)
+ alarm_manager = new(src)
+ select_mode(src, /datum/air_alarm_mode/filtering, should_apply = FALSE)
+
+ AddElement(/datum/element/connect_loc, atmos_connections)
+ AddComponent(/datum/component/usb_port, list(
+ /obj/item/circuit_component/air_alarm_general,
+ /obj/item/circuit_component/air_alarm,
+ /obj/item/circuit_component/air_alarm_scrubbers,
+ /obj/item/circuit_component/air_alarm_vents
+ ))
+
+ GLOB.air_alarms += src
+ find_and_hang_on_wall()
+ check_enviroment()
+
+/obj/machinery/airalarm/process()
+ if(!COOLDOWN_FINISHED(src, warning_cooldown))
+ return
+
+ speak(warning_message)
+ COOLDOWN_START(src, warning_cooldown, AIRALARM_WARNING_COOLDOWN)
+
+/obj/machinery/airalarm/Destroy()
+ if(my_area)
+ my_area = null
+ if(connected_sensor)
+ UnregisterSignal(connected_sensor, COMSIG_PARENT_QDELETING)
+ UnregisterSignal(connected_sensor.loc, COMSIG_TURF_EXPOSE)
+ connected_sensor.connected_airalarm = null
+ connected_sensor = null
+
+ QDEL_NULL(alarm_manager)
+ GLOB.air_alarms -= src
+ return ..()
+
+/obj/machinery/airalarm/proc/check_enviroment()
+ var/turf/our_turf = connected_sensor ? get_turf(connected_sensor) : get_turf(src)
+ var/datum/gas_mixture/environment = our_turf.return_air()
+ if(isnull(environment))
+ return
+ check_danger(our_turf, environment, environment.temperature)
+
+/obj/machinery/airalarm/proc/get_enviroment()
+ var/turf/our_turf = connected_sensor ? get_turf(connected_sensor) : get_turf(src)
+ return our_turf.return_air()
+
+/obj/machinery/airalarm/power_change()
+ check_enviroment()
+ return ..()
+
+/obj/machinery/airalarm/on_enter_area(datum/source, area/area_to_register)
+ //were already registered to an area. exit from here first before entering into an new area
+ if(!isnull(my_area))
+ return
+ . = ..()
+
+ my_area = connected_sensor ? get_area(connected_sensor) : area_to_register
+ update_appearance()
+
+/obj/machinery/airalarm/update_name(updates)
+ . = ..()
+ name = "[get_area_name(my_area)] Air Alarm"
+
+/obj/machinery/airalarm/on_exit_area(datum/source, area/area_to_unregister)
+ //we cannot unregister from an area we never registered to in the first place
+ if(my_area != area_to_unregister)
+ return
+ . = ..()
+
+ my_area = connected_sensor ? get_area(connected_sensor) : null
+
+/obj/machinery/airalarm/examine(mob/user)
+ . = ..()
+ switch(buildstage)
+ if(AIR_ALARM_BUILD_NO_CIRCUIT)
+ . += span_notice("It is missing air alarm electronics.")
+ if(AIR_ALARM_BUILD_NO_WIRES)
+ . += span_notice("It is missing wiring.")
+ if(AIR_ALARM_BUILD_COMPLETE)
+ . += span_notice("Right-click to [locked ? "unlock" : "lock"] the interface.")
+
+/obj/machinery/airalarm/ui_status(mob/user, datum/ui_state/state)
+ if(HAS_SILICON_ACCESS(user) && aidisabled)
+ to_chat(user, "AI control has been disabled.")
+ else if(!shorted)
+ return ..()
+ return UI_CLOSE
+
+/obj/machinery/airalarm/multitool_act(mob/living/user, obj/item/multitool/multi_tool)
+ .= ..()
+
+ if (!istype(multi_tool) || locked)
+ return .
+
+ if(istype(multi_tool.buffer, /obj/machinery/air_sensor))
+ var/obj/machinery/air_sensor/sensor = multi_tool.buffer
+
+ if(!allow_link_change)
+ balloon_alert(user, "linking disabled")
+ return ITEM_INTERACT_BLOCKING
+ if(connected_sensor || sensor.connected_airalarm)
+ balloon_alert(user, "sensor already connected!")
+ return ITEM_INTERACT_BLOCKING
+
+ connect_sensor(sensor)
+ balloon_alert(user, "connected sensor")
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/airalarm/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "AirAlarm", name)
+ ui.open()
+
+/obj/machinery/airalarm/ui_static_data(mob/user)
+ var/list/data = list()
+ data["thresholdTypeMap"] = list(
+ "warning_min" = TLV_VAR_WARNING_MIN,
+ "hazard_min" = TLV_VAR_HAZARD_MIN,
+ "warning_max" = TLV_VAR_WARNING_MAX,
+ "hazard_max" = TLV_VAR_HAZARD_MAX,
+ "all" = TLV_VAR_ALL,
+ )
+ return data
+
+/obj/machinery/airalarm/ui_data(mob/user)
+ var/data = list()
+
+ data["locked"] = locked
+ data["siliconUser"] = HAS_SILICON_ACCESS(user)
+ data["emagged"] = (obj_flags & EMAGGED ? 1 : 0)
+ data["dangerLevel"] = danger_level
+ data["atmosAlarm"] = !!my_area.active_alarms[ALARM_ATMOS]
+ data["fireAlarm"] = my_area.fire
+ data["faultStatus"] = my_area.fault_status
+ data["faultLocation"] = my_area.fault_location
+ data["sensor"] = !!connected_sensor
+ data["allowLinkChange"] = allow_link_change
+
+ var/datum/gas_mixture/environment = get_enviroment()
+ var/total_moles = environment.total_moles()
+ var/temp = environment.temperature
+ var/pressure = environment.return_pressure()
+
+ data["envData"] = list()
+ if(connected_sensor)
+ data["envData"] += list(list(
+ "name" = "Linked area",
+ "value" = my_area.name
+ ))
+ data["envData"] += list(list(
+ "name" = "Pressure",
+ "value" = "[round(pressure, 0.01)] kPa",
+ "danger" = tlv_collection["pressure"].check_value(pressure)
+ ))
+ data["envData"] += list(list(
+ "name" = "Temperature",
+ "value" = "[round(temp, 0.01)] Kelvin / [round(temp, 0.01) - T0C] Celcius",
+ "danger" = tlv_collection["temperature"].check_value(temp),
+ ))
+ if(total_moles)
+ for(var/gas_path in environment.gases)
+ var/moles = environment.gases[gas_path][MOLES]
+ var/portion = moles / total_moles
+ data["envData"] += list(list(
+ "name" = GLOB.meta_gas_info[gas_path][META_GAS_NAME],
+ "value" = "[round(moles, 0.01)] moles / [round(100 * portion, 0.01)] % / [round(portion * pressure, 0.01)] kPa",
+ "danger" = tlv_collection[gas_path].check_value(portion * pressure),
+ ))
+
+ data["tlvSettings"] = list()
+ for(var/threshold in tlv_collection)
+ var/datum/tlv/tlv = tlv_collection[threshold]
+ var/list/singular_tlv = list()
+ if(threshold == "pressure")
+ singular_tlv["name"] = "Pressure"
+ singular_tlv["unit"] = "kPa"
+ else if (threshold == "temperature")
+ singular_tlv["name"] = "Temperature"
+ singular_tlv["unit"] = "K"
+ else
+ singular_tlv["name"] = GLOB.meta_gas_info[threshold][META_GAS_NAME]
+ singular_tlv["unit"] = "kPa"
+ singular_tlv["id"] = threshold
+ singular_tlv["warning_min"] = tlv.warning_min
+ singular_tlv["hazard_min"] = tlv.hazard_min
+ singular_tlv["warning_max"] = tlv.warning_max
+ singular_tlv["hazard_max"] = tlv.hazard_max
+ data["tlvSettings"] += list(singular_tlv)
+
+ if(!locked || HAS_SILICON_ACCESS(user))
+ data["vents"] = list()
+ for(var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in my_area.air_vents)
+ data["vents"] += list(list(
+ "refID" = REF(vent),
+ "long_name" = sanitize(vent.name),
+ "power" = vent.on,
+ "overclock" = vent.fan_overclocked,
+ "integrity" = vent.get_integrity_percentage(),
+ "checks" = vent.pressure_checks,
+ "excheck" = vent.pressure_checks & ATMOS_EXTERNAL_BOUND,
+ "incheck" = vent.pressure_checks & ATMOS_INTERNAL_BOUND,
+ "direction" = vent.pump_direction,
+ "external" = vent.external_pressure_bound,
+ "internal" = vent.internal_pressure_bound,
+ "extdefault" = (vent.external_pressure_bound == ONE_ATMOSPHERE),
+ "intdefault" = (vent.internal_pressure_bound == 0)
+ ))
+ data["scrubbers"] = list()
+ for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in my_area.air_scrubbers)
+ var/list/filter_types = list()
+ for (var/path in GLOB.meta_gas_info)
+ var/list/gas = GLOB.meta_gas_info[path]
+ filter_types += list(list("gas_id" = gas[META_GAS_ID], "gas_name" = gas[META_GAS_NAME], "enabled" = (path in scrubber.filter_types)))
+ data["scrubbers"] += list(list(
+ "refID" = REF(scrubber),
+ "long_name" = sanitize(scrubber.name),
+ "power" = scrubber.on,
+ "scrubbing" = scrubber.scrubbing,
+ "widenet" = scrubber.widenet,
+ "filter_types" = filter_types,
+ ))
+
+ data["selectedModePath"] = selected_mode.type
+ data["modes"] = list()
+ for(var/mode_path in GLOB.air_alarm_modes)
+ var/datum/air_alarm_mode/mode = GLOB.air_alarm_modes[mode_path]
+ if(!(obj_flags & EMAGGED) && mode.emag)
+ continue
+ data["modes"] += list(list(
+ "name" = mode.name,
+ "desc" = mode.desc,
+ "danger" = mode.danger,
+ "path" = mode.type
+ ))
+
+ // forgive me holy father
+ data["panicSiphonPath"] = /datum/air_alarm_mode/panic_siphon
+ data["filteringPath"] = /datum/air_alarm_mode/filtering
+
+ return data
+
+/obj/machinery/airalarm/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+
+ if(. || buildstage != AIR_ALARM_BUILD_COMPLETE)
+ return
+ var/mob/user = ui.user
+ if((locked && !HAS_SILICON_ACCESS(user)) || (HAS_SILICON_ACCESS(user) && aidisabled))
+ return
+
+ var/area/area = connected_sensor ? get_area(connected_sensor) : get_area(src)
+
+ ASSERT(!isnull(area))
+
+ var/ref = params["ref"]
+ var/obj/machinery/atmospherics/components/unary/vent_pump/vent
+ var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber
+ if(!isnull(ref))
+ scrubber = locate(ref) in area.air_scrubbers
+ vent = locate(ref) in area.air_vents
+
+ switch (action)
+ if ("power")
+ var/obj/machinery/atmospherics/components/powering = vent || scrubber
+ powering.on = !!params["val"]
+ powering.atmos_conditions_changed()
+ powering.update_appearance(UPDATE_ICON)
+
+ if("overclock")
+ if(isnull(vent))
+ return TRUE
+ vent.toggle_overclock(source = key_name(user))
+ vent.update_appearance(UPDATE_ICON)
+ return TRUE
+
+ if ("direction")
+ if (isnull(vent))
+ return TRUE
+
+ var/value = params["val"]
+
+ if (value == ATMOS_DIRECTION_SIPHONING || value == ATMOS_DIRECTION_RELEASING)
+ vent.pump_direction = value
+ vent.update_appearance(UPDATE_ICON)
+ if ("incheck")
+ if (isnull(vent))
+ return TRUE
+
+ var/new_checks = clamp((text2num(params["val"]) || 0) ^ ATMOS_INTERNAL_BOUND, NONE, ATMOS_BOUND_MAX)
+ vent.pressure_checks = new_checks
+ vent.update_appearance(UPDATE_ICON)
+ if ("excheck")
+ if (isnull(vent))
+ return TRUE
+
+ var/new_checks = clamp((text2num(params["val"]) || 0) ^ ATMOS_EXTERNAL_BOUND, NONE, ATMOS_BOUND_MAX)
+ vent.pressure_checks = new_checks
+ vent.update_appearance(UPDATE_ICON)
+ if ("set_internal_pressure")
+ if (isnull(vent))
+ return TRUE
+
+ var/old_pressure = vent.internal_pressure_bound
+ var/new_pressure = clamp(text2num(params["value"]), 0, ATMOS_PUMP_MAX_PRESSURE)
+ vent.internal_pressure_bound = new_pressure
+ if (old_pressure != new_pressure)
+ vent.investigate_log("internal pressure was set to [new_pressure] by [key_name(user)]", INVESTIGATE_ATMOS)
+ if ("reset_internal_pressure")
+ if (isnull(vent))
+ return TRUE
+
+ if (vent.internal_pressure_bound != 0)
+ vent.internal_pressure_bound = 0
+ vent.investigate_log("internal pressure was reset by [key_name(user)]", INVESTIGATE_ATMOS)
+ if ("set_external_pressure")
+ if (isnull(vent))
+ return TRUE
+
+ var/old_pressure = vent.external_pressure_bound
+ var/new_pressure = clamp(text2num(params["value"]), 0, ATMOS_PUMP_MAX_PRESSURE)
+
+ if (old_pressure == new_pressure)
+ return TRUE
+
+ vent.external_pressure_bound = new_pressure
+ vent.investigate_log("external pressure was set to [new_pressure] by [key_name(user)]", INVESTIGATE_ATMOS)
+ vent.update_appearance(UPDATE_ICON)
+ if ("reset_external_pressure")
+ if (isnull(vent))
+ return TRUE
+
+ if (vent.external_pressure_bound == ATMOS_PUMP_MAX_PRESSURE)
+ return TRUE
+
+ vent.external_pressure_bound = ATMOS_PUMP_MAX_PRESSURE
+ vent.investigate_log("internal pressure was reset by [key_name(user)]", INVESTIGATE_ATMOS)
+ vent.update_appearance(UPDATE_ICON)
+ if ("scrubbing")
+ if (isnull(scrubber))
+ return TRUE
+
+ scrubber.set_scrubbing(!!params["val"], user)
+ if ("widenet")
+ if (isnull(scrubber))
+ return TRUE
+
+ scrubber.set_widenet(!!params["val"])
+ if ("toggle_filter")
+ if (isnull(scrubber))
+ return TRUE
+
+ scrubber.toggle_filters(params["val"])
+ if ("mode")
+ select_mode(user, text2path(params["mode"]))
+ investigate_log("was turned to [selected_mode.name] mode by [key_name(user)]", INVESTIGATE_ATMOS)
+
+ if ("set_threshold")
+ var/threshold = text2path(params["threshold"]) || params["threshold"]
+ var/datum/tlv/tlv = tlv_collection[threshold]
+ if(isnull(tlv))
+ return
+ var/threshold_type = params["threshold_type"]
+ var/value = params["value"]
+ tlv.set_value(threshold_type, value)
+ investigate_log("threshold value for [threshold]:[threshold_type] was set to [value] by [key_name(user)]", INVESTIGATE_ATMOS)
+
+ check_enviroment()
+
+ if("reset_threshold")
+ var/threshold = text2path(params["threshold"]) || params["threshold"]
+ var/datum/tlv/tlv = tlv_collection[threshold]
+ if(isnull(tlv))
+ return
+ var/threshold_type = params["threshold_type"]
+ tlv.reset_value(threshold_type)
+ investigate_log("threshold value for [threshold]:[threshold_type] was reset by [key_name(user)]", INVESTIGATE_ATMOS)
+
+ check_enviroment()
+
+ if ("alarm")
+ if (alarm_manager.send_alarm(ALARM_ATMOS))
+ danger_level = AIR_ALARM_ALERT_HAZARD
+
+ if ("reset")
+ if (alarm_manager.clear_alarm(ALARM_ATMOS))
+ danger_level = AIR_ALARM_ALERT_NONE
+
+ if ("disconnect_sensor")
+ if(allow_link_change)
+ disconnect_sensor()
+
+ if ("lock")
+ togglelock(user)
+ return TRUE
+
+ update_appearance()
+
+ return TRUE
+
+/obj/machinery/airalarm/update_appearance(updates)
+ . = ..()
+
+ if(panel_open || (machine_stat & (NOPOWER|BROKEN)) || shorted)
+ set_light(0)
+ return
+
+ var/color
+ if(danger_level == AIR_ALARM_ALERT_HAZARD)
+ color = "#FF0022" // red
+ else if(danger_level == AIR_ALARM_ALERT_WARNING || my_area.active_alarms[ALARM_ATMOS])
+ color = "#FFAA00" // yellow
+ else
+ color = "#00FFCC" // teal
+
+ set_light(1.5, 1, color)
+
+/obj/machinery/airalarm/update_icon_state()
+ if(panel_open)
+ switch(buildstage)
+ if(AIR_ALARM_BUILD_COMPLETE)
+ icon_state = "alarmx"
+ if(AIR_ALARM_BUILD_NO_WIRES)
+ icon_state = "alarm_b2"
+ if(AIR_ALARM_BUILD_NO_CIRCUIT)
+ icon_state = "alarm_b1"
+ return ..()
+
+ icon_state = isnull(connected_sensor) ? "alarmp" : "alarmp_remote"
+ return ..()
+
+/obj/machinery/airalarm/update_overlays()
+ . = ..()
+
+ if(panel_open || (machine_stat & (NOPOWER|BROKEN)) || shorted)
+ return
+
+ var/state
+ if(danger_level == AIR_ALARM_ALERT_HAZARD)
+ state = "alarm1"
+ else if(danger_level == AIR_ALARM_ALERT_WARNING || my_area.active_alarms[ALARM_ATMOS])
+ state = "alarm2"
+ else
+ state = "alarm0"
+
+ . += mutable_appearance(icon, state)
+ . += emissive_appearance(icon, state, src, alpha = src.alpha)
+
+/// Check the current air and update our danger level.
+/// [/obj/machinery/airalarm/var/danger_level]
+/obj/machinery/airalarm/proc/check_danger(turf/location, datum/gas_mixture/environment, exposed_temperature)
+ SIGNAL_HANDLER
+ if((machine_stat & (NOPOWER|BROKEN)) || shorted)
+ return
+
+ if(!environment)
+ return
+
+ var/old_danger = danger_level
+ danger_level = AIR_ALARM_ALERT_NONE
+
+ var/total_moles = environment.total_moles()
+ var/pressure = environment.return_pressure()
+ var/temp = environment.return_temperature()
+
+ danger_level = max(danger_level, tlv_collection["pressure"].check_value(pressure))
+ danger_level = max(danger_level, tlv_collection["temperature"].check_value(temp))
+ if(total_moles)
+ var/list/cached_gas_info = GLOB.meta_gas_info
+ for(var/datum/gas/gas_path as anything in cached_gas_info)
+ var/moles = environment.gases[gas_path] ? environment.gases[gas_path][MOLES] : 0
+ danger_level = max(danger_level, tlv_collection[gas_path].check_value(pressure * moles / total_moles))
+
+ if(danger_level)
+ alarm_manager.send_alarm(ALARM_ATMOS)
+ var/is_high_pressure = tlv_collection["pressure"].hazard_max != TLV_VALUE_IGNORE && pressure >= tlv_collection["pressure"].hazard_max
+ var/is_high_temp = tlv_collection["temperature"].hazard_max != TLV_VALUE_IGNORE && temp >= tlv_collection["temperature"].hazard_max
+ var/is_low_pressure = tlv_collection["pressure"].hazard_min != TLV_VALUE_IGNORE && pressure <= tlv_collection["pressure"].hazard_min
+ var/is_low_temp = tlv_collection["temperature"].hazard_min != TLV_VALUE_IGNORE && temp <= tlv_collection["temperature"].hazard_min
+
+ if(is_low_pressure && is_low_temp)
+ warning_message = "Danger! Low pressure and temperature detected."
+ return
+ if(is_low_pressure && is_high_temp)
+ warning_message = "Danger! Low pressure and high temperature detected."
+ return
+ if(is_high_pressure && is_high_temp)
+ warning_message = "Danger! High pressure and temperature detected."
+ return
+ if(is_high_pressure && is_low_temp)
+ warning_message = "Danger! High pressure and low temperature detected."
+ return
+ if(is_low_pressure)
+ warning_message = "Danger! Low pressure detected."
+ return
+ if(is_high_pressure)
+ warning_message = "Danger! High pressure detected."
+ return
+ if(is_low_temp)
+ warning_message = "Danger! Low temperature detected."
+ return
+ if(is_high_temp)
+ warning_message = "Danger! High temperature detected."
+ return
+ else
+ warning_message = null
+
+ else
+ alarm_manager.clear_alarm(ALARM_ATMOS)
+ warning_message = null
+
+ if(old_danger != danger_level)
+ update_appearance()
+
+ selected_mode.replace(my_area, pressure)
+
+/obj/machinery/airalarm/proc/select_mode(atom/source, datum/air_alarm_mode/mode_path, should_apply = TRUE)
+ var/datum/air_alarm_mode/new_mode = GLOB.air_alarm_modes[mode_path]
+ if(!new_mode)
+ return
+ if(new_mode.emag && !(obj_flags & EMAGGED))
+ return
+ selected_mode = new_mode
+ if(should_apply)
+ selected_mode.apply(my_area)
+ SEND_SIGNAL(src, COMSIG_AIRALARM_UPDATE_MODE, source)
+
+MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/airalarm, 27)
+
+/obj/machinery/airalarm/proc/speak(warning_message)
+ if(machine_stat & (BROKEN|NOPOWER))
+ return
+ if(!speaker_enabled)
+ return
+ if(!warning_message)
+ return
+
+ say(warning_message)
+
+/// Used for unlocked air alarm helper, which unlocks the air alarm.
+/obj/machinery/airalarm/proc/unlock()
+ locked = FALSE
+
+/// Used for syndicate_access air alarm helper, which sets air alarm's required access to syndicate_access.
+/obj/machinery/airalarm/proc/give_syndicate_access()
+ req_access = list(ACCESS_SYNDICATE)
+
+///Used for away_general_access air alarm helper, which set air alarm's required access to away_general_access.
+/obj/machinery/airalarm/proc/give_away_general_access()
+ req_access = list(ACCESS_AWAY_GENERAL)
+
+///Used for engine_access air alarm helper, which set air alarm's required access to away_general_access.
+/obj/machinery/airalarm/proc/give_engine_access()
+ name = "engine air alarm"
+ locked = FALSE
+ req_access = null
+ req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ENGINEERING)
+
+///Used for mixingchamber_access air alarm helper, which set air alarm's required access to away_general_access.
+/obj/machinery/airalarm/proc/give_mixingchamber_access()
+ name = "chamber air alarm"
+ locked = FALSE
+ req_access = null
+ req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ORDNANCE)
+
+///Used for all_access air alarm helper, which set air alarm's required access to null.
+/obj/machinery/airalarm/proc/give_all_access()
+ name = "all-access air alarm"
+ desc = "This particular atmos control unit appears to have no access restrictions."
+ locked = FALSE
+ req_access = null
+ req_one_access = null
+
+///Used for air alarm cold room tlv helper, which sets cold room temperature and pressure alarm thresholds
+/obj/machinery/airalarm/proc/set_tlv_cold_room()
+ tlv_collection["temperature"] = new /datum/tlv/cold_room_temperature
+ tlv_collection["pressure"] = new /datum/tlv/cold_room_pressure
+
+///Used for air alarm no tlv helper, which removes alarm thresholds
+/obj/machinery/airalarm/proc/set_tlv_no_checks()
+ tlv_collection["temperature"] = new /datum/tlv/no_checks
+ tlv_collection["pressure"] = new /datum/tlv/no_checks
+
+ for(var/gas_path in GLOB.meta_gas_info)
+ tlv_collection[gas_path] = new /datum/tlv/no_checks
+
+///Used for air alarm link helper, which connects air alarm to a sensor with corresponding chamber_id
+/obj/machinery/airalarm/proc/setup_chamber_link()
+ var/obj/machinery/air_sensor/sensor = GLOB.objects_by_id_tag[GLOB.map_loaded_sensors[air_sensor_chamber_id]]
+ if(isnull(sensor))
+ log_mapping("[src] at [AREACOORD(src)] tried to connect to a sensor, but no sensor with chamber_id:[air_sensor_chamber_id] found!")
+ return
+ if(connected_sensor)
+ log_mapping("[src] at [AREACOORD(src)] tried to connect to more than one sensor!")
+ return
+ connect_sensor(sensor)
+
+///Used to connect air alarm with a sensor
+/obj/machinery/airalarm/proc/connect_sensor(obj/machinery/air_sensor/sensor)
+ sensor.connected_airalarm = src
+ connected_sensor = sensor
+
+ RegisterSignal(connected_sensor, COMSIG_PARENT_QDELETING, PROC_REF(disconnect_sensor))
+
+ // Transfer signal from air alarm to sensor
+ UnregisterSignal(loc, COMSIG_TURF_EXPOSE)
+ RegisterSignal(connected_sensor.loc, COMSIG_TURF_EXPOSE, PROC_REF(check_danger), override=TRUE)
+
+ my_area = get_area(connected_sensor)
+
+ check_enviroment()
+
+ update_appearance()
+ update_name()
+
+///Used to reset the air alarm to default configuration after disconnecting from air sensor
+/obj/machinery/airalarm/proc/disconnect_sensor()
+ UnregisterSignal(connected_sensor, COMSIG_PARENT_QDELETING)
+
+ // Transfer signal from sensor to air alarm
+ UnregisterSignal(connected_sensor.loc, COMSIG_TURF_EXPOSE)
+ RegisterSignal(loc, COMSIG_TURF_EXPOSE, PROC_REF(check_danger), override=TRUE)
+
+ connected_sensor.connected_airalarm = null
+ connected_sensor = null
+ my_area = get_area(src)
+
+ check_enviroment()
+
+ update_appearance()
+ update_name()
+
+#undef AIRALARM_WARNING_COOLDOWN
diff --git a/code/modules/atmospherics/machinery/air_alarm/air_alarm_circuit.dm b/code/modules/atmospherics/machinery/air_alarm/air_alarm_circuit.dm
new file mode 100644
index 0000000000000..1f38c3d40cb8d
--- /dev/null
+++ b/code/modules/atmospherics/machinery/air_alarm/air_alarm_circuit.dm
@@ -0,0 +1,684 @@
+/obj/item/circuit_component/air_alarm_general
+ display_name = "Air Alarm"
+ desc = "Outputs basic information that the air alarm has recorded"
+
+ var/obj/machinery/airalarm/connected_alarm
+
+ /// Enables the fire alarm
+ var/datum/port/input/enable_fire_alarm
+ /// Disables the fire alarm
+ var/datum/port/input/disable_fire_alarm
+
+ /// The mode to set the air alarm to
+ var/datum/port/input/option/mode
+ /// The trigger to set the mode
+ var/datum/port/input/set_mode
+
+ /// Whether the fire alarm is enabled or not
+ var/datum/port/output/fire_alarm_enabled
+ /// The current set mode
+ var/datum/port/output/current_mode
+
+ var/static/list/options_map
+
+/obj/item/circuit_component/air_alarm_general/populate_options()
+ if(!options_map)
+ options_map = list()
+ for(var/mode_path in GLOB.air_alarm_modes)
+ var/datum/air_alarm_mode/mode = GLOB.air_alarm_modes[mode_path]
+ if(!mode.emag)
+ options_map[mode.name] = mode.type
+
+/obj/item/circuit_component/air_alarm_general/populate_ports()
+ mode = add_option_port("Mode", options_map, order = 1)
+ set_mode = add_input_port("Set Mode", PORT_TYPE_SIGNAL, trigger = PROC_REF(set_mode))
+ enable_fire_alarm = add_input_port("Enable Alarm", PORT_TYPE_SIGNAL, trigger = PROC_REF(trigger_alarm))
+ disable_fire_alarm = add_input_port("Disable Alarm", PORT_TYPE_SIGNAL, trigger = PROC_REF(trigger_alarm))
+
+ fire_alarm_enabled = add_output_port("Alarm Enabled", PORT_TYPE_NUMBER)
+ current_mode = add_output_port("Current Mode", PORT_TYPE_STRING)
+
+/obj/item/circuit_component/air_alarm_general/register_usb_parent(atom/movable/shell)
+ . = ..()
+ if(istype(shell, /obj/machinery/airalarm))
+ connected_alarm = shell
+ RegisterSignal(connected_alarm.alarm_manager, COMSIG_ALARM_TRIGGERED, PROC_REF(on_alarm_triggered))
+ RegisterSignal(connected_alarm.alarm_manager, COMSIG_ALARM_CLEARED, PROC_REF(on_alarm_cleared))
+ RegisterSignal(shell, COMSIG_AIRALARM_UPDATE_MODE, PROC_REF(on_mode_updated))
+ current_mode.set_value(connected_alarm.selected_mode.name)
+
+/obj/item/circuit_component/air_alarm_general/unregister_usb_parent(atom/movable/shell)
+ if(connected_alarm)
+ UnregisterSignal(connected_alarm.alarm_manager, list(
+ COMSIG_ALARM_TRIGGERED,
+ COMSIG_ALARM_CLEARED,
+ ))
+ connected_alarm = null
+
+ UnregisterSignal(shell, list(
+ COMSIG_AIRALARM_UPDATE_MODE,
+ ))
+ return ..()
+
+/obj/item/circuit_component/air_alarm_general/proc/on_mode_updated(obj/machinery/airalarm/alarm, datum/signal_source)
+ SIGNAL_HANDLER
+ current_mode.set_value(alarm.selected_mode.name)
+
+/obj/item/circuit_component/air_alarm_general/proc/on_alarm_triggered(datum/source, alarm_type, area/location)
+ SIGNAL_HANDLER
+ if(alarm_type == ALARM_ATMOS)
+ fire_alarm_enabled.set_output(TRUE)
+
+/obj/item/circuit_component/air_alarm_general/proc/on_alarm_cleared(datum/source, alarm_type, area/location)
+ SIGNAL_HANDLER
+ if(alarm_type == ALARM_ATMOS)
+ fire_alarm_enabled.set_output(FALSE)
+
+
+/obj/item/circuit_component/air_alarm_general/proc/trigger_alarm(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ if(port == enable_fire_alarm)
+ if(connected_alarm.alarm_manager.send_alarm(ALARM_ATMOS))
+ connected_alarm.danger_level = AIR_ALARM_ALERT_HAZARD
+ else
+ if(connected_alarm.alarm_manager.clear_alarm(ALARM_ATMOS))
+ connected_alarm.danger_level = AIR_ALARM_ALERT_NONE
+
+/obj/item/circuit_component/air_alarm_general/proc/set_mode(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ if(!mode.value)
+ return
+
+ connected_alarm.select_mode(parent.get_creator(), options_map[mode.value])
+ connected_alarm.investigate_log("was turned to [connected_alarm.selected_mode.name] by [parent.get_creator()]")
+
+/obj/item/circuit_component/air_alarm
+ display_name = "Air Alarm Core Control"
+ desc = "Controls levels of gases and their temperature as well as all vents and scrubbers in the room."
+
+ var/datum/port/input/option/air_alarm_options
+
+ var/datum/port/input/min_2
+ var/datum/port/input/min_1
+ var/datum/port/input/max_1
+ var/datum/port/input/max_2
+
+ var/datum/port/input/set_data
+ var/datum/port/input/request_data
+
+ var/datum/port/output/pressure
+ var/datum/port/output/temperature
+ var/datum/port/output/gas_amount
+ var/datum/port/output/update_received
+
+ var/obj/machinery/airalarm/connected_alarm
+ var/list/options_map
+
+ ui_buttons = list(
+ "plus" = "add_new_component"
+ )
+
+ var/list/alarm_duplicates = list()
+ var/max_alarm_duplicates = 20
+
+/obj/item/circuit_component/air_alarm/ui_perform_action(mob/user, action)
+ if(length(alarm_duplicates) >= max_alarm_duplicates)
+ return
+
+ if(action == "add_new_component")
+ var/obj/item/circuit_component/air_alarm/component = new /obj/item/circuit_component/air_alarm/duplicate(parent)
+ parent.add_component(component)
+ RegisterSignal(component, COMSIG_PARENT_QDELETING, PROC_REF(on_duplicate_removed))
+ component.connected_alarm = connected_alarm
+ alarm_duplicates += component
+
+/obj/item/circuit_component/air_alarm/proc/on_duplicate_removed(datum/source)
+ SIGNAL_HANDLER
+ alarm_duplicates -= source
+
+/obj/item/circuit_component/air_alarm/populate_ports()
+ min_2 = add_input_port("Hazard Minimum", PORT_TYPE_NUMBER, trigger = null)
+ min_1 = add_input_port("Warning Minimum", PORT_TYPE_NUMBER, trigger = null)
+ max_1 = add_input_port("Warning Maximum", PORT_TYPE_NUMBER, trigger = null)
+ max_2 = add_input_port("Hazard Maximum", PORT_TYPE_NUMBER, trigger = null)
+ set_data = add_input_port("Set Limits", PORT_TYPE_SIGNAL, trigger = PROC_REF(set_limits))
+ request_data = add_input_port("Request Data", PORT_TYPE_SIGNAL)
+
+ pressure = add_output_port("Pressure", PORT_TYPE_NUMBER)
+ temperature = add_output_port("Temperature", PORT_TYPE_NUMBER)
+ gas_amount = add_output_port("Chosen Gas Amount", PORT_TYPE_NUMBER)
+ update_received = add_output_port("Update Received", PORT_TYPE_SIGNAL)
+
+/obj/item/circuit_component/air_alarm/populate_options()
+ var/static/list/component_options
+
+ if(!component_options)
+ component_options = list(
+ "Pressure" = "pressure",
+ "Temperature" = "temperature"
+ )
+
+ for(var/gas_id in GLOB.meta_gas_info)
+ component_options[GLOB.meta_gas_info[gas_id][META_GAS_NAME]] = gas_id2path(gas_id)
+
+ air_alarm_options = add_option_port("Air Alarm Options", component_options)
+ options_map = component_options
+
+/obj/item/circuit_component/air_alarm/duplicate
+ display_name = "Air Alarm Control"
+
+ circuit_size = 0
+ ui_buttons = list()
+
+/obj/item/circuit_component/air_alarm/duplicate/removed_from(obj/item/integrated_circuit/removed_from)
+ if(!QDELING(src))
+ qdel(src)
+ return ..()
+
+/obj/item/circuit_component/air_alarm/duplicate/Destroy()
+ connected_alarm = null
+ return ..()
+
+/obj/item/circuit_component/air_alarm/removed_from(obj/item/integrated_circuit/removed_from)
+ QDEL_LIST(alarm_duplicates)
+ return ..()
+
+/obj/item/circuit_component/air_alarm/register_usb_parent(atom/movable/shell)
+ . = ..()
+ if(istype(shell, /obj/machinery/airalarm))
+ connected_alarm = shell
+
+/obj/item/circuit_component/air_alarm/unregister_usb_parent(atom/movable/shell)
+ connected_alarm = null
+ for(var/obj/item/circuit_component/air_alarm/alarm as anything in alarm_duplicates)
+ alarm.connected_alarm = null
+ return ..()
+
+/obj/item/circuit_component/air_alarm/proc/set_limits()
+ CIRCUIT_TRIGGER
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/current_option = air_alarm_options.value
+
+ if(!current_option)
+ return
+
+ var/datum/tlv/settings = connected_alarm.tlv_collection[options_map[current_option]]
+ if(min_2.value != null)
+ settings.hazard_min = min_2.value
+ if(min_1.value != null)
+ settings.warning_min = min_1.value
+ if(max_1.value != null)
+ settings.warning_max = max_1.value
+ if(max_2.value != null)
+ settings.hazard_max = max_2.value
+
+/obj/item/circuit_component/air_alarm/input_received(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/current_option = air_alarm_options.value
+
+ var/turf/alarm_turf = get_turf(connected_alarm)
+ var/datum/gas_mixture/environment = alarm_turf.return_air()
+ pressure.set_output(round(environment.return_pressure()))
+ temperature.set_output(round(environment.temperature))
+ if(ispath(options_map[current_option]))
+ gas_amount.set_output(round(environment.gases[options_map[current_option]][MOLES]))
+
+ update_received.set_output(COMPONENT_SIGNAL)
+
+/obj/item/circuit_component/air_alarm_scrubbers
+ display_name = "Air Alarm Scrubber Core Control"
+ desc = "Controls the scrubbers in the room."
+
+ var/datum/port/input/option/scrubbers
+
+ /// Enables the scrubber
+ var/datum/port/input/enable
+ /// Disables the scrubber
+ var/datum/port/input/disable
+
+ /// Enables siphoning
+ var/datum/port/input/enable_siphon
+ /// Disables siphoning
+ var/datum/port/input/disable_siphon
+ /// Enables extended range
+ var/datum/port/input/enable_extended_range
+ /// Disables extended range
+ var/datum/port/input/disable_extended_range
+ /// Gas to filter using the scrubber
+ var/datum/port/input/gas_filter
+ /// Sets the filter
+ var/datum/port/input/set_gas_filter
+ /// Requests an update of the data
+ var/datum/port/input/request_update
+
+
+ /// Whether the scrubber is enabled or not
+ var/datum/port/output/enabled
+ /// Whether the scrubber is siphoning or not
+ var/datum/port/output/is_siphoning
+ /// Information based on what the scrubber is filtering. Outputs null if the scrubber is siphoning
+ var/datum/port/output/filtering
+ /// Sent when an update is received
+ var/datum/port/output/update_received
+
+ var/obj/machinery/airalarm/connected_alarm
+
+ ui_buttons = list(
+ "plus" = "add_new_component"
+ )
+
+ var/static/list/filtering_map = list()
+
+ var/max_scrubber_duplicates = 20
+ var/list/scrubber_duplicates = list()
+
+/obj/item/circuit_component/air_alarm_scrubbers/ui_perform_action(mob/user, action)
+ if(length(scrubber_duplicates) >= max_scrubber_duplicates)
+ return
+
+ if(action == "add_new_component")
+ var/obj/item/circuit_component/air_alarm_scrubbers/component = new /obj/item/circuit_component/air_alarm_scrubbers/duplicate(parent)
+ parent.add_component(component)
+ RegisterSignal(component, COMSIG_PARENT_QDELETING, PROC_REF(on_duplicate_removed))
+ component.connected_alarm = connected_alarm
+ component.scrubbers.possible_options = extract_id_tags(connected_alarm.my_area.air_scrubbers)
+ scrubber_duplicates += component
+
+/obj/item/circuit_component/air_alarm_scrubbers/proc/on_duplicate_removed(datum/source)
+ SIGNAL_HANDLER
+ scrubber_duplicates -= source
+
+/obj/item/circuit_component/air_alarm_scrubbers/populate_options()
+ scrubbers = add_option_port("Scrubber", null)
+
+/obj/item/circuit_component/air_alarm_scrubbers/populate_ports()
+ gas_filter = add_input_port("Gas To Filter", PORT_TYPE_LIST(PORT_TYPE_STRING), trigger = null)
+ set_gas_filter = add_input_port("Set Filter", PORT_TYPE_SIGNAL, trigger = PROC_REF(set_gas_to_filter))
+ enable_extended_range = add_input_port("Enable Extra Range", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_range))
+ disable_extended_range = add_input_port("Disable Extra Range", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_range))
+ enable_siphon = add_input_port("Enable Siphon", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_siphon))
+ disable_siphon = add_input_port("Disable Siphon", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_siphon))
+ enable = add_input_port("Enable", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_scrubber))
+ disable = add_input_port("Disable", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_scrubber))
+ request_update = add_input_port("Request Data", PORT_TYPE_SIGNAL, trigger = PROC_REF(update_data))
+
+ enabled = add_output_port("Enabled", PORT_TYPE_NUMBER)
+ is_siphoning = add_output_port("Siphoning", PORT_TYPE_NUMBER)
+ filtering = add_output_port("Filtered Gases", PORT_TYPE_LIST(PORT_TYPE_STRING))
+ update_received = add_output_port("Update Received", PORT_TYPE_SIGNAL)
+
+/obj/item/circuit_component/air_alarm_scrubbers/duplicate
+ display_name = "Air Alarm Scrubber Control"
+ circuit_size = 0
+ ui_buttons = list()
+
+/obj/item/circuit_component/air_alarm_scrubbers/duplicate/Destroy()
+ connected_alarm = null
+ return ..()
+
+/obj/item/circuit_component/air_alarm_scrubbers/duplicate/removed_from(obj/item/integrated_circuit/removed_from)
+ if(!QDELING(src))
+ qdel(src)
+ return ..()
+
+/obj/item/circuit_component/air_alarm_scrubbers/removed_from(obj/item/integrated_circuit/removed_from)
+ QDEL_LIST(scrubber_duplicates)
+ return ..()
+
+/obj/item/circuit_component/air_alarm_scrubbers/register_usb_parent(atom/movable/shell)
+ . = ..()
+ if(istype(shell, /obj/machinery/airalarm))
+ connected_alarm = shell
+ scrubbers.possible_options = extract_id_tags(connected_alarm.my_area.air_scrubbers)
+
+/obj/item/circuit_component/air_alarm_scrubbers/unregister_usb_parent(atom/movable/shell)
+ connected_alarm = null
+ scrubbers.possible_options = null
+ for(var/obj/item/circuit_component/air_alarm_scrubbers/scrubber as anything in scrubber_duplicates)
+ scrubber.connected_alarm = null
+ return ..()
+
+/obj/item/circuit_component/air_alarm_scrubbers/get_ui_notices()
+ . = ..()
+ var/static/list/meta_data = list()
+ if(length(meta_data) == 0)
+ for(var/typepath as anything in GLOB.meta_gas_info)
+ meta_data += GLOB.meta_gas_info[typepath][META_GAS_ID]
+ . += create_table_notices(meta_data, column_name = "Gas", column_name_plural = "Gases")
+
+/obj/item/circuit_component/air_alarm_scrubbers/proc/set_gas_to_filter(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ INVOKE_ASYNC(src, PROC_REF(set_gas_filter_async), port)
+
+/obj/item/circuit_component/air_alarm_scrubbers/proc/set_gas_filter_async(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/list/valid_filters = list()
+ for(var/info in gas_filter.value)
+ var/gas_type = gas_id2path(info)
+ if(!gas_type)
+ continue
+ valid_filters += gas_type
+
+ var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber = find_by_id_tag(connected_alarm.my_area.air_scrubbers, scrubbers.value)
+ if(isnull(scrubber))
+ return
+
+ scrubber.filter_types = valid_filters
+
+/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_scrubber(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ INVOKE_ASYNC(src, PROC_REF(toggle_scrubber_async), port)
+
+/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_scrubber_async(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ // var/scrubber_id = scrubbers.value
+ var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber = find_by_id_tag(connected_alarm.my_area.air_scrubbers, scrubbers.value)
+ if (isnull(scrubber))
+ return
+
+ scrubber.on = (port == enable)
+ scrubber.update_appearance(UPDATE_ICON)
+
+/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_range(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ INVOKE_ASYNC(src, PROC_REF(toggle_range_async), port)
+
+/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_range_async(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber = find_by_id_tag(connected_alarm.my_area.air_scrubbers, scrubbers.value)
+ if(isnull(scrubber))
+ return
+
+ scrubber.widenet = (port == enable_extended_range)
+ scrubber.update_appearance(UPDATE_ICON)
+
+/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_siphon(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ INVOKE_ASYNC(src, PROC_REF(toggle_siphon_async), port)
+
+/obj/item/circuit_component/air_alarm_scrubbers/proc/toggle_siphon_async(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber = find_by_id_tag(connected_alarm.my_area.air_scrubbers, scrubbers.value)
+ if(isnull(scrubber))
+ return
+
+ scrubber.scrubbing = (port != enable_siphon)
+ scrubber.update_appearance(UPDATE_ICON)
+
+/obj/item/circuit_component/air_alarm_scrubbers/proc/update_data()
+ CIRCUIT_TRIGGER
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber = find_by_id_tag(connected_alarm.my_area.air_scrubbers, scrubbers.value)
+ if(isnull(scrubber))
+ return
+
+ enabled.set_value(scrubber.on)
+ is_siphoning.set_value(scrubber.scrubbing == ATMOS_DIRECTION_SCRUBBING)
+
+ var/list/filtered = list()
+
+ for(var/datum/gas/gas_type as anything in scrubber.filter_types)
+ filtered += initial(gas_type.id)
+
+ filtering.set_value(filtered)
+
+ update_received.set_value(COMPONENT_SIGNAL)
+
+/obj/item/circuit_component/air_alarm_vents
+ display_name = "Air Alarm Vent Core Control"
+ desc = "Controls the vents in the room."
+
+ var/datum/port/input/option/vents
+
+ /// Enables the vent
+ var/datum/port/input/enable
+ /// Disables the vent
+ var/datum/port/input/disable
+
+ /// Enables siphoning
+ var/datum/port/input/enable_siphon
+ /// Disables siphoning
+ var/datum/port/input/disable_siphon
+ /// Enables external
+ var/datum/port/input/enable_external
+ /// Disables external
+ var/datum/port/input/disable_external
+ /// External target pressure
+ var/datum/port/input/external_pressure
+ /// Enables internal
+ var/datum/port/input/enable_internal
+ /// Disables internal
+ var/datum/port/input/disable_internal
+ /// Internal target pressure
+ var/datum/port/input/internal_pressure
+ /// Requests an update of the data
+ var/datum/port/input/request_update
+
+
+ /// Whether the scrubber is enabled or not
+ var/datum/port/output/enabled
+ /// Whether the scrubber is siphoning or not
+ var/datum/port/output/is_siphoning
+ /// Whether internal pressure is on or not
+ var/datum/port/output/internal_on
+ /// Whether external pressure is on or not
+ var/datum/port/output/external_on
+ /// Reported external pressure
+ var/datum/port/output/current_external_pressure
+ /// Reported internal pressure
+ var/datum/port/output/current_internal_pressure
+ /// Sent when an update is received
+ var/datum/port/output/update_received
+
+ var/obj/machinery/airalarm/connected_alarm
+
+ ui_buttons = list(
+ "plus" = "add_new_component"
+ )
+
+ var/static/list/filtering_map = list()
+
+ var/max_vent_duplicates = 20
+ var/list/vent_duplicates = list()
+
+/obj/item/circuit_component/air_alarm_vents/ui_perform_action(mob/user, action)
+ if(length(vent_duplicates) >= max_vent_duplicates)
+ return
+
+ if(action == "add_new_component")
+ var/obj/item/circuit_component/air_alarm_vents/component = new /obj/item/circuit_component/air_alarm_vents/duplicate(parent)
+ parent.add_component(component)
+ RegisterSignal(component, COMSIG_PARENT_QDELETING, PROC_REF(on_duplicate_removed))
+ vent_duplicates += component
+ component.connected_alarm = connected_alarm
+ component.vents.possible_options = extract_id_tags(connected_alarm.my_area.air_vents)
+
+/obj/item/circuit_component/air_alarm_vents/proc/on_duplicate_removed(datum/source)
+ SIGNAL_HANDLER
+ vent_duplicates -= source
+
+/obj/item/circuit_component/air_alarm_vents/populate_options()
+ vents = add_option_port("Vent", null)
+
+/obj/item/circuit_component/air_alarm_vents/populate_ports()
+ external_pressure = add_input_port("External Pressure", PORT_TYPE_NUMBER, trigger = PROC_REF(set_external_pressure))
+ internal_pressure = add_input_port("Internal Pressure", PORT_TYPE_NUMBER, trigger = PROC_REF(set_internal_pressure))
+
+ enable_external = add_input_port("Enable External", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_external))
+ disable_external = add_input_port("Disable External", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_external))
+ enable_internal = add_input_port("Enable Internal", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_internal))
+ disable_internal = add_input_port("Disable Internal", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_internal))
+
+ enable_siphon = add_input_port("Enable Siphon", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_siphon))
+ disable_siphon = add_input_port("Disable Siphon", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_siphon))
+ enable = add_input_port("Enable", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_vent))
+ disable = add_input_port("Disable", PORT_TYPE_SIGNAL, trigger = PROC_REF(toggle_vent))
+ request_update = add_input_port("Request Data", PORT_TYPE_SIGNAL, trigger = PROC_REF(update_data))
+
+ enabled = add_output_port("Enabled", PORT_TYPE_NUMBER)
+ is_siphoning = add_output_port("Siphoning", PORT_TYPE_NUMBER)
+ external_on = add_output_port("External On", PORT_TYPE_NUMBER)
+ internal_on = add_output_port("Internal On", PORT_TYPE_NUMBER)
+ current_external_pressure = add_output_port("External Pressure", PORT_TYPE_NUMBER)
+ current_internal_pressure = add_output_port("Internal Pressure", PORT_TYPE_NUMBER)
+ update_received = add_output_port("Update Received", PORT_TYPE_SIGNAL)
+
+/obj/item/circuit_component/air_alarm_vents/duplicate
+ display_name = "Air Alarm Vent Control"
+
+ circuit_size = 0
+ ui_buttons = list()
+
+/obj/item/circuit_component/air_alarm_vents/duplicate/removed_from(obj/item/integrated_circuit/removed_from)
+ if(!QDELING(src))
+ qdel(src)
+ return ..()
+
+/obj/item/circuit_component/air_alarm_vents/duplicate/Destroy()
+ connected_alarm = null
+ return ..()
+
+/obj/item/circuit_component/air_alarm_vents/removed_from(obj/item/integrated_circuit/removed_from)
+ QDEL_LIST(vent_duplicates)
+ return ..()
+
+/obj/item/circuit_component/air_alarm_vents/register_usb_parent(atom/movable/shell)
+ . = ..()
+ if(istype(shell, /obj/machinery/airalarm))
+ connected_alarm = shell
+ vents.possible_options = extract_id_tags(connected_alarm.my_area.air_vents)
+
+/obj/item/circuit_component/air_alarm_vents/unregister_usb_parent(atom/movable/shell)
+ connected_alarm = null
+ vents.possible_options = null
+ for(var/obj/item/circuit_component/air_alarm_vents/vent as anything in vent_duplicates)
+ vent.connected_alarm = null
+ return ..()
+
+/obj/item/circuit_component/air_alarm_vents/proc/toggle_vent(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ INVOKE_ASYNC(src, PROC_REF(toggle_vent_async), port)
+
+/obj/item/circuit_component/air_alarm_vents/proc/toggle_vent_async(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/obj/machinery/atmospherics/components/unary/vent_pump/vent = find_by_id_tag(connected_alarm.my_area.air_vents, vents.value)
+ if(isnull(vent))
+ return
+
+ vent.on = (port == enable)
+ vent.update_appearance(UPDATE_ICON)
+
+/obj/item/circuit_component/air_alarm_vents/proc/toggle_external(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ INVOKE_ASYNC(src, PROC_REF(toggle_external_async), port)
+
+/obj/item/circuit_component/air_alarm_vents/proc/toggle_external_async(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/obj/machinery/atmospherics/components/unary/vent_pump/vent = find_by_id_tag(connected_alarm.my_area.air_vents, vents.value)
+ if(isnull(vent))
+ return
+
+ if(port == enable_external)
+ vent.pressure_checks |= ATMOS_EXTERNAL_BOUND
+ else
+ vent.pressure_checks &= ~ATMOS_EXTERNAL_BOUND
+
+/obj/item/circuit_component/air_alarm_vents/proc/toggle_internal(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ INVOKE_ASYNC(src, PROC_REF(toggle_internal_async), port)
+
+/obj/item/circuit_component/air_alarm_vents/proc/toggle_internal_async(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/obj/machinery/atmospherics/components/unary/vent_pump/vent = find_by_id_tag(connected_alarm.my_area.air_vents, vents.value)
+ if(isnull(vent))
+ return
+
+ if(port == enable_internal)
+ vent.pressure_checks |= ATMOS_INTERNAL_BOUND
+ else
+ vent.pressure_checks &= ~ATMOS_INTERNAL_BOUND
+
+/obj/item/circuit_component/air_alarm_vents/proc/set_internal_pressure(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ INVOKE_ASYNC(src, PROC_REF(set_internal_pressure_async), port)
+
+/obj/item/circuit_component/air_alarm_vents/proc/set_internal_pressure_async(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/obj/machinery/atmospherics/components/unary/vent_pump/vent = find_by_id_tag(connected_alarm.my_area.air_vents, vents.value)
+ if(isnull(vent))
+ return
+
+ vent.internal_pressure_bound = clamp(internal_pressure.value, 0, ATMOS_PUMP_MAX_PRESSURE)
+
+/obj/item/circuit_component/air_alarm_vents/proc/set_external_pressure(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ INVOKE_ASYNC(src, PROC_REF(set_external_pressure_async), port)
+
+/obj/item/circuit_component/air_alarm_vents/proc/set_external_pressure_async(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/obj/machinery/atmospherics/components/unary/vent_pump/vent = find_by_id_tag(connected_alarm.my_area.air_vents, vents.value)
+ if(isnull(vent))
+ return
+
+ vent.internal_pressure_bound = clamp(external_pressure.value, 0, ATMOS_PUMP_MAX_PRESSURE)
+
+/obj/item/circuit_component/air_alarm_vents/proc/toggle_siphon(datum/port/input/port)
+ CIRCUIT_TRIGGER
+ INVOKE_ASYNC(src, PROC_REF(toggle_siphon_async), port)
+
+/obj/item/circuit_component/air_alarm_vents/proc/toggle_siphon_async(datum/port/input/port)
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/obj/machinery/atmospherics/components/unary/vent_pump/vent = find_by_id_tag(connected_alarm.my_area.air_vents, vents.value)
+ if(isnull(vent))
+ return
+
+ vent.pump_direction = (port == enable_siphon) ? ATMOS_DIRECTION_SIPHONING : ATMOS_DIRECTION_RELEASING
+
+/obj/item/circuit_component/air_alarm_vents/proc/update_data()
+ CIRCUIT_TRIGGER
+ if(!connected_alarm || connected_alarm.locked)
+ return
+
+ var/obj/machinery/atmospherics/components/unary/vent_pump/vent = find_by_id_tag(connected_alarm.my_area.air_vents, vents.value)
+ if(isnull(vent))
+ return
+
+ enabled.set_value(vent.on)
+ is_siphoning.set_value(vent.pump_direction == ATMOS_DIRECTION_SIPHONING)
+ internal_on.set_value(!!(vent.pressure_checks & ATMOS_INTERNAL_BOUND))
+ current_internal_pressure.set_value(vent.internal_pressure_bound)
+ external_on.set_value(!!(vent.pressure_checks & ATMOS_EXTERNAL_BOUND))
+ current_external_pressure.set_value(vent.external_pressure_bound)
+ update_received.set_value(COMPONENT_SIGNAL)
diff --git a/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm b/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm
new file mode 100644
index 0000000000000..15ab632aa3b5a
--- /dev/null
+++ b/code/modules/atmospherics/machinery/air_alarm/air_alarm_interact.dm
@@ -0,0 +1,186 @@
+
+/obj/machinery/airalarm/crowbar_act(mob/living/user, obj/item/tool)
+ if(buildstage != AIR_ALARM_BUILD_NO_WIRES)
+ return
+ user.visible_message(span_notice("[user.name] removes the electronics from [name]."), \
+ span_notice("You start prying out the circuit..."))
+ tool.play_tool_sound(src)
+ if (tool.use_tool(src, user, 20))
+ if (buildstage == AIR_ALARM_BUILD_NO_WIRES)
+ to_chat(user, span_notice("You remove the air alarm electronics."))
+ new /obj/item/electronics/airalarm(drop_location())
+ playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE)
+ buildstage = AIR_ALARM_BUILD_NO_CIRCUIT
+ update_appearance()
+ return TRUE
+
+/obj/machinery/airalarm/screwdriver_act(mob/living/user, obj/item/tool)
+ if(buildstage != AIR_ALARM_BUILD_COMPLETE)
+ return
+ tool.play_tool_sound(src)
+ toggle_panel_open()
+ to_chat(user, span_notice("The wires have been [panel_open ? "exposed" : "unexposed"]."))
+ update_appearance()
+ return TRUE
+
+/obj/machinery/airalarm/wirecutter_act(mob/living/user, obj/item/tool)
+ if(!(buildstage == AIR_ALARM_BUILD_COMPLETE && panel_open && wires.is_all_cut()))
+ return
+ tool.play_tool_sound(src)
+ to_chat(user, span_notice("You cut the final wires."))
+ var/obj/item/stack/cable_coil/cables = new(drop_location(), 5)
+ user.put_in_hands(cables)
+ buildstage = AIR_ALARM_BUILD_NO_WIRES
+ update_appearance()
+ return TRUE
+
+/obj/machinery/airalarm/wrench_act(mob/living/user, obj/item/tool)
+ if(buildstage != AIR_ALARM_BUILD_NO_CIRCUIT)
+ return
+ to_chat(user, span_notice("You detach \the [src] from the wall."))
+ tool.play_tool_sound(src)
+ var/obj/item/wallframe/airalarm/alarm_frame = new(drop_location())
+ user.put_in_hands(alarm_frame)
+ qdel(src)
+ return TRUE
+
+
+/obj/machinery/airalarm/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
+ if((buildstage == AIR_ALARM_BUILD_NO_CIRCUIT) && (the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS))
+ return list("mode" = RCD_UPGRADE_SIMPLE_CIRCUITS, "delay" = 20, "cost" = 1)
+ return FALSE
+
+/obj/machinery/airalarm/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_UPGRADE_SIMPLE_CIRCUITS)
+ user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \
+ span_notice("You adapt an air alarm circuit and slot it into the assembly."))
+ buildstage = AIR_ALARM_BUILD_NO_WIRES
+ update_appearance()
+ return TRUE
+ return FALSE
+
+/obj/machinery/airalarm/attack_hand_secondary(mob/user, list/modifiers)
+ . = ..()
+ if(!can_interact(user))
+ return
+ if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc))
+ return
+ togglelock(user)
+ return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
+
+/obj/machinery/airalarm/proc/togglelock(mob/living/user)
+ if(machine_stat & (NOPOWER|BROKEN))
+ to_chat(user, span_warning("It does nothing!"))
+ else
+ if(src.allowed(usr) && !wires.is_cut(WIRE_IDSCAN))
+ locked = !locked
+ to_chat(user, span_notice("You [ locked ? "lock" : "unlock"] the air alarm interface."))
+ if(!locked)
+ ui_interact(user)
+ else
+ to_chat(user, span_danger("Access denied."))
+ return
+
+/obj/machinery/airalarm/emag_act(mob/user)
+ if(obj_flags & EMAGGED)
+ return
+ obj_flags |= EMAGGED
+ visible_message(span_warning("Sparks fly out of [src]!"), span_notice("You emag [src], disabling its safeties."))
+ playsound(src, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
+
+/obj/machinery/airalarm/deconstruct(disassembled = TRUE)
+ if(!(flags_1 & NODECONSTRUCT_1))
+ new /obj/item/stack/sheet/iron(loc, 2)
+ var/obj/item/I = new /obj/item/electronics/airalarm(loc)
+ if(!disassembled)
+ I.take_damage(I.max_integrity * 0.5, sound_effect=FALSE)
+ new /obj/item/stack/cable_coil(loc, 3)
+ qdel(src)
+
+/obj/machinery/airalarm/attackby(obj/item/W, mob/user, params)
+ update_last_used(user)
+ switch(buildstage)
+ if(AIR_ALARM_BUILD_COMPLETE)
+ if(W.GetID())// trying to unlock the interface with an ID card
+ togglelock(user)
+ return
+ else if(panel_open && is_wire_tool(W))
+ wires.interact(user)
+ return
+ if(AIR_ALARM_BUILD_NO_WIRES)
+ if(istype(W, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/cable = W
+ if(cable.get_amount() < 5)
+ to_chat(user, span_warning("You need five lengths of cable to wire the air alarm!"))
+ return
+ user.visible_message(span_notice("[user.name] wires the air alarm."), \
+ span_notice("You start wiring the air alarm..."))
+ if (do_after(user, 20, target = src))
+ if (cable.get_amount() >= 5 && buildstage == AIR_ALARM_BUILD_NO_WIRES)
+ cable.use(5)
+ to_chat(user, span_notice("You wire the air alarm."))
+ wires.repair()
+ aidisabled = FALSE
+ locked = FALSE
+ shorted = FALSE
+ danger_level = AIR_ALARM_ALERT_NONE
+ buildstage = AIR_ALARM_BUILD_COMPLETE
+ select_mode(user, /datum/air_alarm_mode/filtering)
+ update_appearance()
+ return
+ if(AIR_ALARM_BUILD_NO_CIRCUIT)
+ if(istype(W, /obj/item/electronics/airalarm))
+ if(user.temporarilyRemoveItemFromInventory(W))
+ to_chat(user, span_notice("You insert the circuit."))
+ buildstage = AIR_ALARM_BUILD_NO_WIRES
+ update_appearance()
+ qdel(W)
+ return
+
+ if(istype(W, /obj/item/electroadaptive_pseudocircuit))
+ var/obj/item/electroadaptive_pseudocircuit/P = W
+ if(!P.adapt_circuit(user, 25))
+ return
+ user.visible_message(span_notice("[user] fabricates a circuit and places it into [src]."), \
+ span_notice("You adapt an air alarm circuit and slot it into the assembly."))
+ buildstage = AIR_ALARM_BUILD_NO_WIRES
+ update_appearance()
+ return
+
+ return ..()
+
+/obj/machinery/airalarm/proc/reset(wire)
+ switch(wire)
+ if(WIRE_POWER)
+ if(!wires.is_cut(WIRE_POWER))
+ shorted = FALSE
+ update_appearance()
+ if(WIRE_AI)
+ if(!wires.is_cut(WIRE_AI))
+ aidisabled = FALSE
+
+/obj/machinery/airalarm/proc/shock(mob/user, prb)
+ if((machine_stat & (NOPOWER))) // unpowered, no shock
+ return FALSE
+ if(!prob(prb))
+ return FALSE //you lucked out, no shock for you
+ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
+ s.set_up(5, 1, src)
+ s.start() //sparks always.
+ if (electrocute_mob(user, get_area(src), src, 1, TRUE))
+ return TRUE
+ else
+ return FALSE
+
+/obj/item/electronics/airalarm
+ name = "air alarm electronics"
+ icon_state = "airalarm_electronics"
+
+/obj/item/wallframe/airalarm
+ name = "air alarm frame"
+ desc = "Used for building Air Alarms."
+ icon = 'icons/obj/monitors.dmi'
+ icon_state = "alarm_bitem"
+ result_path = /obj/machinery/airalarm
+ pixel_shift = 24
diff --git a/code/modules/atmospherics/machinery/air_alarm/air_alarm_modes.dm b/code/modules/atmospherics/machinery/air_alarm/air_alarm_modes.dm
new file mode 100644
index 0000000000000..ae20bda1f5dda
--- /dev/null
+++ b/code/modules/atmospherics/machinery/air_alarm/air_alarm_modes.dm
@@ -0,0 +1,201 @@
+/// Keys are [/datum/air_alarm_mode] paths
+/// Values are their respective instances.
+GLOBAL_LIST_INIT(air_alarm_modes, init_air_alarm_modes())
+
+/proc/init_air_alarm_modes()
+ var/list/ret = list()
+ for(var/mode_path in subtypesof(/datum/air_alarm_mode))
+ ret[mode_path] = new mode_path
+ return ret
+
+/// Various modes that an [/obj/machinery/airalarm] can assume.
+/datum/air_alarm_mode
+ /// Name of the mode.
+ var/name
+ /// More detail on the mode.
+ var/desc
+ /// TRUE if this mode can be dangerous if selected.
+ var/danger
+ /// TRUE if the air alarm needs to be emagged for this to be selected.
+ var/emag = FALSE
+
+/** The proc that runs when this air alarm mode is selected.
+ *
+ * Arguments:
+ * * applied - which area will we apply this mode to.
+ */
+/datum/air_alarm_mode/proc/apply(area/applied)
+ return
+
+/datum/air_alarm_mode/proc/replace(area/applied, pressure)
+ return
+
+/// The default.
+/datum/air_alarm_mode/filtering
+ name = "Filtering"
+ desc = "Scrubs out contaminants"
+ danger = FALSE
+
+/datum/air_alarm_mode/filtering/apply(area/applied)
+ for (var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in applied.air_vents)
+ vent.on = TRUE
+ vent.pressure_checks = ATMOS_EXTERNAL_BOUND
+ vent.external_pressure_bound = ONE_ATMOSPHERE
+ vent.update_appearance(UPDATE_ICON)
+
+ for (var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in applied.air_scrubbers)
+ scrubber.on = TRUE
+ scrubber.filter_types = list(/datum/gas/carbon_dioxide)
+ scrubber.set_scrubbing(ATMOS_DIRECTION_SCRUBBING)
+ scrubber.set_widenet(FALSE)
+
+/datum/air_alarm_mode/contaminated
+ name = "Contaminated"
+ desc = "Scrubs out ALL contaminants quickly"
+ danger = FALSE
+
+/datum/air_alarm_mode/contaminated/apply(area/applied)
+ for (var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in applied.air_vents)
+ vent.on = TRUE
+ vent.pressure_checks = ATMOS_EXTERNAL_BOUND
+ vent.external_pressure_bound = ONE_ATMOSPHERE
+ vent.update_appearance(UPDATE_ICON)
+
+ var/list/filtered = subtypesof(/datum/gas)
+ filtered -= list(/datum/gas/oxygen, /datum/gas/nitrogen)
+ for (var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in applied.air_scrubbers)
+ scrubber.on = TRUE
+ scrubber.filter_types = filtered.Copy()
+ scrubber.set_scrubbing(ATMOS_DIRECTION_SCRUBBING)
+ scrubber.set_widenet(TRUE)
+
+/datum/air_alarm_mode/draught
+ name = "Draught"
+ desc = "Siphons out air while replacing"
+ danger = FALSE
+
+/datum/air_alarm_mode/draught/apply(area/applied)
+ for (var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in applied.air_vents)
+ vent.on = TRUE
+ vent.pressure_checks = ATMOS_EXTERNAL_BOUND
+ vent.external_pressure_bound = ONE_ATMOSPHERE * 2
+ vent.update_appearance(UPDATE_ICON)
+
+ for (var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in applied.air_scrubbers)
+ scrubber.on = TRUE
+ scrubber.set_widenet(FALSE)
+ scrubber.set_scrubbing(ATMOS_DIRECTION_SIPHONING)
+
+/datum/air_alarm_mode/refill
+ name = "Refill"
+ desc = "Triple vent output"
+ danger = TRUE
+
+/datum/air_alarm_mode/refill/apply(area/applied)
+ for (var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in applied.air_vents)
+ vent.on = TRUE
+ vent.pressure_checks = ATMOS_EXTERNAL_BOUND
+ vent.external_pressure_bound = ONE_ATMOSPHERE * 3
+ vent.update_appearance(UPDATE_ICON)
+
+ for (var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in applied.air_scrubbers)
+ scrubber.on = TRUE
+
+ scrubber.filter_types = list(/datum/gas/carbon_dioxide)
+ scrubber.set_widenet(FALSE)
+ scrubber.set_scrubbing(ATMOS_DIRECTION_SCRUBBING)
+
+/datum/air_alarm_mode/cycle
+ name = "Cycle"
+ desc = "Siphons air before replacing"
+ danger = TRUE
+
+/// Same as [/datum/air_alarm_mode/siphon/apply]
+/datum/air_alarm_mode/cycle/apply(area/applied)
+ for (var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in applied.air_vents)
+ vent.on = FALSE
+ vent.update_appearance(UPDATE_ICON)
+
+ for (var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in applied.air_scrubbers)
+ scrubber.on = TRUE
+ scrubber.set_widenet(TRUE)
+ scrubber.set_scrubbing(ATMOS_DIRECTION_SIPHONING)
+
+/// Special case for cycles. Cycles need to refill the air again after it's scrubbed out so this proc is called.
+/// Same as [/datum/air_alarm_mode/filtering/apply]
+/datum/air_alarm_mode/cycle/replace(area/applied, pressure)
+ if(pressure >= ONE_ATMOSPHERE * 0.05)
+ return
+
+ for (var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in applied.air_vents)
+ vent.on = TRUE
+ vent.pressure_checks = ATMOS_EXTERNAL_BOUND
+ vent.external_pressure_bound = ONE_ATMOSPHERE
+ vent.update_appearance(UPDATE_ICON)
+
+ for (var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in applied.air_scrubbers)
+ scrubber.on = TRUE
+ scrubber.filter_types = list(/datum/gas/carbon_dioxide)
+ scrubber.set_scrubbing(ATMOS_DIRECTION_SCRUBBING)
+ scrubber.set_widenet(FALSE)
+
+/datum/air_alarm_mode/siphon
+ name = "Siphon"
+ desc = "Siphons air out of the room"
+ danger = TRUE
+
+/datum/air_alarm_mode/siphon/apply(area/applied)
+ for (var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in applied.air_vents)
+ vent.on = FALSE
+ vent.update_appearance(UPDATE_ICON)
+
+ for (var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in applied.air_scrubbers)
+ scrubber.on = TRUE
+ scrubber.set_widenet(FALSE)
+ scrubber.set_scrubbing(ATMOS_DIRECTION_SIPHONING)
+
+/datum/air_alarm_mode/panic_siphon
+ name = "Panic Siphon"
+ desc = "Siphons air out of the room quickly"
+ danger = TRUE
+
+/datum/air_alarm_mode/panic_siphon/apply(area/applied)
+ for (var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in applied.air_vents)
+ vent.on = FALSE
+ vent.update_appearance(UPDATE_ICON)
+
+ for (var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in applied.air_scrubbers)
+ scrubber.on = TRUE
+ scrubber.set_widenet(TRUE)
+ scrubber.set_scrubbing(ATMOS_DIRECTION_SIPHONING)
+
+/datum/air_alarm_mode/off
+ name = "Off"
+ desc = "Shuts off vents and scrubbers"
+ danger = FALSE
+
+/datum/air_alarm_mode/off/apply(area/applied)
+ for (var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in applied.air_vents)
+ vent.on = FALSE
+ vent.update_appearance(UPDATE_ICON)
+
+ for (var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in applied.air_scrubbers)
+ scrubber.on = FALSE
+ scrubber.update_appearance(UPDATE_ICON)
+
+/datum/air_alarm_mode/flood
+ name = "Flood"
+ desc = "Shuts off scrubbers and opens vents"
+ danger = TRUE
+ emag = TRUE
+
+/datum/air_alarm_mode/flood/apply(area/applied)
+ for (var/obj/machinery/atmospherics/components/unary/vent_pump/vent as anything in applied.air_vents)
+ vent.on = TRUE
+ vent.pressure_checks = ATMOS_INTERNAL_BOUND
+ vent.internal_pressure_bound = 0
+ vent.update_appearance(UPDATE_ICON)
+
+ for (var/obj/machinery/atmospherics/components/unary/vent_scrubber/scrubber as anything in applied.air_scrubbers)
+ scrubber.on = FALSE
+ scrubber.update_appearance(UPDATE_ICON)
diff --git a/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm b/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm
new file mode 100644
index 0000000000000..cfe74f13c346c
--- /dev/null
+++ b/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm
@@ -0,0 +1,111 @@
+// A datum for dealing with threshold limit values
+/datum/tlv
+ var/warning_min = 0
+ var/warning_max = 0
+ var/hazard_min = 0
+ var/hazard_max = 0
+
+/** Initialize a TLV and set it's values if given arguments, mostly for map varedits.
+ * We provide this functionality but please consider not doing this and making proper subtypes.
+ * Only by doing the latter will [datum/tlv/proc/reset_value] work.
+ */
+/datum/tlv/New(min2 as num, min1 as num, max1 as num, max2 as num)
+ if(min2)
+ hazard_min = min2
+ if(min1)
+ warning_min = min1
+ if(max1)
+ warning_max = max1
+ if(max2)
+ hazard_max = max2
+
+/datum/tlv/proc/check_value(val)
+ if(hazard_max != TLV_VALUE_IGNORE && val >= hazard_max)
+ return AIR_ALARM_ALERT_HAZARD
+ if(hazard_min != TLV_VALUE_IGNORE && val <= hazard_min)
+ return AIR_ALARM_ALERT_HAZARD
+ if(warning_max != TLV_VALUE_IGNORE && val >= warning_max)
+ return AIR_ALARM_ALERT_WARNING
+ if(warning_min != TLV_VALUE_IGNORE && val <= warning_min)
+ return AIR_ALARM_ALERT_WARNING
+
+ return AIR_ALARM_ALERT_NONE
+
+/** Set this particular TLV
+ *
+ * Arguments:
+ * * threshold_type: What kind of variable do we want to set. Accepts bitfield subsets of [TLV_VAR_ALL].
+ * * value: How much to set it to. Accepts a number or [TLV_VALUE_IGNORE]
+ */
+/datum/tlv/proc/set_value(threshold_type, value)
+ if(threshold_type & TLV_VAR_WARNING_MIN)
+ warning_min = value
+ if(threshold_type & TLV_VAR_HAZARD_MIN)
+ hazard_min = value
+ if(threshold_type & TLV_VAR_WARNING_MAX)
+ warning_max = value
+ if(threshold_type & TLV_VAR_HAZARD_MAX)
+ hazard_max = value
+
+/** Reset this particular TLV to it's original value.
+ *
+ * Arguments:
+ * * threshold_type: What kind of variable do we want to set. Accepts bitfield subsets of [TLV_VAR_ALL].
+ */
+/datum/tlv/proc/reset_value(threshold_type)
+ if(threshold_type & TLV_VAR_WARNING_MIN)
+ warning_min = initial(warning_min)
+ if(threshold_type & TLV_VAR_HAZARD_MIN)
+ hazard_min = initial(hazard_min)
+ if(threshold_type & TLV_VAR_WARNING_MAX)
+ warning_max = initial(warning_max)
+ if(threshold_type & TLV_VAR_HAZARD_MAX)
+ hazard_max = initial(hazard_max)
+
+/datum/tlv/no_checks
+ warning_min = TLV_VALUE_IGNORE
+ hazard_min = TLV_VALUE_IGNORE
+ warning_max = TLV_VALUE_IGNORE
+ hazard_max = TLV_VALUE_IGNORE
+
+/datum/tlv/dangerous
+ warning_min = TLV_VALUE_IGNORE
+ hazard_min = TLV_VALUE_IGNORE
+ warning_max = 0.2
+ hazard_max = 0.5
+
+/datum/tlv/oxygen
+ warning_min = 19
+ hazard_min = 16
+ warning_max = TLV_VALUE_IGNORE
+ hazard_max = TLV_VALUE_IGNORE
+
+/datum/tlv/carbon_dioxide
+ warning_min = TLV_VALUE_IGNORE
+ hazard_min = TLV_VALUE_IGNORE
+ warning_max = 5
+ hazard_max = 10
+
+/datum/tlv/pressure
+ warning_min = WARNING_LOW_PRESSURE
+ hazard_min = HAZARD_LOW_PRESSURE
+ warning_max = WARNING_HIGH_PRESSURE
+ hazard_max = HAZARD_HIGH_PRESSURE
+
+/datum/tlv/temperature
+ warning_min = BODYTEMP_COLD_WARNING_1+10
+ hazard_min = BODYTEMP_COLD_WARNING_1
+ warning_max = BODYTEMP_HEAT_WARNING_1-27
+ hazard_max = BODYTEMP_HEAT_WARNING_1
+
+/datum/tlv/cold_room_pressure
+ warning_min = ONE_ATMOSPHERE * 0.9
+ hazard_min = ONE_ATMOSPHERE * 0.8
+ warning_max = ONE_ATMOSPHERE * 1.1
+ hazard_max = ONE_ATMOSPHERE * 1.2
+
+/datum/tlv/cold_room_temperature
+ warning_min = COLD_ROOM_TEMP - 20
+ hazard_min = COLD_ROOM_TEMP - 40
+ warning_max = COLD_ROOM_TEMP + 20
+ hazard_max = COLD_ROOM_TEMP + 40
diff --git a/code/modules/atmospherics/machinery/air_alarm/air_alarm_variants.dm b/code/modules/atmospherics/machinery/air_alarm/air_alarm_variants.dm
new file mode 100644
index 0000000000000..4997ac2e5bff3
--- /dev/null
+++ b/code/modules/atmospherics/machinery/air_alarm/air_alarm_variants.dm
@@ -0,0 +1,42 @@
+
+/obj/machinery/airalarm/server
+
+/obj/machinery/airalarm/server/Initialize()
+ . = ..()
+ tlv_collection["temperature"] = new /datum/tlv/no_checks
+ tlv_collection["pressure"] = new /datum/tlv/no_checks
+
+/obj/machinery/airalarm/kitchen_cold_room
+
+/obj/machinery/airalarm/kitchen_cold_room/Initialize()
+ . = ..()
+ tlv_collection["temperature"] = new /datum/tlv/cold_room_temperature
+ tlv_collection["pressure"] = new /datum/tlv/cold_room_pressure
+
+/obj/machinery/airalarm/unlocked
+ locked = FALSE
+
+/obj/machinery/airalarm/engine
+ name = "engine air alarm"
+ locked = FALSE
+ req_access = null
+ req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ENGINEERING)
+
+/obj/machinery/airalarm/mixingchamber
+ name = "chamber air alarm"
+ locked = FALSE
+ req_access = null
+ req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ORDNANCE)
+
+/obj/machinery/airalarm/all_access
+ name = "all-access air alarm"
+ desc = "This particular atmos control unit appears to have no access restrictions."
+ locked = FALSE
+ req_access = null
+ req_one_access = null
+
+/obj/machinery/airalarm/syndicate //general syndicate access
+ req_access = list(ACCESS_SYNDICATE)
+
+/obj/machinery/airalarm/away //general away mission access
+ req_access = list(ACCESS_AWAY_GENERAL)
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
deleted file mode 100644
index 4f07e1fff707c..0000000000000
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ /dev/null
@@ -1,959 +0,0 @@
-/datum/tlv
- var/min2
- var/min1
- var/max1
- var/max2
-
-/datum/tlv/New(min2 as num, min1 as num, max1 as num, max2 as num)
- if(min2) src.min2 = min2
- if(min1) src.min1 = min1
- if(max1) src.max1 = max1
- if(max2) src.max2 = max2
-
-/datum/tlv/proc/get_danger_level(val as num)
- if(max2 != -1 && val >= max2)
- return 2
- if(min2 != -1 && val <= min2)
- return 2
- if(max1 != -1 && val >= max1)
- return 1
- if(min1 != -1 && val <= min1)
- return 1
- return 0
-
-/datum/tlv/no_checks
- min2 = -1
- min1 = -1
- max1 = -1
- max2 = -1
-
-/datum/tlv/dangerous
- min2 = -1
- min1 = -1
- max1 = 0.2
- max2 = 0.5
-
-/obj/item/electronics/airalarm
- name = "air alarm electronics"
- custom_price = 5
- icon_state = "airalarm_electronics"
-
-/obj/item/wallframe/airalarm
- name = "air alarm frame"
- desc = "Used for building Air Alarms."
- icon = 'icons/obj/monitors.dmi'
- icon_state = "alarm_bitem"
- result_path = /obj/machinery/airalarm
- pixel_shift = 24
-
-#define AALARM_MODE_SCRUBBING 1
-#define AALARM_MODE_VENTING 2 //makes draught
-#define AALARM_MODE_PANIC 3 //like siphon, but stronger (enables widenet)
-#define AALARM_MODE_REPLACEMENT 4 //sucks off all air, then refill and swithes to scrubbing
-#define AALARM_MODE_OFF 5
-#define AALARM_MODE_FLOOD 6 //Emagged mode; turns off scrubbers and pressure checks on vents
-#define AALARM_MODE_SIPHON 7 //Scrubbers suck air
-#define AALARM_MODE_CONTAMINATED 8 //Turns on all filtering and widenet scrubbing.
-#define AALARM_MODE_REFILL 9 //just like normal, but with triple the air output
-
-#define AALARM_REPORT_TIMEOUT 100
-
-/obj/machinery/airalarm
- name = "air alarm"
- desc = "A machine that monitors atmosphere levels and alerts if the area is dangerous."
- icon = 'icons/obj/monitors.dmi'
- icon_state = "alarmp"
- use_power = IDLE_POWER_USE
- idle_power_usage = 4
- active_power_usage = 8
- power_channel = AREA_USAGE_ENVIRON
- req_access = list(ACCESS_ATMOSPHERICS)
- max_integrity = 250
- integrity_failure = 0.33
- armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 90, ACID = 30, STAMINA = 0, BLEED = 0)
- resistance_flags = FIRE_PROOF
- clicksound = 'sound/machines/terminal_select.ogg'
- layer = ABOVE_WINDOW_LAYER
-
-
- var/danger_level = 0
- var/mode = AALARM_MODE_SCRUBBING
-
- var/locked = TRUE
- var/aidisabled = 0
- var/shorted = 0
- var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
-
- var/frequency = FREQ_ATMOS_CONTROL
- var/alarm_frequency = FREQ_ATMOS_ALARMS
- var/datum/radio_frequency/radio_connection
- ///Represents a signel source of atmos alarms, complains to all the listeners if one of our thresholds is violated
- var/datum/alarm_handler/alarm_manager
-
- var/list/TLV = list( // Breathable air.
- "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa. Values are min2, min1, max1, max2
- "temperature" = new/datum/tlv(T0C, T0C+10, T0C+40, T0C+66),
- GAS_O2 = new/datum/tlv(16, 19, 40, 50), // Partial pressure, kpa
- GAS_N2 = new/datum/tlv(-1, -1, 1000, 1000),
- GAS_CO2 = new/datum/tlv(-1, -1, 5, 10),
- GAS_PLASMA = new/datum/tlv/dangerous,
- GAS_NITROUS = new/datum/tlv/dangerous,
- GAS_BZ = new/datum/tlv/dangerous,
- GAS_HYPERNOB = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic
- GAS_H2O = new/datum/tlv/dangerous,
- GAS_TRITIUM = new/datum/tlv/dangerous,
- GAS_STIMULUM = new/datum/tlv/dangerous,
- GAS_NITRYL = new/datum/tlv/dangerous,
- GAS_PLUOXIUM = new/datum/tlv(-1, -1, 5, 6), // Unlike oxygen, pluoxium does not fuel plasma/tritium fires
- )
-
-/obj/machinery/airalarm/server // No checks here.
- TLV = list(
- "pressure" = new/datum/tlv/no_checks,
- "temperature" = new/datum/tlv/no_checks,
- GAS_O2 = new/datum/tlv/no_checks,
- GAS_N2 = new/datum/tlv/no_checks,
- GAS_CO2 = new/datum/tlv/no_checks,
- GAS_PLASMA = new/datum/tlv/no_checks,
- GAS_NITROUS = new/datum/tlv/no_checks,
- GAS_BZ = new/datum/tlv/no_checks,
- GAS_HYPERNOB = new/datum/tlv/no_checks,
- GAS_H2O = new/datum/tlv/no_checks,
- GAS_TRITIUM = new/datum/tlv/no_checks,
- GAS_STIMULUM = new/datum/tlv/no_checks,
- GAS_NITRYL = new/datum/tlv/no_checks,
- GAS_PLUOXIUM = new/datum/tlv/no_checks
- )
-
-/obj/machinery/airalarm/kitchen_cold_room // Kitchen cold rooms start off at -20°C or 253.15 K.
- TLV = list(
- "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa
- "temperature" = new/datum/tlv(T0C-273.15, T0C-80, T0C-10, T0C+10),
- GAS_O2 = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa
- GAS_N2 = new/datum/tlv(-1, -1, 1000, 1000),
- GAS_CO2 = new/datum/tlv(-1, -1, 5, 10),
- GAS_PLASMA = new/datum/tlv/dangerous,
- GAS_NITROUS = new/datum/tlv/dangerous,
- GAS_BZ = new/datum/tlv/dangerous,
- GAS_HYPERNOB = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic
- GAS_H2O = new/datum/tlv/dangerous,
- GAS_TRITIUM = new/datum/tlv/dangerous,
- GAS_STIMULUM = new/datum/tlv/dangerous,
- GAS_NITRYL = new/datum/tlv/dangerous,
- GAS_PLUOXIUM = new/datum/tlv(-1, -1, 1000, 1000) // Unlike oxygen, pluoxium does not fuel plasma/tritium fires
- )
-
-/obj/machinery/airalarm/unlocked
- locked = FALSE
-
-/obj/machinery/airalarm/engine
- name = "engine air alarm"
- locked = FALSE
- req_access = null
- req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ENGINE)
-
-/obj/machinery/airalarm/mixingchamber
- name = "chamber air alarm"
- locked = FALSE
- req_access = null
- req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_TOX, ACCESS_TOX_STORAGE)
-
-/obj/machinery/airalarm/all_access
- name = "all-access air alarm"
- desc = "This particular atmospherics control unit appears to have no access restrictions."
- locked = FALSE
- req_access = null
- req_one_access = null
-
-/obj/machinery/airalarm/syndicate //general syndicate access
- req_access = list(ACCESS_SYNDICATE)
-
-/obj/machinery/airalarm/away //general away mission access
- req_access = list(ACCESS_AWAY_GENERAL)
-
-MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/airalarm, 24)
-
-//all air alarms in area are connected via magic
-/area
- var/list/air_vent_names = list()
- var/list/air_scrub_names = list()
- var/list/air_vent_info = list()
- var/list/air_scrub_info = list()
-
-CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/airalarm)
-
-/obj/machinery/airalarm/Initialize(mapload, ndir, nbuild)
- . = ..()
- wires = new /datum/wires/airalarm(src)
- if(ndir)
- setDir(ndir)
-
- if(nbuild)
- buildstage = 0
- panel_open = TRUE
-
- if(name == initial(name))
- name = "[get_area_name(src)] Air Alarm"
-
- alarm_manager = new(src)
- update_appearance()
-
- set_frequency(frequency)
- AddComponent(/datum/component/usb_port, list(
- /obj/item/circuit_component/air_alarm,
- ))
- GLOB.zclear_atoms += src
-
-/obj/machinery/airalarm/Destroy()
- SSradio.remove_object(src, frequency)
- QDEL_NULL(wires)
- QDEL_NULL(alarm_manager)
- GLOB.zclear_atoms -= src
- return ..()
-
-/obj/machinery/airalarm/examine(mob/user)
- . = ..()
- switch(buildstage)
- if(0)
- . += "It is missing air alarm electronics."
- if(1)
- . += "It is missing wiring."
- if(2)
- . += "Alt-click to [locked ? "unlock" : "lock"] the interface."
-
-/obj/machinery/airalarm/ui_status(mob/user)
- if(user.has_unlimited_silicon_privilege && aidisabled)
- to_chat(user, "AI control has been disabled.")
- else if(!shorted)
- return ..()
- return UI_CLOSE
-
-
-/obj/machinery/airalarm/ui_state(mob/user)
- return GLOB.default_state
-
-/obj/machinery/airalarm/ui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "AirAlarm")
- ui.open()
- ui.set_autoupdate(TRUE) // Turf gas mixture
-
-//Oh my, thats a lot of data being sent that should probably be refactored
-/obj/machinery/airalarm/ui_data(mob/user)
- var/data = list(
- "locked" = locked,
- "siliconUser" = user.has_unlimited_silicon_privilege,
- "emagged" = (obj_flags & EMAGGED ? 1 : 0),
- "danger_level" = danger_level,
- )
-
- var/area/A = get_area(src)
- data["atmos_alarm"] = !!A.active_alarms[ALARM_ATMOS]
- data["fire_alarm"] = A.fire
-
- var/turf/T = get_turf(src)
- var/datum/gas_mixture/environment = T.return_air()
- var/datum/tlv/cur_tlv
-
- data["environment_data"] = list()
- var/pressure = environment.return_pressure()
- cur_tlv = TLV["pressure"]
- data["environment_data"] += list(list(
- "name" = "Pressure",
- "value" = pressure,
- "unit" = "kPa",
- "danger_level" = cur_tlv.get_danger_level(pressure)
- ))
- var/temperature = environment.return_temperature()
- cur_tlv = TLV["temperature"]
- data["environment_data"] += list(list(
- "name" = "Temperature",
- "value" = temperature,
- "unit" = "K ([round(temperature - T0C, 0.1)]C)",
- "danger_level" = cur_tlv.get_danger_level(temperature)
- ))
- var/total_moles = environment.total_moles()
- var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.return_temperature() / environment.return_volume()
- for(var/gas_id in environment.get_gases())
- if(!(gas_id in TLV)) // We're not interested in this gas, it seems.
- continue
- cur_tlv = TLV[gas_id]
- data["environment_data"] += list(list(
- "name" = GLOB.gas_data.names[gas_id],
- "value" = environment.get_moles(gas_id) / total_moles * 100,
- "unit" = "%",
- "danger_level" = cur_tlv.get_danger_level(environment.get_moles(gas_id) * partial_pressure)
- ))
-
- if(!locked || user.has_unlimited_silicon_privilege)
- data["vents"] = list()
- for(var/id_tag in A.air_vent_names)
- var/long_name = A.air_vent_names[id_tag]
- var/list/info = A.air_vent_info[id_tag]
- if(!info || info["frequency"] != frequency || info["has_aac"])
- continue
- data["vents"] += list(list(
- "id_tag" = id_tag,
- "long_name" = sanitize(long_name),
- "power" = info["power"],
- "checks" = info["checks"],
- "excheck" = info["checks"]&1,
- "incheck" = info["checks"]&2,
- "direction" = info["direction"],
- "external" = info["external"],
- "internal" = info["internal"],
- "extdefault"= (info["external"] == ONE_ATMOSPHERE),
- "intdefault"= (info["internal"] == 0)
- ))
- data["scrubbers"] = list()
- for(var/id_tag in A.air_scrub_names)
- var/long_name = A.air_scrub_names[id_tag]
- var/list/info = A.air_scrub_info[id_tag]
- if(!info || info["frequency"] != frequency)
- continue
- data["scrubbers"] += list(list(
- "id_tag" = id_tag,
- "long_name" = sanitize(long_name),
- "power" = info["power"],
- "scrubbing" = info["scrubbing"],
- "widenet" = info["widenet"],
- "filter_types" = info["filter_types"]
- ))
- data["mode"] = mode
- data["modes"] = list()
- data["modes"] += list(list("name" = "Filtering - Scrubs out contaminants", "mode" = AALARM_MODE_SCRUBBING, "selected" = mode == AALARM_MODE_SCRUBBING, "danger" = 0))
- data["modes"] += list(list("name" = "Contaminated - Scrubs out ALL contaminants quickly","mode" = AALARM_MODE_CONTAMINATED, "selected" = mode == AALARM_MODE_CONTAMINATED, "danger" = 0))
- data["modes"] += list(list("name" = "Draught - Siphons out air while replacing", "mode" = AALARM_MODE_VENTING, "selected" = mode == AALARM_MODE_VENTING, "danger" = 0))
- data["modes"] += list(list("name" = "Refill - Triple vent output", "mode" = AALARM_MODE_REFILL, "selected" = mode == AALARM_MODE_REFILL, "danger" = 1))
- data["modes"] += list(list("name" = "Cycle - Siphons air before replacing", "mode" = AALARM_MODE_REPLACEMENT, "selected" = mode == AALARM_MODE_REPLACEMENT, "danger" = 1))
- data["modes"] += list(list("name" = "Siphon - Siphons air out of the room", "mode" = AALARM_MODE_SIPHON, "selected" = mode == AALARM_MODE_SIPHON, "danger" = 1))
- data["modes"] += list(list("name" = "Panic Siphon - Siphons air out of the room quickly","mode" = AALARM_MODE_PANIC, "selected" = mode == AALARM_MODE_PANIC, "danger" = 1))
- data["modes"] += list(list("name" = "Off - Shuts off vents and scrubbers", "mode" = AALARM_MODE_OFF, "selected" = mode == AALARM_MODE_OFF, "danger" = 0))
- if(obj_flags & EMAGGED)
- data["modes"] += list(list("name" = "Flood - Shuts off scrubbers and opens vents", "mode" = AALARM_MODE_FLOOD, "selected" = mode == AALARM_MODE_FLOOD, "danger" = 1))
-
- var/datum/tlv/selected
- var/list/thresholds = list()
-
- selected = TLV["pressure"]
- thresholds += list(list("name" = "Pressure", "settings" = list()))
- thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min2", "selected" = selected.min2))
- thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min1", "selected" = selected.min1))
- thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max1", "selected" = selected.max1))
- thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max2", "selected" = selected.max2))
-
- selected = TLV["temperature"]
- thresholds += list(list("name" = "Temperature", "settings" = list()))
- thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min2", "selected" = selected.min2))
- thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min1", "selected" = selected.min1))
- thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max1", "selected" = selected.max1))
- thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max2", "selected" = selected.max2))
-
- for(var/gas_id in GLOB.gas_data.names)
- if(!(gas_id in TLV)) // We're not interested in this gas, it seems.
- continue
- selected = TLV[gas_id]
- thresholds += list(list("name" = GLOB.gas_data.names[gas_id], "settings" = list()))
- thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min2", "selected" = selected.min2))
- thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min1", "selected" = selected.min1))
- thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max1", "selected" = selected.max1))
- thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max2", "selected" = selected.max2))
-
- data["thresholds"] = thresholds
- return data
-
-/obj/machinery/airalarm/ui_act(action, params)
- if(..() || buildstage != 2)
- return
- if((locked && !usr.has_unlimited_silicon_privilege) || (usr.has_unlimited_silicon_privilege && aidisabled))
- return
- var/device_id = params["id_tag"]
- switch(action)
- if("lock")
- if(usr.has_unlimited_silicon_privilege && !wires.is_cut(WIRE_IDSCAN))
- locked = !locked
- . = TRUE
- if("power", "toggle_filter", "widenet", "scrubbing", "direction")
- send_signal(device_id, list("[action]" = params["val"]), usr)
- . = TRUE
- if("excheck")
- send_signal(device_id, list("checks" = text2num(params["val"])^1), usr)
- . = TRUE
- if("incheck")
- send_signal(device_id, list("checks" = text2num(params["val"])^2), usr)
- . = TRUE
- if("set_external_pressure", "set_internal_pressure")
- var/target = params["value"]
- if(!isnull(target))
- send_signal(device_id, list("[action]" = target), usr)
- . = TRUE
- if("reset_external_pressure")
- send_signal(device_id, list("reset_external_pressure"), usr)
- . = TRUE
- if("reset_internal_pressure")
- send_signal(device_id, list("reset_internal_pressure"), usr)
- . = TRUE
- if("threshold")
- var/env = params["env"]
- if(text2path(env))
- env = text2path(env)
-
- var/name = params["var"]
- var/datum/tlv/tlv = TLV[env]
- if(isnull(tlv))
- return
- var/value = input("New [name] for [env]:", name, tlv.vars[name]) as num|null
- if(!isnull(value) && !..())
- if(value < 0)
- tlv.vars[name] = -1
- else
- tlv.vars[name] = round(value, 0.01)
- investigate_log(" treshold value for [env]:[name] was set to [value] by [key_name(usr)]",INVESTIGATE_ATMOS)
- . = TRUE
- if("mode")
- mode = text2num(params["mode"])
- investigate_log("was turned to [get_mode_name(mode)] mode by [key_name(usr)]",INVESTIGATE_ATMOS)
- apply_mode(usr)
- . = TRUE
- if("alarm")
- if(alarm_manager.send_alarm(ALARM_ATMOS))
- post_alert(2)
- . = TRUE
- if("reset")
- if(alarm_manager.clear_alarm(ALARM_ATMOS))
- post_alert(0)
- . = TRUE
- if(.)
- update_appearance()
-
-
-/obj/machinery/airalarm/proc/reset(wire)
- switch(wire)
- if(WIRE_POWER)
- if(!wires.is_cut(WIRE_POWER))
- shorted = FALSE
- wires.ui_update()
- update_icon()
- if(WIRE_AI)
- if(!wires.is_cut(WIRE_AI))
- aidisabled = FALSE
- wires.ui_update()
-
-
-/obj/machinery/airalarm/proc/shock(mob/user, prb)
- if((machine_stat & (NOPOWER))) // unpowered, no shock
- return 0
- if(!prob(prb))
- return 0 //you lucked out, no shock for you
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(5, 1, src)
- s.start() //sparks always.
- if (electrocute_mob(user, get_area(src), src, 1, TRUE))
- return 1
- else
- return 0
-
-/obj/machinery/airalarm/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = SSradio.add_object(src, frequency, RADIO_TO_AIRALARM)
-
-/obj/machinery/airalarm/proc/send_signal(target, list/command, atom/user)//sends signal 'command' to 'target'. Returns 0 if no radio connection, 1 otherwise
- if(!radio_connection)
- return 0
-
- var/datum/signal/signal = new(command)
- signal.data["tag"] = target
- signal.data["sigtype"] = "command"
- signal.data["user"] = user
- radio_connection.post_signal(src, signal, RADIO_FROM_AIRALARM)
-
- return 1
-
-/obj/machinery/airalarm/proc/get_mode_name(mode_value)
- switch(mode_value)
- if(AALARM_MODE_SCRUBBING)
- return "Filtering"
- if(AALARM_MODE_CONTAMINATED)
- return "Contaminated"
- if(AALARM_MODE_VENTING)
- return "Draught"
- if(AALARM_MODE_REFILL)
- return "Refill"
- if(AALARM_MODE_PANIC)
- return "Panic Siphon"
- if(AALARM_MODE_REPLACEMENT)
- return "Cycle"
- if(AALARM_MODE_SIPHON)
- return "Siphon"
- if(AALARM_MODE_OFF)
- return "Off"
- if(AALARM_MODE_FLOOD)
- return "Flood"
-
-/obj/machinery/airalarm/proc/apply_mode(atom/signal_source)
- var/area/A = get_area(src)
- switch(mode)
- if(AALARM_MODE_SCRUBBING)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "set_filters" = list(GAS_CO2, GAS_BZ),
- "scrubbing" = 1,
- "widenet" = 0
- ), signal_source)
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 1,
- "checks" = 1,
- "set_external_pressure" = ONE_ATMOSPHERE
- ), signal_source)
- if(AALARM_MODE_CONTAMINATED)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "set_filters" = list(
- GAS_CO2,
- GAS_PLASMA,
- GAS_H2O,
- GAS_HYPERNOB,
- GAS_NITROUS,
- GAS_NITRYL,
- GAS_TRITIUM,
- GAS_BZ,
- GAS_STIMULUM,
- GAS_PLUOXIUM
- ),
- "scrubbing" = 1,
- "widenet" = 1
- ), signal_source)
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 1,
- "checks" = 1,
- "set_external_pressure" = ONE_ATMOSPHERE
- ), signal_source)
- if(AALARM_MODE_VENTING)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "widenet" = 0,
- "scrubbing" = 0
- ), signal_source)
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 1,
- "checks" = 1,
- "set_external_pressure" = ONE_ATMOSPHERE*2
- ), signal_source)
- if(AALARM_MODE_REFILL)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "set_filters" = list(GAS_CO2, GAS_BZ),
- "scrubbing" = 1,
- "widenet" = 0
- ), signal_source)
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 1,
- "checks" = 1,
- "set_external_pressure" = ONE_ATMOSPHERE * 3
- ), signal_source)
- if(AALARM_MODE_PANIC,
- AALARM_MODE_REPLACEMENT)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "widenet" = 1,
- "scrubbing" = 0
- ), signal_source)
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 0
- ), signal_source)
- if(AALARM_MODE_SIPHON)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 1,
- "widenet" = 0,
- "scrubbing" = 0
- ), signal_source)
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 0
- ), signal_source)
-
- if(AALARM_MODE_OFF)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 0
- ), signal_source)
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 0
- ), signal_source)
- if(AALARM_MODE_FLOOD)
- for(var/device_id in A.air_scrub_names)
- send_signal(device_id, list(
- "power" = 0
- ), signal_source)
- for(var/device_id in A.air_vent_names)
- send_signal(device_id, list(
- "power" = 1,
- "checks" = 2,
- "set_internal_pressure" = 0
- ), signal_source)
-
-/obj/machinery/airalarm/update_appearance(updates)
- . = ..()
-
- if(panel_open || (machine_stat & (NOPOWER|BROKEN)) || shorted)
- set_light(0)
- return
-
- var/area/our_area = get_area(src)
- var/color
- switch(max(danger_level, !!our_area.active_alarms[ALARM_ATMOS]))
- if(0)
- color = "#03A728" // green
- if(1)
- color = "#EC8B2F" // yellow
- if(2)
- color = "#DA0205" // red
-
- set_light(1.4, 1, color)
-
-/obj/machinery/airalarm/update_icon_state()
- if(panel_open)
- switch(buildstage)
- if(2)
- icon_state = "alarmx"
- if(1)
- icon_state = "alarm_b2"
- if(0)
- icon_state = "alarm_b1"
- return ..()
-
- icon_state = "alarmp"
- return ..()
-
-/obj/machinery/airalarm/update_overlays()
- . = ..()
-
- if((machine_stat & (NOPOWER|BROKEN)) || shorted)
- return
-
- var/area/our_area = get_area(src)
- var/state
- switch(max(danger_level, !!our_area.active_alarms[ALARM_ATMOS]))
- if(0)
- state = "alarm0"
- if(1)
- state = "alarm2" //yes, alarm2 is yellow alarm
- if(2)
- state = "alarm1"
-
- . += mutable_appearance(icon, state)
- . += emissive_appearance(icon, state, alpha = src.alpha)
-
-/obj/machinery/airalarm/process()
- if((machine_stat & (NOPOWER|BROKEN)) || shorted)
- return
-
- var/turf/location = get_turf(src)
- if(!location)
- return
-
- var/datum/tlv/cur_tlv
-
- var/datum/gas_mixture/environment = location.return_air()
- var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.return_temperature() / environment.return_volume()
-
- cur_tlv = TLV["pressure"]
- var/environment_pressure = environment.return_pressure()
- var/pressure_dangerlevel = cur_tlv.get_danger_level(environment_pressure)
-
- cur_tlv = TLV["temperature"]
- var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.return_temperature())
-
- var/gas_dangerlevel = 0
- for(var/gas_id in environment.get_gases())
- if(!(gas_id in TLV)) // We're not interested in this gas, it seems.
- continue
- cur_tlv = TLV[gas_id]
- gas_dangerlevel = max(gas_dangerlevel, cur_tlv.get_danger_level(environment.get_moles(gas_id) * partial_pressure))
-
- var/old_danger_level = danger_level
- danger_level = max(pressure_dangerlevel, temperature_dangerlevel, gas_dangerlevel)
-
- if(old_danger_level != danger_level)
- apply_danger_level()
- if(mode == AALARM_MODE_REPLACEMENT && environment_pressure < ONE_ATMOSPHERE * 0.05)
- mode = AALARM_MODE_SCRUBBING
- apply_mode(src)
-
-
-/obj/machinery/airalarm/proc/post_alert(alert_level)
- var/datum/radio_frequency/frequency = SSradio.return_frequency(alarm_frequency)
-
- if(!frequency)
- return
-
- var/datum/signal/alert_signal = new(list(
- "zone" = get_area_name(src, TRUE),
- "type" = "Atmospheric"
- ))
- var/area/A = get_area(src)
- if(alert_level==2)
- alert_signal.data["alert"] = "severe"
- A.set_pressure_alarm_effect()
- else if (alert_level==1)
- alert_signal.data["alert"] = "minor"
- A.set_pressure_alarm_effect()
- else if (alert_level==0)
- alert_signal.data["alert"] = "clear"
- A.unset_pressure_alarm_effect()
-
- frequency.post_signal(src, alert_signal, range = -1)
-
-/obj/machinery/airalarm/proc/apply_danger_level()
- var/area/A = get_area(src)
-
- var/new_area_danger_level = 0
- for(var/obj/machinery/airalarm/AA in A)
- if (!(AA.machine_stat & (NOPOWER|BROKEN)) && !AA.shorted)
- new_area_danger_level = clamp(max(new_area_danger_level, AA.danger_level), 0, 1)
-
- var/did_anything_happen
- if(new_area_danger_level)
- did_anything_happen = alarm_manager.send_alarm(ALARM_ATMOS)
- else
- did_anything_happen = alarm_manager.clear_alarm(ALARM_ATMOS)
- if(did_anything_happen) //if something actually changed
- post_alert(new_area_danger_level)
-
- update_appearance()
-
-/obj/machinery/airalarm/attackby(obj/item/W, mob/user, params)
- switch(buildstage)
- if(2)
- if(W.tool_behaviour == TOOL_WIRECUTTER && panel_open && wires.is_all_cut())
- W.play_tool_sound(src)
- to_chat(user, "You cut the final wires.")
- new /obj/item/stack/cable_coil(loc, 5)
- buildstage = 1
- update_icon()
- return
- else if(W.tool_behaviour == TOOL_SCREWDRIVER) // Opening that Air Alarm up.
- W.play_tool_sound(src)
- panel_open = !panel_open
- to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"].")
- update_icon()
- return
- else if(istype(W, /obj/item/card/id) || istype(W, /obj/item/modular_computer/tablet/pda))// trying to unlock the interface with an ID card
- togglelock(user)
- return
- else if(panel_open && is_wire_tool(W))
- wires.interact(user)
- return
- if(1)
- if(W.tool_behaviour == TOOL_CROWBAR)
- user.visible_message("[user.name] removes the electronics from [src.name].",\
- "You start prying out the circuit.")
- W.play_tool_sound(src)
- if (W.use_tool(src, user, 20))
- if (buildstage == 1)
- to_chat(user, "You remove the air alarm electronics.")
- new /obj/item/electronics/airalarm( src.loc )
- playsound(src.loc, 'sound/items/deconstruct.ogg', 50, 1)
- buildstage = 0
- update_icon()
- return
-
- if(istype(W, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/cable = W
- if(cable.get_amount() < 5)
- to_chat(user, "You need five lengths of cable to wire the air alarm!")
- return
- user.visible_message("[user.name] wires the air alarm.", \
- "You start wiring the air alarm.")
- if (do_after(user, 20, target = src))
- if (cable.get_amount() >= 5 && buildstage == 1)
- cable.use(5)
- to_chat(user, "You wire the air alarm.")
- wires.repair()
- aidisabled = 0
- locked = FALSE
- mode = 1
- shorted = 0
- post_alert(0)
- buildstage = 2
- update_icon()
- return
- if(0)
- if(istype(W, /obj/item/electronics/airalarm))
- if(user.temporarilyRemoveItemFromInventory(W))
- to_chat(user, "You insert the circuit.")
- buildstage = 1
- update_icon()
- qdel(W)
- return
-
- if(istype(W, /obj/item/electroadaptive_pseudocircuit))
- var/obj/item/electroadaptive_pseudocircuit/P = W
- if(!P.adapt_circuit(user, 25))
- return
- user.visible_message("[user] fabricates a circuit and places it into [src].", \
- "You adapt an air alarm circuit and slot it into the assembly.")
- buildstage = 1
- update_icon()
- return
-
- if(W.tool_behaviour == TOOL_WRENCH)
- to_chat(user, "You detach \the [src] from the wall.")
- W.play_tool_sound(src)
- new /obj/item/wallframe/airalarm( user.loc )
- qdel(src)
- return
-
- return ..()
-
-/obj/machinery/airalarm/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- if((buildstage == 0) && (the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS))
- return list("mode" = RCD_UPGRADE_SIMPLE_CIRCUITS, "delay" = 20, "cost" = 1)
- return FALSE
-
-/obj/machinery/airalarm/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
- switch(passed_mode)
- if(RCD_UPGRADE_SIMPLE_CIRCUITS)
- user.visible_message("[user] fabricates a circuit and places it into [src].", \
- "You adapt an air alarm circuit and slot it into the assembly.")
- buildstage = 1
- update_icon()
- return TRUE
- return FALSE
-
-/obj/machinery/airalarm/AltClick(mob/user)
- if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc))
- return
- else
- togglelock(user)
-
-/obj/machinery/airalarm/proc/togglelock(mob/living/user)
- if(machine_stat & (NOPOWER|BROKEN))
- to_chat(user, "It does nothing!")
- else
- if(src.allowed(usr) && !wires.is_cut(WIRE_IDSCAN))
- locked = !locked
- to_chat(user, "You [ locked ? "lock" : "unlock"] the air alarm interface.")
- updateUsrDialog()
- else
- to_chat(user, "Access denied.")
- return
-
-/obj/machinery/airalarm/on_emag(mob/user)
- ..()
- visible_message("Sparks fly out of [src]!", "You emag [src], disabling its safeties.")
- playsound(src, "sparks", 50, 1)
-
-/obj/machinery/airalarm/atom_break(damage_flag)
- ..()
- update_icon()
-
-/obj/machinery/airalarm/deconstruct(disassembled = TRUE)
- if(!(flags_1 & NODECONSTRUCT_1))
- new /obj/item/stack/sheet/iron(loc, 2)
- var/obj/item/I = new /obj/item/electronics/airalarm(loc)
- if(!disassembled)
- I.take_damage(I.max_integrity * 0.5, sound_effect=FALSE)
- new /obj/item/stack/cable_coil(loc, 3)
- qdel(src)
-
-/obj/item/circuit_component/air_alarm
- display_name = "Air Alarm"
- desc = "Controls levels of gases and their temperature as well as all vents and scrubbers in the room."
-
- var/datum/port/input/option/air_alarm_options
-
- var/datum/port/input/min_2
- var/datum/port/input/min_1
- var/datum/port/input/max_1
- var/datum/port/input/max_2
-
- var/datum/port/input/request_data
-
- var/datum/port/output/pressure
- var/datum/port/output/temperature
- var/datum/port/output/gas_amount
-
- var/obj/machinery/airalarm/connected_alarm
- var/list/options_map
-
-/obj/item/circuit_component/air_alarm/populate_ports()
- min_2 = add_input_port("Min 2", PORT_TYPE_NUMBER)
- min_1 = add_input_port("Min 1", PORT_TYPE_NUMBER)
- max_1 = add_input_port("Max 1", PORT_TYPE_NUMBER)
- max_2 = add_input_port("Max 2", PORT_TYPE_NUMBER)
- request_data = add_input_port("Request Atmosphere Data", PORT_TYPE_SIGNAL)
-
- pressure = add_output_port("Pressure", PORT_TYPE_NUMBER)
- temperature = add_output_port("Temperature", PORT_TYPE_NUMBER)
- gas_amount = add_output_port("Chosen Gas Amount", PORT_TYPE_NUMBER)
-
-/obj/item/circuit_component/air_alarm/populate_options()
- var/static/list/component_options
-
- if(!component_options)
- component_options = list(
- "Pressure" = "pressure",
- "Temperature" = "temperature"
- )
-
- for(var/gas_id in GLOB.gas_data.ids)
- component_options[GLOB.gas_data.names[gas_id]] = gas_id
-
- air_alarm_options = add_option_port("Air Alarm Options", component_options)
- options_map = component_options
-
-/obj/item/circuit_component/air_alarm/register_usb_parent(atom/movable/parent)
- . = ..()
- if(istype(parent, /obj/machinery/airalarm))
- connected_alarm = parent
-
-/obj/item/circuit_component/air_alarm/unregister_usb_parent(atom/movable/parent)
- connected_alarm = null
- return ..()
-
-/obj/item/circuit_component/air_alarm/input_received(datum/port/input/port)
- if(!connected_alarm || connected_alarm.locked)
- return
-
- var/current_option = air_alarm_options.value
-
- if(COMPONENT_TRIGGERED_BY(request_data, port))
- var/turf/alarm_turf = get_turf(connected_alarm)
- var/datum/gas_mixture/environment = alarm_turf.return_air()
- pressure.set_output(round(environment.return_pressure()))
- temperature.set_output(round(environment.return_temperature()))
- if(ispath(options_map[current_option]))
- gas_amount.set_output(round(environment.get_moles(current_option)))
- return
-
- var/datum/tlv/settings = connected_alarm.TLV[options_map[current_option]]
- settings.min2 = min_2
- settings.min1 = min_1
- settings.max1 = max_1
- settings.max2 = max_2
-
-#undef AALARM_MODE_SCRUBBING
-#undef AALARM_MODE_VENTING
-#undef AALARM_MODE_PANIC
-#undef AALARM_MODE_REPLACEMENT
-#undef AALARM_MODE_OFF
-#undef AALARM_MODE_FLOOD
-#undef AALARM_MODE_SIPHON
-#undef AALARM_MODE_CONTAMINATED
-#undef AALARM_MODE_REFILL
-#undef AALARM_REPORT_TIMEOUT
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index 68aeead0da8bd..195f30365b037 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -12,7 +12,7 @@
/obj/machinery/atmospherics
anchored = TRUE
- move_resist = INFINITY //Moving a connected machine without actually doing the normal (dis)connection things will probably cause a LOT of issues.
+ move_resist = INFINITY //Moving a connected machine without actually doing the normal (dis)connection things will probably cause a LOT of issues. (this imply moving machines with something that can push turfs like a megafauna)
idle_power_usage = 0
active_power_usage = 0
power_channel = AREA_USAGE_ENVIRON
@@ -20,28 +20,56 @@
resistance_flags = FIRE_PROOF
max_integrity = 200
obj_flags = CAN_BE_HIT | ON_BLUEPRINTS
- var/can_unwrench = 0
+ ///Check if the object can be unwrenched
+ var/can_unwrench = FALSE
+ ///Bitflag of the initialized directions (NORTH | SOUTH | EAST | WEST)
var/initialize_directions = 0
- var/pipe_color
+ ///The color of the pipe
+ var/pipe_color = COLOR_VERY_LIGHT_GRAY
+ ///What layer the pipe is in (from 1 to 5, default 3)
var/piping_layer = PIPING_LAYER_DEFAULT
+ ///The flags of the pipe/component (PIPING_ALL_LAYER | PIPING_ONE_PER_TURF | PIPING_DEFAULT_LAYER_ONLY | PIPING_CARDINAL_AUTONORMALIZE)
var/pipe_flags = NONE
///This only works on pipes, because they have 1000 subtypes which need to be visible and invisible under tiles, so we track this here
var/hide = TRUE
+ ///Identifiers for the iconset, the path where the image will be taken from
var/static/list/iconsetids = list()
+ ///The unique identifier created from the iconsetids, the parameters are then used to define the pipe image (icon, icon_state, color, direction, piping_layer)
var/static/list/pipeimages = list()
+ ///The image of the pipe/device used for ventcrawling
var/image/pipe_vision_img = null
+ ///The type of the device (UNARY, BINARY, TRINARY, QUATERNARY)
var/device_type = 0
+ ///The lists of nodes that a pipe/device has, depends on the device_type var (from 1 to 4)
var/list/obj/machinery/atmospherics/nodes
+ ///The path of the pipe/device that will spawn after unwrenching it (such as pipe fittings)
var/construction_type
- var/pipe_state //icon_state as a pipe item
+ ///icon_state as a pipe item
+ var/pipe_state
+ ///Check if the device should be on or off (mostly used in processing for machines)
var/on = FALSE
- /// whether it can be painted
- var/paintable = FALSE
+ ///Whether it can be painted
+ var/paintable = TRUE
+
+ ///Is the thing being rebuilt by SSair or not. Prevents list bloat
+ var/rebuilding = FALSE
+
+ ///The bitflag that's being checked on ventcrawling. Default is to allow ventcrawling and seeing pipes.
+ var/vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE
+
+ ///Store the smart pipes connections, used for pipe construction
+ var/connection_num = 0
+
+ ///keeps the name of the object from being overridden if it's vareditted.
+ var/override_naming
+
+ ///If we should init and immediately start processing
+ var/init_processing = FALSE
/obj/machinery/atmospherics/examine(mob/user)
. = ..()
@@ -61,14 +89,14 @@
..()
if(process)
SSair.start_processing_machine(src)
- SetInitDirections()
+ set_init_directions()
/obj/machinery/atmospherics/Destroy()
for(var/i in 1 to device_type)
- nullifyNode(i)
+ nullify_node(i)
SSair.stop_processing_machine(src)
- SSair.pipenets_needing_rebuilt -= src
+ SSair.rebuild_queue -= src
if(pipe_vision_img)
qdel(pipe_vision_img)
@@ -76,32 +104,60 @@
return ..()
//return QDEL_HINT_FINDREFERENCE
+/**
+ * Called by the machinery disconnect(), custom for each type
+ */
/obj/machinery/atmospherics/proc/destroy_network()
return
-/obj/machinery/atmospherics/proc/build_network()
- // Called to build a network from this node
+/obj/machinery/atmospherics/proc/set_on(active)
+ on = active
+ SEND_SIGNAL(src, COMSIG_ATMOS_MACHINE_SET_ON, on)
+
+/// This should only be called by SSair as part of the rebuild queue.
+/// Handles rebuilding pipelines after init or they've been changed.
+/obj/machinery/atmospherics/proc/rebuild_pipes()
+ var/list/targets = get_rebuild_targets()
+ rebuilding = FALSE
+ for(var/datum/pipeline/build_off as anything in targets)
+ build_off.build_pipeline(src) //This'll add to the expansion queue
+
+/**
+ * Returns a list of new pipelines that need to be built up
+ */
+/obj/machinery/atmospherics/proc/get_rebuild_targets()
return
-/obj/machinery/atmospherics/proc/nullifyNode(i)
- if(nodes[i])
- var/obj/machinery/atmospherics/N = nodes[i]
- N.disconnect(src)
- nodes[i] = null
+/**
+ * Called on destroy(mostly deconstruction) and when moving nodes around, disconnect the nodes from the network
+ * Arguments:
+ * * i - is the current iteration of the node, based on the device_type (from 1 to 4)
+ */
+/obj/machinery/atmospherics/proc/nullify_node(i)
+ if(!nodes[i])
+ return
+ var/obj/machinery/atmospherics/node_machine = nodes[i]
+ node_machine.disconnect(src)
+ nodes[i] = null
-/obj/machinery/atmospherics/proc/getNodeConnects()
+/obj/machinery/atmospherics/proc/get_node_connects()
var/list/node_connects = list()
node_connects.len = device_type
for(var/i in 1 to device_type)
for(var/D in GLOB.cardinals)
- if(D & GetInitDirections())
+ if(D & get_init_directions())
if(D in node_connects)
continue
node_connects[i] = D
break
return node_connects
+/**
+ * Setter for device direction
+ *
+ * Set the direction to either SOUTH or WEST if the pipe_flag is set to PIPING_CARDINAL_AUTONORMALIZE, called in New(), used mostly by layer manifolds
+ */
/obj/machinery/atmospherics/proc/normalize_cardinal_directions()
switch(dir)
if(SOUTH)
@@ -109,65 +165,175 @@
if(WEST)
setDir(EAST)
-//this is called just after the air controller sets up turfs
-/obj/machinery/atmospherics/proc/atmosinit(list/node_connects)
+
+/**
+ * Initialize for atmos devices
+ *
+ * initialize the nodes for each pipe/device, this is called just after the air controller sets up turfs
+ * Arguments:
+ * * list/node_connects - a list of the nodes on the device that can make a connection to other machines
+ */
+/obj/machinery/atmospherics/proc/atmos_init(list/node_connects)
if(!node_connects) //for pipes where order of nodes doesn't matter
- node_connects = getNodeConnects()
+ node_connects = get_node_connects()
for(var/i in 1 to device_type)
for(var/obj/machinery/atmospherics/target in get_step(src,node_connects[i]))
- if(can_be_node(target, i))
+ if(can_be_node(target))
nodes[i] = target
break
update_icon()
-/obj/machinery/atmospherics/proc/setPipingLayer(new_layer)
+/**
+ * setter for pipe layers
+ *
+ * Set the layer of the pipe that the device has to a new_layer
+ * Arguments:
+ * * new_layer - the layer at which we want the piping_layer to be (1 to 5)
+ */
+/obj/machinery/atmospherics/proc/set_piping_layer(new_layer)
piping_layer = (pipe_flags & PIPING_DEFAULT_LAYER_ONLY) ? PIPING_LAYER_DEFAULT : new_layer
update_icon()
+/**
+ * Check if a node can actually exists by connecting to another machine
+ * called on atmosinit()
+ * Arguments:
+ * * obj/machinery/atmospherics/target - the machine we are connecting to
+ * * iteration - the current node we are checking (from 1 to 4)
+ */
/obj/machinery/atmospherics/proc/can_be_node(obj/machinery/atmospherics/target, iteration)
return connection_check(target, piping_layer)
-//Find a connecting /obj/machinery/atmospherics in specified direction
-/obj/machinery/atmospherics/proc/findConnecting(direction, prompted_layer)
- for(var/obj/machinery/atmospherics/target in get_step_multiz(src, direction))
- if(target.initialize_directions & get_dir(target,src) && !istype(target, /obj/machinery/atmospherics/pipe/multiz))
- if(connection_check(target, prompted_layer))
- return target
+/**
+ * Find a connecting /obj/machinery/atmospherics in specified direction, called by relaymove()
+ * used by ventcrawling mobs to check if they can move inside a pipe in a specific direction
+ * Arguments:
+ * * direction - the direction we are checking against
+ * * prompted_layer - the piping_layer we are inside
+ */
+/obj/machinery/atmospherics/proc/find_connecting(direction, prompted_layer)
+ for(var/obj/machinery/atmospherics/target in get_step_multiz(src, direction))
+ if(!(target.initialize_directions & get_dir(target,src)))
+ continue
+ if(connection_check(target, prompted_layer))
+ return target
+
+/**
+ * Check the connection between two nodes
+ *
+ * Check if our machine and the target machine are connectable by both calling isConnectable and by checking that the directions and piping_layer are compatible
+ * called by can_be_node() (for building a network) and findConnecting() (for ventcrawling)
+ * Arguments:
+ * * obj/machinery/atmospherics/target - the machinery we want to connect to
+ * * given_layer - the piping_layer we are checking
+ */
/obj/machinery/atmospherics/proc/connection_check(obj/machinery/atmospherics/target, given_layer)
- if(isConnectable(target, given_layer) && target.isConnectable(src, given_layer) && (target.initialize_directions & get_dir(target,src) || istype(target, /obj/machinery/atmospherics/pipe/multiz)))
+ if(is_connectable(target, given_layer) && target.is_connectable(src, given_layer) && (target.initialize_directions & get_dir(target,src) || istype(target, /obj/machinery/atmospherics/pipe/multiz)))
return TRUE
return FALSE
-/obj/machinery/atmospherics/proc/isConnectable(obj/machinery/atmospherics/target, given_layer)
+/**
+ * check if the piping layer and color are the same on both sides (grey can connect to all colors)
+ * returns TRUE or FALSE if the connection is possible or not
+ * Arguments:
+ * * obj/machinery/atmospherics/target - the machinery we want to connect to
+ * * given_layer - the piping_layer we are connecting to
+ */
+/obj/machinery/atmospherics/proc/is_connectable(obj/machinery/atmospherics/target, given_layer)
if(isnull(given_layer))
given_layer = piping_layer
- if((target.piping_layer == given_layer) || (target.pipe_flags & PIPING_ALL_LAYER))
+
+ // you can't place the machine on the same location as the target cause it blocks
+ if(target.loc == loc)
+ return FALSE
+
+ //if the target is not in the same piping layer & it does not have the all layer connection flag[which allows it to be connected regardless of layer] then we are out
+ if(target.pipe_flags & PIPING_DISTRO_AND_WASTE_LAYERS)
+ if(ISODD(given_layer))
+ return FALSE
+ else if(target.piping_layer != given_layer && !(target.pipe_flags & PIPING_ALL_LAYER))
+ return FALSE
+
+ //if the target does not have the same color and it does not have all color connection flag[which allows it to be connected regardless of color] & one of the pipes is not gray[allowing for connection regardless] then we are out
+ if(target.pipe_color != pipe_color && !((target.pipe_flags | pipe_flags) & PIPING_ALL_COLORS) && target.pipe_color != COLOR_VERY_LIGHT_GRAY && pipe_color != COLOR_VERY_LIGHT_GRAY)
+ return FALSE
+
+ return TRUE
+/**
+ * check if the piping layer are the same on both sides or one of them has the PIPING_ALL_LAYER flag
+ * returns TRUE if one of the parameters is TRUE
+ * called by isConnectable()
+ * Arguments:
+ * * obj/machinery/atmospherics/target - the machinery we want to connect to
+ * * given_layer - the piping_layer we are connecting to
+ */
+/obj/machinery/atmospherics/proc/check_connectable_layer(obj/machinery/atmospherics/target, given_layer)
+ if(target.piping_layer == given_layer || (target.pipe_flags | pipe_flags) & PIPING_ALL_LAYER)
return TRUE
return FALSE
+/**
+ * check if the color are the same on both sides or if one of the pipes are grey or have the PIPING_ALL_COLORS flag
+ * returns TRUE if one of the parameters is TRUE
+ * Arguments:
+ * * obj/machinery/atmospherics/target - the machinery we want to connect to
+ */
+/obj/machinery/atmospherics/proc/check_connectable_color(obj/machinery/atmospherics/target)
+ if(lowertext(target.pipe_color) == lowertext(pipe_color) || ((target.pipe_flags | pipe_flags) & PIPING_ALL_COLORS) || lowertext(target.pipe_color) == lowertext(COLOR_VERY_LIGHT_GRAY) || lowertext(pipe_color == COLOR_VERY_LIGHT_GRAY))
+ return TRUE
+ return FALSE
+
+/**
+ * Called on construction and when expanding the datum_pipeline, returns the nodes of the device
+ */
/obj/machinery/atmospherics/proc/pipeline_expansion()
return nodes
-/obj/machinery/atmospherics/proc/SetInitDirections()
+/**
+ * Set the initial directions of the device (NORTH || SOUTH || EAST || WEST), called on New()
+ */
+/obj/machinery/atmospherics/proc/set_init_directions()
return
-/obj/machinery/atmospherics/proc/GetInitDirections()
+/**
+ * Getter of initial directions
+ */
+/obj/machinery/atmospherics/proc/get_init_directions()
return initialize_directions
-/obj/machinery/atmospherics/proc/returnPipenet()
+/**
+ * Called by addMember() in datum_pipeline.dm, returns the parent network the device is connected to
+ */
+/obj/machinery/atmospherics/proc/return_pipenet()
return
-/obj/machinery/atmospherics/proc/returnPipenetAir()
+/*
+ * Called by add_machinery_member() in datum_pipeline.dm, returns a list of gas_mixtures and assigns them into other_airs (by add_machinery_member) to allow pressure redistribution for the machineries.
+ */
+/obj/machinery/atmospherics/proc/return_pipenet_airs()
return
-/obj/machinery/atmospherics/proc/setPipenet()
+/**
+ * Called by build_pipeline() and addMember() in datum_pipeline.dm, set the network the device is connected to, to the datum pipeline it has reference
+ */
+/obj/machinery/atmospherics/proc/set_pipenet()
return
-/obj/machinery/atmospherics/proc/replacePipenet()
+/**
+ * Similar to setPipenet() but instead of setting a network to a pipeline, it replaces the old pipeline with a new one, called by Merge() in datum_pipeline.dm
+ */
+/obj/machinery/atmospherics/proc/replace_pipenet()
return
+/**
+ * Disconnects the nodes
+ *
+ * Called by nullifyNode(), it disconnects two nodes by removing the reference id from the node itself that called this proc
+ * Arguments:
+ * * obj/machinery/atmospherics/reference - the machinery we are removing from the node connection
+ */
/obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference)
if(istype(reference, /obj/machinery/atmospherics/pipe))
var/obj/machinery/atmospherics/pipe/P = reference
@@ -180,7 +346,7 @@
if(istype(W, /obj/item/pipe)) //lets you autodrop
var/obj/item/pipe/pipe = W
if(user.dropItemToGround(pipe))
- pipe.setPipingLayer(piping_layer) //align it with us
+ pipe.set_piping_layer(piping_layer) //align it with us
return TRUE
else
return ..()
@@ -217,10 +383,25 @@
return deconstruct(TRUE)
return TRUE
+/**
+ * Getter for can_unwrench
+ *
+ * Called by wrench_act() to check if the device can be unwrenched, each device override this with custom code (like if on/operating can't unwrench)
+ * Arguments:
+ * * mob/user - the mob doing the act
+ */
/obj/machinery/atmospherics/proc/can_unwrench(mob/user)
return can_unwrench
-// Throws the user when they unwrench a pipe with a major difference between the internal and environmental pressure.
+/**
+ * Pipe pressure release calculations
+ *
+ * Throws the user when they unwrench a pipe with a major difference between the internal and environmental pressure.
+ * Called by wrench_act() before deconstruct()
+ * Arguments:
+ * * mob_user - the mob doing the act
+ * * pressures - it can be passed on from wrench_act(), it's the pressure difference between the enviroment pressure and the pipe internal pressure
+ */
/obj/machinery/atmospherics/proc/unsafe_pressure_release(mob/living/carbon/user, pressures = null)
if(!user)
return
@@ -246,15 +427,27 @@
/obj/machinery/atmospherics/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
if(can_unwrench)
- var/obj/item/pipe/stored = new construction_type(loc, null, dir, src)
- stored.setPipingLayer(piping_layer)
+ var/obj/item/pipe/stored = new construction_type(loc, null, dir, src, pipe_color)
+ stored.set_piping_layer(piping_layer)
if(!disassembled)
stored.take_damage(stored.max_integrity * 0.5, sound_effect=FALSE)
transfer_fingerprints_to(stored)
. = stored
..()
-/obj/machinery/atmospherics/proc/getpipeimage(iconset, iconstate, direction, col=rgb(255,255,255), piping_layer=3, trinary = FALSE)
+/**
+ * Getter for pipe underlay
+ *
+ * Creates the image for the pipe underlay that all components use, called by get_pipe_underlay() in components_base.dm
+ * Arguments:
+ * * iconset - path of the iconstate we are using (ex: 'icons/obj/atmospherics/components/thermomachine.dmi')
+ * * iconstate - the image we are using inside the file
+ * * direction - the direction of our device
+ * * col - the color (in hex value, like #559900) that the pipe should have
+ * * piping_layer - the piping_layer the device is in, used inside PIPING_LAYER_SHIFT
+ * * trinary - if TRUE we also use PIPING_FORWARD_SHIFT on layer 1 and 5 for trinary devices (filters and mixers)
+ */
+/obj/machinery/atmospherics/proc/get_pipe_image(iconset, iconstate, direction, col=rgb(255,255,255), piping_layer=3, trinary = FALSE)
//Add identifiers for the iconset
if(iconsetids[iconset] == null)
@@ -271,17 +464,25 @@
if(trinary && (piping_layer == 1 || piping_layer == 5))
PIPING_FORWARD_SHIFT(pipe_overlay, piping_layer, 2)
+///Similar to getpipeimage(); will create an image from the set_icon and set_state; mostly used to create overlays for connections.
+/obj/machinery/atmospherics/proc/pipe_overlay(set_icon, set_state, direction, color = COLOR_VERY_LIGHT_GRAY, piping_layer = 3, set_layer = PIPE_VISIBLE_LEVEL)
+ var/image/pipe_overlay
+ pipe_overlay = image(icon = set_icon, icon_state = set_state, layer = set_layer, dir = direction)
+ pipe_overlay.color = color
+ PIPING_LAYER_SHIFT(pipe_overlay, piping_layer)
+ return pipe_overlay
+
/obj/machinery/atmospherics/on_construction(obj_color, set_layer)
if(can_unwrench)
add_atom_colour(obj_color, FIXED_COLOUR_PRIORITY)
pipe_color = obj_color
- setPipingLayer(set_layer)
- atmosinit()
+ set_piping_layer(set_layer)
+ atmos_init()
var/list/nodes = pipeline_expansion()
for(var/obj/machinery/atmospherics/A in nodes)
- A.atmosinit()
- A.addMember(src)
- build_network()
+ A.atmos_init()
+ A.add_member(src)
+ SSair.add_to_rebuild_queue(src)
/obj/machinery/atmospherics/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs)
if(istype(arrived, /mob/living))
@@ -301,14 +502,14 @@
return
if(user in buckled_mobs)// fixes buckle ventcrawl edgecase fuck bug
return
- var/obj/machinery/atmospherics/target_move = findConnecting(direction, user.ventcrawl_layer)
+ var/obj/machinery/atmospherics/target_move = find_connecting(direction, user.ventcrawl_layer)
if(target_move)
if(target_move.can_crawl_through())
if(is_type_in_typecache(target_move, GLOB.ventcrawl_machinery))
user.forceMove(target_move.loc) //handle entering and so on.
user.visible_message("You hear something squeezing through the ducts...", "You climb out the ventilation system.")
else
- var/list/pipenetdiff = returnPipenets() ^ target_move.returnPipenets()
+ var/list/pipenetdiff = return_pipenets() ^ target_move.return_pipenets()
if(pipenetdiff.len)
user.update_pipe_vision(target_move)
user.forceMove(target_move)
@@ -330,24 +531,60 @@
L.handle_ventcrawl(src)
return
-/// Whether ventcrawling creatures can move in or out of this machine.
+/**
+ * Getter for vent crawling
+ *
+ * returns TRUE or FALSE, many devices overrides this (like cryo, or vents)
+ * called by relaymove()
+ */
/obj/machinery/atmospherics/proc/can_crawl_through()
return TRUE
-/obj/machinery/atmospherics/proc/returnPipenets()
+/**
+ * Getter of a list of pipenets
+ *
+ * called in relaymove() to create the image for vent crawling
+ */
+/obj/machinery/atmospherics/proc/return_pipenets()
return list()
/obj/machinery/atmospherics/update_remote_sight(mob/user)
user.sight |= (SEE_TURFS|BLIND)
-//Used for certain children of obj/machinery/atmospherics to not show pipe vision when mob is inside it.
+/**
+ * Used for certain children of obj/machinery/atmospherics to not show pipe vision when mob is inside it.
+ */
/obj/machinery/atmospherics/proc/can_see_pipes()
return TRUE
+/**
+ * Update the layer in which the pipe/device is in, that way pipes have consistent layer depending on piping_layer
+ */
/obj/machinery/atmospherics/proc/update_layer()
- layer = initial(layer) + (piping_layer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_LCHANGE
+ layer = initial(layer) + (piping_layer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_LCHANGE + (GLOB.pipe_colors_ordered[pipe_color] * 0.01)
+/**
+ * Called by the RPD.dm pre_attack()
+ * Arguments:
+ * * paint_color - color that the pipe will be painted in (colors in hex like #4f4f4f)
+ */
/obj/machinery/atmospherics/proc/paint(paint_color)
+ if(paintable)
+ add_atom_colour(paint_color, FIXED_COLOUR_PRIORITY)
+ set_pipe_color(paint_color)
+ update_node_icon()
+ return paintable
+
+/// Setter for pipe color, so we can ensure it's all uniform and save cpu time
+/obj/machinery/atmospherics/proc/set_pipe_color(pipe_colour)
+ src.pipe_color = uppertext(pipe_colour)
+ update_name()
+
+/// Return TRUE if there is device connected to portables_connector
+/obj/machinery/atmospherics/proc/portable_device_connected(node)
+ var/obj/machinery/atmospherics/components/unary/portables_connector/portable_devices_connector = nodes[node]
+ if(portable_devices_connector.connected_device)
+ return TRUE
return FALSE
#undef PIPE_VISIBLE_LEVEL
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/binary_devices.dm b/code/modules/atmospherics/machinery/components/binary_devices/binary_devices.dm
index accec64dbd8c0..c71e8b1cd1d06 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/binary_devices.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/binary_devices.dm
@@ -5,15 +5,16 @@
use_power = IDLE_POWER_USE
device_type = BINARY
layer = GAS_PUMP_LAYER
+ pipe_flags = PIPING_BRIDGE
-/obj/machinery/atmospherics/components/binary/SetInitDirections()
+/obj/machinery/atmospherics/components/binary/set_init_directions()
switch(dir)
if(NORTH, SOUTH)
initialize_directions = NORTH|SOUTH
if(EAST, WEST)
initialize_directions = EAST|WEST
-/obj/machinery/atmospherics/components/binary/getNodeConnects()
+/obj/machinery/atmospherics/components/binary/get_node_connects()
return list(turn(dir, 180), dir)
///Used by binary devices to set what the offset will be for each layer
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
index acfd081a60f73..651249cc8b8dc 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
@@ -49,7 +49,7 @@
if(air2.return_temperature()>0)
var/pressure_delta = (input_starting_pressure - output_starting_pressure)/2
- var/transfer_moles = pressure_delta*air1.return_volume()/(air2.return_temperature() * R_IDEAL_GAS_EQUATION)
+ var/transfer_moles = (pressure_delta*air1.return_volume())/(air2.return_temperature() * R_IDEAL_GAS_EQUATION)
last_pressure_delta = pressure_delta
@@ -94,35 +94,35 @@
if(node1)
node1.disconnect(src)
nodes[1] = null
- nullifyPipenet(parents[1])
+ nullify_pipenet(parents[1])
if(node2)
node2.disconnect(src)
nodes[2] = null
- nullifyPipenet(parents[2])
+ nullify_pipenet(parents[2])
if(anchored)
- SetInitDirections()
- atmosinit()
+ set_init_directions()
+ atmos_init()
node1 = nodes[1]
if(node1)
- node1.atmosinit()
- node1.addMember(src)
+ node1.atmos_init()
+ node1.add_member(src)
node2 = nodes[2]
if(node2)
- node2.atmosinit()
- node2.addMember(src)
+ node2.atmos_init()
+ node2.add_member(src)
SSair.add_to_rebuild_queue(src)
return TRUE
-/obj/machinery/atmospherics/components/binary/circulator/SetInitDirections()
+/obj/machinery/atmospherics/components/binary/circulator/set_init_directions()
switch(dir)
if(NORTH, SOUTH)
initialize_directions = EAST|WEST
if(EAST, WEST)
initialize_directions = NORTH|SOUTH
-/obj/machinery/atmospherics/components/binary/circulator/getNodeConnects()
+/obj/machinery/atmospherics/components/binary/circulator/get_node_connects()
if(flipped)
return list(turn(dir, 270), turn(dir, 90))
return list(turn(dir, 90), turn(dir, 270))
@@ -163,7 +163,7 @@
generator.update_icon()
generator = null
-/obj/machinery/atmospherics/components/binary/circulator/setPipingLayer(new_layer)
+/obj/machinery/atmospherics/components/binary/circulator/set_piping_layer(new_layer)
..()
pixel_x = 0
pixel_y = 0
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
index 298b46b58133d..376a8034136fd 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/dp_vent_pump.dm
@@ -1,7 +1,5 @@
//Acts like a normal vent, but has an input AND output.
-#define EXT_BOUND 1
-#define INPUT_MIN 2
#define OUTPUT_MAX 4
/obj/machinery/atmospherics/components/binary/dp_vent_pump
@@ -20,34 +18,22 @@
interacts_with_air = TRUE
- var/frequency = 0
- var/id = null
- var/datum/radio_frequency/radio_connection
-
- var/pump_direction = 1 //0 = siphoning, 1 = releasing
+ ///Indicates that the direction of the pump, if ATMOS_DIRECTION_SIPHONING is siphoning, if ATMOS_DIRECTION_RELEASING is releasing
+ var/pump_direction = ATMOS_DIRECTION_RELEASING
+ ///Set the maximum allowed external pressure
var/external_pressure_bound = ONE_ATMOSPHERE
+ ///Set the maximum pressure at the input port
var/input_pressure_min = 0
+ ///Set the maximum pressure at the output port
var/output_pressure_max = 0
-
- var/pressure_checks = EXT_BOUND
-
- var/obj/machinery/advanced_airlock_controller/aac = null
-
- //EXT_BOUND: Do not pass external_pressure_bound
- //INPUT_MIN: Do not pass input_pressure_min
- //OUTPUT_MAX: Do not pass output_pressure_max
-
-/obj/machinery/atmospherics/components/binary/dp_vent_pump/Destroy()
- SSradio.remove_object(src, frequency)
- if(aac)
- aac.vents -= src
- return ..()
+ ///Set the flag for the pressure bound
+ var/pressure_checks = ATMOS_EXTERNAL_BOUND
/obj/machinery/atmospherics/components/binary/dp_vent_pump/update_icon_nopipes()
cut_overlays()
if(showpipe)
- var/image/cap = getpipeimage(icon, "dpvent_cap", dir, piping_layer = piping_layer)
+ var/image/cap = get_pipe_image(icon, "dpvent_cap", dir, pipe_color, piping_layer = piping_layer)
add_overlay(cap)
if(welded)
@@ -74,111 +60,35 @@
if(pump_direction) //input -> external
var/pressure_delta = 10000
- if(pressure_checks&EXT_BOUND)
+ if(pressure_checks&ATMOS_EXTERNAL_BOUND)
pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure))
- if(pressure_checks&INPUT_MIN)
+ if(pressure_checks&ATMOS_INTERNAL_BOUND)
pressure_delta = min(pressure_delta, (air1.return_pressure() - input_pressure_min))
if(pressure_delta > 0)
if(air1.return_temperature() > 0)
- var/transfer_moles = pressure_delta*environment.return_volume()/(air1.return_temperature() * R_IDEAL_GAS_EQUATION)
+ var/transfer_moles = (pressure_delta*environment.volume)/(air1.return_temperature() * R_IDEAL_GAS_EQUATION)
loc.assume_air_moles(air1, transfer_moles)
- air_update_turf()
var/datum/pipeline/parent1 = parents[1]
- if(!parent1)
- return
- parent1.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
+ parent1.update = TRUE
else //external -> output
if(environment.return_pressure() > 0)
var/our_multiplier = air2.return_volume() / (environment.return_temperature() * R_IDEAL_GAS_EQUATION)
var/moles_delta = 10000 * our_multiplier
- if(pressure_checks&EXT_BOUND)
+ if(pressure_checks&ATMOS_EXTERNAL_BOUND)
moles_delta = min(moles_delta, (environment_pressure - output_pressure_max) * environment.return_volume() / (environment.return_temperature() * R_IDEAL_GAS_EQUATION))
- if(pressure_checks&INPUT_MIN)
+ if(pressure_checks&ATMOS_INTERNAL_BOUND)
moles_delta = min(moles_delta, (input_pressure_min - air2.return_pressure()) * our_multiplier)
if(moles_delta > 0)
loc.transfer_air(air2, moles_delta)
- air_update_turf()
var/datum/pipeline/parent2 = parents[2]
- parent2.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
-
- //Radio remote control
-
-/obj/machinery/atmospherics/components/binary/dp_vent_pump/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- if(frequency)
- radio_connection = SSradio.add_object(src, frequency, filter = RADIO_ATMOSIA)
-
-/obj/machinery/atmospherics/components/binary/dp_vent_pump/proc/broadcast_status()
- if(!radio_connection)
- return
-
- var/datum/signal/signal = new(list(
- "tag" = id,
- "device" = "ADVP",
- "power" = on,
- "direction" = pump_direction?("release"):("siphon"),
- "checks" = pressure_checks,
- "input" = input_pressure_min,
- "output" = output_pressure_max,
- "external" = external_pressure_bound,
- "sigtype" = "status"
- ))
- radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
-
-/obj/machinery/atmospherics/components/binary/dp_vent_pump/atmosinit()
- ..()
- if(frequency)
- set_frequency(frequency)
- broadcast_status()
-
-/obj/machinery/atmospherics/components/binary/dp_vent_pump/receive_signal(datum/signal/signal)
- if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
- return
-
- if("power" in signal.data)
- on = text2num(signal.data["power"])
-
- if("power_toggle" in signal.data)
- on = !on
-
- if("set_direction" in signal.data)
- pump_direction = text2num(signal.data["set_direction"])
-
- if("checks" in signal.data)
- pressure_checks = text2num(signal.data["checks"])
-
- if("purge" in signal.data)
- pressure_checks &= ~1
- pump_direction = 0
-
- if("stabilize" in signal.data)
- pressure_checks |= 1
- pump_direction = 1
-
- if("set_input_pressure" in signal.data)
- input_pressure_min = clamp(text2num(signal.data["set_input_pressure"]),0,ONE_ATMOSPHERE*50)
-
- if("set_output_pressure" in signal.data)
- output_pressure_max = clamp(text2num(signal.data["set_output_pressure"]),0,ONE_ATMOSPHERE*50)
-
- if("set_external_pressure" in signal.data)
- external_pressure_bound = clamp(text2num(signal.data["set_external_pressure"]),0,ONE_ATMOSPHERE*50)
-
- if("status" in signal.data)
- spawn(2)
- broadcast_status()
- return //do not update_icon
- spawn(2)
- broadcast_status()
- update_icon()
+ parent2.update = TRUE
/obj/machinery/atmospherics/components/binary/dp_vent_pump/welder_act(mob/living/user, obj/item/I)
if(!I.tool_start_check(user, amount=0))
@@ -221,8 +131,8 @@
..()
var/datum/gas_mixture/air1 = airs[1]
var/datum/gas_mixture/air2 = airs[2]
- air1.set_volume(1000)
- air2.set_volume(1000)
+ air1.volume = 1000
+ air2.volume = 1000
// Mapping
@@ -247,16 +157,13 @@
icon_state = "dpvent_map_on-4"
/obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume/incinerator_toxmix
- id = INCINERATOR_TOXMIX_DP_VENTPUMP
- frequency = FREQ_AIRLOCK_CONTROL
+ id_tag = INCINERATOR_TOXMIX_DP_VENTPUMP
/obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume/incinerator_atmos
- id = INCINERATOR_ATMOS_DP_VENTPUMP
- frequency = FREQ_AIRLOCK_CONTROL
+ id_tag = INCINERATOR_ATMOS_DP_VENTPUMP
/obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume/incinerator_syndicatelava
- id = INCINERATOR_SYNDICATELAVA_DP_VENTPUMP
- frequency = FREQ_AIRLOCK_CONTROL
+ id_tag = INCINERATOR_SYNDICATELAVA_DP_VENTPUMP
/obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume/layer2
piping_layer = 2
@@ -278,6 +185,4 @@
piping_layer = 4
icon_state = "dpvent_map_on-4"
-#undef EXT_BOUND
-#undef INPUT_MIN
#undef OUTPUT_MAX
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 5497bc81d6534..20d9a967b998a 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/passive_gate.dm
@@ -20,10 +20,6 @@ Passive gate is similar to the regular pump except:
var/target_pressure = ONE_ATMOSPHERE
- var/frequency = 0
- var/id = null
- var/datum/radio_frequency/radio_connection
-
construction_type = /obj/item/pipe/directional
pipe_state = "passivegate"
@@ -45,15 +41,11 @@ Passive gate is similar to the regular pump except:
ui_update()
return
-/obj/machinery/atmospherics/components/binary/passive_gate/Destroy()
- SSradio.remove_object(src,frequency)
- return ..()
-
/obj/machinery/atmospherics/components/binary/passive_gate/update_icon_nopipes()
cut_overlays()
icon_state = "passgate_off-[set_overlay_offset(piping_layer)]"
if(on)
- add_overlay(getpipeimage(icon, "passgate_on-[set_overlay_offset(piping_layer)]"))
+ add_overlay(get_pipe_image(icon, "passgate_on-[set_overlay_offset(piping_layer)]"))
/obj/machinery/atmospherics/components/binary/passive_gate/process_atmos()
..()
@@ -65,28 +57,6 @@ Passive gate is similar to the regular pump except:
if(air1.release_gas_to(air2, target_pressure))
update_parents()
-//Radio remote control
-
-/obj/machinery/atmospherics/components/binary/passive_gate/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- if(frequency)
- radio_connection = SSradio.add_object(src, frequency, filter = RADIO_ATMOSIA)
-
-/obj/machinery/atmospherics/components/binary/passive_gate/proc/broadcast_status()
- if(!radio_connection)
- return
-
- var/datum/signal/signal = new(list(
- "tag" = id,
- "device" = "AGP",
- "power" = on,
- "target_output" = target_pressure,
- "sigtype" = "status"
- ))
- radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
-
-
/obj/machinery/atmospherics/components/binary/passive_gate/ui_state(mob/user)
return GLOB.default_state
@@ -125,37 +95,6 @@ Passive gate is similar to the regular pump except:
if(.)
update_icon()
-/obj/machinery/atmospherics/components/binary/passive_gate/atmosinit()
- ..()
- if(frequency)
- set_frequency(frequency)
-
-/obj/machinery/atmospherics/components/binary/passive_gate/receive_signal(datum/signal/signal)
- if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
- return
-
- var/old_on = on //for logging
-
- if("power" in signal.data)
- on = text2num(signal.data["power"])
-
- if("power_toggle" in signal.data)
- on = !on
-
- if("set_output_pressure" in signal.data)
- target_pressure = clamp(text2num(signal.data["set_output_pressure"]),0,ONE_ATMOSPHERE*100)
-
- if(on != old_on)
- investigate_log("was turned [on ? "on" : "off"] by a remote signal", INVESTIGATE_ATMOS)
-
- if("status" in signal.data)
- broadcast_status()
- return
-
- broadcast_status()
- update_icon()
- ui_update()
-
/obj/machinery/atmospherics/components/binary/passive_gate/can_unwrench(mob/user)
. = ..()
if(. && on)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm b/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm
index c136cb3b746b5..b80087ce150b6 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/pressure_valve.dm
@@ -8,12 +8,6 @@
//Amount of pressure needed before the valve for it to open
var/target_pressure = ONE_ATMOSPHERE
- //Frequency for radio signaling
- var/frequency = 0
- //ID for radio signaling
- var/id = null
- //Connection to the radio processing
- var/datum/radio_frequency/radio_connection
//Check if the gas is moving from one pipenet to the other
var/is_gas_flowing = FALSE
@@ -35,12 +29,6 @@
update_icon()
return ..()
-/obj/machinery/atmospherics/components/binary/pressure_valve/Destroy()
- SSradio.remove_object(src,frequency)
- if(radio_connection)
- radio_connection = null
- return ..()
-
/obj/machinery/atmospherics/components/binary/pressure_valve/update_icon_nopipes()
if(on && is_operational)
if(is_gas_flowing)
@@ -66,25 +54,6 @@
is_gas_flowing = FALSE
update_icon_nopipes()
-/obj/machinery/atmospherics/components/binary/pressure_valve/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- if(frequency)
- radio_connection = SSradio.add_object(src, frequency, filter = RADIO_ATMOSIA)
-
-/obj/machinery/atmospherics/components/binary/pressure_valve/proc/broadcast_status()
- if(!radio_connection)
- return
-
- var/datum/signal/signal = new(list(
- "tag" = id,
- "device" = "AGP",
- "power" = on,
- "target_output" = target_pressure,
- "sigtype" = "status"
- ))
- radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
-
/obj/machinery/atmospherics/components/binary/pressure_valve/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
@@ -119,36 +88,6 @@
investigate_log("was set to [target_pressure] kPa by [key_name(usr)]", INVESTIGATE_ATMOS)
update_icon()
-/obj/machinery/atmospherics/components/binary/pressure_valve/atmosinit()
- . = ..()
- if(frequency)
- set_frequency(frequency)
-
-/obj/machinery/atmospherics/components/binary/pressure_valve/receive_signal(datum/signal/signal)
- if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
- return
-
- var/old_on = on //for logging
-
- if("power" in signal.data)
- on = text2num(signal.data["power"])
-
- if("power_toggle" in signal.data)
- on = !on
-
- if("set_output_pressure" in signal.data)
- target_pressure = clamp(text2num(signal.data["set_output_pressure"]),0,ONE_ATMOSPHERE*100)
-
- if(on != old_on)
- investigate_log("was turned [on ? "on" : "off"] by a remote signal", INVESTIGATE_ATMOS)
-
- if("status" in signal.data)
- broadcast_status()
- return
-
- broadcast_status()
- update_icon()
-
/obj/machinery/atmospherics/components/binary/pressure_valve/can_unwrench(mob/user)
. = ..()
if(. && on && is_operational)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
index 7496fa99b06d6..c0fbc3ba4afc6 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/pump.dm
@@ -20,10 +20,6 @@
var/target_pressure = ONE_ATMOSPHERE
- var/frequency = 0
- var/id = null
- var/datum/radio_frequency/radio_connection
-
construction_type = /obj/item/pipe/directional
pipe_state = "pump"
@@ -48,60 +44,20 @@
ui_update()
return
-
-/obj/machinery/atmospherics/components/binary/pump/Destroy()
- SSradio.remove_object(src,frequency)
- if(radio_connection)
- radio_connection = null
- return ..()
-
/obj/machinery/atmospherics/components/binary/pump/update_icon_nopipes()
icon_state = "pump_[on && is_operational ? "on" : "off"]-[set_overlay_offset(piping_layer)]"
/obj/machinery/atmospherics/components/binary/pump/process_atmos()
-// ..()
if(!on || !is_operational)
return
- var/datum/gas_mixture/air1 = airs[1]
- var/datum/gas_mixture/air2 = airs[2]
- var/output_starting_pressure = air2.return_pressure()
- if((target_pressure - output_starting_pressure) < 0.01)
- //No need to pump gas if target is already reached!
- return
- //Calculate necessary moles to transfer using PV=nRT
- if((air1.total_moles() > 0) && (air1.return_temperature()>0))
- var/pressure_delta = target_pressure - output_starting_pressure
- var/transfer_moles = pressure_delta*air2.return_volume()/(air1.return_temperature() * R_IDEAL_GAS_EQUATION)
- air1.transfer_to(air2,transfer_moles)
+ var/datum/gas_mixture/input_air = airs[1]
+ var/datum/gas_mixture/output_air = airs[2]
+ var/datum/gas_mixture/output_pipenet_air = parents[2].air
+ if(input_air.pump_gas_to(output_air, target_pressure, output_pipenet_air = output_pipenet_air))
update_parents()
-/obj/machinery/atmospherics/components/binary/pump/proc/set_on(active)
- on = active
- SEND_SIGNAL(src, COMSIG_PUMP_SET_ON, on)
-
-//Radio remote control
-/obj/machinery/atmospherics/components/binary/pump/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- if(frequency)
- radio_connection = SSradio.add_object(src, frequency, filter = RADIO_ATMOSIA)
-
-/obj/machinery/atmospherics/components/binary/pump/proc/broadcast_status()
- if(!radio_connection)
- return
-
- var/datum/signal/signal = new(list(
- "tag" = id,
- "device" = "AGP",
- "power" = on,
- "target_output" = target_pressure,
- "sigtype" = "status"
- ))
- radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
-
-
/obj/machinery/atmospherics/components/binary/pump/ui_state(mob/user)
return GLOB.default_state
@@ -140,37 +96,6 @@
if(.)
update_icon()
-/obj/machinery/atmospherics/components/binary/pump/atmosinit()
- ..()
- if(frequency)
- set_frequency(frequency)
-
-/obj/machinery/atmospherics/components/binary/pump/receive_signal(datum/signal/signal)
- if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
- return
-
- var/old_on = on //for logging
-
- if("power" in signal.data)
- set_on(text2num(signal.data["power"]))
-
- if("power_toggle" in signal.data)
- set_on(!on)
-
- if("set_output_pressure" in signal.data)
- target_pressure = clamp(text2num(signal.data["set_output_pressure"]),0,ONE_ATMOSPHERE*50)
-
- if(on != old_on)
- investigate_log("was turned [on ? "on" : "off"] by a remote signal", INVESTIGATE_ATMOS)
-
- if("status" in signal.data)
- broadcast_status()
- return
-
- broadcast_status()
- update_icon()
- ui_update()
-
/obj/machinery/atmospherics/components/binary/pump/can_unwrench(mob/user)
. = ..()
if(. && on && is_operational)
@@ -253,10 +178,10 @@
. = ..()
if(istype(shell, /obj/machinery/atmospherics/components/binary/pump))
connected_pump = shell
- RegisterSignal(connected_pump, COMSIG_PUMP_SET_ON, PROC_REF(handle_pump_activation))
+ RegisterSignal(connected_pump, COMSIG_ATMOS_MACHINE_SET_ON, PROC_REF(handle_pump_activation))
/obj/item/circuit_component/atmos_pump/unregister_usb_parent(atom/movable/shell)
- UnregisterSignal(connected_pump, COMSIG_PUMP_SET_ON)
+ UnregisterSignal(connected_pump, COMSIG_ATMOS_MACHINE_SET_ON)
connected_pump = null
return ..()
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm
index 18da76771dc01..6f0787b1753de 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/temperature_pump.dm
@@ -51,14 +51,15 @@
var/input_capacity = remove_input.heat_capacity()
var/output_capacity = air_output.heat_capacity()
- var/cooling_heat_amount = (heat_transfer_rate * 0.01) * coolant_temperature_delta * (input_capacity * output_capacity / (input_capacity + output_capacity))
- remove_input.set_temperature(max(remove_input.return_temperature() - (cooling_heat_amount / input_capacity), TCMB))
- remove_output.set_temperature(max(remove_output.return_temperature() + (cooling_heat_amount / output_capacity), TCMB))
+ var/cooling_heat_amount = (heat_transfer_rate * 0.01) * CALCULATE_CONDUCTION_ENERGY(coolant_temperature_delta, output_capacity, input_capacity)
+ remove_output.temperature = (max(remove_output.return_temperature() + (cooling_heat_amount / output_capacity), TCMB))
+ remove_input.temperature = max(remove_input.temperature - (cooling_heat_amount / input_capacity), TCMB)
+ update_parents()
+
air_input.merge(remove_input)
air_output.merge(remove_output)
- update_parents()
/obj/machinery/atmospherics/components/binary/temperature_pump/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/valve.dm b/code/modules/atmospherics/machinery/components/binary_devices/valve.dm
index d751f7f9dad35..3e31070b06115 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/valve.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/valve.dm
@@ -12,7 +12,8 @@ It's like a regular ol' straight pipe, but you can turn it on and off.
shift_underlay_only = FALSE
interaction_flags_machine = INTERACT_MACHINE_OFFLINE | INTERACT_MACHINE_OPEN //Intentionally no allow_silicon flag
- pipe_flags = PIPING_CARDINAL_AUTONORMALIZE
+ pipe_flags = PIPING_CARDINAL_AUTONORMALIZE | PIPING_BRIDGE
+ custom_reconcilation = TRUE
var/frequency = 0
var/id = null
@@ -24,16 +25,6 @@ It's like a regular ol' straight pipe, but you can turn it on and off.
var/switching = FALSE
-/obj/machinery/atmospherics/components/binary/valve/Destroy()
- //Should only happen on extreme circumstances
- if(on)
- //Let's give presumably now-severed pipenets a chance to scramble for what's happening at next SSair fire()
- if(parents[1])
- parents[1].update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
- if(parents[2])
- parents[2].update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
- . = ..()
-
/obj/machinery/atmospherics/components/binary/valve/update_icon_nopipes(animation = FALSE)
normalize_cardinal_directions()
if(animation)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm
index 638527e13f1cf..0e47538d93b03 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/volume_pump.dm
@@ -21,10 +21,6 @@
var/transfer_rate = MAX_TRANSFER_RATE
var/overclocked = FALSE
- var/frequency = 0
- var/id = null
- var/datum/radio_frequency/radio_connection
-
construction_type = /obj/item/pipe/directional
pipe_state = "volumepump"
@@ -46,15 +42,10 @@
ui_update()
return
-/obj/machinery/atmospherics/components/binary/volume_pump/Destroy()
- SSradio.remove_object(src,frequency)
- return ..()
-
/obj/machinery/atmospherics/components/binary/volume_pump/update_icon_nopipes()
icon_state = "volpump_[on && is_operational ? "on" : "off"]-[set_overlay_offset(piping_layer)]"
/obj/machinery/atmospherics/components/binary/volume_pump/process_atmos()
-// ..()
if(!on || !is_operational)
return
@@ -72,15 +63,21 @@
if(overclocked && (output_starting_pressure-input_starting_pressure > 1000))//Overclocked pumps can only force gas a certain amount.
return
+
+ var/transfer_ratio = transfer_rate / air1.volume
+
+ var/datum/gas_mixture/removed = air1.remove_ratio(transfer_ratio)
+
+ if(!removed.total_moles())
+ return
+
if(overclocked)//Some of the gas from the mixture leaks to the environment when overclocked
var/turf/open/T = loc
if(istype(T))
- var/datum/gas_mixture/leaked = air1.remove_ratio(VOLUME_PUMP_LEAK_AMOUNT)
+ var/datum/gas_mixture/leaked = removed.remove_ratio(VOLUME_PUMP_LEAK_AMOUNT)
T.assume_air(leaked)
- T.air_update_turf()
- var/transfer_ratio = transfer_rate / air1.return_volume()
- air1.transfer_ratio_to(air2,transfer_ratio)
+ air2.merge(removed)
update_parents()
@@ -89,26 +86,6 @@
if(overclocked)
. += "Its warning light is on[on ? " and it's spewing gas!" : "."]"
-/obj/machinery/atmospherics/components/binary/volume_pump/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- if(frequency)
- radio_connection = SSradio.add_object(src, frequency)
-
-/obj/machinery/atmospherics/components/binary/volume_pump/proc/broadcast_status()
- if(!radio_connection)
- return
-
- var/datum/signal/signal = new(list(
- "tag" = id,
- "device" = "APV",
- "power" = on,
- "transfer_rate" = transfer_rate,
- "sigtype" = "status"
- ))
- radio_connection.post_signal(src, signal)
-
-
/obj/machinery/atmospherics/components/binary/volume_pump/ui_state(mob/user)
return GLOB.default_state
@@ -125,11 +102,6 @@
data["max_rate"] = round(MAX_TRANSFER_RATE)
return data
-/obj/machinery/atmospherics/components/binary/volume_pump/atmosinit()
- ..()
-
- set_frequency(frequency)
-
/obj/machinery/atmospherics/components/binary/volume_pump/ui_act(action, params)
if(..())
return
@@ -152,33 +124,6 @@
if(.)
update_icon()
-/obj/machinery/atmospherics/components/binary/volume_pump/receive_signal(datum/signal/signal)
- if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
- return
-
- var/old_on = on //for logging
-
- if("power" in signal.data)
- on = text2num(signal.data["power"])
-
- if("power_toggle" in signal.data)
- on = !on
-
- if("set_transfer_rate" in signal.data)
- var/datum/gas_mixture/air1 = airs[1]
- transfer_rate = clamp(text2num(signal.data["set_transfer_rate"]),0,air1.return_volume())
-
- if(on != old_on)
- investigate_log("was turned [on ? "on" : "off"] by a remote signal", INVESTIGATE_ATMOS)
-
- if("status" in signal.data)
- broadcast_status()
- return //do not update_icon
-
- broadcast_status()
- update_icon()
- ui_update()
-
/obj/machinery/atmospherics/components/binary/volume_pump/can_unwrench(mob/user)
. = ..()
if(. && on && is_operational)
diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm
index 24b28222afd05..71f852d907d81 100644
--- a/code/modules/atmospherics/machinery/components/components_base.dm
+++ b/code/modules/atmospherics/machinery/components/components_base.dm
@@ -3,13 +3,20 @@
/obj/machinery/atmospherics/components
hide = FALSE
-
- var/welded = FALSE //Used on pumps and scrubbers
+ ///Is the component welded?
+ var/welded = FALSE
+ ///Should the component should show the pipe underneath it?
var/showpipe = TRUE
- var/shift_underlay_only = TRUE //Layering only shifts underlay?
-
+ ///When the component is on a non default layer should we shift everything? Or just the underlay pipe
+ var/shift_underlay_only = TRUE
+ ///Stores the component pipeline
var/list/datum/pipeline/parents
+ ///If this is queued for a rebuild this var signifies whether parents should be updated after it's done
+ var/update_parents_after_rebuild = FALSE
+ ///Stores the component gas mixture
var/list/datum/gas_mixture/airs
+ ///Handles whether the custom reconcilation handling should be used
+ var/custom_reconcilation = FALSE
/obj/machinery/atmospherics/components/New()
parents = new(device_type)
@@ -18,12 +25,9 @@
..()
for(var/i in 1 to device_type)
- var/datum/gas_mixture/A = new(200)
- airs[i] = A
-
-/obj/machinery/atmospherics/components/examine(mob/user)
- . = ..()
- . += "[src] is on layer [piping_layer]."
+ var/datum/gas_mixture/component_mixture = new
+ component_mixture.volume = 200
+ airs[i] = component_mixture
/obj/machinery/atmospherics/components/Initialize(mapload)
. = ..()
@@ -33,150 +37,206 @@
// Iconnery
+/**
+ * Called by update_icon(), used individually by each component to determine the icon state without the pipe in consideration
+ */
/obj/machinery/atmospherics/components/proc/update_icon_nopipes()
return
-/obj/machinery/atmospherics/components/proc/hide_pipe(datum/source, underfloor_accessibility)
- SIGNAL_HANDLER
- showpipe = !!underfloor_accessibility
- update_icon()
+/**
+ * Called in Initialize(), set the showpipe var to true or false depending on the situation, calls update_icon()
+ */
+/obj/machinery/atmospherics/components/proc/hide_pipe(datum/source, covered)
+ showpipe = !covered
+ update_appearance()
/obj/machinery/atmospherics/components/update_icon()
update_icon_nopipes()
underlays.Cut()
- plane = showpipe ? GAME_PLANE : FLOOR_PLANE
+ color = null
if(!showpipe)
- return
+ return ..()
+ if(pipe_flags & PIPING_DISTRO_AND_WASTE_LAYERS)
+ return ..()
var/connected = 0 //Direction bitset
+ var/underlay_pipe_layer = shift_underlay_only ? piping_layer : 3
+
for(var/i in 1 to device_type) //adds intact pieces
- if(nodes[i])
- var/obj/machinery/atmospherics/node = nodes[i]
- var/image/img = get_pipe_underlay("pipe_intact", get_dir(src, node), node.pipe_color)
- underlays += img
- connected |= img.dir
+ if(!nodes[i])
+ continue
+ var/obj/machinery/atmospherics/node = nodes[i]
+ var/node_dir = get_dir(src, node)
+ var/mutable_appearance/pipe_appearance = mutable_appearance('icons/obj/atmospherics/pipes/pipe_underlays.dmi', "intact_[node_dir]_[underlay_pipe_layer]")
+ pipe_appearance.color = node.pipe_color
+ underlays += pipe_appearance
+ connected |= node_dir
for(var/direction in GLOB.cardinals)
if((initialize_directions & direction) && !(connected & direction))
- underlays += get_pipe_underlay("pipe_exposed", direction)
+ var/mutable_appearance/pipe_appearance = mutable_appearance('icons/obj/atmospherics/pipes/pipe_underlays.dmi', "exposed_[direction]_[underlay_pipe_layer]")
+ pipe_appearance.color = pipe_color
+ underlays += pipe_appearance
if(!shift_underlay_only)
PIPING_LAYER_SHIFT(src, piping_layer)
+ return ..()
+/**
+ * Called by update_icon() when showpipe is TRUE, set the image for the underlay pipe
+ * Arguments:
+ * * -state: icon_state of the selected pipe
+ * * -dir: direction of the pipe
+ * * -color: color of the pipe
+ */
/obj/machinery/atmospherics/components/proc/get_pipe_underlay(state, dir, color = null)
if(color)
- . = getpipeimage('icons/obj/atmospherics/components/binary_devices.dmi', state, dir, color, piping_layer = shift_underlay_only ? piping_layer : 3)
+ . = get_pipe_image('icons/obj/atmospherics/components/binary_devices.dmi', state, dir, color, piping_layer = shift_underlay_only ? piping_layer : 3)
else
- . = getpipeimage('icons/obj/atmospherics/components/binary_devices.dmi', state, dir, piping_layer = shift_underlay_only ? piping_layer : 3)
+ . = get_pipe_image('icons/obj/atmospherics/components/binary_devices.dmi', state, dir, piping_layer = shift_underlay_only ? piping_layer : 3)
// Pipenet stuff; housekeeping
-/obj/machinery/atmospherics/components/nullifyNode(i)
- // Every node has a parent pipeline and an air associated with it, but we need to accomdate for edge cases like init dir cache building...
+/obj/machinery/atmospherics/components/nullify_node(i)
if(parents[i])
- nullifyPipenet(parents[i])
- if(airs[i])
- QDEL_NULL(airs[i])
- ..()
+ nullify_pipenet(parents[i])
+ QDEL_NULL(airs[i])
+ return ..()
/obj/machinery/atmospherics/components/on_construction()
- ..()
+ . = ..()
update_parents()
-/obj/machinery/atmospherics/components/build_network()
- for(var/i in 1 to device_type)
- if(QDELETED(parents[i]))
- parents[i] = new /datum/pipeline()
- var/datum/pipeline/P = parents[i]
- P.build_pipeline(src)
+/obj/machinery/atmospherics/components/rebuild_pipes()
+ . = ..()
+ if(update_parents_after_rebuild)
+ update_parents()
-/obj/machinery/atmospherics/components/proc/nullifyPipenet(datum/pipeline/reference)
+/obj/machinery/atmospherics/components/get_rebuild_targets()
+ var/list/to_return = list()
+ for(var/i in 1 to device_type)
+ if(parents[i])
+ continue
+ parents[i] = new /datum/pipeline()
+ to_return += parents[i]
+ return to_return
+
+/**
+ * Called by nullify_node(), used to remove the pipeline the component is attached to
+ * Arguments:
+ * * -reference: the pipeline the component is attached to
+ */
+/obj/machinery/atmospherics/components/proc/nullify_pipenet(datum/pipeline/reference)
if(!reference)
- CRASH("nullifyPipenet(null) called by [type] on [COORD(src)]")
- var/i = parents.Find(reference)
- reference.other_airs -= airs[i]
- reference.other_atmosmch -= src
+ CRASH("nullify_pipenet(null) called by [type] on [COORD(src)]")
+
+ for (var/i in 1 to length(parents))
+ if (parents[i] == reference)
+ reference.other_airs -= airs[i] // Disconnects from the pipeline side
+ parents[i] = null // Disconnects from the machinery side.
+
+ reference.other_atmos_machines -= src
+ if(custom_reconcilation)
+ reference.require_custom_reconcilation -= src
+
/**
* We explicitly qdel pipeline when this particular pipeline
* is projected to have no member and cause GC problems.
* We have to do this because components don't qdel pipelines
- * while pipes must and will happily wreck and rebuild everything again
- * every time they are qdeleted.
+ * while pipes must and will happily wreck and rebuild everything
+ * again every time they are qdeleted.
*/
- if(!(reference.other_atmosmch.len || reference.members.len || QDESTROYING(reference)))
+
+ if(!length(reference.other_atmos_machines) && !length(reference.members))
+ if(QDESTROYING(reference))
+ CRASH("nullify_pipenet() called on qdeleting [reference]")
qdel(reference)
- parents[i] = null
-// We should return every air sharing a parent
-/obj/machinery/atmospherics/components/returnPipenetAir(datum/pipeline/reference)
- for(var/i in 1 to device_type)
- if(parents[i] == reference)
- if(.)
- if(!islist(.))
- . = list(.)
- . += airs[i]
- else
- . = airs[i]
+/obj/machinery/atmospherics/components/return_pipenet_airs(datum/pipeline/reference)
+ var/list/returned_air = list()
+
+ for (var/i in 1 to parents.len)
+ if (parents[i] == reference)
+ returned_air += airs[i]
+ return returned_air
/obj/machinery/atmospherics/components/pipeline_expansion(datum/pipeline/reference)
if(reference)
return list(nodes[parents.Find(reference)])
return ..()
-/obj/machinery/atmospherics/components/setPipenet(datum/pipeline/reference, obj/machinery/atmospherics/A)
- parents[nodes.Find(A)] = reference
+/obj/machinery/atmospherics/components/set_pipenet(datum/pipeline/reference, obj/machinery/target_component)
+ parents[nodes.Find(target_component)] = reference
-/obj/machinery/atmospherics/components/returnPipenet(obj/machinery/atmospherics/A = nodes[1]) //returns parents[1] if called without argument
- return parents[nodes.Find(A)]
+/obj/machinery/atmospherics/components/return_pipenet(obj/machinery/atmospherics/target_component = nodes[1]) //returns parents[1] if called without argument
+ return parents[nodes.Find(target_component)]
-/obj/machinery/atmospherics/components/replacePipenet(datum/pipeline/Old, datum/pipeline/New)
+/obj/machinery/atmospherics/components/replace_pipenet(datum/pipeline/Old, datum/pipeline/New)
parents[parents.Find(Old)] = New
-/obj/machinery/atmospherics/components/unsafe_pressure_release(var/mob/user, var/pressures)
- ..()
+/obj/machinery/atmospherics/components/unsafe_pressure_release(mob/user, pressures)
+ . = ..()
var/turf/T = get_turf(src)
- if(T)
- //Remove the gas from airs and assume it
- var/datum/gas_mixture/environment = T.return_air()
- var/lost = null
- var/times_lost = 0
- for(var/i in 1 to device_type)
- var/datum/gas_mixture/air = airs[i]
- lost += pressures*environment.return_volume()/(air.return_temperature() * R_IDEAL_GAS_EQUATION)
- times_lost++
- var/shared_loss = lost/times_lost
-
- for(var/i in 1 to device_type)
- var/datum/gas_mixture/air = airs[i]
- T.assume_air_moles(air, shared_loss)
-
-/obj/machinery/atmospherics/components/proc/safe_input(var/title, var/text, var/default_set)
- var/new_value = input(usr,text,title,default_set) as num
- if(usr.canUseTopic(src))
- return new_value
- return default_set
+ if(!T)
+ return
+ //Remove the gas from airs and assume it
+ var/datum/gas_mixture/environment = T.return_air()
+ var/lost = null
+ var/times_lost = 0
+ for(var/i in 1 to device_type)
+ var/datum/gas_mixture/air = airs[i]
+ lost += pressures*environment.volume/(air.temperature * R_IDEAL_GAS_EQUATION)
+ times_lost++
+ var/shared_loss = lost/times_lost
+
+ var/datum/gas_mixture/to_release
+ for(var/i in 1 to device_type)
+ var/datum/gas_mixture/air = airs[i]
+ if(!to_release)
+ to_release = air.remove(shared_loss)
+ continue
+ to_release.merge(air.remove(shared_loss))
+ T.assume_air(to_release)
// Helpers
+/**
+ * Called in most atmos processes and gas handling situations, update the parents pipelines of the devices connected to the source component
+ * This way gases won't get stuck
+ */
/obj/machinery/atmospherics/components/proc/update_parents()
+ if(!SSair.initialized)
+ return
+ if(rebuilding)
+ update_parents_after_rebuild = TRUE
+ return
for(var/i in 1 to device_type)
var/datum/pipeline/parent = parents[i]
if(!parent)
- //WARNING("Component is missing a pipenet! Rebuilding...")
- //At pre-SSair_rebuild_pipenets times, not having a parent wasn't supposed to happen
+ WARNING("Component is missing a pipenet! Rebuilding...")
SSair.add_to_rebuild_queue(src)
- continue
- parent.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
+ else
+ parent.update = TRUE
-/obj/machinery/atmospherics/components/returnPipenets()
+/obj/machinery/atmospherics/components/return_pipenets()
. = list()
for(var/i in 1 to device_type)
- . += returnPipenet(nodes[i])
+ . += return_pipenet(nodes[i])
+
+/// When this machine is in a pipenet that is reconciling airs, this proc can add pipelines to the calculation.
+/// Can be either a list of pipenets or a single pipenet.
+/obj/machinery/atmospherics/components/proc/return_pipenets_for_reconcilation(datum/pipeline/requester)
+ return list()
+
+/// When this machine is in a pipenet that is reconciling airs, this proc can add airs to the calculation.
+/// Can be either a list of airs or a single air mix.
+/obj/machinery/atmospherics/components/proc/return_airs_for_reconcilation(datum/pipeline/requester)
+ return list()
// UI Stuff
@@ -190,3 +250,136 @@
/obj/machinery/atmospherics/components/return_analyzable_air()
return airs
+
+/obj/machinery/atmospherics/components/paint(paint_color)
+ if(paintable)
+ add_atom_colour(paint_color, FIXED_COLOUR_PRIORITY)
+ pipe_color = paint_color
+ update_node_icon()
+ return paintable
+
+/**
+ * Handles machinery deconstruction and unsafe pressure release
+ */
+/obj/machinery/atmospherics/components/proc/crowbar_deconstruction_act(mob/living/user, obj/item/tool, internal_pressure = 0)
+ if(!panel_open)
+ balloon_alert(user, "open panel!")
+ return TRUE
+
+ var/unsafe_wrenching = FALSE
+ var/filled_pipe = FALSE
+ var/datum/gas_mixture/environment_air = loc.return_air()
+
+ for(var/i in 1 to device_type)
+ var/datum/gas_mixture/inside_air = airs[i]
+ if(inside_air.total_moles() > 0 || internal_pressure)
+ filled_pipe = TRUE
+ if(!nodes[i] || (istype(nodes[i], /obj/machinery/atmospherics/components/unary/portables_connector) && !portable_device_connected(i)))
+ internal_pressure = internal_pressure > airs[i].return_pressure() ? internal_pressure : airs[i].return_pressure()
+
+ if(!filled_pipe)
+ default_deconstruction_crowbar(tool)
+ return TRUE
+
+ to_chat(user, "You begin to unfasten \the [src]...")
+
+ internal_pressure -= environment_air.return_pressure()
+
+ if(internal_pressure > 2 * ONE_ATMOSPHERE)
+ to_chat(user, "As you begin deconstructing \the [src] a gush of air blows in your face... maybe you should reconsider?")
+ unsafe_wrenching = TRUE
+
+ if(!do_after(user, 2 SECONDS, src))
+ return
+ if(unsafe_wrenching)
+ unsafe_pressure_release(user, internal_pressure)
+ tool.play_tool_sound(src, 50)
+ deconstruct(TRUE)
+ return TRUE
+
+/obj/machinery/atmospherics/components/default_change_direction_wrench(mob/user, obj/item/I)
+ . = ..()
+ if(!.)
+ return FALSE
+ set_init_directions()
+ reconnect_nodes()
+ return TRUE
+
+/obj/machinery/atmospherics/components/proc/reconnect_nodes()
+ for(var/i in 1 to device_type)
+ var/obj/machinery/atmospherics/node = nodes[i]
+ if(node)
+ if(src in node.nodes)
+ node.disconnect(src)
+ nodes[i] = null
+ if(parents[i])
+ nullify_pipenet(parents[i])
+ for(var/i in 1 to device_type)
+ var/obj/machinery/atmospherics/node = nodes[i]
+ atmos_init()
+ node = nodes[i]
+ if(node)
+ node.atmos_init()
+ node.add_member(src)
+ update_parents()
+ SSair.add_to_rebuild_queue(src)
+
+/**
+ * Disconnects all nodes from ourselves, remove us from the node's nodes.
+ * Nullify our parent pipenet
+ */
+/obj/machinery/atmospherics/components/proc/disconnect_nodes()
+ for(var/i in 1 to device_type)
+ var/obj/machinery/atmospherics/node = nodes[i]
+ if(node)
+ if(src in node.nodes) //Only if it's actually connected. On-pipe version would is one-sided.
+ node.disconnect(src)
+ nodes[i] = null
+ if(parents[i])
+ nullify_pipenet(parents[i])
+
+/**
+ * Connects all nodes to ourselves, add us to the node's nodes.
+ * Calls atmos_init() on the node and on us.
+ */
+/obj/machinery/atmospherics/components/proc/connect_nodes()
+ atmos_init()
+ for(var/i in 1 to device_type)
+ var/obj/machinery/atmospherics/node = nodes[i]
+ if(node)
+ node.atmos_init()
+ node.add_member(src)
+ SSair.add_to_rebuild_queue(src)
+
+/**
+ * Easy way to toggle nodes connection and disconnection.
+ *
+ * Arguments:
+ * * disconnect - if TRUE, disconnects all nodes. If FALSE, connects all nodes.
+ */
+/obj/machinery/atmospherics/components/proc/change_nodes_connection(disconnect)
+ if(disconnect)
+ disconnect_nodes()
+ return
+ connect_nodes()
+
+/obj/machinery/atmospherics/components/update_layer()
+ layer = (showpipe ? initial(layer) : ABOVE_OPEN_TURF_LAYER) + (piping_layer - PIPING_LAYER_DEFAULT) * PIPING_LAYER_LCHANGE + (GLOB.pipe_colors_ordered[pipe_color] * 0.001)
+
+/**
+ * Handles air relocation to the pipenet/environment
+ */
+/obj/machinery/atmospherics/components/proc/relocate_airs(datum/gas_mixture/to_release)
+ var/turf/local_turf = get_turf(src)
+ for(var/i in 1 to device_type)
+ var/datum/gas_mixture/air = airs[i]
+ if(!nodes[i] || (istype(nodes[i], /obj/machinery/atmospherics/components/unary/portables_connector) && !portable_device_connected(i)))
+ if(!to_release)
+ to_release = air
+ continue
+ to_release.merge(air)
+ continue
+ var/datum/gas_mixture/parents_air = parents[i].air
+ parents_air.merge(air)
+ if(to_release)
+ local_turf.assume_air(to_release)
diff --git a/code/modules/atmospherics/machinery/components/tank.dm b/code/modules/atmospherics/machinery/components/tank.dm
new file mode 100644
index 0000000000000..7ddbeedbd30f8
--- /dev/null
+++ b/code/modules/atmospherics/machinery/components/tank.dm
@@ -0,0 +1,148 @@
+/obj/machinery/atmospherics/components/tank
+ icon = 'icons/obj/atmospherics/pipes/pressure_tank.dmi'
+ icon_state = "generic"
+
+ name = "pressure tank"
+ desc = "A large vessel containing pressurized gas."
+
+ max_integrity = 800
+ density = TRUE
+ layer = ABOVE_WINDOW_LAYER
+
+ pipe_flags = PIPING_ONE_PER_TURF
+ device_type = QUATERNARY
+ initialize_directions = NONE
+ custom_reconcilation = TRUE
+
+ /// The volume of the gas mixture
+ var/volume = 2500 //in liters
+ /// The max pressure of the gas mixture before damaging the tank
+ var/max_pressure = 46000
+ /// The typepath of the gas this tank should be filled with.
+ var/gas_type = null
+
+ ///Reference to the gas mix inside the tank
+ var/datum/gas_mixture/air_contents
+
+
+/obj/machinery/atmospherics/components/tank/Initialize(mapload)
+ . = ..()
+ air_contents = new
+ air_contents.temperature = T20C
+ air_contents.volume = volume
+ if(gas_type)
+ fill_to_pressure(gas_type)
+
+ name = "[name] ([GLOB.meta_gas_info[gas_type][META_GAS_NAME]])"
+ set_piping_layer(piping_layer)
+
+ // Mapped in tanks should automatically connect to adjacent pipenets in the direction set in dir
+ if(mapload)
+ initialize_directions = dir
+
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/machinery/atmospherics/components/tank/wrench_act(mob/living/user, obj/item/item)
+ . = TRUE
+ var/new_dir = get_dir(src, user)
+
+ if(new_dir in GLOB.diagonals)
+ return
+
+ item.play_tool_sound(src, 10)
+ if(!item.use_tool(src, user, 3 SECONDS))
+ return
+
+ toggle_side_port(new_dir)
+
+ item.play_tool_sound(src, 50)
+
+/// Recalculates pressure based on the current max integrity compared to original
+/obj/machinery/atmospherics/components/tank/proc/refresh_pressure_limit()
+ var/max_pressure_multiplier = max_integrity / initial(max_integrity)
+ max_pressure = max_pressure_multiplier * initial(max_pressure)
+
+/// Fills the tank to the maximum safe pressure.
+/// Safety margin is a multiplier for the cap for the purpose of this proc so it doesn't have to be filled completely.
+/obj/machinery/atmospherics/components/tank/proc/fill_to_pressure(gastype, safety_margin = 0.5)
+ var/pressure_limit = max_pressure * safety_margin
+
+ var/moles_to_add = (pressure_limit * air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ air_contents.assert_gas(gastype)
+ air_contents.gases[gastype][MOLES] += moles_to_add
+ air_contents.archive()
+
+/obj/machinery/atmospherics/components/tank/process_atmos()
+ if(air_contents.react(src))
+ update_parents()
+
+ if(air_contents.return_pressure() > max_pressure)
+ take_damage(0.1, BRUTE, sound_effect = FALSE)
+ if(prob(40))
+ playsound(src, 'sound/effects/spray3.ogg', 30, vary = TRUE)
+
+///////////////////////////////////////////////////////////////////
+// Pipenet stuff
+
+/obj/machinery/atmospherics/components/tank/return_analyzable_air()
+ return air_contents
+
+/obj/machinery/atmospherics/components/tank/return_airs_for_reconcilation(datum/pipeline/requester)
+ . = ..()
+ if(!air_contents)
+ return
+ . += air_contents
+
+/obj/machinery/atmospherics/components/tank/proc/toggle_side_port(new_dir)
+ if(initialize_directions & new_dir)
+ initialize_directions &= ~new_dir
+ else
+ initialize_directions |= new_dir
+
+ for(var/i in 1 to length(nodes))
+ var/obj/machinery/atmospherics/components/node = nodes[i]
+ if(!node)
+ continue
+ if(src in node.nodes)
+ node.disconnect(src)
+ nodes[i] = null
+ if(parents[i])
+ nullify_pipenet(parents[i])
+
+ atmos_init()
+
+ for(var/obj/machinery/atmospherics/components/node as anything in nodes)
+ if(!node)
+ continue
+ node.atmos_init()
+ node.add_member(src)
+ SSair.add_to_rebuild_queue(src)
+
+ update_parents()
+
+////////////////////////////////////////////////////////////////////////////////////////
+
+/obj/machinery/atmospherics/components/tank/air
+ icon_state = "grey"
+ name = "pressure tank (Air)"
+
+/obj/machinery/atmospherics/components/tank/air/New()
+ ..()
+ var/datum/gas_mixture/air_contents = airs[1]
+ SET_MOLES(/datum/gas/oxygen, air_contents, 6*ONE_ATMOSPHERE*volume/(R_IDEAL_GAS_EQUATION*T20C) * O2STANDARD)
+ SET_MOLES(/datum/gas/nitrogen, air_contents, 6*ONE_ATMOSPHERE*volume/(R_IDEAL_GAS_EQUATION*T20C) * N2STANDARD)
+
+/obj/machinery/atmospherics/components/tank/carbon_dioxide
+ gas_type = /datum/gas/carbon_dioxide
+
+/obj/machinery/atmospherics/components/tank/plasma
+ icon_state = "orange"
+ gas_type = /datum/gas/plasma
+
+/obj/machinery/atmospherics/components/tank/oxygen
+ icon_state = "blue"
+ gas_type = /datum/gas/oxygen
+
+/obj/machinery/atmospherics/components/tank/nitrogen
+ icon_state = "red"
+ gas_type = /datum/gas/nitrogen
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
index 24ca6da28e61e..22dfea89b6b45 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm
@@ -8,9 +8,6 @@
can_unwrench = TRUE
var/transfer_rate = MAX_TRANSFER_RATE
var/filter_type = null
- var/frequency = 0
- var/datum/radio_frequency/radio_connection
-
construction_type = /obj/item/pipe/trinary/flippable
pipe_state = "filter"
@@ -30,38 +27,18 @@
ui_update()
return
-/obj/machinery/atmospherics/components/trinary/filter/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- if(frequency)
- radio_connection = SSradio.add_object(src, frequency, RADIO_ATMOSIA)
-
-/obj/machinery/atmospherics/components/trinary/filter/Destroy()
- SSradio.remove_object(src,frequency)
- return ..()
-
-/obj/machinery/atmospherics/components/trinary/filter/update_icon()
- cut_overlays()
+/obj/machinery/atmospherics/components/trinary/filter/update_overlays()
+ . = ..()
for(var/direction in GLOB.cardinals)
if(!(direction & initialize_directions))
continue
- var/obj/machinery/atmospherics/node = findConnecting(direction)
- var/image/cap
- if(node)
- cap = getpipeimage(icon, "cap", direction, node.pipe_color, piping_layer = piping_layer, trinary = TRUE)
- else
- cap = getpipeimage(icon, "cap", direction, piping_layer = piping_layer, trinary = TRUE)
-
- add_overlay(cap)
-
- return ..()
+ . += get_pipe_image(icon, "cap", direction, pipe_color, piping_layer, TRUE)
/obj/machinery/atmospherics/components/trinary/filter/update_icon_nopipes()
var/on_state = on && nodes[1] && nodes[2] && nodes[3] && is_operational
icon_state = "filter_[on_state ? "on" : "off"]-[set_overlay_offset(piping_layer)][flipped ? "_f" : ""]"
-
/obj/machinery/atmospherics/components/trinary/filter/process_atmos()
..()
if(!on || !(nodes[1] && nodes[2] && nodes[3]) || !is_operational)
@@ -69,7 +46,7 @@
//Early return
var/datum/gas_mixture/air1 = airs[1]
- if(!air1 || air1.return_temperature() <= 0)
+ if(!air1 || air1.temperature <= 0)
return
var/datum/gas_mixture/air2 = airs[2]
@@ -81,24 +58,40 @@
//No need to transfer if target is already full!
return
- var/transfer_ratio = transfer_rate / air1.return_volume()
+ var/transfer_ratio = transfer_rate / air1.volume
//Actually transfer the gas
if(transfer_ratio <= 0)
return
- if(filter_type && air2.return_pressure() <= 9000)
- air1.scrub_into(air2, transfer_ratio, list(filter_type))
- if(air3.return_pressure() <= 9000)
- air1.transfer_ratio_to(air3, transfer_ratio)
+ var/datum/gas_mixture/removed = air1.remove_ratio(transfer_ratio)
- update_parents()
+ if(!removed || !removed.total_moles())
+ return
-/obj/machinery/atmospherics/components/trinary/filter/atmosinit()
- set_frequency(frequency)
- return ..()
+ var/filtering = TRUE
+ if(!ispath(filter_type))
+ if(filter_type)
+ filter_type = gas_id2path(filter_type) //support for mappers so they don't need to type out paths
+ else
+ filtering = FALSE
+
+ if(filtering && removed.gases[filter_type])
+ var/datum/gas_mixture/filtered_out = new
+ filtered_out.temperature = removed.temperature
+ SET_MOLES(filter_type, filtered_out, removed.gases[filter_type][MOLES])
+
+ removed.gases[filter_type][MOLES] = 0
+ removed.garbage_collect()
+
+ var/datum/gas_mixture/target = (air2.return_pressure() < MAX_OUTPUT_PRESSURE ? air2 : air1) //if there's no room for the filtered gas; just leave it in air1
+ target.merge(filtered_out)
+
+ air3.merge(removed)
+
+ update_parents()
/obj/machinery/atmospherics/components/trinary/filter/ui_state(mob/user)
return GLOB.default_state
@@ -117,8 +110,8 @@
data["filter_types"] = list()
data["filter_types"] += list(list("name" = "Nothing", "id" = "", "selected" = !filter_type))
- for(var/id in GLOB.gas_data.ids)
- data["filter_types"] += list(list("name" = GLOB.gas_data.names[id], "id" = id, "selected" = (id == filter_type)))
+ for(var/id in subtypesof(/datum/gas))
+ data["filter_types"] += list(list("name" = GLOB.meta_gas_info[id][META_GAS_NAME], "id" = id, "selected" = (id == filter_type)))
return data
@@ -148,10 +141,10 @@
if("filter")
filter_type = null
var/filter_name = "nothing"
- var/gas = params["mode"]
- if(gas in GLOB.gas_data.names)
+ var/gas = gas_id2path(params["mode"])
+ if(gas in subtypesof(/datum/gas))
filter_type = gas
- filter_name = GLOB.gas_data.names[gas]
+ filter_name = GLOB.meta_gas_info[gas][META_GAS_NAME]
investigate_log("was set to filter [filter_name] by [key_name(usr)]", INVESTIGATE_ATMOS)
. = TRUE
if(.)
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
index cbd612de38a2b..a787314f97dbd 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/mixer.dm
@@ -34,22 +34,13 @@
ui_update()
return
-/obj/machinery/atmospherics/components/trinary/mixer/update_icon()
- cut_overlays()
+/obj/machinery/atmospherics/components/trinary/mixer/update_overlays()
+ . = ..()
for(var/direction in GLOB.cardinals)
if(!(direction & initialize_directions))
continue
- var/obj/machinery/atmospherics/node = findConnecting(direction)
-
- var/image/cap
- if(node)
- cap = getpipeimage(icon, "cap", direction, node.pipe_color, piping_layer = piping_layer, trinary = TRUE)
- else
- cap = getpipeimage(icon, "cap", direction, piping_layer = piping_layer, trinary = TRUE)
- add_overlay(cap)
-
- return ..()
+ . += get_pipe_image(icon, "cap", direction, pipe_color, piping_layer, TRUE)
/obj/machinery/atmospherics/components/trinary/mixer/update_icon_nopipes()
var/on_state = on && nodes[1] && nodes[2] && nodes[3] && is_operational
@@ -58,12 +49,12 @@
/obj/machinery/atmospherics/components/trinary/mixer/New()
..()
var/datum/gas_mixture/air3 = airs[3]
- air3.set_volume(300)
+ air3.volume = 300
airs[3] = air3
/obj/machinery/atmospherics/components/trinary/mixer/process_atmos()
..()
- if(!on || !(nodes[1] && nodes[2] && nodes[3]) || !is_operational)
+ if(!on || !(nodes[1] && nodes[2] && nodes[3]) && !is_operational)
return
//Get those gases, mah boiiii
@@ -82,26 +73,30 @@
return
//Calculate necessary moles to transfer using PV=nRT
- var/general_transfer = (target_pressure - output_starting_pressure) * air3.return_volume() / R_IDEAL_GAS_EQUATION
+ var/general_transfer = (target_pressure - output_starting_pressure) * air3.volume / R_IDEAL_GAS_EQUATION
+
+ //Calculate combined temperature for accurate output ratio
+ var/combined_heat_capacity = air1.heat_capacity() + air2.heat_capacity()
+ var/equalized_temperature = combined_heat_capacity ? (air1.thermal_energy() + air2.thermal_energy()) / combined_heat_capacity : 0
- var/transfer_moles1 = air1.return_temperature() ? node1_concentration * general_transfer / air1.return_temperature() : 0
- var/transfer_moles2 = air2.return_temperature() ? node2_concentration * general_transfer / air2.return_temperature() : 0
+ var/transfer_moles1 = equalized_temperature ? (node1_concentration * general_transfer) / equalized_temperature : 0
+ var/transfer_moles2 = equalized_temperature ? (node2_concentration * general_transfer) / equalized_temperature : 0
var/air1_moles = air1.total_moles()
var/air2_moles = air2.total_moles()
if(!node2_concentration)
- if(air1.return_temperature() <= 0)
+ if(air1.temperature <= 0)
return
transfer_moles1 = min(transfer_moles1, air1_moles)
transfer_moles2 = 0
else if(!node1_concentration)
- if(air2.return_temperature() <= 0)
+ if(air2.temperature <= 0)
return
transfer_moles2 = min(transfer_moles2, air2_moles)
transfer_moles1 = 0
else
- if(air1.return_temperature() <= 0 || air2.return_temperature() <= 0)
+ if(air1.temperature <= 0 || air2.temperature <= 0)
return
if((transfer_moles2 <= 0) || (transfer_moles1 <= 0))
return
@@ -114,17 +109,19 @@
//Actually transfer the gas
if(transfer_moles1)
- air1.transfer_to(air3, transfer_moles1)
+ var/datum/gas_mixture/removed1 = air1.remove(transfer_moles1)
+ air3.merge(removed1)
var/datum/pipeline/parent1 = parents[1]
- parent1.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
+ parent1.update = TRUE
if(transfer_moles2)
- air2.transfer_to(air3, transfer_moles2)
+ var/datum/gas_mixture/removed2 = air2.remove(transfer_moles2)
+ air3.merge(removed2)
var/datum/pipeline/parent2 = parents[2]
- parent2.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
+ parent2.update = TRUE
var/datum/pipeline/parent3 = parents[3]
- parent3.update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
+ parent3.update = TRUE
/obj/machinery/atmospherics/components/trinary/mixer/ui_state(mob/user)
diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/trinary_devices.dm b/code/modules/atmospherics/machinery/components/trinary_devices/trinary_devices.dm
index 01b89560d683e..d96b7244eb47d 100644
--- a/code/modules/atmospherics/machinery/components/trinary_devices/trinary_devices.dm
+++ b/code/modules/atmospherics/machinery/components/trinary_devices/trinary_devices.dm
@@ -9,7 +9,7 @@
var/flipped = FALSE
-/obj/machinery/atmospherics/components/trinary/SetInitDirections()
+/obj/machinery/atmospherics/components/trinary/set_init_directions()
switch(dir)
if(NORTH)
initialize_directions = EAST|NORTH|SOUTH
@@ -24,7 +24,7 @@
Housekeeping and pipe network stuff
*/
-/obj/machinery/atmospherics/components/trinary/getNodeConnects()
+/obj/machinery/atmospherics/components/trinary/get_node_connects()
//Mixer:
//1 and 2 is input
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/airlock_pump.dm b/code/modules/atmospherics/machinery/components/unary_devices/airlock_pump.dm
new file mode 100644
index 0000000000000..9dc659beb3bc7
--- /dev/null
+++ b/code/modules/atmospherics/machinery/components/unary_devices/airlock_pump.dm
@@ -0,0 +1,596 @@
+/**
+ * The pump looks up for the airlocks automatically based on airlock_pump_distance_limit and airlock_group_distance_limit values.
+ * When placed, the dir value (direction where the pipes are coming from) is considered as a direction towards the station (internal). The opposite direction is external.
+ * The airlock then tries to find airlocks or walls towards these directions until airlock_pump_distance_limit number of tiles reached.
+ * When it finds a valid object, then it tries to find airlocks, in directions perpendicular to the found tiles.
+ * And then adds them to the corresponding group (external/internal) until airlock_group_distance_limit number of tiles reached
+ *
+ * Example scheme of a valid configuration:
+ * A-----W
+ * A-----A
+ * W--P--A
+ * W-----W
+ * A-----W
+ *
+ * Where:
+ * A - airlocks
+ * W - walls
+ * P - pump
+ */
+/// A vent, scrubber and a sensor in a single device meant specifically for cycling airlocks. Ideal for airlocks of up to 3x3 tiles in size to avoid wind and timing out.
+/obj/machinery/atmospherics/components/unary/airlock_pump
+ name = "external airlock pump"
+ desc = "A pump for cycling an external airlock controlled by the connected doors."
+ icon = 'icons/obj/atmospherics/components/unary_devices.dmi'
+ icon_state = "airlock_pump"
+ pipe_state = "airlock_pump"
+ use_power = IDLE_POWER_USE
+ can_unwrench = TRUE
+ welded = FALSE
+ vent_movement = VENTCRAWL_ALLOWED | VENTCRAWL_CAN_SEE | VENTCRAWL_ENTRANCE_ALLOWED
+ max_integrity = 100
+ paintable = FALSE
+ pipe_flags = PIPING_ONE_PER_TURF | PIPING_DISTRO_AND_WASTE_LAYERS | PIPING_DEFAULT_LAYER_ONLY | PIPING_ALL_COLORS
+ layer = GAS_PUMP_LAYER
+ hide = TRUE
+ device_type = BINARY // Even though it is unary, it has two nodes on one side - used in node count checks
+
+ ///Indicates that the direction of the pump, if ATMOS_DIRECTION_SIPHONING is siphoning, if ATMOS_DIRECTION_RELEASING is releasing
+ var/pump_direction = ATMOS_DIRECTION_SIPHONING
+ ///Target pressure for pressurization cycle
+ var/internal_pressure_target = ONE_ATMOSPHERE
+ ///Target pressure for depressurization cycle
+ var/external_pressure_target = 0
+ ///Target pressure for the current cycle
+ var/cycle_pressure_target
+ ///Allowed error in pressure checks
+ var/allowed_pressure_error = ONE_ATMOSPHERE / 100
+ ///Minimal distro pressure to start cycling
+ var/min_distro_pressure = ONE_ATMOSPHERE / 10
+ ///Which pressure holds docked vessel\station for override of external_pressure_target
+ var/docked_side_pressure
+ ///Rate of the pump to remove gases from the air
+ var/volume_rate = 1000
+ ///The start time of the current cycle to calculate cycle duration
+ var/cycle_start_time
+ ///Max duration of cycle, after which the pump will unlock the airlocks with a warning
+ var/cycle_timeout = 10 SECONDS
+ ///List of the turfs adjacent to the pump for faster cycling and avoiding wind
+ var/list/turf/adjacent_turfs = list()
+ ///Max distance between the airlock and the pump. Used to set up cycling.
+ var/airlock_pump_distance_limit = 2
+ ///Max distance between the central airlock and the side airlocks in a group
+ var/airlock_group_distance_limit = 2
+ ///Type of airlocks required for automatic cycling setup. To avoid hacking bridge doors. Ignored for mapspawn pump.
+ var/valid_airlock_typepath = /obj/machinery/door/airlock/external
+ ///Station-facing airlocks used in cycling
+ var/list/obj/machinery/door/airlock/internal_airlocks
+ ///Space-facing airlocks used in cycling
+ var/list/obj/machinery/door/airlock/external_airlocks
+ ///Whether both airlocks are specified and cycling is available
+ var/cycling_set_up = FALSE
+ ///Whether the pump opens the airlocks up instead of simpy unbolting them on cycle
+ var/open_airlock_on_cycle = TRUE
+ ///Airlocks currently animating
+ var/airlocks_animating = FALSE
+ ///Whether the airlocks comment the cycling details to the chat
+ var/is_cycling_audible = TRUE
+
+ COOLDOWN_DECLARE(check_turfs_cooldown)
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/update_icon_nopipes()
+ if(!on || !is_operational || !powered())
+ icon_state = "vent_off"
+ else
+ icon_state = pump_direction ? "vent_out" : "vent_in"
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/update_overlays()
+ . = ..()
+ if(!showpipe)
+ return
+
+ var/mutable_appearance/distro_pipe_appearance = get_pipe_image(icon, "pipe_exposed", dir, COLOR_BLUE, piping_layer = 4)
+ if(nodes[1])
+ distro_pipe_appearance = get_pipe_image(icon, "pipe_intact", dir, COLOR_BLUE, piping_layer = 4)
+ . += distro_pipe_appearance
+
+ var/mutable_appearance/waste_pipe_appearance = get_pipe_image(icon, "pipe_exposed", dir, COLOR_RED, piping_layer = 2)
+ if(nodes[2])
+ waste_pipe_appearance = get_pipe_image(icon, "pipe_intact", dir, COLOR_RED, piping_layer = 2)
+ . += waste_pipe_appearance
+
+ var/mutable_appearance/distro_cap_appearance = get_pipe_image(icon, "vent_cap", dir, piping_layer = 4)
+ . += distro_cap_appearance
+
+ var/mutable_appearance/waste_cap_appearance = get_pipe_image(icon, "vent_cap", dir, piping_layer = 2)
+ . += waste_cap_appearance
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/atmos_init(list/node_connects)
+ for(var/obj/machinery/atmospherics/target in get_step(src, dir))
+ if(connection_check(target, 4) && !nodes[1])
+ nodes[1] = target // Distro
+ if(connection_check(target, 2) && !nodes[2])
+ nodes[2] = target // Waste
+ update_appearance()
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/Initialize(mapload)
+ . = ..()
+ if(mapload)
+ can_unwrench = FALSE
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/LateInitialize()
+ . = ..()
+ set_links()
+ // If we are on docked shuttle - setup docking variables
+ // Example - 'build your own shuttle' evac vessel
+ var/turf/local_turf = get_turf(src)
+ if (!cycling_set_up || !isshuttleturf(local_turf))
+ return
+
+ var/tile_air_pressure
+ for(var/obj/machinery/door/airlock/external_airlock in external_airlocks)
+ var/current_area = get_area(external_airlock)
+ for(var/obj/machinery/door/airlock/other_airlock in orange(2, external_airlock)) // does not include src, extended because some escape pods have 1 plating turf exposed to space
+ if(get_area(other_airlock) != current_area) // does not include double-wide airlocks unless actually docked
+ // Cycle linking is only disabled if we are actually adjacent to another airlock
+ external_airlock.shuttledocked = TRUE
+ other_airlock.shuttledocked = TRUE
+ if (other_airlock.cycle_pump)
+ INVOKE_ASYNC(other_airlock.cycle_pump, TYPE_PROC_REF(/obj/machinery/atmospherics/components/unary/airlock_pump, on_dock_request), internal_pressure_target) // Only case when airlock pumps speaking to each other directly
+ // Save external airlocks turf in case our own docking purpouses
+ local_turf = get_turf(other_airlock)
+
+ if (local_turf)
+ local_turf = get_step(local_turf, REVERSE_DIR(dir))
+ tile_air_pressure = 0
+ if (local_turf)
+ tile_air_pressure = max(0, local_turf.return_air().return_pressure())
+ on_dock_request(tile_air_pressure)
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/New()
+ . = ..()
+ var/datum/gas_mixture/distro_air = airs[1]
+ var/datum/gas_mixture/waste_air = airs[2]
+ distro_air.volume = 1000
+ waste_air.volume = 1000
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/on_deconstruction(disassembled)
+ . = ..()
+ if(cycling_set_up)
+ break_all_links()
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/can_unwrench(mob/user)
+ . = ..()
+ if(!.)
+ to_chat(user, "You cannot unwrench [src], it is secured firmly in place!")
+ return FALSE
+ if(. && on)
+ to_chat(user, "You cannot unwrench [src], wait for the cycle completion!")
+ return FALSE
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/process_atmos()
+ if(!on)
+ return
+
+ if(!powered())
+ stop_cycle("No power. Cycle aborted.", unbolt_only = TRUE)
+ return //Couldn't complete the cycle due to power outage
+
+ var/turf/location = get_turf(loc)
+ if(isclosedturf(location))
+ return
+
+ if(COOLDOWN_FINISHED(src, check_turfs_cooldown))
+ check_turfs()
+ COOLDOWN_START(src, check_turfs_cooldown, 2 SECONDS)
+
+ if(world.time - cycle_start_time > cycle_timeout)
+ stop_cycle("Cycling timed out, bolts unlocked.", unbolt_only = TRUE)
+ return //Couldn't complete the cycle before timeout
+
+ var/datum/gas_mixture/distro_air = airs[1]
+ var/datum/gas_mixture/tile_air = loc.return_air()
+ var/tile_air_pressure = tile_air.return_pressure()
+
+ if(pump_direction == ATMOS_DIRECTION_RELEASING) //distro node -> tile
+ var/pressure_delta = cycle_pressure_target - tile_air_pressure
+ if(pressure_delta <= allowed_pressure_error && stop_cycle("Pressurization complete."))
+ return //Internal target pressure reached
+
+ var/available_moles = distro_air.total_moles()
+ var/total_tiles = adjacent_turfs.len + 1
+ var/split_moles = QUANTIZE(available_moles / total_tiles)
+
+ fill_tile(loc, split_moles, pressure_delta)
+ for(var/turf/tile as anything in adjacent_turfs)
+ fill_tile(tile, split_moles, pressure_delta)
+ else //tile -> waste node
+ var/pressure_delta = tile_air_pressure - cycle_pressure_target
+ if(pressure_delta <= allowed_pressure_error && stop_cycle("Decompression complete."))
+ return //External target pressure reached
+
+ siphon_tile(loc)
+ for(var/turf/tile as anything in adjacent_turfs)
+ siphon_tile(tile)
+
+
+/// Fill a tile with air from the distro node
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/fill_tile(turf/tile, moles, pressure_delta)
+ var/datum/pipeline/distro_pipe = parents[1]
+ var/datum/gas_mixture/distro_air = airs[1]
+ var/datum/gas_mixture/tile_air = tile.return_air()
+ var/transfer_moles = (volume_rate / tile_air.volume) * (pressure_delta * tile_air.volume) / (distro_air.temperature * R_IDEAL_GAS_EQUATION)
+ moles = min(moles, transfer_moles)
+
+ var/datum/gas_mixture/removed_air = distro_air.remove(moles)
+
+ if(!removed_air)
+ return //No air in distro
+
+ tile.assume_air(removed_air)
+ distro_pipe.update = TRUE
+
+
+/// Siphon air from the tile to the waste node within the volume rate limit
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/siphon_tile(turf/tile)
+ var/datum/pipeline/waste_pipe = parents[2]
+ var/datum/gas_mixture/waste_air = airs[2]
+ var/datum/gas_mixture/tile_air = tile.return_air()
+
+ var/transfer_moles = tile_air.total_moles() * (volume_rate / tile_air.volume)
+ var/datum/gas_mixture/removed_air = tile.remove_air(transfer_moles)
+
+ if(!removed_air)
+ return //No air on the tile
+
+ waste_air.merge(removed_air)
+ waste_pipe.update = TRUE
+
+
+/// Proc for triggering cycle by clicking on a bolted airlock that has a pump assigned
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/airlock_act(obj/machinery/door/airlock/airlock)
+ if(on)
+ airlock.do_animate(AIRLOCK_DENY) // Already cycling
+ return
+ if(!cycling_set_up)
+ airlock.say("Airlock pair not found.")
+ return
+ if(airlock in external_airlocks)
+ // If it's not null - we shuttledocked
+ // (it may be 0. Maybe badmin set internal pressure to 0 as well, who knows)
+ if(docked_side_pressure != null)
+ // Space-faced airlock detection
+ var/turf/external_tile = get_step(airlock, REVERSE_DIR(dir))
+ // Map edge or space turf
+ if (external_tile == null || isspaceturf(external_tile) || isopenspace(external_tile))
+ airlock.do_animate(AIRLOCK_DENY)
+ return
+ var/tile_air_pressure = max(0, external_tile.return_air().return_pressure())
+ var/pressure_delta = docked_side_pressure - tile_air_pressure
+ if (pressure_delta > 0 ? (pressure_delta > allowed_pressure_error*10) : (pressure_delta*-1 > allowed_pressure_error*10))
+ // Disabled to avoid airlocks close-open spam
+ airlock.do_animate(AIRLOCK_DENY)
+ return
+
+ start_cycle(ATMOS_DIRECTION_SIPHONING, airlock)
+ else if(airlock in internal_airlocks)
+ start_cycle(ATMOS_DIRECTION_RELEASING, airlock)
+
+
+///Start decompression or pressurization cycle depending on the passed direction
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/start_cycle(cycle_direction, obj/machinery/door/airlock/source_airlock = null)
+ if(on || !cycling_set_up || airlocks_animating || !powered())
+ return FALSE
+
+ pump_direction = cycle_direction
+
+ for(var/obj/machinery/door/airlock/airlock as anything in (internal_airlocks + external_airlocks))
+ INVOKE_ASYNC(airlock, TYPE_PROC_REF(/obj/machinery/door/airlock, secure_close))
+
+ airlocks_animating = TRUE
+ stoplag(1 SECONDS) // Wait for closing animation
+ airlocks_animating = FALSE
+
+ on = TRUE
+ cycle_start_time = world.time
+
+ var/turf/local_turf = get_turf(src)
+ var/tile_air_pressure = max(0, local_turf.return_air().return_pressure())
+
+ if(pump_direction == ATMOS_DIRECTION_RELEASING)
+ cycle_pressure_target = internal_pressure_target
+ var/pressure_delta = cycle_pressure_target - tile_air_pressure
+ if(pressure_delta <= allowed_pressure_error)
+ stop_cycle("Pressure nominal, cycle skipped.")
+ return TRUE
+
+ var/datum/gas_mixture/distro_air = airs[1]
+ if(distro_air.return_pressure() < min_distro_pressure)
+ stop_cycle("Low pipe pressure, cycle skipped. Proceed with caution.", unbolt_only = TRUE)
+ return TRUE
+
+ if(!source_airlock)
+ source_airlock = internal_airlocks[1]
+ if(is_cycling_audible)
+ source_airlock.say("Pressurizing airlock.")
+ else
+ cycle_pressure_target = docked_side_pressure != null ? docked_side_pressure : external_pressure_target
+ var/pressure_delta = tile_air_pressure - cycle_pressure_target
+ if(pressure_delta <= allowed_pressure_error)
+ stop_cycle("Pressure nominal, cycle skipped.")
+ return TRUE
+
+ if(!source_airlock)
+ source_airlock = external_airlocks[1]
+ if(is_cycling_audible)
+ source_airlock.say("Decompressing airlock.")
+
+ update_appearance()
+ return TRUE
+
+
+///Complete/Abort cycle with the passed message
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/stop_cycle(message = null, unbolt_only = FALSE)
+ if(!on)
+ return FALSE
+ on = FALSE
+
+ // In case we can open both sides safe_dock will do it for us
+ // it also handles its own messages. If we can't - procceed
+ if (docked_side_pressure != null && safe_dock(unbolt_only))
+ return TRUE
+
+ var/list/obj/machinery/door/airlock/unlocked_airlocks = pump_direction == ATMOS_DIRECTION_RELEASING ? internal_airlocks : external_airlocks
+ for(var/obj/machinery/door/airlock/airlock as anything in unlocked_airlocks)
+ airlock.unbolt()
+ if(open_airlock_on_cycle && !unbolt_only)
+ INVOKE_ASYNC(airlock, TYPE_PROC_REF(/obj/machinery/door/airlock, secure_open)) //Can unbolt, but without audio
+
+ airlocks_animating = TRUE
+ stoplag(1 SECONDS) // Wait for opening animation
+ airlocks_animating = FALSE
+
+ if(message && is_cycling_audible)
+ unlocked_airlocks[1].say(message)
+
+ update_appearance()
+ return TRUE
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/on_dock_request(requester_pressure = 0)
+ if (docked_side_pressure != null)
+ return
+
+ docked_side_pressure = requester_pressure
+
+ if (!powered() || !cycling_set_up)
+ return
+
+ // We just finishing previous cycle
+ if (airlocks_animating)
+ say("Docking request queued.")
+ stoplag(1.1 SECONDS) // Wait for opening animation
+ if (airlocks_animating) // Should (almost) never happened
+ say("ERROR: D11. Please re-initiate docking sequence.")
+ return
+
+ if (on)
+ // You can't go there, there is a shuttle now
+ if (pump_direction == ATMOS_DIRECTION_SIPHONING)
+ stop_cycle("Cycling sequence overriden by docking sequence.", TRUE)
+ start_cycle(ATMOS_DIRECTION_RELEASING)
+ // If cycling inside, docking will be handled by stop_cycle proc
+ return
+
+ // Check if we need cycle in
+ var/turf/local_turf = get_turf(src)
+ var/tile_air_pressure = max(0, local_turf.return_air().return_pressure())
+ var/pressure_delta = internal_pressure_target - tile_air_pressure
+ if(pressure_delta <= allowed_pressure_error)
+ // We fine
+ safe_dock()
+ else
+ var/obj/machinery/door/airlock/source_airlock = pick(internal_airlocks)
+ source_airlock.say("Docking sequence initiated")
+ start_cycle(ATMOS_DIRECTION_RELEASING)
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/safe_dock(unbolt_only = FALSE)
+ var/pressure_delta = internal_pressure_target - docked_side_pressure
+ // Docked vessel has pressure higher then our internal
+ if ((pressure_delta + allowed_pressure_error) < 0)
+ return FALSE
+ // Pressure is too different, its unsafe to open both sides
+ else if (pressure_delta > allowed_pressure_error * 10)
+ return FALSE
+ // No power handles by stop_cycle pretty good
+ else if (!powered())
+ return FALSE
+
+ var/turf/local_turf = get_turf(src)
+ var/tile_air_pressure = max(0, local_turf.return_air().return_pressure())
+ pressure_delta = internal_pressure_target - tile_air_pressure
+ // Chamber is not pressurised
+ if(pressure_delta > allowed_pressure_error)
+ return FALSE
+
+ for(var/obj/machinery/door/airlock/airlock as anything in (external_airlocks + internal_airlocks))
+ if (airlock in external_airlocks)
+ airlock.air_tight = TRUE
+ local_turf = get_step(airlock, REVERSE_DIR(dir))
+ // Map edge or space turf
+ if (local_turf == null || isspaceturf(local_turf) || isopenspace(local_turf))
+ continue
+
+ tile_air_pressure = max(0, local_turf.return_air().return_pressure())
+ pressure_delta = docked_side_pressure - tile_air_pressure
+ // Do not open airlocks leading in space
+ // If docked entity now has pressure lower or higher then was declared on docking
+ // We will keep airlocks closed until redocking or fixing atmos
+ if (pressure_delta > 0 ? (pressure_delta > allowed_pressure_error*10) : (pressure_delta*-1 > allowed_pressure_error*10))
+ continue
+
+ airlock.unbolt()
+ if(open_airlock_on_cycle && !unbolt_only)
+ INVOKE_ASYNC(airlock, TYPE_PROC_REF(/obj/machinery/door/airlock, secure_open))
+
+ airlocks_animating = TRUE
+ stoplag(1 SECONDS) // Wait for closing animation
+ airlocks_animating = FALSE
+ update_appearance()
+ say("Docking complete.")
+ return TRUE
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/undock()
+ if (docked_side_pressure == null)
+ return
+ docked_side_pressure = null
+ if(!powered())
+ return
+
+ for(var/obj/machinery/door/airlock/airlock as anything in external_airlocks)
+ INVOKE_ASYNC(airlock, TYPE_PROC_REF(/obj/machinery/door/airlock, secure_close), TRUE)
+
+ say("Docking connection terminated.")
+ airlocks_animating = TRUE
+ stoplag(1 SECONDS) // Wait for closing animation
+ airlocks_animating = FALSE
+
+
+///Update adjacent_turfs with atmospherically adjacent tiles
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/check_turfs()
+ adjacent_turfs.Cut()
+ var/turf/local_turf = get_turf(src)
+ adjacent_turfs = local_turf.get_atmos_adjacent_turfs(alldir = TRUE)
+
+
+///Find airlocks and link up with them
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/set_links()
+ var/perpendicular_dirs = NSCOMPONENT(dir) ? WEST|EAST : NORTH|SOUTH
+ var/turf/internal_airlocks_origin = find_density(get_turf(src), dir)
+ var/turf/external_airlocks_origin = find_density(get_turf(src), REVERSE_DIR(dir))
+ internal_airlocks = get_adjacent_airlocks(internal_airlocks_origin, perpendicular_dirs)
+ external_airlocks = get_adjacent_airlocks(external_airlocks_origin, perpendicular_dirs)
+
+ if(!internal_airlocks.len || !internal_airlocks.len)
+ if(!can_unwrench) //maploaded pump
+ CRASH("[type] couldn't find airlocks to cycle with!")
+ internal_airlocks = list()
+ external_airlocks = list()
+ say("Cycling setup failed. No opposite airlocks found.")
+ return
+
+ for(var/obj/machinery/door/airlock/airlock as anything in (internal_airlocks + external_airlocks))
+ airlock.set_cycle_pump(src)
+ RegisterSignal(airlock, COMSIG_PARENT_QDELETING, PROC_REF(unlink_airlock))
+ if (airlock in external_airlocks)
+ INVOKE_ASYNC(airlock, TYPE_PROC_REF(/obj/machinery/door/airlock, secure_close))
+ else if(open_airlock_on_cycle)
+ INVOKE_ASYNC(airlock, TYPE_PROC_REF(/obj/machinery/door/airlock, secure_open))
+
+ cycle_timeout *= round((internal_airlocks.len + external_airlocks.len) / 2)
+ cycling_set_up = TRUE
+ if(can_unwrench)
+ say("Cycling setup complete.")
+
+
+///Get the turf of the first found airlock or an airtight structure (walls) within the allowed range
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/find_density(turf/origin, direction, max_distance = airlock_pump_distance_limit)
+ var/turf/next_turf = origin
+ var/limit = max(1, max_distance)
+ while(limit)
+ limit--
+ next_turf = get_step(next_turf, direction)
+ var/obj/machinery/door/airlock/found_airlock = locate() in next_turf
+ if(is_valid_airlock(found_airlock))
+ return found_airlock.loc
+ if(!next_turf.can_atmos_pass)
+ return next_turf
+
+
+///Find airlocks adjacent to the central one, lined up along the provided directions
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/get_adjacent_airlocks(origin_turf, directions)
+ var/list/airlocks = list()
+
+ var/obj/machinery/door/airlock/origin_airlock = locate() in origin_turf
+ if(is_valid_airlock(origin_airlock))
+ airlocks.Add(origin_airlock)
+
+ for(var/direction in GLOB.cardinals)
+ if(!(direction & directions))
+ continue
+ var/turf/next_turf = origin_turf
+ var/limit = max(0, airlock_group_distance_limit)
+ while(limit)
+ limit--
+ next_turf = get_step(next_turf, direction)
+ var/obj/machinery/door/airlock/found_airlock = locate() in next_turf
+ if (is_valid_airlock(found_airlock))
+ airlocks.Add(found_airlock)
+ else
+ limit = 0
+
+ return airlocks
+
+
+///Whether the passed airlock can be linked with
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/is_valid_airlock(obj/machinery/door/airlock/airlock)
+ if(!airlock)
+ return FALSE
+ if(airlock.cycle_pump)
+ return FALSE // Already linked
+ if(can_unwrench && !istype(airlock, valid_airlock_typepath))
+ return FALSE // Invalid airlock type and the pump is not mapspawn
+ return TRUE
+
+
+///Find airlocks and link up with them
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/unlink_airlock(airlock)
+ UnregisterSignal(airlock, COMSIG_PARENT_QDELETING)
+
+ if(airlock in internal_airlocks)
+ internal_airlocks.Remove(airlock)
+ if(airlock in external_airlocks)
+ external_airlocks.Remove(airlock)
+
+ if(!internal_airlocks.len || !external_airlocks.len)
+ break_all_links()
+
+
+///Break the cycling setup
+/obj/machinery/atmospherics/components/unary/airlock_pump/proc/break_all_links()
+ for(var/obj/machinery/door/airlock/airlock as anything in (internal_airlocks + external_airlocks))
+ UnregisterSignal(airlock, COMSIG_PARENT_QDELETING)
+
+ external_airlocks = list()
+ internal_airlocks = list()
+ cycle_timeout = initial(cycle_timeout)
+ cycling_set_up = FALSE
+
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/relaymove(mob/living/user, direction)
+ if(initialize_directions & direction)
+ return ..()
+ if((NORTH|EAST) & direction)
+ user.ventcrawl_layer = clamp(user.ventcrawl_layer + 2, PIPING_LAYER_DEFAULT - 1, PIPING_LAYER_DEFAULT + 1)
+ if((SOUTH|WEST) & direction)
+ user.ventcrawl_layer = clamp(user.ventcrawl_layer - 2, PIPING_LAYER_DEFAULT - 1, PIPING_LAYER_DEFAULT + 1)
+ to_chat(user, "You align yourself with the [user.ventcrawl_layer == 2 ? 1 : 2]\th output.")
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/unbolt_only
+ open_airlock_on_cycle = FALSE
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/silent
+ is_cycling_audible = FALSE
+
+/obj/machinery/atmospherics/components/unary/airlock_pump/lavaland
+ external_pressure_target = MAXIMUM_LAVALAND_EQUIPMENT_EFFECT_PRESSURE
+
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index 2c46790844080..721a805e9b7f6 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -1,6 +1,9 @@
#define CRYOMOBS 'icons/obj/cryo_mobs.dmi'
#define CRYO_MULTIPLY_FACTOR 1.5 // Multiply factor is used with efficiency to multiply Tx quantity and how much extra is transfered to occupant magically.
#define CRYO_TX_QTY 0.4 // Tx quantity is how much volume should be removed from the cell's beaker - multiplied by delta_time
+#define CRYO_MIN_GAS_MOLES 5
+#define MAX_TEMPERATURE 4000
+
/obj/machinery/atmospherics/components/unary/cryo_cell
name = "cryo cell"
@@ -23,6 +26,7 @@
var/efficiency = 1
var/sleep_factor = 0.00125
var/unconscious_factor = 0.001
+ /// Our approximation of a mob's heat capacity.
var/heat_capacity = 20000
var/conduction_coefficient = 0.3
@@ -223,7 +227,7 @@
beaker.reagents.trans_to(occupant, (CRYO_TX_QTY / (efficiency * CRYO_MULTIPLY_FACTOR)) * delta_time, efficiency * CRYO_MULTIPLY_FACTOR, method = VAPOR) // Transfer reagents.
use_power(1000 * efficiency)
- return 1
+ return TRUE
/obj/machinery/atmospherics/components/unary/cryo_cell/process_atmos()
..()
@@ -233,7 +237,7 @@
var/datum/gas_mixture/air1 = airs[1]
- if(!nodes[1] || !airs[1] || air1.get_moles(GAS_O2) < 5) // Turn off if the machine won't work due to not having enough moles to operate.
+ if(!nodes[1] || !airs[1] || GET_MOLES(/datum/gas/oxygen, air1) < 5) // Turn off if the machine won't work due to not having enough moles to operate.
on = FALSE
update_icon()
var/msg = "Aborting. Not enough gas present to operate."
@@ -252,12 +256,12 @@
if(abs(temperature_delta) > 1)
var/air_heat_capacity = air1.heat_capacity()
- var/heat = ((1 - cold_protection) * 0.1 + conduction_coefficient) * temperature_delta * (air_heat_capacity * heat_capacity / (air_heat_capacity + heat_capacity))
+ var/heat = ((1 - cold_protection) * 0.1 + conduction_coefficient) * CALCULATE_CONDUCTION_ENERGY(temperature_delta, heat_capacity, air_heat_capacity)
- air1.set_temperature(max(air1.return_temperature() - heat / air_heat_capacity, TCMB))
mob_occupant.adjust_bodytemperature(heat / heat_capacity, TCMB)
+ air1.temperature = clamp(air1.temperature - heat / air_heat_capacity, TCMB, MAX_TEMPERATURE)
- air1.set_moles(GAS_O2, max(0,air1.get_moles(GAS_O2) - 0.5 / efficiency)) // Magically consume gas? Why not, we run on cryo magic.
+ SET_MOLES(/datum/gas/oxygen, air1, max(0,GET_MOLES(/datum/gas/oxygen, air1) - 0.5 / efficiency)) // Magically consume gas? Why not, we run on cryo magic.
update_parents()
@@ -467,19 +471,21 @@
/obj/machinery/atmospherics/components/unary/cryo_cell/default_change_direction_wrench(mob/user, obj/item/wrench/W)
. = ..()
if(.)
- SetInitDirections()
+ set_init_directions()
var/obj/machinery/atmospherics/node = nodes[1]
if(node)
node.disconnect(src)
nodes[1] = null
- nullifyPipenet(parents[1])
- atmosinit()
+ nullify_pipenet(parents[1])
+ atmos_init()
node = nodes[1]
if(node)
- node.atmosinit()
- node.addMember(src)
+ node.atmos_init()
+ node.add_member(src)
SSair.add_to_rebuild_queue(src)
#undef CRYOMOBS
#undef CRYO_MULTIPLY_FACTOR
#undef CRYO_TX_QTY
+#undef CRYO_MIN_GAS_MOLES
+#undef MAX_TEMPERATURE
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 0021cebdc802a..5068730358e5d 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/heat_exchanger.dm
@@ -32,7 +32,7 @@
icon_state = "he0"
PIPING_LAYER_SHIFT(src, piping_layer)
-/obj/machinery/atmospherics/components/unary/heat_exchanger/atmosinit()
+/obj/machinery/atmospherics/components/unary/heat_exchanger/atmos_init()
var/obj/machinery/atmospherics/components/unary/heat_exchanger/partner = partner_ref?.resolve()
if(!partner)
partner_ref = null
@@ -72,8 +72,8 @@
var/combined_energy = partner_air_contents.return_temperature()*other_air_heat_capacity + air_heat_capacity*air_contents.return_temperature()
var/new_temperature = combined_energy/combined_heat_capacity
- air_contents.set_temperature(new_temperature)
- partner_air_contents.set_temperature(new_temperature)
+ air_contents.temperature = (new_temperature)
+ partner_air_contents.temperature = (new_temperature)
if(abs(old_temperature-air_contents.return_temperature()) > 1)
update_parents()
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 a30950c10d879..d73012995d623 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/outlet_injector.dm
@@ -50,7 +50,7 @@
cut_overlays()
if(showpipe)
// everything is already shifted so don't shift the cap
- add_overlay(getpipeimage(icon, "inje_cap", initialize_directions))
+ add_overlay(get_pipe_image(icon, "inje_cap", initialize_directions, pipe_color))
if(!nodes[1] || !on || !is_operational)
icon_state = "inje_off"
@@ -70,8 +70,6 @@
if(air_contents != null)
if(air_contents.return_temperature() > 0)
loc.assume_air_ratio(air_contents, volume_rate / air_contents.return_volume())
- air_update_turf()
-
update_parents()
/obj/machinery/atmospherics/components/unary/outlet_injector/proc/inject()
@@ -110,7 +108,7 @@
))
radio_connection.post_signal(src, signal)
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmosinit()
+/obj/machinery/atmospherics/components/unary/outlet_injector/atmos_init()
set_frequency(frequency)
broadcast_status()
..()
@@ -209,75 +207,3 @@
/obj/machinery/atmospherics/components/unary/outlet_injector/on/layer4
piping_layer = 4
icon_state = "inje_map-4"
-
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos
- frequency = FREQ_ATMOS_STORAGE
- on = TRUE
- volume_rate = MAX_TRANSFER_RATE
-
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/atmos_waste
- name = "atmos waste outlet injector"
- id = ATMOS_GAS_MONITOR_WASTE_ATMOS
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/engine_waste
- name = "engine outlet injector"
- id = ATMOS_GAS_MONITOR_WASTE_ENGINE
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/plasma_input
- name = "plasma tank input injector"
- id = ATMOS_GAS_MONITOR_INPUT_PLASMA
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/oxygen_input
- name = "oxygen tank input injector"
- id = ATMOS_GAS_MONITOR_INPUT_O2
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/nitrogen_input
- name = "nitrogen tank input injector"
- id = ATMOS_GAS_MONITOR_INPUT_N2
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/mix_input
- name = "mix tank input injector"
- id = ATMOS_GAS_MONITOR_INPUT_MIX
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/nitrous_input
- name = "nitrous oxide tank input injector"
- id = ATMOS_GAS_MONITOR_INPUT_N2O
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/air_input
- name = "air mix tank input injector"
- id = ATMOS_GAS_MONITOR_INPUT_AIR
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/carbon_input
- name = "carbon dioxide tank input injector"
- id = ATMOS_GAS_MONITOR_INPUT_CO2
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/incinerator_input
- name = "incinerator chamber input injector"
- id = ATMOS_GAS_MONITOR_INPUT_INCINERATOR
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/toxins_mixing_input
- name = "toxins mixing input injector"
- id = ATMOS_GAS_MONITOR_INPUT_TOXINS_LAB
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/toxins_waste_input
- name = "toxins waste input injector"
- id = ATMOS_GAS_MONITOR_INPUT_TOXINS_WASTE
-/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/sm_waste_input
- name = "supermatter waste input injector"
- id = ATMOS_GAS_MONITOR_INPUT_SM_WASTE
-
-
-#define LAYER_HELPER(FULLPATH)\
-##FULLPATH/layer2 {\
- piping_layer = 2;\
- icon_state = "inje_map-2";\
-}\
-##FULLPATH/layer4 {\
- piping_layer = 4;\
- icon_state = "inje_map-4";\
-}
-
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/atmos_waste)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/engine_waste)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/plasma_input)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/oxygen_input)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/nitrogen_input)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/mix_input)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/nitrous_input)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/air_input)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/carbon_input)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/incinerator_input)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/toxins_mixing_input)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/toxins_waste_input)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/outlet_injector/atmos/sm_waste_input)
-
-#undef LAYER_HELPER
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 1fa5221e38eac..3853d3f46e2c3 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/passive_vent.dm
@@ -15,30 +15,20 @@
/obj/machinery/atmospherics/components/unary/passive_vent/update_icon_nopipes()
cut_overlays()
if(showpipe)
- var/image/cap = getpipeimage(icon, "vent_cap", initialize_directions)
+ var/image/cap = get_pipe_image(icon, "vent_cap", initialize_directions, pipe_color)
add_overlay(cap)
icon_state = "passive_vent"
/obj/machinery/atmospherics/components/unary/passive_vent/process_atmos()
- ..()
- if(isclosedturf(loc))
+ var/turf/location = get_turf(loc)
+ if(isclosedturf(location))
return
- var/active = FALSE
- var/datum/gas_mixture/external = loc.return_air()
+ var/datum/gas_mixture/external = location.return_air()
var/datum/gas_mixture/internal = airs[1]
- var/external_pressure = external.return_pressure()
- var/internal_pressure = internal.return_pressure()
- var/pressure_delta = abs(external_pressure - internal_pressure)
- if(pressure_delta > 0.5)
- equalize_all_gases_in_list(list(internal,external))
- active = TRUE
-
- active = internal.temperature_share(external, OPEN_HEAT_TRANSFER_COEFFICIENT) || active
-
- if(active)
- air_update_turf()
+ if(internal.equalize(external))
+ air_update_turf(FALSE, FALSE)
update_parents()
/obj/machinery/atmospherics/components/unary/passive_vent/can_crawl_through()
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm b/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm
index 2fc2804e60a60..d2bf48fc092e5 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm
@@ -13,15 +13,22 @@
pipe_flags = PIPING_ONE_PER_TURF
pipe_state = "connector"
+ custom_reconcilation = TRUE
+ ///Reference to the connected device
var/obj/machinery/portable_atmospherics/connected_device
- var/obj/machinery/atmospherics/components/unary/portables_connector/connect_to
-
/obj/machinery/atmospherics/components/unary/portables_connector/New()
- ..()
+ . = ..()
var/datum/gas_mixture/air_contents = airs[1]
- air_contents.set_volume(0)
+ air_contents.volume = 0
+ if(connected_device)
+ var/datum/pipeline/parent = parents[1]
+ if(parent)
+ airs[1] = connected_device.air_contents
+ parent.reconcile_air()
+ else
+ CRASH("Portable canister without parent pipeline at [COORD(src)]")
/obj/machinery/atmospherics/components/unary/portables_connector/Destroy()
if(connected_device)
@@ -31,7 +38,7 @@
/obj/machinery/atmospherics/components/unary/portables_connector/update_icon_nopipes()
icon_state = "connector"
if(showpipe)
- var/image/cap = getpipeimage(icon, "connector_cap", initialize_directions)
+ var/image/cap = get_pipe_image(icon, "connector_cap", initialize_directions, pipe_color)
add_overlay(cap)
/obj/machinery/atmospherics/components/unary/portables_connector/process_atmos()
@@ -39,26 +46,18 @@
return
update_parents()
+/obj/machinery/atmospherics/components/unary/portables_connector/return_airs_for_reconcilation(datum/pipeline/requester)
+ . = ..()
+ if(!connected_device)
+ return
+ . += connected_device.return_air()
+
/obj/machinery/atmospherics/components/unary/portables_connector/can_unwrench(mob/user)
. = ..()
if(. && connected_device)
to_chat(user, "You cannot unwrench [src], detach [connected_device] first!")
return FALSE
-/obj/machinery/atmospherics/components/unary/portables_connector/portableConnectorReturnAir()
- return connected_device.portableConnectorReturnAir()
-
-/obj/machinery/atmospherics/components/unary/portables_connector/build_network()
- . = ..()
- if(connect_to)
- var/obj/machinery/portable_atmospherics/PA = connect_to
- if(PA)
- PA.connect(src)
-
-/obj/proc/portableConnectorReturnAir()
- return
-
-
/obj/machinery/atmospherics/components/unary/portables_connector/layer2
piping_layer = 2
icon_state = "connector_map-2"
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
deleted file mode 100644
index 53cf63376ccdc..0000000000000
--- a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm
+++ /dev/null
@@ -1,53 +0,0 @@
-#define AIR_CONTENTS ((25*ONE_ATMOSPHERE)*(air_contents.return_volume())/(R_IDEAL_GAS_EQUATION*air_contents.return_temperature()))
-/obj/machinery/atmospherics/components/unary/tank
- icon = 'icons/obj/atmospherics/pipes/pressure_tank.dmi'
- icon_state = "generic"
-
- name = "pressure tank"
- desc = "A large vessel containing pressurized gas."
-
- max_integrity = 800
- density = TRUE
- layer = ABOVE_WINDOW_LAYER
- pipe_flags = PIPING_ONE_PER_TURF
-
- var/volume = 10000 //in liters
- var/gas_type = null
-
-/obj/machinery/atmospherics/components/unary/tank/New()
- ..()
- var/datum/gas_mixture/air_contents = airs[1]
- air_contents.set_volume(volume)
- air_contents.set_temperature(T20C)
- if(gas_type)
- air_contents.set_moles(gas_type, AIR_CONTENTS)
- name = "[name] ([GLOB.gas_data.names[gas_type]])"
- setPipingLayer(piping_layer)
-
-
-/obj/machinery/atmospherics/components/unary/tank/air
- icon_state = "grey"
- name = "pressure tank (Air)"
-
-/obj/machinery/atmospherics/components/unary/tank/air/New()
- ..()
- var/datum/gas_mixture/air_contents = airs[1]
- air_contents.set_moles(GAS_O2, AIR_CONTENTS * 0.2)
- air_contents.set_moles(GAS_N2, AIR_CONTENTS * 0.8)
-
-/obj/machinery/atmospherics/components/unary/tank/carbon_dioxide
- gas_type = GAS_CO2
-
-/obj/machinery/atmospherics/components/unary/tank/plasma
- icon_state = "orange"
- gas_type = GAS_PLASMA
-
-/obj/machinery/atmospherics/components/unary/tank/oxygen
- icon_state = "blue"
- gas_type = GAS_O2
-
-/obj/machinery/atmospherics/components/unary/tank/nitrogen
- icon_state = "red"
- gas_type = GAS_N2
-
-#undef AIR_CONTENTS
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
index 582a53629a376..ab731aab208ae 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/thermomachine.dm
@@ -1,6 +1,8 @@
+#define THERMOMACHINE_POWER_CONVERSION 0.01
+
/obj/machinery/atmospherics/components/unary/thermomachine
icon = 'icons/obj/atmospherics/components/thermomachine.dmi'
- icon_state = "freezer"
+ icon_state = "thermo_base"
name = "Thermomachine"
desc = "Heats or cools gas in connected pipes."
@@ -11,160 +13,191 @@
layer = OBJ_LAYER
circuit = /obj/item/circuitboard/machine/thermomachine
-
-
+ move_resist = MOVE_RESIST_DEFAULT
+ vent_movement = NONE
pipe_flags = PIPING_ONE_PER_TURF
- var/icon_state_off = "freezer"
- var/icon_state_on = "freezer_1"
- var/icon_state_open = "freezer-o"
+ greyscale_config = /datum/greyscale_config/thermomachine
+ greyscale_colors = COLOR_VIBRANT_LIME
+
+ set_dir_on_move = FALSE
- var/min_temperature = T20C //actual temperature will be defined by RefreshParts() and by the cooling var
- var/max_temperature = T20C //actual temperature will be defined by RefreshParts() and by the cooling var
+ var/min_temperature = T20C //actual temperature will be defined by RefreshParts()
+ var/max_temperature = T20C //actual temperature will be defined by RefreshParts()
var/target_temperature = T20C
var/heat_capacity = 0
var/interactive = TRUE // So mapmakers can disable interaction.
- var/cooling = TRUE
var/base_heating = 140
var/base_cooling = 170
/obj/machinery/atmospherics/components/unary/thermomachine/Initialize(mapload)
. = ..()
- initialize_directions = dir
RefreshParts()
update_appearance()
-/obj/machinery/atmospherics/components/unary/thermomachine/proc/swap_function()
- cooling = !cooling
- if(cooling)
- icon_state_off = "freezer"
- icon_state_on = "freezer_1"
- icon_state_open = "freezer-o"
- else
- icon_state_off = "heater"
- icon_state_on = "heater_1"
- icon_state_open = "heater-o"
- target_temperature = T20C
- RefreshParts()
- update_icon()
+/obj/machinery/atmospherics/components/unary/thermomachine/is_connectable()
+ if(!anchored)
+ return FALSE
+ . = ..()
-/obj/machinery/atmospherics/components/unary/thermomachine/on_construction()
+/obj/machinery/atmospherics/components/unary/thermomachine/on_construction(mob/user, obj_color, set_layer)
var/obj/item/circuitboard/machine/thermomachine/board = circuit
if(board)
piping_layer = board.pipe_layer
- return ..(dir, piping_layer)
+ set_layer = piping_layer
+
+ ..() //Skipping the rest of on_construction() would be a bad idea so we clean up after it instead.
+
+ if(check_pipe_on_turf())
+ set_anchored(FALSE)
+ panel_open = TRUE
+ icon_state = "thermo-open"
+ balloon_alert(user, "the port is already in use!")
/obj/machinery/atmospherics/components/unary/thermomachine/RefreshParts()
var/calculated_bin_rating
for(var/obj/item/stock_parts/matter_bin/bin in component_parts)
calculated_bin_rating += bin.rating
heat_capacity = 5000 * ((calculated_bin_rating - 1) ** 2)
- min_temperature = T20C
- max_temperature = T20C
- if(cooling)
- var/calculated_laser_rating
- for(var/obj/item/stock_parts/micro_laser/laser in component_parts)
- calculated_laser_rating += laser.rating
- min_temperature = max(T0C - (base_cooling + calculated_laser_rating * 15), TCMB) //73.15K with T1 stock parts
- else
- var/calculated_laser_rating
- for(var/obj/item/stock_parts/micro_laser/laser in component_parts)
- calculated_laser_rating += laser.rating
- max_temperature = T20C + (base_heating * calculated_laser_rating) //573.15K with T1 stock parts
+
+ var/calculated_laser_rating = 0
+ for(var/obj/item/stock_parts/micro_laser/laser in component_parts)
+ calculated_laser_rating += laser.rating
+ min_temperature = max(T0C - (base_cooling + calculated_laser_rating * 15), TCMB) //73.15K with T1 stock parts
+ max_temperature = T20C + (base_heating * calculated_laser_rating) //573.15K with T1 stock parts
/obj/machinery/atmospherics/components/unary/thermomachine/update_icon()
- cut_overlays()
+ var/colors_to_use = ""
+ switch(target_temperature)
+ if(BODYTEMP_HEAT_WARNING_3 to INFINITY)
+ colors_to_use = COLOR_RED
+ if(BODYTEMP_HEAT_WARNING_2 to BODYTEMP_HEAT_WARNING_3)
+ colors_to_use = COLOR_ORANGE
+ if(BODYTEMP_HEAT_WARNING_1 to BODYTEMP_HEAT_WARNING_2)
+ colors_to_use = COLOR_YELLOW
+ if(BODYTEMP_COLD_WARNING_1 to BODYTEMP_HEAT_WARNING_1)
+ colors_to_use = COLOR_VIBRANT_LIME
+ if(BODYTEMP_COLD_WARNING_2 to BODYTEMP_COLD_WARNING_1)
+ colors_to_use = COLOR_CYAN
+ if(BODYTEMP_COLD_WARNING_3 to BODYTEMP_COLD_WARNING_2)
+ colors_to_use = COLOR_BLUE
+ else
+ colors_to_use = COLOR_VIOLET
+
+ if(greyscale_colors != colors_to_use)
+ set_greyscale(colors=colors_to_use)
if(panel_open)
- icon_state = icon_state_open
- else if(on && is_operational)
- icon_state = icon_state_on
- else
- icon_state = icon_state_off
-
- add_overlay(getpipeimage(icon, "pipe", dir, , piping_layer))
+ icon_state = "thermo-open"
+ return ..()
+ if(on && is_operational)
+ icon_state = "thermo_1"
+ return ..()
+ icon_state = "thermo_base"
+ return ..()
-/obj/machinery/atmospherics/components/unary/thermomachine/update_icon_nopipes()
- cut_overlays()
- if(showpipe)
- add_overlay(getpipeimage(icon, "scrub_cap", initialize_directions))
+/obj/machinery/atmospherics/components/unary/thermomachine/update_overlays()
+ . = ..()
+ if(!initial(icon))
+ return
+ var/mutable_appearance/thermo_overlay = new(initial(icon))
+ . += get_pipe_image(thermo_overlay, "pipe", dir, pipe_color, piping_layer)
/obj/machinery/atmospherics/components/unary/thermomachine/examine(mob/user)
. = ..()
. += "The thermostat is set to [target_temperature]K ([(T0C-target_temperature)*-1]C)."
if(in_range(user, src) || isobserver(user))
- . += "The status display reads: Efficiency [(heat_capacity/5000)*100]%."
+ . += "The status display reads: Efficiency [(heat_capacity/7500)*100]%."
. += "Temperature range [min_temperature]K - [max_temperature]K ([(T0C-min_temperature)*-1]C - [(T0C-max_temperature)*-1]C)."
/obj/machinery/atmospherics/components/unary/thermomachine/AltClick(mob/living/user)
- if(!can_interact(user))
- return
- if(cooling)
+ if(panel_open)
+ balloon_alert(user, "close panel!")
+ return TRUE
+
+ if(target_temperature == T20C)
+ target_temperature = max_temperature
+ else if(target_temperature == max_temperature)
target_temperature = min_temperature
- investigate_log("was set to [target_temperature] K by [key_name(user)]", INVESTIGATE_ATMOS)
else
- target_temperature = max_temperature
- investigate_log("was set to [target_temperature] K by [key_name(user)]", INVESTIGATE_ATMOS)
- balloon_alert(user, "You set the target temperature to [target_temperature] K.")
+ target_temperature = T20C
+
+ investigate_log("was set to [target_temperature] K by [key_name(user)]", INVESTIGATE_ATMOS)
+ balloon_alert(user, "temperature reset to [target_temperature] K")
+ update_appearance()
+/// Performs heat calculation for the freezer.
+/// We just equalize the gasmix with an object at temp = var/target_temperature and heat cap = var/heat_capacity
/obj/machinery/atmospherics/components/unary/thermomachine/process_atmos()
- ..()
- if(!is_operational || !on || !nodes[1]) //if it has no power or its switched off, dont process atmos
+ if(!on)
return
- var/datum/gas_mixture/air_contents = airs[1]
- var/air_heat_capacity = air_contents.heat_capacity()
- var/combined_heat_capacity = heat_capacity + air_heat_capacity
- var/old_temperature = air_contents.return_temperature()
+ var/turf/local_turf = get_turf(src)
- if(combined_heat_capacity > 0)
- var/combined_energy = heat_capacity * target_temperature + air_heat_capacity * air_contents.return_temperature()
- air_contents.set_temperature(combined_energy/combined_heat_capacity)
+ if(!is_operational || !local_turf)
+ on = FALSE
+ update_appearance()
+ return
- var/temperature_delta= abs(old_temperature - air_contents.return_temperature())
- if(temperature_delta > 1)
- active_power_usage = (heat_capacity * temperature_delta) / 10 + idle_power_usage
- update_parents()
- else
- active_power_usage = idle_power_usage
- return 1
+ // The gas we want to cool/heat
+ var/datum/gas_mixture/port = airs[1]
-/obj/machinery/atmospherics/components/unary/thermomachine/attackby(obj/item/I, mob/user, params)
+ if(!port.total_moles()) // Nothing to cool? go home lad
+ return
+
+ var/port_capacity = port.heat_capacity()
+
+ // The difference between target and what we need to heat/cool. Positive if heating, negative if cooling.
+ var/temperature_target_delta = target_temperature - port.temperature
+
+ // We perfectly can do W1+W2 / C1+C2 here but this lets us count the power easily.
+ var/heat_amount = CALCULATE_CONDUCTION_ENERGY(temperature_target_delta, port_capacity, heat_capacity)
+
+ port.temperature = max(((port.temperature * port_capacity) + heat_amount) / port_capacity, TCMB)
+
+ heat_amount = min(abs(heat_amount), 1e8) * THERMOMACHINE_POWER_CONVERSION
+
+ // This produces a nice curve that scales decently well for really hot stuff, and is nice to not fusion. It'll do
+ var/power_usage = idle_power_usage + (heat_amount * 0.05) ** (1.05 - (5e7 * 0.16 / max(heat_amount, 5e7)))
+
+ active_power_usage = power_usage
+ update_parents()
+
+
+/obj/machinery/atmospherics/components/unary/thermomachine/attackby(obj/item/tool, mob/user, params)
if(!on)
- if(default_deconstruction_screwdriver(user, icon_state_open, icon_state_off, I))
+ if(default_deconstruction_screwdriver(user, "thermo-open", "thermo-0", tool))
return
- if(default_change_direction_wrench(user, I))
+ if(default_change_direction_wrench(user, tool))
return
- if(default_deconstruction_crowbar(I))
+ if(default_deconstruction_crowbar(tool))
return
return ..()
-/obj/machinery/atmospherics/components/unary/thermomachine/default_change_direction_wrench(mob/user, obj/item/I)
- if(!..())
- return FALSE
- SetInitDirections()
- var/obj/machinery/atmospherics/node = nodes[1]
- if(node)
- node.disconnect(src)
- nodes[1] = null
- //Sometimes this gets called more than once per atmos tick; i.e. before the incoming build_network call by SSAIR_REBUILD_PIPENETS, so we check this here.
- if(parents[1])
- nullifyPipenet(parents[1])
-
- atmosinit()
- node = nodes[1]
- if(node)
- node.atmosinit()
- node.addMember(src)
- SSair.add_to_rebuild_queue(src)
+/obj/machinery/atmospherics/components/unary/thermomachine/multitool_act(mob/living/user, obj/item/multitool/multitool)
+ if(!panel_open)
+ balloon_alert(user, "open panel!")
+ return TRUE
+ piping_layer = (piping_layer >= PIPING_LAYER_MAX) ? PIPING_LAYER_MIN : (piping_layer + 1)
+ to_chat(user, "You change the circuitboard to layer [piping_layer].")
+ if(anchored)
+ reconnect_nodes()
+ update_appearance()
return TRUE
+/obj/machinery/atmospherics/components/unary/thermomachine/proc/check_pipe_on_turf()
+ for(var/obj/machinery/atmospherics/device in get_turf(src))
+ if(device == src)
+ continue
+ if(device.piping_layer == piping_layer)
+ return TRUE
+ return FALSE
+
/obj/machinery/atmospherics/components/unary/thermomachine/ui_status(mob/user)
if(interactive)
return ..()
return UI_CLOSE
-
/obj/machinery/atmospherics/components/unary/thermomachine/ui_state(mob/user)
return GLOB.default_state
@@ -178,7 +211,6 @@
/obj/machinery/atmospherics/components/unary/thermomachine/ui_data(mob/user)
var/list/data = list()
data["on"] = on
- data["cooling"] = cooling
data["min"] = min_temperature
data["max"] = max_temperature
@@ -201,10 +233,6 @@
use_power = on ? ACTIVE_POWER_USE : IDLE_POWER_USE
investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", INVESTIGATE_ATMOS)
. = TRUE
- if("cooling")
- swap_function()
- investigate_log("was changed to [cooling ? "cooling" : "heating"] by [key_name(usr)]", INVESTIGATE_ATMOS)
- . = TRUE
if("target")
var/target = params["target"]
var/adjust = text2num(params["adjust"])
@@ -221,48 +249,74 @@
if(.)
target_temperature = clamp(target, min_temperature, max_temperature)
investigate_log("was set to [target_temperature] K by [key_name(usr)]", INVESTIGATE_ATMOS)
- if(.)
- update_icon()
+ update_icon()
/obj/machinery/atmospherics/components/unary/thermomachine/CtrlClick(mob/living/user)
- if(!can_interact(user))
- return
+ if(!anchored)
+ return TRUE
+ if(panel_open)
+ balloon_alert(user, "close panel!")
+ return TRUE
+ if(!is_operational)
+ return TRUE
+
on = !on
+ balloon_alert(user, "turned [on ? "on" : "off"]")
+ investigate_log("was turned [on ? "on" : "off"] by [key_name(user)]", INVESTIGATE_ATMOS)
update_icon()
+ return TRUE
+
+/obj/machinery/atmospherics/components/unary/thermomachine/update_layer()
+ return
/obj/machinery/atmospherics/components/unary/thermomachine/freezer
- icon_state = "freezer"
- icon_state_off = "freezer"
- icon_state_on = "freezer_1"
- icon_state_open = "freezer-o"
- cooling = TRUE
+
+/obj/machinery/atmospherics/components/unary/thermomachine/freezer/layer1
+ piping_layer = 1
+
+/obj/machinery/atmospherics/components/unary/thermomachine/freezer/layer2
+ piping_layer = 2
+
+/obj/machinery/atmospherics/components/unary/thermomachine/freezer/layer4
+ piping_layer = 4
+
+/obj/machinery/atmospherics/components/unary/thermomachine/freezer/layer5
+ piping_layer = 5
/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on
on = TRUE
- icon_state = "freezer_1"
+ icon_state = "thermo_base_1"
/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on/Initialize(mapload)
. = ..()
if(target_temperature == initial(target_temperature))
target_temperature = min_temperature
-
/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on/coldroom
- name = "cold room freezer"
+ name = "Cold room temperature control unit"
+ icon_state = "thermo_base_1"
+ greyscale_colors = COLOR_CYAN
/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on/coldroom/Initialize(mapload)
. = ..()
- target_temperature = T0C-20
+ target_temperature = COLD_ROOM_TEMP
/obj/machinery/atmospherics/components/unary/thermomachine/heater
- icon_state = "heater"
- icon_state_off = "heater"
- icon_state_on = "heater_1"
- icon_state_open = "heater-o"
- cooling = FALSE
+
+/obj/machinery/atmospherics/components/unary/thermomachine/heater/layer1
+ piping_layer = 1
+
+/obj/machinery/atmospherics/components/unary/thermomachine/heater/layer2
+ piping_layer = 2
+
+/obj/machinery/atmospherics/components/unary/thermomachine/heater/layer4
+ piping_layer = 4
+
+/obj/machinery/atmospherics/components/unary/thermomachine/heater/layer5
+ piping_layer = 5
/obj/machinery/atmospherics/components/unary/thermomachine/heater/on
on = TRUE
- icon_state = "heater_1"
+ icon_state = "thermo_base_1"
#define QUICK_LAYER_HELPER(PATH)\
##PATH/layer_1 {\
@@ -286,3 +340,4 @@ QUICK_LAYER_HELPER(/obj/machinery/atmospherics/components/unary/thermomachine/fr
QUICK_LAYER_HELPER(/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on/coldroom)
#undef QUICK_LAYER_HELPER
+#undef THERMOMACHINE_POWER_CONVERSION
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm b/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm
index 8f31f8b58ef73..b2956b70067ba 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/unary_devices.dm
@@ -12,7 +12,7 @@
pipe_interference_group = "atmos-[piping_layer]"\
)
-/obj/machinery/atmospherics/components/unary/SetInitDirections()
+/obj/machinery/atmospherics/components/unary/set_init_directions()
initialize_directions = dir
/obj/machinery/atmospherics/components/unary/on_construction()
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 b52996392bdea..73d92f701884d 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_pump.dm
@@ -1,10 +1,5 @@
-#define EXT_BOUND 1
-#define INT_BOUND 2
#define NO_BOUND 3
-#define SIPHONING 0
-#define RELEASING 1
-
/obj/machinery/atmospherics/components/unary/vent_pump
icon_state = "vent_map-3"
@@ -21,43 +16,62 @@
interacts_with_air = TRUE
- var/pump_direction = RELEASING
-
- var/pressure_checks = EXT_BOUND
+ ///Direction of pumping the gas (ATMOS_DIRECTION_RELEASING or ATMOS_DIRECTION_SIPHONING)
+ var/pump_direction = ATMOS_DIRECTION_RELEASING
+ ///Should we check internal pressure, external pressure, both or none? (ATMOS_EXTERNAL_BOUND, ATMOS_INTERNAL_BOUND, NO_BOUND)
+ var/pressure_checks = ATMOS_EXTERNAL_BOUND
+ ///The external pressure threshold (default 101 kPa)
var/external_pressure_bound = ONE_ATMOSPHERE
+ ///The internal pressure threshold (default 0 kPa)
var/internal_pressure_bound = 0
- // EXT_BOUND: Do not pass external_pressure_bound
- // INT_BOUND: Do not pass internal_pressure_bound
+ // ATMOS_EXTERNAL_BOUND: Do not pass external_pressure_bound
+ // ATMOS_INTERNAL_BOUND: Do not pass internal_pressure_bound
// NO_BOUND: Do not pass either
- var/frequency = FREQ_ATMOS_CONTROL
- var/datum/radio_frequency/radio_connection
- var/radio_filter_out
- var/radio_filter_in
+ /// id of air sensor its connected to
+ var/chamber_id
- var/obj/machinery/advanced_airlock_controller/aac = null
+ ///area this vent is assigned to
+ var/area/assigned_area
-/obj/machinery/atmospherics/components/unary/vent_pump/New()
- if(!id_tag)
- id_tag = id_tag = SSnetworks.assign_random_name()
+/obj/machinery/atmospherics/components/unary/vent_pump/Initialize(mapload)
. = ..()
+ assign_to_area()
+
/obj/machinery/atmospherics/components/unary/vent_pump/Destroy()
- var/area/A = get_area(src)
- if (A)
- A.air_vent_names -= id_tag
- A.air_vent_info -= id_tag
- if(aac)
- aac.vents -= src
-
- SSradio.remove_object(src,frequency)
- radio_connection = null
+ disconnect_from_area()
+
+ var/area/vent_area = get_area(src)
+ if (vent_area)
+ vent_area.air_vents -= src
+
return ..()
+/obj/machinery/atmospherics/components/unary/vent_pump/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
+ . = ..()
+
+ var/area/old_area = get_area(old_loc)
+ var/area/new_area = get_area(src)
+
+ if (old_area == new_area)
+ return
+
+ disconnect_from_area()
+ assign_to_area()
+
+/obj/machinery/atmospherics/components/unary/vent_pump/proc/assign_to_area()
+ var/area/area = get_area(src)
+ area?.air_vents += src
+
+/obj/machinery/atmospherics/components/unary/vent_pump/proc/disconnect_from_area()
+ var/area/area = get_area(src)
+ area?.air_vents -= src
+
/obj/machinery/atmospherics/components/unary/vent_pump/update_icon_nopipes()
cut_overlays()
if(showpipe)
- var/image/cap = getpipeimage(icon, "vent_cap", initialize_directions)
+ var/image/cap = get_pipe_image(icon, "vent_cap", initialize_directions)
add_overlay(cap)
else
PIPING_LAYER_SHIFT(src, PIPING_LAYER_DEFAULT)
@@ -71,14 +85,14 @@
icon_state = "vent_off"
return
- if(pump_direction & RELEASING)
+ if(pump_direction & ATMOS_DIRECTION_RELEASING)
icon_state = "vent_out-off"
else // pump_direction == SIPHONING
icon_state = "vent_in-off"
return
if(icon_state == ("vent_out-off" || "vent_in-off" || "vent_off"))
- if(pump_direction & RELEASING)
+ if(pump_direction & ATMOS_DIRECTION_RELEASING)
icon_state = "vent_out"
flick("vent_out-starting", src)
else // pump_direction == SIPHONING
@@ -86,7 +100,7 @@
flick("vent_in-starting", src)
return
- if(pump_direction & RELEASING)
+ if(pump_direction & ATMOS_DIRECTION_RELEASING)
icon_state = "vent_out"
else // pump_direction == SIPHONING
icon_state = "vent_in"
@@ -108,149 +122,39 @@
var/environment_pressure = environment.return_pressure()
- if(pump_direction & RELEASING) // internal -> external
+ if(pump_direction & ATMOS_DIRECTION_RELEASING) // internal -> external
var/pressure_delta = 10000
- if(pressure_checks&EXT_BOUND)
+ if(pressure_checks&ATMOS_EXTERNAL_BOUND)
pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure))
- if(pressure_checks&INT_BOUND)
+ if(pressure_checks&ATMOS_INTERNAL_BOUND)
pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound))
if(pressure_delta > 0)
if(air_contents.return_temperature() > 0 && air_contents.return_volume() > 0)
- var/transfer_moles = pressure_delta*environment.return_volume()/(air_contents.return_temperature() * R_IDEAL_GAS_EQUATION)
+ var/transfer_moles = (pressure_delta*environment.return_volume())/(air_contents.return_temperature() * R_IDEAL_GAS_EQUATION)
loc.assume_air_moles(air_contents, transfer_moles)
- air_update_turf()
else // external -> internal
if(environment.return_pressure() > 0)
var/our_multiplier = air_contents.return_volume() / (environment.return_temperature() * R_IDEAL_GAS_EQUATION)
var/moles_delta = 10000 * our_multiplier
- if(pressure_checks&EXT_BOUND)
+ if(pressure_checks&ATMOS_EXTERNAL_BOUND)
moles_delta = min(moles_delta, (environment_pressure - external_pressure_bound) * environment.return_volume() / (environment.return_temperature() * R_IDEAL_GAS_EQUATION))
- if(pressure_checks&INT_BOUND)
+ if(pressure_checks&ATMOS_INTERNAL_BOUND)
moles_delta = min(moles_delta, (internal_pressure_bound - air_contents.return_pressure()) * our_multiplier)
if(moles_delta > 0)
loc.transfer_air(air_contents, moles_delta)
- air_update_turf()
update_parents()
-//Radio remote control
-
-/obj/machinery/atmospherics/components/unary/vent_pump/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- if(frequency)
- radio_connection = SSradio.add_object(src, frequency,radio_filter_in)
-
-/obj/machinery/atmospherics/components/unary/vent_pump/proc/broadcast_status()
- if(!radio_connection)
- return
-
- var/datum/signal/signal = new(list(
- "tag" = id_tag,
- "frequency" = frequency,
- "device" = "VP",
- "timestamp" = world.time,
- "power" = on,
- "direction" = pump_direction,
- "checks" = pressure_checks,
- "internal" = internal_pressure_bound,
- "external" = external_pressure_bound,
- "sigtype" = "status",
- "has_aac" = aac != null
- ))
-
- var/area/A = get_area(src)
- if(!A.air_vent_names[id_tag])
- name = "\improper [A.name] vent pump #[A.air_vent_names.len + 1]"
- A.air_vent_names[id_tag] = name
- A.air_vent_info[id_tag] = signal.data
-
- radio_connection.post_signal(src, signal, radio_filter_out)
-
-
-/obj/machinery/atmospherics/components/unary/vent_pump/atmosinit()
- //some vents work his own spesial way
- radio_filter_in = frequency==FREQ_ATMOS_CONTROL?(RADIO_FROM_AIRALARM):null
- radio_filter_out = frequency==FREQ_ATMOS_CONTROL?(RADIO_TO_AIRALARM):null
- if(frequency)
- set_frequency(frequency)
- broadcast_status()
- ..()
-
-/obj/machinery/atmospherics/components/unary/vent_pump/receive_signal(datum/signal/signal)
- if(!is_operational)
- return
- // log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/atmospherics/components/unary/vent_pump/receive_signal([signal.debug_print()])")
- if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
- return
-
- var/atom/signal_sender = signal.data["user"]
-
- if("purge" in signal.data)
- pressure_checks &= ~EXT_BOUND
- pump_direction = SIPHONING
-
- if("stabilize" in signal.data)
- pressure_checks |= EXT_BOUND
- pump_direction = RELEASING
-
- if("power" in signal.data)
- on = text2num(signal.data["power"])
-
- if("power_toggle" in signal.data)
- on = !on
-
- if("checks" in signal.data)
- var/old_checks = pressure_checks
- pressure_checks = text2num(signal.data["checks"])
- if(pressure_checks != old_checks)
- investigate_log(" pressure checks were set to [pressure_checks] by [key_name(signal_sender)]",INVESTIGATE_ATMOS)
-
- if("checks_toggle" in signal.data)
- pressure_checks = (pressure_checks?0:NO_BOUND)
-
- if("direction" in signal.data)
- pump_direction = text2num(signal.data["direction"])
-
- if("set_internal_pressure" in signal.data)
- var/old_pressure = internal_pressure_bound
- internal_pressure_bound = clamp(text2num(signal.data["set_internal_pressure"]),0,ONE_ATMOSPHERE*50)
- if(old_pressure != internal_pressure_bound)
- investigate_log(" internal pressure was set to [internal_pressure_bound] by [key_name(signal_sender)]",INVESTIGATE_ATMOS)
-
- if("set_external_pressure" in signal.data)
- var/old_pressure = external_pressure_bound
- external_pressure_bound = clamp(text2num(signal.data["set_external_pressure"]),0,ONE_ATMOSPHERE*50)
- if(old_pressure != external_pressure_bound)
- investigate_log(" external pressure was set to [external_pressure_bound] by [key_name(signal_sender)]",INVESTIGATE_ATMOS)
-
- if("reset_external_pressure" in signal.data)
- external_pressure_bound = ONE_ATMOSPHERE
-
- if("reset_internal_pressure" in signal.data)
- internal_pressure_bound = 0
-
- if("adjust_internal_pressure" in signal.data)
- internal_pressure_bound = clamp(internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]),0,ONE_ATMOSPHERE*50)
-
- if("adjust_external_pressure" in signal.data)
- external_pressure_bound = clamp(external_pressure_bound + text2num(signal.data["adjust_external_pressure"]),0,ONE_ATMOSPHERE*50)
-
- if("init" in signal.data)
- name = signal.data["init"]
+/obj/machinery/atmospherics/components/unary/vent_pump/update_name()
+ . = ..()
+ if(override_naming)
return
-
- if("status" in signal.data)
- broadcast_status()
- return // do not update_icon
-
- // log_admin("DEBUG \[[world.timeofday]\]: vent_pump/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]")
- broadcast_status()
- update_icon()
+ var/area/vent_area = get_area(src)
+ name = "\proper [vent_area.name] [name] [id_tag]"
/obj/machinery/atmospherics/components/unary/vent_pump/welder_act(mob/living/user, obj/item/I)
if(!I.tool_start_check(user, amount=0))
@@ -303,15 +207,15 @@
/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/New()
..()
var/datum/gas_mixture/air_contents = airs[1]
- air_contents.set_volume(1000)
+ air_contents.volume = 1000
// mapping
-/obj/machinery/atmospherics/components/unary/vent_pump/layer1
+/obj/machinery/atmospherics/components/unary/vent_pump/layer2
piping_layer = 2
icon_state = "vent_map-2"
-/obj/machinery/atmospherics/components/unary/vent_pump/layer3
+/obj/machinery/atmospherics/components/unary/vent_pump/layer4
piping_layer = 4
icon_state = "vent_map-4"
@@ -328,8 +232,8 @@
icon_state = "vent_map_on-4"
/obj/machinery/atmospherics/components/unary/vent_pump/siphon
- pump_direction = SIPHONING
- pressure_checks = INT_BOUND
+ pump_direction = ATMOS_DIRECTION_SIPHONING
+ pressure_checks = ATMOS_INTERNAL_BOUND
internal_pressure_bound = 4000
external_pressure_bound = 0
@@ -353,38 +257,6 @@
piping_layer = 4
icon_state = "vent_map_siphon_on-4"
-/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos
- frequency = FREQ_ATMOS_STORAGE
- on = TRUE
- icon_state = "vent_map_siphon_on-3"
-
-/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/plasma_output
- name = "plasma tank output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_PLASMA
-/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/oxygen_output
- name = "oxygen tank output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_O2
-/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/nitrogen_output
- name = "nitrogen tank output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_N2
-/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/mix_output
- name = "mix tank output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_MIX
-/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/nitrous_output
- name = "nitrous oxide tank output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_N2O
-/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/carbon_output
- name = "carbon dioxide tank output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_CO2
-/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/incinerator_output
- name = "incinerator chamber output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_INCINERATOR
- frequency = FREQ_ATMOS_CONTROL
-/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/toxins_mixing_output
- name = "toxins mixing output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_TOXINS_LAB
- frequency = FREQ_ATMOS_CONTROL
-
/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/layer2
piping_layer = 2
icon_state = "vent_map-2"
@@ -406,8 +278,8 @@
icon_state = "vent_map_on-4"
/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/siphon
- pump_direction = SIPHONING
- pressure_checks = INT_BOUND
+ pump_direction = ATMOS_DIRECTION_SIPHONING
+ pressure_checks = ATMOS_INTERNAL_BOUND
internal_pressure_bound = 2000
external_pressure_bound = 0
@@ -431,47 +303,4 @@
piping_layer = 4
icon_state = "vent_map_siphon_on-4"
-/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/siphon/atmos
- frequency = FREQ_ATMOS_STORAGE
- on = TRUE
- icon_state = "vent_map_siphon_on-3"
-
-/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/siphon/atmos/air_output
- name = "air mix tank output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_AIR
-
-/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/siphon/atmos/toxins_waste_output
- name = "toxins waste output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_TOXINS_WASTE
-
-/obj/machinery/atmospherics/components/unary/vent_pump/high_volume/siphon/atmos/sm_waste
- name = "supermatter waste output inlet"
- id_tag = ATMOS_GAS_MONITOR_OUTPUT_SM_WASTE
-
-#define LAYER_HELPER(FULLPATH)\
-##FULLPATH/layer2 {\
- piping_layer = 2;\
- icon_state = "vent_map_siphon_on-2";\
-}\
-##FULLPATH/layer4 {\
- piping_layer = 4;\
- icon_state = "vent_map_siphon_on-4";\
-}
-
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/plasma_output)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/oxygen_output)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/nitrogen_output)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/mix_output)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/nitrous_output)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/carbon_output)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/incinerator_output)
-LAYER_HELPER(/obj/machinery/atmospherics/components/unary/vent_pump/siphon/atmos/toxins_mixing_output)
-
-#undef LAYER_HELPER
-
-#undef INT_BOUND
-#undef EXT_BOUND
#undef NO_BOUND
-
-#undef SIPHONING
-#undef RELEASING
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 78f7434100d7f..cd85c3813bfc8 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
@@ -1,5 +1,7 @@
#define SIPHONING 0
#define SCRUBBING 1
+///filtered gases at or below this amount automatically get removed from the mix
+#define MINIMUM_MOLES_TO_SCRUB MOLAR_ACCURACY*100
/obj/machinery/atmospherics/components/unary/vent_scrubber
icon_state = "scrub_map-3"
@@ -14,48 +16,137 @@
layer = GAS_SCRUBBER_LAYER
shift_underlay_only = FALSE
hide = TRUE
+ processing_flags = NONE
interacts_with_air = TRUE
- var/scrubbing = SCRUBBING //0 = siphoning, 1 = scrubbing
-
- var/filter_types = list(GAS_CO2, GAS_BZ)
+ ///The mode of the scrubber (ATMOS_DIRECTION_SCRUBBING or ATMOS_DIRECTION_SIPHONING)
+ var/scrubbing = ATMOS_DIRECTION_SCRUBBING
+ ///The list of gases we are filtering
+ var/list/filter_types = list(/datum/gas/carbon_dioxide, /datum/gas/bz)
+ ///Rate of the scrubber to remove gases from the air
var/volume_rate = 200
- var/widenet = 0 //is this scrubber acting on the 3x3 area around it.
+ ///is this scrubber acting on the 3x3 area around it.
+ var/widenet = 0
+ ///List of the turfs near the scrubber, used for widenet
var/list/turf/adjacent_turfs = list()
- var/frequency = FREQ_ATMOS_CONTROL
- var/datum/radio_frequency/radio_connection
- var/radio_filter_out
- var/radio_filter_in
-
pipe_state = "scrubber"
+ COOLDOWN_DECLARE(check_turfs_cooldown)
-/obj/machinery/atmospherics/components/unary/vent_scrubber/New()
- if(!id_tag)
- id_tag = SSnetworks.assign_random_name()
+/obj/machinery/atmospherics/components/unary/vent_scrubber/Initialize(mapload)
. = ..()
+ AddElement(/datum/element/atmos_sensitive, mapload)
/obj/machinery/atmospherics/components/unary/vent_scrubber/Destroy()
- var/area/A = get_area(src)
- if (A)
- A.air_scrub_names -= id_tag
- A.air_scrub_info -= id_tag
-
- SSradio.remove_object(src,frequency)
- radio_connection = null
+ disconnect_from_area()
adjacent_turfs.Cut()
return ..()
+/obj/machinery/atmospherics/components/unary/vent_scrubber/Moved(atom/old_loc, movement_dir, forced, list/old_locs, momentum_change)
+ . = ..()
+
+ var/area/old_area = get_area(old_loc)
+ var/area/new_area = get_area(src)
+
+ if (old_area == new_area)
+ return
+
+ disconnect_from_area()
+ assign_to_area()
+
+/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/assign_to_area()
+ var/area/area = get_area(src)
+ area?.air_scrubbers += src
+
+/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/disconnect_from_area()
+ var/area/area = get_area(src)
+ area?.air_scrubbers -= src
+
+///adds a gas or list of gases to our filter_types. used so that the scrubber can check if its supposed to be processing after each change
+/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/add_filters(filter_or_filters)
+ if(!islist(filter_or_filters))
+ filter_or_filters = list(filter_or_filters)
+
+ for(var/gas_to_filter in filter_or_filters)
+ var/translated_gas = istext(gas_to_filter) ? gas_id2path(gas_to_filter) : gas_to_filter
+
+ if(ispath(translated_gas, /datum/gas))
+ filter_types |= translated_gas
+ continue
+
+ var/turf/open/our_turf = get_turf(src)
+
+ if(!isopenturf(our_turf))
+ return FALSE
+
+ var/datum/gas_mixture/turf_gas = our_turf.air
+ if(!turf_gas)
+ return FALSE
+
+ check_atmos_process(our_turf, turf_gas, turf_gas.temperature)
+ return TRUE
+
+///remove a gas or list of gases from our filter_types.used so that the scrubber can check if its supposed to be processing after each change
+/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/remove_filters(filter_or_filters)
+ if(!islist(filter_or_filters))
+ filter_or_filters = list(filter_or_filters)
+
+ for(var/gas_to_filter in filter_or_filters)
+ var/translated_gas = istext(gas_to_filter) ? gas_id2path(gas_to_filter) : gas_to_filter
+
+ if(ispath(translated_gas, /datum/gas))
+ filter_types -= translated_gas
+ continue
+
+ var/turf/open/our_turf = get_turf(src)
+ var/datum/gas_mixture/turf_gas
+
+ if(isopenturf(our_turf))
+ turf_gas = our_turf.air
+
+ if(!turf_gas)
+ return FALSE
+
+ check_atmos_process(our_turf, turf_gas, turf_gas.temperature)
+ return TRUE
+
+// WARNING: This proc takes untrusted user input from toggle_filter in air alarm's ui_act
+/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/toggle_filters(filter_or_filters)
+ if(!islist(filter_or_filters))
+ filter_or_filters = list(filter_or_filters)
+
+ for(var/gas_to_filter in filter_or_filters)
+ var/translated_gas = istext(gas_to_filter) ? gas_id2path(gas_to_filter) : gas_to_filter
+
+ if(ispath(translated_gas, /datum/gas))
+ if(translated_gas in filter_types)
+ filter_types -= translated_gas
+ else
+ filter_types |= translated_gas
+
+ var/turf/open/our_turf = get_turf(src)
+
+ if(!isopenturf(our_turf))
+ return FALSE
+
+ var/datum/gas_mixture/turf_gas = our_turf.air
+
+ if(!turf_gas)
+ return FALSE
+
+ check_atmos_process(our_turf, turf_gas, turf_gas.temperature)
+ return TRUE
+
/obj/machinery/atmospherics/components/unary/vent_scrubber/auto_use_power()
if(!on || welded || !is_operational || !powered(power_channel))
return FALSE
var/amount = idle_power_usage
- if(scrubbing & SCRUBBING)
+ if(scrubbing == ATMOS_DIRECTION_SCRUBBING)
amount += idle_power_usage * length(filter_types)
- else //scrubbing == SIPHONING
+ else
amount = active_power_usage
if(widenet)
@@ -66,7 +157,7 @@
/obj/machinery/atmospherics/components/unary/vent_scrubber/update_icon_nopipes()
cut_overlays()
if(showpipe)
- var/image/cap = getpipeimage(icon, "scrub_cap", initialize_directions)
+ var/image/cap = get_pipe_image(icon, "scrub_cap", initialize_directions)
add_overlay(cap)
else
PIPING_LAYER_SHIFT(src, PIPING_LAYER_DEFAULT)
@@ -79,59 +170,75 @@
icon_state = "scrub_off"
return
- if(scrubbing & SCRUBBING)
+ if(scrubbing == ATMOS_DIRECTION_SCRUBBING)
if(widenet)
icon_state = "scrub_wide"
else
icon_state = "scrub_on"
- else //scrubbing == SIPHONING
+ else
icon_state = "scrub_purge"
-/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/set_frequency(new_frequency)
- SSradio.remove_object(src, frequency)
- frequency = new_frequency
- radio_connection = SSradio.add_object(src, frequency, radio_filter_in)
+/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/try_update_atmos_process()
+ var/turf/open/turf = get_turf(src)
+ if (!istype(turf))
+ return
+ var/datum/gas_mixture/turf_gas = turf.air
+ if (isnull(turf_gas))
+ return
+ check_atmos_process(turf, turf_gas, turf_gas.temperature)
+
+/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/update_power_usage()
+ idle_power_usage = initial(idle_power_usage)
+ active_power_usage = initial(idle_power_usage)
+ var/new_power_usage = 0
+ if(scrubbing == ATMOS_DIRECTION_SCRUBBING)
+ new_power_usage = idle_power_usage + idle_power_usage * length(filter_types)
+ active_power_usage = IDLE_POWER_USE
+ else
+ new_power_usage = active_power_usage
+ active_power_usage = ACTIVE_POWER_USE
+ if(widenet)
+ new_power_usage += new_power_usage * (length(adjacent_turfs) * (length(adjacent_turfs) / 2))
+ active_power_usage = new_power_usage
+
-/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/broadcast_status()
- if(!radio_connection)
+/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/set_scrubbing(scrubbing, mob/user)
+ src.scrubbing = scrubbing
+ investigate_log(" was toggled to [scrubbing ? "scrubbing" : "siphon"] mode by [isnull(user) ? "the game" : key_name(user)]", INVESTIGATE_ATMOS)
+ update_appearance(UPDATE_ICON)
+ try_update_atmos_process()
+ update_power_usage()
+
+/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/set_widenet(widenet)
+ src.widenet = widenet
+ update_appearance(UPDATE_ICON)
+ update_power_usage()
+
+/obj/machinery/atmospherics/components/unary/vent_scrubber/update_name()
+ . = ..()
+ if(override_naming)
+ return
+ var/area/scrub_area = get_area(src)
+ name = "\proper [scrub_area.name] [name] [id_tag]"
+
+/obj/machinery/atmospherics/components/unary/vent_scrubber/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ if(welded || !is_operational)
+ return FALSE
+ if(!nodes[1] || !on || (!filter_types && scrubbing != ATMOS_DIRECTION_SIPHONING))
+ on = FALSE
return FALSE
- var/list/f_types = list()
- for(var/id in GLOB.gas_data.ids)
- f_types += list(list("gas_id" = id, "gas_name" = GLOB.gas_data.names[id], "enabled" = (id in filter_types)))
-
- var/datum/signal/signal = new(list(
- "tag" = id_tag,
- "frequency" = frequency,
- "device" = "VS",
- "timestamp" = world.time,
- "power" = on,
- "scrubbing" = scrubbing,
- "widenet" = widenet,
- "filter_types" = f_types,
- "sigtype" = "status"
- ))
-
- var/area/A = get_area(src)
- if(!A.air_scrub_names[id_tag])
- name = "\improper [A.name] air scrubber #[A.air_scrub_names.len + 1]"
- A.air_scrub_names[id_tag] = name
-
- A.air_scrub_info[id_tag] = signal.data
- radio_connection.post_signal(src, signal, radio_filter_out)
+ var/list/changed_gas = air.gases
- return TRUE
+ if(!changed_gas)
+ return FALSE
-/obj/machinery/atmospherics/components/unary/vent_scrubber/atmosinit()
- radio_filter_in = frequency==initial(frequency)?(RADIO_FROM_AIRALARM):null
- radio_filter_out = frequency==initial(frequency)?(RADIO_TO_AIRALARM):null
- if(frequency)
- set_frequency(frequency)
- broadcast_status()
- check_turfs()
- ..()
+ if(scrubbing == ATMOS_DIRECTION_SIPHONING || length(filter_types & changed_gas))
+ return TRUE
+
+ return FALSE
-/obj/machinery/atmospherics/components/unary/vent_scrubber/process_atmos()
+/obj/machinery/atmospherics/components/unary/vent_scrubber/atmos_expose(datum/gas_mixture/air, exposed_temperature)
..()
if(welded || !is_operational)
return FALSE
@@ -140,89 +247,59 @@
return FALSE
scrub(loc)
if(widenet)
+ if(COOLDOWN_FINISHED(src, check_turfs_cooldown))
+ check_turfs()
+ COOLDOWN_START(src, check_turfs_cooldown, 2 SECONDS)
for(var/turf/tile in adjacent_turfs)
scrub(tile)
return TRUE
-/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/scrub(var/turf/open/tile)
+/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/scrub(var/turf/tile)
if(!istype(tile))
return FALSE
var/datum/gas_mixture/environment = tile.return_air()
var/datum/gas_mixture/air_contents = airs[1]
+ var/list/env_gases = environment.gases
if(air_contents.return_pressure() >= 50 * ONE_ATMOSPHERE || !islist(filter_types))
return FALSE
if(scrubbing & SCRUBBING)
- environment.scrub_into(air_contents, volume_rate/environment.return_volume(), filter_types)
- tile.air_update_turf()
+ ///contains all of the gas we're sucking out of the tile, gets put into our parent pipenet
+ var/datum/gas_mixture/filtered_out = new
+ var/list/filtered_gases = filtered_out.gases
+ filtered_out.temperature = environment.temperature
+ ///maximum percentage of the turfs gas we can filter
+ var/removal_ratio = min(1, volume_rate / environment.volume)
+ var/total_moles_to_remove = 0
+ for(var/gas in filter_types & env_gases)
+ total_moles_to_remove += env_gases[gas][MOLES]
+ if(total_moles_to_remove == 0)//sometimes this gets non gc'd values
+ environment.garbage_collect()
+ return FALSE
+ for(var/gas in filter_types & env_gases)
+ filtered_out.add_gas(gas)
+ //take this gases portion of removal_ratio of the turfs air, or all of that gas if less than or equal to MINIMUM_MOLES_TO_SCRUB
+ var/transfered_moles = max(QUANTIZE(env_gases[gas][MOLES] * removal_ratio * (env_gases[gas][MOLES] / total_moles_to_remove)), min(MINIMUM_MOLES_TO_SCRUB, env_gases[gas][MOLES]))
+ filtered_gases[gas][MOLES] = transfered_moles
+ env_gases[gas][MOLES] -= transfered_moles
+ environment.garbage_collect()
+ air_contents.merge(filtered_out)
else //Just siphoning all air
- environment.transfer_ratio_to(air_contents, volume_rate/environment.return_volume())
- tile.air_update_turf()
-
+ var/transfer_moles = environment.total_moles() * (volume_rate / environment.volume)
+ var/datum/gas_mixture/removed = tile.remove_air(transfer_moles)
+ air_contents.merge(removed)
update_parents()
-
return TRUE
-//There is no easy way for an object to be notified of changes to atmos can pass flags
-// So we check every machinery process (2 seconds)
-/obj/machinery/atmospherics/components/unary/vent_scrubber/process()
- if(widenet)
- check_turfs()
-
//we populate a list of turfs with nonatmos-blocked cardinal turfs AND
// diagonal turfs that can share atmos with *both* of the cardinal turfs
/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/check_turfs()
adjacent_turfs.Cut()
- var/turf/T = get_turf(src)
- if(istype(T))
- adjacent_turfs = T.GetAtmosAdjacentTurfs(alldir = 1)
-
-/obj/machinery/atmospherics/components/unary/vent_scrubber/receive_signal(datum/signal/signal)
- if(!is_operational || !signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
- return 0
-
- var/atom/signal_sender = signal.data["user"]
-
- if("power" in signal.data)
- on = text2num(signal.data["power"])
- if("power_toggle" in signal.data)
- on = !on
-
- if("widenet" in signal.data)
- widenet = text2num(signal.data["widenet"])
- if("toggle_widenet" in signal.data)
- widenet = !widenet
-
- var/old_scrubbing = scrubbing
- if("scrubbing" in signal.data)
- scrubbing = text2num(signal.data["scrubbing"])
- if("toggle_scrubbing" in signal.data)
- scrubbing = !scrubbing
- if(scrubbing != old_scrubbing)
- investigate_log(" was toggled to [scrubbing ? "scrubbing" : "siphon"] mode by [key_name(signal_sender)]",INVESTIGATE_ATMOS)
-
- if("toggle_filter" in signal.data)
- filter_types ^= signal.data["toggle_filter"]
-
- if("set_filters" in signal.data)
- filter_types = list()
- for(var/gas in signal.data["set_filters"])
- filter_types += gas
-
- if("init" in signal.data)
- name = signal.data["init"]
- return
-
- if("status" in signal.data)
- broadcast_status()
- return //do not update_icon
-
- broadcast_status()
- update_icon()
- return
+ var/turf/local_turf = get_turf(src)
+ adjacent_turfs = local_turf.get_atmos_adjacent_turfs(alldir = TRUE)
/obj/machinery/atmospherics/components/unary/vent_scrubber/power_change()
. = ..()
@@ -290,10 +367,9 @@
icon_state = "scrub_map_on-4"
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/lavaland
- filter_types = list(GAS_CO2, GAS_PLASMA, GAS_H2O, GAS_BZ)
+ filter_types = list(/datum/gas/carbon_dioxide, /datum/gas/plasma, /datum/gas/water_vapor, /datum/gas/bz)
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer4/lavaland
- filter_types = list(GAS_CO2, GAS_PLASMA, GAS_H2O, GAS_BZ)
+ filter_types = list(/datum/gas/carbon_dioxide, /datum/gas/plasma, /datum/gas/water_vapor, /datum/gas/bz)
-#undef SIPHONING
-#undef SCRUBBING
+#undef MINIMUM_MOLES_TO_SCRUB
diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm
index 94b347f1be75e..5930ba4ee705a 100644
--- a/code/modules/atmospherics/machinery/datum_pipeline.dm
+++ b/code/modules/atmospherics/machinery/datum_pipeline.dm
@@ -3,135 +3,192 @@
var/list/datum/gas_mixture/other_airs
var/list/obj/machinery/atmospherics/pipe/members
- var/list/obj/machinery/atmospherics/components/other_atmosmch
+ var/list/obj/machinery/atmospherics/components/other_atmos_machines
+ /// List of other_atmos_machines that have custom_reconcilation set
+ /// We're essentially caching this to avoid needing to filter over it when processing our machines
+ var/list/obj/machinery/atmospherics/components/require_custom_reconcilation
+
+ ///Should we equalize air amoung all our members?
var/update = TRUE
+ ///Is this pipeline being reconstructed?
+ var/building = FALSE
/datum/pipeline/New()
other_airs = list()
members = list()
- other_atmosmch = list()
+ other_atmos_machines = list()
+ require_custom_reconcilation = list()
SSair.networks += src
/datum/pipeline/Destroy()
SSair.networks -= src
- if(air && air.return_volume())
+ if(building)
+ SSair.remove_from_expansion(src)
+ if(air?.volume)
temporarily_store_air()
- for(var/obj/machinery/atmospherics/pipe/P in members)
- P.parent = null
- for(var/obj/machinery/atmospherics/components/C in other_atmosmch)
- C.nullifyPipenet(src)
+ for(var/obj/machinery/atmospherics/pipe/considered_pipe in members)
+ considered_pipe.replace_pipenet(considered_pipe.parent, null)
+ if(QDELETED(considered_pipe))
+ continue
+ SSair.add_to_rebuild_queue(considered_pipe)
+ for(var/obj/machinery/atmospherics/components/considered_component in other_atmos_machines)
+ considered_component.nullify_pipenet(src)
return ..()
/datum/pipeline/process()
- if(update)
- update = FALSE
- reconcile_air()
+ if(!update || building)
+ return
+
+ reconcile_air()
update = air.react(src)
+/datum/pipeline/proc/set_air(datum/gas_mixture/new_air)
+ if(new_air == air)
+ return
+ air = new_air
+
+///Preps a pipeline for rebuilding, inserts it into the rebuild queue
/datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/base)
+ building = TRUE
var/volume = 0
if(istype(base, /obj/machinery/atmospherics/pipe))
- var/obj/machinery/atmospherics/pipe/E = base
- volume = E.volume
- members += E
- if(E.air_temporary)
- air = E.air_temporary
- E.air_temporary = null
+ var/obj/machinery/atmospherics/pipe/considered_pipe = base
+ volume = considered_pipe.volume
+ members += considered_pipe
+ if(considered_pipe.air_temporary)
+ air = considered_pipe.air_temporary
+ considered_pipe.air_temporary = null
else
- addMachineryMember(base)
+ add_machinery_member(base)
+
if(!air)
air = new
+
+ air.volume = volume
+ SSair.add_to_expansion(src, base)
+
+///Has the same effect as build_pipeline(), but this doesn't queue its work, so overrun abounds. It's useful for the pregame
+/datum/pipeline/proc/build_pipeline_blocking(obj/machinery/atmospherics/base)
+ var/volume = 0
+ if(istype(base, /obj/machinery/atmospherics/pipe))
+ var/obj/machinery/atmospherics/pipe/considered_pipe = base
+ volume = considered_pipe.volume
+ members += considered_pipe
+ if(considered_pipe.air_temporary)
+ set_air(considered_pipe.air_temporary)
+ considered_pipe.air_temporary = null
+ else
+ add_machinery_member(base)
+
+ if(!air)
+ set_air(new /datum/gas_mixture)
var/list/possible_expansions = list(base)
- while(possible_expansions.len>0)
+ while(length(possible_expansions))
for(var/obj/machinery/atmospherics/borderline in possible_expansions)
-
var/list/result = borderline.pipeline_expansion(src)
-
- if(result.len>0)
- for(var/obj/machinery/atmospherics/P in result)
- if(istype(P, /obj/machinery/atmospherics/pipe))
- var/obj/machinery/atmospherics/pipe/item = P
- if(!members.Find(item))
-
- if(item.parent)
- var/static/pipenetwarnings = 10
- if(pipenetwarnings > 0)
- log_mapping("build_pipeline(): [item.type] added to a pipenet while still having one. (pipes leading to the same spot stacking in one turf) Nearby: ([item.x], [item.y], [item.z]).")
- pipenetwarnings -= 1
- if(pipenetwarnings == 0)
- log_mapping("build_pipeline(): further messages about pipenets will be suppressed")
- members += item
- possible_expansions += item
-
- volume += item.volume
- item.parent = src
-
- if(item.air_temporary)
- air.merge(item.air_temporary)
- item.air_temporary = null
- else
- P.setPipenet(src, borderline)
- addMachineryMember(P)
+ if(!result?.len)
+ possible_expansions -= borderline
+ continue
+ for(var/obj/machinery/atmospherics/considered_device in result)
+ if(!istype(considered_device, /obj/machinery/atmospherics/pipe))
+ considered_device.set_pipenet(src, borderline)
+ add_machinery_member(considered_device)
+ continue
+ var/obj/machinery/atmospherics/pipe/item = considered_device
+ if(members.Find(item))
+ continue
+ if(item.parent)
+ var/static/pipenetwarnings = 10
+ if(pipenetwarnings > 0)
+ log_mapping("build_pipeline(): [item.type] added to a pipenet while still having one. (pipes leading to the same spot stacking in one turf) around [AREACOORD(item)].")
+ pipenetwarnings--
+ if(pipenetwarnings == 0)
+ log_mapping("build_pipeline(): further messages about pipenets will be suppressed")
+
+ members += item
+ possible_expansions += item
+
+ volume += item.volume
+ item.replace_pipenet(item.parent, src)
+
+ if(item.air_temporary)
+ air.merge(item.air_temporary)
+ item.air_temporary = null
possible_expansions -= borderline
- air.set_volume(volume)
-
-/datum/pipeline/proc/addMachineryMember(obj/machinery/atmospherics/components/C)
- other_atmosmch |= C
- var/datum/gas_mixture/G = C.returnPipenetAir(src)
- if(!G)
- stack_trace("addMachineryMember: Null gasmix added to pipeline datum from [C] which is of type [C.type]. Nearby: ([C.x], [C.y], [C.z])")
- other_airs |= G
-
-/datum/pipeline/proc/addMember(obj/machinery/atmospherics/A, obj/machinery/atmospherics/N)
- if(istype(A, /obj/machinery/atmospherics/pipe))
- var/obj/machinery/atmospherics/pipe/P = A
- if(P.parent)
- merge(P.parent)
- P.parent = src
- var/list/adjacent = P.pipeline_expansion()
- for(var/obj/machinery/atmospherics/pipe/I in adjacent)
- if(I.parent == src)
- continue
- var/datum/pipeline/E = I.parent
- merge(E)
- if(!members.Find(P))
- members += P
- air.set_volume(air.return_volume() + P.volume)
+ air.volume = volume
+
+/**
+ * For a machine to properly "connect" to a pipeline and share gases,
+ * the pipeline needs to acknowledge a gas mixture as it's member.
+ * This is currently handled by the other_airs list in the pipeline datum.
+ *
+ * Other_airs itself is populated by gas mixtures through the parents list that each machineries have.
+* This parents list is populated when a machinery calls update_parents and is then added into the queue by the controller.
+*/
+
+/datum/pipeline/proc/add_machinery_member(obj/machinery/atmospherics/components/considered_component)
+ other_atmos_machines |= considered_component
+ if(considered_component.custom_reconcilation)
+ require_custom_reconcilation |= considered_component
+ var/list/returned_airs = considered_component.return_pipenet_airs(src)
+ if (!length(returned_airs) || (null in returned_airs))
+ stack_trace("add_machinery_member: Nonexistent (empty list) or null machinery gasmix added to pipeline datum from [considered_component] \
+ which is of type [considered_component.type]. Nearby: ([considered_component.x], [considered_component.y], [considered_component.z])")
+ other_airs |= returned_airs
+
+/datum/pipeline/proc/add_member(obj/machinery/atmospherics/reference_device, obj/machinery/atmospherics/device_to_add)
+ if(!istype(reference_device, /obj/machinery/atmospherics/pipe))
+ reference_device.set_pipenet(src, device_to_add)
+ add_machinery_member(reference_device)
else
- A.setPipenet(src, N)
- addMachineryMember(A)
-
-/datum/pipeline/proc/merge(datum/pipeline/E)
- if(E == src)
+ var/obj/machinery/atmospherics/pipe/reference_pipe = reference_device
+ if(reference_pipe.parent)
+ merge(reference_pipe.parent)
+ reference_pipe.replace_pipenet(reference_pipe.parent, src)
+ var/list/adjacent = reference_pipe.pipeline_expansion()
+ for(var/obj/machinery/atmospherics/pipe/adjacent_pipe in adjacent)
+ if(adjacent_pipe.parent == src)
+ continue
+ var/datum/pipeline/parent_pipeline = adjacent_pipe.parent
+ merge(parent_pipeline)
+ if(!members.Find(reference_pipe))
+ members += reference_pipe
+ air.volume += reference_pipe.volume
+
+/datum/pipeline/proc/merge(datum/pipeline/parent_pipeline)
+ if(parent_pipeline == src)
return
- air.set_volume(air.return_volume() + E.air.return_volume())
- members.Add(E.members)
- for(var/obj/machinery/atmospherics/pipe/S in E.members)
- S.parent = src
- air.merge(E.air)
- for(var/obj/machinery/atmospherics/components/C in E.other_atmosmch)
- C.replacePipenet(E, src)
- other_atmosmch.Add(E.other_atmosmch)
- other_airs.Add(E.other_airs)
- E.members.Cut()
- E.other_atmosmch.Cut()
+ air.volume += parent_pipeline.air.volume
+ members.Add(parent_pipeline.members)
+ for(var/obj/machinery/atmospherics/pipe/reference_pipe in parent_pipeline.members)
+ reference_pipe.replace_pipenet(reference_pipe.parent, src)
+ air.merge(parent_pipeline.air)
+ for(var/obj/machinery/atmospherics/components/reference_component in parent_pipeline.other_atmos_machines)
+ reference_component.replace_pipenet(parent_pipeline, src)
+ if(reference_component.custom_reconcilation)
+ require_custom_reconcilation |= reference_component
+ other_atmos_machines |= parent_pipeline.other_atmos_machines
+ other_airs |= parent_pipeline.other_airs
+ parent_pipeline.members.Cut()
+ parent_pipeline.other_atmos_machines.Cut()
+ parent_pipeline.require_custom_reconcilation.Cut()
update = TRUE
- qdel(E)
+ qdel(parent_pipeline)
-/obj/machinery/atmospherics/proc/addMember(obj/machinery/atmospherics/A)
+/obj/machinery/atmospherics/proc/add_member(obj/machinery/atmospherics/considered_device)
return
-/obj/machinery/atmospherics/pipe/addMember(obj/machinery/atmospherics/A)
- parent.addMember(A, src)
+/obj/machinery/atmospherics/pipe/add_member(obj/machinery/atmospherics/considered_device)
+ parent.add_member(considered_device, src)
-/obj/machinery/atmospherics/components/addMember(obj/machinery/atmospherics/A)
- var/datum/pipeline/P = returnPipenet(A)
- if(!P)
- CRASH("null.addMember() called by [type] on [COORD(src)]")
- P.addMember(A, src)
+/obj/machinery/atmospherics/components/add_member(obj/machinery/atmospherics/considered_device)
+ var/datum/pipeline/device_pipeline = return_pipenet(considered_device)
+ if(!device_pipeline)
+ CRASH("null.add_member() called by [type] on [COORD(src)]")
+ device_pipeline.add_member(considered_device, src)
/datum/pipeline/proc/temporarily_store_air()
@@ -139,90 +196,91 @@
for(var/obj/machinery/atmospherics/pipe/member in members)
member.air_temporary = new
- member.air_temporary.set_volume(member.volume)
- member.air_temporary.copy_from(air)
+ member.air_temporary.volume = member.volume
+ member.air_temporary.copy_from_ratio(air, member.volume / air.volume)
- member.air_temporary.multiply(member.volume/air.return_volume())
-
- member.air_temporary.set_temperature(air.return_temperature())
+ member.air_temporary.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.return_volume())
- var/target_temperature
- var/target_heat_capacity
-
- if(isopenturf(target))
+ var/partial_heat_capacity = total_heat_capacity * (share_volume / air.volume)
- var/turf/open/modeled_location = target
- target_temperature = modeled_location.GetTemperature()
- target_heat_capacity = modeled_location.GetHeatCapacity()
+ var/turf_temperature = target.get_temperature()
+ var/turf_heat_capacity = target.get_heat_capacity()
+ if(turf_heat_capacity <= 0 || partial_heat_capacity <= 0)
+ return TRUE
- var/delta_temperature = 0
- var/sharer_heat_capacity = 0
+ var/delta_temperature = turf_temperature - air.temperature
- delta_temperature = (air.return_temperature() - target_temperature)
- sharer_heat_capacity = target_heat_capacity
+ var/heat = thermal_conductivity * CALCULATE_CONDUCTION_ENERGY(delta_temperature, partial_heat_capacity, turf_heat_capacity)
+ air.temperature += heat / total_heat_capacity
+ target.take_temperature(-1 * heat / turf_heat_capacity)
- var/self_temperature_delta = 0
- var/sharer_temperature_delta = 0
+ if(target.blocks_air)
+ target.temperature_expose(air, target.temperature)
+ update = TRUE
- if((sharer_heat_capacity>0) && (partial_heat_capacity>0))
- var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*sharer_heat_capacity/(partial_heat_capacity+sharer_heat_capacity))
+/datum/pipeline/proc/return_air()
+ . = other_airs + air
+ if(list_clear_nulls(.))
+ stack_trace("[src] has one or more null gas mixtures, which may cause bugs. Null mixtures will not be considered in reconcile_air().")
- self_temperature_delta = -heat/total_heat_capacity
- sharer_temperature_delta = heat/sharer_heat_capacity
- else
- return 1
+/datum/pipeline/proc/reconcile_air()
+ var/list/datum/gas_mixture/gas_mixture_list = list()
+ var/list/datum/pipeline/pipeline_list = list()
+ pipeline_list += src
- air.set_temperature(air.return_temperature() + self_temperature_delta)
- modeled_location.TakeTemperature(sharer_temperature_delta)
+ for(var/i = 1; i <= pipeline_list.len; i++) //can't do a for-each here because we may add to the list within the loop
+ var/datum/pipeline/pipeline = pipeline_list[i]
+ if(!pipeline)
+ continue
+ gas_mixture_list += pipeline.other_airs
+ gas_mixture_list += pipeline.air
+ for(var/obj/machinery/atmospherics/components/atmos_machine as anything in pipeline.require_custom_reconcilation)
+ pipeline_list |= atmos_machine.return_pipenets_for_reconcilation(src)
+ gas_mixture_list += atmos_machine.return_airs_for_reconcilation(src)
+ var/total_thermal_energy = 0
+ var/total_heat_capacity = 0
- else
- if((target.heat_capacity>0) && (partial_heat_capacity>0))
- var/delta_temperature = air.return_temperature() - target.return_temperature()
+ var/list/total_gases = list()
- var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
+ var/volume_sum = 0
- air.set_temperature(air.return_temperature() - heat/total_heat_capacity)
- update = TRUE
+ var/static/process_id = 0
+ process_id = (process_id + 1) % (SHORT_REAL_LIMIT - 1)
-/datum/pipeline/proc/return_air()
- . = other_airs + air
- if(null in .)
- stack_trace("[src]([REF(src)]) has one or more null gas mixtures, which may cause bugs. Null mixtures will not be considered in reconcile_air().")
- list_clear_nulls(.)
-
-/datum/pipeline/proc/empty()
- for(var/datum/gas_mixture/GM in get_all_connected_airs())
- GM.clear()
-
-/datum/pipeline/proc/get_all_connected_airs()
- var/list/datum/gas_mixture/GL = list()
- var/list/datum/pipeline/PL = list()
- PL += src
-
- for(var/i = 1; i <= PL.len; i++) //can't do a for-each here because we may add to the list within the loop
- var/datum/pipeline/P = PL[i]
- if(!P)
+ for(var/datum/gas_mixture/gas_mixture as anything in gas_mixture_list)
+ // Ensure we never walk the same mix twice
+ if(gas_mixture.pipeline_cycle == process_id)
+ gas_mixture_list -= gas_mixture
continue
- GL += P.return_air()
- for(var/atmosmch in P.other_atmosmch)
- if (istype(atmosmch, /obj/machinery/atmospherics/components/binary/valve))
- var/obj/machinery/atmospherics/components/binary/valve/V = atmosmch
- if(V.on)
- PL |= V.parents[1]
- PL |= V.parents[2]
- else if (istype(atmosmch, /obj/machinery/atmospherics/components/unary/portables_connector))
- var/obj/machinery/atmospherics/components/unary/portables_connector/C = atmosmch
- if(C.connected_device)
- GL += C.portableConnectorReturnAir()
- return GL
+ gas_mixture.pipeline_cycle = process_id
+ volume_sum += gas_mixture.volume
-/datum/pipeline/proc/reconcile_air()
- var/list/datum/gas_mixture/GL = get_all_connected_airs()
- equalize_all_gases_in_list(GL)
+ // This is sort of a combined merge + heat_capacity calculation
+
+ var/list/giver_gases = gas_mixture.gases
+ var/heat_capacity = 0
+ //gas transfer
+ for(var/giver_id in giver_gases)
+ var/giver_gas_data = giver_gases[giver_id]
+ ASSERT_GAS_IN_LIST(giver_id, total_gases)
+ total_gases[giver_id][MOLES] += giver_gas_data[MOLES]
+ heat_capacity += giver_gas_data[MOLES] * giver_gas_data[GAS_META][META_GAS_SPECIFIC_HEAT]
+
+ total_heat_capacity += heat_capacity
+ total_thermal_energy += gas_mixture.temperature * heat_capacity
+
+ if(volume_sum == 0)
+ return
+
+ var/datum/gas_mixture/total_gas_mixture = new(volume_sum)
+ total_gas_mixture.temperature = total_heat_capacity ? (total_thermal_energy / total_heat_capacity) : 0
+ total_gas_mixture.gases = total_gases
+ total_gas_mixture.garbage_collect()
+
+ //Update individual gas_mixtures by volume ratio
+ for(var/datum/gas_mixture/gas_mixture as anything in gas_mixture_list)
+ gas_mixture.copy_from_ratio(total_gas_mixture, gas_mixture.volume / volume_sum)
diff --git a/code/modules/atmospherics/machinery/other/meter.dm b/code/modules/atmospherics/machinery/other/meter.dm
index 91c8e8bad1f7e..a874b7c5c6c59 100644
--- a/code/modules/atmospherics/machinery/other/meter.dm
+++ b/code/modules/atmospherics/machinery/other/meter.dm
@@ -3,28 +3,18 @@
desc = "It measures something."
icon = 'icons/obj/atmospherics/pipes/meter.dmi'
icon_state = "meterX"
- layer = GAS_PUMP_LAYER
+ layer = HIGH_PIPE_LAYER
power_channel = AREA_USAGE_ENVIRON
use_power = IDLE_POWER_USE
idle_power_usage = 2
- active_power_usage = 4
+ active_power_usage = 9
max_integrity = 150
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 40, ACID = 0, STAMINA = 0, BLEED = 0)
- var/frequency = 0
- var/atom/target
+ greyscale_config = /datum/greyscale_config/meter
+ greyscale_colors = COLOR_GRAY
+ var/obj/machinery/atmospherics/pipe/target
var/target_layer = PIPING_LAYER_DEFAULT
-/obj/machinery/meter/atmos
- frequency = FREQ_ATMOS_STORAGE
-
-/obj/machinery/meter/atmos/atmos_waste_loop
- name = "waste loop gas flow meter"
- id_tag = ATMOS_GAS_MONITOR_LOOP_ATMOS_WASTE
-
-/obj/machinery/meter/atmos/distro_loop
- name = "distribution loop gas flow meter"
- id_tag = ATMOS_GAS_MONITOR_LOOP_DISTRIBUTION
-
CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/meter)
/obj/machinery/meter/Initialize(mapload, new_piping_layer)
@@ -37,7 +27,9 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/meter)
/obj/machinery/meter/Destroy()
SSair.stop_processing_machine(src)
- target = null
+ if(!isnull(target))
+ UnregisterSignal(target, COMSIG_PARENT_QDELETING)
+ target = null
return ..()
/obj/machinery/meter/proc/reattach_to_layer()
@@ -53,23 +45,20 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/meter)
target_layer = new_layer
PIPING_LAYER_DOUBLE_SHIFT(src, target_layer)
-/obj/machinery/meter/process_atmos()
- if(!target)
+/obj/machinery/meter/on_set_is_operational(old_value)
+ if(is_operational)
+ SSair.start_processing_machine(src)//dont set icon_state here because it will be reset on next process() if it ever happens
+ else
icon_state = "meterX"
- return 0
+ SSair.stop_processing_machine(src)
- if(machine_stat & (BROKEN|NOPOWER))
- icon_state = "meter0"
- return 0
-
- use_power(5)
-
- var/datum/gas_mixture/environment = target.return_air()
- if(!environment)
+/obj/machinery/meter/process_atmos()
+ var/datum/gas_mixture/pipe_air = target?.return_air()
+ if(!pipe_air)
icon_state = "meterX"
- return 0
+ return FALSE
- var/env_pressure = environment.return_pressure()
+ var/env_pressure = pipe_air.return_pressure()
if(env_pressure <= 0.15*ONE_ATMOSPHERE)
icon_state = "meter0"
else if(env_pressure <= 1.8*ONE_ATMOSPHERE)
@@ -84,25 +73,38 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/meter)
else
icon_state = "meter4"
- if(frequency)
- var/datum/radio_frequency/radio_connection = SSradio.return_frequency(frequency)
+ var/env_temperature = pipe_air.temperature
- if(!radio_connection)
- return
+ var/new_greyscale = greyscale_colors
- var/datum/signal/signal = new(list(
- "id_tag" = id_tag,
- "device" = "AM",
- "pressure" = round(env_pressure),
- "sigtype" = "status"
- ))
- radio_connection.post_signal(src, signal)
+ if(env_pressure == 0 || env_temperature == 0)
+ new_greyscale = COLOR_GRAY
+ else
+ switch(env_temperature)
+ if(BODYTEMP_HEAT_WARNING_3 to INFINITY)
+ new_greyscale = COLOR_RED
+ if(BODYTEMP_HEAT_WARNING_2 to BODYTEMP_HEAT_WARNING_3)
+ new_greyscale = COLOR_ORANGE
+ if(BODYTEMP_HEAT_WARNING_1 to BODYTEMP_HEAT_WARNING_2)
+ new_greyscale = COLOR_YELLOW
+ if(BODYTEMP_COLD_WARNING_1 to BODYTEMP_HEAT_WARNING_1)
+ new_greyscale = COLOR_VIBRANT_LIME
+ if(BODYTEMP_COLD_WARNING_2 to BODYTEMP_COLD_WARNING_1)
+ new_greyscale = COLOR_CYAN
+ if(BODYTEMP_COLD_WARNING_3 to BODYTEMP_COLD_WARNING_2)
+ new_greyscale = COLOR_BLUE
+ else
+ new_greyscale = COLOR_VIOLET
+
+ if(new_greyscale != greyscale_colors)//dont update if nothing has changed since last update
+ greyscale_colors = new_greyscale
+ set_greyscale(greyscale_colors)
/obj/machinery/meter/proc/status()
if (target)
- var/datum/gas_mixture/environment = target.return_air()
- if(environment)
- . = "The pressure gauge reads [round(environment.return_pressure(), 0.01)] kPa; [round(environment.return_temperature(),0.01)] K ([round(environment.return_temperature()-T0C,0.01)]°C)."
+ var/datum/gas_mixture/pipe_air = target.return_air()
+ if(pipe_air)
+ . = "The pressure gauge reads [round(pipe_air.return_pressure(), 0.01)] kPa; [round(pipe_air.temperature,0.01)] K ([round(pipe_air.temperature-T0C,0.01)]°C)."
else
. = "The sensor error light is blinking."
else
diff --git a/code/modules/atmospherics/machinery/other/miner.dm b/code/modules/atmospherics/machinery/other/miner.dm
index 6f7b4260e1439..f9958625a68c6 100644
--- a/code/modules/atmospherics/machinery/other/miner.dm
+++ b/code/modules/atmospherics/machinery/other/miner.dm
@@ -134,8 +134,9 @@
if(!isopenturf(O))
return FALSE
var/datum/gas_mixture/merger = new
- merger.set_moles(spawn_id, spawn_mol * delta_time)
- merger.set_temperature(spawn_temp)
+ SET_MOLES(spawn_id, merger, spawn_mol * delta_time)
+
+ merger.temperature = (spawn_temp)
O.assume_air(merger)
/obj/machinery/atmospherics/miner/attack_silicon(mob/living/silicon/user)
@@ -146,62 +147,62 @@
/obj/machinery/atmospherics/miner/n2o
name = "\improper N2O Gas Miner"
overlay_color = "#FFCCCC"
- spawn_id = GAS_NITROUS
+ spawn_id = /datum/gas/nitrous_oxide
/obj/machinery/atmospherics/miner/nitrogen
name = "\improper N2 Gas Miner"
overlay_color = "#CCFFCC"
- spawn_id = GAS_N2
+ spawn_id = /datum/gas/nitrogen
/obj/machinery/atmospherics/miner/oxygen
name = "\improper O2 Gas Miner"
overlay_color = "#007FFF"
- spawn_id = GAS_O2
+ spawn_id = /datum/gas/oxygen
/obj/machinery/atmospherics/miner/plasma
name = "\improper Plasma Gas Miner"
overlay_color = "#FF0000"
- spawn_id = GAS_PLASMA
+ spawn_id = /datum/gas/plasma
/obj/machinery/atmospherics/miner/carbon_dioxide
name = "\improper CO2 Gas Miner"
overlay_color = "#CDCDCD"
- spawn_id = GAS_CO2
+ spawn_id = /datum/gas/carbon_dioxide
/obj/machinery/atmospherics/miner/bz
name = "\improper BZ Gas Miner"
overlay_color = "#FAFF00"
- spawn_id = GAS_BZ
+ spawn_id = /datum/gas/bz
/obj/machinery/atmospherics/miner/water_vapor
name = "\improper Water Vapor Gas Miner"
overlay_color = "#99928E"
- spawn_id = GAS_H2O
+ spawn_id = /datum/gas/water_vapor
/obj/machinery/atmospherics/miner/tritium
name = "\improper Tritium Gas Miner"
overlay_color = "#1ae000"
- spawn_id = GAS_TRITIUM
+ spawn_id = /datum/gas/tritium
/obj/machinery/atmospherics/miner/hypernoblium
name = "\improper Hypernoblium Gas Miner"
overlay_color = "#00a6e7"
- spawn_id = GAS_HYPERNOB
+ spawn_id = /datum/gas/hypernoblium
/obj/machinery/atmospherics/miner/nitryl
name = "\improper Nitryl Gas Miner"
overlay_color = "#5e4000"
- spawn_id = GAS_NITRYL
+ spawn_id = /datum/gas/nitryl
/obj/machinery/atmospherics/miner/stimulum
name = "\improper Stimulum Gas Miner"
overlay_color = "#c9c9c9"
- spawn_id = GAS_STIMULUM
+ spawn_id = /datum/gas/stimulum
/obj/machinery/atmospherics/miner/pluoxium
name = "\improper Pluoxium Gas Miner"
overlay_color = "#c5c9b1"
- spawn_id = GAS_PLUOXIUM
+ spawn_id = /datum/gas/pluoxium
/obj/machinery/atmospherics/miner/station
power_draw = GASMINER_POWER_FULLSCALE
@@ -211,37 +212,37 @@
/obj/machinery/atmospherics/miner/station/n2o
name = "\improper N2O Gas Miner"
overlay_color = "#FFCCCC"
- spawn_id = GAS_NITROUS
+ spawn_id = /datum/gas/nitrous_oxide
/obj/machinery/atmospherics/miner/station/nitrogen
name = "\improper N2 Gas Miner"
overlay_color = "#CCFFCC"
- spawn_id = GAS_N2
+ spawn_id = /datum/gas/nitrogen
/obj/machinery/atmospherics/miner/station/oxygen
name = "\improper O2 Gas Miner"
overlay_color = "#007FFF"
- spawn_id = GAS_O2
+ spawn_id = /datum/gas/oxygen
/obj/machinery/atmospherics/miner/station/plasma
name = "\improper Plasma Gas Miner"
overlay_color = "#FF0000"
- spawn_id = GAS_PLASMA
+ spawn_id = /datum/gas/plasma
/obj/machinery/atmospherics/miner/station/carbon_dioxide
name = "\improper CO2 Gas Miner"
overlay_color = "#CDCDCD"
- spawn_id = GAS_CO2
+ spawn_id = /datum/gas/carbon_dioxide
/obj/machinery/atmospherics/miner/station/bz
name = "\improper BZ Gas Miner"
overlay_color = "#FAFF00"
- spawn_id = GAS_BZ
+ spawn_id = /datum/gas/bz
/obj/machinery/atmospherics/miner/station/water_vapor
name = "\improper Water Vapor Gas Miner"
overlay_color = "#99928E"
- spawn_id = GAS_H2O
+ spawn_id = /datum/gas/water_vapor
#undef GASMINER_POWER_NONE
diff --git a/code/modules/atmospherics/machinery/pipes/bridge_pipe.dm b/code/modules/atmospherics/machinery/pipes/bridge_pipe.dm
new file mode 100644
index 0000000000000..eb18ac9b9bc5c
--- /dev/null
+++ b/code/modules/atmospherics/machinery/pipes/bridge_pipe.dm
@@ -0,0 +1,47 @@
+/obj/machinery/atmospherics/pipe/bridge_pipe
+ icon = 'icons/obj/atmospherics/pipes/bridge_pipe.dmi'
+ icon_state = "bridge_center"
+
+ name = "bridge pipe"
+ desc = "A one meter section of regular pipe used to connect pipenets over pipes."
+
+ dir = SOUTH
+ initialize_directions = NORTH | SOUTH
+ pipe_flags = PIPING_CARDINAL_AUTONORMALIZE | PIPING_BRIDGE
+ device_type = BINARY
+
+ construction_type = /obj/item/pipe/binary
+ pipe_state = "bridge_center"
+
+ var/static/list/mutable_appearance/center_cache = list()
+
+/obj/machinery/atmospherics/pipe/bridge_pipe/Initialize()
+ icon_state = ""
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/bridge_pipe/SetInitDirections()
+ switch(dir)
+ if(NORTH, SOUTH)
+ initialize_directions = SOUTH|NORTH
+ if(EAST, WEST)
+ initialize_directions = EAST|WEST
+
+/obj/machinery/atmospherics/pipe/bridge_pipe/update_overlays()
+ . = ..()
+ var/mutable_appearance/center = center_cache["[piping_layer]"]
+ if(!center)
+ center = mutable_appearance(icon, "bridge_center")
+ PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer)
+ center_cache["[piping_layer]"] = center
+ . += center
+
+ layer = HIGH_PIPE_LAYER //to stay above all sorts of pipes
+
+ //Add non-broken pieces
+ for(var/i in 1 to device_type)
+ if(!nodes[i])
+ continue
+ var/image/pipe = getpipeimage('icons/obj/atmospherics/pipes/manifold.dmi', "pipe-[piping_layer]", get_dir(src, nodes[i]))
+ PIPING_LAYER_DOUBLE_SHIFT(pipe, piping_layer)
+ pipe.layer = layer + 0.01
+ . += pipe
diff --git a/code/modules/atmospherics/machinery/pipes/color_adapter.dm b/code/modules/atmospherics/machinery/pipes/color_adapter.dm
new file mode 100644
index 0000000000000..2ce20648efa75
--- /dev/null
+++ b/code/modules/atmospherics/machinery/pipes/color_adapter.dm
@@ -0,0 +1,62 @@
+/obj/machinery/atmospherics/pipe/color_adapter
+ icon = 'icons/obj/atmospherics/pipes/color_adapter.dmi'
+ icon_state = "adapter_map-3"
+
+ name = "color adapter"
+ desc = "A one meter section of regular pipe used to connect different colored pipes."
+
+ dir = SOUTH
+ initialize_directions = NORTH | SOUTH
+ pipe_flags = PIPING_CARDINAL_AUTONORMALIZE | PIPING_ALL_COLORS | PIPING_BRIDGE
+ device_type = BINARY
+
+ construction_type = /obj/item/pipe/binary
+ pipe_state = "adapter_center"
+
+ paintable = FALSE
+ hide = FALSE
+
+ var/static/list/mutable_appearance/center_cache = list()
+
+/obj/machinery/atmospherics/pipe/color_adapter/Initialize()
+ icon_state = ""
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/color_adapter/SetInitDirections()
+ switch(dir)
+ if(NORTH, SOUTH)
+ initialize_directions = SOUTH|NORTH
+ if(EAST, WEST)
+ initialize_directions = EAST|WEST
+
+/obj/machinery/atmospherics/pipe/color_adapter/update_overlays()
+ . = ..()
+ var/mutable_appearance/center = center_cache["[piping_layer]"]
+ if(!center)
+ center = mutable_appearance(icon, "adapter_center")
+ PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer)
+ center_cache["[piping_layer]"] = center
+ . += center
+
+ update_layer()
+
+ //Add non-broken pieces
+ for(var/i in 1 to device_type)
+ if(!nodes[i])
+ continue
+ var/image/pipe = getpipeimage('icons/obj/atmospherics/pipes/manifold.dmi', "pipe-[piping_layer]", get_dir(src, nodes[i]), nodes[i].pipe_color)
+ PIPING_LAYER_DOUBLE_SHIFT(pipe, piping_layer)
+ pipe.layer = layer + 0.01
+ . += pipe
+
+/obj/machinery/atmospherics/pipe/color_adapter/layer1
+ icon_state = "adapter_map-1"
+
+/obj/machinery/atmospherics/pipe/color_adapter/layer2
+ icon_state = "adapter_map-2"
+
+/obj/machinery/atmospherics/pipe/color_adapter/layer4
+ icon_state = "adapter_map-4"
+
+/obj/machinery/atmospherics/pipe/color_adapter/layer5
+ icon_state = "adapter_map-5"
diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm
index b0070488a00af..d761446cfcb0d 100644
--- a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm
+++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm
@@ -14,7 +14,7 @@
add_atom_colour("#404040", FIXED_COLOUR_PRIORITY)
-/obj/machinery/atmospherics/pipe/heat_exchanging/isConnectable(obj/machinery/atmospherics/pipe/heat_exchanging/target, given_layer, HE_type_check = TRUE)
+/obj/machinery/atmospherics/pipe/heat_exchanging/is_connectable(obj/machinery/atmospherics/pipe/heat_exchanging/target, given_layer, HE_type_check = TRUE)
if(istype(target, /obj/machinery/atmospherics/pipe/heat_exchanging) != HE_type_check)
return FALSE
. = ..()
@@ -25,11 +25,11 @@
var/turf/T = loc
if(istype(T))
- if(isclosedturf(T))
+ if(T.blocks_air)
environment_temperature = T.return_temperature()
else
var/turf/open/OT = T
- environment_temperature = OT.GetTemperature()
+ environment_temperature = OT.get_temperature()
else if(T != null)
environment_temperature = T.return_temperature()
@@ -47,7 +47,7 @@
for(var/m in buckled_mobs)
var/mob/living/L = m
L.bodytemperature = avg_temp
- pipe_air.set_temperature(avg_temp)
+ pipe_air.temperature = (avg_temp)
/obj/machinery/atmospherics/pipe/heat_exchanging/process(delta_time)
if(!parent)
diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm
index a5b736806f0fb..502a27a038f42 100644
--- a/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm
+++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm
@@ -15,17 +15,17 @@
construction_type = /obj/item/pipe/directional
pipe_state = "junction"
-/obj/machinery/atmospherics/pipe/heat_exchanging/junction/SetInitDirections()
+/obj/machinery/atmospherics/pipe/heat_exchanging/junction/set_init_directions()
switch(dir)
if(NORTH, SOUTH)
initialize_directions = SOUTH|NORTH
if(EAST, WEST)
initialize_directions = WEST|EAST
-/obj/machinery/atmospherics/pipe/heat_exchanging/junction/getNodeConnects()
+/obj/machinery/atmospherics/pipe/heat_exchanging/junction/get_node_connects()
return list(turn(dir, 180), dir)
-/obj/machinery/atmospherics/pipe/heat_exchanging/junction/isConnectable(obj/machinery/atmospherics/target, given_layer, he_type_check)
+/obj/machinery/atmospherics/pipe/heat_exchanging/junction/is_connectable(obj/machinery/atmospherics/target, given_layer, he_type_check)
if(dir == get_dir(target, src))
return ..(target, given_layer, FALSE) //we want a normal pipe instead
return ..(target, given_layer, TRUE)
diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm
index f02e1a4b75a61..c59c3c743312f 100644
--- a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm
+++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm
@@ -22,7 +22,7 @@
center = mutable_appearance(icon, "manifold_center")
return ..()
-/obj/machinery/atmospherics/pipe/heat_exchanging/manifold/SetInitDirections()
+/obj/machinery/atmospherics/pipe/heat_exchanging/manifold/set_init_directions()
initialize_directions = ALL_CARDINALS
initialize_directions &= ~dir
@@ -35,7 +35,7 @@
//Add non-broken pieces
for(var/i in 1 to device_type)
if(nodes[i])
- add_overlay( getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) )
+ add_overlay( get_pipe_image(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) )
update_layer()
diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm
index 18b4b1923f302..a321f7967e464 100644
--- a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm
+++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm
@@ -21,7 +21,7 @@
center = mutable_appearance(icon, "manifold4w_center")
return ..()
-/obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w/SetInitDirections()
+/obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w/set_init_directions()
initialize_directions = initial(initialize_directions)
/obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w/update_icon()
@@ -33,7 +33,7 @@
//Add non-broken pieces
for(var/i in 1 to device_type)
if(nodes[i])
- add_overlay( getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) )
+ add_overlay( get_pipe_image(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) )
update_layer()
diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/simple.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/simple.dm
index 7a5d9e5e6d1ef..7c43cd771af20 100644
--- a/code/modules/atmospherics/machinery/pipes/heat_exchange/simple.dm
+++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/simple.dm
@@ -14,7 +14,7 @@
construction_type = /obj/item/pipe/binary/bendable
pipe_state = "he"
-/obj/machinery/atmospherics/pipe/heat_exchanging/simple/SetInitDirections()
+/obj/machinery/atmospherics/pipe/heat_exchanging/simple/set_init_directions()
if(dir in GLOB.diagonals)
initialize_directions = dir
return
diff --git a/code/modules/atmospherics/machinery/pipes/layermanifold.dm b/code/modules/atmospherics/machinery/pipes/layermanifold.dm
index d0473acdaab3d..8d94aee411bf2 100644
--- a/code/modules/atmospherics/machinery/pipes/layermanifold.dm
+++ b/code/modules/atmospherics/machinery/pipes/layermanifold.dm
@@ -5,12 +5,12 @@
desc = "A special pipe to bridge pipe layers with."
dir = SOUTH
initialize_directions = NORTH|SOUTH
- pipe_flags = PIPING_ALL_LAYER | PIPING_DEFAULT_LAYER_ONLY | PIPING_CARDINAL_AUTONORMALIZE
+ pipe_flags = PIPING_ALL_LAYER | PIPING_DEFAULT_LAYER_ONLY | PIPING_CARDINAL_AUTONORMALIZE | PIPING_BRIDGE
piping_layer = PIPING_LAYER_DEFAULT
device_type = 0
construction_type = /obj/item/pipe/binary
pipe_state = "manifoldlayer"
- paintable = FALSE
+ paintable = TRUE
///Reference to all the nodes in the front
var/list/front_nodes
@@ -30,59 +30,61 @@
return ..()
/obj/machinery/atmospherics/pipe/layer_manifold/Destroy()
- nullifyAllNodes()
+ nullify_all_nodes()
return ..()
-/obj/machinery/atmospherics/pipe/layer_manifold/proc/nullifyAllNodes()
- var/list/obj/machinery/atmospherics/needs_nullifying = get_all_connected_nodes()
+/obj/machinery/atmospherics/pipe/layer_manifold/proc/nullify_all_nodes()
+ for(var/obj/machinery/atmospherics/node in nodes)
+ node.disconnect(src)
+ SSair.add_to_rebuild_queue(node)
front_nodes = null
back_nodes = null
nodes = list()
- for(var/obj/machinery/atmospherics/A in needs_nullifying)
- if(A != null && src != null) //if it's already null why are we doing this? The answer is byond... it'll always find a way
- A.disconnect(src)
- SSair.add_to_rebuild_queue(A)
-/obj/machinery/atmospherics/pipe/layer_manifold/proc/get_all_connected_nodes()
- return front_nodes + back_nodes + nodes
+/obj/machinery/atmospherics/pipe/layer_manifold/update_layer()
+ layer = initial(layer) + (PIPING_LAYER_MAX * PIPING_LAYER_LCHANGE) //This is above everything else.
-/obj/machinery/atmospherics/pipe/layer_manifold/update_icon()
- cut_overlays()
- layer = initial(layer) + (PIPING_LAYER_MAX * PIPING_LAYER_LCHANGE) //This is above everything else.
+/obj/machinery/atmospherics/pipe/layer_manifold/update_overlays()
+ . = ..()
for(var/node in front_nodes)
- add_attached_images(node)
+ var/list/front_images = get_attached_images(node)
+ if(length(front_images))
+ . += front_images
for(var/node in back_nodes)
- add_attached_images(node)
+ var/list/back_images = get_attached_images(node)
+ if(length(back_images))
+ . += back_images
-/obj/machinery/atmospherics/pipe/layer_manifold/proc/add_attached_images(obj/machinery/atmospherics/A)
- if(!A)
+/obj/machinery/atmospherics/pipe/layer_manifold/proc/get_attached_images(obj/machinery/atmospherics/machine_check)
+ if(!machine_check)
return
- if(istype(A, /obj/machinery/atmospherics/pipe/layer_manifold))
- for(var/i in PIPING_LAYER_MIN to PIPING_LAYER_MAX)
- add_attached_image(get_dir(src, A), i)
- return
- add_attached_image(get_dir(src, A), A.piping_layer, A.pipe_color)
-/obj/machinery/atmospherics/pipe/layer_manifold/proc/add_attached_image(p_dir, p_layer, p_color = null)
- var/image/I
+ . = list()
- if(p_color)
- I = getpipeimage(icon, "pipe", p_dir, p_color, piping_layer = p_layer)
- else
- I = getpipeimage(icon, "pipe", p_dir, piping_layer = p_layer)
+ if(istype(machine_check, /obj/machinery/atmospherics/pipe/layer_manifold))
+ for(var/i in PIPING_LAYER_MIN to PIPING_LAYER_MAX)
+ . += get_attached_image(get_dir(src, machine_check), i, COLOR_VERY_LIGHT_GRAY)
+ return
+ if(istype(machine_check, /obj/machinery/atmospherics/components/unary/airlock_pump))
+ . += get_attached_image(get_dir(src, machine_check), 4, COLOR_BLUE)
+ //. += get_attached_image(get_dir(src, machine_check), 2, COLOR_RED) // Only the distro node is added currently to the pipenet, it doesn't merge the pipenet with the waste node
+ return
+ . += get_attached_image(get_dir(src, machine_check), machine_check.piping_layer, machine_check.pipe_color)
- I.layer = layer - 0.01
- add_overlay(I)
+/obj/machinery/atmospherics/pipe/layer_manifold/proc/get_attached_image(p_dir, p_layer, p_color)
+ var/mutable_appearance/muta = mutable_appearance('icons/obj/atmospherics/pipes/layer_manifold_underlays.dmi', "intact_[p_dir]_[p_layer]", layer = layer - 0.01, appearance_flags = RESET_COLOR)
+ muta.color = p_color
+ return muta
-/obj/machinery/atmospherics/pipe/layer_manifold/SetInitDirections()
+/obj/machinery/atmospherics/pipe/layer_manifold/set_init_directions()
switch(dir)
if(NORTH, SOUTH)
initialize_directions = NORTH|SOUTH
if(EAST, WEST)
initialize_directions = EAST|WEST
-/obj/machinery/atmospherics/pipe/layer_manifold/isConnectable(obj/machinery/atmospherics/target, given_layer)
+/obj/machinery/atmospherics/pipe/layer_manifold/is_connectable(obj/machinery/atmospherics/target, given_layer)
if(!given_layer)
return TRUE
. = ..()
@@ -92,8 +94,8 @@
back_nodes = list()
var/list/new_nodes = list()
for(var/iter in PIPING_LAYER_MIN to PIPING_LAYER_MAX)
- var/obj/machinery/atmospherics/foundfront = findConnecting(dir, iter)
- var/obj/machinery/atmospherics/foundback = findConnecting(turn(dir, 180), iter)
+ var/obj/machinery/atmospherics/foundfront = find_connecting(dir, iter)
+ var/obj/machinery/atmospherics/foundback = find_connecting(turn(dir, 180), iter)
front_nodes += foundfront
back_nodes += foundback
if(foundfront && !QDELETED(foundfront))
@@ -103,29 +105,28 @@
update_appearance()
return new_nodes
-/obj/machinery/atmospherics/pipe/layer_manifold/atmosinit()
+/obj/machinery/atmospherics/pipe/layer_manifold/atmos_init()
normalize_cardinal_directions()
findAllConnections()
-/obj/machinery/atmospherics/pipe/layer_manifold/setPipingLayer()
+/obj/machinery/atmospherics/pipe/layer_manifold/set_piping_layer()
piping_layer = PIPING_LAYER_DEFAULT
/obj/machinery/atmospherics/pipe/layer_manifold/pipeline_expansion()
- return get_all_connected_nodes()
+ return nodes
/obj/machinery/atmospherics/pipe/layer_manifold/disconnect(obj/machinery/atmospherics/reference)
if(istype(reference, /obj/machinery/atmospherics/pipe))
- var/obj/machinery/atmospherics/pipe/P = reference
- P.destroy_network()
- while(reference in get_all_connected_nodes())
- if(reference in nodes)
- var/i = nodes.Find(reference)
- nodes[i] = null
- if(reference in front_nodes)
- var/i = front_nodes.Find(reference)
+ var/obj/machinery/atmospherics/pipe/pipe_reference = reference
+ pipe_reference.destroy_network()
+ while(reference in nodes)
+ var/i = nodes.Find(reference)
+ nodes[i] = null
+ i = front_nodes.Find(reference)
+ if(i)
front_nodes[i] = null
- if(reference in back_nodes)
- var/i = back_nodes.Find(reference)
+ i = back_nodes.Find(reference)
+ if(i)
back_nodes[i] = null
update_appearance()
diff --git a/code/modules/atmospherics/machinery/pipes/manifold.dm b/code/modules/atmospherics/machinery/pipes/manifold.dm
deleted file mode 100644
index 93353618e61ef..0000000000000
--- a/code/modules/atmospherics/machinery/pipes/manifold.dm
+++ /dev/null
@@ -1,50 +0,0 @@
-//3-Way Manifold
-
-/obj/machinery/atmospherics/pipe/manifold
- icon = 'icons/obj/atmospherics/pipes/manifold.dmi'
- icon_state = "manifold-3"
-
- name = "pipe manifold"
- desc = "A manifold composed of regular pipes."
-
- dir = SOUTH
- initialize_directions = EAST|NORTH|WEST
-
- device_type = TRINARY
-
- construction_type = /obj/item/pipe/trinary
- pipe_state = "manifold"
-
- FASTDMM_PROP(\
- pipe_type = PIPE_TYPE_MANIFOLD,\
- pipe_interference_group = "atmos-[piping_layer]"\
- )
-
- var/mutable_appearance/center
-
-/* We use New() instead of Initialize() because these values are used in update_icon()
- * in the mapping subsystem init before Initialize() is called in the atoms subsystem init.
- * This is true for the other manifolds (the 4 ways and the heat exchanges) too.
- */
-/obj/machinery/atmospherics/pipe/manifold/New()
- icon_state = ""
- center = mutable_appearance(icon, "manifold_center")
- return ..()
-
-/obj/machinery/atmospherics/pipe/manifold/SetInitDirections()
- initialize_directions = NORTH|SOUTH|EAST|WEST
- initialize_directions &= ~dir
-
-/obj/machinery/atmospherics/pipe/manifold/update_icon()
- cut_overlays()
- if(!center)
- center = mutable_appearance(icon, "manifold_center")
- PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer)
- add_overlay(center)
-
- //Add non-broken pieces
- for(var/i in 1 to device_type)
- if(nodes[i])
- add_overlay( getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) )
-
- update_layer()
diff --git a/code/modules/atmospherics/machinery/pipes/manifold4w.dm b/code/modules/atmospherics/machinery/pipes/manifold4w.dm
deleted file mode 100644
index 48e47d5405805..0000000000000
--- a/code/modules/atmospherics/machinery/pipes/manifold4w.dm
+++ /dev/null
@@ -1,44 +0,0 @@
-//4-Way Manifold
-
-/obj/machinery/atmospherics/pipe/manifold4w
- icon = 'icons/obj/atmospherics/pipes/manifold.dmi'
- icon_state = "manifold4w-3"
-
- name = "4-way pipe manifold"
- desc = "A manifold composed of regular pipes."
-
- initialize_directions = ALL_CARDINALS
-
- device_type = QUATERNARY
-
- construction_type = /obj/item/pipe/quaternary
- pipe_state = "manifold4w"
-
- FASTDMM_PROP(\
- pipe_type = PIPE_TYPE_MANIFOLD4W,\
- pipe_interference_group = "atmos-[piping_layer]"\
- )
-
- var/mutable_appearance/center
-
-/obj/machinery/atmospherics/pipe/manifold4w/New()
- icon_state = ""
- center = mutable_appearance(icon, "manifold4w_center")
- return ..()
-
-/obj/machinery/atmospherics/pipe/manifold4w/SetInitDirections()
- initialize_directions = initial(initialize_directions)
-
-/obj/machinery/atmospherics/pipe/manifold4w/update_icon()
- cut_overlays()
- if(!center)
- center = mutable_appearance(icon, "manifold_center")
- PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer)
- add_overlay(center)
-
- //Add non-broken pieces
- for(var/i in 1 to device_type)
- if(nodes[i])
- add_overlay( getpipeimage(icon, "pipe-[piping_layer]", get_dir(src, nodes[i])) )
-
- update_layer()
diff --git a/code/modules/atmospherics/machinery/pipes/mapping.dm b/code/modules/atmospherics/machinery/pipes/mapping.dm
index 1be896d3882c6..dce09be9092ed 100644
--- a/code/modules/atmospherics/machinery/pipes/mapping.dm
+++ b/code/modules/atmospherics/machinery/pipes/mapping.dm
@@ -1,84 +1,100 @@
//Colored pipes, use these for mapping
-#define HELPER_PARTIAL(Fulltype, Type, Iconbase, Color) \
- ##Fulltype { \
- pipe_color = Color; \
- color = Color; \
- } \
- ##Fulltype/visible { \
- hide = FALSE; \
- layer = GAS_PIPE_VISIBLE_LAYER; \
- FASTDMM_PROP(pipe_group = "atmos-[piping_layer]-"+Type+"-visible");\
- } \
- ##Fulltype/visible/layer2 { \
- piping_layer = 2; \
- icon_state = Iconbase + "-2"; \
- } \
- ##Fulltype/visible/layer4 { \
- piping_layer = 4; \
- icon_state = Iconbase + "-4"; \
- } \
- ##Fulltype/visible/layer1 { \
- piping_layer = 1; \
- icon_state = Iconbase + "-1"; \
- } \
- ##Fulltype/visible/layer5 { \
- piping_layer = 5; \
- icon_state = Iconbase + "-5"; \
- } \
- ##Fulltype/hidden { \
- hide = TRUE; \
- } \
- ##Fulltype/hidden/layer2 { \
- piping_layer = 2; \
- icon_state = Iconbase + "-2"; \
- } \
- ##Fulltype/hidden/layer4 { \
- piping_layer = 4; \
- icon_state = Iconbase + "-4"; \
- } \
- ##Fulltype/hidden/layer1 { \
- piping_layer = 1; \
- icon_state = Iconbase + "-1"; \
- } \
- ##Fulltype/hidden/layer5 { \
- piping_layer = 5; \
- icon_state = Iconbase + "-5"; \
+#define HELPER_PIPING_LAYER(Fulltype) \
+ ##Fulltype/layer1 { \
+ piping_layer = 1; \
+ } \
+ ##Fulltype/layer2 { \
+ piping_layer = 2; \
+ } \
+ ##Fulltype/layer4 { \
+ piping_layer = 4; \
+ } \
+ ##Fulltype/layer5 { \
+ piping_layer = 5; \
}
-#define HELPER_PARTIAL_NAMED(Fulltype, Type, Iconbase, Color, Name) \
- HELPER_PARTIAL(Fulltype, Type, Iconbase, Color) \
- ##Fulltype { \
- name = Name; \
+#define HELPER_PARTIAL(Fulltype, Iconbase, Color) \
+ HELPER_PIPING_LAYER(Fulltype/visible) \
+ HELPER_PIPING_LAYER(Fulltype/hidden) \
+ ##Fulltype { \
+ pipe_color = Color; \
+ color = Color; \
+ } \
+ ##Fulltype/visible { \
+ hide = FALSE; \
+ layer = GAS_PIPE_VISIBLE_LAYER; \
+ } \
+ ##Fulltype/visible/layer2 { \
+ icon_state = Iconbase + "-2"; \
+ } \
+ ##Fulltype/visible/layer4 { \
+ icon_state = Iconbase + "-4"; \
+ } \
+ ##Fulltype/visible/layer1 { \
+ icon_state = Iconbase + "-1"; \
+ } \
+ ##Fulltype/visible/layer5 { \
+ icon_state = Iconbase + "-5"; \
+ } \
+ ##Fulltype/hidden { \
+ hide = TRUE; \
+ } \
+ ##Fulltype/hidden/layer2 { \
+ icon_state = Iconbase + "-2"; \
+ } \
+ ##Fulltype/hidden/layer4 { \
+ icon_state = Iconbase + "-4"; \
+ } \
+ ##Fulltype/hidden/layer1 { \
+ icon_state = Iconbase + "-1"; \
+ } \
+ ##Fulltype/hidden/layer5 { \
+ icon_state = Iconbase + "-5"; \
+ }
+
+#define HELPER_PARTIAL_NAMED(Fulltype, Iconbase, Name, Color) \
+ HELPER_PARTIAL(Fulltype, Iconbase, Color) \
+ ##Fulltype { \
+ name = Name; \
}
#define HELPER(Type, Color) \
- HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/simple/##Type, #Type, "pipe11", Color) \
- HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/manifold/##Type, #Type, "manifold", Color) \
- HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/manifold4w/##Type, #Type, "manifold4w", Color) \
- HELPER_PARTIAL(/obj/effect/mapping_helpers/simple_pipes/##Type, #Type, "pipe", Color)
+ HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/smart/simple/##Type, "pipe11", Color) \
+ HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/smart/manifold/##Type, "manifold", Color) \
+ HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/smart/manifold4w/##Type, "manifold4w", Color) \
+ HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/bridge_pipe/##Type, "bridge_map", Color) \
+ HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/layer_manifold/##Type, "manifoldlayer", Color) \
+ HELPER_PARTIAL(/obj/machinery/atmospherics/components/binary/pump/off/##Type, "pump_map", Color) \
+ HELPER_PARTIAL(/obj/machinery/atmospherics/components/binary/pump/on/##Type, "pump_on_map", Color) \
+ HELPER_PARTIAL(/obj/machinery/atmospherics/pipe/multiz/##Type, "adapter", Color) \
#define HELPER_NAMED(Type, Name, Color) \
- HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/simple/##Type, #Type, "pipe11", Color, Name) \
- HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/manifold/##Type, #Type, "manifold", Color, Name) \
- HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/manifold4w/##Type, #Type, "manifold4w", Color, Name) \
- HELPER_PARTIAL_NAMED(/obj/effect/mapping_helpers/simple_pipes/##Type, #Type, "pipe", Color, Name)
+ HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/smart/simple/##Type, "pipe11", Name, Color) \
+ HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/smart/manifold/##Type, "manifold", Name, Color) \
+ HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/smart/manifold4w/##Type, "manifold4w", Name, Color) \
+ HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/bridge_pipe/##Type, "bridge_map", Name, Color) \
+ HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/layer_manifold/##Type, "manifoldlayer", Name, Color) \
+ HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/components/binary/pump/off/##Type, "pump_map", Name, Color) \
+ HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/components/binary/pump/on/##Type, "pump_on_map", Name, Color) \
+ HELPER_PARTIAL_NAMED(/obj/machinery/atmospherics/pipe/multiz/##Type, "adapter", Name, Color) \
-HELPER(general, null)
-HELPER(yellow, rgb(255, 198, 0))
-HELPER(cyan, rgb(0, 255, 249))
-HELPER(green, rgb(30, 255, 0))
-HELPER(orange, rgb(255, 129, 25))
-HELPER(purple, rgb(128, 0, 182))
-HELPER(dark, rgb(69, 69, 69))
-HELPER(brown, rgb(178, 100, 56))
-HELPER(violet, rgb(64, 0, 128))
-HELPER(amethyst, rgb(130, 43, 255))
+HELPER(yellow, COLOR_YELLOW)
+HELPER(general, COLOR_VERY_LIGHT_GRAY)
+HELPER(cyan, COLOR_CYAN)
+HELPER(green, COLOR_VIBRANT_LIME)
+HELPER(orange, COLOR_ENGINEERING_ORANGE)
+HELPER(purple, COLOR_PURPLE)
+HELPER(dark, COLOR_DARK)
+HELPER(brown, COLOR_BROWN)
+HELPER(violet, COLOR_STRONG_VIOLET)
+HELPER(pink, COLOR_LIGHT_PINK)
-HELPER_NAMED(scrubbers, "scrubbers pipe", rgb(255, 0, 0))
-HELPER_NAMED(supply, "air supply pipe", rgb(0, 0, 255))
+HELPER_NAMED(scrubbers, "scrubbers pipe", COLOR_RED)
+HELPER_NAMED(supply, "air supply pipe", COLOR_BLUE)
#undef HELPER_NAMED
#undef HELPER
#undef HELPER_PARTIAL_NAMED
#undef HELPER_PARTIAL
+#undef HELPER_PIPING_LAYER
diff --git a/code/modules/atmospherics/machinery/pipes/multiz.dm b/code/modules/atmospherics/machinery/pipes/multiz.dm
index 699e4ab965f8a..8000227d6d0f6 100644
--- a/code/modules/atmospherics/machinery/pipes/multiz.dm
+++ b/code/modules/atmospherics/machinery/pipes/multiz.dm
@@ -32,7 +32,7 @@
pipe = mutable_appearance(icon, "pipe-[piping_layer]")
return ..()
-/obj/machinery/atmospherics/pipe/multiz/SetInitDirections()
+/obj/machinery/atmospherics/pipe/multiz/set_init_directions()
initialize_directions = dir
/obj/machinery/atmospherics/pipe/multiz/update_icon()
@@ -47,11 +47,11 @@
/obj/machinery/atmospherics/pipe/multiz/pipeline_expansion()
var/turf/T = get_turf(src)
for(var/obj/machinery/atmospherics/pipe/multiz/above in GET_TURF_ABOVE(T))
- if(above.piping_layer == piping_layer)
+ if(is_connectable(above, piping_layer))
nodes += above
above.nodes += src // Two way travel :)
for(var/obj/machinery/atmospherics/pipe/multiz/below in GET_TURF_BELOW(T))
- if(below.piping_layer == piping_layer)
+ if(is_connectable(below, piping_layer))
below.pipeline_expansion() // If we've got one below us, force it to add us on facebook
return ..()
diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm
index fe07d92789a8d..f3bc6355a4e26 100644
--- a/code/modules/atmospherics/machinery/pipes/pipes.dm
+++ b/code/modules/atmospherics/machinery/pipes/pipes.dm
@@ -1,10 +1,12 @@
/obj/machinery/atmospherics/pipe
+ damage_deflection = 12
var/datum/gas_mixture/air_temporary //used when reconstructing a pipeline that broke
var/volume = 0
use_power = NO_POWER_USE
can_unwrench = 1
var/datum/pipeline/parent = null
+
paintable = TRUE
//Buckling
@@ -28,84 +30,32 @@
. = ..()
if(hide)
- AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE)
-
-/obj/machinery/atmospherics/pipe/examine(mob/user)
- . = ..()
- . += "[src] is on layer [piping_layer]."
+ AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) //if changing this, change the subtypes RemoveElements too, because thats how bespoke works
-/obj/machinery/atmospherics/pipe/nullifyNode(i)
- var/obj/machinery/atmospherics/oldN = nodes[i]
- ..()
- if(oldN)
- SSair.add_to_rebuild_queue(oldN)
-
-/obj/machinery/atmospherics/pipe/destroy_network()
+/obj/machinery/atmospherics/pipe/on_deconstruction(disassembled)
+ //we delete the parent here so it initializes air_temporary for us. See /datum/pipeline/Destroy() which calls temporarily_store_air()
QDEL_NULL(parent)
-/obj/machinery/atmospherics/pipe/build_network()
- if(QDELETED(parent))
- parent = new
- parent.build_pipeline(src)
-
-/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()
- if(parent)
- return parent.air
-
-/obj/machinery/atmospherics/pipe/return_analyzable_air()
- if(parent)
- return parent.air
-
-/obj/machinery/atmospherics/pipe/remove_air(amount)
- return parent.air.remove(amount)
-
-/obj/machinery/atmospherics/pipe/remove_air_ratio(ratio)
- return parent.air.remove_ratio(ratio)
-
-/obj/machinery/atmospherics/pipe/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/pipe_meter))
- var/obj/item/pipe_meter/meter = W
- user.dropItemToGround(meter)
- meter.setAttachLayer(piping_layer)
- else
- return ..()
-/obj/machinery/atmospherics/pipe/returnPipenet()
- if(parent)
- return parent.air
-
-/obj/machinery/atmospherics/pipe/setPipenet(datum/pipeline/P)
- parent = P
+ return ..()
/obj/machinery/atmospherics/pipe/Destroy()
QDEL_NULL(parent)
+ return ..()
- releaseAirToTurf()
- QDEL_NULL(air_temporary)
-
- var/turf/T = loc
- for(var/obj/machinery/meter/meter in T)
- if(meter.target == src)
- var/obj/item/pipe_meter/PM = new (T)
- meter.transfer_fingerprints_to(PM)
- qdel(meter)
+/obj/machinery/atmospherics/pipe/update_icon()
. = ..()
+ update_layer()
-/obj/machinery/atmospherics/pipe/proc/update_node_icon()
+/obj/machinery/atmospherics/proc/update_node_icon()
for(var/i in 1 to device_type)
if(nodes[i])
var/obj/machinery/atmospherics/N = nodes[i]
N.update_icon()
-/obj/machinery/atmospherics/pipe/returnPipenets()
- . = list(parent)
-
/obj/machinery/atmospherics/pipe/run_atom_armor(damage_amount, damage_type, damage_flag = 0, attack_dir)
if(damage_flag == MELEE && damage_amount < 12)
return 0
@@ -117,3 +67,58 @@
pipe_color = paint_color
update_node_icon()
return paintable
+
+//-----------------
+// PIPENET STUFF
+
+/obj/machinery/atmospherics/pipe/nullify_node(i)
+ var/obj/machinery/atmospherics/old_node = nodes[i]
+ . = ..()
+ if(old_node)
+ SSair.add_to_rebuild_queue(old_node)
+
+/obj/machinery/atmospherics/pipe/destroy_network()
+ QDEL_NULL(parent)
+
+/obj/machinery/atmospherics/pipe/get_rebuild_targets()
+ if(!QDELETED(parent))
+ return
+ replace_pipenet(parent, new /datum/pipeline)
+ return list(parent)
+
+/obj/machinery/atmospherics/pipe/proc/releaseAirToTurf()
+ if(air_temporary)
+ var/turf/T = loc
+ T.assume_air(air_temporary)
+
+/obj/machinery/atmospherics/pipe/return_air()
+ if(air_temporary)
+ return air_temporary
+ return parent.air
+
+/obj/machinery/atmospherics/pipe/return_analyzable_air()
+ if(air_temporary)
+ return air_temporary
+ return parent.air
+
+/obj/machinery/atmospherics/pipe/remove_air(amount)
+ if(air_temporary)
+ return air_temporary.remove(amount)
+ return parent.air.remove(amount)
+
+/obj/machinery/atmospherics/pipe/attackby(obj/item/item, mob/user, params)
+ if(istype(item, /obj/item/pipe_meter))
+ var/obj/item/pipe_meter/meter = item
+ user.dropItemToGround(meter)
+ meter.setAttachLayer(piping_layer)
+ else
+ return ..()
+
+/obj/machinery/atmospherics/pipe/return_pipenet()
+ return parent
+
+/obj/machinery/atmospherics/pipe/replace_pipenet(datum/pipeline/old_pipenet, datum/pipeline/new_pipenet)
+ parent = new_pipenet
+
+/obj/machinery/atmospherics/pipe/return_pipenets()
+ . = list(parent)
diff --git a/code/modules/atmospherics/machinery/pipes/simple.dm b/code/modules/atmospherics/machinery/pipes/simple.dm
deleted file mode 100644
index da6fab8c66d0d..0000000000000
--- a/code/modules/atmospherics/machinery/pipes/simple.dm
+++ /dev/null
@@ -1,37 +0,0 @@
-// Simple Pipe
-// The regular pipe you see everywhere, including bent ones.
-
-/obj/machinery/atmospherics/pipe/simple
- icon = 'icons/obj/atmospherics/pipes/simple.dmi'
- icon_state = "pipe11-3"
-
- name = "pipe"
- desc = "A one meter section of regular pipe."
-
- dir = SOUTH
- initialize_directions = SOUTH|NORTH
- pipe_flags = PIPING_CARDINAL_AUTONORMALIZE
-
- device_type = BINARY
-
- construction_type = /obj/item/pipe/binary/bendable
- pipe_state = "simple"
-
- FASTDMM_PROP(\
- pipe_type = PIPE_TYPE_SIMPLE,\
- pipe_interference_group = "atmos-[piping_layer]"\
- )
-
-/obj/machinery/atmospherics/pipe/simple/SetInitDirections()
- if(dir in GLOB.diagonals)
- initialize_directions = dir
- return
- switch(dir)
- if(NORTH, SOUTH)
- initialize_directions = SOUTH|NORTH
- if(EAST, WEST)
- initialize_directions = EAST|WEST
-
-/obj/machinery/atmospherics/pipe/simple/update_icon()
- icon_state = "pipe[nodes[1] ? "1" : "0"][nodes[2] ? "1" : "0"]-[piping_layer]"
- update_layer()
diff --git a/code/modules/atmospherics/machinery/pipes/smart.dm b/code/modules/atmospherics/machinery/pipes/smart.dm
new file mode 100644
index 0000000000000..faee2e747036c
--- /dev/null
+++ b/code/modules/atmospherics/machinery/pipes/smart.dm
@@ -0,0 +1,114 @@
+GLOBAL_LIST_INIT(atmos_components, typecacheof(list(/obj/machinery/atmospherics)))
+
+/obj/machinery/atmospherics/pipe/smart
+ icon = 'icons/obj/atmospherics/pipes/simple.dmi'
+ icon_state = "pipe11-3"
+
+ name = "pipe"
+ desc = "A one meter section of regular pipe."
+
+ vis_flags = VIS_INHERIT_ICON | VIS_INHERIT_ICON_STATE | VIS_INHERIT_DIR | VIS_INHERIT_ID
+
+ device_type = QUATERNARY
+ construction_type = /obj/item/pipe/quaternary
+ pipe_state = "manifold4w"
+ connection_num = 0
+ var/list/connections
+ var/static/list/mutable_appearance/center_cache = list()
+ var/mutable_appearance/pipe_appearance
+
+/* We use New() instead of Initialize() because these values are used in update_icon()
+ * in the mapping subsystem init before Initialize() is called in the atoms subsystem init.
+ */
+/obj/machinery/atmospherics/pipe/smart/Initialize()
+ icon_state = ""
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/smart/SetInitDirections()
+ initialize_directions = ALL_CARDINALS
+
+/obj/machinery/atmospherics/pipe/smart/proc/check_connections()
+ var/mutable_appearance/center
+ connection_num = 0
+ connections = NONE
+ for(var/direction in GLOB.cardinals)
+ var/turf/turf = get_step(src, direction)
+ if(!turf)
+ continue
+ for(var/obj/machinery/atmospherics/machine in turf)
+ if(connection_check(machine, piping_layer))
+ connections |= direction
+ connection_num++
+ break
+
+ switch(connection_num)
+ if(0)
+ center = mutable_appearance('icons/obj/atmospherics/pipes/manifold.dmi', "manifold4w_center")
+ dir = SOUTH
+ if(1)
+ center = mutable_appearance('icons/obj/atmospherics/pipes/simple.dmi', "pipe00-3")
+ dir = connections
+ if(2)
+ center = mutable_appearance('icons/obj/atmospherics/pipes/simple.dmi', "pipe00-3")
+ dir = check_binary_direction(connections)
+ if(3)
+ center = mutable_appearance('icons/obj/atmospherics/pipes/manifold.dmi', "manifold_center")
+ dir = check_manifold_direction(connections)
+
+ if(4)
+ center = mutable_appearance('icons/obj/atmospherics/pipes/manifold.dmi', "manifold4w_center")
+ dir = NORTH
+ return center
+
+/obj/machinery/atmospherics/pipe/smart/proc/check_binary_direction(direction)
+ switch(direction)
+ if(EAST|WEST)
+ return EAST
+ if(SOUTH|NORTH)
+ return SOUTH
+ else
+ return direction
+
+/obj/machinery/atmospherics/pipe/smart/proc/check_manifold_direction(direction)
+ switch(direction)
+ if(NORTH|SOUTH|EAST)
+ return WEST
+ if(NORTH|SOUTH|WEST)
+ return EAST
+ if(NORTH|WEST|EAST)
+ return SOUTH
+ if(SOUTH|WEST|EAST)
+ return NORTH
+ else
+ return null
+
+/obj/machinery/atmospherics/pipe/smart/update_overlays()
+ . = ..()
+ var/mutable_appearance/center = center_cache["[piping_layer]"]
+ center = check_connections()
+ PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer)
+ center_cache["[piping_layer]"] = center
+ pipe_appearance = center
+ . += center
+
+ update_layer()
+
+ //Add non-broken pieces
+ for(var/i in 1 to device_type)
+ if(!nodes[i])
+ continue
+ . += pipe_overlay('icons/obj/atmospherics/pipes/manifold.dmi', "pipe-[piping_layer]", get_dir(src, nodes[i]), set_layer = (layer + 0.01))
+
+
+//mapping helpers
+/obj/machinery/atmospherics/pipe/smart/simple
+ icon = 'icons/obj/atmospherics/pipes/simple.dmi'
+ icon_state = "pipe11-3"
+
+/obj/machinery/atmospherics/pipe/smart/manifold
+ icon = 'icons/obj/atmospherics/pipes/manifold.dmi'
+ icon_state = "manifold-3"
+
+/obj/machinery/atmospherics/pipe/smart/manifold4w
+ icon = 'icons/obj/atmospherics/pipes/manifold.dmi'
+ icon_state = "manifold4w-3"
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index 9939d30ac3fb9..c6e760875f5c3 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -1,4 +1,7 @@
+///The default pressure for releasing air into an holding tank or the turf
#define CAN_DEFAULT_RELEASE_PRESSURE (ONE_ATMOSPHERE)
+///The temperature resistance of this canister
+#define TEMPERATURE_RESISTANCE (1000 + T0C)
/obj/machinery/portable_atmospherics/canister
name = "canister"
@@ -8,35 +11,34 @@
greyscale_config = /datum/greyscale_config/canister/hazard
greyscale_colors = "#ffff00#000000"
density = TRUE
- volume = 1000
+ volume = 2000
armor = list(MELEE = 50, BULLET = 50, LASER = 50, ENERGY = 100, BOMB = 10, BIO = 100, RAD = 100, FIRE = 80, ACID = 50, STAMINA = 0, BLEED = 0)
- max_integrity = 250
+ max_integrity = 300
integrity_failure = 0.4
pressure_resistance = 7 * ONE_ATMOSPHERE
req_access = list()
var/icon/canister_overlay_file = 'icons/obj/atmospherics/canisters.dmi'
+ ///Is the valve open?
var/valve_open = FALSE
+ ///Used to log opening and closing of the valve, available on VV
var/release_log = ""
+ ///How much the canister should be filled (recommended from 0 to 1)
var/filled = 0.5
- var/gas_type
+ ///Maximum pressure allowed on initialize inside the canister, multiplied by the filled var
+ var/maximum_pressure = 90 * ONE_ATMOSPHERE
+ ///Stores the path of the gas for mapped canisters
+ var/datum/gas/gas_type
+ ///Player controlled var that set the release pressure of the canister
var/release_pressure = ONE_ATMOSPHERE
- var/can_max_release_pressure = (ONE_ATMOSPHERE * 10)
- var/can_min_release_pressure = (ONE_ATMOSPHERE / 10)
- var/temperature_resistance = 1000 + T0C
- var/starter_temp = T20C
- // Prototype vars
- var/prototype = FALSE
- var/valve_timer = null
- var/timer_set = 30
- var/default_timer_set = 30
- var/minimum_timer_set = 1
- var/maximum_timer_set = 300
- var/timing = FALSE
- var/restricted = FALSE
-
- var/update = 0
+ ///Is shielding turned on/off
+ var/shielding_powered = FALSE
+ ///The powercell used to enable shielding
+ var/obj/item/stock_parts/cell/internal_cell
+ ///used while processing to update appearance only when its pressure state changes
+ var/current_pressure_state
+ ///List of all the gases, used in labelling the canisters
var/static/list/label2types = list(
"n2" = /obj/machinery/portable_atmospherics/canister/nitrogen,
"o2" = /obj/machinery/portable_atmospherics/canister/oxygen,
@@ -54,199 +56,47 @@
"caution" = /obj/machinery/portable_atmospherics/canister,
)
-/obj/machinery/portable_atmospherics/canister/Initialize(mapload)
+/obj/machinery/portable_atmospherics/canister/Initialize(mapload, datum/gas_mixture/existing_mixture)
. = ..()
- AddComponent(/datum/component/usb_port, list(/obj/item/circuit_component/canister_valve))
-
-/obj/item/circuit_component/canister_valve
- display_name = "Canister Valve"
- desc = "The interface for communicating with a canister's valve."
-
- var/obj/machinery/portable_atmospherics/canister/attached_can
+ if(mapload)
+ internal_cell = new /obj/item/stock_parts/cell/high(src)
- /// Toggles the canister's valve
- var/datum/port/input/toggle
- /// Set's the can's target pressure value
- var/datum/port/input/pressure
+ if(existing_mixture)
+ air_contents.copy_from(existing_mixture)
+ else
+ create_gas()
-/obj/item/circuit_component/canister_valve/populate_ports()
- toggle = add_input_port("Toggle", PORT_TYPE_SIGNAL)
- pressure = add_input_port("Target Pressure", PORT_TYPE_NUMBER)
+ if(ispath(gas_type, /datum/gas))
+ desc = "[GLOB.meta_gas_info[gas_type][META_GAS_NAME]]. [GLOB.meta_gas_info[gas_type][META_GAS_DESC]]"
-/obj/item/circuit_component/canister_valve/register_usb_parent(atom/movable/shell)
- . = ..()
- if(istype(shell, /obj/machinery/portable_atmospherics/canister))
- attached_can = shell
+ var/random_quality = rand()
+ pressure_limit = initial(pressure_limit) * (1 + 0.2 * random_quality)
-/obj/item/circuit_component/canister_valve/unregister_usb_parent(atom/movable/shell)
- attached_can = null
- return ..()
+ update_icon()
+ AddComponent(/datum/component/usb_port, list(/obj/item/circuit_component/canister_valve))
+ AddElement(/datum/element/atmos_sensitive, mapload)
+ AddElement(/datum/element/volatile_gas_storage)
+ AddComponent(/datum/component/gas_leaker, leak_rate=0.01)
-/obj/item/circuit_component/canister_valve/input_received(datum/port/input/port)
+/obj/machinery/portable_atmospherics/canister/examine(user)
. = ..()
- if(.)
- return
-
- if(!attached_can)
- return
-
- var/logmsg
-
- if(COMPONENT_TRIGGERED_BY(toggle, port))
- logmsg = "Valve was toggled by [parent.get_creator_admin()]'s circuit, starting a transfer into \the [attached_can.holding || "air"].
"
- if(!attached_can.holding)
- var/list/danger = list()
- for(var/id in attached_can.air_contents.get_gases())
- if(!(GLOB.gas_data.flags[id] & GAS_FLAG_DANGEROUS))
- continue
- if(attached_can.air_contents.get_moles(id) > (GLOB.gas_data.visibility[id] || MOLES_GAS_VISIBLE)) //if moles_visible is undefined, default to default visibility
- danger[GLOB.gas_data.names[id]] = attached_can.air_contents.get_moles(id) //ex. "plasma" = 20
-
- if(danger.len && attached_can.valve_open)
- message_admins("[parent.get_creator_admin()]'s circuit opened a canister that contains the following at [ADMIN_VERBOSEJMP(attached_can)]:")
- log_admin("[parent.get_creator_admin()]'s circuit opened a canister that contains the following at [AREACOORD(attached_can)]:")
- for(var/name in danger)
- var/msg = "[name]: [danger[name]] moles."
- log_admin(msg)
- message_admins(msg)
- attached_can.set_valve()
- attached_can.release_log += logmsg
- if(COMPONENT_TRIGGERED_BY(pressure, port))
- attached_can.release_pressure = clamp(round(pressure), attached_can.can_min_release_pressure, attached_can.can_max_release_pressure)
- investigate_log("[attached_can.name] was set to [pressure] kPa by [parent.get_creator()]'s circuit'.", INVESTIGATE_ATMOS)
+ if(atom_integrity < max_integrity)
+ . += "Integrity compromised, repair hull with a welding tool."
+ . += "A sticker on its side says MAX SAFE PRESSURE: [siunit_pressure(initial(pressure_limit), 0)]; MAX SAFE TEMPERATURE: [siunit(temp_limit, "K", 0)]."
+ . += "The hull is welded together and can be cut apart."
+ if(internal_cell)
+ . += "The internal cell has [internal_cell.percent()]% of its total charge."
+ else
+ . += "Warning, no cell installed, use a screwdriver to open the hatch and insert one."
+ if(panel_open)
+ . += "Hatch open, close it with a screwdriver."
/obj/machinery/portable_atmospherics/canister/interact(mob/user)
+ . = ..()
if(!allowed(user))
to_chat(user, "Error - Unauthorized User")
playsound(src, 'sound/misc/compiler-failure.ogg', 50, 1)
return
- ..()
-
-/obj/machinery/portable_atmospherics/canister/air
- name = "air canister"
- desc = "Pre-mixed air."
- greyscale_config = /datum/greyscale_config/canister
- greyscale_colors = "#c6c0b5"
-
-/obj/machinery/portable_atmospherics/canister/bz
- name = "\improper BZ canister"
- desc = "BZ, a powerful hallucinogenic nerve agent."
- gas_type = GAS_BZ
- greyscale_config = /datum/greyscale_config/canister/double_stripe
- greyscale_colors = "#9b5d7f#d0d2a0"
-
-/obj/machinery/portable_atmospherics/canister/carbon_dioxide
- name = "co2 canister"
- desc = "Carbon dioxide. What the fuck is carbon dioxide?"
- gas_type = GAS_CO2
- greyscale_config = /datum/greyscale_config/canister
- greyscale_colors = "#4e4c48"
-
-/obj/machinery/portable_atmospherics/canister/nitrogen
- name = "n2 canister"
- desc = "Nitrogen gas. Reportedly useful for something."
- gas_type = GAS_N2
- greyscale_config = /datum/greyscale_config/canister
- greyscale_colors = "#d41010"
-
-/obj/machinery/portable_atmospherics/canister/nitrous_oxide
- name = "n2o canister"
- desc = "Nitrous oxide gas. Known to cause drowsiness."
- gas_type = GAS_NITROUS
- greyscale_config = /datum/greyscale_config/canister/double_stripe
- greyscale_colors = "#c63e3b#f7d5d3"
-
-/obj/machinery/portable_atmospherics/canister/nitryl
- name = "nitryl canister"
- desc = "Nitryl gas. Feels great 'til the acid eats your lungs."
- gas_type = GAS_NITRYL
- greyscale_config = /datum/greyscale_config/canister
- greyscale_colors = "#7b4732"
-
-/obj/machinery/portable_atmospherics/canister/nob
- name = "hyper-noblium canister"
- desc = "Hyper-Noblium. More noble than all other gases."
- gas_type = GAS_HYPERNOB
- greyscale_config = /datum/greyscale_config/canister/double_stripe
- greyscale_colors = "#6399fc#b2b2b2"
-
-/obj/machinery/portable_atmospherics/canister/oxygen
- name = "o2 canister"
- desc = "Oxygen. Necessary for human life."
- gas_type = GAS_O2
- greyscale_config = /datum/greyscale_config/canister/stripe
- greyscale_colors = "#2786e5#e8fefe"
-
-/obj/machinery/portable_atmospherics/canister/pluoxium
- name = "pluoxium canister"
- desc = "Pluoxium. Like oxygen, but more bang for your buck."
- gas_type = GAS_PLUOXIUM
- greyscale_config = /datum/greyscale_config/canister
- greyscale_colors = "#2786e5"
-
-/obj/machinery/portable_atmospherics/canister/stimulum
- name = "stimulum canister"
- desc = "Stimulum. High energy gas, high energy people."
- gas_type = GAS_STIMULUM
- greyscale_config = /datum/greyscale_config/canister
- greyscale_colors = "#9b5d7f"
-
-/obj/machinery/portable_atmospherics/canister/plasma
- name = "plasma canister"
- desc = "Plasma gas. The reason YOU are here. Highly toxic."
- gas_type = GAS_PLASMA
- greyscale_config = /datum/greyscale_config/canister/hazard
- greyscale_colors = "#f64300#000000"
-
-/obj/machinery/portable_atmospherics/canister/tritium
- name = "tritium canister"
- desc = "Tritium. Inhalation might cause irradiation."
- gas_type = GAS_TRITIUM
- greyscale_config = /datum/greyscale_config/canister/hazard
- greyscale_colors = "#3fcd40#000000"
-
-/obj/machinery/portable_atmospherics/canister/water_vapor
- name = "water vapor canister"
- desc = "Water Vapor. We get it, you vape."
- gas_type = GAS_H2O
- filled = 1
- greyscale_config = /datum/greyscale_config/canister/double_stripe
- greyscale_colors = "#4c4e4d#f7d5d3"
-
-
-/obj/machinery/portable_atmospherics/canister/proc/get_time_left()
- if(timing)
- . = round(max(0, valve_timer - world.time) / 10, 1)
- else
- . = timer_set
-
-/obj/machinery/portable_atmospherics/canister/proc/set_active()
- timing = !timing
- if(timing)
- valve_timer = world.time + (timer_set * 10)
- update_icon()
-
-/obj/machinery/portable_atmospherics/canister/proto
- name = "prototype canister"
- greyscale_config = /datum/greyscale_config/prototype_canister
- greyscale_colors = "#ffffff#a50021#ffffff"
-
-/obj/machinery/portable_atmospherics/canister/proto/default
- name = "prototype canister"
- desc = "The best way to fix an atmospheric emergency... or the best way to introduce one."
- volume = 5000
- max_integrity = 300
- temperature_resistance = 2000 + T0C
- can_max_release_pressure = (ONE_ATMOSPHERE * 30)
- can_min_release_pressure = (ONE_ATMOSPHERE / 30)
- prototype = TRUE
-
-/obj/machinery/portable_atmospherics/canister/proto/default/oxygen
- name = "prototype canister"
- desc = "A prototype canister for a prototype bike, what could go wrong?"
- gas_type = GAS_O2
- filled = 1
- release_pressure = ONE_ATMOSPHERE*2
/obj/machinery/portable_atmospherics/canister/vv_get_dropdown()
. = ..()
@@ -267,95 +117,132 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/portable_atmospherics/canister)
create_gas()
update_icon()
-
-/obj/machinery/portable_atmospherics/canister/proc/create_gas()
- if(gas_type)
- if(starter_temp)
- air_contents.set_temperature(starter_temp)
- if(!air_contents.return_volume())
- CRASH("Auxtools is failing somehow! Gas with pointer [air_contents._extools_pointer_gasmixture] is not valid.")
- air_contents.set_moles(gas_type, (maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
-
-/obj/machinery/portable_atmospherics/canister/air/create_gas()
- air_contents.set_temperature(starter_temp)
- air_contents.set_moles(GAS_O2, (O2STANDARD * maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
- air_contents.set_moles(GAS_N2, (N2STANDARD * maximum_pressure * filled) * air_contents.return_volume() / (R_IDEAL_GAS_EQUATION * air_contents.return_temperature()))
-
/obj/machinery/portable_atmospherics/canister/update_icon()
. = ..()
update_overlays()
/obj/machinery/portable_atmospherics/canister/update_overlays()
. = ..()
- if(machine_stat & BROKEN)
- . += mutable_appearance(canister_overlay_file, "broken")
- return
- var/last_update = update
- update = 0
+ if(shielding_powered)
+ . += mutable_appearance(canister_overlay_file, "shielding")
+ . += emissive_appearance(canister_overlay_file, "shielding", src)
+
+ if(panel_open)
+ . += mutable_appearance(canister_overlay_file, "cell_hatch")
+ if(machine_stat & BROKEN)
+ . += mutable_appearance(canister_overlay_file, "broken")
if(holding)
. += mutable_appearance(canister_overlay_file, "can-open")
if(connected_port)
. += mutable_appearance(canister_overlay_file, "can-connector")
- var/pressure = air_contents.return_pressure()
- switch(pressure)
- if((40 * ONE_ATMOSPHERE) to INFINITY)
- . += mutable_appearance(canister_overlay_file, "can-3")
- if((10 * ONE_ATMOSPHERE) to (40 * ONE_ATMOSPHERE))
- . += mutable_appearance(canister_overlay_file, "can-2")
- if((5 * ONE_ATMOSPHERE) to (10 * ONE_ATMOSPHERE))
- . += mutable_appearance(canister_overlay_file, "can-1")
- if((10) to (5 * ONE_ATMOSPHERE))
- . += mutable_appearance(canister_overlay_file, "can-0")
- if(update == last_update)
- return
+ var/light_state = get_pressure_state()
+ if(light_state) //happens when pressure is below 10kpa which means no light
+ . += mutable_appearance(canister_overlay_file, light_state)
+ . += emissive_appearance(canister_overlay_file, "[light_state]-light", layer, src.alpha)
-/obj/machinery/portable_atmospherics/canister/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > temperature_resistance)
- take_damage(5, BURN, 0)
+/obj/machinery/portable_atmospherics/canister/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return (exposed_temperature > TEMPERATURE_RESISTANCE && !shielding_powered)
+/obj/machinery/portable_atmospherics/canister/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ take_damage(5, BURN, 0)
-/obj/machinery/portable_atmospherics/canister/deconstruct(disassembled = TRUE)
- if(!(flags_1 & NODECONSTRUCT_1))
- if(!(machine_stat & BROKEN))
- canister_break()
- if(disassembled)
- new /obj/item/stack/sheet/iron (loc, 10)
+/obj/machinery/portable_atmospherics/canister/on_deconstruction(disassembled = TRUE)
+ if(!(machine_stat & BROKEN))
+ canister_break()
+ if(!disassembled)
+ new /obj/item/stack/sheet/iron (drop_location(), 5)
+ qdel(src)
+ return
+ new /obj/item/stack/sheet/iron (drop_location(), 10)
+ if(internal_cell)
+ internal_cell.forceMove(drop_location())
+
+/obj/machinery/portable_atmospherics/canister/attackby(obj/item/item, mob/user, params)
+ if(istype(item, /obj/item/stock_parts/cell))
+ var/obj/item/stock_parts/cell/active_cell = item
+ if(!panel_open)
+ balloon_alert(user, "open hatch first!")
+ return TRUE
+ if(!user.transferItemToLoc(active_cell, src))
+ return TRUE
+ if(internal_cell)
+ user.put_in_hands(internal_cell)
+ balloon_alert(user, "you replace the cell")
else
- new /obj/item/stack/sheet/iron (loc, 5)
- qdel(src)
+ balloon_alert(user, "you install the cell")
+ internal_cell = active_cell
+ return TRUE
+ return ..()
+
+/obj/machinery/portable_atmospherics/canister/screwdriver_act(mob/living/user, obj/item/screwdriver)
+ if(default_deconstruction_screwdriver(user, icon_state, icon_state, screwdriver))
+ update_appearance()
+ return TRUE
+
+/obj/machinery/portable_atmospherics/canister/crowbar_act(mob/living/user, obj/item/tool)
+ if(!panel_open || !internal_cell)
+ return TRUE
+
+ internal_cell.forceMove(drop_location())
+ balloon_alert(user, "cell removed")
+ return TRUE
/obj/machinery/portable_atmospherics/canister/welder_act(mob/living/user, obj/item/I)
+ . = ..()
if(user.a_intent == INTENT_HARM)
- return FALSE
+ return FALSE //We're attacking the canister.
- if(machine_stat & BROKEN)
- if(!I.tool_start_check(user, amount=0))
+ if(atom_integrity < max_integrity)
+ to_chat(user, "You begin welding [src] back together...")
+ if(I.use_tool(src, user, 3 SECONDS, volume=50))
+ update_integrity(max_integrity)
+ to_chat(user, "You weld [src] back together.")
return TRUE
- to_chat(user, "You begin cutting [src] apart...")
- if(I.use_tool(src, user, 30, volume=50))
- deconstruct(TRUE)
- else
- to_chat(user, "You cannot slice [src] apart when it isn't broken.")
+
+ var/pressure = air_contents.return_pressure()
+ if(pressure > 300)
+ to_chat(user, "The pressure gauge on [src] indicates a high pressure inside... maybe you want to reconsider?")
+ message_admins("[src] deconstructed by [ADMIN_LOOKUPFLW(user)]")
+ user.log_message("deconstructed [src] with a welder.", LOG_GAME)
+ to_chat(user, "You begin cutting [src] apart...")
+ if(I.use_tool(src, user, 5 SECONDS, volume=50))
+ to_chat(user, "You cut [src] apart.")
+ deconstruct(TRUE)
return TRUE
+/obj/machinery/portable_atmospherics/canister/Exited(atom/movable/gone, direction)
+ . = ..()
+ if(gone == internal_cell)
+ internal_cell = null
+
+/obj/machinery/portable_atmospherics/canister/take_damage(damage_amount, damage_type = BRUTE, damage_flag = "", sound_effect = TRUE, attack_dir, armour_penetration = 0)
+ . = ..()
+ if(!. || QDELETED(src))
+ return
+ SSair.start_processing_machine(src)
+
/obj/machinery/portable_atmospherics/canister/atom_break(damage_flag)
. = ..()
if(!.)
return
canister_break()
+/**
+ * Handle canisters disassemble, releases the gas content in the turf
+ */
/obj/machinery/portable_atmospherics/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(air_contents)
- air_update_turf()
+ T.assume_air(expelled_gas)
+
+ atom_break()
- set_machine_stat(machine_stat | BROKEN)
- density = FALSE
+ set_density(FALSE)
playsound(src.loc, 'sound/effects/spray.ogg', 10, 1, -3)
update_icon()
investigate_log("was destroyed.", INVESTIGATE_ATMOS)
@@ -377,22 +264,67 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/portable_atmospherics/canister)
else if(valve_open && holding)
user.investigate_log("started a transfer into [holding].", INVESTIGATE_ATMOS)
+/obj/machinery/portable_atmospherics/canister/process(seconds_per_tick)
+ if(!shielding_powered)
+ return
+
+ var/our_pressure = air_contents.return_pressure()
+ var/our_temperature = air_contents.return_temperature()
+ var/energy_factor = round(log(10, max(our_pressure - pressure_limit, 1)) + log(10, max(our_temperature - temp_limit, 1)))
+ var/energy_consumed = energy_factor * 250 * seconds_per_tick
+
+ if(!energy_consumed)
+ return
+
+ if(powered(AREA_USAGE_EQUIP))
+ use_power(energy_consumed, AREA_USAGE_EQUIP)
+ else if(!internal_cell?.use(energy_consumed * 0.025))
+ shielding_powered = FALSE
+ SSair.start_processing_machine(src)
+ investigate_log("shielding turned off due to power loss")
+ update_icon()
+
+///return the icon_state component for the canister's indicator light based on its current pressure reading
+/obj/machinery/portable_atmospherics/canister/proc/get_pressure_state()
+ var/air_pressure = air_contents.return_pressure()
+ switch(air_pressure)
+ if((40 * ONE_ATMOSPHERE) to INFINITY)
+ return "can-3"
+ if((10 * ONE_ATMOSPHERE) to (40 * ONE_ATMOSPHERE))
+ return "can-2"
+ if((5 * ONE_ATMOSPHERE) to (10 * ONE_ATMOSPHERE))
+ return "can-1"
+ if((10) to (5 * ONE_ATMOSPHERE))
+ return "can-0"
+ else
+ return null
+
/obj/machinery/portable_atmospherics/canister/process_atmos()
- ..()
if(machine_stat & BROKEN)
return PROCESS_KILL
- if(timing && valve_timer < world.time)
- valve_open = !valve_open
- timing = FALSE
// Handle gas transfer.
if(valve_open)
- var/turf/T = get_turf(src)
- var/datum/gas_mixture/target_air = holding ? holding.air_contents : T.return_air()
+ var/turf/location = get_turf(src)
+ var/datum/gas_mixture/target_air = holding?.return_air() || location.return_air()
+ excited = TRUE
- if(air_contents.release_gas_to(target_air, release_pressure) && !holding)
- air_update_turf()
- update_icon()
+ if(air_contents.release_gas_to(target_air, release_pressure))
+ if(!holding)
+ air_update_turf(FALSE, FALSE)
+
+ // A bit different than other atmos devices. Wont stop if currently taking damage.
+ if(take_atmos_damage())
+ update_icon()
+ excited = TRUE
+ return ..() //we have already updated appearance so dont need to update again below
+
+ var/new_pressure_state = get_pressure_state()
+ if(current_pressure_state != new_pressure_state) //update apperance only when its pressure changes significantly from its current value
+ update_icon()
+ current_pressure_state = new_pressure_state
+
+ return ..()
/obj/machinery/portable_atmospherics/canister/ui_status(mob/user)
. = ..()
@@ -409,31 +341,30 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/portable_atmospherics/canister)
ui.open()
ui.set_autoupdate(TRUE) // Canister pressure, tank pressure, prototype canister timer
+/obj/machinery/portable_atmospherics/canister/ui_static_data(mob/user)
+ return list(
+ "defaultReleasePressure" = round(CAN_DEFAULT_RELEASE_PRESSURE),
+ "minReleasePressure" = round(CAN_MIN_RELEASE_PRESSURE),
+ "maxReleasePressure" = round(CAN_MAX_RELEASE_PRESSURE),
+ "pressureLimit" = round(pressure_limit),
+ "holdingTankLeakPressure" = round(TANK_LEAK_PRESSURE),
+ "holdingTankFragPressure" = round(TANK_FRAGMENT_PRESSURE)
+ )
+
/obj/machinery/portable_atmospherics/canister/ui_data()
var/data = list()
data["portConnected"] = connected_port ? 1 : 0
data["tankPressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
- data["releasePressure"] = round(release_pressure ? release_pressure : 0)
- data["defaultReleasePressure"] = round(CAN_DEFAULT_RELEASE_PRESSURE)
- data["minReleasePressure"] = round(can_min_release_pressure)
- data["maxReleasePressure"] = round(can_max_release_pressure)
data["valveOpen"] = valve_open ? 1 : 0
-
- data["isPrototype"] = prototype ? 1 : 0
- if (prototype)
- data["restricted"] = restricted
- data["timing"] = timing
- data["time_left"] = get_time_left()
- data["timer_set"] = timer_set
- data["timer_is_not_default"] = timer_set != default_timer_set
- data["timer_is_not_min"] = timer_set != minimum_timer_set
- data["timer_is_not_max"] = timer_set != maximum_timer_set
-
data["hasHoldingTank"] = holding ? 1 : 0
if (holding)
+ var/datum/gas_mixture/holding_mix = holding.return_air()
data["holdingTank"] = list()
data["holdingTank"]["name"] = holding.name
- data["holdingTank"]["tankPressure"] = round(holding.air_contents.return_pressure())
+ data["holdingTank"]["tankPressure"] = round(holding_mix.return_pressure())
+
+ data["shielding"] = shielding_powered
+ data["cellCharge"] = internal_cell ? internal_cell.percent() : 0
return data
/obj/machinery/portable_atmospherics/canister/ui_act(action, params)
@@ -450,78 +381,39 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/portable_atmospherics/canister)
desc = initial(replacement.desc)
icon_state = initial(replacement.icon_state)
set_greyscale(initial(replacement.greyscale_colors), initial(replacement.greyscale_config))
- if("restricted")
- if(!prototype)
- return // Prototype canister only feature
- restricted = !restricted
- if(restricted)
- req_access = list(ACCESS_ENGINE)
- else
- req_access = list()
- . = TRUE
if("pressure")
var/pressure = params["pressure"]
if(pressure == "reset")
pressure = CAN_DEFAULT_RELEASE_PRESSURE
. = TRUE
else if(pressure == "min")
- pressure = can_min_release_pressure
+ pressure = CAN_MIN_RELEASE_PRESSURE
. = TRUE
else if(pressure == "max")
- pressure = can_max_release_pressure
+ pressure = CAN_MAX_RELEASE_PRESSURE
. = TRUE
else if(pressure == "input")
- pressure = input("New release pressure ([can_min_release_pressure]-[can_max_release_pressure] kPa):", name, release_pressure) as num|null
+ pressure = input("New release pressure ([CAN_MIN_RELEASE_PRESSURE]-[CAN_MAX_RELEASE_PRESSURE] kPa):", name, release_pressure) as num|null
if(!isnull(pressure) && !..())
. = TRUE
else if(text2num(pressure) != null)
pressure = text2num(pressure)
. = TRUE
if(.)
- release_pressure = clamp(round(pressure), can_min_release_pressure, can_max_release_pressure)
+ release_pressure = clamp(round(pressure), CAN_MIN_RELEASE_PRESSURE, CAN_MAX_RELEASE_PRESSURE)
investigate_log("was set to [release_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS)
if("valve")
- set_valve(usr)
+ toggle_valve(usr)
. = TRUE
- /* // Apparently the timer isn't present in TGUI - commenting out so it can't be used via exploits
- if("timer")
- if(!prototype)
- return
- var/change = params["change"]
- switch(change)
- if("reset")
- timer_set = default_timer_set
- . = TRUE
- if("decrease")
- timer_set = max(minimum_timer_set, timer_set - 10)
- . = TRUE
- if("increase")
- timer_set = min(maximum_timer_set, timer_set + 10)
- . = TRUE
- if("input")
- var/user_input = input(usr, "Set time to valve toggle.", name) as null|num
- if(!user_input)
- return
- var/N = text2num(user_input)
- if(!N)
- return
- timer_set = clamp(N,minimum_timer_set,maximum_timer_set)
- log_admin("[key_name(usr)] has activated a prototype valve timer")
- . = TRUE
- if("toggle_timer")
- set_active()
- . = TRUE
- */
if("eject")
- if(holding)
- if(valve_open)
- message_admins("[ADMIN_LOOKUPFLW(usr)] removed [holding] from [src] with valve still open at [ADMIN_VERBOSEJMP(src)] releasing contents into the air.")
- usr.investigate_log(" removed the [holding], leaving the valve open and transferring into the air.", INVESTIGATE_ATMOS)
- replace_tank(usr, FALSE)
+ if(eject_tank(usr))
. = TRUE
+ if("shielding")
+ toggle_shielding(usr)
+ . = TRUE
update_icon()
-/obj/machinery/portable_atmospherics/canister/proc/set_valve(mob/user)
+/obj/machinery/portable_atmospherics/canister/proc/toggle_valve(mob/user)
var/logmsg
valve_open = !valve_open
if(valve_open)
@@ -530,11 +422,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/portable_atmospherics/canister)
logmsg = "Valve was opened by [key_name(user)], starting a transfer into \the [holding || "air"].
"
if(!holding)
var/list/danger = list()
- for(var/id in air_contents.get_gases())
- if(!(GLOB.gas_data.flags[id] & GAS_FLAG_DANGEROUS))
+ for(var/id in air_contents.gases)
+ if(!(GLOB.meta_gas_info[id][META_GAS_DANGER]))
continue
- if(air_contents.get_moles(id) > (GLOB.gas_data.visibility[id] || MOLES_GAS_VISIBLE)) //if moles_visible is undefined, default to default visibility
- danger[GLOB.gas_data.names[id]] = air_contents.get_moles(id) //ex. "plasma" = 20
+ if(air_contents.gases[id][MOLES] > (GLOB.meta_gas_info[id][META_GAS_MOLES_VISIBLE] || MOLES_GAS_VISIBLE)) //if moles_visible is undefined, default to default visibility
+ danger[GLOB.meta_gas_info[id][META_GAS_NAME]] = air_contents.gases[id][MOLES] //ex. "plasma" = 20
if(danger.len && user)
message_admins("[ADMIN_LOOKUPFLW(user)] opened a canister that contains the following at [ADMIN_VERBOSEJMP(src)]:")
@@ -550,4 +442,214 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/portable_atmospherics/canister)
investigate_log(logmsg, INVESTIGATE_ATMOS)
release_log += logmsg
+/// Turns canister shielding on or off
+/obj/machinery/portable_atmospherics/canister/proc/toggle_shielding(mob/user, wire_pulsed = FALSE)
+ shielding_powered = !shielding_powered
+ SSair.start_processing_machine(src)
+ message_admins("[ADMIN_LOOKUPFLW(user)] turned [shielding_powered ? "on" : "off"] [wire_pulsed ? "via wire pulse" : ""] the [src] powered shielding.")
+ user.investigate_log("turned [shielding_powered ? "on" : "off"] [wire_pulsed ? "via wire pulse" : ""] the [src] powered shielding.")
+ update_icon()
+
+/// Ejects tank from canister, if any
+/obj/machinery/portable_atmospherics/canister/proc/eject_tank(mob/user, wire_pulsed = FALSE)
+ if(!holding)
+ return FALSE
+ if(valve_open)
+ message_admins("[ADMIN_LOOKUPFLW(user)] removed [holding] from [src] with valve still open [wire_pulsed ? "via wire pulse" : ""] at [ADMIN_VERBOSEJMP(src)] releasing contents into the air.")
+ user.investigate_log("removed the [holding] [wire_pulsed ? "via wire pulse" : ""], leaving the valve open and transferring into the air.", INVESTIGATE_ATMOS)
+ replace_tank(user, FALSE)
+ return TRUE
+
+/obj/machinery/portable_atmospherics/canister/unregister_holding()
+ valve_open = FALSE
+ return ..()
+
+/obj/machinery/portable_atmospherics/canister/take_atmos_damage()
+ return shielding_powered ? FALSE : ..()
+
+//////////// Circuit stuffs! ///////////////////////////////////////////////////
+
+/obj/item/circuit_component/canister_valve
+ display_name = "Canister Valve"
+ desc = "The interface for communicating with a canister's valve."
+
+ var/obj/machinery/portable_atmospherics/canister/attached_can
+
+ /// Toggles the canister's valve
+ var/datum/port/input/toggle
+ /// Set's the can's target pressure value
+ var/datum/port/input/pressure
+
+/obj/item/circuit_component/canister_valve/populate_ports()
+ toggle = add_input_port("Toggle", PORT_TYPE_SIGNAL)
+ pressure = add_input_port("Target Pressure", PORT_TYPE_NUMBER)
+
+/obj/item/circuit_component/canister_valve/register_usb_parent(atom/movable/shell)
+ . = ..()
+ if(istype(shell, /obj/machinery/portable_atmospherics/canister))
+ attached_can = shell
+
+/obj/item/circuit_component/canister_valve/unregister_usb_parent(atom/movable/shell)
+ attached_can = null
+ return ..()
+
+/obj/item/circuit_component/canister_valve/input_received(datum/port/input/port)
+ . = ..()
+ if(.)
+ return
+
+ if(!attached_can)
+ return
+
+ var/logmsg
+
+ if(COMPONENT_TRIGGERED_BY(toggle, port))
+ logmsg = "Valve was toggled by [parent.get_creator_admin()]'s circuit, starting a transfer into \the [attached_can.holding || "air"].
"
+ if(!attached_can.holding)
+ var/list/danger = list()
+ var/datum/gas_mixture/attached_can_air = attached_can.return_air()
+ for(var/id in attached_can_air.gases)
+ if(!(GLOB.meta_gas_info[id][META_GAS_DANGER]))
+ continue
+ if(attached_can_air.gases[id][MOLES] > (GLOB.meta_gas_info[id][META_GAS_MOLES_VISIBLE] || MOLES_GAS_VISIBLE)) //if moles_visible is undefined, default to default visibility
+ danger[GLOB.meta_gas_info[id][META_GAS_NAME]] = attached_can_air.gases[id][MOLES] //ex. "plasma" = 20
+
+ if(danger.len && attached_can.valve_open)
+ message_admins("[parent.get_creator_admin()]'s circuit opened a canister that contains the following at [ADMIN_VERBOSEJMP(attached_can)]:")
+ log_admin("[parent.get_creator_admin()]'s circuit opened a canister that contains the following at [AREACOORD(attached_can)]:")
+ for(var/name in danger)
+ var/msg = "[name]: [danger[name]] moles."
+ log_admin(msg)
+ message_admins(msg)
+ attached_can.toggle_valve()
+ attached_can.release_log += logmsg
+ if(COMPONENT_TRIGGERED_BY(pressure, port))
+ attached_can.release_pressure = clamp(round(pressure), CAN_MIN_RELEASE_PRESSURE, CAN_MAX_RELEASE_PRESSURE)
+ investigate_log("[attached_can.name] was set to [pressure] kPa by [parent.get_creator()]'s circuit'.", INVESTIGATE_ATMOS)
+
+///////////////////Canister Presets////////////////////////////////////
+
+/obj/machinery/portable_atmospherics/canister/air
+ name = "air canister"
+ desc = "Pre-mixed air."
+ greyscale_config = /datum/greyscale_config/canister
+ greyscale_colors = "#c6c0b5"
+
+/obj/machinery/portable_atmospherics/canister/bz
+ name = "\improper BZ canister"
+ desc = "BZ, a powerful hallucinogenic nerve agent."
+ gas_type = /datum/gas/bz
+ greyscale_config = /datum/greyscale_config/canister/double_stripe
+ greyscale_colors = "#9b5d7f#d0d2a0"
+
+/obj/machinery/portable_atmospherics/canister/carbon_dioxide
+ name = "co2 canister"
+ desc = "Carbon dioxide. What the fuck is carbon dioxide?"
+ gas_type = /datum/gas/carbon_dioxide
+ greyscale_config = /datum/greyscale_config/canister
+ greyscale_colors = "#4e4c48"
+
+/obj/machinery/portable_atmospherics/canister/nitrogen
+ name = "n2 canister"
+ desc = "Nitrogen gas. Reportedly useful for something."
+ gas_type = /datum/gas/nitrogen
+ greyscale_config = /datum/greyscale_config/canister
+ greyscale_colors = "#d41010"
+
+/obj/machinery/portable_atmospherics/canister/nitrous_oxide
+ name = "n2o canister"
+ desc = "Nitrous oxide gas. Known to cause drowsiness."
+ gas_type = /datum/gas/nitrous_oxide
+ greyscale_config = /datum/greyscale_config/canister/double_stripe
+ greyscale_colors = "#c63e3b#f7d5d3"
+
+/obj/machinery/portable_atmospherics/canister/nitryl
+ name = "nitryl canister"
+ desc = "Nitryl gas. Feels great 'til the acid eats your lungs."
+ gas_type = /datum/gas/nitryl
+ greyscale_config = /datum/greyscale_config/canister
+ greyscale_colors = "#7b4732"
+
+/obj/machinery/portable_atmospherics/canister/nob
+ name = "hyper-noblium canister"
+ desc = "Hyper-Noblium. More noble than all other gases."
+ gas_type = /datum/gas/hypernoblium
+ greyscale_config = /datum/greyscale_config/canister/double_stripe
+ greyscale_colors = "#6399fc#b2b2b2"
+
+/obj/machinery/portable_atmospherics/canister/oxygen
+ name = "o2 canister"
+ desc = "Oxygen. Necessary for human life."
+ gas_type = /datum/gas/oxygen
+ greyscale_config = /datum/greyscale_config/canister/stripe
+ greyscale_colors = "#2786e5#e8fefe"
+
+/obj/machinery/portable_atmospherics/canister/pluoxium
+ name = "pluoxium canister"
+ desc = "Pluoxium. Like oxygen, but more bang for your buck."
+ gas_type = /datum/gas/pluoxium
+ greyscale_config = /datum/greyscale_config/canister
+ greyscale_colors = "#2786e5"
+
+/obj/machinery/portable_atmospherics/canister/stimulum
+ name = "stimulum canister"
+ desc = "Stimulum. High energy gas, high energy people."
+ gas_type = /datum/gas/stimulum
+ greyscale_config = /datum/greyscale_config/canister
+ greyscale_colors = "#9b5d7f"
+
+/obj/machinery/portable_atmospherics/canister/plasma
+ name = "plasma canister"
+ desc = "Plasma gas. The reason YOU are here. Highly toxic."
+ gas_type = /datum/gas/plasma
+ greyscale_config = /datum/greyscale_config/canister/hazard
+ greyscale_colors = "#f64300#000000"
+
+/obj/machinery/portable_atmospherics/canister/tritium
+ name = "tritium canister"
+ desc = "Tritium. Inhalation might cause irradiation."
+ gas_type = /datum/gas/tritium
+ greyscale_config = /datum/greyscale_config/canister/hazard
+ greyscale_colors = "#3fcd40#000000"
+
+/obj/machinery/portable_atmospherics/canister/water_vapor
+ name = "water vapor canister"
+ desc = "Water Vapor. We get it, you vape."
+ gas_type = /datum/gas/water_vapor
+ filled = 1
+ greyscale_config = /datum/greyscale_config/canister/double_stripe
+ greyscale_colors = "#4c4e4d#f7d5d3"
+
+/obj/machinery/portable_atmospherics/canister/fusion_test
+ name = "fusion test canister"
+ desc = "Don't be a badmin."
+ temp_limit = 1e12
+ pressure_limit = 1e14
+
+/**
+ * Called on Initialize(), fill the canister with the gas_type specified up to the filled level (half if 0.5, full if 1)
+ * Used for canisters spawned in maps and by admins
+ */
+/obj/machinery/portable_atmospherics/canister/proc/create_gas()
+ if(!gas_type)
+ return
+ air_contents.add_gas(gas_type)
+ air_contents.gases[gas_type][MOLES] = (maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ SSair.start_processing_machine(src)
+
+/obj/machinery/portable_atmospherics/canister/air/create_gas()
+ air_contents.add_gases(/datum/gas/oxygen, /datum/gas/nitrogen)
+ air_contents.gases[/datum/gas/oxygen][MOLES] = (O2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ air_contents.gases[/datum/gas/nitrogen][MOLES] = (N2STANDARD * maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature)
+ SSair.start_processing_machine(src)
+
+/obj/machinery/portable_atmospherics/canister/fusion_test/create_gas()
+ air_contents.add_gases(/datum/gas/carbon_dioxide, /datum/gas/tritium)
+ air_contents.gases[/datum/gas/carbon_dioxide][MOLES] = 300
+ air_contents.gases[/datum/gas/tritium][MOLES] = 300
+ air_contents.temperature = 10000
+ SSair.start_processing_machine(src)
+
+
#undef CAN_DEFAULT_RELEASE_PRESSURE
+#undef TEMPERATURE_RESISTANCE
diff --git a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
index 36f8f066a4066..c0ad19e859618 100644
--- a/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
+++ b/code/modules/atmospherics/machinery/portable/portable_atmospherics.dm
@@ -1,3 +1,5 @@
+#define PORTABLE_ATMOS_IGNORE_ATMOS_LIMIT 0
+
/obj/machinery/portable_atmospherics
name = "portable_atmospherics"
icon = 'icons/obj/atmos.dmi'
@@ -7,35 +9,45 @@
anchored = FALSE
interacts_with_air = TRUE
+ ///Stores the gas mixture of the portable component. Don't access this directly, use return_air() so you support the temporary processing it provides
var/datum/gas_mixture/air_contents
+ ///Stores the reference of the connecting port
var/obj/machinery/atmospherics/components/unary/portables_connector/connected_port
+ ///Stores the reference of the tank the machine is holding
var/obj/item/tank/holding
-
+ ///Volume (in L) of the inside of the machine
var/volume = 0
- var/maximum_pressure = 90 * ONE_ATMOSPHERE
+ ///Used to track if anything of note has happen while running process_atmos().
+ ///Treat it as a process_atmos() scope var, we just declare it here to pass it between parent calls.
+ ///Should be false on start of every process_atmos() proc, since true means we'll process again next tick.
+ var/excited = FALSE
+
+ /// Max amount of heat allowed inside the machine before it starts to melt. [PORTABLE_ATMOS_IGNORE_ATMOS_LIMIT] is special value meaning we are immune.
+ var/temp_limit = 10000
+ /// Max amount of pressure allowed inside of the canister before it starts to break. [PORTABLE_ATMOS_IGNORE_ATMOS_LIMIT] is special value meaning we are immune.
+ var/pressure_limit = 500000
/obj/machinery/portable_atmospherics/Initialize(mapload)
. = ..()
- air_contents = new(volume)
- air_contents.set_temperature(T20C)
+ air_contents = new
+ air_contents.volume = volume
+ air_contents.temperature = T20C
SSair.start_processing_machine(src)
/obj/machinery/portable_atmospherics/Destroy()
SSair.stop_processing_machine(src)
disconnect()
- qdel(air_contents)
- air_contents = null
+ QDEL_NULL(air_contents)
return ..()
/obj/machinery/portable_atmospherics/ex_act(severity, target)
- if(severity == 1 || target == src)
- if(resistance_flags & INDESTRUCTIBLE)
- return //Indestructable cans shouldn't release air
+ if(resistance_flags & INDESTRUCTIBLE)
+ return FALSE //Indestructible cans shouldn't release air
+ if(severity == EXPLODE_DEVASTATE || target == src)
//This explosion will destroy the can, release its air.
- var/turf/T = get_turf(src)
- T.assume_air(air_contents)
- T.air_update_turf()
+ var/turf/local_turf = get_turf(src)
+ local_turf.assume_air(air_contents)
return ..()
@@ -44,15 +56,46 @@
return atmosanalyzer_scan(user, holding, TRUE)
/obj/machinery/portable_atmospherics/process_atmos()
- if(!connected_port && air_contents != null && src != null) // Pipe network handles reactions if connected.
- air_contents.react(src)
+ excited = (excited | air_contents.react(src))
+ if(!excited)
+ return PROCESS_KILL
+ excited = FALSE
+
+/// Take damage if a variable is exceeded. Damage is equal to temp/limit * heat/limit.
+/// The damage multiplier is treated as 1 if something is being ignored while the other one is exceeded.
+/// On most cases only one will be exceeded, so the other one is scaled down.
+/obj/machinery/portable_atmospherics/proc/take_atmos_damage()
+ var/taking_damage = FALSE
+
+ var/temp_damage = 1
+ var/pressure_damage = 1
+
+ if(temp_limit != PORTABLE_ATMOS_IGNORE_ATMOS_LIMIT)
+ temp_damage = air_contents.temperature / temp_limit
+ taking_damage = temp_damage > 1
+
+ if(pressure_limit != PORTABLE_ATMOS_IGNORE_ATMOS_LIMIT)
+ pressure_damage = air_contents.return_pressure() / pressure_limit
+ taking_damage = taking_damage || pressure_damage > 1
+
+ if(!taking_damage)
+ return FALSE
+
+ take_damage(clamp(temp_damage * pressure_damage, 5, 50), BURN, 0)
+ return TRUE
/obj/machinery/portable_atmospherics/return_air()
+ SSair.start_processing_machine(src)
return air_contents
/obj/machinery/portable_atmospherics/return_analyzable_air()
return air_contents
+/**
+ * Allow the portable machine to be connected to a connector
+ * Arguments:
+ * * new_port - the connector that we trying to connect to
+ */
/obj/machinery/portable_atmospherics/proc/connect(obj/machinery/atmospherics/components/unary/portables_connector/new_port)
//Make sure not already connected to something else
if(connected_port || !new_port || new_port.connected_device)
@@ -65,12 +108,15 @@
//Perform the connection
connected_port = new_port
connected_port.connected_device = src
- connected_port.parents[1].update = PIPENET_UPDATE_STATUS_RECONCILE_NEEDED
+ var/datum/pipeline/connected_port_parent = connected_port.parents[1]
+ if(connected_port_parent)
+ connected_port_parent.reconcile_air()
set_anchored(TRUE) //Prevent movement
pixel_x = new_port.pixel_x
pixel_y = new_port.pixel_y
+ SSair.start_processing_machine(src)
update_appearance()
return TRUE
@@ -79,85 +125,93 @@
if(.)
disconnect()
+/**
+ * Allow the portable machine to be disconnected from the connector
+ */
/obj/machinery/portable_atmospherics/proc/disconnect()
if(!connected_port)
return FALSE
- anchored = FALSE
+ set_anchored(FALSE)
connected_port.connected_device = null
connected_port = null
pixel_x = 0
pixel_y = 0
+ SSair.start_processing_machine(src)
update_appearance()
return TRUE
-/obj/machinery/portable_atmospherics/portableConnectorReturnAir()
- return air_contents
-
/obj/machinery/portable_atmospherics/AltClick(mob/living/user)
. = ..()
if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, !ismonkey(user)) || !can_interact(user))
return
- if(holding)
- to_chat(user, "You remove [holding] from [src].")
- replace_tank(user, TRUE)
+ if(!holding)
+ return
+ to_chat(user, "You remove [holding] from [src].")
+ replace_tank(user, TRUE)
/obj/machinery/portable_atmospherics/examine(mob/user)
. = ..()
- if(holding)
- . += "\The [src] contains [holding]. Alt-click [src] to remove it.\n"+\
- "Click [src] with another gas tank to hot swap [holding]."
-
+ if(!holding)
+ return
+ . += "\The [src] contains [holding]. Alt-click [src] to remove it."+\
+ "Click [src] with another gas tank to hot swap [holding]."
+
+/**
+ * Allow the player to place a tank inside the machine.
+ * Arguments:
+ * * User: the player doing the act
+ * * close_valve: used in the canister.dm file, check if the valve is open or not
+ * * new_tank: the tank we are trying to put in the machine
+ */
/obj/machinery/portable_atmospherics/proc/replace_tank(mob/living/user, close_valve, obj/item/tank/new_tank)
if(!user)
return FALSE
if(holding)
user.put_in_hands(holding)
+ UnregisterSignal(holding, COMSIG_PARENT_QDELETING)
holding = null
if(new_tank)
holding = new_tank
+ RegisterSignal(holding, COMSIG_PARENT_QDELETING, PROC_REF(unregister_holding))
+
+ SSair.start_processing_machine(src)
update_appearance()
return TRUE
-/obj/machinery/portable_atmospherics/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/tank))
- if(!(machine_stat & BROKEN))
- var/obj/item/tank/T = W
- if(!user.transferItemToLoc(T, src))
- return
- to_chat(user, "[holding ? "In one smooth motion you pop [holding] out of [src]'s connector and replace it with [T]" : "You insert [T] into [src]"].")
- investigate_log("had its internal [holding] swapped with [T] by [key_name(user)].", INVESTIGATE_ATMOS)
- replace_tank(user, FALSE, T)
- update_appearance()
- else if(W.tool_behaviour == TOOL_WRENCH)
- if(!(machine_stat & BROKEN))
- if(connected_port)
- investigate_log("was disconnected from [connected_port] by [key_name(user)].", INVESTIGATE_ATMOS)
- disconnect()
- W.play_tool_sound(src)
- user.visible_message( \
- "[user] disconnects [src].", \
- "You unfasten [src] from the port.", \
- "You hear a ratchet.")
- update_appearance()
- return
- else
- var/obj/machinery/atmospherics/components/unary/portables_connector/possible_port = locate(/obj/machinery/atmospherics/components/unary/portables_connector) in loc
- if(!possible_port)
- to_chat(user, "Nothing happens.")
- return
- if(!connect(possible_port))
- to_chat(user, "[name] failed to connect to the port.")
- return
- W.play_tool_sound(src)
- user.visible_message( \
- "[user] connects [src].", \
- "You fasten [src] to the port.", \
- "You hear a ratchet.")
- update_appearance()
- investigate_log("was connected to [possible_port] by [key_name(user)].", INVESTIGATE_ATMOS)
- else
- return ..()
+/obj/machinery/portable_atmospherics/attackby(obj/item/item, mob/user, params)
+ if(istype(item, /obj/item/tank))
+ return replace_tank(user, FALSE, item)
+ return ..()
+
+/obj/machinery/portable_atmospherics/wrench_act(mob/living/user, obj/item/wrench)
+ if(machine_stat & BROKEN)
+ return FALSE
+ if(connected_port)
+ investigate_log("was disconnected from [connected_port] by [key_name(user)].", INVESTIGATE_ATMOS)
+ disconnect()
+ wrench.play_tool_sound(src)
+ user.visible_message( \
+ "[user] disconnects [src].", \
+ "You unfasten [src] from the port.", \
+ "You hear a ratchet.")
+ update_appearance()
+ return TRUE
+ var/obj/machinery/atmospherics/components/unary/portables_connector/possible_port = locate(/obj/machinery/atmospherics/components/unary/portables_connector) in loc
+ if(!possible_port)
+ to_chat(user, "Nothing happens.")
+ return FALSE
+ if(!connect(possible_port))
+ to_chat(user, "[name] failed to connect to the port.")
+ return FALSE
+ wrench.play_tool_sound(src)
+ user.visible_message( \
+ "[user] connects [src].", \
+ "You fasten [src] to the port.", \
+ "You hear a ratchet.")
+ update_appearance()
+ investigate_log("was connected to [possible_port] by [key_name(user)].", INVESTIGATE_ATMOS)
+ return TRUE
/obj/machinery/portable_atmospherics/attacked_by(obj/item/I, mob/user)
if(I.force < 10 && !(machine_stat & BROKEN))
@@ -166,3 +220,13 @@
investigate_log("was smacked with \a [I] by [key_name(user)].", INVESTIGATE_ATMOS)
add_fingerprint(user)
..()
+
+/// Holding tanks can get to zero integrity and be destroyed without other warnings due to pressure change.
+/// This checks for that case and removes our reference to it.
+/obj/machinery/portable_atmospherics/proc/unregister_holding()
+ SIGNAL_HANDLER
+
+ UnregisterSignal(holding, COMSIG_PARENT_QDELETING)
+ holding = null
+
+#undef PORTABLE_ATMOS_IGNORE_ATMOS_LIMIT
diff --git a/code/modules/atmospherics/machinery/portable/pump.dm b/code/modules/atmospherics/machinery/portable/pump.dm
index 68ce64d522f1d..3694ac36d7306 100644
--- a/code/modules/atmospherics/machinery/portable/pump.dm
+++ b/code/modules/atmospherics/machinery/portable/pump.dm
@@ -1,9 +1,3 @@
-#define PUMP_OUT "out"
-#define PUMP_IN "in"
-#define PUMP_MAX_PRESSURE (ONE_ATMOSPHERE * 25)
-#define PUMP_MIN_PRESSURE (ONE_ATMOSPHERE / 10)
-#define PUMP_DEFAULT_PRESSURE (ONE_ATMOSPHERE)
-
/obj/machinery/portable_atmospherics/pump
name = "portable air pump"
desc = "It's a small portable air pump, capable of siphoning or pumping gasses into its surroundings. It has a decent internal gas storage, and a slot for external tanks. It can be wrenched to a connection port to join it into the pipe net."
@@ -11,83 +5,22 @@
density = TRUE
-
+ ///Is the machine on?
var/on = FALSE
+ ///What direction is the machine pumping (in or out)?
var/direction = PUMP_OUT
+ ///Player configurable, sets what's the release pressure
var/target_pressure = ONE_ATMOSPHERE
- var/obj/machinery/atmospherics/components/binary/pump/pump
volume = 1000
-/obj/machinery/portable_atmospherics/pump/Initialize(mapload)
+/obj/machinery/portable_atmospherics/pump/ComponentInitialize()
. = ..()
- pump = new(src, FALSE)
- pump.on = TRUE
- pump.machine_stat = 0
- SSair.add_to_rebuild_queue(pump)
AddComponent(/datum/component/usb_port, list(/obj/item/circuit_component/portable_pump))
-/obj/item/circuit_component/portable_pump
- display_name = "Pump Controller"
- desc = "The interface for communicating with a portable pump."
-
- var/obj/machinery/portable_atmospherics/pump/attached_pump
-
- var/datum/port/input/turn_on
-
- var/datum/port/input/turn_off
-
- var/datum/port/input/pump_in
-
- var/datum/port/input/pump_out
-
- var/datum/port/input/target_pressure
-
-/obj/item/circuit_component/portable_pump/populate_ports()
- turn_on = add_input_port("Turn On", PORT_TYPE_SIGNAL)
- turn_off = add_input_port("Turn Off", PORT_TYPE_SIGNAL)
-
- pump_in = add_input_port("Set pump IN", PORT_TYPE_SIGNAL)
- pump_out = add_input_port("Set pump OUT", PORT_TYPE_SIGNAL)
-
- target_pressure = add_input_port("Target Pressure", PORT_TYPE_NUMBER)
-
-/obj/item/circuit_component/portable_pump/register_usb_parent(atom/movable/shell)
- . = ..()
- if(istype(shell, /obj/machinery/portable_atmospherics/pump))
- attached_pump = shell
-
-/obj/item/circuit_component/portable_pump/unregister_usb_parent(atom/movable/shell)
- attached_pump = null
- return ..()
-
-/obj/item/circuit_component/portable_pump/input_received(datum/port/input/port)
- . = ..()
- if(.)
- return
-
- if(!attached_pump)
- return
-
- if(COMPONENT_TRIGGERED_BY(turn_on, port))
- attached_pump.on = TRUE
- if(attached_pump.holding && (attached_pump.direction == PUMP_IN))
- investigate_log("[parent.get_creator()] started a transfer into [attached_pump.holding].", INVESTIGATE_ATMOS)
- if(COMPONENT_TRIGGERED_BY(turn_off, port))
- attached_pump.on = FALSE
- if(COMPONENT_TRIGGERED_BY(pump_in, port))
- attached_pump.direction = PUMP_IN
- if(COMPONENT_TRIGGERED_BY(pump_out, port))
- attached_pump.direction = PUMP_OUT
- if(COMPONENT_TRIGGERED_BY(target_pressure, port))
- attached_pump.target_pressure = clamp(round(target_pressure), PUMP_MIN_PRESSURE, PUMP_MAX_PRESSURE)
- investigate_log("a portable pump was set to [attached_pump.target_pressure] kPa by [parent.get_creator()].", INVESTIGATE_ATMOS)
-
-/obj/machinery/portable_atmospherics/pump/Destroy()
- var/turf/T = get_turf(src)
- T.assume_air(air_contents)
- air_update_turf()
- QDEL_NULL(pump)
+/obj/machinery/portable_atmospherics/pump/on_deconstruction(disassembled)
+ var/turf/local_turf = get_turf(src)
+ local_turf.assume_air(air_contents)
return ..()
/obj/machinery/portable_atmospherics/pump/update_icon()
@@ -100,47 +33,58 @@
add_overlay("siphon-connector")
/obj/machinery/portable_atmospherics/pump/process_atmos()
- ..()
+ if(take_atmos_damage())
+ excited = TRUE
+ return ..()
+
if(!on)
- pump.airs[1] = null
- pump.airs[2] = null
- return
+ return ..()
+
+ excited = TRUE
+
+ var/turf/local_turf = get_turf(src)
- var/turf/T = get_turf(src)
- if(direction == PUMP_OUT) // Hook up the internal pump.
- pump.airs[1] = holding ? holding.air_contents : air_contents
- pump.airs[2] = holding ? air_contents : T.return_air()
+ var/datum/gas_mixture/sending
+ var/datum/gas_mixture/receiving
+
+ if (holding) //Work with tank when inserted, otherwise - with area
+ sending = (direction == PUMP_IN ? holding.return_air() : air_contents)
+ receiving = (direction == PUMP_IN ? air_contents : holding.return_air())
else
- pump.airs[1] = holding ? air_contents : T.return_air()
- pump.airs[2] = holding ? holding.air_contents : air_contents
+ sending = (direction == PUMP_IN ? local_turf.return_air() : air_contents)
+ receiving = (direction == PUMP_IN ? air_contents : local_turf.return_air())
+
+ if(sending.pump_gas_to(receiving, target_pressure) && !holding)
+ air_update_turf(FALSE, FALSE) // Update the environment if needed.
+
+ return ..()
- pump.process_atmos() // Pump gas.
- if(!holding)
- air_update_turf() // Update the environment if needed.
/obj/machinery/portable_atmospherics/pump/emp_act(severity)
. = ..()
if(. & EMP_PROTECT_SELF)
return
- if(is_operational)
- if(prob(50 / severity))
- on = !on
- if(prob(100 / severity))
- direction = PUMP_OUT
- pump.target_pressure = rand(0, 100 * ONE_ATMOSPHERE)
- update_icon()
+ if(!is_operational)
+ return
+ if(prob(50 / severity))
+ on = !on
+ if(on)
+ SSair.start_processing_machine(src)
+ if(prob(100 / severity))
+ direction = PUMP_OUT
+ target_pressure = rand(0, 100 * ONE_ATMOSPHERE)
+ update_icon()
/obj/machinery/portable_atmospherics/pump/replace_tank(mob/living/user, close_valve)
. = ..()
- if(.)
- if(close_valve)
- if(on)
- on = FALSE
- update_icon()
- else if(on && holding && direction == PUMP_OUT)
- user.investigate_log("started a transfer into [holding].", INVESTIGATE_ATMOS)
-
-
+ if(!.)
+ return
+ if(close_valve)
+ if(on)
+ on = FALSE
+ update_appearance()
+ else if(on && holding && direction == PUMP_OUT)
+ user.investigate_log("started a transfer into [holding].", INVESTIGATE_ATMOS)
/obj/machinery/portable_atmospherics/pump/ui_state(mob/user)
return GLOB.physical_state
@@ -158,7 +102,7 @@
data["direction"] = direction == PUMP_IN ? TRUE : FALSE
data["connected"] = connected_port ? TRUE : FALSE
data["pressure"] = round(air_contents.return_pressure() ? air_contents.return_pressure() : 0)
- data["target_pressure"] = round(pump.target_pressure ? pump.target_pressure : 0)
+ data["target_pressure"] = round(target_pressure ? target_pressure : 0)
data["default_pressure"] = round(PUMP_DEFAULT_PRESSURE)
data["min_pressure"] = round(PUMP_MIN_PRESSURE)
data["max_pressure"] = round(PUMP_MAX_PRESSURE)
@@ -166,7 +110,8 @@
if(holding)
data["holding"] = list()
data["holding"]["name"] = holding.name
- data["holding"]["pressure"] = round(holding.air_contents.return_pressure())
+ var/datum/gas_mixture/holding_mix = holding.return_air()
+ data["holding"]["pressure"] = round(holding_mix.return_pressure())
else
data["holding"] = null
return data
@@ -177,9 +122,11 @@
switch(action)
if("power")
on = !on
+ if(on)
+ SSair.start_processing_machine(src)
if(on && !holding)
- var/plasma = air_contents.get_moles(GAS_PLASMA)
- var/n2o = air_contents.get_moles(GAS_NITROUS)
+ var/plasma = GET_MOLES(/datum/gas/plasma, air_contents)
+ var/n2o = GET_MOLES(/datum/gas/nitrous_oxide, air_contents)
if(n2o || plasma)
message_admins("[ADMIN_LOOKUPFLW(usr)] turned on a pump that contains [n2o ? "N2O" : ""][n2o && plasma ? " & " : ""][plasma ? "Plasma" : ""] at [ADMIN_VERBOSEJMP(src)]")
log_admin("[key_name(usr)] turned on a pump that contains [n2o ? "N2O" : ""][n2o && plasma ? " & " : ""][plasma ? "Plasma" : ""] at [AREACOORD(src)]")
@@ -209,17 +156,72 @@
pressure = text2num(pressure)
. = TRUE
if(.)
- pump.target_pressure = clamp(round(pressure), PUMP_MIN_PRESSURE, PUMP_MAX_PRESSURE)
- investigate_log("was set to [pump.target_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS)
+ target_pressure = clamp(pressure, PUMP_MIN_PRESSURE, PUMP_MAX_PRESSURE)
+ investigate_log("was set to [target_pressure] kPa by [key_name(usr)].", INVESTIGATE_ATMOS)
if("eject")
if(holding)
replace_tank(usr, FALSE)
. = TRUE
+ update_icon()
+
+/obj/machinery/portable_atmospherics/pump/unregister_holding()
+ on = FALSE
+ return ..()
+
+//////////////////////////////////////// CIRCUIT STUFFS ///////////////////////////////
+
+/obj/item/circuit_component/portable_pump
+ display_name = "Pump Controller"
+ desc = "The interface for communicating with a portable pump."
+
+ var/obj/machinery/portable_atmospherics/pump/attached_pump
+
+ var/datum/port/input/turn_on
+
+ var/datum/port/input/turn_off
+
+ var/datum/port/input/pump_in
+
+ var/datum/port/input/pump_out
+
+ var/datum/port/input/target_pressure
+
+/obj/item/circuit_component/portable_pump/populate_ports()
+ turn_on = add_input_port("Turn On", PORT_TYPE_SIGNAL)
+ turn_off = add_input_port("Turn Off", PORT_TYPE_SIGNAL)
+
+ pump_in = add_input_port("Set pump IN", PORT_TYPE_SIGNAL)
+ pump_out = add_input_port("Set pump OUT", PORT_TYPE_SIGNAL)
+
+ target_pressure = add_input_port("Target Pressure", PORT_TYPE_NUMBER)
+
+/obj/item/circuit_component/portable_pump/register_usb_parent(atom/movable/shell)
+ . = ..()
+ if(istype(shell, /obj/machinery/portable_atmospherics/pump))
+ attached_pump = shell
+
+/obj/item/circuit_component/portable_pump/unregister_usb_parent(atom/movable/shell)
+ attached_pump = null
+ return ..()
+
+/obj/item/circuit_component/portable_pump/input_received(datum/port/input/port)
+ . = ..()
if(.)
- update_icon()
+ return
-#undef PUMP_OUT
-#undef PUMP_IN
-#undef PUMP_MAX_PRESSURE
-#undef PUMP_MIN_PRESSURE
-#undef PUMP_DEFAULT_PRESSURE
+ if(!attached_pump)
+ return
+
+ if(COMPONENT_TRIGGERED_BY(turn_on, port))
+ attached_pump.on = TRUE
+ if(attached_pump.holding && (attached_pump.direction == PUMP_IN))
+ investigate_log("[parent.get_creator()] started a transfer into [attached_pump.holding].", INVESTIGATE_ATMOS)
+ if(COMPONENT_TRIGGERED_BY(turn_off, port))
+ attached_pump.on = FALSE
+ if(COMPONENT_TRIGGERED_BY(pump_in, port))
+ attached_pump.direction = PUMP_IN
+ if(COMPONENT_TRIGGERED_BY(pump_out, port))
+ attached_pump.direction = PUMP_OUT
+ if(COMPONENT_TRIGGERED_BY(target_pressure, port))
+ attached_pump.target_pressure = clamp(round(target_pressure), PUMP_MIN_PRESSURE, PUMP_MAX_PRESSURE)
+ investigate_log("a portable pump was set to [attached_pump.target_pressure] kPa by [parent.get_creator()].", INVESTIGATE_ATMOS)
diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm
index fdfd77d663e06..fd75274df3be8 100644
--- a/code/modules/atmospherics/machinery/portable/scrubber.dm
+++ b/code/modules/atmospherics/machinery/portable/scrubber.dm
@@ -5,18 +5,20 @@
density = TRUE
-
+ ///Is the machine on?
var/on = FALSE
- var/volume_rate = 1000
+ ///the rate the machine will scrub air
+ var/volume_rate = 500
+ ///Multiplier with ONE_ATMOSPHERE, if the enviroment pressure is higher than that, the scrubber won't work
var/overpressure_m = 80
- volume = 1000
+ ///List of gases that can be scrubbed
+ var/list/scrubbing = list(/datum/gas/plasma, /datum/gas/carbon_dioxide, /datum/gas/nitrous_oxide, /datum/gas/bz, /datum/gas/nitryl, /datum/gas/tritium, /datum/gas/hypernoblium, /datum/gas/water_vapor)
- var/list/scrubbing = list(GAS_PLASMA, GAS_CO2, GAS_NITROUS, GAS_BZ, GAS_NITRYL, GAS_TRITIUM, GAS_HYPERNOB, GAS_H2O)
+ volume = 2000
-/obj/machinery/portable_atmospherics/scrubber/Destroy()
- var/turf/T = get_turf(src)
- T.assume_air(air_contents)
- air_update_turf()
+/obj/machinery/portable_atmospherics/scrubber/on_deconstruction(disassembled)
+ var/turf/local_turf = get_turf(src)
+ local_turf.assume_air(air_contents)
return ..()
/obj/machinery/portable_atmospherics/scrubber/update_icon()
@@ -29,23 +31,65 @@
add_overlay("scrubber-connector")
/obj/machinery/portable_atmospherics/scrubber/process_atmos()
- ..()
+ if(take_atmos_damage())
+ excited = TRUE
+ return ..()
+
if(!on)
- return
+ return ..()
- if(holding)
- scrub(holding.air_contents)
- else
- var/turf/T = get_turf(src)
- scrub(T.return_air())
+ excited = TRUE
+
+ if(!isnull(holding))
+ scrub(holding.return_air())
+ return ..()
+
+ var/turf/epicentre = get_turf(src)
+ if(isopenturf(epicentre))
+ scrub(epicentre.return_air())
+ for(var/turf/open/openturf as anything in epicentre.get_atmos_adjacent_turfs(alldir = TRUE))
+ scrub(openturf.return_air())
+ return ..()
-/obj/machinery/portable_atmospherics/scrubber/proc/scrub(var/datum/gas_mixture/mixture)
+
+/**
+ * Called in process_atmos(), handles the scrubbing of the given gas_mixture
+ * Arguments:
+ * * mixture: the gas mixture to be scrubbed
+ */
+/obj/machinery/portable_atmospherics/scrubber/proc/scrub(datum/gas_mixture/environment)
if(air_contents.return_pressure() >= overpressure_m * ONE_ATMOSPHERE)
return
- mixture.scrub_into(air_contents, volume_rate / mixture.return_volume(), scrubbing)
- if(!holding)
- air_update_turf()
+ var/list/env_gases = environment.gases
+
+ //contains all of the gas we're sucking out of the tile, gets put into our parent pipenet
+ var/datum/gas_mixture/filtered_out = new
+ var/list/filtered_gases = filtered_out.gases
+ filtered_out.temperature = environment.temperature
+
+ //maximum percentage of the turfs gas we can filter
+ var/removal_ratio = min(1, volume_rate / environment.volume)
+
+ var/total_moles_to_remove = 0
+ for(var/gas in scrubbing & env_gases)
+ total_moles_to_remove += env_gases[gas][MOLES]
+
+ if(total_moles_to_remove == 0)//sometimes this gets non gc'd values
+ environment.garbage_collect()
+ return FALSE
+
+ for(var/gas in scrubbing & env_gases)
+ filtered_out.add_gas(gas)
+ var/transferred_moles = max(QUANTIZE(env_gases[gas][MOLES] * removal_ratio * (env_gases[gas][MOLES] / total_moles_to_remove)), min(MOLAR_ACCURACY*1000, env_gases[gas][MOLES]))
+
+ filtered_gases[gas][MOLES] = transferred_moles
+ env_gases[gas][MOLES] -= transferred_moles
+
+ environment.garbage_collect()
+
+ //Remix the resulting gases
+ air_contents.merge(filtered_out)
/obj/machinery/portable_atmospherics/scrubber/emp_act(severity)
. = ..()
@@ -54,6 +98,8 @@
if(is_operational)
if(prob(50 / severity))
on = !on
+ if(on)
+ SSair.start_processing_machine(src)
update_appearance()
@@ -75,13 +121,14 @@
data["id_tag"] = -1 //must be defined in order to reuse code between portable and vent scrubbers
data["filter_types"] = list()
- for(var/id in GLOB.gas_data.ids)
- data["filter_types"] += list(list("gas_id" = id, "gas_name" = GLOB.gas_data.names[id], "enabled" = (id in scrubbing)))
+ for(var/gas_type in subtypesof(/datum/gas))
+ data["filter_types"] += list(list("gas_id" = GLOB.meta_gas_info[gas_type][META_GAS_ID], "gas_name" = GLOB.meta_gas_info[gas_type][META_GAS_NAME], "enabled" = (gas_type in scrubbing)))
if(holding)
data["holding"] = list()
data["holding"]["name"] = holding.name
- data["holding"]["pressure"] = round(holding.air_contents.return_pressure())
+ var/datum/gas_mixture/holding_mix = holding.return_air()
+ data["holding"]["pressure"] = round(holding_mix.return_pressure())
else
data["holding"] = null
return data
@@ -102,6 +149,8 @@
switch(action)
if("power")
on = !on
+ if(on)
+ SSair.start_processing_machine(src)
. = TRUE
if("eject")
if(holding)
@@ -113,6 +162,10 @@
if(.)
update_appearance()
+/obj/machinery/portable_atmospherics/pump/unregister_holding()
+ on = FALSE
+ return ..()
+
/obj/machinery/portable_atmospherics/scrubber/huge
name = "huge air scrubber"
icon_state = "scrubber:0"
@@ -137,18 +190,23 @@
on = FALSE
update_icon()
use_power = on ? ACTIVE_POWER_USE : IDLE_POWER_USE
+
if(!on)
- return
+ return ..()
+
+ excited = TRUE
- ..()
if(!holding)
var/turf/T = get_turf(src)
- for(var/turf/AT in T.GetAtmosAdjacentTurfs(alldir = TRUE))
+ for(var/turf/AT in T.get_atmos_adjacent_turfs(alldir = TRUE))
scrub(AT.return_air())
-/obj/machinery/portable_atmospherics/scrubber/huge/attackby(obj/item/W, mob/user)
- if(default_unfasten_wrench(user, W))
+ return ..()
+
+/obj/machinery/portable_atmospherics/scrubber/huge/wrench_act(mob/living/user, obj/item/tool)
+ . = ..()
+ if(default_unfasten_wrench(user, tool))
if(!movable)
on = FALSE
- else
- return ..()
+ return TRUE
+ return FALSE
diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm
index c9a942f1f5b38..3af6c576f50fc 100644
--- a/code/modules/awaymissions/mission_code/snowdin.dm
+++ b/code/modules/awaymissions/mission_code/snowdin.dm
@@ -140,7 +140,7 @@
/turf/open/floor/iron/dark/snowdin
initial_gas_mix = FROZEN_ATMOS
planetary_atmos = 1
- initial_temperature = 180
+ temperature = 180
/turf/open/lava/plasma
name = "liquid plasma"
diff --git a/code/modules/cargo/bounties/engineering.dm b/code/modules/cargo/bounties/engineering.dm
index 2f4902309fa3c..4d28ae30967d5 100644
--- a/code/modules/cargo/bounties/engineering.dm
+++ b/code/modules/cargo/bounties/engineering.dm
@@ -4,23 +4,26 @@
reward = 7500
wanted_types = list(/obj/item/tank)
var/moles_required = 20 // A full tank is 28 moles, but CentCom ignores that fact.
- var/gas_type = GAS_PLUOXIUM
+ var/gas_type = /datum/gas/pluoxium
/datum/bounty/item/engineering/gas/applies_to(obj/O)
if(!..())
return FALSE
var/obj/item/tank/T = O
- return T.air_contents.get_moles(gas_type) >= moles_required
+ var/datum/gas_mixture/our_mix = T.return_air()
+ if(!our_mix.gases[gas_type])
+ return FALSE
+ return our_mix.gases[gas_type][MOLES] >= moles_required
/datum/bounty/item/engineering/gas/nitryl_tank
name = "Full Tank of Nitryl"
description = "The non-human staff of Station 88 has been volunteered to test performance enhancing drugs. Ship them a tank full of Nitryl so they can get started."
- gas_type = GAS_NITRYL
+ gas_type = /datum/gas/nitryl
/datum/bounty/item/engineering/gas/tritium_tank
name = "Full Tank of Tritium"
description = "Station 49 is looking to kickstart their research program. Ship them a tank full of Tritium."
- gas_type = GAS_TRITIUM
+ gas_type = /datum/gas/tritium
/datum/bounty/item/engineering/energy_ball
name = "Contained Tesla Ball"
diff --git a/code/modules/cargo/exports/large_objects.dm b/code/modules/cargo/exports/large_objects.dm
index c5e80f845a7e9..a94f351d1404d 100644
--- a/code/modules/cargo/exports/large_objects.dm
+++ b/code/modules/cargo/exports/large_objects.dm
@@ -129,10 +129,13 @@
/datum/export/large/gas_canister/get_cost(obj/O)
var/obj/machinery/portable_atmospherics/canister/C = O
var/worth = 10
-
- worth += C.air_contents.get_moles(GAS_BZ)*4
- worth += C.air_contents.get_moles(GAS_STIMULUM)*100
- worth += C.air_contents.get_moles(GAS_HYPERNOB)*1000
- worth += C.air_contents.get_moles(GAS_TRITIUM)*5
- worth += C.air_contents.get_moles(GAS_PLUOXIUM)*5
+ var/datum/gas_mixture/canister_mix = C.return_air()
+ var/canister_gas = canister_mix.gases
+ worth += canister_gas[/datum/gas/bz][MOLES]*4
+ worth += canister_gas[/datum/gas/stimulum][MOLES]*100
+ worth += canister_gas[/datum/gas/hypernoblium][MOLES]*1000
+ worth += canister_gas[/datum/gas/tritium][MOLES]*5
+ worth += canister_gas[/datum/gas/pluoxium][MOLES]*5
+
+ canister_mix.garbage_collect()
return worth
diff --git a/code/modules/clothing/gloves/color.dm b/code/modules/clothing/gloves/color.dm
index 9fec37410bc64..4d97700720f6f 100644
--- a/code/modules/clothing/gloves/color.dm
+++ b/code/modules/clothing/gloves/color.dm
@@ -207,7 +207,7 @@
REMOVE_TRAIT(user, carrytrait, CLOTHING_TRAIT)
/obj/item/clothing/gloves/color/latex/atom_break()
- ..()
+ . = ..()
if(ishuman(loc))
REMOVE_TRAIT(loc, carrytrait, CLOTHING_TRAIT)
diff --git a/code/modules/clothing/under/accessories.dm b/code/modules/clothing/under/accessories.dm
index 1dafe12f602e3..9041638b41223 100755
--- a/code/modules/clothing/under/accessories.dm
+++ b/code/modules/clothing/under/accessories.dm
@@ -236,11 +236,17 @@
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = -10, ACID = 0, STAMINA = 0, BLEED = 0) //It's made of plasma. Of course it's flammable.
custom_materials = list(/datum/material/plasma=1000)
-/obj/item/clothing/accessory/medal/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
- atmos_spawn_air("plasma=20;TEMP=[exposed_temperature]")
- visible_message(" \The [src] bursts into flame!","Your [src] bursts into flame!")
- qdel(src)
+/obj/item/clothing/accessory/medal/plasma/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
+/obj/item/clothing/accessory/medal/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+
+/obj/item/clothing/accessory/medal/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ atmos_spawn_air("plasma=20;TEMP=[exposed_temperature]")
+ visible_message("\The [src] bursts into flame!", "Your [src] bursts into flame!")
+ qdel(src)
/obj/item/clothing/accessory/medal/plasma/nobel_science
name = "nobel sciences award"
diff --git a/code/modules/events/alien_infestation.dm b/code/modules/events/alien_infestation.dm
index 16ddd69d6fa23..799e31cc8d820 100644
--- a/code/modules/events/alien_infestation.dm
+++ b/code/modules/events/alien_infestation.dm
@@ -55,7 +55,7 @@
continue//no parent vent
//Stops Aliens getting stuck in small networks.
//See: Security, Virology
- if(temp_vent_parent.other_atmosmch.len > 20)
+ if(temp_vent_parent.other_atmos_machines.len > 20)
vents += temp_vent
if(!vents.len)
diff --git a/code/modules/events/diona_infestation.dm b/code/modules/events/diona_infestation.dm
index ef2d878e128df..221fdebb0eb17 100644
--- a/code/modules/events/diona_infestation.dm
+++ b/code/modules/events/diona_infestation.dm
@@ -21,7 +21,7 @@
if(!temp_vent_parent)
continue//no parent vent
//Stops nymphs getting stuck in small networks.
- if(temp_vent_parent.other_atmosmch.len > 20)
+ if(temp_vent_parent.other_atmos_machines.len > 20)
vents += temp_vent
if(!vents.len)
message_admins("An event attempted to spawn nymphs but no suitable vents were found. Shutting down.")
diff --git a/code/modules/events/mimite_infestation.dm b/code/modules/events/mimite_infestation.dm
index dd99e6047d6c0..d04c1618a1856 100644
--- a/code/modules/events/mimite_infestation.dm
+++ b/code/modules/events/mimite_infestation.dm
@@ -35,7 +35,7 @@
if(!temp_vent_parent)
continue//no parent vent
//Stops mimites getting stuck in small networks.
- if(temp_vent_parent.other_atmosmch.len > 20)
+ if(temp_vent_parent.other_atmos_machines.len > 20)
vents += temp_vent
if(!vents.len)
message_admins("An event attempted to spawn mimites but no suitable vents were found. Shutting down.")
diff --git a/code/modules/events/spacevine.dm b/code/modules/events/spacevine.dm
index b1e12c936440e..0f0f0e18fc1b9 100644
--- a/code/modules/events/spacevine.dm
+++ b/code/modules/events/spacevine.dm
@@ -24,6 +24,10 @@
new /datum/spacevine_controller(T, list(pick(subtypesof(/datum/spacevine_mutation))), rand(10,100), rand(1,6)) //spawn a controller at turf with randomized stats and a single random mutation
message_admins("Event spacevine has been spawned in [ADMIN_VERBOSEJMP(T)].")
+/obj/structure/spacevine/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
/datum/spacevine_mutation
var/name = ""
var/severity = 1
@@ -213,7 +217,7 @@
var/turf/open/floor/T = holder.loc
if(istype(T))
var/datum/gas_mixture/GM = T.air
- GM.set_moles(GAS_O2, max(GM.get_moles(GAS_O2) - severity * holder.energy, 0))
+ SET_MOLES(/datum/gas/oxygen, GM, max(GET_MOLES(/datum/gas/oxygen, GM) - severity * holder.energy, 0))
/datum/spacevine_mutation/nitro_eater
name = "nitrogen consuming"
@@ -225,7 +229,7 @@
var/turf/open/floor/T = holder.loc
if(istype(T))
var/datum/gas_mixture/GM = T.air
- GM.set_moles(GAS_N2, max(GM.get_moles(GAS_N2) - severity * holder.energy, 0))
+ SET_MOLES(/datum/gas/nitrogen, GM, max(GET_MOLES(/datum/gas/nitrogen, GM) - severity * holder.energy, 0))
/datum/spacevine_mutation/carbondioxide_eater
name = "CO2 consuming"
@@ -237,7 +241,7 @@
var/turf/open/floor/T = holder.loc
if(istype(T))
var/datum/gas_mixture/GM = T.air
- GM.set_moles(GAS_CO2, max(GM.get_moles(GAS_CO2) - severity * holder.energy, 0))
+ REMOVE_MOLES(/datum/gas/carbon_dioxide, GM, severity * holder.energy - GET_MOLES(/datum/gas/carbon_dioxide, GM))
/datum/spacevine_mutation/plasma_eater
name = "toxins consuming"
@@ -249,7 +253,7 @@
var/turf/open/floor/T = holder.loc
if(istype(T))
var/datum/gas_mixture/GM = T.air
- GM.set_moles(GAS_PLASMA, max(GM.get_moles(GAS_PLASMA) - severity * holder.energy, 0))
+ SET_MOLES(/datum/gas/plasma, GM, max(GET_MOLES(/datum/gas/plasma, GM) - severity * holder.energy, 0))
/datum/spacevine_mutation/thorns
name = "thorny"
@@ -569,10 +573,14 @@
if(!i && prob(100/severity))
qdel(src)
-/obj/structure/spacevine/temperature_expose(null, temp, volume)
+/obj/structure/spacevine/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return TRUE
+
+/obj/structure/spacevine/atmos_expose(datum/gas_mixture/air, exposed_temperature)
var/override = 0
+ var/volume = air.return_volume()
for(var/datum/spacevine_mutation/SM in mutations)
- override += SM.process_temperature(src, temp, volume)
+ override += SM.process_temperature(src, exposed_temperature, volume)
if(!override)
qdel(src)
diff --git a/code/modules/events/spider_infestation.dm b/code/modules/events/spider_infestation.dm
index a2715faac6365..1f43ff59f8410 100644
--- a/code/modules/events/spider_infestation.dm
+++ b/code/modules/events/spider_infestation.dm
@@ -30,7 +30,7 @@
if(!temp_vent_parent)
continue// no parent vent
- if(length(temp_vent_parent.other_atmosmch) > 20)
+ if(length(temp_vent_parent.other_atmos_machines) > 20)
vents += temp_vent // Makes sure the vent network's big enough
if(!length(vents))
diff --git a/code/modules/events/supermatter_surge.dm b/code/modules/events/supermatter_surge.dm
index 0b1335ea5a3e5..16ba4719c47a2 100644
--- a/code/modules/events/supermatter_surge.dm
+++ b/code/modules/events/supermatter_surge.dm
@@ -42,12 +42,14 @@
// primarily so the supermatter doesn't tesla the instant these happen
supermatter.matter_power += power * power_proportion
var/datum/gas_mixture/gas_puff = new
- var/selected_gas = pick(4;GAS_CO2, 4;GAS_H2O, 1;GAS_BZ)
- gas_puff.set_moles(selected_gas, 500)
- gas_puff.set_temperature(500)
+ var/selected_gas = pick(4;/datum/gas/carbon_dioxide, 4;/datum/gas/water_vapor, 1;/datum/gas/bz)
+ gas_puff.gases[selected_gas][MOLES] = 500
+
+ gas_puff.temperature = (500)
var/energy_ratio = (power * 500 * (1-power_proportion)) / gas_puff.thermal_energy()
if(energy_ratio < 1) // energy output we want is lower than current energy, reduce the amount of gas we puff out
- gas_puff.set_moles(GAS_H2O, energy_ratio * 500)
+ gas_puff.gases[/datum/gas/water_vapor][MOLES] = energy_ratio * 500
+
else // energy output we want is higher than current energy, increase its actual heat
- gas_puff.set_temperature(energy_ratio * 500)
+ gas_puff.temperature = (energy_ratio * 500)
supermatter.assume_air(gas_puff)
diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm
index 631d64185c887..380d23eb28bcb 100644
--- a/code/modules/events/wormholes.dm
+++ b/code/modules/events/wormholes.dm
@@ -51,7 +51,7 @@ GLOBAL_LIST_EMPTY(all_wormholes) // So we can pick wormholes to teleport to
CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/portal/wormhole)
-/obj/effect/portal/wormhole/Initialize(mapload, _creator, _lifespan = 0, obj/effect/portal/_linked, automatic_link = FALSE, turf/hard_target_override, atmos_link_override)
+/obj/effect/portal/wormhole/Initialize(mapload, _creator, _lifespan = 0, obj/effect/portal/_linked, automatic_link = FALSE, turf/hard_target_override)
. = ..()
GLOB.all_wormholes += src
diff --git a/code/modules/hallucination/plasma_flood.dm b/code/modules/hallucination/plasma_flood.dm
index 0dfbb32423e61..41f4b74d1d2cd 100644
--- a/code/modules/hallucination/plasma_flood.dm
+++ b/code/modules/hallucination/plasma_flood.dm
@@ -58,7 +58,7 @@
for(var/turf/FT in flood_turfs)
for(var/dir in GLOB.cardinals)
var/turf/T = get_step(FT, dir)
- if((T in flood_turfs) || !FT.CanAtmosPass(T))
+ if((T in flood_turfs) || !FT.can_atmos_pass(T))
continue
var/obj/effect/plasma_image_holder/pih = new(T)
var/image/new_plasma = image(image_icon, pih, image_state, FLY_LAYER)
diff --git a/code/modules/holodeck/area_copy.dm b/code/modules/holodeck/area_copy.dm
index a80e470ddd88b..399126f99401a 100644
--- a/code/modules/holodeck/area_copy.dm
+++ b/code/modules/holodeck/area_copy.dm
@@ -142,6 +142,6 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars,list(
if(toupdate.len)
for(var/turf/T1 in toupdate)
- CALCULATE_ADJACENT_TURFS(T1)
+ CALCULATE_ADJACENT_TURFS(T1, KILL_EXCITED)
return copiedobjs
diff --git a/code/modules/holodeck/holo_effect.dm b/code/modules/holodeck/holo_effect.dm
index c136791e98066..6c5b06c9e46db 100644
--- a/code/modules/holodeck/holo_effect.dm
+++ b/code/modules/holodeck/holo_effect.dm
@@ -66,7 +66,7 @@
var/datum/effect_system/spark_spread/s = new
s.set_up(3, 1, T)
s.start()
- T.set_temperature(5000)
+ T.temperature = (5000)
T.hotspot_expose(50000,50000,1)
/obj/effect/holodeck_effect/random_book
diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm
index 4f885592a0b24..736244a1018ee 100644
--- a/code/modules/hydroponics/grown/towercap.dm
+++ b/code/modules/hydroponics/grown/towercap.dm
@@ -246,7 +246,7 @@
if(isopenturf(loc))
var/turf/open/O = loc
if(O.air)
- if(O.air.get_moles(GAS_O2) > 13)
+ if(GET_MOLES(/datum/gas/oxygen, O.air) > 13)
return TRUE
return FALSE
diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm
index f7719b3c233ba..2563893c7c38b 100644
--- a/code/modules/mapping/map_template.dm
+++ b/code/modules/mapping/map_template.dm
@@ -106,7 +106,7 @@
)
)
for(var/turf/affected_turf as anything in template_and_bordering_turfs)
- affected_turf.air_update_turf(TRUE)
+ affected_turf.air_update_turf(TRUE, TRUE)
affected_turf.levelupdate()
/datum/map_template/proc/load_new_z(orbital_body_type, list/level_traits = list(ZTRAIT_AWAY = TRUE))
@@ -150,7 +150,7 @@
locate(min(T.x+width, world.maxx), min(T.y+height, world.maxy), T.z))
for(var/L in border)
var/turf/turf_to_disable = L
- turf_to_disable.ImmediateDisableAdjacency()
+ turf_to_disable.immediate_disable_adjacency()
// Accept cached maps, but don't save them automatically - we don't want
// ruins clogging up memory for the whole round.
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm
index 2bd4db8a0c4b6..c74c152ef9e6e 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers.dm
@@ -323,134 +323,6 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
organ.organ_flags |= ORGAN_FROZEN
container.update_icon()
-/obj/effect/mapping_helpers/simple_pipes
- name = "Simple Pipes"
- late = TRUE
- icon_state = "pipe-3"
- alpha = 175
- layer = GAS_PIPE_VISIBLE_LAYER
- var/piping_layer = 3
- var/pipe_color = ""
- var/hide = FALSE
-
- FASTDMM_PROP(\
- pipe_type = PIPE_TYPE_AUTO,\
- pipe_interference_group = "atmos-[piping_layer]"\
- )
-
- var/list/pipe_types = list(
- /obj/machinery/atmospherics/pipe/simple/general/visible,
- /obj/machinery/atmospherics/pipe/simple/general/visible,
- /obj/machinery/atmospherics/pipe/manifold/general/visible,
- /obj/machinery/atmospherics/pipe/manifold4w/general/visible
- )
-
-/obj/effect/mapping_helpers/simple_pipes/Initialize(mapload)
- preform_layer(piping_layer, pipe_color)
- qdel(src)
-
-/obj/effect/mapping_helpers/simple_pipes/proc/preform_layer(override_layer, override_color, override_name = null)
- var/list/connections = list( dir2text(NORTH) = FALSE, dir2text(SOUTH) = FALSE , dir2text(EAST) = FALSE , dir2text(WEST) = FALSE)
- var/list/valid_connectors = typecacheof(/obj/machinery/atmospherics)
- var/connection_num = 0
- for(var/direction in connections)
- var/turf/T = get_step(src, text2dir(direction))
- for(var/thing in T.contents)
- // If it is a mapping helper
- if(istype(thing, /obj/effect/mapping_helpers/simple_pipes))
- var/obj/effect/mapping_helpers/simple_pipes/found = thing
-
- // If it is a supply_scrubber mapping helper
- if(istype(found, /obj/effect/mapping_helpers/simple_pipes/supply_scrubber))
- if(override_layer != 2 && override_layer != 4 && !istype(src, /obj/effect/mapping_helpers/simple_pipes/supply_scrubber))
- continue // We allow it if we're also a supply_scrubber helper, otherwise we gotta be on layers 2 or 4.
-
- // If it is a regular mapping helper
- else
- if(found.piping_layer != override_layer)
- continue // We have to have the same layer to allow it.
-
- connections[direction] = TRUE
- connection_num++
- break
-
- if(!is_type_in_typecache(thing, valid_connectors))
- continue
-
- var/obj/machinery/atmospherics/AM = thing
- if(AM.piping_layer != override_layer && !istype(AM, /obj/machinery/atmospherics/pipe/layer_manifold))
- continue
-
- if(angle2dir(dir2angle(text2dir(direction))+180) & AM.initialize_directions)
- connections[direction] = TRUE
- connection_num++
- break
-
- switch(connection_num)
- if(1)
- for(var/direction in connections)
- if(connections[direction] != TRUE)
- continue
- spawn_pipe(direction, connection_num, override_layer, override_color, override_name)
- return
- if(2)
- for(var/direction in connections)
- if(connections[direction] != TRUE)
- continue
- //Detects straight pipes connected from east to west , north to south etc.
- if(connections[dir2text(angle2dir(dir2angle(text2dir(direction))+180))] == TRUE)
- spawn_pipe(direction, connection_num, override_layer, override_color, override_name)
- return
-
- for(var/direction2 in (connections - direction))
- if(connections[direction2] != TRUE)
- continue
- spawn_pipe(dir2text(text2dir(direction)+text2dir(direction2)), connection_num, override_layer, override_color, override_name)
- return
- if(3)
- for(var/direction in connections)
- if(connections[direction] == FALSE)
- spawn_pipe(direction, connection_num, override_layer, override_color, override_name)
- return
- if(4)
- spawn_pipe(dir2text(NORTH), connection_num, override_layer, override_color, override_name)
- return
-
-/// Spawn the pipe on the layer we specify
-/obj/effect/mapping_helpers/simple_pipes/proc/spawn_pipe(direction, connection_num, override_layer, override_color, override_name = null)
- var/T = pipe_types[connection_num]
- var/obj/machinery/atmospherics/pipe/pipe = new T(get_turf(src), TRUE, text2dir(direction))
-
- if(!isnull(override_name))
- pipe.name = override_name
- pipe.piping_layer = override_layer
- pipe.update_layer()
- pipe.paint(override_color)
- // prevents duplicates on the station blueprints mode since the effect is on
- pipe.obj_flags &= ~ON_BLUEPRINTS
-
-/obj/effect/mapping_helpers/simple_pipes/supply_scrubber
- name = "Simple Supply/Scrubber Pipes"
- icon_state = "pipe-2-4"
- color = rgb(128, 0, 128) // purple in-between pipe
-
-// Instead of using our current layer, we use
-/obj/effect/mapping_helpers/simple_pipes/supply_scrubber/Initialize(mapload)
- preform_layer(2, rgb(0, 0, 255), override_name = "air supply pipe")
- preform_layer(4, rgb(255, 0, 0), override_name = "scrubbers pipe")
-
- qdel(src)
-
-/obj/effect/mapping_helpers/simple_pipes/supply_scrubber/hidden
- name = "Hidden Simple Supply/Scrubber Pipes"
- hide = TRUE
- pipe_types = list(
- /obj/machinery/atmospherics/pipe/simple/general/hidden,
- /obj/machinery/atmospherics/pipe/simple/general/hidden,
- /obj/machinery/atmospherics/pipe/manifold/general/hidden,
- /obj/machinery/atmospherics/pipe/manifold4w/general/hidden
- )
-
//Color correction helper - only use of these per area, it will convert the entire area
/obj/effect/mapping_helpers/color_correction
name = "color correction helper"
@@ -520,10 +392,10 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
/obj/effect/mapping_helpers/atmos_auto_connect/LateInitialize()
. = ..()
- var/obj/machinery/portable_atmospherics/PortAtmos = locate(/obj/machinery/portable_atmospherics) in loc
- var/obj/machinery/atmospherics/components/unary/portables_connector/Connector = locate(/obj/machinery/atmospherics/components/unary/portables_connector) in loc
- if(PortAtmos && Connector)
- Connector.connect_to = PortAtmos
+ var/obj/machinery/portable_atmospherics/port_atmos = locate(/obj/machinery/portable_atmospherics) in loc
+ var/obj/machinery/atmospherics/components/unary/portables_connector/connector = locate(/obj/machinery/atmospherics/components/unary/portables_connector) in loc
+ if(port_atmos && connector)
+ port_atmos.connect(connector)
qdel(src)
return
CRASH("Failed to find a portable atmospherics or a portables connector at [AREACOORD(src)]")
@@ -544,7 +416,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
/** internal code variables - not for mappers **/
/// used to skip a direction on a turf
var/skip_direction
- /// there are a few stuff that "CanAtmosPass()" is not reliable
+ /// there are a few stuff that "can_atmos_pass()" is not reliable
var/static/list/unliable_atmos_blockers
@@ -568,7 +440,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
if(isspaceturf(each_turf) || isopenspace(each_turf))
continue
- if(!each_turf.CanAtmosPass(my_turf))
+ if(!each_turf.can_atmos_pass(my_turf))
for(var/atom/movable/movable_content as anything in each_turf.contents)
if(is_type_in_typecache(movable_content, unliable_atmos_blockers))
unliable_atmos_blocking = TRUE
@@ -605,7 +477,7 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
// puts a directional window for each direction.
for(var/turf/each_turf in nearby_turfs)
- if(!each_turf.CanAtmosPass(my_turf) || isspaceturf(each_turf) || isopenspace(each_turf))
+ if(!each_turf.can_atmos_pass(my_turf) || isspaceturf(each_turf) || isopenspace(each_turf))
continue
var/obj/d_glass = new window_type(each_turf)
diff --git a/code/modules/mining/coins.dm b/code/modules/mining/coins.dm
index 337d0e6b225a4..f48a20e79d946 100644
--- a/code/modules/mining/coins.dm
+++ b/code/modules/mining/coins.dm
@@ -119,9 +119,11 @@
/obj/item/coin/plasma
custom_materials = list(/datum/material/plasma = 400)
-/obj/item/coin/plasma/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
- plasma_ignition(0)
+/obj/item/coin/plasma/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 300
+
+/obj/item/coin/plasma/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ plasma_ignition(0)
/obj/item/coin/plasma/bullet_act(obj/projectile/Proj)
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index ff5b9ac353ce1..fd097fbd9bb4f 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -28,6 +28,7 @@
/obj/item/survivalcapsule/Destroy()
template = null // without this, capsules would be one use. per round.
+ air_update_turf(TRUE, FALSE)
. = ..()
/obj/item/survivalcapsule/examine(mob/user)
@@ -296,7 +297,7 @@
density = TRUE
var/buildstacktype = /obj/item/stack/sheet/iron
var/buildstackamount = 5
- CanAtmosPass = ATMOS_PASS_NO
+ can_atmos_pass = ATMOS_PASS_NO
/obj/structure/fans/deconstruct()
if(!(flags_1 & NODECONSTRUCT_1))
@@ -324,7 +325,7 @@
/obj/structure/fans/Initialize(mapload)
. = ..()
- air_update_turf(1)
+ air_update_turf(TRUE, TRUE)
//Inivisible, indestructible fans
/obj/structure/fans/tiny/invisible
diff --git a/code/modules/mob/living/carbon/alien/life.dm b/code/modules/mob/living/carbon/alien/life.dm
index ede9e50ccb3c2..29465cdfc405a 100644
--- a/code/modules/mob/living/carbon/alien/life.dm
+++ b/code/modules/mob/living/carbon/alien/life.dm
@@ -15,20 +15,20 @@
var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.return_temperature())/BREATH_VOLUME
//Partial pressure of the toxins in our breath
- var/toxins_pp = (breath.get_moles(GAS_PLASMA)/breath.total_moles())*breath_pressure
+ var/toxins_pp = (GET_MOLES(/datum/gas/plasma, breath)/breath.total_moles())*breath_pressure
if(toxins_pp > tox_detect_threshold) // Detect toxins in air
- adjustPlasma(breath.get_moles(GAS_PLASMA)*250)
+ adjustPlasma(GET_MOLES(/datum/gas/plasma, breath)*250)
throw_alert("alien_tox", /atom/movable/screen/alert/alien_tox)
- toxins_used = breath.get_moles(GAS_PLASMA)
+ toxins_used = GET_MOLES(/datum/gas/plasma, breath)
else
clear_alert("alien_tox")
//Breathe in toxins and out oxygen
- breath.adjust_moles(GAS_PLASMA, -toxins_used)
- breath.adjust_moles(GAS_O2, toxins_used)
+ breath.gases[/datum/gas/plasma][MOLES] += -toxins_used
+ breath.gases[/datum/gas/oxygen][MOLES] += toxins_used
//BREATH TEMPERATURE
handle_breath_temperature(breath)
@@ -50,7 +50,7 @@
breath = loc.remove_air_ratio(breath_ratio)
if(breath)
- breath.set_volume(BREATH_VOLUME)
+ breath.volume = BREATH_VOLUME
check_breath(breath)
/mob/living/carbon/alien/handle_status_effects(delta_time)
diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm
index 40168e56f1f3d..89891c28a04c8 100644
--- a/code/modules/mob/living/carbon/alien/special/facehugger.dm
+++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm
@@ -28,6 +28,10 @@
var/strength = 5
var/attached = 0
+/obj/item/clothing/mask/facehugger/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
/obj/item/clothing/mask/facehugger/Initialize(mapload)
. = ..()
var/static/list/loc_connections = list(
@@ -95,9 +99,12 @@
. += "It looks like the proboscis has been removed."
-/obj/item/clothing/mask/facehugger/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature > 300)
- Die()
+/obj/item/clothing/mask/facehugger/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ Die()
+
+
+/obj/item/clothing/mask/facehugger/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return (exposed_temperature > 300)
/obj/item/clothing/mask/facehugger/equipped(mob/M)
. = ..()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 289e2d2fd1da6..035a4dfc1cf89 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -113,8 +113,9 @@
var/list/tab_data = ..()
var/obj/item/tank/target_tank = internal || external
if(target_tank)
+ var/datum/gas_mixture/target_tank_air = target_tank.return_air()
tab_data["Internal Atmosphere Info"] = GENERATE_STAT_TEXT("[target_tank.name]")
- tab_data["Tank Pressure"] = GENERATE_STAT_TEXT("[target_tank.air_contents.return_pressure()]")
+ tab_data["Tank Pressure"] = GENERATE_STAT_TEXT("[target_tank_air.return_pressure()]")
tab_data["Distribution Pressure"] = GENERATE_STAT_TEXT("[target_tank.distribute_pressure]")
if(istype(wear_suit, /obj/item/clothing/suit/space))
var/obj/item/clothing/suit/space/S = wear_suit
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 72f87cd8b1ce2..6a0621e0e1741 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -104,14 +104,14 @@
if(P.starting)
var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
- var/turf/curloc = get_turf(src)
+ var/turf/current_location = get_turf(src)
// redirect the projectile
P.original = locate(new_x, new_y, P.z)
- P.starting = curloc
+ P.starting = current_location
P.firer = src
- P.yo = new_y - curloc.y
- P.xo = new_x - curloc.x
+ P.yo = new_y - current_location.y
+ P.xo = new_x - current_location.x
var/new_angle_s = P.Angle + rand(120,240)
while(new_angle_s > 180) // Translate to regular projectile degrees
new_angle_s -= 360
diff --git a/code/modules/mob/living/carbon/human/species_types/oozelings.dm b/code/modules/mob/living/carbon/human/species_types/oozelings.dm
index 35dc8f5afb36d..bbfc68d8af4a7 100644
--- a/code/modules/mob/living/carbon/human/species_types/oozelings.dm
+++ b/code/modules/mob/living/carbon/human/species_types/oozelings.dm
@@ -88,11 +88,11 @@
if(!atmos_sealed)
var/datum/gas_mixture/environment = H.loc.return_air()
if(environment?.total_moles())
- if(environment.get_moles(GAS_H2O) >= 1)
+ if(GET_MOLES(/datum/gas/water_vapor, environment) >= 1)
H.blood_volume -= 15
if(prob(50))
to_chat(H, "Your ooze melts away rapidly in the water vapor!")
- if(H.blood_volume <= 672 && environment.get_moles(GAS_PLASMA) >= 1)
+ if(H.blood_volume <= 672 && GET_MOLES(/datum/gas/plasma, environment) >= 1)
H.blood_volume += 15
if(H.blood_volume < BLOOD_VOLUME_OKAY && prob(5))
to_chat(H, "You feel drained!")
diff --git a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
index 584ea5dddfa43..6fd06a264b2ab 100644
--- a/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
+++ b/code/modules/mob/living/carbon/human/species_types/plasmamen.dm
@@ -54,7 +54,7 @@
var/datum/gas_mixture/environment = H.loc.return_air()
if(environment)
if(environment.total_moles())
- if(environment.get_moles(GAS_O2) >= 1) //Same threshold that extinguishes fire
+ if(GET_MOLES(/datum/gas/oxygen, environment) >= 1) //Same threshold 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/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index e2c54e8c6499c..35ab3fca15a05 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -129,23 +129,22 @@
breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME)
else if(isturf(loc)) //Breathe from loc as turf
- var/breath_ratio = 0
+ var/breath_moles = 0
if(environment)
- breath_ratio = BREATH_VOLUME/environment.return_volume()
+ breath_moles = environment.total_moles()*BREATH_PERCENTAGE
- breath = loc.remove_air_ratio(breath_ratio)
+ breath = loc.remove_air(breath_moles)
else //Breathe from loc as obj again
- if(istype(loc, /obj/))
+ if(isobj(loc))
var/obj/loc_as_obj = loc
loc_as_obj.handle_internal_lifeform(src,0)
if(breath)
- breath.set_volume(BREATH_VOLUME)
+ breath.volume = BREATH_VOLUME
check_breath(breath)
if(breath)
loc.assume_air(breath)
- air_update_turf()
/mob/living/carbon/proc/has_smoke_protection()
if(HAS_TRAIT(src, TRAIT_NOBREATH))
@@ -182,9 +181,9 @@
var/oxygen_used = 0
var/moles = breath.total_moles()
var/breath_pressure = (moles*R_IDEAL_GAS_EQUATION*breath.return_temperature())/BREATH_VOLUME
- var/O2_partialpressure = ((breath.get_moles(GAS_O2)/moles)*breath_pressure) + (((breath.get_moles(GAS_PLUOXIUM)*8)/moles)*breath_pressure)
- var/Toxins_partialpressure = (breath.get_moles(GAS_PLASMA)/moles)*breath_pressure
- var/CO2_partialpressure = (breath.get_moles(GAS_CO2)/moles)*breath_pressure
+ var/O2_partialpressure = ((GET_MOLES(/datum/gas/oxygen, breath)/moles)*breath_pressure) + (((GET_MOLES(/datum/gas/pluoxium, breath)*8)/moles)*breath_pressure)
+ var/Toxins_partialpressure = (GET_MOLES(/datum/gas/plasma, breath)/moles)*breath_pressure
+ var/CO2_partialpressure = (GET_MOLES(/datum/gas/carbon_dioxide, breath)/moles)*breath_pressure
//OXYGEN
@@ -195,7 +194,7 @@
var/ratio = 1 - O2_partialpressure/safe_oxy_min
adjustOxyLoss(min(5*ratio, 3))
failed_last_breath = 1
- oxygen_used = breath.get_moles(GAS_O2)*ratio
+ oxygen_used = GET_MOLES(/datum/gas/oxygen, breath)*ratio
else
adjustOxyLoss(3)
failed_last_breath = 1
@@ -205,11 +204,11 @@
failed_last_breath = 0
if(health >= crit_threshold)
adjustOxyLoss(-5)
- oxygen_used = breath.get_moles(GAS_O2)
+ oxygen_used = GET_MOLES(/datum/gas/oxygen, breath)
clear_alert("not_enough_oxy")
- breath.adjust_moles(GAS_O2, -oxygen_used)
- breath.adjust_moles(GAS_CO2, oxygen_used)
+ ADD_MOLES(/datum/gas/carbon_dioxide, breath, oxygen_used)
+ REMOVE_MOLES(/datum/gas/oxygen, breath, oxygen_used)
//CARBON DIOXIDE
if(CO2_partialpressure > safe_co2_max)
@@ -228,15 +227,15 @@
//TOXINS/PLASMA
if(Toxins_partialpressure > safe_tox_max)
- var/ratio = (breath.get_moles(GAS_PLASMA)/safe_tox_max) * 10
+ var/ratio = (GET_MOLES(/datum/gas/plasma, breath)/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")
//NITROUS OXIDE
- if(breath.get_moles(GAS_NITROUS))
- var/SA_partialpressure = (breath.get_moles(GAS_NITROUS)/breath.total_moles())*breath_pressure
+ if(GET_MOLES(/datum/gas/nitrous_oxide, breath))
+ var/SA_partialpressure = (GET_MOLES(/datum/gas/nitrous_oxide, breath)/breath.total_moles())*breath_pressure
if(SA_partialpressure > SA_para_min)
Unconscious(60)
if(SA_partialpressure > SA_sleep_min)
@@ -249,21 +248,21 @@
SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria")
//BZ (Facepunch port of their Agent B)
- if(breath.get_moles(GAS_BZ))
- var/bz_partialpressure = (breath.get_moles(GAS_BZ)/breath.total_moles())*breath_pressure
+ if(GET_MOLES(/datum/gas/bz, breath))
+ var/bz_partialpressure = (GET_MOLES(/datum/gas/bz, breath)/breath.total_moles())*breath_pressure
if(bz_partialpressure > 1)
hallucination += 10
else if(bz_partialpressure > 0.01)
hallucination += 5
//TRITIUM
- if(breath.get_moles(GAS_TRITIUM))
- var/tritium_partialpressure = (breath.get_moles(GAS_TRITIUM)/breath.total_moles())*breath_pressure
+ if(GET_MOLES(/datum/gas/tritium, breath))
+ var/tritium_partialpressure = (GET_MOLES(/datum/gas/tritium, breath)/breath.total_moles())*breath_pressure
radiation += tritium_partialpressure/10
//NITRYL
- if(breath.get_moles(GAS_NITRYL))
- var/nitryl_partialpressure = (breath.get_moles(GAS_NITRYL)/breath.total_moles())*breath_pressure
+ if(GET_MOLES(/datum/gas/nitryl, breath))
+ var/nitryl_partialpressure = (GET_MOLES(/datum/gas/nitryl, breath)/breath.total_moles())*breath_pressure
adjustFireLoss(nitryl_partialpressure/4)
//BREATH TEMPERATURE
@@ -274,7 +273,7 @@
//Fourth and final link in a breath chain
/mob/living/carbon/proc/handle_breath_temperature(datum/gas_mixture/breath)
// The air you breathe out should match your body temperature
- breath.set_temperature(bodytemperature)
+ breath.temperature = bodytemperature
/// Attempts to take a breath from the external or internal air tank.
/mob/living/carbon/proc/get_breath_from_internal(volume_needed)
diff --git a/code/modules/mob/living/life.dm b/code/modules/mob/living/life.dm
index b98d460e29a1f..d21f0ad94481e 100644
--- a/code/modules/mob/living/life.dm
+++ b/code/modules/mob/living/life.dm
@@ -93,7 +93,7 @@
ExtinguishMob()
return TRUE //mob was put out, on_fire = FALSE via ExtinguishMob(), no need to update everything down the chain.
var/datum/gas_mixture/G = loc.return_air() // Check if we're standing in an oxygenless environment
- if(G.get_moles(GAS_O2) < 1)
+ if(GET_MOLES(/datum/gas/oxygen, G) < 1)
ExtinguishMob() //If there's no oxygen in the tile we're on, put out the fire
return TRUE
var/turf/location = get_turf(src)
diff --git a/code/modules/mob/living/simple_animal/bot/atmosbot.dm b/code/modules/mob/living/simple_animal/bot/atmosbot.dm
index 1430ad333a862..6a2b4ae9ddca5 100644
--- a/code/modules/mob/living/simple_animal/bot/atmosbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/atmosbot.dm
@@ -52,16 +52,16 @@
var/last_barrier_tick
//Gasses
var/list/gasses = list(
- GAS_BZ = 1,
- GAS_CO2 = 1,
- GAS_HYPERNOB = 1,
- GAS_NITROUS = 1,
- GAS_NITRYL = 1,
- GAS_PLASMA = 1,
- GAS_PLUOXIUM = 0,
- GAS_STIMULUM = 0,
- GAS_TRITIUM = 1,
- GAS_H2O = 0,
+ /datum/gas/bz = 1,
+ /datum/gas/carbon_dioxide = 1,
+ /datum/gas/hypernoblium = 1,
+ /datum/gas/nitrous_oxide = 1,
+ /datum/gas/nitryl = 1,
+ /datum/gas/plasma = 1,
+ /datum/gas/pluoxium = 0,
+ /datum/gas/stimulum = 0,
+ /datum/gas/tritium = 1,
+ /datum/gas/water_vapor = 0,
)
// Have we spoken our alert yet?
var/has_spoken = FALSE
@@ -200,7 +200,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/simple_animal/bot/atmosbot)
/mob/living/simple_animal/bot/atmosbot/proc/change_temperature()
var/turf/T = get_turf(src)
var/datum/gas_mixture/environment = T.return_air()
- environment.set_temperature(ideal_temperature)
+ environment.temperature = (ideal_temperature)
/mob/living/simple_animal/bot/atmosbot/proc/vent_air()
//Just start pumping out air
@@ -216,11 +216,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/simple_animal/bot/atmosbot)
if(pressure_delta > 0)
var/transfer_moles = pressure_delta*environment.return_volume()/(T20C * R_IDEAL_GAS_EQUATION)
if(emagged == 2)
- environment.adjust_moles(GAS_CO2, transfer_moles)
+ environment.gases[/datum/gas/carbon_dioxide][MOLES] += transfer_moles
else
- environment.adjust_moles(GAS_N2, transfer_moles * 0.7885)
- environment.adjust_moles(GAS_O2, transfer_moles * 0.2115)
- air_update_turf()
+ environment.gases[/datum/gas/nitrogen][MOLES] += transfer_moles * 0.7885
+ environment.gases[/datum/gas/oxygen][MOLES] += transfer_moles * 0.2115
+ air_update_turf(FALSE, FALSE)
new /obj/effect/temp_visual/vent_wind(get_turf(src))
/mob/living/simple_animal/bot/atmosbot/proc/scrub_toxins()
@@ -231,8 +231,8 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/simple_animal/bot/atmosbot)
var/datum/gas_mixture/environment = T.return_air()
for(var/G in gasses)
if(gasses[G])
- var/moles_in_atmos = environment.get_moles(G)
- environment.adjust_moles(G, -min(moles_in_atmos, ATMOSBOT_MAX_SCRUB_CHANGE))
+ var/moles_in_atmos = GET_MOLES(G, environment)
+ REMOVE_MOLES(G, environment, min(moles_in_atmos, ATMOSBOT_MAX_SCRUB_CHANGE))
/mob/living/simple_animal/bot/atmosbot/proc/deploy_holobarrier()
if(deployed_holobarrier)
@@ -249,11 +249,11 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/simple_animal/bot/atmosbot)
//Toxins in the air
if(emagged != 2)
for(var/G in gasses)
- if(gasses[G] && gas_mix.get_moles(G) > 0.2)
+ if(gasses[G] && GET_MOLES(G, gas_mix) > 0.2)
return ATMOSBOT_HIGH_TOXINS
//Too little oxygen or too little pressure
var/partial_pressure = R_IDEAL_GAS_EQUATION * gas_mix.return_temperature() / gas_mix.return_volume()
- var/oxygen_moles = gas_mix.get_moles(GAS_O2) * partial_pressure
+ var/oxygen_moles = GET_MOLES(/datum/gas/oxygen, gas_mix) * partial_pressure
if(oxygen_moles < 20 || gas_mix.return_pressure() < WARNING_LOW_PRESSURE)
return ATMOSBOT_LOW_OXYGEN
//Check temperature
@@ -267,7 +267,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/simple_animal/bot/atmosbot)
for(var/obj/structure/holosign/barrier/atmos/A in target_turf)
blocked = TRUE
break
- if(!target_turf.CanAtmosPass(target_turf) || blocked)
+ if(!target_turf.can_atmos_pass(target_turf) || blocked)
//Pressumable from being inside a holobarrier, move somewhere nearby
var/turf/open/floor/floor_turf = pick(view(3, src))
if(floor_turf && istype(floor_turf))
@@ -278,7 +278,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/simple_animal/bot/atmosbot)
/mob/living/simple_animal/bot/atmosbot/proc/return_nearest_breach()
var/turf/origin = get_turf(src)
- if(isclosedturf(origin))
+ if(origin.blocks_air)
return null
var/room_limit = ATMOSBOT_MAX_AREA_SCAN
@@ -294,7 +294,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/simple_animal/bot/atmosbot)
for(var/obj/structure/holosign/barrier/atmos/A in checking_turf)
blocked = TRUE
break
- if(blocked || !checking_turf.CanAtmosPass(checking_turf))
+ if(blocked || !checking_turf.can_atmos_pass(checking_turf))
continue
var/datum/gas_mixture/current_air = checking_turf.return_air()
if (!current_air)
@@ -303,7 +303,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/mob/living/simple_animal/bot/atmosbot)
//Add adjacent turfs
for(var/direction in list(NORTH, SOUTH, EAST, WEST))
var/turf/adjacent_turf = get_step(checking_turf, direction)
- if((adjacent_turf in checked_turfs) || !adjacent_turf.CanAtmosPass(adjacent_turf))
+ if((adjacent_turf in checked_turfs) || !(adjacent_turf.can_atmos_pass(adjacent_turf)))
continue
var/datum/gas_mixture/checking_air = checking_turf.return_air()
if (!checking_air)
diff --git a/code/modules/mob/living/simple_animal/bot/bot.dm b/code/modules/mob/living/simple_animal/bot/bot.dm
index 57c63fa117ab6..6e355f48527a6 100644
--- a/code/modules/mob/living/simple_animal/bot/bot.dm
+++ b/code/modules/mob/living/simple_animal/bot/bot.dm
@@ -466,7 +466,7 @@ Pass the desired type path itself, declaring a temporary var beforehand is not r
var/turf/T = get_turf(src)
if(!T)
return
- var/list/adjacent = T.GetAtmosAdjacentTurfs(1)
+ var/list/adjacent = T.get_atmos_adjacent_turfs(1)
var/atom/final_result
var/static/list/turf_typecache = typecacheof(/turf)
if(shuffle) //If we were on the same tile as another bot, let's randomize our choices so we dont both go the same way
diff --git a/code/modules/mob/living/simple_animal/bot/firebot.dm b/code/modules/mob/living/simple_animal/bot/firebot.dm
index 85f6690118cad..3bdc4c9cf695f 100644
--- a/code/modules/mob/living/simple_animal/bot/firebot.dm
+++ b/code/modules/mob/living/simple_animal/bot/firebot.dm
@@ -33,7 +33,7 @@
var/speech_cooldown = 0
var/detected_cooldown = 0
- var/foam_cooldown = 0
+ COOLDOWN_DECLARE(foam_cooldown)
var/extinguish_people = TRUE
var/extinguish_fires = TRUE
@@ -49,6 +49,12 @@
create_extinguisher()
+/mob/living/simple_animal/bot/firebot/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
+
+
/mob/living/simple_animal/bot/firebot/bot_reset()
create_extinguisher()
@@ -262,11 +268,13 @@
return result
-/mob/living/simple_animal/bot/firebot/temperature_expose(datum/gas_mixture/air, temperature, volume)
- if((temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && foam_cooldown + FOAM_INTERVAL < world.time)
+/mob/living/simple_animal/bot/firebot/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return (exposed_temperature > T0C + 200 || exposed_temperature < BODYTEMP_COLD_DAMAGE_LIMIT)
+
+/mob/living/simple_animal/bot/firebot/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ if(COOLDOWN_FINISHED(src, foam_cooldown))
new /obj/effect/particle_effect/foam/firefighting(loc)
- foam_cooldown = world.time
- ..()
+ COOLDOWN_START(src, foam_cooldown, FOAM_INTERVAL)
/mob/living/simple_animal/bot/firebot/proc/spray_water(atom/target, mob/user)
if(stationary_mode)
diff --git a/code/modules/mob/living/simple_animal/constructs.dm b/code/modules/mob/living/simple_animal/constructs.dm
index e63ceaa7f6182..7df454611412b 100644
--- a/code/modules/mob/living/simple_animal/constructs.dm
+++ b/code/modules/mob/living/simple_animal/constructs.dm
@@ -180,14 +180,14 @@
if(P.starting)
var/new_x = P.starting.x + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
var/new_y = P.starting.y + pick(0, 0, -1, 1, -2, 2, -2, 2, -2, 2, -3, 3, -3, 3)
- var/turf/curloc = get_turf(src)
+ var/turf/current_location = get_turf(src)
// redirect the projectile
P.original = locate(new_x, new_y, P.z)
- P.starting = curloc
+ P.starting = current_location
P.firer = src
- P.yo = new_y - curloc.y
- P.xo = new_x - curloc.x
+ P.yo = new_y - current_location.y
+ P.xo = new_x - current_location.x
var/new_angle_s = P.Angle + rand(120,240)
while(new_angle_s > 180) // Translate to regular projectile degrees
new_angle_s -= 360
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 f2b9417323fca..0dbb19c5a1032 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -453,7 +453,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/effect/temp_visual/lava_warning)
anchored = TRUE
opacity = FALSE
density = TRUE
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
duration = 82
color = COLOR_DARK_ORANGE
diff --git a/code/modules/mob/living/simple_animal/hostile/mimite.dm b/code/modules/mob/living/simple_animal/hostile/mimite.dm
index 32cdcec0884fc..8c45a86264468 100644
--- a/code/modules/mob/living/simple_animal/hostile/mimite.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mimite.dm
@@ -253,7 +253,7 @@
if(get_dist(src, entry_vent) <= 3)
var/list/vents = list()
var/datum/pipeline/entry_vent_parent = entry_vent.parents[1]
- for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in entry_vent_parent.other_atmosmch)
+ for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in entry_vent_parent.other_atmos_machines)
vents.Add(temp_vent)
if(!vents.len)
entry_vent = null
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
index 22ee2359b6f9c..723004162cb95 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
@@ -57,7 +57,7 @@
. = ..()
if(banana_time && banana_time < world.time)
var/turf/T = get_turf(src)
- var/list/adjacent = T.GetAtmosAdjacentTurfs(1)
+ var/list/adjacent = T.get_atmos_adjacent_turfs(1)
new banana_type(pick(adjacent))
banana_time = world.time + rand(30,60)
diff --git a/code/modules/mob/living/simple_animal/hostile/tree.dm b/code/modules/mob/living/simple_animal/hostile/tree.dm
index 64213374437fe..f70c499368058 100644
--- a/code/modules/mob/living/simple_animal/hostile/tree.dm
+++ b/code/modules/mob/living/simple_animal/hostile/tree.dm
@@ -49,11 +49,11 @@
if(isopenturf(loc))
var/turf/open/T = src.loc
if(T.air)
- var/co2 = T.air.get_moles(GAS_CO2)
+ var/co2 = GET_MOLES(/datum/gas/carbon_dioxide, T.air)
if(co2 > 0)
if(prob(25))
var/amt = min(co2, 9)
- T.air.adjust_moles(GAS_CO2, -amt)
+ T.air.gases[/datum/gas/carbon_dioxide][MOLES] += -amt
T.atmos_spawn_air("o2=[amt];TEMP=293.15")
/mob/living/simple_animal/hostile/tree/festivus
diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm
index 67f9136df2696..931e1638a7de5 100644
--- a/code/modules/mob/living/simple_animal/simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/simple_animal.dm
@@ -279,10 +279,10 @@
if(isturf(loc) && isopenturf(loc))
var/turf/open/ST = loc
if(ST.air)
- var/tox = ST.air.get_moles(GAS_PLASMA)
- var/oxy = ST.air.get_moles(GAS_O2)
- var/n2 = ST.air.get_moles(GAS_N2)
- var/co2 = ST.air.get_moles(GAS_CO2)
+ var/tox = GET_MOLES(/datum/gas/plasma, ST.air)
+ var/oxy = GET_MOLES(/datum/gas/oxygen, ST.air)
+ var/n2 = GET_MOLES(/datum/gas/nitrogen, ST.air)
+ var/co2 = GET_MOLES(/datum/gas/carbon_dioxide, ST.air)
if(atmos_requirements["min_oxy"] && oxy < atmos_requirements["min_oxy"])
. = FALSE
diff --git a/code/modules/mob/living/simple_animal/slime/life.dm b/code/modules/mob/living/simple_animal/slime/life.dm
index a043bcf72665a..8399b94e9d435 100644
--- a/code/modules/mob/living/simple_animal/slime/life.dm
+++ b/code/modules/mob/living/simple_animal/slime/life.dm
@@ -95,13 +95,13 @@
adjustBruteLoss(round(sqrt(bodytemperature)) * 2)
if(stat != DEAD)
- var/bz_percentage = environment.total_moles() ? (environment.get_moles(GAS_BZ) / environment.total_moles()) : 0
+ var/bz_percentage = environment.total_moles() ? (GET_MOLES(/datum/gas/bz, environment) / environment.total_moles()) : 0
var/stasis = (bz_percentage >= 0.05 && bodytemperature < (T0C + 100)) || force_stasis
if(transformeffects & SLIME_EFFECT_DARK_PURPLE)
var/amt = is_adult ? 30 : 15
- var/plas_amt = min(amt,environment.get_moles(GAS_PLASMA))
- environment.adjust_moles(GAS_PLASMA, -plas_amt)
- environment.adjust_moles(GAS_O2, plas_amt)
+ var/plas_amt = min(amt,GET_MOLES(/datum/gas/plasma, environment))
+ REMOVE_MOLES(/datum/gas/plasma, environment, plas_amt)
+ ADD_MOLES(/datum/gas/oxygen, environment, plas_amt)
adjustBruteLoss(plas_amt ? -2 : 0)
switch(stat)
diff --git a/code/modules/mob/living/ventcrawling.dm b/code/modules/mob/living/ventcrawling.dm
index 34a30f59b160a..9851fb8b6ce59 100644
--- a/code/modules/mob/living/ventcrawling.dm
+++ b/code/modules/mob/living/ventcrawling.dm
@@ -48,7 +48,7 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
if(vent_found)
var/datum/pipeline/vent_found_parent = vent_found.parents[1]
- if(vent_found_parent && (vent_found_parent.members.len || vent_found_parent.other_atmosmch))
+ if(vent_found_parent && (vent_found_parent.members.len || vent_found_parent.other_atmos_machines))
visible_message("[src] begins climbing into the ventilation system." ,"You begin climbing into the ventilation system.")
if(!do_after(src, 25, target = vent_found))
@@ -86,9 +86,9 @@ GLOBAL_LIST_INIT(ventcrawl_machinery, typecacheof(list(
return
var/list/totalMembers = list()
- for(var/datum/pipeline/P in starting_machine.returnPipenets())
+ for(var/datum/pipeline/P in starting_machine.return_pipenets())
totalMembers += P.members
- totalMembers += P.other_atmosmch
+ totalMembers += P.other_atmos_machines
if(!totalMembers.len)
return
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index 60568ac0b5070..989024342245a 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -137,9 +137,9 @@
var/t = "Coordinates: [x],[y] \n"
t += "Temperature: [environment.return_temperature()] \n"
- for(var/id in environment.get_gases())
- if(environment.get_moles(id))
- t+="[GLOB.gas_data.names[id]]: [environment.get_moles(id)] \n"
+ for(var/id in environment.gases)
+ if(environment.gases[id][MOLES])
+ t+="[GLOB.meta_gas_info[id][META_GAS_NAME]]: [environment.gases[id][MOLES]] \n"
to_chat(usr, t)
diff --git a/code/modules/modular_computers/file_system/programs/atmosscan.dm b/code/modules/modular_computers/file_system/programs/atmosscan.dm
index 10b2f2e7efc7d..23d8a53028585 100644
--- a/code/modules/modular_computers/file_system/programs/atmosscan.dm
+++ b/code/modules/modular_computers/file_system/programs/atmosscan.dm
@@ -30,10 +30,10 @@
data["AirTempC"] = round(environment.return_temperature() - T0C)
data["AirTempK"] = round(environment.return_temperature())
if (total_moles)
- for(var/id in environment.get_gases())
- var/gas_level = environment.get_moles(id)/total_moles
+ for(var/id in environment.gases)
+ var/gas_level = GET_MOLES(id, environment)/total_moles
if(gas_level > 0)
- airlist += list(list("name" = "[GLOB.gas_data.names[id]]", "percentage" = round(gas_level*100, 0.01)))
+ airlist += list(list("name" = "[GLOB.meta_gas_info[id][META_GAS_NAME]]", "percentage" = round(gas_level*100, 0.01)))
data["AirData"] = airlist
else
data["AirPressure"] = 0
diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm
index 2019fceb2c707..84d83d736a104 100644
--- a/code/modules/power/apc/apc_main.dm
+++ b/code/modules/power/apc/apc_main.dm
@@ -190,6 +190,18 @@
. = ..()
+/obj/machinery/power/apc/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
+/obj/machinery/power/apc/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return (exposed_temperature > 2000)
+
+/obj/machinery/power/apc/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ take_damage(min(exposed_temperature/100, 10), BURN)
+
+
+
/obj/machinery/power/apc/handle_atom_del(atom/A)
if(A == cell)
cell = null
diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm
index bbcc96bd490b9..d4bcf7ddd43f9 100644
--- a/code/modules/power/generator.dm
+++ b/code/modules/power/generator.dm
@@ -80,8 +80,8 @@
var/heat = energy_transfer*(1-efficiency)
lastgen += energy_transfer*efficiency
- hot_air.set_temperature(hot_air.return_temperature() - energy_transfer/hot_air_heat_capacity)
- cold_air.set_temperature(cold_air.return_temperature() + heat/cold_air_heat_capacity)
+ hot_air.temperature = (hot_air.return_temperature() - energy_transfer/hot_air_heat_capacity)
+ cold_air.temperature = (cold_air.return_temperature() + heat/cold_air_heat_capacity)
//add_avail(lastgen) This is done in process now
// update icon overlays only if displayed level has changed
diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm
index 7a79332566807..558e5efbc9692 100644
--- a/code/modules/power/lighting/light.dm
+++ b/code/modules/power/lighting/light.dm
@@ -127,6 +127,10 @@
if(nightshift_enabled)
update(FALSE, TRUE, TRUE)
+/obj/machinery/light/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
/obj/machinery/light/Destroy()
var/area/A = get_area(src)
if(A)
@@ -632,7 +636,10 @@
// called when on fire
-/obj/machinery/light/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+/obj/machinery/light/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature > 673
+
+/obj/machinery/light/atmos_expose(datum/gas_mixture/air, exposed_temperature)
if(prob(max(0, exposed_temperature - 673))) //0% at <400C, 100% at >500C
break_light_tube()
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index ce00cf86dfd14..57e54573e80b8 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -49,29 +49,30 @@
/obj/machinery/power/rad_collector/process(delta_time)
if(!loaded_tank)
return
+ var/datum/gas_mixture/loaded_tank_air = loaded_tank.return_air()
if(!bitcoinmining)
- if(loaded_tank.air_contents.get_moles(GAS_PLASMA) < 0.0001)
+ if(GET_MOLES(/datum/gas/plasma, loaded_tank.air_contents) < 0.0001)
investigate_log("out of fuel.", INVESTIGATE_ENGINES)
playsound(src, 'sound/machines/ding.ogg', 50, 1)
var/msg = "Plasma depleted, recommend replacing tank."
radio.talk_into(src, msg, RADIO_CHANNEL_ENGINEERING)
eject()
else
- var/gasdrained = min(powerproduction_drain*drainratio*delta_time,loaded_tank.air_contents.get_moles(GAS_PLASMA))
- loaded_tank.air_contents.adjust_moles(GAS_PLASMA, -gasdrained)
- loaded_tank.air_contents.adjust_moles(GAS_TRITIUM, gasdrained)
+ var/gasdrained = min(powerproduction_drain*drainratio*delta_time,GET_MOLES(/datum/gas/plasma, loaded_tank.air_contents))
+ REMOVE_MOLES(/datum/gas/plasma, loaded_tank.air_contents, gasdrained)
+ ADD_MOLES(/datum/gas/tritium, loaded_tank.air_contents, gasdrained)
var/power_produced = RAD_COLLECTOR_OUTPUT
add_avail(power_produced)
stored_energy-=power_produced
else if(is_station_level(z) && SSresearch.science_tech)
- if(!loaded_tank.air_contents.get_moles(GAS_TRITIUM) || !loaded_tank.air_contents.get_moles(GAS_O2))
+ if(!GET_MOLES(/datum/gas/tritium, loaded_tank.air_contents) || !GET_MOLES(/datum/gas/oxygen, loaded_tank.air_contents))
playsound(src, 'sound/machines/ding.ogg', 50, 1)
eject()
else
var/gasdrained = bitcoinproduction_drain*drainratio*delta_time
- loaded_tank.air_contents.adjust_moles(GAS_TRITIUM, -gasdrained)
- loaded_tank.air_contents.adjust_moles(GAS_O2, -gasdrained)
- loaded_tank.air_contents.adjust_moles(GAS_CO2, gasdrained*2)
+ loaded_tank_air.gases[/datum/gas/tritium][MOLES] += -gasdrained
+ loaded_tank_air.gases[/datum/gas/oxygen][MOLES] += -gasdrained
+ loaded_tank_air.gases[/datum/gas/carbon_dioxide][MOLES] += gasdrained*2
var/bitcoins_mined = RAD_COLLECTOR_OUTPUT
var/datum/bank_account/D = SSeconomy.get_budget_account(ACCOUNT_ENG_ID)
if(D)
@@ -86,7 +87,9 @@
toggle_power()
user.visible_message("[user.name] turns the [src.name] [active? "on":"off"].", \
"You turn the [src.name] [active? "on":"off"].")
- var/fuel = loaded_tank?.air_contents.get_moles(GAS_PLASMA)
+ var/fuel = 0
+ if(loaded_tank)
+ fuel = GET_MOLES(/datum/gas/plasma, loaded_tank.air_contents)
investigate_log("turned [active?"on":"off"] by [key_name(user)]. [loaded_tank?"Fuel: [round(fuel/0.29)]%":"It is empty"].", INVESTIGATE_ENGINES)
return
else
diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm
index fdeda81ddd307..bf8b25f1295b5 100644
--- a/code/modules/power/singularity/containment_field.dm
+++ b/code/modules/power/singularity/containment_field.dm
@@ -28,6 +28,7 @@
/obj/machinery/field/containment/Destroy()
FG1?.fields -= src
FG2?.fields -= src
+ air_update_turf(TRUE, FALSE)
return ..()
/obj/machinery/field/containment/proc/block_singularity()
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index d12d02585111d..57185bb495479 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -182,6 +182,8 @@ field_generator power level display
/obj/machinery/field/generator/proc/turn_off()
active = FG_OFFLINE
+ air_update_turf(TRUE, FALSE)
+ can_atmos_pass = ATMOS_PASS_YES
spawn(1)
cleanup()
while (warming_up>0 && !active)
@@ -251,8 +253,8 @@ field_generator power level display
turn_off()
return
move_resist = INFINITY
- CanAtmosPass = ATMOS_PASS_NO
- air_update_turf(TRUE)
+ can_atmos_pass = ATMOS_PASS_NO
+ air_update_turf(TRUE, TRUE)
addtimer(CALLBACK(src, PROC_REF(setup_field), 1), 1)
addtimer(CALLBACK(src, PROC_REF(setup_field), 2), 2)
addtimer(CALLBACK(src, PROC_REF(setup_field), 4), 3)
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 66d887c438d3e..3a0689d1b2dfb 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -222,14 +222,14 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
var/list/gasdata = list()
if(air.total_moles())
data["SM_moles"] = air.total_moles()
- for(var/gasid in air.get_gases())
+ for(var/gasid in air.gases)
gasdata.Add(list(list(
- "name"= GLOB.gas_data.names[gasid],
- "amount" = round(100*air.get_moles(gasid)/air.total_moles(),0.01))))
+ "name"= GLOB.meta_gas_info[gasid][META_GAS_NAME],
+ "amount" = round(100*GET_MOLES(gasid, air)/air.total_moles(),0.01))))
else
- for(var/gasid in air.get_gases())
+ for(var/gasid in air.gases)
gasdata.Add(list(list(
- "name"= GLOB.gas_data.names[gasid],
+ "name"= air.gases[gasid][GAS_META][META_GAS_NAME],
"amount" = 0)))
data["gases"] = gasdata
return data
@@ -457,15 +457,15 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
//Can cause an overestimation of mol count, should stabalize things though.
//Prevents huge bursts of gas/heat when a large amount of something is introduced
//They range between 0 and 1
- plasmacomp += clamp(max(removed.get_moles(GAS_PLASMA)/combined_gas, 0) - plasmacomp, -1, gas_change_rate)
- o2comp += clamp(max(removed.get_moles(GAS_O2)/combined_gas, 0) - o2comp, -1, gas_change_rate)
- co2comp += clamp(max(removed.get_moles(GAS_CO2)/combined_gas, 0) - co2comp, -1, gas_change_rate)
- pluoxiumcomp += clamp(max(removed.get_moles(GAS_PLUOXIUM)/combined_gas, 0) - pluoxiumcomp, -1, gas_change_rate)
- tritiumcomp += clamp(max(removed.get_moles(GAS_TRITIUM)/combined_gas, 0) - tritiumcomp, -1, gas_change_rate)
- bzcomp += clamp(max(removed.get_moles(GAS_BZ)/combined_gas, 0) - bzcomp, -1, gas_change_rate)
+ plasmacomp += clamp(max(GET_MOLES(/datum/gas/plasma, removed)/combined_gas, 0) - plasmacomp, -1, gas_change_rate)
+ o2comp += clamp(max(GET_MOLES(/datum/gas/oxygen, removed)/combined_gas, 0) - o2comp, -1, gas_change_rate)
+ co2comp += clamp(max(GET_MOLES(/datum/gas/carbon_dioxide, removed)/combined_gas, 0) - co2comp, -1, gas_change_rate)
+ pluoxiumcomp += clamp(max(GET_MOLES(/datum/gas/pluoxium, removed)/combined_gas, 0) - pluoxiumcomp, -1, gas_change_rate)
+ tritiumcomp += clamp(max(GET_MOLES(/datum/gas/tritium, removed)/combined_gas, 0) - tritiumcomp, -1, gas_change_rate)
+ bzcomp += clamp(max(GET_MOLES(/datum/gas/bz, removed)/combined_gas, 0) - bzcomp, -1, gas_change_rate)
- n2ocomp += clamp(max(removed.get_moles(GAS_NITROUS)/combined_gas, 0) - n2ocomp, -1, gas_change_rate)
- n2comp += clamp(max(removed.get_moles(GAS_N2)/combined_gas, 0) - n2comp, -1, gas_change_rate)
+ n2ocomp += clamp(max(GET_MOLES(/datum/gas/nitrous_oxide, removed)/combined_gas, 0) - n2ocomp, -1, gas_change_rate)
+ n2comp += clamp(max(GET_MOLES(/datum/gas/nitrogen, removed)/combined_gas, 0) - n2comp, -1, gas_change_rate)
gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp + tritiumcomp + bzcomp - pluoxiumcomp - n2comp, 0), 1)
@@ -516,18 +516,18 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
//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.
- removed.set_temperature(removed.return_temperature() + ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER))
+ removed.temperature = (removed.return_temperature() + ((device_energy * dynamic_heat_modifier) / THERMAL_RELEASE_MODIFIER))
- removed.set_temperature(max(0, min(removed.return_temperature(), 2500 * dynamic_heat_modifier)))
+ removed.temperature = (max(0, min(removed.return_temperature(), 2500 * dynamic_heat_modifier)))
//Calculate how much gas to release
- removed.adjust_moles(GAS_PLASMA, max((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER, 0))
+ ADD_MOLES(/datum/gas/plasma, removed, max((device_energy * dynamic_heat_modifier) / PLASMA_RELEASE_MODIFIER, 0))
- removed.adjust_moles(GAS_O2, max(((device_energy + removed.return_temperature() * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER, 0))
+ ADD_MOLES(/datum/gas/oxygen, removed, max(((device_energy + removed.return_temperature() * dynamic_heat_modifier) - T0C) / OXYGEN_RELEASE_MODIFIER, 0))
if(produces_gas)
env.merge(removed)
- air_update_turf()
+ air_update_turf(FALSE, FALSE)
for(var/mob/living/carbon/human/l in viewers(HALLUCINATION_RANGE(power), src)) // If they can see it without mesons on. Bad on them.
if(HAS_TRAIT(l, TRAIT_MADNESS_IMMUNE) || (l.mind && HAS_TRAIT(l.mind, TRAIT_MADNESS_IMMUNE)))
diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm
index f4a77de779931..9e6b93bbf22cc 100644
--- a/code/modules/power/turbine.dm
+++ b/code/modules/power/turbine.dm
@@ -29,7 +29,7 @@
icon_state = "compressor"
density = TRUE
resistance_flags = FIRE_PROOF
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
circuit = /obj/item/circuitboard/machine/power_compressor
var/obj/machinery/power/turbine/turbine
var/datum/gas_mixture/gas_contained
@@ -54,7 +54,7 @@
icon_state = "turbine"
density = TRUE
resistance_flags = FIRE_PROOF
- CanAtmosPass = ATMOS_PASS_DENSITY
+ can_atmos_pass = ATMOS_PASS_DENSITY
circuit = /obj/item/circuitboard/machine/power_turbine
diff --git a/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm b/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm
index 18607b919aba4..64279d6ddccc4 100644
--- a/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm
+++ b/code/modules/procedural_mapping/mapGeneratorModules/helpers.dm
@@ -12,11 +12,8 @@
var/list/map = mother.map
for(var/turf/open/T in map)
if(T.air)
- if(T.initial_gas_mix)
- T.air.parse_gas_string(T.initial_gas_mix)
- T.set_temperature(T.air.return_temperature())
- else
- T.air.copy_from_turf(T)
+ T.air = T.create_gas_mixture()
+ SSair.add_to_active(T, TRUE)
/datum/mapGeneratorModule/bottomLayer/massdelete
spawnableAtoms = list()
diff --git a/code/modules/projectiles/ammunition/_firing.dm b/code/modules/projectiles/ammunition/_firing.dm
index b3f6c491ccfcf..4819a42f9cc32 100644
--- a/code/modules/projectiles/ammunition/_firing.dm
+++ b/code/modules/projectiles/ammunition/_firing.dm
@@ -41,8 +41,8 @@
qdel(reagents)
/obj/item/ammo_casing/proc/throw_proj(atom/target, turf/targloc, mob/living/user, params, spread)
- var/turf/curloc = get_turf(user)
- if (!istype(targloc) || !istype(curloc) || !BB)
+ var/turf/current_location = get_turf(user)
+ if (!istype(targloc) || !istype(current_location) || !BB)
return FALSE
var/firing_dir
@@ -52,7 +52,7 @@
new firing_effect_type(get_turf(src), firing_dir)
var/direct_target
- if(targloc == curloc)
+ if(targloc == current_location)
if(target) //if the target is right on our location we'll skip the travelling code in the proj's fire()
direct_target = target
if(!direct_target)
diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm
index a403dd09a0e98..3d90d6b3cc89b 100644
--- a/code/modules/projectiles/guns/misc/beam_rifle.dm
+++ b/code/modules/projectiles/guns/misc/beam_rifle.dm
@@ -192,12 +192,12 @@
P.color = rgb(255 * percent,255 * ((100 - percent) / 100),0)
else
P.color = rgb(0, 255, 0)
- var/turf/curloc = get_turf(src)
+ var/turf/current_location = get_turf(src)
var/turf/targloc = get_turf(aiming_target)
if(!istype(targloc))
- if(!istype(curloc))
+ if(!istype(current_location))
return
- targloc = get_turf_in_angle(lastangle, curloc, 10)
+ targloc = get_turf_in_angle(lastangle, current_location, 10)
P.preparePixelProjectile(targloc, current_user, aiming_params, 0)
P.fire(lastangle)
@@ -382,12 +382,12 @@
HS_BB.gun = host
/obj/item/ammo_casing/energy/beam_rifle/throw_proj(atom/target, turf/targloc, mob/living/user, params, spread)
- var/turf/curloc = get_turf(user)
- if(!istype(curloc) || !BB)
+ var/turf/current_location = get_turf(user)
+ if(!istype(current_location) || !BB)
return FALSE
var/obj/item/gun/energy/beam_rifle/gun = loc
if(!targloc && gun)
- targloc = get_turf_in_angle(gun.lastangle, curloc, 10)
+ targloc = get_turf_in_angle(gun.lastangle, current_location, 10)
else if(!targloc)
return FALSE
var/firing_dir
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index 978e3e6851040..f73944924c6c9 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -844,7 +844,7 @@
//Spread is FORCED!
/obj/projectile/proc/preparePixelProjectile(atom/target, atom/source, params, spread = 0)
- var/turf/curloc = get_turf(source)
+ var/turf/current_location = get_turf(source)
var/turf/targloc = get_turf(target)
trajectory_ignore_forcemove = TRUE
forceMove(get_turf(source))
@@ -852,8 +852,8 @@
starting = get_turf(source)
original = target
if(targloc || !params)
- yo = targloc.y - curloc.y
- xo = targloc.x - curloc.x
+ yo = targloc.y - current_location.y
+ xo = targloc.x - current_location.x
set_angle(get_angle(src, targloc) + spread)
if(isliving(source) && params)
@@ -863,8 +863,8 @@
set_angle(calculated[1] + spread)
else if(targloc)
- yo = targloc.y - curloc.y
- xo = targloc.x - curloc.x
+ yo = targloc.y - current_location.y
+ xo = targloc.x - current_location.x
set_angle(get_angle(src, targloc) + spread)
else
stack_trace("WARNING: Projectile [type] fired without either mouse parameters, or a target atom to aim at!")
diff --git a/code/modules/reagents/chem_splash.dm b/code/modules/reagents/chem_splash.dm
index 431754b4fce67..13f36942604eb 100644
--- a/code/modules/reagents/chem_splash.dm
+++ b/code/modules/reagents/chem_splash.dm
@@ -45,7 +45,7 @@
for(var/turf/T as() in turflist)
if(accessible[T])
continue
- for(var/thing in T.GetAtmosAdjacentTurfs(alldir = TRUE))
+ for(var/thing in T.get_atmos_adjacent_turfs(alldir = TRUE))
var/turf/NT = thing
if(!(NT in accessible))
continue
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 345901695efff..9c614a3a96903 100755
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -299,7 +299,7 @@
if(isopenturf(T))
var/turf/open/OT = T
OT.MakeSlippery(wet_setting=TURF_WET_ICE, min_wet_time=100, wet_time_to_add=reac_volume SECONDS) // Is less effective in high pressure/high heat capacity environments. More effective in low pressure.
- OT.air.set_temperature(OT.air.return_temperature() - MOLES_CELLSTANDARD*100*reac_volume/OT.air.heat_capacity()) // reduces environment temperature by 5K per unit.
+ OT.air.temperature = (OT.air.return_temperature() - MOLES_CELLSTANDARD*100*reac_volume/OT.air.heat_capacity()) // reduces environment temperature by 5K per unit.
/datum/reagent/consumable/condensedcapsaicin
name = "Condensed Capsaicin"
@@ -455,7 +455,7 @@
var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T)
if(hotspot)
var/datum/gas_mixture/lowertemp = T.return_air()
- lowertemp.set_temperature(max( min(lowertemp.return_temperature()-2000,lowertemp.return_temperature() / 2) ,TCMB))
+ lowertemp.temperature = (max( min(lowertemp.return_temperature()-2000,lowertemp.return_temperature() / 2) ,TCMB))
lowertemp.react(src)
qdel(hotspot)
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index add12c80b80ba..54dbb9836ddc0 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -187,7 +187,7 @@
if(hotspot && !isspaceturf(T))
if(T.air)
var/datum/gas_mixture/G = T.air
- G.set_temperature(max(min(G.return_temperature()-(CT*1000),G.return_temperature()/CT),TCMB))
+ G.temperature = (max(min(G.return_temperature()-(CT*1000),G.return_temperature()/CT),TCMB))
G.react(src)
qdel(hotspot)
var/obj/effect/acid/A = (locate(/obj/effect/acid) in T)
diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
index c22f01d136836..e1f43eadab69e 100644
--- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm
@@ -322,7 +322,7 @@
if(T.air)
var/datum/gas_mixture/G = T.air
if(G.return_temperature() > T20C)
- G.set_temperature(max(G.return_temperature()/2,T20C))
+ G.temperature = (max(G.return_temperature()/2,T20C))
G.react(src)
qdel(hotspot)
diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm
index f2998e7f8de6b..1fc448358e0b5 100644
--- a/code/modules/reagents/reagent_containers.dm
+++ b/code/modules/reagents/reagent_containers.dm
@@ -181,8 +181,8 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/item/reagent_containers)
reagents.expose_temperature(1000)
return ..()
-/obj/item/reagent_containers/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- reagents.expose_temperature(exposed_temperature)
+/obj/item/reagent_containers/fire_act(temperature, volume)
+ reagents.expose_temperature(temperature)
/obj/item/reagent_containers/on_reagent_change(changetype)
update_icon()
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index 41809a81de167..5ba3459cfd571 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -396,16 +396,16 @@ CREATION_TEST_IGNORE_SUBTYPES(/obj/machinery/disposal)
var/atom/L = loc //recharging from loc turf
var/datum/gas_mixture/env = L.return_air()
+ if(!env.temperature)
+ return
var/pressure_delta = (SEND_PRESSURE*1.01) - air_contents.return_pressure()
- if(env.return_temperature() > 0)
- var/transfer_moles = 0.05 * delta_time * pressure_delta * air_contents.return_volume() / (env.return_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()
+ var/transfer_moles = 0.05 * delta_time * (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(FALSE, FALSE)
//if full enough, switch to ready mode
if(air_contents.return_pressure() >= SEND_PRESSURE)
diff --git a/code/modules/recycling/disposal/holder.dm b/code/modules/recycling/disposal/holder.dm
index 3f03a8aee8502..380325e57e544 100644
--- a/code/modules/recycling/disposal/holder.dm
+++ b/code/modules/recycling/disposal/holder.dm
@@ -29,7 +29,7 @@
/obj/structure/disposalholder/proc/init(obj/machinery/disposal/D)
if(!istype(D))
return //Why check for things that don't exist?
- gas = D.air_contents// transfer gas resv. into holder object
+ gas = D.return_air()// transfer gas resv. into holder object
//Check for any living mobs trigger hasmob.
//hasmob effects whether the package goes to cargo or its tagged destination.
@@ -148,7 +148,6 @@
// called to vent all gas in holder to a location
/obj/structure/disposalholder/proc/vent_gas(turf/T)
T.assume_air(gas)
- T.air_update_turf()
/obj/structure/disposalholder/AllowDrop()
return TRUE
diff --git a/code/modules/research/xenobiology/crossbreeding/_misc.dm b/code/modules/research/xenobiology/crossbreeding/_misc.dm
index 8fee94597f33f..26990b87c8098 100644
--- a/code/modules/research/xenobiology/crossbreeding/_misc.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_misc.dm
@@ -129,7 +129,7 @@ Slimecrossing Items
desc = "A mass of solidified slime gel - completely impenetrable, but it's melting away!"
icon = 'icons/obj/slimecrossing.dmi'
icon_state = "slimebarrier_thick"
- CanAtmosPass = ATMOS_PASS_NO
+ can_atmos_pass = ATMOS_PASS_NO
opacity = TRUE
timeleft = 100
diff --git a/code/modules/research/xenobiology/crossbreeding/_structures.dm b/code/modules/research/xenobiology/crossbreeding/_structures.dm
index f54a072c32e76..b4ca3ae75bea6 100644
--- a/code/modules/research/xenobiology/crossbreeding/_structures.dm
+++ b/code/modules/research/xenobiology/crossbreeding/_structures.dm
@@ -149,8 +149,8 @@ GLOBAL_LIST_EMPTY(bluespace_slime_crystals)
if(!istype(T))
return
var/datum/gas_mixture/gas = T.return_air()
- gas.set_temperature(T0C + 200)
- T.air_update_turf()
+ gas.temperature = (T0C + 200)
+ T.air_update_turf(FALSE, FALSE)
/obj/structure/slime_crystal/purple
colour = "purple"
@@ -191,7 +191,7 @@ GLOBAL_LIST_EMPTY(bluespace_slime_crystals)
continue
var/datum/gas_mixture/gas = T.return_air()
gas.parse_gas_string(OPENTURF_DEFAULT_ATMOS)
- T.air_update_turf()
+ T.air_update_turf(FALSE, FALSE)
/obj/structure/slime_crystal/metal
colour = "metal"
@@ -236,8 +236,8 @@ GLOBAL_LIST_EMPTY(bluespace_slime_crystals)
var/turf/open/open_turf = T
var/datum/gas_mixture/air = open_turf.return_air()
- if(air.get_moles(GAS_PLASMA) > 15)
- air.adjust_moles(GAS_PLASMA, -15)
+ if(GET_MOLES(/datum/gas/plasma, air) > 15)
+ REMOVE_MOLES(/datum/gas/plasma, air, 15)
new /obj/item/stack/sheet/mineral/plasma(open_turf)
/obj/structure/slime_crystal/darkpurple/Destroy()
diff --git a/code/modules/research/xenobiology/crossbreeding/chilling.dm b/code/modules/research/xenobiology/crossbreeding/chilling.dm
index 9a1e4d432f6ce..57a1ac0fb826f 100644
--- a/code/modules/research/xenobiology/crossbreeding/chilling.dm
+++ b/code/modules/research/xenobiology/crossbreeding/chilling.dm
@@ -106,9 +106,10 @@ Chilling extracts:
for(var/turf/open/T in A)
var/datum/gas_mixture/G = T.air
if(istype(G))
- G.set_moles(GAS_PLASMA, 0)
+ G.gases[/datum/gas/plasma][MOLES] = 0
+
filtered = TRUE
- T.air_update_turf()
+ T.air_update_turf(FALSE, FALSE)
if(filtered)
user.visible_message("Cracks spread throughout [src], and some air is sucked in!")
else
diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm
index 65859a5902198..11008e77ef95d 100644
--- a/code/modules/shuttle/on_move.dm
+++ b/code/modules/shuttle/on_move.dm
@@ -33,7 +33,7 @@ All ShuttleMove procs go here
if(M.pulledby)
M.pulledby.stop_pulling()
M.stop_pulling()
- M.visible_message("[shuttle] slams into [M]!")
+ M.visible_message("")
SSblackbox.record_feedback("tally", "shuttle_gib", 1, M.type)
M.gib()
@@ -71,15 +71,10 @@ All ShuttleMove procs go here
sanity.Insert(inject_index, /turf/baseturf_skipover/shuttle)
newT.baseturfs = baseturfs_string_list(sanity, newT)
+ air_update_turf(TRUE, TRUE)
if(isopenturf(src))
- var/turf/open/after_src_terf = src
- update_air_ref(isspaceturf(src) ? 0 : (after_src_terf.planetary_atmos ? 1 : 2))
- else
- update_air_ref(-1)
-
- //Air stuff
- newT.air_update_turf(TRUE)
- air_update_turf(TRUE)
+ var/turf/open/new_open = newT
+ new_open.copy_air_with_tile(src)
return TRUE
@@ -119,8 +114,8 @@ All ShuttleMove procs go here
return TRUE
/turf/proc/lateShuttleMove(turf/oldT)
- air_update_turf(TRUE)
- oldT.air_update_turf(TRUE)
+ air_update_turf(TRUE, blocks_air)
+ oldT.air_update_turf(TRUE, oldT.blocks_air)
/////////////////////////////////////////////////////////////////////////////////////
@@ -258,20 +253,20 @@ All ShuttleMove procs go here
break
if(!connected)
- nullifyNode(i)
+ nullify_node(i)
if(!nodes[i])
missing_nodes = TRUE
if(missing_nodes)
- atmosinit()
+ atmos_init()
for(var/obj/machinery/atmospherics/A in pipeline_expansion())
- A.atmosinit()
- if(A.returnPipenet())
- A.addMember(src)
+ A.atmos_init()
+ if(A.return_pipenet())
+ A.add_member(src)
SSair.add_to_rebuild_queue(src)
else
- // atmosinit() calls update_icon(), so we don't need to call it
+ // atmos_init() calls update_icon(), so we don't need to call it
update_icon()
/obj/machinery/navbeacon/beforeShuttleMove(turf/newT, rotation, move_mode, obj/docking_port/mobile/moving_dock)
diff --git a/code/modules/shuttle/shuttle_rotate.dm b/code/modules/shuttle/shuttle_rotate.dm
index dcfbdaf5794fe..9250197db416d 100644
--- a/code/modules/shuttle/shuttle_rotate.dm
+++ b/code/modules/shuttle/shuttle_rotate.dm
@@ -81,13 +81,13 @@ If ever any of these procs are useful for non-shuttles, rename it to proc/rotate
/************************************Machine rotate procs************************************/
/obj/machinery/atmospherics/shuttleRotate(rotation, params)
- var/list/real_node_connect = getNodeConnects()
+ var/list/real_node_connect = get_node_connects()
for(var/i in 1 to device_type)
real_node_connect[i] = angle2dir(rotation+dir2angle(real_node_connect[i]))
. = ..()
- SetInitDirections()
- var/list/supposed_node_connect = getNodeConnects()
+ set_init_directions()
+ var/list/supposed_node_connect = get_node_connects()
var/list/nodes_copy = nodes.Copy()
for(var/i in 1 to device_type)
diff --git a/code/modules/shuttle/super_cruise/orbital_poi_generator/loot/alien_artifact.dm b/code/modules/shuttle/super_cruise/orbital_poi_generator/loot/alien_artifact.dm
index 761873d5532c7..e08f1a70b8a80 100644
--- a/code/modules/shuttle/super_cruise/orbital_poi_generator/loot/alien_artifact.dm
+++ b/code/modules/shuttle/super_cruise/orbital_poi_generator/loot/alien_artifact.dm
@@ -200,7 +200,7 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom/movable/proximity_monitor_holder)
/datum/artifact_effect/airfreeze/Initialize(atom/source)
. = ..()
- source.CanAtmosPass = ATMOS_PASS_NO
+ source.can_atmos_pass = ATMOS_PASS_NO
/datum/artifact_effect/airfreeze/register_signals(source)
RegisterSignal(source, COMSIG_MOVABLE_MOVED, PROC_REF(updateAir))
@@ -208,10 +208,10 @@ CREATION_TEST_IGNORE_SUBTYPES(/atom/movable/proximity_monitor_holder)
/datum/artifact_effect/airfreeze/proc/updateAir(atom/source, atom/oldLoc)
if(isturf(oldLoc))
var/turf/oldTurf = oldLoc
- oldTurf.air_update_turf(TRUE)
+ oldTurf.air_update_turf(TRUE, TRUE)
if(isturf(source.loc))
var/turf/newTurf = source.loc
- newTurf.air_update_turf(TRUE)
+ newTurf.air_update_turf(TRUE, TRUE)
//===================
// Atmos Stabilizer
@@ -418,10 +418,10 @@ GLOBAL_LIST_EMPTY(destabliization_exits)
var/datum/gas_mixture/air = T.return_air()
var/input_id = initial(input.id)
var/output_id = initial(output.id)
- var/moles = min(air.get_moles(input_id), 5)
+ var/moles = min(GET_MOLES(input_id, air), 5)
if(moles)
- air.adjust_moles(input_id, -moles)
- air.adjust_moles(output_id, moles)
+ air.gases[input_id][MOLES] += -moles
+ air.gases[output_id][MOLES] += moles
//===================
// Recharger
diff --git a/code/modules/shuttle/super_cruise/shuttle_components/plasma_refiner.dm b/code/modules/shuttle/super_cruise/shuttle_components/plasma_refiner.dm
index 96603f6d019e0..813c54dfb0d82 100644
--- a/code/modules/shuttle/super_cruise/shuttle_components/plasma_refiner.dm
+++ b/code/modules/shuttle/super_cruise/shuttle_components/plasma_refiner.dm
@@ -20,7 +20,7 @@
if(!air_contents)
return
qdel(stack)
- air_contents.adjust_moles(GAS_PLASMA, moles_created)
+ air_contents.gases[/datum/gas/plasma][MOLES] += moles_created
say("[moles_created] moles of plasma refined.")
return
@@ -35,12 +35,12 @@
/obj/machinery/atmospherics/components/unary/plasma_refiner/AltClick(mob/living/user)
var/datum/gas_mixture/air_contents = airs[1]
- var/plasmoles = air_contents.get_moles(GAS_PLASMA)
+ var/plasmoles = GET_MOLES(/datum/gas/plasma, air_contents)
if(!air_contents)
return
if(plasmoles >= 100)
var/obj/item/stack/sheet/mineral/plasma/P = new(src.loc, 1)
- air_contents.adjust_moles(GAS_PLASMA, -100)
+ air_contents.gases[/datum/gas/plasma][MOLES] += -100
say("100 moles of plasma consumed. A sheet of [P.name] has been created.")
else
say("Insufficient plasma. At least 100 moles of plasma are required. There are currently [plasmoles] moles of plasma.")
@@ -56,16 +56,16 @@
/obj/machinery/atmospherics/components/unary/plasma_refiner/default_change_direction_wrench(mob/user, obj/item/I)
. = ..()
if(.)
- SetInitDirections()
+ set_init_directions()
var/obj/machinery/atmospherics/node = nodes[1]
if(node)
node.disconnect(src)
nodes[1] = null
if(parents[1])
- nullifyPipenet(parents[1])
- atmosinit()
+ nullify_pipenet(parents[1])
+ atmos_init()
node = nodes[1]
if(node)
- node.atmosinit()
- node.addMember(src)
+ node.atmos_init()
+ node.add_member(src)
SSair.add_to_rebuild_queue(src)
diff --git a/code/modules/station_goals/dna_vault.dm b/code/modules/station_goals/dna_vault.dm
index 90dffe1eb6a6d..980f92adc54eb 100644
--- a/code/modules/station_goals/dna_vault.dm
+++ b/code/modules/station_goals/dna_vault.dm
@@ -263,7 +263,7 @@
to_chat(H, "You feel resistant to airborne toxins.")
if(locate(/obj/item/organ/lungs) in H.internal_organs)
var/obj/item/organ/lungs/L = H.internal_organs_slot[ORGAN_SLOT_LUNGS]
- L.gas_max -= GAS_PLASMA
+ L.gas_max -= /datum/gas/plasma
ADD_TRAIT(H, TRAIT_VIRUSIMMUNE, "dna_vault")
if(VAULT_NOBREATH)
to_chat(H, "Your lungs feel great.")
diff --git a/code/modules/surgery/organs/augments_chest.dm b/code/modules/surgery/organs/augments_chest.dm
index 5edb0bbf147ad..26bf330da7da2 100644
--- a/code/modules/surgery/organs/augments_chest.dm
+++ b/code/modules/surgery/organs/augments_chest.dm
@@ -198,8 +198,9 @@
// Priority 3: use internals tank.
var/obj/item/tank/I = owner.internal
- if(I && I.air_contents && I.air_contents.total_moles() >= num && use_fuel)
- T.assume_air_moles(I.air_contents, num)
+ var/datum/gas_mixture/I_air = I.return_air()
+ if(I && I_air && I_air.total_moles() >= num && use_fuel)
+ T.assume_air_moles(I_air, num)
toggle(silent = TRUE)
return 0
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index 2f00674d27b44..7f7e1d74d24f1 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -23,6 +23,7 @@
food_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/medicine/salbutamol = 5)
//Breath damage
+ //These thresholds are checked against what amounts to total_mix_pressure * (gas_type_mols/total_mols)
var/breathing_class = BREATH_OXY // can be a gas instead of a breathing class
var/safe_breath_min = 16
@@ -32,8 +33,8 @@
var/safe_damage_type = OXY
var/list/gas_min = list()
var/list/gas_max = list(
- GAS_CO2 = 30, // Yes it's an arbitrary value who cares?
- GAS_PLASMA = MOLES_GAS_VISIBLE
+ /datum/gas/carbon_dioxide = 30, // Yes it's an arbitrary value who cares?
+ /datum/breathing_class/plasma = MOLES_GAS_VISIBLE
)
var/list/gas_damage = list(
"default" = list(
@@ -41,7 +42,7 @@
max = MAX_TOXIC_GAS_DAMAGE,
damage_type = OXY
),
- GAS_PLASMA = list(
+ /datum/gas/plasma = list(
min = MIN_TOXIC_GAS_DAMAGE,
max = MAX_TOXIC_GAS_DAMAGE,
damage_type = TOX
@@ -146,13 +147,12 @@
var/alert_category
var/alert_type
if(ispath(breathing_class))
- var/datum/breathing_class/class = GLOB.gas_data.breathing_classes[breathing_class]
+ var/datum/breathing_class/class = GLOB.breathing_class_info[breathing_class]
alert_category = class.low_alert_category
alert_type = class.low_alert_datum
else
- var/list/breath_alert_info = GLOB.gas_data.breath_alert_info
- if(breathing_class in breath_alert_info)
- var/list/alert = breath_alert_info[breathing_class]["not_enough_alert"]
+ var/list/alert = GLOB.meta_gas_info[breathing_class][META_GAS_BREATH_ALERT_INFO]?["not_enough_alert"]
+ if(alert)
alert_category = alert["alert_category"]
alert_type = alert["alert_type"]
throw_alert_for(H, alert_category, alert_type)
@@ -160,15 +160,13 @@
#define PP_MOLES(X) ((X / total_moles) * pressure)
- #define PP(air, gas) PP_MOLES(air.get_moles(gas))
+ #define PP(air, gas) PP_MOLES(GET_MOLES(gas, air))
var/gas_breathed = 0
var/pressure = breath.return_pressure()
var/total_moles = breath.total_moles()
- var/list/breath_alert_info = GLOB.gas_data.breath_alert_info
- var/list/breath_results = GLOB.gas_data.breath_results
- var/list/breathing_classes = GLOB.gas_data.breathing_classes
+ var/list/breathing_classes = GLOB.breathing_class_info
var/list/mole_adjustments = list()
for(var/entry in gas_min)
var/required_pp = 0
@@ -176,14 +174,16 @@
var/safe_min = gas_min[entry]
var/alert_category = null
var/alert_type = null
- if(ispath(entry))
- var/datum/breathing_class/class = breathing_classes[entry]
+ var/datum/breathing_class/class = breathing_classes[entry]
+ if(class)
var/list/gases = class.gases
var/list/products = class.products
alert_category = class.low_alert_category
alert_type = class.low_alert_datum
for(var/gas in gases)
- var/moles = breath.get_moles(gas)
+ if (!(gas in breath.gases))
+ continue
+ var/moles = breath.gases[gas][MOLES]
var/multiplier = gases[gas]
mole_adjustments[gas] = (gas in mole_adjustments) ? mole_adjustments[gas] - moles : -moles
required_pp += PP_MOLES(moles) * multiplier
@@ -193,14 +193,14 @@
for(var/product in products)
mole_adjustments[product] = (product in mole_adjustments) ? mole_adjustments[product] + to_add : to_add
else
- required_moles = breath.get_moles(entry)
+ required_moles = GET_MOLES(entry, breath)
required_pp = PP_MOLES(required_moles)
- if(entry in breath_alert_info)
- var/list/alert = breath_alert_info[entry]["not_enough_alert"]
+ var/list/alert = GLOB.meta_gas_info[entry][META_GAS_BREATH_ALERT_INFO]?["not_enough_alert"]
+ if(alert)
alert_category = alert["alert_category"]
alert_type = alert["alert_type"]
mole_adjustments[entry] = -required_moles
- mole_adjustments[breath_results[entry]] = required_moles
+ mole_adjustments[GLOB.meta_gas_info[entry][META_GAS_BREATH_RESULTS]] = required_moles
if(required_pp < safe_min)
var/multiplier = handle_too_little_breath(H, required_pp, safe_min, required_moles)
if(required_moles > 0)
@@ -213,28 +213,26 @@
if(H.health >= H.crit_threshold)
H.adjustOxyLoss(-breathModifier)
clear_alert_for(H, alert_category)
- var/list/danger_reagents = GLOB.gas_data.breath_reagents_dangerous
for(var/entry in gas_max)
var/found_pp = 0
- var/datum/breathing_class/breathing_class = entry
+ var/datum/breathing_class/breathing_class = breathing_classes[entry]
var/datum/reagent/danger_reagent = null
var/alert_category = null
var/alert_type = null
- if(ispath(breathing_class))
- breathing_class = breathing_classes[breathing_class]
+ if(breathing_class)
alert_category = breathing_class.high_alert_category
alert_type = breathing_class.high_alert_datum
danger_reagent = breathing_class.danger_reagent
found_pp = breathing_class.get_effective_pp(breath)
else
- danger_reagent = danger_reagents[entry]
- if(entry in breath_alert_info)
- var/list/alert = breath_alert_info[entry]["too_much_alert"]
+ danger_reagent = GLOB.meta_gas_info[entry][META_GAS_BREATH_REAGENT_DANGEROUS]
+ var/list/alert = GLOB.meta_gas_info[entry][META_GAS_BREATH_ALERT_INFO]?["too_much_alert"]
+ if(alert)
alert_category = alert["alert_category"]
alert_type = alert["alert_type"]
found_pp = PP(breath, entry)
if(found_pp > gas_max[entry])
- if(istype(danger_reagent))
+ if(danger_reagent && istype(danger_reagent))
H.reagents.add_reagent(danger_reagent,1)
var/list/damage_info = (entry in gas_damage) ? gas_damage[entry] : gas_damage["default"]
var/dam = found_pp / gas_max[entry] * 10
@@ -242,22 +240,21 @@
throw_alert_for(H, alert_category, alert_type)
else
clear_alert_for(H, alert_category)
- var/list/breath_reagents = GLOB.gas_data.breath_reagents
- for(var/gas in breath.get_gases())
- if(gas in breath_reagents)
- var/datum/reagent/R = breath_reagents[gas]
- //H.reagents.add_reagent(R, breath.get_moles(gas) * R.molarity) // See next line
- H.reagents.add_reagent(R, breath.get_moles(gas) * 2) // 2 represents molarity of O2, we don't have citadel molarity
- mole_adjustments[gas] = (gas in mole_adjustments) ? mole_adjustments[gas] - breath.get_moles(gas) : -breath.get_moles(gas)
+ for(var/gas in breath.gases)
+ var/datum/reagent/R = GLOB.meta_gas_info[gas][META_GAS_BREATH_REAGENT]
+ if(R)
+ //H.reagents.add_reagent(R, breath.gases[gas][MOLES] * R.molarity) // See next line
+ H.reagents.add_reagent(R, breath.gases[gas][MOLES] * 2) // 2 represents molarity of O2, we don't have citadel molarity
+ mole_adjustments[gas] = (gas in mole_adjustments) ? mole_adjustments[gas] - breath.gases[gas][MOLES] : -breath.gases[gas][MOLES]
for(var/gas in mole_adjustments)
- breath.adjust_moles(gas, mole_adjustments[gas])
+ ADJUST_MOLES(gas, breath, mole_adjustments[gas])
if(breath) // If there's some other shit in the air lets deal with it here.
// N2O
- var/SA_pp = PP(breath, GAS_NITROUS)
+ var/SA_pp = PP(breath, /datum/gas/nitrous_oxide)
if(SA_pp > SA_para_min) // Enough to make us stunned for a bit
H.Unconscious(60) // 60 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
@@ -271,7 +268,7 @@
// BZ
- var/bz_pp = PP(breath, GAS_BZ)
+ var/bz_pp = PP(breath, /datum/gas/bz)
if(bz_pp > BZ_brain_damage_min)
H.hallucination += 10
H.reagents.add_reagent(/datum/reagent/metabolite/bz,5)
@@ -283,7 +280,7 @@
H.reagents.add_reagent(/datum/reagent/metabolite/bz,1)
// Nitryl
- var/nitryl_pp = PP(breath,GAS_NITRYL)
+ var/nitryl_pp = PP(breath,/datum/gas/nitryl)
if (prob(nitryl_pp))
to_chat(H, "Your mouth feels like it's burning!")
if (nitryl_pp >40)
@@ -294,18 +291,18 @@
H.silent = max(H.silent, 3)
else
H.adjustFireLoss(nitryl_pp/4)
- gas_breathed = PP(breath,GAS_NITRYL)
+ gas_breathed = PP(breath,/datum/gas/nitryl)
if (gas_breathed > gas_stimulation_min)
H.reagents.add_reagent(/datum/reagent/nitryl,1)
- breath.adjust_moles(GAS_NITRYL, -gas_breathed)
+ REMOVE_MOLES(/datum/gas/nitryl, breath, gas_breathed)
// Stimulum
- gas_breathed = PP(breath,GAS_STIMULUM)
+ gas_breathed = PP(breath,/datum/gas/stimulum)
if (gas_breathed > gas_stimulation_min)
var/existing = H.reagents.get_reagent_amount(/datum/reagent/stimulum)
H.reagents.add_reagent(/datum/reagent/stimulum, max(0, 5 - existing))
- breath.adjust_moles(GAS_STIMULUM, -gas_breathed)
+ REMOVE_MOLES(/datum/gas/stimulum, breath, gas_breathed)
handle_breath_temperature(breath, H)
return TRUE
@@ -354,7 +351,7 @@
to_chat(H, "You feel [hot_message] in your [name]!")
// The air you breathe out should match your body temperature
- breath.set_temperature(H.bodytemperature)
+ breath.temperature = H.bodytemperature
/obj/item/organ/lungs/on_life()
..()
@@ -378,7 +375,7 @@
/obj/item/organ/lungs/plasmaman/populate_gas_info()
..()
- gas_max -= GAS_PLASMA
+ gas_max -= /datum/breathing_class/plasma
/obj/item/organ/lungs/slime
name = "vacuole"
@@ -408,8 +405,8 @@
safe_breath_min = 4
safe_breath_max = 250
gas_max = list(
- GAS_PLASMA = 30,
- GAS_CO2 = 30
+ /datum/gas/plasma = 30,
+ /datum/gas/carbon_dioxide = 30
)
maxHealth = 2 * STANDARD_ORGAN_THRESHOLD
@@ -430,8 +427,8 @@
safe_breath_min = 4
safe_breath_max = 20
gas_max = list(
- GAS_CO2 = 45,
- GAS_PLASMA = MOLES_GAS_VISIBLE
+ /datum/gas/carbon_dioxide = 45,
+ /datum/gas/plasma = MOLES_GAS_VISIBLE
)
/obj/item/organ/lungs/diona
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index bc8779197a870..fcf028372c7a7 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -16,6 +16,7 @@
#include "asset_smart_cache.dm"
#include "async.dm"
#include "bloody_footprints.dm"
+#include "breath.dm"
#include "check_adjustable_clothing.dm"
#include "closets.dm"
#include "component_tests.dm"
@@ -34,6 +35,7 @@
#include "food_edibility_check.dm"
#include "gamemode_sanity.dm"
+#include "gas_transfer.dm"
#include "greyscale_config.dm"
#include "handcuff_tests.dm"
#include "heretic_knowledge.dm"
@@ -44,6 +46,7 @@
#include "metabolizing.dm"
#include "missing_icons.dm"
#include "ntnetwork_tests.dm"
+#include "orphaned_genturf.dm"
#include "preference_species.dm"
#include "preferences.dm"
#include "projectiles.dm"
diff --git a/code/modules/unit_tests/breath.dm b/code/modules/unit_tests/breath.dm
new file mode 100644
index 0000000000000..6aa9e19e57766
--- /dev/null
+++ b/code/modules/unit_tests/breath.dm
@@ -0,0 +1,36 @@
+/// Tests to make sure humans can breath in normal situations
+/// Built to prevent regression on an issue surrounding QUANTIZE() and BREATH_VOLUME
+/// See the comment on BREATH_VOLUME for more details
+/datum/unit_test/breath_sanity
+
+/datum/unit_test/breath_sanity/Run()
+ var/mob/living/carbon/human/consistent/lab_rat = allocate(/mob/living/carbon/human/consistent)
+ var/obj/item/clothing/mask/breath/tube = allocate(/obj/item/clothing/mask/breath)
+ var/obj/item/tank/internals/emergency_oxygen/source = allocate(/obj/item/tank/internals/emergency_oxygen)
+
+ lab_rat.equip_to_slot_if_possible(tube, ITEM_SLOT_MASK)
+ lab_rat.equip_to_slot_if_possible(source, ITEM_SLOT_HANDS)
+ source.toggle_internals(lab_rat)
+
+ lab_rat.breathe()
+
+ TEST_ASSERT(!lab_rat.has_alert("not_enough_oxy"), "Humans can't get a full breath from standard o2 tanks")
+ lab_rat.clear_alert("not_enough_oxy")
+
+ //Prep the mob
+ lab_rat.forceMove(run_loc_floor_bottom_left)
+ source.toggle_internals(lab_rat)
+ TEST_ASSERT(!lab_rat.internal, "toggle_internals() failed to toggle internals")
+
+ var/turf/open/to_fill = run_loc_floor_bottom_left
+ //Prep the floor
+ to_fill.initial_gas_mix = OPENTURF_DEFAULT_ATMOS
+ to_fill.air = new
+ to_fill.air.copy_from_turf(to_fill)
+
+ lab_rat.breathe()
+
+ TEST_ASSERT(!lab_rat.has_alert("not_enough_oxy"), "Humans can't get a full breath from the standard initial_gas_mix on a turf")
+
+
+
diff --git a/code/modules/unit_tests/gas_transfer.dm b/code/modules/unit_tests/gas_transfer.dm
new file mode 100644
index 0000000000000..565fd62a79bd7
--- /dev/null
+++ b/code/modules/unit_tests/gas_transfer.dm
@@ -0,0 +1,31 @@
+/// Test to make sure the pressure pumping proc used by things like portable pumps, pressure pumps, etc actually work.
+/datum/unit_test/atmospheric_gas_transfer
+
+/datum/unit_test/atmospheric_gas_transfer/Run()
+ for (var/tempNmoles in list(1e4, 1e6, 1e8, 1e10, 1e12))
+ var/datum/gas_mixture/first_mix = allocate(/datum/gas_mixture)
+ var/datum/gas_mixture/second_mix = allocate(/datum/gas_mixture)
+
+ first_mix.volume = 200
+ second_mix.volume = 200
+
+ SET_MOLES(/datum/gas/hypernoblium, first_mix, tempNmoles)
+ SET_MOLES(/datum/gas/tritium, second_mix, 200)
+
+ first_mix.temperature = tempNmoles
+ second_mix.temperature = T20C
+
+ var/initial_pressure = second_mix.return_pressure()
+ // A constant value would be nicer but there will be cases when even MOLAR_ACCURACY amounts would far exceed the pressure so we need to scale it somewhat.
+ var/additional_pressure = (tempNmoles / 1000) + 500
+
+ /* ERROR MARGIN CALCULATION
+ * We calculate how much would the pressure change if MOLAR_ACCURACY amount of hothotgas is imparted on the cold mix.
+ * This number gets really big for very high temperatures so it's somewhat meaningless, but our main goal is to ensure the code doesn't break.
+ */
+ var/error_margin = first_mix.gas_pressure_minimum_transfer(second_mix) - initial_pressure
+
+ first_mix.pump_gas_to(second_mix, (initial_pressure + additional_pressure))
+ var/margin = abs(second_mix.return_pressure() - (initial_pressure+additional_pressure))
+
+ TEST_ASSERT(margin<=error_margin, "Gas pressure pumping test failed for [tempNmoles]. Expected pressure = [initial_pressure+additional_pressure] +/- [error_margin]. Got [second_mix.return_pressure()].")
diff --git a/code/modules/unit_tests/orphaned_genturf.dm b/code/modules/unit_tests/orphaned_genturf.dm
new file mode 100644
index 0000000000000..289b883d2def4
--- /dev/null
+++ b/code/modules/unit_tests/orphaned_genturf.dm
@@ -0,0 +1,7 @@
+/// Ensures we do not leave genturfs sitting around post work
+/// They serve as notice to the mapper and have no functionality, but it's good to make note of it here
+/datum/unit_test/orphaned_genturf
+
+/datum/unit_test/orphaned_genturf/Run()
+ for(var/turf/open/genturf/orphaned in ALL_TURFS())
+ TEST_FAIL("Floating genturf ([orphaned.type]) detected at ([orphaned.x], [orphaned.y], [orphaned.z]) : [orphaned.loc.type]. Why was it not replaced?")
diff --git a/code/modules/vehicles/mecha/_mecha.dm b/code/modules/vehicles/mecha/_mecha.dm
index 601b44e634860..374fa10b2ff30 100644
--- a/code/modules/vehicles/mecha/_mecha.dm
+++ b/code/modules/vehicles/mecha/_mecha.dm
@@ -198,10 +198,10 @@
radio.name = "[src] radio"
cabin_air = new
- cabin_air.set_temperature(T20C)
- cabin_air.set_volume(200)
- cabin_air.set_moles(GAS_O2, O2STANDARD*cabin_air.return_volume()/(R_IDEAL_GAS_EQUATION*cabin_air.return_temperature()))
- cabin_air.set_moles(GAS_N2, N2STANDARD*cabin_air.return_volume()/(R_IDEAL_GAS_EQUATION*cabin_air.return_temperature()))
+ cabin_air.temperature = T20C
+ cabin_air.volume = 200
+ SET_MOLES(/datum/gas/oxygen, cabin_air, O2STANDARD*cabin_air.return_volume()/(R_IDEAL_GAS_EQUATION*cabin_air.return_temperature()))
+ SET_MOLES(/datum/gas/nitrogen, cabin_air, N2STANDARD*cabin_air.return_volume()/(R_IDEAL_GAS_EQUATION*cabin_air.return_temperature()))
add_cell()
add_scanmod()
@@ -220,6 +220,10 @@
become_hearing_sensitive(trait_source = ROUNDSTART_TRAIT)
+/obj/mecha/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/atmos_sensitive)
+
//separate proc so that the ejection mechanism can be easily triggered by other things, such as admins
/obj/vehicle/sealed/mecha/proc/Eject()
for(var/mob/living/occupant as anything in occupants)
@@ -258,7 +262,6 @@
/obj/vehicle/sealed/mecha/atom_destruction()
loc.assume_air(cabin_air)
- air_update_turf(FALSE, FALSE)
Eject()
return ..()
@@ -398,9 +401,9 @@
if(int_tank_air.return_pressure() > internal_tank.maximum_pressure && !(internal_damage & MECHA_INT_TANK_BREACH))
set_internal_damage(MECHA_INT_TANK_BREACH)
if(int_tank_air && int_tank_air.return_volume() > 0) //heat the air_contents
- int_tank_air.set_temperature(min(6000+T0C, int_tank_air.return_temperature()+rand(5,7.5)*delta_time))
+ int_tank_air.temperature = (min(6000+T0C, int_tank_air.return_temperature()+rand(10,15)))
if(cabin_air && cabin_air.return_volume()>0)
- cabin_air.set_temperature(min(6000+T0C, cabin_air.return_temperature()+rand(5,7.5)*delta_time))
+ cabin_air.temperature = (min(6000+T0C, cabin_air.return_temperature()+rand(10,15)))
if(cabin_air.return_temperature() > max_temperature/2)
take_damage(delta_time*2/round(max_temperature/cabin_air.return_temperature(),0.1), BURN, 0, 0)
@@ -417,7 +420,7 @@
if(!(internal_damage & MECHA_INT_TEMP_CONTROL))
if(cabin_air && cabin_air.return_volume() > 0)
var/delta = cabin_air.return_temperature() - T20C
- cabin_air.set_temperature(cabin_air.return_temperature() - clamp(round(delta / 8, 0.1), -5, 5) * delta_time)
+ cabin_air.temperature = (cabin_air.return_temperature() - clamp(round(delta / 8, 0.1), -5, 5) * delta_time)
if(internal_tank)
var/datum/gas_mixture/tank_air = internal_tank.return_air()
@@ -1156,9 +1159,6 @@
return t_air.return_temperature()
return
-/obj/vehicle/sealed/mecha/portableConnectorReturnAir()
- return internal_tank.return_air()
-
///////////////////////
////// Ammo stuff /////
///////////////////////
diff --git a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
index 36e752f7a775e..f3cb7784e9085 100644
--- a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
@@ -551,9 +551,9 @@
return FALSE
var/moles = chassis.internal_tank.air_contents.total_moles()
if(moles < move_cost)
- chassis.internal_tank.air_contents.remove(moles)
+ chassis.internal_tank.remove_air(moles)
return FALSE
- chassis.internal_tank.air_contents.remove(move_cost)
+ chassis.internal_tank.remove_air(move_cost)
generate_effect(movement_dir)
return TRUE
diff --git a/code/modules/vehicles/mecha/mecha_defense.dm b/code/modules/vehicles/mecha/mecha_defense.dm
index 161d39e3aeecd..f6473b3cb3255 100644
--- a/code/modules/vehicles/mecha/mecha_defense.dm
+++ b/code/modules/vehicles/mecha/mecha_defense.dm
@@ -176,10 +176,13 @@
addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/vehicle/sealed/mecha, restore_equipment)), 3 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
equipment_disabled = 1
-/obj/vehicle/sealed/mecha/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(exposed_temperature>max_temperature)
- log_message("Exposed to dangerous temperature.", LOG_MECHA, color="red")
- take_damage(5, BURN, 0, 1)
+/obj/vehicle/sealed/mecha/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
+ return exposed_temperature>max_temperature
+
+/obj/vehicle/sealed/mecha/atmos_expose(datum/gas_mixture/air, exposed_temperature)
+ log_message("Exposed to dangerous temperature.", LOG_MECHA, color="red")
+ take_damage(5, BURN, 0, 1)
+
/obj/vehicle/sealed/mecha/attackby(obj/item/W, mob/user, params)
diff --git a/code/modules/xenoarchaeology/traits/xenoartifact_majors.dm b/code/modules/xenoarchaeology/traits/xenoartifact_majors.dm
index 6c579cfac01d0..e9cc4e6963536 100644
--- a/code/modules/xenoarchaeology/traits/xenoartifact_majors.dm
+++ b/code/modules/xenoarchaeology/traits/xenoartifact_majors.dm
@@ -448,10 +448,10 @@
var/datum/gas_mixture/air = T.return_air()
var/input_id = initial(input.id)
var/output_id = initial(output.id)
- var/moles = min(air.get_moles(input_id), 5)
+ var/moles = min(GET_MOLES(input_id, air), 5)
if(moles)
- air.adjust_moles(input_id, -moles)
- air.adjust_moles(output_id, moles)
+ air.gases[input_id][MOLES] += -moles
+ air.gases[output_id][MOLES] += moles
///============
/// Destabilizing, teleports the victim to that weird place from the exploration meme.
diff --git a/code/modules/xenoarchaeology/traits/xenoartifact_malfunctions.dm b/code/modules/xenoarchaeology/traits/xenoartifact_malfunctions.dm
index 8c9847a3b6a27..75326b6194e60 100644
--- a/code/modules/xenoarchaeology/traits/xenoartifact_malfunctions.dm
+++ b/code/modules/xenoarchaeology/traits/xenoartifact_malfunctions.dm
@@ -233,7 +233,7 @@
///What gasses we've S U C K E D
var/datum/gas_mixture/air_contents
///Gasses we can suck. Currently everything but, it's here if we need to blacklist in the future
- var/list/scrubbing = list(GAS_PLASMA, GAS_CO2, GAS_NITROUS, GAS_BZ, GAS_NITRYL, GAS_TRITIUM, GAS_HYPERNOB, GAS_H2O, GAS_O2, GAS_N2, GAS_STIMULUM, GAS_PLUOXIUM)
+ var/list/scrubbing = list(/datum/gas/plasma, /datum/gas/carbon_dioxide, /datum/gas/nitrous_oxide, /datum/gas/bz, /datum/gas/nitryl, /datum/gas/tritium, /datum/gas/hypernoblium, /datum/gas/water_vapor, /datum/gas/oxygen, /datum/gas/nitrogen, /datum/gas/stimulum, /datum/gas/pluoxium)
///Adjust for balance - I'm sure this will have no ramifications
var/volume = 1000000
var/volume_rate = 200000
@@ -242,7 +242,7 @@
/datum/xenoartifact_trait/malfunction/absorbant/on_init(obj/item/xenoartifact/X)
air_contents = new(volume)
- air_contents.set_temperature(T20C)
+ air_contents.temperature = (T20C)
parent = X
/datum/xenoartifact_trait/malfunction/absorbant/activate(obj/item/xenoartifact/X, atom/target, atom/user, setup)
@@ -250,14 +250,14 @@
var/turf/T = get_turf(X)
var/datum/gas_mixture/mixture = T.return_air()
mixture.scrub_into(air_contents, volume_rate / mixture.return_volume(), scrubbing)
- X.air_update_turf()
+ X.air_update_turf(FALSE, FALSE)
//Throw sucked gas into our tile when we die
/datum/xenoartifact_trait/malfunction/absorbant/Destroy()
. = ..()
var/turf/T = get_turf(parent)
T.assume_air(air_contents)
- parent.air_update_turf()
+ parent.air_update_turf(FALSE, FALSE)
//============
// Hallucination, shows a random hallucination to the target once
diff --git a/dependencies.sh b/dependencies.sh
index e55e8c7eb78e2..37b98e20e9ac9 100755
--- a/dependencies.sh
+++ b/dependencies.sh
@@ -20,9 +20,6 @@ export NODE_VERSION_PRECISE=18.14.2
# SpacemanDMM git tag
export SPACEMAN_DMM_VERSION=suite-1.7.1
-#auxmos version
-export AUXMOS_VERSION=2.2.2
-
# Python version for mapmerge and other tools
export PYTHON_VERSION=3.11.2
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 27b73165e759f..03c69503e6548 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/obj/atmospherics/components/thermomachine.dmi b/icons/obj/atmospherics/components/thermomachine.dmi
index 9b11fa266ff07..bcc36f4242f15 100644
Binary files a/icons/obj/atmospherics/components/thermomachine.dmi and b/icons/obj/atmospherics/components/thermomachine.dmi differ
diff --git a/icons/obj/atmospherics/components/unary_devices.dmi b/icons/obj/atmospherics/components/unary_devices.dmi
index 2d692273ce4d2..40eee56788eb3 100644
Binary files a/icons/obj/atmospherics/components/unary_devices.dmi and b/icons/obj/atmospherics/components/unary_devices.dmi differ
diff --git a/icons/obj/atmospherics/pipes/bridge_pipe.dmi b/icons/obj/atmospherics/pipes/bridge_pipe.dmi
new file mode 100644
index 0000000000000..4374e75458934
Binary files /dev/null and b/icons/obj/atmospherics/pipes/bridge_pipe.dmi differ
diff --git a/icons/obj/atmospherics/pipes/color_adapter.dmi b/icons/obj/atmospherics/pipes/color_adapter.dmi
new file mode 100644
index 0000000000000..9133a33bc38a7
Binary files /dev/null and b/icons/obj/atmospherics/pipes/color_adapter.dmi differ
diff --git a/icons/obj/atmospherics/pipes/layer_manifold_underlays.dmi b/icons/obj/atmospherics/pipes/layer_manifold_underlays.dmi
new file mode 100644
index 0000000000000..6fe47e5019a03
Binary files /dev/null and b/icons/obj/atmospherics/pipes/layer_manifold_underlays.dmi differ
diff --git a/icons/obj/atmospherics/pipes/manifold.dmi b/icons/obj/atmospherics/pipes/manifold.dmi
index f96874dc059f1..008817e96f989 100644
Binary files a/icons/obj/atmospherics/pipes/manifold.dmi and b/icons/obj/atmospherics/pipes/manifold.dmi differ
diff --git a/icons/obj/atmospherics/pipes/pipe_item.dmi b/icons/obj/atmospherics/pipes/pipe_item.dmi
index cfb9c0f9d1bd7..54dac81793975 100644
Binary files a/icons/obj/atmospherics/pipes/pipe_item.dmi and b/icons/obj/atmospherics/pipes/pipe_item.dmi differ
diff --git a/icons/obj/atmospherics/pipes/pipe_underlays.dmi b/icons/obj/atmospherics/pipes/pipe_underlays.dmi
new file mode 100644
index 0000000000000..1a74cc3740190
Binary files /dev/null and b/icons/obj/atmospherics/pipes/pipe_underlays.dmi differ
diff --git a/icons/obj/atmospherics/pipes/simple.dmi b/icons/obj/atmospherics/pipes/simple.dmi
index 19e6bb2586f2a..4e0d7452f2d2b 100644
Binary files a/icons/obj/atmospherics/pipes/simple.dmi and b/icons/obj/atmospherics/pipes/simple.dmi differ
diff --git a/tgui/packages/tgui/interfaces/AirAlarm.js b/tgui/packages/tgui/interfaces/AirAlarm.js
index b8d2550f862b4..c223f0f1e0cbb 100644
--- a/tgui/packages/tgui/interfaces/AirAlarm.js
+++ b/tgui/packages/tgui/interfaces/AirAlarm.js
@@ -157,7 +157,7 @@ const AirAlarmControlVents = (props, context) => {
if (!vents || vents.length === 0) {
return 'Nothing to show';
}
- return vents.map((vent) => );
+ return vents.map((vent) => );
};
// Scrubbers
@@ -169,7 +169,7 @@ const AirAlarmControlScrubbers = (props, context) => {
if (!scrubbers || scrubbers.length === 0) {
return 'Nothing to show';
}
- return scrubbers.map((scrubber) => );
+ return scrubbers.map((scrubber) => );
};
// Modes
diff --git a/tgui/packages/tgui/interfaces/AtmosControlPanel.js b/tgui/packages/tgui/interfaces/AtmosControlPanel.js
new file mode 100644
index 0000000000000..8a3af30203c9d
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/AtmosControlPanel.js
@@ -0,0 +1,89 @@
+import { map, sortBy } from 'common/collections';
+import { flow } from 'common/fp';
+import { useBackend } from '../backend';
+import { Box, Button, Flex, Section, Table } from '../components';
+import { Window } from '../layouts';
+
+export const AtmosControlPanel = (props, context) => {
+ const { act, data } = useBackend(context);
+ const groups = flow([
+ map((group, i) => ({
+ ...group,
+ // Generate a unique id
+ id: group.area + i,
+ })),
+ sortBy((group) => group.id),
+ ])(data.excited_groups);
+ return (
+
+
+
+
+
+
+ Fire Cnt: {data.fire_count}
+ Active Turfs: {data.active_size}
+ Excited Groups: {data.excited_size}
+ Hotspots: {data.hotspots_size}
+ Superconductors: {data.conducting_size}
+
+ act('toggle_user_display')}>
+ Personal View
+
+
+
+ act('toggle_show_all')}>
+ Display all
+
+
+
+
+
+
+
+
+
+ Area Name
+ Breakdown
+ Dismantle
+ Turfs
+ {data.display_max === 1 && 'Max Share'}
+ Display
+
+ {groups.map((group) => (
+
+
+ |
+ {group.breakdown} |
+ {group.dismantle} |
+ {group.size} |
+ {data.display_max === 1 && group.max_share} |
+
+
+ act('toggle_show_group', {
+ group: group.group,
+ })
+ }
+ />
+ |
+
+ ))}
+
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/RapidPipeDispenser.js b/tgui/packages/tgui/interfaces/RapidPipeDispenser.js
index f1d9f5df8bb08..19e045a91ea25 100644
--- a/tgui/packages/tgui/interfaces/RapidPipeDispenser.js
+++ b/tgui/packages/tgui/interfaces/RapidPipeDispenser.js
@@ -16,21 +16,6 @@ const ICON_BY_CATEGORY_NAME = {
'Station Equipment': 'microchip',
};
-const PAINT_COLORS = {
- grey: '#bbbbbb',
- amethyst: '#a365ff',
- blue: '#4466ff',
- brown: '#b26438',
- cyan: '#48eae8',
- dark: '#808080',
- green: '#1edd00',
- orange: '#ffa030',
- purple: '#b535ea',
- red: '#ff3333',
- violet: '#6e00f6',
- yellow: '#ffce26',
-};
-
const TOOLS = [
{
name: 'Dispense',
@@ -44,10 +29,6 @@ const TOOLS = [
name: 'Destroy',
bitmask: 4,
},
- {
- name: 'Paint',
- bitmask: 8,
- },
];
export const RapidPipeDispenser = (props, context) => {
@@ -88,14 +69,14 @@ export const RapidPipeDispenser = (props, context) => {
))}
-
+
{selected_color}
- {Object.keys(PAINT_COLORS).map((colorName) => (
+ {Object.keys(data.paint_colors).map((colorName) => (
act('color', {
paint_color: colorName,
diff --git a/tgui/packages/tgui/interfaces/ThermoMachine.js b/tgui/packages/tgui/interfaces/ThermoMachine.js
index a92b398ae8200..a6269438b8208 100644
--- a/tgui/packages/tgui/interfaces/ThermoMachine.js
+++ b/tgui/packages/tgui/interfaces/ThermoMachine.js
@@ -31,14 +31,6 @@ export const ThermoMachine = (props, context) => {
/>
}>
-
-
{
const { vent } = props;
const { act } = useBackend(context);
- const { id_tag, long_name, power, checks, excheck, incheck, direction, external, internal, extdefault, intdefault } = vent;
+ const { ref, long_name, power, checks, excheck, incheck, direction, external, internal, extdefault, intdefault } = vent;
return (
{
content={power ? 'On' : 'Off'}
onClick={() =>
act('power', {
- id_tag,
+ ref,
val: Number(!power),
})
}
@@ -32,7 +32,7 @@ export const Vent = (props, context) => {
color={!direction && 'danger'}
onClick={() =>
act('direction', {
- id_tag,
+ ref,
val: Number(!direction),
})
}
@@ -45,7 +45,7 @@ export const Vent = (props, context) => {
selected={incheck}
onClick={() =>
act('incheck', {
- id_tag,
+ ref,
val: checks,
})
}
@@ -56,7 +56,7 @@ export const Vent = (props, context) => {
selected={excheck}
onClick={() =>
act('excheck', {
- id_tag,
+ ref,
val: checks,
})
}
@@ -73,7 +73,7 @@ export const Vent = (props, context) => {
maxValue={5066}
onChange={(e, value) =>
act('set_internal_pressure', {
- id_tag,
+ ref,
value,
})
}
@@ -84,7 +84,7 @@ export const Vent = (props, context) => {
content="Reset"
onClick={() =>
act('reset_internal_pressure', {
- id_tag,
+ ref,
})
}
/>
@@ -101,7 +101,7 @@ export const Vent = (props, context) => {
maxValue={5066}
onChange={(e, value) =>
act('set_external_pressure', {
- id_tag,
+ ref,
value,
})
}
@@ -112,7 +112,7 @@ export const Vent = (props, context) => {
content="Reset"
onClick={() =>
act('reset_external_pressure', {
- id_tag,
+ ref,
})
}
/>
@@ -126,7 +126,7 @@ export const Vent = (props, context) => {
export const Scrubber = (props, context) => {
const { scrubber } = props;
const { act } = useBackend(context);
- const { long_name, power, scrubbing, id_tag, widenet, filter_types } = scrubber;
+ const { long_name, power, scrubbing, ref, widenet, filter_types } = scrubber;
return (
{
selected={power}
onClick={() =>
act('power', {
- id_tag,
+ ref,
val: Number(!power),
})
}
@@ -152,7 +152,7 @@ export const Scrubber = (props, context) => {
content={scrubbing ? 'Scrubbing' : 'Siphoning'}
onClick={() =>
act('scrubbing', {
- id_tag,
+ ref,
val: Number(!scrubbing),
})
}
@@ -163,7 +163,7 @@ export const Scrubber = (props, context) => {
content={widenet ? 'Expanded range' : 'Normal range'}
onClick={() =>
act('widenet', {
- id_tag,
+ ref,
val: Number(!widenet),
})
}
@@ -180,7 +180,7 @@ export const Scrubber = (props, context) => {
selected={filter.enabled}
onClick={() =>
act('toggle_filter', {
- id_tag,
+ ref,
val: filter.gas_id,
})
}
diff --git a/tools/UpdatePaths/Scripts/11813_LINDA.txt b/tools/UpdatePaths/Scripts/11813_LINDA.txt
new file mode 100644
index 0000000000000..b203c3d8f498d
--- /dev/null
+++ b/tools/UpdatePaths/Scripts/11813_LINDA.txt
@@ -0,0 +1,8 @@
+/turf/@SUBTYPES{initial_temperature=@ANY} : /turf/@SUBTYPES{@OLD; initial_temperature=@SKIP}
+#comment - Be aware, this current line breaks the tool and the end result is not a removed line, but rather " = None". I don't know how to fix this, so keep this in mind when updating maps.
+
+/obj/machinery/atmospherics/components/unary/tank/@SUBTYPES : /obj/machinery/atmospherics/components/tank/@SUBTYPES{@OLD}
+/obj/machinery/embedded_controller/radio/airlock_controller/@SUBTYPES : /obj/machinery/airlock_controller/@SUBTYPES{@OLD}
+/obj/machinery/air_sensor/atmos/@SUBTYPES: /obj/machinery/air_sensor/@SUBTYPES{@OLD}
+/obj/machinery/portable_atmospherics/canister/proto : @DELETE
+/obj/machinery/embedded_controller/radio/airlock_controller/@SUBTYPES : /obj/machinery/airlock_controller/@SUBTYPES{@OLD}
\ No newline at end of file
diff --git a/tools/ci/install_auxmos.sh b/tools/ci/install_auxmos.sh
deleted file mode 100644
index 591bcf612f19a..0000000000000
--- a/tools/ci/install_auxmos.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-source dependencies.sh
-
-mkdir -p ~/.byond/bin
-wget -O ~/.byond/bin/libauxmos.so "https://github.com/BeeStation/auxmos/releases/download/${AUXMOS_VERSION}/libauxmos.so"
-chmod +x ~/.byond/bin/libauxmos.so
-ldd ~/.byond/bin/libauxmos.so
diff --git a/tools/tgs4_scripts/PreCompile.sh b/tools/tgs4_scripts/PreCompile.sh
index ed588b5d33d78..5fa7810d6d1f1 100755
--- a/tools/tgs4_scripts/PreCompile.sh
+++ b/tools/tgs4_scripts/PreCompile.sh
@@ -70,25 +70,6 @@ cd ..
# I left a few potentially extraneous ones in momentarily due to an inability to test on a linux host at the moment.
apt-get install -y cmake build-essential gcc-multilib g++-multilib cmake wget
-# update auxmos
-if [ ! -d "auxmos" ]; then
- echo "Cloning Auxmos..."
- git clone https://github.com/BeeStation/auxmos
- cd auxmos
-else
- echo "Fetching Auxmos..."
- cd auxmos
- git fetch
-fi
-
-echo "Deploying Auxmos..."
-git checkout "$AUXMOS_VERSION"
-if [ -d "build" ]; then
- rm -R build
-fi
-#note, if FUSION is ever fixed this needs changed to "all_reaction_hooks"
-cargo rustc --target=i686-unknown-linux-gnu --release --features trit_fire_hook,plasma_fire_hook,generic_fire_hook -- -C target-cpu=native
-mv -f target/i686-unknown-linux-gnu/release/libauxmos.so "$1/libauxmos.so"
cd ../../..
# install or update youtube-dl when not present, or if it is present with pip3,