diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000000..cd6a32d5e9e
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,10 @@
+[*]
+indent_style = space
+indent_size = 2
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.dm]
+indent_style = tab
+indent_size = 4
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
index 3158997945b..c3b24c12791 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,10 +1,60 @@
-# dmm map merger hook
-# needs additional setup, see tools/mapmerge/install.txt
-*.dmm merge=merge-dmm eol=crlf
-
-# dmi icon merger hook
-# needs additional setup, see tools/dmitool/merging.txt
-*.dmi merge=merge-dmi
-
-# force changelog merging to use union
-html/changelog.html merge=union
+# dmm map merger hook
+# needs additional setup, see tools/mapmerge/install.txt
+*.dmm merge=merge-dmm eol=crlf
+
+# dmi icon merger hook
+# needs additional setup, see tools/dmitool/merging.txt
+*.dmi merge=merge-dmi
+
+# force changelog merging to use union
+html/changelog.html merge=union
+
+# Enforce Line Endings
+* text=auto
+
+*.ai binary
+*.dmi binary
+*.exe binary
+*.fla binary
+*.gif binary
+*.jar binary
+*.jpg binary
+*.mid binary
+*.ogg binary
+*.pdb binary
+*.png binary
+*.psd binary
+*.s3m binary
+*.sav binary
+*.so binary
+*.svg binary
+*.wav binary
+*.xcf binary
+*.xlsx binary
+
+*.awk text
+*.bat text
+*.conf text
+*.cpp text
+*.cs text
+*.css text
+*.dm text
+*.dmf text
+*.dmm text
+*.gitkeep text
+*.hook text
+*.html text
+*.java text
+*.js text
+*.json text
+*.log text
+*.map text
+*.md text
+*.php text
+*.py text
+*.scss text
+*.sh text
+*.sql text
+*.tmpl text
+*.txt text
+*.vue text
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index c0fb1080cdf..7daad5e4219 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,19 +1,19 @@
-#ignore misc BYOND files
-Thumbs.db
-*.log
-*.rsc
-*.int
-*.dmb
-*.lk
-*.backup
-*.before
-data/
-cfg/
-build_log.txt
-
-__pycache__/
-*.py[cod]
-*$py.class
-/.atom-build.json
-.vscode/
-.vs/
+#ignore misc BYOND files
+Thumbs.db
+*.log
+*.rsc
+*.int
+*.dmb
+*.lk
+*.backup
+*.before
+data/
+cfg/
+build_log.txt
+
+__pycache__/
+*.py[cod]
+*$py.class
+/.atom-build.json
+.vscode/
+.vs/
diff --git a/.travis.yml b/.travis.yml
index 2884d834c6b..99649c86fd7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -85,7 +85,7 @@ jobs:
- (cd vueui && npm run build)
- (num=`grep -E '\\\\(red|blue|green|black|b|i[^mc])' **/*.dm | wc -l`; echo "$num escapes (expecting ${MACRO_COUNT} or less)"; [ $num -le ${MACRO_COUNT} ])
- awk -f tools/indentation.awk **/*.dm
- - md5sum -c - <<< "c3aa6d9bf053dba0a2f763ed314304e2 *html/changelogs/example.yml"
+ - md5sum -c - <<< "60a49502d9f6dfdcc255deb98c901b72 *html/changelogs/example.yml"
- python tools/TagMatcher/tag-matcher.py ../..
- python tools/GenerateChangelog/ss13_genchangelog.py html/changelog.html html/changelogs --dry-run
- python3 tools/mapmerge2/travis_mapcheck.py
diff --git a/README.md b/README.md
index 8811b08f895..5218aca790e 100644
--- a/README.md
+++ b/README.md
@@ -1,96 +1,96 @@
-# Aurorastation
-
-**[Website](https://aurorastation.org/)**
-
-**[Code](https://github.com/Aurorastation/Aurora.3)**
-
-[](http://www.krihelinator.xyz/repositories/Aurorastation/Aurora.3)
-
-[](https://travis-ci.org/Aurorastation/Aurora.3)
-
----
-
-### LICENSE
-Aurorastation is licensed under the GNU Affero General Public License version 3, which can be found in full in LICENSE.
-
-Commits with a git authorship date prior to `1420675200 +0000` (2015/01/08 00:00) are licensed under the GNU General Public License version 3, which can be found in full in LICENSE-GPL3.txt.
-
-All commits whose authorship dates are not prior to `1420675200 +0000` are assumed to be licensed under AGPL v3, if you wish to license under GPL v3 please make this clear in the commit message and any added files.
-
-If you wish to develop and host this codebase in a closed source manner you may use all commits prior to `1420675200 +0000`, which are licensed under GPL v3. The major change here is that if you host a server using any code licensed under AGPLv3 you are required to provide full source code for your servers users as well including addons and modifications you have made.
-
-See [here](https://www.gnu.org/licenses/why-affero-gpl.html) for more information.
-
-### GETTING THE CODE
-The simplest way to obtain the code is using the github .zip feature.
-
-Click [here](https://github.com/Aurorastation/Aurora.3/archive/master.zip) to get the latest stable code as a .zip file, then unzip it to wherever you want.
-
-The more complicated and easier to update method is using git. You'll need to download git or some client from [here](http://git-scm.com/). When that's installed, right click in any folder and click on "Git Bash". When that opens, type in:
-
- git clone https://github.com/Aurorastation/Aurora.3.git
-
-(hint: hold down ctrl and press insert to paste into git bash)
-
-This will take a while to download, but it provides an easier method for updating.
-
-### INSTALLATION
-
-First-time installation should be fairly straightforward. First, you'll need BYOND installed. You can get it from [here](http://www.byond.com/).
-
-This is a sourcecode-only release, so the next step is to compile the server files. Open aurorastation.dme by double-clicking it, open the Build menu, and click compile. This'll take a little while, and if everything's done right you'll get a message like this:
-
- saving aurorastation.dmb (DEBUG mode)
-
- aurorastation.dmb - 0 errors, 0 warnings
-
-If you see any errors or warnings, something has gone wrong - possibly a corrupt download or the files extracted wrong, or a code issue on the main repo. Ask on the server Discord if you're completely lost.
-
-Once that's done, open up the config folder. You'll want to edit config.txt to set the probabilities for different gamemodes in Secret and to set your server location so that all your players don't get disconnected at the end of each round. It's recommended you don't turn on the gamemodes with probability 0, as they have various issues and aren't currently being tested, so they may have unknown and bizarre bugs.
-
-You'll also want to edit admins.txt to remove the default admins and add your own. "Game Master" is the highest level of access, and the other recommended admin levels for now are "Game Admin" and "Moderator". The format is:
-
- byondkey - Rank
-
-where the BYOND key must be in lowercase and the admin rank must be properly capitalised. There are a bunch more admin ranks, but these two should be enough for most servers, assuming you have trustworthy admins.
-
-Finally, to start the server, run Dream Daemon and enter the path to your compiled aurorastation.dmb file. Make sure to set the port to the one you specified in the config.txt, and set the Security box to 'Trusted'. Then press GO and the server should start up and be ready to join.
-
----
-
-### UPDATING
-
-To update an existing installation, first back up your /config and /data folders
-as these store your server configuration, player preferences and banlist.
-
-If you used the zip method, you'll need to download the zip file again and unzip it somewhere else, and then copy the /config and /data folders over.
-
-If you used the git method, you simply need to type this in to git bash:
-
- git pull
-
-When this completes, copy over your /data and /config folders again, just in case.
-
-When you have done this, you'll need to recompile the code, but then it should work fine.
-
----
-
-### Configuration
-
-For a basic setup, simply copy every file from config/example to config.
-
-For more advanced setups, setting the server `tick_lag` in the config as well as configuring SQL are good first steps.
-
----
-
-### SQL Setup
-
-The SQL backend for the library and stats tracking requires a MySQL server, as does the optional SQL saves system. Your server details go in config/dbconfig.txt, and initial database setup is done with [flyway](https://flywaydb.org/). Detailed instructions can be found [here](https://github.com/Aurorastation/Aurora.3/tree/master/SQL).
-
----
-
-### Discord Bot
-
-The Aurorastation codebase uses a built-in Discord bot to interface with Discord. Some of its features rely on the MySQL database, specifically, channel storage and configuration. So a database is required for its operation. If that is present, then setup is relatively easy: simply set up the `config/discord.txt` file according to the example located in the `config/example/` folder, and populate the database with appropriate channel and server information.
-
-At present, there is no built in GUI for doing the latter. So direct database modification is required unless you set up the python companion bot. The python companion bot is BOREALIS II, and can be located [here](https://github.com/Aurorastation/BOREALISbot2). Though not required, it makes database modification easier. See commands that start with `channel_`.
+# Aurorastation
+
+**[Website](https://aurorastation.org/)**
+
+**[Code](https://github.com/Aurorastation/Aurora.3)**
+
+[](http://www.krihelinator.xyz/repositories/Aurorastation/Aurora.3)
+
+[](https://travis-ci.org/Aurorastation/Aurora.3)
+
+---
+
+### LICENSE
+Aurorastation is licensed under the GNU Affero General Public License version 3, which can be found in full in LICENSE.
+
+Commits with a git authorship date prior to `1420675200 +0000` (2015/01/08 00:00) are licensed under the GNU General Public License version 3, which can be found in full in LICENSE-GPL3.txt.
+
+All commits whose authorship dates are not prior to `1420675200 +0000` are assumed to be licensed under AGPL v3, if you wish to license under GPL v3 please make this clear in the commit message and any added files.
+
+If you wish to develop and host this codebase in a closed source manner you may use all commits prior to `1420675200 +0000`, which are licensed under GPL v3. The major change here is that if you host a server using any code licensed under AGPLv3 you are required to provide full source code for your servers users as well including addons and modifications you have made.
+
+See [here](https://www.gnu.org/licenses/why-affero-gpl.html) for more information.
+
+### GETTING THE CODE
+The simplest way to obtain the code is using the github .zip feature.
+
+Click [here](https://github.com/Aurorastation/Aurora.3/archive/master.zip) to get the latest stable code as a .zip file, then unzip it to wherever you want.
+
+The more complicated and easier to update method is using git. You'll need to download git or some client from [here](http://git-scm.com/). When that's installed, right click in any folder and click on "Git Bash". When that opens, type in:
+
+ git clone https://github.com/Aurorastation/Aurora.3.git
+
+(hint: hold down ctrl and press insert to paste into git bash)
+
+This will take a while to download, but it provides an easier method for updating.
+
+### INSTALLATION
+
+First-time installation should be fairly straightforward. First, you'll need BYOND installed. You can get it from [here](http://www.byond.com/).
+
+This is a sourcecode-only release, so the next step is to compile the server files. Open aurorastation.dme by double-clicking it, open the Build menu, and click compile. This'll take a little while, and if everything's done right you'll get a message like this:
+
+ saving aurorastation.dmb (DEBUG mode)
+
+ aurorastation.dmb - 0 errors, 0 warnings
+
+If you see any errors or warnings, something has gone wrong - possibly a corrupt download or the files extracted wrong, or a code issue on the main repo. Ask on the server Discord if you're completely lost.
+
+Once that's done, open up the config folder. You'll want to edit config.txt to set the probabilities for different gamemodes in Secret and to set your server location so that all your players don't get disconnected at the end of each round. It's recommended you don't turn on the gamemodes with probability 0, as they have various issues and aren't currently being tested, so they may have unknown and bizarre bugs.
+
+You'll also want to edit admins.txt to remove the default admins and add your own. "Game Master" is the highest level of access, and the other recommended admin levels for now are "Game Admin" and "Moderator". The format is:
+
+ byondkey - Rank
+
+where the BYOND key must be in lowercase and the admin rank must be properly capitalised. There are a bunch more admin ranks, but these two should be enough for most servers, assuming you have trustworthy admins.
+
+Finally, to start the server, run Dream Daemon and enter the path to your compiled aurorastation.dmb file. Make sure to set the port to the one you specified in the config.txt, and set the Security box to 'Trusted'. Then press GO and the server should start up and be ready to join.
+
+---
+
+### UPDATING
+
+To update an existing installation, first back up your /config and /data folders
+as these store your server configuration, player preferences and banlist.
+
+If you used the zip method, you'll need to download the zip file again and unzip it somewhere else, and then copy the /config and /data folders over.
+
+If you used the git method, you simply need to type this in to git bash:
+
+ git pull
+
+When this completes, copy over your /data and /config folders again, just in case.
+
+When you have done this, you'll need to recompile the code, but then it should work fine.
+
+---
+
+### Configuration
+
+For a basic setup, simply copy every file from config/example to config.
+
+For more advanced setups, setting the server `tick_lag` in the config as well as configuring SQL are good first steps.
+
+---
+
+### SQL Setup
+
+The SQL backend for the library and stats tracking requires a MySQL server, as does the optional SQL saves system. Your server details go in config/dbconfig.txt, and initial database setup is done with [flyway](https://flywaydb.org/). Detailed instructions can be found [here](https://github.com/Aurorastation/Aurora.3/tree/master/SQL).
+
+---
+
+### Discord Bot
+
+The Aurorastation codebase uses a built-in Discord bot to interface with Discord. Some of its features rely on the MySQL database, specifically, channel storage and configuration. So a database is required for its operation. If that is present, then setup is relatively easy: simply set up the `config/discord.txt` file according to the example located in the `config/example/` folder, and populate the database with appropriate channel and server information.
+
+At present, there is no built in GUI for doing the latter. So direct database modification is required unless you set up the python companion bot. The python companion bot is BOREALIS II, and can be located [here](https://github.com/Aurorastation/BOREALISbot2). Though not required, it makes database modification easier. See commands that start with `channel_`.
diff --git a/aurorastation.dme b/aurorastation.dme
index c26284b1e79..3da83e0ddf7 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -369,6 +369,7 @@
#include "code\datums\wires\vending.dm"
#include "code\datums\wires\wires.dm"
#include "code\defines\gases.dm"
+#include "code\defines\mutable_appearance.dm"
#include "code\defines\obj.dm"
#include "code\defines\obj\weapon.dm"
#include "code\defines\procs\announce.dm"
@@ -748,6 +749,7 @@
#include "code\game\objects\items\shooting_range.dm"
#include "code\game\objects\items\skrell.dm"
#include "code\game\objects\items\spirit_board.dm"
+#include "code\game\objects\items\tajara.dm"
#include "code\game\objects\items\toys.dm"
#include "code\game\objects\items\trash.dm"
#include "code\game\objects\items\devices\aicard.dm"
@@ -1297,6 +1299,7 @@
#include "code\modules\clothing\gloves\color.dm"
#include "code\modules\clothing\gloves\miscellaneous.dm"
#include "code\modules\clothing\gloves\stungloves.dm"
+#include "code\modules\clothing\gloves\xeno\tajara.dm"
#include "code\modules\clothing\head\collectable.dm"
#include "code\modules\clothing\head\hardhat.dm"
#include "code\modules\clothing\head\helmet.dm"
@@ -1310,6 +1313,7 @@
#include "code\modules\clothing\masks\gasmask.dm"
#include "code\modules\clothing\masks\miscellaneous.dm"
#include "code\modules\clothing\masks\voice.dm"
+#include "code\modules\clothing\masks\xeno\tajara.dm"
#include "code\modules\clothing\rings\material.dm"
#include "code\modules\clothing\rings\rings.dm"
#include "code\modules\clothing\shoes\colour.dm"
@@ -1318,6 +1322,7 @@
#include "code\modules\clothing\shoes\magboots.dm"
#include "code\modules\clothing\shoes\miscellaneous.dm"
#include "code\modules\clothing\shoes\vaurca.dm"
+#include "code\modules\clothing\shoes\xeno\tajara.dm"
#include "code\modules\clothing\spacesuits\alien.dm"
#include "code\modules\clothing\spacesuits\breaches.dm"
#include "code\modules\clothing\spacesuits\miscellaneous.dm"
@@ -1360,6 +1365,7 @@
#include "code\modules\clothing\suits\storage.dm"
#include "code\modules\clothing\suits\utility.dm"
#include "code\modules\clothing\suits\wiz_robe.dm"
+#include "code\modules\clothing\suits\xeno\tajara.dm"
#include "code\modules\clothing\under\color.dm"
#include "code\modules\clothing\under\miscellaneous.dm"
#include "code\modules\clothing\under\shorts.dm"
@@ -1372,6 +1378,7 @@
#include "code\modules\clothing\under\accessories\lockets.dm"
#include "code\modules\clothing\under\accessories\shirts.dm"
#include "code\modules\clothing\under\accessories\storage.dm"
+#include "code\modules\clothing\under\accessories\xeno\tajara.dm"
#include "code\modules\clothing\under\jobs\civilian.dm"
#include "code\modules\clothing\under\jobs\engineering.dm"
#include "code\modules\clothing\under\jobs\medsci.dm"
@@ -1399,6 +1406,7 @@
#include "code\modules\detectivework\tools\luminol.dm"
#include "code\modules\detectivework\tools\rag.dm"
#include "code\modules\detectivework\tools\sample_kits.dm"
+#include "code\modules\detectivework\tools\scene_cards.dm"
#include "code\modules\detectivework\tools\storage.dm"
#include "code\modules\detectivework\tools\swabs.dm"
#include "code\modules\detectivework\tools\uvlight.dm"
@@ -1500,7 +1508,7 @@
#include "code\modules\heavy_vehicle\mech_wreckage.dm"
#include "code\modules\heavy_vehicle\mecha.dm"
#include "code\modules\heavy_vehicle\components\_components.dm"
-#include "code\modules\heavy_vehicle\components\armour.dm"
+#include "code\modules\heavy_vehicle\components\armor.dm"
#include "code\modules\heavy_vehicle\components\arms.dm"
#include "code\modules\heavy_vehicle\components\body.dm"
#include "code\modules\heavy_vehicle\components\frame.dm"
@@ -1716,7 +1724,6 @@
#include "code\modules\mob\living\autohiss.dm"
#include "code\modules\mob\living\damage_procs.dm"
#include "code\modules\mob\living\default_language.dm"
-#include "code\modules\mob\living\devour.dm"
#include "code\modules\mob\living\life.dm"
#include "code\modules\mob\living\living.dm"
#include "code\modules\mob\living\living_defense.dm"
diff --git a/code/ATMOSPHERICS/atmospherics.dm b/code/ATMOSPHERICS/atmospherics.dm
index d32b433db5e..72b3d0135b1 100644
--- a/code/ATMOSPHERICS/atmospherics.dm
+++ b/code/ATMOSPHERICS/atmospherics.dm
@@ -1,140 +1,140 @@
-/*
-Quick overview:
-
-Pipes combine to form pipelines
-Pipelines and other atmospheric objects combine to form pipe_networks
- Note: A single pipe_network represents a completely open space
-
-Pipes -> Pipelines
-Pipelines + Other Objects -> Pipe network
-
-*/
-/obj/machinery/atmospherics
- anchored = 1
- idle_power_usage = 0
- active_power_usage = 0
- power_channel = ENVIRON
- var/nodealert = 0
- var/power_rating //the maximum amount of power the machine can use to do work, affects how powerful the machine is, in Watts
-
- layer = 2.4 //under wires with their 2.44
-
- var/connect_types = CONNECT_TYPE_REGULAR
- var/icon_connect_type = "" //"-supply" or "-scrubbers"
-
- var/initialize_directions = 0
- var/pipe_color
-
- var/global/datum/pipe_icon_manager/icon_manager
- var/obj/machinery/atmospherics/node1
- var/obj/machinery/atmospherics/node2
- gfi_layer_rotation = GFI_ROTATION_OVERDIR
-
-/obj/machinery/atmospherics/Initialize(mapload)
- . = ..()
- if(!icon_manager)
- icon_manager = new()
-
- if(!pipe_color)
- pipe_color = color
- color = null
-
- if(!pipe_color_check(pipe_color))
- pipe_color = null
-
- if (mapload)
- return INITIALIZE_HINT_LATELOAD
-
-/obj/machinery/atmospherics/Destroy()
- ..()
- return QDEL_HINT_HARDDEL // fuck it
-
-/obj/machinery/atmospherics/proc/atmos_init()
-
-// atmos_init() and Initialize() must be separate, as atmos_init() can be called multiple times after the machine has been initialized.
-
-/obj/machinery/atmospherics/LateInitialize()
- atmos_init()
-
-/obj/machinery/atmospherics/attackby(atom/A, mob/user as mob)
- if(istype(A, /obj/item/device/pipe_painter))
- return
- ..()
-
-/obj/machinery/atmospherics/proc/add_underlay(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type)
- if(node)
- if(!T.is_plating() && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
- //underlays += icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node))
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
- else
- //underlays += icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node))
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
- else
- //underlays += icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color)
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "exposed" + icon_connect_type)
-
-/obj/machinery/atmospherics/proc/update_underlays()
- if(check_icon_cache())
- return 1
- else
- return 0
-
-obj/machinery/atmospherics/proc/check_connect_types(obj/machinery/atmospherics/atmos1, obj/machinery/atmospherics/atmos2)
- return (atmos1.connect_types & atmos2.connect_types)
-
-/obj/machinery/atmospherics/proc/check_connect_types_construction(obj/machinery/atmospherics/atmos1, obj/item/pipe/pipe2)
- return (atmos1.connect_types & pipe2.connect_types)
-
-/obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0)
- if(!istype(icon_manager))
- if(!safety) //to prevent infinite loops
- icon_manager = new()
- check_icon_cache(1)
- return 0
-
- return 1
-
-/obj/machinery/atmospherics/proc/color_cache_name(var/obj/machinery/atmospherics/node)
- //Don't use this for standard pipes
- if(!istype(node))
- return null
-
- return node.pipe_color
-
-/obj/machinery/atmospherics/machinery_process()
- last_flow_rate = 0
- last_power_draw = 0
-
-/obj/machinery/atmospherics/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
- // Check to see if should be added to network. Add self if so and adjust variables appropriately.
- // Note don't forget to have neighbors look as well!
-
- return null
-
-/obj/machinery/atmospherics/proc/build_network()
- // Called to build a network from this node
-
- return null
-
-/obj/machinery/atmospherics/proc/return_network(obj/machinery/atmospherics/reference)
- // Returns pipe_network associated with connection to reference
- // Notes: should create network if necessary
- // Should never return null
-
- return null
-
-/obj/machinery/atmospherics/proc/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
- // Used when two pipe_networks are combining
-
-/obj/machinery/atmospherics/proc/remove_network(datum/pipe_network/network)
- reassign_network(network, null)
-
-/obj/machinery/atmospherics/proc/return_network_air(datum/network/reference)
- // Return a list of gas_mixture(s) in the object
- // associated with reference pipe_network for use in rebuilding the networks gases list
- // Is permitted to return null
-
-/obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference)
-
-/obj/machinery/atmospherics/update_icon()
- return null
+/*
+Quick overview:
+
+Pipes combine to form pipelines
+Pipelines and other atmospheric objects combine to form pipe_networks
+ Note: A single pipe_network represents a completely open space
+
+Pipes -> Pipelines
+Pipelines + Other Objects -> Pipe network
+
+*/
+/obj/machinery/atmospherics
+ anchored = 1
+ idle_power_usage = 0
+ active_power_usage = 0
+ power_channel = ENVIRON
+ var/nodealert = 0
+ var/power_rating //the maximum amount of power the machine can use to do work, affects how powerful the machine is, in Watts
+
+ layer = 2.4 //under wires with their 2.44
+
+ var/connect_types = CONNECT_TYPE_REGULAR
+ var/icon_connect_type = "" //"-supply" or "-scrubbers"
+
+ var/initialize_directions = 0
+ var/pipe_color
+
+ var/global/datum/pipe_icon_manager/icon_manager
+ var/obj/machinery/atmospherics/node1
+ var/obj/machinery/atmospherics/node2
+ gfi_layer_rotation = GFI_ROTATION_OVERDIR
+
+/obj/machinery/atmospherics/Initialize(mapload)
+ . = ..()
+ if(!icon_manager)
+ icon_manager = new()
+
+ if(!pipe_color)
+ pipe_color = color
+ color = null
+
+ if(!pipe_color_check(pipe_color))
+ pipe_color = null
+
+ if (mapload)
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/machinery/atmospherics/Destroy()
+ ..()
+ return QDEL_HINT_HARDDEL // fuck it
+
+/obj/machinery/atmospherics/proc/atmos_init()
+
+// atmos_init() and Initialize() must be separate, as atmos_init() can be called multiple times after the machine has been initialized.
+
+/obj/machinery/atmospherics/LateInitialize()
+ atmos_init()
+
+/obj/machinery/atmospherics/attackby(atom/A, mob/user as mob)
+ if(istype(A, /obj/item/device/pipe_painter))
+ return
+ ..()
+
+/obj/machinery/atmospherics/proc/add_underlay(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type)
+ if(node)
+ if(!T.is_plating() && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
+ //underlays += icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node))
+ underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
+ else
+ //underlays += icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node))
+ underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
+ else
+ //underlays += icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color)
+ underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "exposed" + icon_connect_type)
+
+/obj/machinery/atmospherics/proc/update_underlays()
+ if(check_icon_cache())
+ return 1
+ else
+ return 0
+
+obj/machinery/atmospherics/proc/check_connect_types(obj/machinery/atmospherics/atmos1, obj/machinery/atmospherics/atmos2)
+ return (atmos1.connect_types & atmos2.connect_types)
+
+/obj/machinery/atmospherics/proc/check_connect_types_construction(obj/machinery/atmospherics/atmos1, obj/item/pipe/pipe2)
+ return (atmos1.connect_types & pipe2.connect_types)
+
+/obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0)
+ if(!istype(icon_manager))
+ if(!safety) //to prevent infinite loops
+ icon_manager = new()
+ check_icon_cache(1)
+ return 0
+
+ return 1
+
+/obj/machinery/atmospherics/proc/color_cache_name(var/obj/machinery/atmospherics/node)
+ //Don't use this for standard pipes
+ if(!istype(node))
+ return null
+
+ return node.pipe_color
+
+/obj/machinery/atmospherics/machinery_process()
+ last_flow_rate = 0
+ last_power_draw = 0
+
+/obj/machinery/atmospherics/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+ // Check to see if should be added to network. Add self if so and adjust variables appropriately.
+ // Note don't forget to have neighbors look as well!
+
+ return null
+
+/obj/machinery/atmospherics/proc/build_network()
+ // Called to build a network from this node
+
+ return null
+
+/obj/machinery/atmospherics/proc/return_network(obj/machinery/atmospherics/reference)
+ // Returns pipe_network associated with connection to reference
+ // Notes: should create network if necessary
+ // Should never return null
+
+ return null
+
+/obj/machinery/atmospherics/proc/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
+ // Used when two pipe_networks are combining
+
+/obj/machinery/atmospherics/proc/remove_network(datum/pipe_network/network)
+ reassign_network(network, null)
+
+/obj/machinery/atmospherics/proc/return_network_air(datum/network/reference)
+ // Return a list of gas_mixture(s) in the object
+ // associated with reference pipe_network for use in rebuilding the networks gases list
+ // Is permitted to return null
+
+/obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference)
+
+/obj/machinery/atmospherics/update_icon()
+ return null
diff --git a/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm b/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm
index 5a1486de568..8528d636be2 100644
--- a/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/binary_atmos_base.dm
@@ -1,134 +1,134 @@
-obj/machinery/atmospherics/binary
- dir = SOUTH
- initialize_directions = SOUTH|NORTH
- use_power = 1
-
- var/datum/gas_mixture/air1
- var/datum/gas_mixture/air2
-
- var/datum/pipe_network/network1
- var/datum/pipe_network/network2
-
- Initialize()
- switch(dir)
- if(NORTH)
- initialize_directions = NORTH|SOUTH
- if(SOUTH)
- initialize_directions = NORTH|SOUTH
- if(EAST)
- initialize_directions = EAST|WEST
- if(WEST)
- initialize_directions = EAST|WEST
- air1 = new
- air2 = new
-
- air1.volume = 200
- air2.volume = 200
- . = ..()
-
-// Housekeeping and pipe network stuff below
- network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
- if(reference == node1)
- network1 = new_network
-
- else if(reference == node2)
- network2 = new_network
-
- if(new_network.normal_members.Find(src))
- return 0
-
- new_network.normal_members += src
-
- return null
-
- Destroy()
- QDEL_NULL(air1)
- QDEL_NULL(air2)
-
- if(node1)
- node1.disconnect(src)
- QDEL_NULL(network1)
- if(node2)
- node2.disconnect(src)
- QDEL_NULL(network2)
-
- node1 = null
- node2 = null
-
- return ..()
-
- atmos_init()
- if(node1 && node2) return
-
- var/node2_connect = dir
- var/node1_connect = turn(dir, 180)
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node2 = target
- break
-
- update_icon()
- update_underlays()
-
- build_network()
- if(!network1 && node1)
- network1 = new /datum/pipe_network()
- network1.normal_members += src
- network1.build_network(node1, src)
-
- if(!network2 && node2)
- network2 = new /datum/pipe_network()
- network2.normal_members += src
- network2.build_network(node2, src)
-
-
- return_network(obj/machinery/atmospherics/reference)
- build_network()
-
- if(reference==node1)
- return network1
-
- if(reference==node2)
- return network2
-
- return null
-
- reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
- if(network1 == old_network)
- network1 = new_network
- if(network2 == old_network)
- network2 = new_network
-
- return 1
-
- return_network_air(datum/pipe_network/reference)
- var/list/results = list()
-
- if(network1 == reference)
- results += air1
- if(network2 == reference)
- results += air2
-
- return results
-
- disconnect(obj/machinery/atmospherics/reference)
- if(reference==node1)
- qdel(network1)
- node1 = null
-
- else if(reference==node2)
- qdel(network2)
- node2 = null
-
- update_icon()
- update_underlays()
-
- return null
+obj/machinery/atmospherics/binary
+ dir = SOUTH
+ initialize_directions = SOUTH|NORTH
+ use_power = 1
+
+ var/datum/gas_mixture/air1
+ var/datum/gas_mixture/air2
+
+ var/datum/pipe_network/network1
+ var/datum/pipe_network/network2
+
+ Initialize()
+ switch(dir)
+ if(NORTH)
+ initialize_directions = NORTH|SOUTH
+ if(SOUTH)
+ initialize_directions = NORTH|SOUTH
+ if(EAST)
+ initialize_directions = EAST|WEST
+ if(WEST)
+ initialize_directions = EAST|WEST
+ air1 = new
+ air2 = new
+
+ air1.volume = 200
+ air2.volume = 200
+ . = ..()
+
+// Housekeeping and pipe network stuff below
+ network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+ if(reference == node1)
+ network1 = new_network
+
+ else if(reference == node2)
+ network2 = new_network
+
+ if(new_network.normal_members.Find(src))
+ return 0
+
+ new_network.normal_members += src
+
+ return null
+
+ Destroy()
+ QDEL_NULL(air1)
+ QDEL_NULL(air2)
+
+ if(node1)
+ node1.disconnect(src)
+ QDEL_NULL(network1)
+ if(node2)
+ node2.disconnect(src)
+ QDEL_NULL(network2)
+
+ node1 = null
+ node2 = null
+
+ return ..()
+
+ atmos_init()
+ if(node1 && node2) return
+
+ var/node2_connect = dir
+ var/node1_connect = turn(dir, 180)
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node2 = target
+ break
+
+ update_icon()
+ update_underlays()
+
+ build_network()
+ if(!network1 && node1)
+ network1 = new /datum/pipe_network()
+ network1.normal_members += src
+ network1.build_network(node1, src)
+
+ if(!network2 && node2)
+ network2 = new /datum/pipe_network()
+ network2.normal_members += src
+ network2.build_network(node2, src)
+
+
+ return_network(obj/machinery/atmospherics/reference)
+ build_network()
+
+ if(reference==node1)
+ return network1
+
+ if(reference==node2)
+ return network2
+
+ return null
+
+ reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
+ if(network1 == old_network)
+ network1 = new_network
+ if(network2 == old_network)
+ network2 = new_network
+
+ return 1
+
+ return_network_air(datum/pipe_network/reference)
+ var/list/results = list()
+
+ if(network1 == reference)
+ results += air1
+ if(network2 == reference)
+ results += air2
+
+ return results
+
+ disconnect(obj/machinery/atmospherics/reference)
+ if(reference==node1)
+ qdel(network1)
+ node1 = null
+
+ else if(reference==node2)
+ qdel(network2)
+ node2 = null
+
+ update_icon()
+ update_underlays()
+
+ return null
diff --git a/code/ATMOSPHERICS/components/binary_devices/circulator.dm b/code/ATMOSPHERICS/components/binary_devices/circulator.dm
index 80679f73d0e..e90cc0deff7 100644
--- a/code/ATMOSPHERICS/components/binary_devices/circulator.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/circulator.dm
@@ -1,145 +1,145 @@
-//node1, air1, network1 correspond to input
-//node2, air2, network2 correspond to output
-
-/obj/machinery/atmospherics/binary/circulator
- name = "circulator"
- desc = "A gas circulator turbine and heat exchanger."
- icon = 'icons/obj/pipes.dmi'
- icon_state = "circ-off"
- anchored = 0
-
- var/kinetic_efficiency = 0.04 //combined kinetic and kinetic-to-electric efficiency
- var/volume_ratio = 0.2
-
- var/recent_moles_transferred = 0
- var/last_heat_capacity = 0
- var/last_temperature = 0
- var/last_pressure_delta = 0
- var/last_worldtime_transfer = 0
- var/last_stored_energy_transferred = 0
- var/volume_capacity_used = 0
- var/stored_energy = 0
-
- density = 1
-
-/obj/machinery/atmospherics/binary/circulator/Initialize()
- . = ..()
- desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]."
- air1.volume = 400
-
-/obj/machinery/atmospherics/binary/circulator/proc/return_transfer_air()
- var/datum/gas_mixture/removed
- if(anchored && !(stat&BROKEN) && network1)
- var/input_starting_pressure = air1.return_pressure()
- var/output_starting_pressure = air2.return_pressure()
- last_pressure_delta = max(input_starting_pressure - output_starting_pressure - 5, 0)
-
- //only circulate air if there is a pressure difference (plus 5kPa kinetic, 10kPa static friction)
- if(air1.temperature > 0 && last_pressure_delta > 5)
-
- //Calculate necessary moles to transfer using PV = nRT
- recent_moles_transferred = (last_pressure_delta*network1.volume/(air1.temperature * R_IDEAL_GAS_EQUATION))/3 //uses the volume of the whole network, not just itself
- volume_capacity_used = min( (last_pressure_delta*network1.volume/3)/(input_starting_pressure*air1.volume) , 1) //how much of the gas in the input air volume is consumed
-
- //Calculate energy generated from kinetic turbine
- stored_energy += 1/ADIABATIC_EXPONENT * min(last_pressure_delta * network1.volume , input_starting_pressure*air1.volume) * (1 - volume_ratio**ADIABATIC_EXPONENT) * kinetic_efficiency
-
- //Actually transfer the gas
- removed = air1.remove(recent_moles_transferred)
- if(removed)
- last_heat_capacity = removed.heat_capacity()
- last_temperature = removed.temperature
-
- //Update the gas networks.
- network1.update = 1
-
- last_worldtime_transfer = world.time
- else
- recent_moles_transferred = 0
-
- update_icon()
- return removed
-
-/obj/machinery/atmospherics/binary/circulator/proc/return_stored_energy()
- last_stored_energy_transferred = stored_energy
- stored_energy = 0
- return last_stored_energy_transferred
-
-/obj/machinery/atmospherics/binary/circulator/machinery_process()
- ..()
-
- if(last_worldtime_transfer < world.time - 50)
- recent_moles_transferred = 0
- update_icon()
-
-/obj/machinery/atmospherics/binary/circulator/update_icon()
- if(stat & (BROKEN|NOPOWER) || !anchored)
- icon_state = "circ-p"
- else if(last_pressure_delta > 0 && recent_moles_transferred > 0)
- if(last_pressure_delta > 5*ONE_ATMOSPHERE)
- icon_state = "circ-run"
- else
- icon_state = "circ-slow"
- else
- icon_state = "circ-off"
-
- return 1
-
-/obj/machinery/atmospherics/binary/circulator/attackby(obj/item/W as obj, mob/user as mob)
- if (W.iswrench())
- playsound(src.loc, W.usesound, 75, 1)
- anchored = !anchored
- user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the bolts holding [src.name] to the floor.", \
- "You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor.", \
- "You hear a ratchet")
-
- if(anchored)
- if(dir & (NORTH|SOUTH))
- initialize_directions = NORTH|SOUTH
- else if(dir & (EAST|WEST))
- initialize_directions = EAST|WEST
-
- atmos_init()
- build_network()
- if (node1)
- node1.atmos_init()
- node1.build_network()
- if (node2)
- node2.atmos_init()
- node2.build_network()
- else
- if(node1)
- node1.disconnect(src)
- qdel(network1)
- if(node2)
- node2.disconnect(src)
- qdel(network2)
-
- node1 = null
- node2 = null
-
- else
- ..()
-
-/obj/machinery/atmospherics/binary/circulator/verb/rotate_clockwise()
- set category = "Object"
- set name = "Rotate Circulator (Clockwise)"
- set src in view(1)
-
- if (usr.stat || usr.restrained() || anchored)
- return
-
- src.set_dir(turn(src.dir, 90))
- desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]."
-
-
-/obj/machinery/atmospherics/binary/circulator/verb/rotate_anticlockwise()
- set category = "Object"
- set name = "Rotate Circulator (Counterclockwise)"
- set src in view(1)
-
- if (usr.stat || usr.restrained() || anchored)
- return
-
- src.set_dir(turn(src.dir, -90))
- desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]."
+//node1, air1, network1 correspond to input
+//node2, air2, network2 correspond to output
+
+/obj/machinery/atmospherics/binary/circulator
+ name = "circulator"
+ desc = "A gas circulator turbine and heat exchanger."
+ icon = 'icons/obj/pipes.dmi'
+ icon_state = "circ-off"
+ anchored = 0
+
+ var/kinetic_efficiency = 0.04 //combined kinetic and kinetic-to-electric efficiency
+ var/volume_ratio = 0.2
+
+ var/recent_moles_transferred = 0
+ var/last_heat_capacity = 0
+ var/last_temperature = 0
+ var/last_pressure_delta = 0
+ var/last_worldtime_transfer = 0
+ var/last_stored_energy_transferred = 0
+ var/volume_capacity_used = 0
+ var/stored_energy = 0
+
+ density = 1
+
+/obj/machinery/atmospherics/binary/circulator/Initialize()
+ . = ..()
+ desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]."
+ air1.volume = 400
+
+/obj/machinery/atmospherics/binary/circulator/proc/return_transfer_air()
+ var/datum/gas_mixture/removed
+ if(anchored && !(stat&BROKEN) && network1)
+ var/input_starting_pressure = air1.return_pressure()
+ var/output_starting_pressure = air2.return_pressure()
+ last_pressure_delta = max(input_starting_pressure - output_starting_pressure - 5, 0)
+
+ //only circulate air if there is a pressure difference (plus 5kPa kinetic, 10kPa static friction)
+ if(air1.temperature > 0 && last_pressure_delta > 5)
+
+ //Calculate necessary moles to transfer using PV = nRT
+ recent_moles_transferred = (last_pressure_delta*network1.volume/(air1.temperature * R_IDEAL_GAS_EQUATION))/3 //uses the volume of the whole network, not just itself
+ volume_capacity_used = min( (last_pressure_delta*network1.volume/3)/(input_starting_pressure*air1.volume) , 1) //how much of the gas in the input air volume is consumed
+
+ //Calculate energy generated from kinetic turbine
+ stored_energy += 1/ADIABATIC_EXPONENT * min(last_pressure_delta * network1.volume , input_starting_pressure*air1.volume) * (1 - volume_ratio**ADIABATIC_EXPONENT) * kinetic_efficiency
+
+ //Actually transfer the gas
+ removed = air1.remove(recent_moles_transferred)
+ if(removed)
+ last_heat_capacity = removed.heat_capacity()
+ last_temperature = removed.temperature
+
+ //Update the gas networks.
+ network1.update = 1
+
+ last_worldtime_transfer = world.time
+ else
+ recent_moles_transferred = 0
+
+ update_icon()
+ return removed
+
+/obj/machinery/atmospherics/binary/circulator/proc/return_stored_energy()
+ last_stored_energy_transferred = stored_energy
+ stored_energy = 0
+ return last_stored_energy_transferred
+
+/obj/machinery/atmospherics/binary/circulator/machinery_process()
+ ..()
+
+ if(last_worldtime_transfer < world.time - 50)
+ recent_moles_transferred = 0
+ update_icon()
+
+/obj/machinery/atmospherics/binary/circulator/update_icon()
+ if(stat & (BROKEN|NOPOWER) || !anchored)
+ icon_state = "circ-p"
+ else if(last_pressure_delta > 0 && recent_moles_transferred > 0)
+ if(last_pressure_delta > 5*ONE_ATMOSPHERE)
+ icon_state = "circ-run"
+ else
+ icon_state = "circ-slow"
+ else
+ icon_state = "circ-off"
+
+ return 1
+
+/obj/machinery/atmospherics/binary/circulator/attackby(obj/item/W as obj, mob/user as mob)
+ if (W.iswrench())
+ playsound(src.loc, W.usesound, 75, 1)
+ anchored = !anchored
+ user.visible_message("[user.name] [anchored ? "secures" : "unsecures"] the bolts holding [src.name] to the floor.", \
+ "You [anchored ? "secure" : "unsecure"] the bolts holding [src] to the floor.", \
+ "You hear a ratchet")
+
+ if(anchored)
+ if(dir & (NORTH|SOUTH))
+ initialize_directions = NORTH|SOUTH
+ else if(dir & (EAST|WEST))
+ initialize_directions = EAST|WEST
+
+ atmos_init()
+ build_network()
+ if (node1)
+ node1.atmos_init()
+ node1.build_network()
+ if (node2)
+ node2.atmos_init()
+ node2.build_network()
+ else
+ if(node1)
+ node1.disconnect(src)
+ qdel(network1)
+ if(node2)
+ node2.disconnect(src)
+ qdel(network2)
+
+ node1 = null
+ node2 = null
+
+ else
+ ..()
+
+/obj/machinery/atmospherics/binary/circulator/verb/rotate_clockwise()
+ set category = "Object"
+ set name = "Rotate Circulator (Clockwise)"
+ set src in view(1)
+
+ if (usr.stat || usr.restrained() || anchored)
+ return
+
+ src.set_dir(turn(src.dir, 90))
+ desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]."
+
+
+/obj/machinery/atmospherics/binary/circulator/verb/rotate_anticlockwise()
+ set category = "Object"
+ set name = "Rotate Circulator (Counterclockwise)"
+ set src in view(1)
+
+ if (usr.stat || usr.restrained() || anchored)
+ return
+
+ src.set_dir(turn(src.dir, -90))
+ desc = initial(desc) + " Its outlet port is to the [dir2text(dir)]."
diff --git a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm
index 5c021e2bddf..a549eeb0160 100644
--- a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm
@@ -1,265 +1,265 @@
-#define DEFAULT_PRESSURE_DELTA 10000
-
-#define EXTERNAL_PRESSURE_BOUND ONE_ATMOSPHERE
-#define INTERNAL_PRESSURE_BOUND 0
-#define PRESSURE_CHECKS 1
-
-#define PRESSURE_CHECK_EXTERNAL 1
-#define PRESSURE_CHECK_INPUT 2
-#define PRESSURE_CHECK_OUTPUT 4
-
-/obj/machinery/atmospherics/binary/dp_vent_pump
- icon = 'icons/atmos/vent_pump.dmi'
- icon_state = "map_dp_vent"
-
- //node2 is output port
- //node1 is input port
-
- name = "Dual Port Air Vent"
- desc = "Has a valve and pump attached to it. There are two ports."
-
- level = 1
-
- use_power = 0
- idle_power_usage = 150 //internal circuitry, friction losses and stuff
- power_rating = 7500 //7500 W ~ 10 HP
-
- connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER //connects to regular, supply and scrubbers pipes
-
- var/pump_direction = 1 //0 = siphoning, 1 = releasing
-
- var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
- var/input_pressure_min = INTERNAL_PRESSURE_BOUND
- var/output_pressure_max = DEFAULT_PRESSURE_DELTA
-
- var/frequency = 0
- var/id = null
- var/datum/radio_frequency/radio_connection
-
- var/pressure_checks = PRESSURE_CHECK_EXTERNAL
- //1: Do not pass external_pressure_bound
- //2: Do not pass input_pressure_min
- //4: Do not pass output_pressure_max
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/Initialize()
- . = ..()
- air1.volume = ATMOS_DEFAULT_VOLUME_PUMP
- air2.volume = ATMOS_DEFAULT_VOLUME_PUMP
- icon = null
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume
- name = "Large Dual Port Air Vent"
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume/Initialize()
- . = ..()
- air1.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
- air2.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- var/istate = ""
-
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
-
- if(!T.is_plating() && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe))
- istate += "h"
-
- if(!powered())
- istate += "off"
- else
- istate += "[use_power ? "[pump_direction ? "out" : "in"]" : "off"]"
-
- icon_state = istate
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
- if(!T.is_plating() && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe))
- return
- else
- if (node1)
- add_underlay(T, node1, turn(dir, -180), node1.icon_connect_type)
- else
- add_underlay(T, node1, turn(dir, -180))
- if (node2)
- add_underlay(T, node2, dir, node2.icon_connect_type)
- else
- add_underlay(T, node2, dir)
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/hide(var/i)
- update_icon()
- update_underlays()
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/machinery_process()
- ..()
-
- last_power_draw = 0
- last_flow_rate = 0
-
- if(stat & (NOPOWER|BROKEN) || !use_power)
- return 0
-
- var/datum/gas_mixture/environment = loc.return_air()
-
- var/power_draw = -1
-
- //Figure out the target pressure difference
- var/pressure_delta = get_pressure_delta(environment)
-
- if(pressure_delta > 0.5)
- if(pump_direction) //internal -> external
- if (node1 && (environment.temperature || air1.temperature))
- var/transfer_moles = calculate_transfer_moles(air1, environment, pressure_delta)
- power_draw = pump_gas(src, air1, environment, transfer_moles, power_rating)
-
- if(power_draw >= 0 && network1)
- network1.update = 1
- else //external -> internal
- if (node2 && (environment.temperature || air2.temperature))
- var/transfer_moles = calculate_transfer_moles(environment, air2, pressure_delta, (network2)? network2.volume : 0)
-
- //limit flow rate from turfs
- transfer_moles = min(transfer_moles, environment.total_moles*air2.volume/environment.volume) //group_multiplier gets divided out here
- power_draw = pump_gas(src, environment, air2, transfer_moles, power_rating)
-
- if(power_draw >= 0 && network2)
- network2.update = 1
-
- if (power_draw >= 0)
- last_power_draw = power_draw
- use_power(power_draw)
-
- return 1
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/proc/get_pressure_delta(datum/gas_mixture/environment)
- var/pressure_delta = DEFAULT_PRESSURE_DELTA
- var/environment_pressure = environment.return_pressure()
-
- if(pump_direction) //internal -> external
- if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
- pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here
- if(pressure_checks & PRESSURE_CHECK_INPUT)
- pressure_delta = min(pressure_delta, air1.return_pressure() - input_pressure_min) //decreasing the pressure here
- else //external -> internal
- if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
- pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here
- if(pressure_checks & PRESSURE_CHECK_OUTPUT)
- pressure_delta = min(pressure_delta, output_pressure_max - air2.return_pressure()) //increasing the pressure here
-
- return pressure_delta
-
-
-//Radio remote control
-
-/obj/machinery/atmospherics/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/binary/dp_vent_pump/proc/broadcast_status()
- if(!radio_connection)
- return 0
-
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.source = src
-
- signal.data = list(
- "tag" = id,
- "device" = "ADVP",
- "power" = use_power,
- "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)
-
- return 1
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/atmos_init()
- ..()
- if(frequency)
- set_frequency(frequency)
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/examine(mob/user)
- if(..(user, 1))
- to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W")
-
-
-/obj/machinery/atmospherics/unary/vent_pump/power_change()
- var/old_stat = stat
- ..()
- if(old_stat != stat)
- update_icon()
-
-/obj/machinery/atmospherics/binary/dp_vent_pump/receive_signal(datum/signal/signal)
- if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
- return 0
- if(signal.data["power"])
- use_power = text2num(signal.data["power"])
-
- if(signal.data["power_toggle"])
- use_power = !use_power
-
- if(signal.data["direction"])
- pump_direction = text2num(signal.data["direction"])
-
- if(signal.data["checks"])
- pressure_checks = text2num(signal.data["checks"])
-
- if(signal.data["purge"])
- pressure_checks &= ~1
- pump_direction = 0
-
- if(signal.data["stabalize"])
- pressure_checks |= 1
- pump_direction = 1
-
- if(signal.data["set_input_pressure"])
- input_pressure_min = between(
- 0,
- text2num(signal.data["set_input_pressure"]),
- ONE_ATMOSPHERE*50
- )
-
- if(signal.data["set_output_pressure"])
- output_pressure_max = between(
- 0,
- text2num(signal.data["set_output_pressure"]),
- ONE_ATMOSPHERE*50
- )
-
- if(signal.data["set_external_pressure"])
- external_pressure_bound = between(
- 0,
- text2num(signal.data["set_external_pressure"]),
- ONE_ATMOSPHERE*50
- )
-
- if(signal.data["status"])
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- return //do not update_icon
-
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- update_icon()
-
-#undef DEFAULT_PRESSURE_DELTA
-
-#undef EXTERNAL_PRESSURE_BOUND
-#undef INTERNAL_PRESSURE_BOUND
-#undef PRESSURE_CHECKS
-
-#undef PRESSURE_CHECK_EXTERNAL
-#undef PRESSURE_CHECK_INPUT
-#undef PRESSURE_CHECK_OUTPUT
+#define DEFAULT_PRESSURE_DELTA 10000
+
+#define EXTERNAL_PRESSURE_BOUND ONE_ATMOSPHERE
+#define INTERNAL_PRESSURE_BOUND 0
+#define PRESSURE_CHECKS 1
+
+#define PRESSURE_CHECK_EXTERNAL 1
+#define PRESSURE_CHECK_INPUT 2
+#define PRESSURE_CHECK_OUTPUT 4
+
+/obj/machinery/atmospherics/binary/dp_vent_pump
+ icon = 'icons/atmos/vent_pump.dmi'
+ icon_state = "map_dp_vent"
+
+ //node2 is output port
+ //node1 is input port
+
+ name = "Dual Port Air Vent"
+ desc = "Has a valve and pump attached to it. There are two ports."
+
+ level = 1
+
+ use_power = 0
+ idle_power_usage = 150 //internal circuitry, friction losses and stuff
+ power_rating = 7500 //7500 W ~ 10 HP
+
+ connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER //connects to regular, supply and scrubbers pipes
+
+ var/pump_direction = 1 //0 = siphoning, 1 = releasing
+
+ var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
+ var/input_pressure_min = INTERNAL_PRESSURE_BOUND
+ var/output_pressure_max = DEFAULT_PRESSURE_DELTA
+
+ var/frequency = 0
+ var/id = null
+ var/datum/radio_frequency/radio_connection
+
+ var/pressure_checks = PRESSURE_CHECK_EXTERNAL
+ //1: Do not pass external_pressure_bound
+ //2: Do not pass input_pressure_min
+ //4: Do not pass output_pressure_max
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/Initialize()
+ . = ..()
+ air1.volume = ATMOS_DEFAULT_VOLUME_PUMP
+ air2.volume = ATMOS_DEFAULT_VOLUME_PUMP
+ icon = null
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume
+ name = "Large Dual Port Air Vent"
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume/Initialize()
+ . = ..()
+ air1.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
+ air2.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ var/istate = ""
+
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+
+ if(!T.is_plating() && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe))
+ istate += "h"
+
+ if(!powered())
+ istate += "off"
+ else
+ istate += "[use_power ? "[pump_direction ? "out" : "in"]" : "off"]"
+
+ icon_state = istate
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+ if(!T.is_plating() && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe))
+ return
+ else
+ if (node1)
+ add_underlay(T, node1, turn(dir, -180), node1.icon_connect_type)
+ else
+ add_underlay(T, node1, turn(dir, -180))
+ if (node2)
+ add_underlay(T, node2, dir, node2.icon_connect_type)
+ else
+ add_underlay(T, node2, dir)
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/hide(var/i)
+ update_icon()
+ update_underlays()
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/machinery_process()
+ ..()
+
+ last_power_draw = 0
+ last_flow_rate = 0
+
+ if(stat & (NOPOWER|BROKEN) || !use_power)
+ return 0
+
+ var/datum/gas_mixture/environment = loc.return_air()
+
+ var/power_draw = -1
+
+ //Figure out the target pressure difference
+ var/pressure_delta = get_pressure_delta(environment)
+
+ if(pressure_delta > 0.5)
+ if(pump_direction) //internal -> external
+ if (node1 && (environment.temperature || air1.temperature))
+ var/transfer_moles = calculate_transfer_moles(air1, environment, pressure_delta)
+ power_draw = pump_gas(src, air1, environment, transfer_moles, power_rating)
+
+ if(power_draw >= 0 && network1)
+ network1.update = 1
+ else //external -> internal
+ if (node2 && (environment.temperature || air2.temperature))
+ var/transfer_moles = calculate_transfer_moles(environment, air2, pressure_delta, (network2)? network2.volume : 0)
+
+ //limit flow rate from turfs
+ transfer_moles = min(transfer_moles, environment.total_moles*air2.volume/environment.volume) //group_multiplier gets divided out here
+ power_draw = pump_gas(src, environment, air2, transfer_moles, power_rating)
+
+ if(power_draw >= 0 && network2)
+ network2.update = 1
+
+ if (power_draw >= 0)
+ last_power_draw = power_draw
+ use_power(power_draw)
+
+ return 1
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/proc/get_pressure_delta(datum/gas_mixture/environment)
+ var/pressure_delta = DEFAULT_PRESSURE_DELTA
+ var/environment_pressure = environment.return_pressure()
+
+ if(pump_direction) //internal -> external
+ if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
+ pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here
+ if(pressure_checks & PRESSURE_CHECK_INPUT)
+ pressure_delta = min(pressure_delta, air1.return_pressure() - input_pressure_min) //decreasing the pressure here
+ else //external -> internal
+ if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
+ pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here
+ if(pressure_checks & PRESSURE_CHECK_OUTPUT)
+ pressure_delta = min(pressure_delta, output_pressure_max - air2.return_pressure()) //increasing the pressure here
+
+ return pressure_delta
+
+
+//Radio remote control
+
+/obj/machinery/atmospherics/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/binary/dp_vent_pump/proc/broadcast_status()
+ if(!radio_connection)
+ return 0
+
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.source = src
+
+ signal.data = list(
+ "tag" = id,
+ "device" = "ADVP",
+ "power" = use_power,
+ "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)
+
+ return 1
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/atmos_init()
+ ..()
+ if(frequency)
+ set_frequency(frequency)
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/examine(mob/user)
+ if(..(user, 1))
+ to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W")
+
+
+/obj/machinery/atmospherics/unary/vent_pump/power_change()
+ var/old_stat = stat
+ ..()
+ if(old_stat != stat)
+ update_icon()
+
+/obj/machinery/atmospherics/binary/dp_vent_pump/receive_signal(datum/signal/signal)
+ if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
+ return 0
+ if(signal.data["power"])
+ use_power = text2num(signal.data["power"])
+
+ if(signal.data["power_toggle"])
+ use_power = !use_power
+
+ if(signal.data["direction"])
+ pump_direction = text2num(signal.data["direction"])
+
+ if(signal.data["checks"])
+ pressure_checks = text2num(signal.data["checks"])
+
+ if(signal.data["purge"])
+ pressure_checks &= ~1
+ pump_direction = 0
+
+ if(signal.data["stabalize"])
+ pressure_checks |= 1
+ pump_direction = 1
+
+ if(signal.data["set_input_pressure"])
+ input_pressure_min = between(
+ 0,
+ text2num(signal.data["set_input_pressure"]),
+ ONE_ATMOSPHERE*50
+ )
+
+ if(signal.data["set_output_pressure"])
+ output_pressure_max = between(
+ 0,
+ text2num(signal.data["set_output_pressure"]),
+ ONE_ATMOSPHERE*50
+ )
+
+ if(signal.data["set_external_pressure"])
+ external_pressure_bound = between(
+ 0,
+ text2num(signal.data["set_external_pressure"]),
+ ONE_ATMOSPHERE*50
+ )
+
+ if(signal.data["status"])
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ return //do not update_icon
+
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ update_icon()
+
+#undef DEFAULT_PRESSURE_DELTA
+
+#undef EXTERNAL_PRESSURE_BOUND
+#undef INTERNAL_PRESSURE_BOUND
+#undef PRESSURE_CHECKS
+
+#undef PRESSURE_CHECK_EXTERNAL
+#undef PRESSURE_CHECK_INPUT
+#undef PRESSURE_CHECK_OUTPUT
diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
index 85803f37752..d0a2e940c23 100644
--- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm
@@ -1,261 +1,261 @@
-#define REGULATE_NONE 0
-#define REGULATE_INPUT 1 //shuts off when input side is below the target pressure
-#define REGULATE_OUTPUT 2 //shuts off when output side is above the target pressure
-
-/obj/machinery/atmospherics/binary/passive_gate
- icon = 'icons/atmos/passive_gate.dmi'
- icon_state = "map"
- level = 1
-
- name = "pressure regulator"
- desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. Does not require power."
-
- use_power = 0
- interact_offline = 1
- var/unlocked = 0 //If 0, then the valve is locked closed, otherwise it is open(-able, it's a one-way valve so it closes if gas would flow backwards).
- var/target_pressure = ONE_ATMOSPHERE
- var/max_pressure_setting = 15000 //kPa
- var/set_flow_rate = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
- var/regulate_mode = REGULATE_OUTPUT
-
- var/flowing = 0 //for icons - becomes zero if the valve closes itself due to regulation mode
-
- var/frequency = 0
- var/id = null
- var/datum/radio_frequency/radio_connection
-
-/obj/machinery/atmospherics/binary/passive_gate/Initialize()
- . = ..()
- air1.volume = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
- air2.volume = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
-
-/obj/machinery/atmospherics/binary/passive_gate/update_icon()
- icon_state = (unlocked && flowing)? "on" : "off"
-
-/obj/machinery/atmospherics/binary/passive_gate/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
- add_underlay(T, node1, turn(dir, 180))
- add_underlay(T, node2, dir)
-
-/obj/machinery/atmospherics/binary/passive_gate/hide(var/i)
- update_underlays()
-
-/obj/machinery/atmospherics/binary/passive_gate/machinery_process()
- ..()
-
- last_flow_rate = 0
-
- if(!unlocked)
- return 0
-
- var/output_starting_pressure = air2.return_pressure()
- var/input_starting_pressure = air1.return_pressure()
-
- var/pressure_delta
- switch (regulate_mode)
- if (REGULATE_INPUT)
- pressure_delta = input_starting_pressure - target_pressure
- if (REGULATE_OUTPUT)
- pressure_delta = target_pressure - output_starting_pressure
-
- //-1 if pump_gas() did not move any gas, >= 0 otherwise
- var/returnval = -1
- if((regulate_mode == REGULATE_NONE || pressure_delta > 0.01) && (air1.temperature > 0 || air2.temperature > 0)) //since it's basically a valve, it makes sense to check both temperatures
- flowing = 1
-
- //flow rate limit
- var/transfer_moles = (set_flow_rate/air1.volume)*air1.total_moles
-
- //Figure out how much gas to transfer to meet the target pressure.
- switch (regulate_mode)
- if (REGULATE_INPUT)
- transfer_moles = min(transfer_moles, calculate_transfer_moles(air2, air1, pressure_delta, (network1)? network1.volume : 0))
- if (REGULATE_OUTPUT)
- transfer_moles = min(transfer_moles, calculate_transfer_moles(air1, air2, pressure_delta, (network2)? network2.volume : 0))
-
- //pump_gas() will return a negative number if no flow occurred
- returnval = pump_gas_passive(src, air1, air2, transfer_moles)
-
- if (returnval >= 0)
- if(network1)
- network1.update = 1
-
- if(network2)
- network2.update = 1
-
- if (last_flow_rate)
- flowing = 1
-
- update_icon()
-
-
-//Radio remote control
-
-/obj/machinery/atmospherics/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/binary/passive_gate/proc/broadcast_status()
- if(!radio_connection)
- return 0
-
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.source = src
-
- signal.data = list(
- "tag" = id,
- "device" = "AGP",
- "power" = unlocked,
- "target_output" = target_pressure,
- "regulate_mode" = regulate_mode,
- "set_flow_rate" = set_flow_rate,
- "sigtype" = "status"
- )
-
- radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
-
- return 1
-
-/obj/machinery/atmospherics/binary/passive_gate/atmos_init()
- ..()
- if(frequency)
- set_frequency(frequency)
-
-/obj/machinery/atmospherics/binary/passive_gate/receive_signal(datum/signal/signal)
- if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
- return 0
-
- if("power" in signal.data)
- unlocked = text2num(signal.data["power"])
-
- if("power_toggle" in signal.data)
- unlocked = !unlocked
-
- if("set_target_pressure" in signal.data)
- target_pressure = between(
- 0,
- text2num(signal.data["set_target_pressure"]),
- max_pressure_setting
- )
-
- if("set_regulate_mode" in signal.data)
- regulate_mode = text2num(signal.data["set_regulate_mode"])
-
- if("set_flow_rate" in signal.data)
- regulate_mode = text2num(signal.data["set_flow_rate"])
-
- if("status" in signal.data)
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- return //do not update_icon
-
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- update_icon()
- return
-
-/obj/machinery/atmospherics/binary/passive_gate/attack_hand(user as mob)
- if(..())
- return
- src.add_fingerprint(usr)
- if(!src.allowed(user))
- to_chat(user, "Access denied.")
- return
- usr.set_machine(src)
- ui_interact(user)
- return
-
-/obj/machinery/atmospherics/binary/passive_gate/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- if(stat & (BROKEN|NOPOWER))
- return
-
- // this is the data which will be sent to the ui
- var/data[0]
-
- data = list(
- "on" = unlocked,
- "pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently.
- "max_pressure" = max_pressure_setting,
- "input_pressure" = round(air1.return_pressure()*100),
- "output_pressure" = round(air2.return_pressure()*100),
- "regulate_mode" = regulate_mode,
- "set_flow_rate" = round(set_flow_rate*10),
- "last_flow_rate" = round(last_flow_rate*10)
- )
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "pressure_regulator.tmpl", name, 470, 370)
- ui.set_initial_data(data) // when the ui is first opened this is the data it will use
- ui.open() // open the new ui window
- ui.set_auto_update(1) // auto update every Master Controller tick
-
-
-/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list)
- if(..()) return 1
-
- if(href_list["toggle_valve"])
- unlocked = !unlocked
-
- if(href_list["regulate_mode"])
- switch(href_list["regulate_mode"])
- if ("off") regulate_mode = REGULATE_NONE
- if ("input") regulate_mode = REGULATE_INPUT
- if ("output") regulate_mode = REGULATE_OUTPUT
-
- switch(href_list["set_press"])
- if ("min")
- target_pressure = 0
- if ("max")
- target_pressure = max_pressure_setting
- if ("set")
- var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure Control",src.target_pressure) as num
- src.target_pressure = between(0, new_pressure, max_pressure_setting)
-
- switch(href_list["set_flow_rate"])
- if ("min")
- set_flow_rate = 0
- if ("max")
- set_flow_rate = air1.volume
- if ("set")
- var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[air1.volume]kPa)","Flow Rate Control",src.set_flow_rate) as num
- src.set_flow_rate = between(0, new_flow_rate, air1.volume)
-
- usr.set_machine(src) //Is this even needed with NanoUI?
- src.update_icon()
- src.add_fingerprint(usr)
- return
-
-/obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if (!W.iswrench())
- return ..()
- if (unlocked)
- to_chat(user, "You cannot unwrench \the [src], turn it off first.")
- return 1
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
- if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
- to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- playsound(src.loc, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, 40/W.toolspeed, act_target = src))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- qdel(src)
-
-#undef REGULATE_NONE
-#undef REGULATE_INPUT
-#undef REGULATE_OUTPUT
+#define REGULATE_NONE 0
+#define REGULATE_INPUT 1 //shuts off when input side is below the target pressure
+#define REGULATE_OUTPUT 2 //shuts off when output side is above the target pressure
+
+/obj/machinery/atmospherics/binary/passive_gate
+ icon = 'icons/atmos/passive_gate.dmi'
+ icon_state = "map"
+ level = 1
+
+ name = "pressure regulator"
+ desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. Does not require power."
+
+ use_power = 0
+ interact_offline = 1
+ var/unlocked = 0 //If 0, then the valve is locked closed, otherwise it is open(-able, it's a one-way valve so it closes if gas would flow backwards).
+ var/target_pressure = ONE_ATMOSPHERE
+ var/max_pressure_setting = 15000 //kPa
+ var/set_flow_rate = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
+ var/regulate_mode = REGULATE_OUTPUT
+
+ var/flowing = 0 //for icons - becomes zero if the valve closes itself due to regulation mode
+
+ var/frequency = 0
+ var/id = null
+ var/datum/radio_frequency/radio_connection
+
+/obj/machinery/atmospherics/binary/passive_gate/Initialize()
+ . = ..()
+ air1.volume = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
+ air2.volume = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
+
+/obj/machinery/atmospherics/binary/passive_gate/update_icon()
+ icon_state = (unlocked && flowing)? "on" : "off"
+
+/obj/machinery/atmospherics/binary/passive_gate/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+ add_underlay(T, node1, turn(dir, 180))
+ add_underlay(T, node2, dir)
+
+/obj/machinery/atmospherics/binary/passive_gate/hide(var/i)
+ update_underlays()
+
+/obj/machinery/atmospherics/binary/passive_gate/machinery_process()
+ ..()
+
+ last_flow_rate = 0
+
+ if(!unlocked)
+ return 0
+
+ var/output_starting_pressure = air2.return_pressure()
+ var/input_starting_pressure = air1.return_pressure()
+
+ var/pressure_delta
+ switch (regulate_mode)
+ if (REGULATE_INPUT)
+ pressure_delta = input_starting_pressure - target_pressure
+ if (REGULATE_OUTPUT)
+ pressure_delta = target_pressure - output_starting_pressure
+
+ //-1 if pump_gas() did not move any gas, >= 0 otherwise
+ var/returnval = -1
+ if((regulate_mode == REGULATE_NONE || pressure_delta > 0.01) && (air1.temperature > 0 || air2.temperature > 0)) //since it's basically a valve, it makes sense to check both temperatures
+ flowing = 1
+
+ //flow rate limit
+ var/transfer_moles = (set_flow_rate/air1.volume)*air1.total_moles
+
+ //Figure out how much gas to transfer to meet the target pressure.
+ switch (regulate_mode)
+ if (REGULATE_INPUT)
+ transfer_moles = min(transfer_moles, calculate_transfer_moles(air2, air1, pressure_delta, (network1)? network1.volume : 0))
+ if (REGULATE_OUTPUT)
+ transfer_moles = min(transfer_moles, calculate_transfer_moles(air1, air2, pressure_delta, (network2)? network2.volume : 0))
+
+ //pump_gas() will return a negative number if no flow occurred
+ returnval = pump_gas_passive(src, air1, air2, transfer_moles)
+
+ if (returnval >= 0)
+ if(network1)
+ network1.update = 1
+
+ if(network2)
+ network2.update = 1
+
+ if (last_flow_rate)
+ flowing = 1
+
+ update_icon()
+
+
+//Radio remote control
+
+/obj/machinery/atmospherics/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/binary/passive_gate/proc/broadcast_status()
+ if(!radio_connection)
+ return 0
+
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.source = src
+
+ signal.data = list(
+ "tag" = id,
+ "device" = "AGP",
+ "power" = unlocked,
+ "target_output" = target_pressure,
+ "regulate_mode" = regulate_mode,
+ "set_flow_rate" = set_flow_rate,
+ "sigtype" = "status"
+ )
+
+ radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
+
+ return 1
+
+/obj/machinery/atmospherics/binary/passive_gate/atmos_init()
+ ..()
+ if(frequency)
+ set_frequency(frequency)
+
+/obj/machinery/atmospherics/binary/passive_gate/receive_signal(datum/signal/signal)
+ if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
+ return 0
+
+ if("power" in signal.data)
+ unlocked = text2num(signal.data["power"])
+
+ if("power_toggle" in signal.data)
+ unlocked = !unlocked
+
+ if("set_target_pressure" in signal.data)
+ target_pressure = between(
+ 0,
+ text2num(signal.data["set_target_pressure"]),
+ max_pressure_setting
+ )
+
+ if("set_regulate_mode" in signal.data)
+ regulate_mode = text2num(signal.data["set_regulate_mode"])
+
+ if("set_flow_rate" in signal.data)
+ regulate_mode = text2num(signal.data["set_flow_rate"])
+
+ if("status" in signal.data)
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ return //do not update_icon
+
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ update_icon()
+ return
+
+/obj/machinery/atmospherics/binary/passive_gate/attack_hand(user as mob)
+ if(..())
+ return
+ src.add_fingerprint(usr)
+ if(!src.allowed(user))
+ to_chat(user, "Access denied.")
+ return
+ usr.set_machine(src)
+ ui_interact(user)
+ return
+
+/obj/machinery/atmospherics/binary/passive_gate/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+ if(stat & (BROKEN|NOPOWER))
+ return
+
+ // this is the data which will be sent to the ui
+ var/data[0]
+
+ data = list(
+ "on" = unlocked,
+ "pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently.
+ "max_pressure" = max_pressure_setting,
+ "input_pressure" = round(air1.return_pressure()*100),
+ "output_pressure" = round(air2.return_pressure()*100),
+ "regulate_mode" = regulate_mode,
+ "set_flow_rate" = round(set_flow_rate*10),
+ "last_flow_rate" = round(last_flow_rate*10)
+ )
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if (!ui)
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
+ ui = new(user, src, ui_key, "pressure_regulator.tmpl", name, 470, 370)
+ ui.set_initial_data(data) // when the ui is first opened this is the data it will use
+ ui.open() // open the new ui window
+ ui.set_auto_update(1) // auto update every Master Controller tick
+
+
+/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list)
+ if(..()) return 1
+
+ if(href_list["toggle_valve"])
+ unlocked = !unlocked
+
+ if(href_list["regulate_mode"])
+ switch(href_list["regulate_mode"])
+ if ("off") regulate_mode = REGULATE_NONE
+ if ("input") regulate_mode = REGULATE_INPUT
+ if ("output") regulate_mode = REGULATE_OUTPUT
+
+ switch(href_list["set_press"])
+ if ("min")
+ target_pressure = 0
+ if ("max")
+ target_pressure = max_pressure_setting
+ if ("set")
+ var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure Control",src.target_pressure) as num
+ src.target_pressure = between(0, new_pressure, max_pressure_setting)
+
+ switch(href_list["set_flow_rate"])
+ if ("min")
+ set_flow_rate = 0
+ if ("max")
+ set_flow_rate = air1.volume
+ if ("set")
+ var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[air1.volume]kPa)","Flow Rate Control",src.set_flow_rate) as num
+ src.set_flow_rate = between(0, new_flow_rate, air1.volume)
+
+ usr.set_machine(src) //Is this even needed with NanoUI?
+ src.update_icon()
+ src.add_fingerprint(usr)
+ return
+
+/obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if (!W.iswrench())
+ return ..()
+ if (unlocked)
+ to_chat(user, "You cannot unwrench \the [src], turn it off first.")
+ return 1
+ var/datum/gas_mixture/int_air = return_air()
+ var/datum/gas_mixture/env_air = loc.return_air()
+ if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
+ to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ playsound(src.loc, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, 40/W.toolspeed, act_target = src))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ qdel(src)
+
+#undef REGULATE_NONE
+#undef REGULATE_INPUT
+#undef REGULATE_OUTPUT
diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm
index ab3626dd3f3..c90b6281fd0 100644
--- a/code/ATMOSPHERICS/components/binary_devices/pump.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm
@@ -1,238 +1,238 @@
-/*
-Every cycle, the pump uses the air in air_in to try and make air_out the perfect pressure.
-
-node1, air1, network1 correspond to input
-node2, air2, network2 correspond to output
-
-Thus, the two variables affect pump operation are set in New():
- air1.volume
- This is the volume of gas available to the pump that may be transfered to the output
- air2.volume
- Higher quantities of this cause more air to be perfected later
- but overall network volume is also increased as this increases...
-*/
-
-/obj/machinery/atmospherics/binary/pump
- icon = 'icons/atmos/pump.dmi'
- icon_state = "map_off"
- level = 1
-
- name = "gas pump"
- desc = "A pump"
-
- var/target_pressure = ONE_ATMOSPHERE
-
- //var/max_volume_transfer = 10000
-
- use_power = 0
- idle_power_usage = 150 //internal circuitry, friction losses and stuff
- power_rating = 7500 //7500 W ~ 10 HP
-
- var/max_pressure_setting = 15000 //kPa
-
- var/frequency = 0
- var/id = null
- var/datum/radio_frequency/radio_connection
-
-/obj/machinery/atmospherics/binary/pump/Initialize()
- . = ..()
- air1.volume = ATMOS_DEFAULT_VOLUME_PUMP
- air2.volume = ATMOS_DEFAULT_VOLUME_PUMP
-
-/obj/machinery/atmospherics/binary/pump/on
- icon_state = "map_on"
- use_power = 1
-
-
-/obj/machinery/atmospherics/binary/pump/update_icon()
- if(!powered())
- icon_state = "off"
- else
- icon_state = "[use_power ? "on" : "off"]"
-
-/obj/machinery/atmospherics/binary/pump/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
- add_underlay(T, node1, turn(dir, -180))
- add_underlay(T, node2, dir)
-
-/obj/machinery/atmospherics/binary/pump/hide(var/i)
- update_underlays()
-
-/obj/machinery/atmospherics/binary/pump/machinery_process()
- last_power_draw = 0
- last_flow_rate = 0
-
- if((stat & (NOPOWER|BROKEN)) || !use_power)
- return
-
- var/power_draw = -1
- var/pressure_delta = target_pressure - air2.return_pressure()
-
- if(pressure_delta > 0.01 && air1.temperature > 0)
- //Figure out how much gas to transfer to meet the target pressure.
- var/transfer_moles = calculate_transfer_moles(air1, air2, pressure_delta, (network2)? network2.volume : 0)
- power_draw = pump_gas(src, air1, air2, transfer_moles, power_rating)
-
- if (power_draw >= 0)
- last_power_draw = power_draw
- use_power(power_draw)
-
- if(network1)
- network1.update = 1
-
- if(network2)
- network2.update = 1
-
- return 1
-
-//Radio remote control
-
-/obj/machinery/atmospherics/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/binary/pump/proc/broadcast_status()
- if(!radio_connection)
- return 0
-
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.source = src
-
- signal.data = list(
- "tag" = id,
- "device" = "AGP",
- "power" = use_power,
- "target_output" = target_pressure,
- "sigtype" = "status"
- )
-
- radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
-
- return 1
-
-/obj/machinery/atmospherics/binary/pump/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- if(stat & (BROKEN|NOPOWER))
- return
-
- // this is the data which will be sent to the ui
- var/data[0]
-
- data = list(
- "on" = use_power,
- "pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently.
- "max_pressure" = max_pressure_setting,
- "last_flow_rate" = round(last_flow_rate*10),
- "last_power_draw" = round(last_power_draw),
- "max_power_draw" = power_rating
- )
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if (!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "gas_pump.tmpl", name, 470, 290)
- ui.set_initial_data(data) // when the ui is first opened this is the data it will use
- ui.open() // open the new ui window
- ui.set_auto_update(1) // auto update every Master Controller tick
-
-/obj/machinery/atmospherics/binary/pump/atmos_init()
- ..()
- if(frequency)
- set_frequency(frequency)
-
-/obj/machinery/atmospherics/binary/pump/receive_signal(datum/signal/signal)
- if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
- return 0
-
- if(signal.data["power"])
- if(text2num(signal.data["power"]))
- use_power = 1
- else
- use_power = 0
-
- if("power_toggle" in signal.data)
- use_power = !use_power
-
- if(signal.data["set_output_pressure"])
- target_pressure = between(
- 0,
- text2num(signal.data["set_output_pressure"]),
- ONE_ATMOSPHERE*50
- )
-
- if(signal.data["status"])
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- return //do not update_icon
-
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- update_icon()
- return
-
-/obj/machinery/atmospherics/binary/pump/attack_hand(user as mob)
- if(..())
- return
- src.add_fingerprint(usr)
- if(!src.allowed(user))
- to_chat(user, "Access denied.")
- return
- usr.set_machine(src)
- ui_interact(user)
- return
-
-/obj/machinery/atmospherics/binary/pump/Topic(href,href_list)
- if(..()) return 1
-
- if(href_list["power"])
- use_power = !use_power
-
- switch(href_list["set_press"])
- if ("min")
- target_pressure = 0
- if ("max")
- target_pressure = max_pressure_setting
- if ("set")
- var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure) as num
- src.target_pressure = between(0, new_pressure, max_pressure_setting)
-
- usr.set_machine(src)
- src.add_fingerprint(usr)
-
- src.update_icon()
-
-/obj/machinery/atmospherics/binary/pump/power_change()
- var/old_stat = stat
- ..()
- if(old_stat != stat)
- update_icon()
-
-/obj/machinery/atmospherics/binary/pump/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if (!W.iswrench() && !istype(W, /obj/item/pipewrench))
- return ..()
- if (!(stat & NOPOWER) && use_power)
- to_chat(user, "You cannot unwrench this [src], turn it off first.")
- return 1
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
- if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE && !istype(W, /obj/item/pipewrench))
- to_chat(user, "You cannot unwrench this [src], it's too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- else
- to_chat(user, "You struggle to unwrench \the [src] with your pipe wrench.")
- playsound(src.loc, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, istype(W, /obj/item/pipewrench) ? 80/W.toolspeed : 40/W.toolspeed, act_target = src))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear a ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- qdel(src)
+/*
+Every cycle, the pump uses the air in air_in to try and make air_out the perfect pressure.
+
+node1, air1, network1 correspond to input
+node2, air2, network2 correspond to output
+
+Thus, the two variables affect pump operation are set in New():
+ air1.volume
+ This is the volume of gas available to the pump that may be transfered to the output
+ air2.volume
+ Higher quantities of this cause more air to be perfected later
+ but overall network volume is also increased as this increases...
+*/
+
+/obj/machinery/atmospherics/binary/pump
+ icon = 'icons/atmos/pump.dmi'
+ icon_state = "map_off"
+ level = 1
+
+ name = "gas pump"
+ desc = "A pump"
+
+ var/target_pressure = ONE_ATMOSPHERE
+
+ //var/max_volume_transfer = 10000
+
+ use_power = 0
+ idle_power_usage = 150 //internal circuitry, friction losses and stuff
+ power_rating = 7500 //7500 W ~ 10 HP
+
+ var/max_pressure_setting = 15000 //kPa
+
+ var/frequency = 0
+ var/id = null
+ var/datum/radio_frequency/radio_connection
+
+/obj/machinery/atmospherics/binary/pump/Initialize()
+ . = ..()
+ air1.volume = ATMOS_DEFAULT_VOLUME_PUMP
+ air2.volume = ATMOS_DEFAULT_VOLUME_PUMP
+
+/obj/machinery/atmospherics/binary/pump/on
+ icon_state = "map_on"
+ use_power = 1
+
+
+/obj/machinery/atmospherics/binary/pump/update_icon()
+ if(!powered())
+ icon_state = "off"
+ else
+ icon_state = "[use_power ? "on" : "off"]"
+
+/obj/machinery/atmospherics/binary/pump/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+ add_underlay(T, node1, turn(dir, -180))
+ add_underlay(T, node2, dir)
+
+/obj/machinery/atmospherics/binary/pump/hide(var/i)
+ update_underlays()
+
+/obj/machinery/atmospherics/binary/pump/machinery_process()
+ last_power_draw = 0
+ last_flow_rate = 0
+
+ if((stat & (NOPOWER|BROKEN)) || !use_power)
+ return
+
+ var/power_draw = -1
+ var/pressure_delta = target_pressure - air2.return_pressure()
+
+ if(pressure_delta > 0.01 && air1.temperature > 0)
+ //Figure out how much gas to transfer to meet the target pressure.
+ var/transfer_moles = calculate_transfer_moles(air1, air2, pressure_delta, (network2)? network2.volume : 0)
+ power_draw = pump_gas(src, air1, air2, transfer_moles, power_rating)
+
+ if (power_draw >= 0)
+ last_power_draw = power_draw
+ use_power(power_draw)
+
+ if(network1)
+ network1.update = 1
+
+ if(network2)
+ network2.update = 1
+
+ return 1
+
+//Radio remote control
+
+/obj/machinery/atmospherics/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/binary/pump/proc/broadcast_status()
+ if(!radio_connection)
+ return 0
+
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.source = src
+
+ signal.data = list(
+ "tag" = id,
+ "device" = "AGP",
+ "power" = use_power,
+ "target_output" = target_pressure,
+ "sigtype" = "status"
+ )
+
+ radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
+
+ return 1
+
+/obj/machinery/atmospherics/binary/pump/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+ if(stat & (BROKEN|NOPOWER))
+ return
+
+ // this is the data which will be sent to the ui
+ var/data[0]
+
+ data = list(
+ "on" = use_power,
+ "pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently.
+ "max_pressure" = max_pressure_setting,
+ "last_flow_rate" = round(last_flow_rate*10),
+ "last_power_draw" = round(last_power_draw),
+ "max_power_draw" = power_rating
+ )
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if (!ui)
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
+ ui = new(user, src, ui_key, "gas_pump.tmpl", name, 470, 290)
+ ui.set_initial_data(data) // when the ui is first opened this is the data it will use
+ ui.open() // open the new ui window
+ ui.set_auto_update(1) // auto update every Master Controller tick
+
+/obj/machinery/atmospherics/binary/pump/atmos_init()
+ ..()
+ if(frequency)
+ set_frequency(frequency)
+
+/obj/machinery/atmospherics/binary/pump/receive_signal(datum/signal/signal)
+ if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
+ return 0
+
+ if(signal.data["power"])
+ if(text2num(signal.data["power"]))
+ use_power = 1
+ else
+ use_power = 0
+
+ if("power_toggle" in signal.data)
+ use_power = !use_power
+
+ if(signal.data["set_output_pressure"])
+ target_pressure = between(
+ 0,
+ text2num(signal.data["set_output_pressure"]),
+ ONE_ATMOSPHERE*50
+ )
+
+ if(signal.data["status"])
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ return //do not update_icon
+
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ update_icon()
+ return
+
+/obj/machinery/atmospherics/binary/pump/attack_hand(user as mob)
+ if(..())
+ return
+ src.add_fingerprint(usr)
+ if(!src.allowed(user))
+ to_chat(user, "Access denied.")
+ return
+ usr.set_machine(src)
+ ui_interact(user)
+ return
+
+/obj/machinery/atmospherics/binary/pump/Topic(href,href_list)
+ if(..()) return 1
+
+ if(href_list["power"])
+ use_power = !use_power
+
+ switch(href_list["set_press"])
+ if ("min")
+ target_pressure = 0
+ if ("max")
+ target_pressure = max_pressure_setting
+ if ("set")
+ var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure) as num
+ src.target_pressure = between(0, new_pressure, max_pressure_setting)
+
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+
+ src.update_icon()
+
+/obj/machinery/atmospherics/binary/pump/power_change()
+ var/old_stat = stat
+ ..()
+ if(old_stat != stat)
+ update_icon()
+
+/obj/machinery/atmospherics/binary/pump/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if (!W.iswrench() && !istype(W, /obj/item/pipewrench))
+ return ..()
+ if (!(stat & NOPOWER) && use_power)
+ to_chat(user, "You cannot unwrench this [src], turn it off first.")
+ return 1
+ var/datum/gas_mixture/int_air = return_air()
+ var/datum/gas_mixture/env_air = loc.return_air()
+ if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE && !istype(W, /obj/item/pipewrench))
+ to_chat(user, "You cannot unwrench this [src], it's too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ else
+ to_chat(user, "You struggle to unwrench \the [src] with your pipe wrench.")
+ playsound(src.loc, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, istype(W, /obj/item/pipewrench) ? 80/W.toolspeed : 40/W.toolspeed, act_target = src))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear a ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ qdel(src)
diff --git a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm
index 42b02282cc2..fff0c747c6f 100644
--- a/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm
+++ b/code/ATMOSPHERICS/components/binary_devices/volume_pump.dm
@@ -1,19 +1,19 @@
-/obj/machinery/atmospherics/binary/pump/high_power
- icon = 'icons/atmos/volume_pump.dmi'
- icon_state = "map_off"
- level = 1
-
- name = "high power gas pump"
- desc = "A pump. Has double the power rating of the standard gas pump."
-
- power_rating = 15000 //15000 W ~ 20 HP
-
-/obj/machinery/atmospherics/binary/pump/high_power/on
- use_power = 1
- icon_state = "map_on"
-
-/obj/machinery/atmospherics/binary/pump/high_power/update_icon()
- if(!powered())
- icon_state = "off"
- else
+/obj/machinery/atmospherics/binary/pump/high_power
+ icon = 'icons/atmos/volume_pump.dmi'
+ icon_state = "map_off"
+ level = 1
+
+ name = "high power gas pump"
+ desc = "A pump. Has double the power rating of the standard gas pump."
+
+ power_rating = 15000 //15000 W ~ 20 HP
+
+/obj/machinery/atmospherics/binary/pump/high_power/on
+ use_power = 1
+ icon_state = "map_on"
+
+/obj/machinery/atmospherics/binary/pump/high_power/update_icon()
+ if(!powered())
+ icon_state = "off"
+ else
icon_state = "[use_power ? "on" : "off"]"
\ No newline at end of file
diff --git a/code/ATMOSPHERICS/components/portables_connector.dm b/code/ATMOSPHERICS/components/portables_connector.dm
index b9201e5f124..8f848cc77ae 100644
--- a/code/ATMOSPHERICS/components/portables_connector.dm
+++ b/code/ATMOSPHERICS/components/portables_connector.dm
@@ -1,155 +1,155 @@
-/obj/machinery/atmospherics/portables_connector
- icon = 'icons/atmos/connector.dmi'
- icon_state = "map_connector"
-
- name = "Connector Port"
- desc = "For connecting portables devices related to atmospherics control."
-
- dir = SOUTH
- initialize_directions = SOUTH
-
- var/obj/machinery/portable_atmospherics/connected_device
-
- var/obj/machinery/atmospherics/node
-
- var/datum/pipe_network/network
-
- var/on = 0
- use_power = 0
- level = 1
-
-
-/obj/machinery/atmospherics/portables_connector/Initialize()
- initialize_directions = dir
- . = ..()
-
-/obj/machinery/atmospherics/portables_connector/update_icon()
- icon_state = "connector"
-
-/obj/machinery/atmospherics/portables_connector/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
- add_underlay(T, node, dir)
-
-/obj/machinery/atmospherics/portables_connector/hide(var/i)
- update_underlays()
-
-/obj/machinery/atmospherics/portables_connector/machinery_process()
- ..()
- if(!on)
- return
- if(!connected_device)
- on = 0
- return
- if(network)
- network.update = 1
- return 1
-
-// Housekeeping and pipe network stuff below
-/obj/machinery/atmospherics/portables_connector/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
- if(reference == node)
- network = new_network
-
- if(new_network.normal_members.Find(src))
- return 0
-
- new_network.normal_members += src
-
- return null
-
-/obj/machinery/atmospherics/portables_connector/Destroy()
- loc = null
-
- if(connected_device)
- connected_device.disconnect()
-
- if(node)
- node.disconnect(src)
- qdel(network)
-
- node = null
-
- return ..()
-
-/obj/machinery/atmospherics/portables_connector/atmos_init()
- if(node) return
-
- var/node_connect = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node = target
- break
-
- update_icon()
- update_underlays()
-
-/obj/machinery/atmospherics/portables_connector/build_network()
- if(!network && node)
- network = new /datum/pipe_network()
- network.normal_members += src
- network.build_network(node, src)
-
-
-/obj/machinery/atmospherics/portables_connector/return_network(obj/machinery/atmospherics/reference)
- build_network()
-
- if(reference==node)
- return network
-
- if(reference==connected_device)
- return network
-
- return null
-
-/obj/machinery/atmospherics/portables_connector/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
- if(network == old_network)
- network = new_network
-
- return 1
-
-/obj/machinery/atmospherics/portables_connector/return_network_air(datum/pipe_network/reference)
- var/list/results = list()
-
- if(connected_device)
- results += connected_device.air_contents
-
- return results
-
-/obj/machinery/atmospherics/portables_connector/disconnect(obj/machinery/atmospherics/reference)
- if(reference==node)
- qdel(network)
- node = null
-
- update_underlays()
-
- return null
-
-
-/obj/machinery/atmospherics/portables_connector/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if (!W.iswrench())
- return ..()
- if (connected_device)
- to_chat(user, "You cannot unwrench \the [src], dettach \the [connected_device] first.")
- return 1
- if (locate(/obj/machinery/portable_atmospherics, src.loc))
- return 1
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
- if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
- to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- playsound(src.loc, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, 40/W.toolspeed, act_target = src))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear a ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- qdel(src)
+/obj/machinery/atmospherics/portables_connector
+ icon = 'icons/atmos/connector.dmi'
+ icon_state = "map_connector"
+
+ name = "Connector Port"
+ desc = "For connecting portables devices related to atmospherics control."
+
+ dir = SOUTH
+ initialize_directions = SOUTH
+
+ var/obj/machinery/portable_atmospherics/connected_device
+
+ var/obj/machinery/atmospherics/node
+
+ var/datum/pipe_network/network
+
+ var/on = 0
+ use_power = 0
+ level = 1
+
+
+/obj/machinery/atmospherics/portables_connector/Initialize()
+ initialize_directions = dir
+ . = ..()
+
+/obj/machinery/atmospherics/portables_connector/update_icon()
+ icon_state = "connector"
+
+/obj/machinery/atmospherics/portables_connector/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+ add_underlay(T, node, dir)
+
+/obj/machinery/atmospherics/portables_connector/hide(var/i)
+ update_underlays()
+
+/obj/machinery/atmospherics/portables_connector/machinery_process()
+ ..()
+ if(!on)
+ return
+ if(!connected_device)
+ on = 0
+ return
+ if(network)
+ network.update = 1
+ return 1
+
+// Housekeeping and pipe network stuff below
+/obj/machinery/atmospherics/portables_connector/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+ if(reference == node)
+ network = new_network
+
+ if(new_network.normal_members.Find(src))
+ return 0
+
+ new_network.normal_members += src
+
+ return null
+
+/obj/machinery/atmospherics/portables_connector/Destroy()
+ loc = null
+
+ if(connected_device)
+ connected_device.disconnect()
+
+ if(node)
+ node.disconnect(src)
+ qdel(network)
+
+ node = null
+
+ return ..()
+
+/obj/machinery/atmospherics/portables_connector/atmos_init()
+ if(node) return
+
+ var/node_connect = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node = target
+ break
+
+ update_icon()
+ update_underlays()
+
+/obj/machinery/atmospherics/portables_connector/build_network()
+ if(!network && node)
+ network = new /datum/pipe_network()
+ network.normal_members += src
+ network.build_network(node, src)
+
+
+/obj/machinery/atmospherics/portables_connector/return_network(obj/machinery/atmospherics/reference)
+ build_network()
+
+ if(reference==node)
+ return network
+
+ if(reference==connected_device)
+ return network
+
+ return null
+
+/obj/machinery/atmospherics/portables_connector/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
+ if(network == old_network)
+ network = new_network
+
+ return 1
+
+/obj/machinery/atmospherics/portables_connector/return_network_air(datum/pipe_network/reference)
+ var/list/results = list()
+
+ if(connected_device)
+ results += connected_device.air_contents
+
+ return results
+
+/obj/machinery/atmospherics/portables_connector/disconnect(obj/machinery/atmospherics/reference)
+ if(reference==node)
+ qdel(network)
+ node = null
+
+ update_underlays()
+
+ return null
+
+
+/obj/machinery/atmospherics/portables_connector/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if (!W.iswrench())
+ return ..()
+ if (connected_device)
+ to_chat(user, "You cannot unwrench \the [src], dettach \the [connected_device] first.")
+ return 1
+ if (locate(/obj/machinery/portable_atmospherics, src.loc))
+ return 1
+ var/datum/gas_mixture/int_air = return_air()
+ var/datum/gas_mixture/env_air = loc.return_air()
+ if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
+ to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ playsound(src.loc, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, 40/W.toolspeed, act_target = src))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear a ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ qdel(src)
diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm
index 2e91df67ada..df1abd0d212 100755
--- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm
@@ -1,277 +1,277 @@
-/obj/machinery/atmospherics/trinary/filter
- icon = 'icons/atmos/filter.dmi'
- icon_state = "map"
- density = 0
- level = 1
-
- name = "Gas filter"
-
- use_power = 1
- idle_power_usage = 150 //internal circuitry, friction losses and stuff
- power_rating = 7500 //This also doubles as a measure of how powerful the filter is, in Watts. 7500 W ~ 10 HP
-
- var/temp = null // -- TLE
-
- var/set_flow_rate = ATMOS_DEFAULT_VOLUME_FILTER
-
- /*
- Filter types:
- -1: Nothing
- 0: Phoron: Phoron, Oxygen Agent B
- 1: Oxygen: Oxygen ONLY
- 2: Nitrogen: Nitrogen ONLY
- 3: Carbon Dioxide: Carbon Dioxide ONLY
- 4: Sleeping Agent (N2O)
- */
- var/filter_type = -1
- var/list/filtered_out = list()
-
-
- var/frequency = 0
- var/datum/radio_frequency/radio_connection
-
-/obj/machinery/atmospherics/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/trinary/filter/Initialize()
- . = ..()
- switch(filter_type)
- if(0) //removing hydrocarbons
- filtered_out = list("phoron")
- if(1) //removing O2
- filtered_out = list("oxygen")
- if(2) //removing N2
- filtered_out = list("nitrogen")
- if(3) //removing CO2
- filtered_out = list("carbon_dioxide")
- if(4)//removing N2O
- filtered_out = list("sleeping_agent")
-
- air1.volume = ATMOS_DEFAULT_VOLUME_FILTER
- air2.volume = ATMOS_DEFAULT_VOLUME_FILTER
- air3.volume = ATMOS_DEFAULT_VOLUME_FILTER
-
-/obj/machinery/atmospherics/trinary/filter/update_icon()
- if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter))
- icon_state = "m"
- else
- icon_state = ""
-
- if(!powered())
- icon_state += "off"
- else if(node2 && node3 && node1)
- icon_state += use_power ? "on" : "off"
- else
- icon_state += "off"
- use_power = 0
-
-/obj/machinery/atmospherics/trinary/filter/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
-
- add_underlay(T, node1, turn(dir, -180))
-
- if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter))
- add_underlay(T, node2, turn(dir, 90))
- else
- add_underlay(T, node2, turn(dir, -90))
-
- add_underlay(T, node3, dir)
-
-/obj/machinery/atmospherics/trinary/filter/hide(var/i)
- update_underlays()
-
-/obj/machinery/atmospherics/trinary/filter/power_change()
- var/old_stat = stat
- ..()
- if(old_stat != stat)
- update_icon()
-
-/obj/machinery/atmospherics/trinary/filter/machinery_process()
- ..()
-
- last_power_draw = 0
- last_flow_rate = 0
-
- if((stat & (NOPOWER|BROKEN)) || !use_power)
- return
-
- //Figure out the amount of moles to transfer
- var/transfer_moles = (set_flow_rate/air1.volume)*air1.total_moles
-
- var/power_draw = -1
- if (transfer_moles > MINIMUM_MOLES_TO_FILTER)
- power_draw = filter_gas(src, filtered_out, air1, air2, air3, transfer_moles, power_rating)
-
- if(network2)
- network2.update = 1
-
- if(network3)
- network3.update = 1
-
- if(network1)
- network1.update = 1
-
- if (power_draw >= 0)
- last_power_draw = power_draw
- use_power(power_draw)
-
- return 1
-
-/obj/machinery/atmospherics/trinary/filter/atmos_init()
- set_frequency(frequency)
- ..()
-
-/obj/machinery/atmospherics/trinary/filter/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if (!W.iswrench())
- return ..()
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
- if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
- to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- playsound(src.loc, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, 40/W.toolspeed, act_target = src))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear a ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- qdel(src)
-
-
-/obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE
- if(..())
- return
-
- if(!src.allowed(user))
- to_chat(user, "Access denied.")
- return
-
- var/dat
- var/current_filter_type
- switch(filter_type)
- if(0)
- current_filter_type = "Phoron"
- if(1)
- current_filter_type = "Oxygen"
- if(2)
- current_filter_type = "Nitrogen"
- if(3)
- current_filter_type = "Carbon Dioxide"
- if(4)
- current_filter_type = "Nitrous Oxide"
- if(-1)
- current_filter_type = "Nothing"
- else
- current_filter_type = "ERROR - Report this bug to the admin, please!"
-
- dat += {"
- Power: [use_power?"On":"Off"]
- Filtering: [current_filter_type]
- Set Filter Type:
- Phoron
- Oxygen
- Nitrogen
- Carbon Dioxide
- Nitrous Oxide
- Nothing
-
- Set Flow Rate Limit:
- [src.set_flow_rate]L/s | Change
- Flow rate: [round(last_flow_rate, 0.1)]L/s
- "}
-
- user << browse("[src.name] control[dat]", "window=atmo_filter")
- onclose(user, "atmo_filter")
- return
-
-/obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE
- if(..())
- return 1
- usr.set_machine(src)
- src.add_fingerprint(usr)
- if(href_list["filterset"])
- filter_type = text2num(href_list["filterset"])
-
- filtered_out.Cut() //no need to create new lists unnecessarily
- switch(filter_type)
- if(0) //removing hydrocarbons
- filtered_out += "phoron"
- if(1) //removing O2
- filtered_out += "oxygen"
- if(2) //removing N2
- filtered_out += "nitrogen"
- if(3) //removing CO2
- filtered_out += "carbon_dioxide"
- if(4)//removing N2O
- filtered_out += "sleeping_agent"
-
- if (href_list["temp"])
- src.temp = null
- if(href_list["set_flow_rate"])
- var/new_flow_rate = input(usr,"Enter new flow rate (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate) as num
- src.set_flow_rate = max(0, min(air1.volume, new_flow_rate))
- if(href_list["power"])
- use_power=!use_power
- src.update_icon()
- src.updateUsrDialog()
-/*
- for(var/mob/M in viewers(1, src))
- if ((M.client && M.machine == src))
- src.attack_hand(M)
-*/
- return
-
-/obj/machinery/atmospherics/trinary/filter/m_filter
- icon_state = "mmap"
-
- dir = SOUTH
- initialize_directions = SOUTH|NORTH|EAST
-
-obj/machinery/atmospherics/trinary/filter/m_filter/Initialize()
- switch(dir)
- if(NORTH)
- initialize_directions = WEST|NORTH|SOUTH
- if(SOUTH)
- initialize_directions = SOUTH|EAST|NORTH
- if(EAST)
- initialize_directions = EAST|WEST|NORTH
- if(WEST)
- initialize_directions = WEST|SOUTH|EAST
- . = ..()
-
-/obj/machinery/atmospherics/trinary/filter/m_filter/atmos_init()
- set_frequency(frequency)
-
- if(node1 && node2 && node3) return
-
- var/node1_connect = turn(dir, -180)
- var/node2_connect = turn(dir, 90)
- var/node3_connect = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
- if(target.initialize_directions & get_dir(target,src))
- node1 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
- if(target.initialize_directions & get_dir(target,src))
- node2 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
- if(target.initialize_directions & get_dir(target,src))
- node3 = target
- break
-
- update_icon()
- update_underlays()
+/obj/machinery/atmospherics/trinary/filter
+ icon = 'icons/atmos/filter.dmi'
+ icon_state = "map"
+ density = 0
+ level = 1
+
+ name = "Gas filter"
+
+ use_power = 1
+ idle_power_usage = 150 //internal circuitry, friction losses and stuff
+ power_rating = 7500 //This also doubles as a measure of how powerful the filter is, in Watts. 7500 W ~ 10 HP
+
+ var/temp = null // -- TLE
+
+ var/set_flow_rate = ATMOS_DEFAULT_VOLUME_FILTER
+
+ /*
+ Filter types:
+ -1: Nothing
+ 0: Phoron: Phoron, Oxygen Agent B
+ 1: Oxygen: Oxygen ONLY
+ 2: Nitrogen: Nitrogen ONLY
+ 3: Carbon Dioxide: Carbon Dioxide ONLY
+ 4: Sleeping Agent (N2O)
+ */
+ var/filter_type = -1
+ var/list/filtered_out = list()
+
+
+ var/frequency = 0
+ var/datum/radio_frequency/radio_connection
+
+/obj/machinery/atmospherics/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/trinary/filter/Initialize()
+ . = ..()
+ switch(filter_type)
+ if(0) //removing hydrocarbons
+ filtered_out = list("phoron")
+ if(1) //removing O2
+ filtered_out = list("oxygen")
+ if(2) //removing N2
+ filtered_out = list("nitrogen")
+ if(3) //removing CO2
+ filtered_out = list("carbon_dioxide")
+ if(4)//removing N2O
+ filtered_out = list("sleeping_agent")
+
+ air1.volume = ATMOS_DEFAULT_VOLUME_FILTER
+ air2.volume = ATMOS_DEFAULT_VOLUME_FILTER
+ air3.volume = ATMOS_DEFAULT_VOLUME_FILTER
+
+/obj/machinery/atmospherics/trinary/filter/update_icon()
+ if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter))
+ icon_state = "m"
+ else
+ icon_state = ""
+
+ if(!powered())
+ icon_state += "off"
+ else if(node2 && node3 && node1)
+ icon_state += use_power ? "on" : "off"
+ else
+ icon_state += "off"
+ use_power = 0
+
+/obj/machinery/atmospherics/trinary/filter/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+
+ add_underlay(T, node1, turn(dir, -180))
+
+ if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter))
+ add_underlay(T, node2, turn(dir, 90))
+ else
+ add_underlay(T, node2, turn(dir, -90))
+
+ add_underlay(T, node3, dir)
+
+/obj/machinery/atmospherics/trinary/filter/hide(var/i)
+ update_underlays()
+
+/obj/machinery/atmospherics/trinary/filter/power_change()
+ var/old_stat = stat
+ ..()
+ if(old_stat != stat)
+ update_icon()
+
+/obj/machinery/atmospherics/trinary/filter/machinery_process()
+ ..()
+
+ last_power_draw = 0
+ last_flow_rate = 0
+
+ if((stat & (NOPOWER|BROKEN)) || !use_power)
+ return
+
+ //Figure out the amount of moles to transfer
+ var/transfer_moles = (set_flow_rate/air1.volume)*air1.total_moles
+
+ var/power_draw = -1
+ if (transfer_moles > MINIMUM_MOLES_TO_FILTER)
+ power_draw = filter_gas(src, filtered_out, air1, air2, air3, transfer_moles, power_rating)
+
+ if(network2)
+ network2.update = 1
+
+ if(network3)
+ network3.update = 1
+
+ if(network1)
+ network1.update = 1
+
+ if (power_draw >= 0)
+ last_power_draw = power_draw
+ use_power(power_draw)
+
+ return 1
+
+/obj/machinery/atmospherics/trinary/filter/atmos_init()
+ set_frequency(frequency)
+ ..()
+
+/obj/machinery/atmospherics/trinary/filter/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if (!W.iswrench())
+ return ..()
+ var/datum/gas_mixture/int_air = return_air()
+ var/datum/gas_mixture/env_air = loc.return_air()
+ if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
+ to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ playsound(src.loc, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, 40/W.toolspeed, act_target = src))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear a ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ qdel(src)
+
+
+/obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE
+ if(..())
+ return
+
+ if(!src.allowed(user))
+ to_chat(user, "Access denied.")
+ return
+
+ var/dat
+ var/current_filter_type
+ switch(filter_type)
+ if(0)
+ current_filter_type = "Phoron"
+ if(1)
+ current_filter_type = "Oxygen"
+ if(2)
+ current_filter_type = "Nitrogen"
+ if(3)
+ current_filter_type = "Carbon Dioxide"
+ if(4)
+ current_filter_type = "Nitrous Oxide"
+ if(-1)
+ current_filter_type = "Nothing"
+ else
+ current_filter_type = "ERROR - Report this bug to the admin, please!"
+
+ dat += {"
+ Power: [use_power?"On":"Off"]
+ Filtering: [current_filter_type]
+ Set Filter Type:
+ Phoron
+ Oxygen
+ Nitrogen
+ Carbon Dioxide
+ Nitrous Oxide
+ Nothing
+
+ Set Flow Rate Limit:
+ [src.set_flow_rate]L/s | Change
+ Flow rate: [round(last_flow_rate, 0.1)]L/s
+ "}
+
+ user << browse("[src.name] control[dat]", "window=atmo_filter")
+ onclose(user, "atmo_filter")
+ return
+
+/obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE
+ if(..())
+ return 1
+ usr.set_machine(src)
+ src.add_fingerprint(usr)
+ if(href_list["filterset"])
+ filter_type = text2num(href_list["filterset"])
+
+ filtered_out.Cut() //no need to create new lists unnecessarily
+ switch(filter_type)
+ if(0) //removing hydrocarbons
+ filtered_out += "phoron"
+ if(1) //removing O2
+ filtered_out += "oxygen"
+ if(2) //removing N2
+ filtered_out += "nitrogen"
+ if(3) //removing CO2
+ filtered_out += "carbon_dioxide"
+ if(4)//removing N2O
+ filtered_out += "sleeping_agent"
+
+ if (href_list["temp"])
+ src.temp = null
+ if(href_list["set_flow_rate"])
+ var/new_flow_rate = input(usr,"Enter new flow rate (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate) as num
+ src.set_flow_rate = max(0, min(air1.volume, new_flow_rate))
+ if(href_list["power"])
+ use_power=!use_power
+ src.update_icon()
+ src.updateUsrDialog()
+/*
+ for(var/mob/M in viewers(1, src))
+ if ((M.client && M.machine == src))
+ src.attack_hand(M)
+*/
+ return
+
+/obj/machinery/atmospherics/trinary/filter/m_filter
+ icon_state = "mmap"
+
+ dir = SOUTH
+ initialize_directions = SOUTH|NORTH|EAST
+
+obj/machinery/atmospherics/trinary/filter/m_filter/Initialize()
+ switch(dir)
+ if(NORTH)
+ initialize_directions = WEST|NORTH|SOUTH
+ if(SOUTH)
+ initialize_directions = SOUTH|EAST|NORTH
+ if(EAST)
+ initialize_directions = EAST|WEST|NORTH
+ if(WEST)
+ initialize_directions = WEST|SOUTH|EAST
+ . = ..()
+
+/obj/machinery/atmospherics/trinary/filter/m_filter/atmos_init()
+ set_frequency(frequency)
+
+ if(node1 && node2 && node3) return
+
+ var/node1_connect = turn(dir, -180)
+ var/node2_connect = turn(dir, 90)
+ var/node3_connect = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ node1 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ node2 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ node3 = target
+ break
+
+ update_icon()
+ update_underlays()
diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
index 095ae90763f..350eb8a0a05 100644
--- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm
@@ -1,276 +1,276 @@
-/obj/machinery/atmospherics/trinary/mixer
- icon = 'icons/atmos/mixer.dmi'
- icon_state = "map"
- density = 0
- level = 1
-
- name = "Gas mixer"
-
- use_power = 1
- idle_power_usage = 150 //internal circuitry, friction losses and stuff
- power_rating = 3700 //This also doubles as a measure of how powerful the mixer is, in Watts. 3700 W ~ 5 HP
-
- var/set_flow_rate = ATMOS_DEFAULT_VOLUME_MIXER
- var/list/mixing_inputs
-
- //for mapping
- var/node1_concentration = 0.5
- var/node2_concentration = 0.5
-
- //node 3 is the outlet, nodes 1 & 2 are intakes
-
-/obj/machinery/atmospherics/trinary/mixer/update_icon(var/safety = 0)
- if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer))
- icon_state = "m"
- else if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
- icon_state = "t"
- else
- icon_state = ""
-
- if(!powered())
- icon_state += "off"
- else if(node2 && node3 && node1)
- icon_state += use_power ? "on" : "off"
- else
- icon_state += "off"
- use_power = 0
-
-/obj/machinery/atmospherics/trinary/mixer/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
-
- if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
- add_underlay(T, node1, turn(dir, -90))
- else
- add_underlay(T, node1, turn(dir, -180))
-
- if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer) || istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
- add_underlay(T, node2, turn(dir, 90))
- else
- add_underlay(T, node2, turn(dir, -90))
-
- add_underlay(T, node3, dir)
-
-/obj/machinery/atmospherics/trinary/mixer/hide(var/i)
- update_underlays()
-
-/obj/machinery/atmospherics/trinary/mixer/power_change()
- var/old_stat = stat
- ..()
- if(old_stat != stat)
- update_icon()
-
-/obj/machinery/atmospherics/trinary/mixer/Initialize()
- . = ..()
- air1.volume = ATMOS_DEFAULT_VOLUME_MIXER
- air2.volume = ATMOS_DEFAULT_VOLUME_MIXER
- air3.volume = ATMOS_DEFAULT_VOLUME_MIXER * 1.5
-
- if (!mixing_inputs)
- mixing_inputs = list(src.air1 = node1_concentration, src.air2 = node2_concentration)
-
-/obj/machinery/atmospherics/trinary/mixer/machinery_process()
- ..()
-
- last_power_draw = 0
- last_flow_rate = 0
-
- if((stat & (NOPOWER|BROKEN)) || !use_power)
- return
-
- //Figure out the amount of moles to transfer
- var/transfer_moles = (set_flow_rate*mixing_inputs[air1]/air1.volume)*air1.total_moles + (set_flow_rate*mixing_inputs[air1]/air2.volume)*air2.total_moles
-
- var/power_draw = -1
- if (transfer_moles > MINIMUM_MOLES_TO_FILTER)
- power_draw = mix_gas(src, mixing_inputs, air3, transfer_moles, power_rating)
-
- if(network1 && mixing_inputs[air1])
- network1.update = 1
-
- if(network2 && mixing_inputs[air2])
- network2.update = 1
-
- if(network3)
- network3.update = 1
-
- if (power_draw >= 0)
- last_power_draw = power_draw
- use_power(power_draw)
-
- return 1
-
-/obj/machinery/atmospherics/trinary/mixer/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if (!W.iswrench())
- return ..()
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
- if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
- to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- playsound(src.loc, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, 40/W.toolspeed, act_target = src))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- qdel(src)
-
-/obj/machinery/atmospherics/trinary/mixer/attack_hand(user as mob)
- if(..())
- return
- src.add_fingerprint(usr)
- if(!src.allowed(user))
- to_chat(user, "Access denied.")
- return
- usr.set_machine(src)
- var/dat = {"Power: [use_power?"On":"Off"]
- Set Flow Rate Limit:
- [set_flow_rate]L/s | Change
-
- Flow Rate: [round(last_flow_rate, 0.1)]L/s
-
- Node 1 Concentration:
- -
- -
- [mixing_inputs[air1]]([mixing_inputs[air1]*100]%)
- +
- +
-
- Node 2 Concentration:
- -
- -
- [mixing_inputs[air2]]([mixing_inputs[air2]*100]%)
- +
- +
- "}
-
- user << browse("[src.name] control[dat]", "window=atmo_mixer")
- onclose(user, "atmo_mixer")
- return
-
-/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list)
- if(..()) return 1
- if(href_list["power"])
- use_power = !use_power
- if(href_list["set_press"])
- var/max_flow_rate = min(air1.volume, air2.volume)
- var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",src.set_flow_rate) as num
- src.set_flow_rate = max(0, min(max_flow_rate, new_flow_rate))
- if(href_list["node1_c"])
- var/value = text2num(href_list["node1_c"])
- src.mixing_inputs[air1] = max(0, min(1, src.mixing_inputs[air1] + value))
- src.mixing_inputs[air2] = 1.0 - mixing_inputs[air1]
- if(href_list["node2_c"])
- var/value = text2num(href_list["node2_c"])
- src.mixing_inputs[air2] = max(0, min(1, src.mixing_inputs[air2] + value))
- src.mixing_inputs[air1] = 1.0 - mixing_inputs[air2]
- src.update_icon()
- src.updateUsrDialog()
- return
-
-obj/machinery/atmospherics/trinary/mixer/t_mixer
- icon_state = "tmap"
-
- dir = SOUTH
- initialize_directions = SOUTH|EAST|WEST
-
- //node 3 is the outlet, nodes 1 & 2 are intakes
-
-obj/machinery/atmospherics/trinary/mixer/t_mixer/north
- icon_state = "tmap"
-
- dir = NORTH
- initialize_directions = NORTH|EAST|WEST
-
- //node 3 is the outlet, nodes 1 & 2 are intakes
-
-obj/machinery/atmospherics/trinary/mixer/t_mixer/Initialize()
- switch(dir)
- if(NORTH)
- initialize_directions = EAST|NORTH|WEST
- if(SOUTH)
- initialize_directions = SOUTH|WEST|EAST
- if(EAST)
- initialize_directions = EAST|NORTH|SOUTH
- if(WEST)
- initialize_directions = WEST|NORTH|SOUTH
- . = ..()
-
-obj/machinery/atmospherics/trinary/mixer/t_mixer/atmos_init()
- ..()
- if(node1 && node2 && node3) return
-
- var/node1_connect = turn(dir, -90)
- var/node2_connect = turn(dir, 90)
- var/node3_connect = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
- if(target.initialize_directions & get_dir(target,src))
- node1 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
- if(target.initialize_directions & get_dir(target,src))
- node2 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
- if(target.initialize_directions & get_dir(target,src))
- node3 = target
- break
-
- update_icon()
- update_underlays()
-
-obj/machinery/atmospherics/trinary/mixer/m_mixer
- icon_state = "mmap"
-
- dir = SOUTH
- initialize_directions = SOUTH|NORTH|EAST
-
- //node 3 is the outlet, nodes 1 & 2 are intakes
-
-obj/machinery/atmospherics/trinary/mixer/m_mixer/Initialize()
- switch(dir)
- if(NORTH)
- initialize_directions = WEST|NORTH|SOUTH
- if(SOUTH)
- initialize_directions = SOUTH|EAST|NORTH
- if(EAST)
- initialize_directions = EAST|WEST|NORTH
- if(WEST)
- initialize_directions = WEST|SOUTH|EAST
- . = ..()
-
-obj/machinery/atmospherics/trinary/mixer/m_mixer/atmos_init()
- ..()
- if(node1 && node2 && node3) return
-
- var/node1_connect = turn(dir, -180)
- var/node2_connect = turn(dir, 90)
- var/node3_connect = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
- if(target.initialize_directions & get_dir(target,src))
- node1 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
- if(target.initialize_directions & get_dir(target,src))
- node2 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
- if(target.initialize_directions & get_dir(target,src))
- node3 = target
- break
-
- update_icon()
- update_underlays()
+/obj/machinery/atmospherics/trinary/mixer
+ icon = 'icons/atmos/mixer.dmi'
+ icon_state = "map"
+ density = 0
+ level = 1
+
+ name = "Gas mixer"
+
+ use_power = 1
+ idle_power_usage = 150 //internal circuitry, friction losses and stuff
+ power_rating = 3700 //This also doubles as a measure of how powerful the mixer is, in Watts. 3700 W ~ 5 HP
+
+ var/set_flow_rate = ATMOS_DEFAULT_VOLUME_MIXER
+ var/list/mixing_inputs
+
+ //for mapping
+ var/node1_concentration = 0.5
+ var/node2_concentration = 0.5
+
+ //node 3 is the outlet, nodes 1 & 2 are intakes
+
+/obj/machinery/atmospherics/trinary/mixer/update_icon(var/safety = 0)
+ if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer))
+ icon_state = "m"
+ else if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
+ icon_state = "t"
+ else
+ icon_state = ""
+
+ if(!powered())
+ icon_state += "off"
+ else if(node2 && node3 && node1)
+ icon_state += use_power ? "on" : "off"
+ else
+ icon_state += "off"
+ use_power = 0
+
+/obj/machinery/atmospherics/trinary/mixer/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+
+ if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
+ add_underlay(T, node1, turn(dir, -90))
+ else
+ add_underlay(T, node1, turn(dir, -180))
+
+ if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer) || istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
+ add_underlay(T, node2, turn(dir, 90))
+ else
+ add_underlay(T, node2, turn(dir, -90))
+
+ add_underlay(T, node3, dir)
+
+/obj/machinery/atmospherics/trinary/mixer/hide(var/i)
+ update_underlays()
+
+/obj/machinery/atmospherics/trinary/mixer/power_change()
+ var/old_stat = stat
+ ..()
+ if(old_stat != stat)
+ update_icon()
+
+/obj/machinery/atmospherics/trinary/mixer/Initialize()
+ . = ..()
+ air1.volume = ATMOS_DEFAULT_VOLUME_MIXER
+ air2.volume = ATMOS_DEFAULT_VOLUME_MIXER
+ air3.volume = ATMOS_DEFAULT_VOLUME_MIXER * 1.5
+
+ if (!mixing_inputs)
+ mixing_inputs = list(src.air1 = node1_concentration, src.air2 = node2_concentration)
+
+/obj/machinery/atmospherics/trinary/mixer/machinery_process()
+ ..()
+
+ last_power_draw = 0
+ last_flow_rate = 0
+
+ if((stat & (NOPOWER|BROKEN)) || !use_power)
+ return
+
+ //Figure out the amount of moles to transfer
+ var/transfer_moles = (set_flow_rate*mixing_inputs[air1]/air1.volume)*air1.total_moles + (set_flow_rate*mixing_inputs[air1]/air2.volume)*air2.total_moles
+
+ var/power_draw = -1
+ if (transfer_moles > MINIMUM_MOLES_TO_FILTER)
+ power_draw = mix_gas(src, mixing_inputs, air3, transfer_moles, power_rating)
+
+ if(network1 && mixing_inputs[air1])
+ network1.update = 1
+
+ if(network2 && mixing_inputs[air2])
+ network2.update = 1
+
+ if(network3)
+ network3.update = 1
+
+ if (power_draw >= 0)
+ last_power_draw = power_draw
+ use_power(power_draw)
+
+ return 1
+
+/obj/machinery/atmospherics/trinary/mixer/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if (!W.iswrench())
+ return ..()
+ var/datum/gas_mixture/int_air = return_air()
+ var/datum/gas_mixture/env_air = loc.return_air()
+ if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
+ to_chat(user, "You cannot unwrench \the [src], it too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ playsound(src.loc, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, 40/W.toolspeed, act_target = src))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ qdel(src)
+
+/obj/machinery/atmospherics/trinary/mixer/attack_hand(user as mob)
+ if(..())
+ return
+ src.add_fingerprint(usr)
+ if(!src.allowed(user))
+ to_chat(user, "Access denied.")
+ return
+ usr.set_machine(src)
+ var/dat = {"Power: [use_power?"On":"Off"]
+ Set Flow Rate Limit:
+ [set_flow_rate]L/s | Change
+
+ Flow Rate: [round(last_flow_rate, 0.1)]L/s
+
+ Node 1 Concentration:
+ -
+ -
+ [mixing_inputs[air1]]([mixing_inputs[air1]*100]%)
+ +
+ +
+
+ Node 2 Concentration:
+ -
+ -
+ [mixing_inputs[air2]]([mixing_inputs[air2]*100]%)
+ +
+ +
+ "}
+
+ user << browse("[src.name] control[dat]", "window=atmo_mixer")
+ onclose(user, "atmo_mixer")
+ return
+
+/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list)
+ if(..()) return 1
+ if(href_list["power"])
+ use_power = !use_power
+ if(href_list["set_press"])
+ var/max_flow_rate = min(air1.volume, air2.volume)
+ var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",src.set_flow_rate) as num
+ src.set_flow_rate = max(0, min(max_flow_rate, new_flow_rate))
+ if(href_list["node1_c"])
+ var/value = text2num(href_list["node1_c"])
+ src.mixing_inputs[air1] = max(0, min(1, src.mixing_inputs[air1] + value))
+ src.mixing_inputs[air2] = 1.0 - mixing_inputs[air1]
+ if(href_list["node2_c"])
+ var/value = text2num(href_list["node2_c"])
+ src.mixing_inputs[air2] = max(0, min(1, src.mixing_inputs[air2] + value))
+ src.mixing_inputs[air1] = 1.0 - mixing_inputs[air2]
+ src.update_icon()
+ src.updateUsrDialog()
+ return
+
+obj/machinery/atmospherics/trinary/mixer/t_mixer
+ icon_state = "tmap"
+
+ dir = SOUTH
+ initialize_directions = SOUTH|EAST|WEST
+
+ //node 3 is the outlet, nodes 1 & 2 are intakes
+
+obj/machinery/atmospherics/trinary/mixer/t_mixer/north
+ icon_state = "tmap"
+
+ dir = NORTH
+ initialize_directions = NORTH|EAST|WEST
+
+ //node 3 is the outlet, nodes 1 & 2 are intakes
+
+obj/machinery/atmospherics/trinary/mixer/t_mixer/Initialize()
+ switch(dir)
+ if(NORTH)
+ initialize_directions = EAST|NORTH|WEST
+ if(SOUTH)
+ initialize_directions = SOUTH|WEST|EAST
+ if(EAST)
+ initialize_directions = EAST|NORTH|SOUTH
+ if(WEST)
+ initialize_directions = WEST|NORTH|SOUTH
+ . = ..()
+
+obj/machinery/atmospherics/trinary/mixer/t_mixer/atmos_init()
+ ..()
+ if(node1 && node2 && node3) return
+
+ var/node1_connect = turn(dir, -90)
+ var/node2_connect = turn(dir, 90)
+ var/node3_connect = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ node1 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ node2 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ node3 = target
+ break
+
+ update_icon()
+ update_underlays()
+
+obj/machinery/atmospherics/trinary/mixer/m_mixer
+ icon_state = "mmap"
+
+ dir = SOUTH
+ initialize_directions = SOUTH|NORTH|EAST
+
+ //node 3 is the outlet, nodes 1 & 2 are intakes
+
+obj/machinery/atmospherics/trinary/mixer/m_mixer/Initialize()
+ switch(dir)
+ if(NORTH)
+ initialize_directions = WEST|NORTH|SOUTH
+ if(SOUTH)
+ initialize_directions = SOUTH|EAST|NORTH
+ if(EAST)
+ initialize_directions = EAST|WEST|NORTH
+ if(WEST)
+ initialize_directions = WEST|SOUTH|EAST
+ . = ..()
+
+obj/machinery/atmospherics/trinary/mixer/m_mixer/atmos_init()
+ ..()
+ if(node1 && node2 && node3) return
+
+ var/node1_connect = turn(dir, -180)
+ var/node2_connect = turn(dir, 90)
+ var/node3_connect = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ node1 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ node2 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ node3 = target
+ break
+
+ update_icon()
+ update_underlays()
diff --git a/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm b/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm
index 4559adc7054..d3a3d93ed6d 100644
--- a/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm
+++ b/code/ATMOSPHERICS/components/trinary_devices/trinary_base.dm
@@ -1,169 +1,169 @@
-obj/machinery/atmospherics/trinary
- dir = SOUTH
- initialize_directions = SOUTH|NORTH|WEST
- use_power = 0
-
- var/datum/gas_mixture/air1
- var/datum/gas_mixture/air2
- var/datum/gas_mixture/air3
-
- var/obj/machinery/atmospherics/node3
-
- var/datum/pipe_network/network1
- var/datum/pipe_network/network2
- var/datum/pipe_network/network3
-
- Initialize()
- switch(dir)
- if(NORTH)
- initialize_directions = EAST|NORTH|SOUTH
- if(SOUTH)
- initialize_directions = SOUTH|WEST|NORTH
- if(EAST)
- initialize_directions = EAST|WEST|SOUTH
- if(WEST)
- initialize_directions = WEST|NORTH|EAST
- air1 = new
- air2 = new
- air3 = new
-
- air1.volume = 200
- air2.volume = 200
- air3.volume = 200
- . = ..()
-
-// Housekeeping and pipe network stuff below
- network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
- if(reference == node1)
- network1 = new_network
-
- else if(reference == node2)
- network2 = new_network
-
- else if (reference == node3)
- network3 = new_network
-
- if(new_network.normal_members.Find(src))
- return 0
-
- new_network.normal_members += src
-
- return null
-
- Destroy()
- QDEL_NULL(air1)
- QDEL_NULL(air2)
- QDEL_NULL(air3)
-
- if(node1)
- node1.disconnect(src)
- QDEL_NULL(network1)
- if(node2)
- node2.disconnect(src)
- QDEL_NULL(network2)
- if(node3)
- node3.disconnect(src)
- QDEL_NULL(network3)
-
- node1 = null
- node2 = null
- node3 = null
-
- return ..()
-
- atmos_init()
- if(node1 && node2 && node3) return
-
- var/node1_connect = turn(dir, -180)
- var/node2_connect = turn(dir, -90)
- var/node3_connect = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node2 = target
- break
- for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node3 = target
- break
-
- update_icon()
- update_underlays()
-
- build_network()
- if(!network1 && node1)
- network1 = new /datum/pipe_network()
- network1.normal_members += src
- network1.build_network(node1, src)
-
- if(!network2 && node2)
- network2 = new /datum/pipe_network()
- network2.normal_members += src
- network2.build_network(node2, src)
-
- if(!network3 && node3)
- network3 = new /datum/pipe_network()
- network3.normal_members += src
- network3.build_network(node3, src)
-
-
- return_network(obj/machinery/atmospherics/reference)
- build_network()
-
- if(reference==node1)
- return network1
-
- if(reference==node2)
- return network2
-
- if(reference==node3)
- return network3
-
- return null
-
- reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
- if(network1 == old_network)
- network1 = new_network
- if(network2 == old_network)
- network2 = new_network
- if(network3 == old_network)
- network3 = new_network
-
- return 1
-
- return_network_air(datum/pipe_network/reference)
- var/list/results = list()
-
- if(network1 == reference)
- results += air1
- if(network2 == reference)
- results += air2
- if(network3 == reference)
- results += air3
-
- return results
-
- disconnect(obj/machinery/atmospherics/reference)
- if(reference==node1)
- qdel(network1)
- node1 = null
-
- else if(reference==node2)
- qdel(network2)
- node2 = null
-
- else if(reference==node3)
- qdel(network3)
- node3 = null
-
- update_underlays()
-
- return null
+obj/machinery/atmospherics/trinary
+ dir = SOUTH
+ initialize_directions = SOUTH|NORTH|WEST
+ use_power = 0
+
+ var/datum/gas_mixture/air1
+ var/datum/gas_mixture/air2
+ var/datum/gas_mixture/air3
+
+ var/obj/machinery/atmospherics/node3
+
+ var/datum/pipe_network/network1
+ var/datum/pipe_network/network2
+ var/datum/pipe_network/network3
+
+ Initialize()
+ switch(dir)
+ if(NORTH)
+ initialize_directions = EAST|NORTH|SOUTH
+ if(SOUTH)
+ initialize_directions = SOUTH|WEST|NORTH
+ if(EAST)
+ initialize_directions = EAST|WEST|SOUTH
+ if(WEST)
+ initialize_directions = WEST|NORTH|EAST
+ air1 = new
+ air2 = new
+ air3 = new
+
+ air1.volume = 200
+ air2.volume = 200
+ air3.volume = 200
+ . = ..()
+
+// Housekeeping and pipe network stuff below
+ network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+ if(reference == node1)
+ network1 = new_network
+
+ else if(reference == node2)
+ network2 = new_network
+
+ else if (reference == node3)
+ network3 = new_network
+
+ if(new_network.normal_members.Find(src))
+ return 0
+
+ new_network.normal_members += src
+
+ return null
+
+ Destroy()
+ QDEL_NULL(air1)
+ QDEL_NULL(air2)
+ QDEL_NULL(air3)
+
+ if(node1)
+ node1.disconnect(src)
+ QDEL_NULL(network1)
+ if(node2)
+ node2.disconnect(src)
+ QDEL_NULL(network2)
+ if(node3)
+ node3.disconnect(src)
+ QDEL_NULL(network3)
+
+ node1 = null
+ node2 = null
+ node3 = null
+
+ return ..()
+
+ atmos_init()
+ if(node1 && node2 && node3) return
+
+ var/node1_connect = turn(dir, -180)
+ var/node2_connect = turn(dir, -90)
+ var/node3_connect = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node1_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node2_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node2 = target
+ break
+ for(var/obj/machinery/atmospherics/target in get_step(src,node3_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node3 = target
+ break
+
+ update_icon()
+ update_underlays()
+
+ build_network()
+ if(!network1 && node1)
+ network1 = new /datum/pipe_network()
+ network1.normal_members += src
+ network1.build_network(node1, src)
+
+ if(!network2 && node2)
+ network2 = new /datum/pipe_network()
+ network2.normal_members += src
+ network2.build_network(node2, src)
+
+ if(!network3 && node3)
+ network3 = new /datum/pipe_network()
+ network3.normal_members += src
+ network3.build_network(node3, src)
+
+
+ return_network(obj/machinery/atmospherics/reference)
+ build_network()
+
+ if(reference==node1)
+ return network1
+
+ if(reference==node2)
+ return network2
+
+ if(reference==node3)
+ return network3
+
+ return null
+
+ reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
+ if(network1 == old_network)
+ network1 = new_network
+ if(network2 == old_network)
+ network2 = new_network
+ if(network3 == old_network)
+ network3 = new_network
+
+ return 1
+
+ return_network_air(datum/pipe_network/reference)
+ var/list/results = list()
+
+ if(network1 == reference)
+ results += air1
+ if(network2 == reference)
+ results += air2
+ if(network3 == reference)
+ results += air3
+
+ return results
+
+ disconnect(obj/machinery/atmospherics/reference)
+ if(reference==node1)
+ qdel(network1)
+ node1 = null
+
+ else if(reference==node2)
+ qdel(network2)
+ node2 = null
+
+ else if(reference==node3)
+ qdel(network3)
+ node3 = null
+
+ update_underlays()
+
+ return null
diff --git a/code/ATMOSPHERICS/components/unary/cold_sink.dm b/code/ATMOSPHERICS/components/unary/cold_sink.dm
index 5349e0404c5..09588b2c4cc 100644
--- a/code/ATMOSPHERICS/components/unary/cold_sink.dm
+++ b/code/ATMOSPHERICS/components/unary/cold_sink.dm
@@ -1,186 +1,186 @@
-//TODO: Put this under a common parent type with heaters to cut down on the copypasta
-#define FREEZER_PERF_MULT 2.5
-
-/obj/machinery/atmospherics/unary/freezer
- name = "gas cooling system"
- desc = "Cools gas when connected to pipe network"
- icon = 'icons/obj/sleeper.dmi'
- icon_state = "freezer_0"
- density = 1
- anchored = 1
- use_power = 0
- idle_power_usage = 5 // 5 Watts for thermostat related circuitry
-
- var/heatsink_temperature = T20C // The constant temperature reservoir into which the freezer pumps heat. Probably the hull of the station or something.
- var/internal_volume = 600 // L
-
- var/max_power_rating = 20000 // Power rating when the usage is turned up to 100
- var/power_setting = 100
-
- var/set_temperature = T20C // Thermostat
- var/cooling = 0
-
- component_types = list(
- /obj/item/circuitboard/unary_atmos/cooler,
- /obj/item/stock_parts/matter_bin,
- /obj/item/stock_parts/capacitor = 2,
- /obj/item/stock_parts/manipulator,
- /obj/item/stack/cable_coil{amount = 2}
- )
-
-/obj/machinery/atmospherics/unary/freezer/Initialize()
- initialize_directions = dir
- . = ..()
-
-/obj/machinery/atmospherics/unary/freezer/atmos_init()
- if(node)
- return
-
- var/node_connect = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src, node_connect))
- if(target.initialize_directions & get_dir(target, src))
- node = target
- break
-
- //copied from pipe construction code since heaters/freezers don't use fittings and weren't doing this check - this all really really needs to be refactored someday.
- //check that there are no incompatible pipes/machinery in our own location
- for(var/obj/machinery/atmospherics/M in src.loc)
- if(M != src && (M.initialize_directions & node_connect) && M.check_connect_types(M,src)) // matches at least one direction on either type of pipe & same connection type
- node = null
- break
-
- update_icon()
-
-/obj/machinery/atmospherics/unary/freezer/update_icon()
- if(node)
- if(use_power && cooling)
- icon_state = "freezer_1"
- else
- icon_state = "freezer"
- else
- icon_state = "freezer_0"
- return
-
-/obj/machinery/atmospherics/unary/freezer/attack_ai(mob/user as mob)
- ui_interact(user)
-
-/obj/machinery/atmospherics/unary/freezer/attack_hand(mob/user as mob)
- ui_interact(user)
-
-/obj/machinery/atmospherics/unary/freezer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- // this is the data which will be sent to the ui
- var/data[0]
- data["on"] = use_power ? 1 : 0
- data["gasPressure"] = round(air_contents.return_pressure())
- data["gasTemperature"] = round(air_contents.temperature)
- data["minGasTemperature"] = 0
- data["maxGasTemperature"] = round(T20C+500)
- data["targetGasTemperature"] = round(set_temperature)
- data["powerSetting"] = power_setting
-
- var/temp_class = "good"
- if(air_contents.temperature > (T0C - 20))
- temp_class = "bad"
- else if(air_contents.temperature < (T0C - 20) && air_contents.temperature > (T0C - 100))
- temp_class = "average"
- data["gasTemperatureClass"] = temp_class
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if(!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "freezer.tmpl", "Gas Cooling System", 440, 300)
- // when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
- // open the new ui window
- ui.open()
- // auto update every Master Controller tick
- ui.set_auto_update(1)
-
-/obj/machinery/atmospherics/unary/freezer/Topic(href, href_list)
- if(..())
- return 1
- if(href_list["toggleStatus"])
- use_power = !use_power
- update_icon()
- if(href_list["temp"])
- var/amount = text2num(href_list["temp"])
- if(amount > 0)
- set_temperature = min(set_temperature + amount, 1000)
- else
- set_temperature = max(set_temperature + amount, 0)
- if(href_list["setPower"]) //setting power to 0 is redundant anyways
- var/new_setting = between(0, text2num(href_list["setPower"]), 100)
- set_power_level(new_setting)
-
- add_fingerprint(usr)
-
-/obj/machinery/atmospherics/unary/freezer/machinery_process()
- ..()
-
- if(stat & (NOPOWER|BROKEN) || !use_power)
- cooling = 0
- update_icon()
- return
-
- if(network && air_contents.temperature > set_temperature)
- cooling = 1
-
- var/heat_transfer = max( -air_contents.get_thermal_energy_change(set_temperature - 5), 0 )
-
- //Assume the heat is being pumped into the hull which is fixed at heatsink_temperature
- //not /really/ proper thermodynamics but whatever
- var/cop = FREEZER_PERF_MULT * air_contents.temperature/heatsink_temperature //heatpump coefficient of performance from thermodynamics -> power used = heat_transfer/cop
- heat_transfer = min(heat_transfer, cop * power_rating) //limit heat transfer by available power
-
- var/removed = -air_contents.add_thermal_energy(-heat_transfer) //remove the heat
- if(debug)
- visible_message("[src]: Removing [removed] W.")
-
- use_power(power_rating)
-
- network.update = 1
- else
- cooling = 0
-
- update_icon()
-
-//upgrading parts
-/obj/machinery/atmospherics/unary/freezer/RefreshParts()
- ..()
- var/cap_rating = 0
- var/manip_rating = 0
- var/bin_rating = 0
- for(var/obj/item/stock_parts/P in component_parts)
- if(iscapacitor(P))
- cap_rating += P.rating
- else if(ismanipulator(P))
- manip_rating += P.rating
- else if(ismatterbin(P))
- bin_rating += P.rating
-
- power_rating = initial(power_rating) * cap_rating / 2 //more powerful
- heatsink_temperature = initial(heatsink_temperature) / ((manip_rating + bin_rating) / 2) //more efficient
- air_contents.volume = max(initial(internal_volume) - 200, 0) + 200 * bin_rating
- set_power_level(power_setting)
-
-/obj/machinery/atmospherics/unary/freezer/proc/set_power_level(var/new_power_setting)
- power_setting = new_power_setting
- power_rating = max_power_rating * (power_setting/100)
-
-/obj/machinery/atmospherics/unary/freezer/attackby(var/obj/item/O as obj, var/mob/user as mob)
- if(default_deconstruction_screwdriver(user, O))
- return
- if(default_deconstruction_crowbar(user, O))
- return
- if(default_part_replacement(user, O))
- return
-
- ..()
-
-/obj/machinery/atmospherics/unary/freezer/examine(mob/user)
- ..(user)
- if(panel_open)
- to_chat(user, "The maintenance hatch is open.")
+//TODO: Put this under a common parent type with heaters to cut down on the copypasta
+#define FREEZER_PERF_MULT 2.5
+
+/obj/machinery/atmospherics/unary/freezer
+ name = "gas cooling system"
+ desc = "Cools gas when connected to pipe network"
+ icon = 'icons/obj/sleeper.dmi'
+ icon_state = "freezer_0"
+ density = 1
+ anchored = 1
+ use_power = 0
+ idle_power_usage = 5 // 5 Watts for thermostat related circuitry
+
+ var/heatsink_temperature = T20C // The constant temperature reservoir into which the freezer pumps heat. Probably the hull of the station or something.
+ var/internal_volume = 600 // L
+
+ var/max_power_rating = 20000 // Power rating when the usage is turned up to 100
+ var/power_setting = 100
+
+ var/set_temperature = T20C // Thermostat
+ var/cooling = 0
+
+ component_types = list(
+ /obj/item/circuitboard/unary_atmos/cooler,
+ /obj/item/stock_parts/matter_bin,
+ /obj/item/stock_parts/capacitor = 2,
+ /obj/item/stock_parts/manipulator,
+ /obj/item/stack/cable_coil{amount = 2}
+ )
+
+/obj/machinery/atmospherics/unary/freezer/Initialize()
+ initialize_directions = dir
+ . = ..()
+
+/obj/machinery/atmospherics/unary/freezer/atmos_init()
+ if(node)
+ return
+
+ var/node_connect = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src, node_connect))
+ if(target.initialize_directions & get_dir(target, src))
+ node = target
+ break
+
+ //copied from pipe construction code since heaters/freezers don't use fittings and weren't doing this check - this all really really needs to be refactored someday.
+ //check that there are no incompatible pipes/machinery in our own location
+ for(var/obj/machinery/atmospherics/M in src.loc)
+ if(M != src && (M.initialize_directions & node_connect) && M.check_connect_types(M,src)) // matches at least one direction on either type of pipe & same connection type
+ node = null
+ break
+
+ update_icon()
+
+/obj/machinery/atmospherics/unary/freezer/update_icon()
+ if(node)
+ if(use_power && cooling)
+ icon_state = "freezer_1"
+ else
+ icon_state = "freezer"
+ else
+ icon_state = "freezer_0"
+ return
+
+/obj/machinery/atmospherics/unary/freezer/attack_ai(mob/user as mob)
+ ui_interact(user)
+
+/obj/machinery/atmospherics/unary/freezer/attack_hand(mob/user as mob)
+ ui_interact(user)
+
+/obj/machinery/atmospherics/unary/freezer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+ // this is the data which will be sent to the ui
+ var/data[0]
+ data["on"] = use_power ? 1 : 0
+ data["gasPressure"] = round(air_contents.return_pressure())
+ data["gasTemperature"] = round(air_contents.temperature)
+ data["minGasTemperature"] = 0
+ data["maxGasTemperature"] = round(T20C+500)
+ data["targetGasTemperature"] = round(set_temperature)
+ data["powerSetting"] = power_setting
+
+ var/temp_class = "good"
+ if(air_contents.temperature > (T0C - 20))
+ temp_class = "bad"
+ else if(air_contents.temperature < (T0C - 20) && air_contents.temperature > (T0C - 100))
+ temp_class = "average"
+ data["gasTemperatureClass"] = temp_class
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if(!ui)
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
+ ui = new(user, src, ui_key, "freezer.tmpl", "Gas Cooling System", 440, 300)
+ // when the ui is first opened this is the data it will use
+ ui.set_initial_data(data)
+ // open the new ui window
+ ui.open()
+ // auto update every Master Controller tick
+ ui.set_auto_update(1)
+
+/obj/machinery/atmospherics/unary/freezer/Topic(href, href_list)
+ if(..())
+ return 1
+ if(href_list["toggleStatus"])
+ use_power = !use_power
+ update_icon()
+ if(href_list["temp"])
+ var/amount = text2num(href_list["temp"])
+ if(amount > 0)
+ set_temperature = min(set_temperature + amount, 1000)
+ else
+ set_temperature = max(set_temperature + amount, 0)
+ if(href_list["setPower"]) //setting power to 0 is redundant anyways
+ var/new_setting = between(0, text2num(href_list["setPower"]), 100)
+ set_power_level(new_setting)
+
+ add_fingerprint(usr)
+
+/obj/machinery/atmospherics/unary/freezer/machinery_process()
+ ..()
+
+ if(stat & (NOPOWER|BROKEN) || !use_power)
+ cooling = 0
+ update_icon()
+ return
+
+ if(network && air_contents.temperature > set_temperature)
+ cooling = 1
+
+ var/heat_transfer = max( -air_contents.get_thermal_energy_change(set_temperature - 5), 0 )
+
+ //Assume the heat is being pumped into the hull which is fixed at heatsink_temperature
+ //not /really/ proper thermodynamics but whatever
+ var/cop = FREEZER_PERF_MULT * air_contents.temperature/heatsink_temperature //heatpump coefficient of performance from thermodynamics -> power used = heat_transfer/cop
+ heat_transfer = min(heat_transfer, cop * power_rating) //limit heat transfer by available power
+
+ var/removed = -air_contents.add_thermal_energy(-heat_transfer) //remove the heat
+ if(debug)
+ visible_message("[src]: Removing [removed] W.")
+
+ use_power(power_rating)
+
+ network.update = 1
+ else
+ cooling = 0
+
+ update_icon()
+
+//upgrading parts
+/obj/machinery/atmospherics/unary/freezer/RefreshParts()
+ ..()
+ var/cap_rating = 0
+ var/manip_rating = 0
+ var/bin_rating = 0
+ for(var/obj/item/stock_parts/P in component_parts)
+ if(iscapacitor(P))
+ cap_rating += P.rating
+ else if(ismanipulator(P))
+ manip_rating += P.rating
+ else if(ismatterbin(P))
+ bin_rating += P.rating
+
+ power_rating = initial(power_rating) * cap_rating / 2 //more powerful
+ heatsink_temperature = initial(heatsink_temperature) / ((manip_rating + bin_rating) / 2) //more efficient
+ air_contents.volume = max(initial(internal_volume) - 200, 0) + 200 * bin_rating
+ set_power_level(power_setting)
+
+/obj/machinery/atmospherics/unary/freezer/proc/set_power_level(var/new_power_setting)
+ power_setting = new_power_setting
+ power_rating = max_power_rating * (power_setting/100)
+
+/obj/machinery/atmospherics/unary/freezer/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(default_deconstruction_screwdriver(user, O))
+ return
+ if(default_deconstruction_crowbar(user, O))
+ return
+ if(default_part_replacement(user, O))
+ return
+
+ ..()
+
+/obj/machinery/atmospherics/unary/freezer/examine(mob/user)
+ ..(user)
+ if(panel_open)
+ to_chat(user, "The maintenance hatch is open.")
diff --git a/code/ATMOSPHERICS/components/unary/generator_input.dm b/code/ATMOSPHERICS/components/unary/generator_input.dm
index 2b31097dc41..3a4d11428bb 100644
--- a/code/ATMOSPHERICS/components/unary/generator_input.dm
+++ b/code/ATMOSPHERICS/components/unary/generator_input.dm
@@ -1,21 +1,21 @@
-/obj/machinery/atmospherics/unary/generator_input
- icon = 'icons/obj/atmospherics/heat_exchanger.dmi'
- icon_state = "intact"
- density = 1
-
- name = "Generator Input"
- desc = "Placeholder"
-
- var/update_cycle
-
- update_icon()
- if(node)
- icon_state = "intact"
- else
- icon_state = "exposed"
-
- return
-
- proc
- return_exchange_air()
+/obj/machinery/atmospherics/unary/generator_input
+ icon = 'icons/obj/atmospherics/heat_exchanger.dmi'
+ icon_state = "intact"
+ density = 1
+
+ name = "Generator Input"
+ desc = "Placeholder"
+
+ var/update_cycle
+
+ update_icon()
+ if(node)
+ icon_state = "intact"
+ else
+ icon_state = "exposed"
+
+ return
+
+ proc
+ return_exchange_air()
return air_contents
\ No newline at end of file
diff --git a/code/ATMOSPHERICS/components/unary/heat_exchanger.dm b/code/ATMOSPHERICS/components/unary/heat_exchanger.dm
index 93af5cb8d5a..67461129228 100644
--- a/code/ATMOSPHERICS/components/unary/heat_exchanger.dm
+++ b/code/ATMOSPHERICS/components/unary/heat_exchanger.dm
@@ -1,89 +1,89 @@
-/obj/machinery/atmospherics/unary/heat_exchanger
-
- icon = 'icons/obj/atmospherics/heat_exchanger.dmi'
- icon_state = "intact"
- density = 1
-
- name = "Heat Exchanger"
- desc = "Exchanges heat between two input gases. Setup for fast heat transfer"
-
- var/obj/machinery/atmospherics/unary/heat_exchanger/partner = null
- var/update_cycle
-
- update_icon()
- if(node)
- icon_state = "intact"
- else
- icon_state = "exposed"
-
- return
-
- atmos_init()
- if(!partner)
- var/partner_connect = turn(dir,180)
-
- for(var/obj/machinery/atmospherics/unary/heat_exchanger/target in get_step(src,partner_connect))
- if(target.dir & get_dir(src,target))
- partner = target
- partner.partner = src
- break
-
- ..()
-
- machinery_process()
- ..()
- if(QDELETED(partner))
- return 0
-
- if(!SSair || SSair.times_fired <= update_cycle)
- return 0
-
- update_cycle = SSair.times_fired
- partner.update_cycle = SSair.times_fired
-
- var/air_heat_capacity = air_contents.heat_capacity()
- var/other_air_heat_capacity = partner.air_contents.heat_capacity()
- var/combined_heat_capacity = other_air_heat_capacity + air_heat_capacity
-
- var/old_temperature = air_contents.temperature
- var/other_old_temperature = partner.air_contents.temperature
-
- if(combined_heat_capacity > 0)
- var/combined_energy = partner.air_contents.temperature*other_air_heat_capacity + air_heat_capacity*air_contents.temperature
-
- var/new_temperature = combined_energy/combined_heat_capacity
- air_contents.temperature = new_temperature
- partner.air_contents.temperature = new_temperature
-
- if(network)
- if(abs(old_temperature-air_contents.temperature) > 1)
- network.update = 1
-
- if(partner.network)
- if(abs(other_old_temperature-partner.air_contents.temperature) > 1)
- partner.network.update = 1
-
- return 1
-
- attackby(var/obj/item/W as obj, var/mob/user as mob)
- if (!W.iswrench())
- return ..()
- var/turf/T = src.loc
- if (level==1 && isturf(T) && !T.is_plating())
- to_chat(user, "You must remove the plating first.")
- return 1
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
- if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
- to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- playsound(src.loc, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, 40/W.toolspeed, act_target = src))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear a ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- qdel(src)
+/obj/machinery/atmospherics/unary/heat_exchanger
+
+ icon = 'icons/obj/atmospherics/heat_exchanger.dmi'
+ icon_state = "intact"
+ density = 1
+
+ name = "Heat Exchanger"
+ desc = "Exchanges heat between two input gases. Setup for fast heat transfer"
+
+ var/obj/machinery/atmospherics/unary/heat_exchanger/partner = null
+ var/update_cycle
+
+ update_icon()
+ if(node)
+ icon_state = "intact"
+ else
+ icon_state = "exposed"
+
+ return
+
+ atmos_init()
+ if(!partner)
+ var/partner_connect = turn(dir,180)
+
+ for(var/obj/machinery/atmospherics/unary/heat_exchanger/target in get_step(src,partner_connect))
+ if(target.dir & get_dir(src,target))
+ partner = target
+ partner.partner = src
+ break
+
+ ..()
+
+ machinery_process()
+ ..()
+ if(QDELETED(partner))
+ return 0
+
+ if(!SSair || SSair.times_fired <= update_cycle)
+ return 0
+
+ update_cycle = SSair.times_fired
+ partner.update_cycle = SSair.times_fired
+
+ var/air_heat_capacity = air_contents.heat_capacity()
+ var/other_air_heat_capacity = partner.air_contents.heat_capacity()
+ var/combined_heat_capacity = other_air_heat_capacity + air_heat_capacity
+
+ var/old_temperature = air_contents.temperature
+ var/other_old_temperature = partner.air_contents.temperature
+
+ if(combined_heat_capacity > 0)
+ var/combined_energy = partner.air_contents.temperature*other_air_heat_capacity + air_heat_capacity*air_contents.temperature
+
+ var/new_temperature = combined_energy/combined_heat_capacity
+ air_contents.temperature = new_temperature
+ partner.air_contents.temperature = new_temperature
+
+ if(network)
+ if(abs(old_temperature-air_contents.temperature) > 1)
+ network.update = 1
+
+ if(partner.network)
+ if(abs(other_old_temperature-partner.air_contents.temperature) > 1)
+ partner.network.update = 1
+
+ return 1
+
+ attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if (!W.iswrench())
+ return ..()
+ var/turf/T = src.loc
+ if (level==1 && isturf(T) && !T.is_plating())
+ to_chat(user, "You must remove the plating first.")
+ return 1
+ var/datum/gas_mixture/int_air = return_air()
+ var/datum/gas_mixture/env_air = loc.return_air()
+ if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
+ to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ playsound(src.loc, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, 40/W.toolspeed, act_target = src))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear a ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ qdel(src)
diff --git a/code/ATMOSPHERICS/components/unary/heat_source.dm b/code/ATMOSPHERICS/components/unary/heat_source.dm
index b6d59cb3ccd..a44d857d7a1 100644
--- a/code/ATMOSPHERICS/components/unary/heat_source.dm
+++ b/code/ATMOSPHERICS/components/unary/heat_source.dm
@@ -1,172 +1,172 @@
-//TODO: Put this under a common parent type with freezers to cut down on the copypasta
-#define HEATER_PERF_MULT 2.5
-
-/obj/machinery/atmospherics/unary/heater
- name = "gas heating system"
- desc = "Heats gas when connected to a pipe network"
- icon = 'icons/obj/sleeper.dmi'
- icon_state = "heater_0"
- density = 1
- anchored = 1
- use_power = 0
- idle_power_usage = 5 //5 Watts for thermostat related circuitry
-
- var/max_temperature = T20C + 680
- var/internal_volume = 600 //L
-
- var/max_power_rating = 20000 //power rating when the usage is turned up to 100
- var/power_setting = 100
-
- var/set_temperature = T20C //thermostat
- var/heating = 0 //mainly for icon updates
-
- component_types = list(
- /obj/item/circuitboard/unary_atmos/heater,
- /obj/item/stock_parts/matter_bin,
- /obj/item/stock_parts/capacitor = 2,
- /obj/item/stack/cable_coil{amount = 5}
- )
-
-/obj/machinery/atmospherics/unary/heater/Initialize()
- initialize_directions = dir
- . = ..()
-
-/obj/machinery/atmospherics/unary/heater/atmos_init()
- if(node)
- return
-
- var/node_connect = dir
-
- //check that there is something to connect to
- for(var/obj/machinery/atmospherics/target in get_step(src, node_connect))
- if(target.initialize_directions & get_dir(target, src))
- node = target
- break
-
- //copied from pipe construction code since heaters/freezers don't use fittings and weren't doing this check - this all really really needs to be refactored someday.
- //check that there are no incompatible pipes/machinery in our own location
- for(var/obj/machinery/atmospherics/M in src.loc)
- if(M != src && (M.initialize_directions & node_connect) && M.check_connect_types(M,src)) // matches at least one direction on either type of pipe & same connection type
- node = null
- break
-
- update_icon()
-
-
-/obj/machinery/atmospherics/unary/heater/update_icon()
- if(node)
- if(use_power && heating)
- icon_state = "heater_1"
- else
- icon_state = "heater"
- else
- icon_state = "heater_0"
- return
-
-
-/obj/machinery/atmospherics/unary/heater/machinery_process()
- ..()
-
- if(stat & (NOPOWER|BROKEN) || !use_power)
- heating = 0
- update_icon()
- return
-
- if(network && air_contents.total_moles && air_contents.temperature < set_temperature)
- air_contents.add_thermal_energy(power_rating * HEATER_PERF_MULT)
- use_power(power_rating)
-
- heating = 1
- network.update = 1
- else
- heating = 0
-
- update_icon()
-
-/obj/machinery/atmospherics/unary/heater/attack_ai(mob/user as mob)
- ui_interact(user)
-
-/obj/machinery/atmospherics/unary/heater/attack_hand(mob/user as mob)
- ui_interact(user)
-
-/obj/machinery/atmospherics/unary/heater/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
- // this is the data which will be sent to the ui
- var/data[0]
- data["on"] = use_power ? 1 : 0
- data["gasPressure"] = round(air_contents.return_pressure())
- data["gasTemperature"] = round(air_contents.temperature)
- data["minGasTemperature"] = 0
- data["maxGasTemperature"] = round(max_temperature)
- data["targetGasTemperature"] = round(set_temperature)
- data["powerSetting"] = power_setting
-
- var/temp_class = "normal"
- if(air_contents.temperature > (T20C+40))
- temp_class = "bad"
- data["gasTemperatureClass"] = temp_class
-
- // update the ui if it exists, returns null if no ui is passed/found
- ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
- if(!ui)
- // the ui does not exist, so we'll create a new() one
- // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
- ui = new(user, src, ui_key, "freezer.tmpl", "Gas Heating System", 440, 300)
- // when the ui is first opened this is the data it will use
- ui.set_initial_data(data)
- // open the new ui window
- ui.open()
- // auto update every Master Controller tick
- ui.set_auto_update(1)
-
-/obj/machinery/atmospherics/unary/heater/Topic(href, href_list)
- if(..())
- return 1
- if(href_list["toggleStatus"])
- use_power = !use_power
- update_icon()
- if(href_list["temp"])
- var/amount = text2num(href_list["temp"])
- if(amount > 0)
- set_temperature = min(set_temperature + amount, max_temperature)
- else
- set_temperature = max(set_temperature + amount, 0)
- if(href_list["setPower"]) //setting power to 0 is redundant anyways
- var/new_setting = between(0, text2num(href_list["setPower"]), 100)
- set_power_level(new_setting)
-
- add_fingerprint(usr)
-
-//upgrading parts
-/obj/machinery/atmospherics/unary/heater/RefreshParts()
- ..()
- var/cap_rating = 0
- var/bin_rating = 0
- for(var/obj/item/stock_parts/P in component_parts)
- if(iscapacitor(P))
- cap_rating += P.rating
- else if(ismatterbin(P))
- bin_rating += P.rating
-
- max_power_rating = initial(max_power_rating) * cap_rating / 2
- max_temperature = max(initial(max_temperature) - T20C, 0) * ((bin_rating * 4 + cap_rating) / 5) + T20C
- air_contents.volume = max(initial(internal_volume) - 200, 0) + 200 * bin_rating
- set_power_level(power_setting)
-
-/obj/machinery/atmospherics/unary/heater/proc/set_power_level(var/new_power_setting)
- power_setting = new_power_setting
- power_rating = max_power_rating * (power_setting/100)
-
-/obj/machinery/atmospherics/unary/heater/attackby(var/obj/item/O as obj, var/mob/user as mob)
- if(default_deconstruction_screwdriver(user, O))
- return
- if(default_deconstruction_crowbar(user, O))
- return
- if(default_part_replacement(user, O))
- return
-
- ..()
-
-/obj/machinery/atmospherics/unary/heater/examine(mob/user)
- ..(user)
- if(panel_open)
- to_chat(user, "The maintenance hatch is open.")
+//TODO: Put this under a common parent type with freezers to cut down on the copypasta
+#define HEATER_PERF_MULT 2.5
+
+/obj/machinery/atmospherics/unary/heater
+ name = "gas heating system"
+ desc = "Heats gas when connected to a pipe network"
+ icon = 'icons/obj/sleeper.dmi'
+ icon_state = "heater_0"
+ density = 1
+ anchored = 1
+ use_power = 0
+ idle_power_usage = 5 //5 Watts for thermostat related circuitry
+
+ var/max_temperature = T20C + 680
+ var/internal_volume = 600 //L
+
+ var/max_power_rating = 20000 //power rating when the usage is turned up to 100
+ var/power_setting = 100
+
+ var/set_temperature = T20C //thermostat
+ var/heating = 0 //mainly for icon updates
+
+ component_types = list(
+ /obj/item/circuitboard/unary_atmos/heater,
+ /obj/item/stock_parts/matter_bin,
+ /obj/item/stock_parts/capacitor = 2,
+ /obj/item/stack/cable_coil{amount = 5}
+ )
+
+/obj/machinery/atmospherics/unary/heater/Initialize()
+ initialize_directions = dir
+ . = ..()
+
+/obj/machinery/atmospherics/unary/heater/atmos_init()
+ if(node)
+ return
+
+ var/node_connect = dir
+
+ //check that there is something to connect to
+ for(var/obj/machinery/atmospherics/target in get_step(src, node_connect))
+ if(target.initialize_directions & get_dir(target, src))
+ node = target
+ break
+
+ //copied from pipe construction code since heaters/freezers don't use fittings and weren't doing this check - this all really really needs to be refactored someday.
+ //check that there are no incompatible pipes/machinery in our own location
+ for(var/obj/machinery/atmospherics/M in src.loc)
+ if(M != src && (M.initialize_directions & node_connect) && M.check_connect_types(M,src)) // matches at least one direction on either type of pipe & same connection type
+ node = null
+ break
+
+ update_icon()
+
+
+/obj/machinery/atmospherics/unary/heater/update_icon()
+ if(node)
+ if(use_power && heating)
+ icon_state = "heater_1"
+ else
+ icon_state = "heater"
+ else
+ icon_state = "heater_0"
+ return
+
+
+/obj/machinery/atmospherics/unary/heater/machinery_process()
+ ..()
+
+ if(stat & (NOPOWER|BROKEN) || !use_power)
+ heating = 0
+ update_icon()
+ return
+
+ if(network && air_contents.total_moles && air_contents.temperature < set_temperature)
+ air_contents.add_thermal_energy(power_rating * HEATER_PERF_MULT)
+ use_power(power_rating)
+
+ heating = 1
+ network.update = 1
+ else
+ heating = 0
+
+ update_icon()
+
+/obj/machinery/atmospherics/unary/heater/attack_ai(mob/user as mob)
+ ui_interact(user)
+
+/obj/machinery/atmospherics/unary/heater/attack_hand(mob/user as mob)
+ ui_interact(user)
+
+/obj/machinery/atmospherics/unary/heater/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
+ // this is the data which will be sent to the ui
+ var/data[0]
+ data["on"] = use_power ? 1 : 0
+ data["gasPressure"] = round(air_contents.return_pressure())
+ data["gasTemperature"] = round(air_contents.temperature)
+ data["minGasTemperature"] = 0
+ data["maxGasTemperature"] = round(max_temperature)
+ data["targetGasTemperature"] = round(set_temperature)
+ data["powerSetting"] = power_setting
+
+ var/temp_class = "normal"
+ if(air_contents.temperature > (T20C+40))
+ temp_class = "bad"
+ data["gasTemperatureClass"] = temp_class
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = SSnanoui.try_update_ui(user, src, ui_key, ui, data, force_open)
+ if(!ui)
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
+ ui = new(user, src, ui_key, "freezer.tmpl", "Gas Heating System", 440, 300)
+ // when the ui is first opened this is the data it will use
+ ui.set_initial_data(data)
+ // open the new ui window
+ ui.open()
+ // auto update every Master Controller tick
+ ui.set_auto_update(1)
+
+/obj/machinery/atmospherics/unary/heater/Topic(href, href_list)
+ if(..())
+ return 1
+ if(href_list["toggleStatus"])
+ use_power = !use_power
+ update_icon()
+ if(href_list["temp"])
+ var/amount = text2num(href_list["temp"])
+ if(amount > 0)
+ set_temperature = min(set_temperature + amount, max_temperature)
+ else
+ set_temperature = max(set_temperature + amount, 0)
+ if(href_list["setPower"]) //setting power to 0 is redundant anyways
+ var/new_setting = between(0, text2num(href_list["setPower"]), 100)
+ set_power_level(new_setting)
+
+ add_fingerprint(usr)
+
+//upgrading parts
+/obj/machinery/atmospherics/unary/heater/RefreshParts()
+ ..()
+ var/cap_rating = 0
+ var/bin_rating = 0
+ for(var/obj/item/stock_parts/P in component_parts)
+ if(iscapacitor(P))
+ cap_rating += P.rating
+ else if(ismatterbin(P))
+ bin_rating += P.rating
+
+ max_power_rating = initial(max_power_rating) * cap_rating / 2
+ max_temperature = max(initial(max_temperature) - T20C, 0) * ((bin_rating * 4 + cap_rating) / 5) + T20C
+ air_contents.volume = max(initial(internal_volume) - 200, 0) + 200 * bin_rating
+ set_power_level(power_setting)
+
+/obj/machinery/atmospherics/unary/heater/proc/set_power_level(var/new_power_setting)
+ power_setting = new_power_setting
+ power_rating = max_power_rating * (power_setting/100)
+
+/obj/machinery/atmospherics/unary/heater/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ if(default_deconstruction_screwdriver(user, O))
+ return
+ if(default_deconstruction_crowbar(user, O))
+ return
+ if(default_part_replacement(user, O))
+ return
+
+ ..()
+
+/obj/machinery/atmospherics/unary/heater/examine(mob/user)
+ ..(user)
+ if(panel_open)
+ to_chat(user, "The maintenance hatch is open.")
diff --git a/code/ATMOSPHERICS/components/unary/outlet_injector.dm b/code/ATMOSPHERICS/components/unary/outlet_injector.dm
index 1081a4b575e..5991c0fd9de 100644
--- a/code/ATMOSPHERICS/components/unary/outlet_injector.dm
+++ b/code/ATMOSPHERICS/components/unary/outlet_injector.dm
@@ -1,152 +1,152 @@
-//Basically a one way passive valve. If the pressure inside is greater than the environment then gas will flow passively,
-//but it does not permit gas to flow back from the environment into the injector. Can be turned off to prevent any gas flow.
-//When it receives the "inject" signal, it will try to pump it's entire contents into the environment regardless of pressure, using power.
-
-/obj/machinery/atmospherics/unary/outlet_injector
- icon = 'icons/atmos/injector.dmi'
- icon_state = "map_injector"
- layer = 3
-
- name = "air injector"
- desc = "Passively injects air into its surroundings. Has a valve attached to it that can control flow rate."
-
- use_power = 0
- idle_power_usage = 150 //internal circuitry, friction losses and stuff
- power_rating = 15000 //15000 W ~ 20 HP
-
- var/injecting = 0
-
- var/volume_rate = 50 //flow rate limit
-
- var/frequency = 0
- var/id = null
- var/datum/radio_frequency/radio_connection
-
- level = 1
-
-/obj/machinery/atmospherics/unary/outlet_injector/Initialize()
- . = ..()
- air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 500 //Give it a small reservoir for injecting. Also allows it to have a higher flow rate limit than vent pumps, to differentiate injectors a bit more.
-
-/obj/machinery/atmospherics/unary/outlet_injector/update_icon()
- if(!powered())
- icon_state = "off"
- else
- icon_state = "[use_power ? "on" : "off"]"
-
-/obj/machinery/atmospherics/unary/outlet_injector/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
- add_underlay(T, node, dir)
-
-/obj/machinery/atmospherics/unary/outlet_injector/power_change()
- var/old_stat = stat
- ..()
- if(old_stat != stat)
- update_icon()
-
-/obj/machinery/atmospherics/unary/outlet_injector/machinery_process()
- ..()
-
- last_power_draw = 0
- last_flow_rate = 0
-
- if((stat & (NOPOWER|BROKEN)) || !use_power)
- return
-
- var/power_draw = -1
- var/datum/gas_mixture/environment = loc.return_air()
-
- if(environment && air_contents.temperature > 0)
- var/transfer_moles = (volume_rate/air_contents.volume)*air_contents.total_moles //apply flow rate limit
- power_draw = pump_gas(src, air_contents, environment, transfer_moles, power_rating)
-
- if (power_draw >= 0)
- last_power_draw = power_draw
- use_power(power_draw)
-
- if(network)
- network.update = 1
-
- return 1
-
-/obj/machinery/atmospherics/unary/outlet_injector/proc/inject()
- if(injecting || (stat & NOPOWER))
- return 0
-
- var/datum/gas_mixture/environment = loc.return_air()
- if (!environment)
- return 0
-
- injecting = 1
-
- if(air_contents.temperature > 0)
- var/power_used = pump_gas(src, air_contents, environment, air_contents.total_moles, power_rating)
- use_power(power_used)
-
- if(network)
- network.update = 1
-
- flick("inject", src)
-
-/obj/machinery/atmospherics/unary/outlet_injector/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/unary/outlet_injector/proc/broadcast_status()
- if(!radio_connection)
- return 0
-
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.source = src
-
- signal.data = list(
- "tag" = id,
- "device" = "AO",
- "power" = use_power,
- "volume_rate" = volume_rate,
- "sigtype" = "status"
- )
-
- radio_connection.post_signal(src, signal)
-
- return 1
-
-/obj/machinery/atmospherics/unary/outlet_injector/atmos_init()
- ..()
-
- set_frequency(frequency)
-
-/obj/machinery/atmospherics/unary/outlet_injector/receive_signal(datum/signal/signal)
- if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
- return 0
-
- if(signal.data["power"])
- use_power = text2num(signal.data["power"])
-
- if(signal.data["power_toggle"])
- use_power = !use_power
-
- if(signal.data["inject"])
- spawn inject()
- return
-
- if(signal.data["set_volume_rate"])
- var/number = text2num(signal.data["set_volume_rate"])
- volume_rate = between(0, number, air_contents.volume)
-
- if(signal.data["status"])
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- return //do not update_icon
-
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- update_icon()
-
-/obj/machinery/atmospherics/unary/outlet_injector/hide(var/i)
- update_underlays()
+//Basically a one way passive valve. If the pressure inside is greater than the environment then gas will flow passively,
+//but it does not permit gas to flow back from the environment into the injector. Can be turned off to prevent any gas flow.
+//When it receives the "inject" signal, it will try to pump it's entire contents into the environment regardless of pressure, using power.
+
+/obj/machinery/atmospherics/unary/outlet_injector
+ icon = 'icons/atmos/injector.dmi'
+ icon_state = "map_injector"
+ layer = 3
+
+ name = "air injector"
+ desc = "Passively injects air into its surroundings. Has a valve attached to it that can control flow rate."
+
+ use_power = 0
+ idle_power_usage = 150 //internal circuitry, friction losses and stuff
+ power_rating = 15000 //15000 W ~ 20 HP
+
+ var/injecting = 0
+
+ var/volume_rate = 50 //flow rate limit
+
+ var/frequency = 0
+ var/id = null
+ var/datum/radio_frequency/radio_connection
+
+ level = 1
+
+/obj/machinery/atmospherics/unary/outlet_injector/Initialize()
+ . = ..()
+ air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 500 //Give it a small reservoir for injecting. Also allows it to have a higher flow rate limit than vent pumps, to differentiate injectors a bit more.
+
+/obj/machinery/atmospherics/unary/outlet_injector/update_icon()
+ if(!powered())
+ icon_state = "off"
+ else
+ icon_state = "[use_power ? "on" : "off"]"
+
+/obj/machinery/atmospherics/unary/outlet_injector/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+ add_underlay(T, node, dir)
+
+/obj/machinery/atmospherics/unary/outlet_injector/power_change()
+ var/old_stat = stat
+ ..()
+ if(old_stat != stat)
+ update_icon()
+
+/obj/machinery/atmospherics/unary/outlet_injector/machinery_process()
+ ..()
+
+ last_power_draw = 0
+ last_flow_rate = 0
+
+ if((stat & (NOPOWER|BROKEN)) || !use_power)
+ return
+
+ var/power_draw = -1
+ var/datum/gas_mixture/environment = loc.return_air()
+
+ if(environment && air_contents.temperature > 0)
+ var/transfer_moles = (volume_rate/air_contents.volume)*air_contents.total_moles //apply flow rate limit
+ power_draw = pump_gas(src, air_contents, environment, transfer_moles, power_rating)
+
+ if (power_draw >= 0)
+ last_power_draw = power_draw
+ use_power(power_draw)
+
+ if(network)
+ network.update = 1
+
+ return 1
+
+/obj/machinery/atmospherics/unary/outlet_injector/proc/inject()
+ if(injecting || (stat & NOPOWER))
+ return 0
+
+ var/datum/gas_mixture/environment = loc.return_air()
+ if (!environment)
+ return 0
+
+ injecting = 1
+
+ if(air_contents.temperature > 0)
+ var/power_used = pump_gas(src, air_contents, environment, air_contents.total_moles, power_rating)
+ use_power(power_used)
+
+ if(network)
+ network.update = 1
+
+ flick("inject", src)
+
+/obj/machinery/atmospherics/unary/outlet_injector/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/unary/outlet_injector/proc/broadcast_status()
+ if(!radio_connection)
+ return 0
+
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.source = src
+
+ signal.data = list(
+ "tag" = id,
+ "device" = "AO",
+ "power" = use_power,
+ "volume_rate" = volume_rate,
+ "sigtype" = "status"
+ )
+
+ radio_connection.post_signal(src, signal)
+
+ return 1
+
+/obj/machinery/atmospherics/unary/outlet_injector/atmos_init()
+ ..()
+
+ set_frequency(frequency)
+
+/obj/machinery/atmospherics/unary/outlet_injector/receive_signal(datum/signal/signal)
+ if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
+ return 0
+
+ if(signal.data["power"])
+ use_power = text2num(signal.data["power"])
+
+ if(signal.data["power_toggle"])
+ use_power = !use_power
+
+ if(signal.data["inject"])
+ spawn inject()
+ return
+
+ if(signal.data["set_volume_rate"])
+ var/number = text2num(signal.data["set_volume_rate"])
+ volume_rate = between(0, number, air_contents.volume)
+
+ if(signal.data["status"])
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ return //do not update_icon
+
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ update_icon()
+
+/obj/machinery/atmospherics/unary/outlet_injector/hide(var/i)
+ update_underlays()
diff --git a/code/ATMOSPHERICS/components/unary/oxygen_generator.dm b/code/ATMOSPHERICS/components/unary/oxygen_generator.dm
index 3c48ed7d2ff..93207f310a7 100644
--- a/code/ATMOSPHERICS/components/unary/oxygen_generator.dm
+++ b/code/ATMOSPHERICS/components/unary/oxygen_generator.dm
@@ -1,48 +1,48 @@
-obj/machinery/atmospherics/unary/oxygen_generator
- icon = 'icons/obj/atmospherics/oxygen_generator.dmi'
- icon_state = "intact_off"
- density = 1
-
- name = "Oxygen Generator"
- desc = ""
-
- dir = SOUTH
- initialize_directions = SOUTH
-
- var/on = 0
-
- var/oxygen_content = 10
-
- update_icon()
- if(node)
- icon_state = "intact_[on?("on"):("off")]"
- else
- icon_state = "exposed_off"
-
- on = 0
-
- return
-
- Initialize()
- . = ..()
- air_contents.volume = 50
-
- machinery_process()
- ..()
- if(!on)
- return 0
-
- var/total_moles = air_contents.total_moles
-
- if(total_moles < oxygen_content)
- var/current_heat_capacity = air_contents.heat_capacity()
-
- var/added_oxygen = oxygen_content - total_moles
-
- air_contents.temperature = (current_heat_capacity*air_contents.temperature + 20*added_oxygen*T0C)/(current_heat_capacity+20*added_oxygen)
- air_contents.adjust_gas("oxygen", added_oxygen)
-
- if(network)
- network.update = 1
-
- return 1
+obj/machinery/atmospherics/unary/oxygen_generator
+ icon = 'icons/obj/atmospherics/oxygen_generator.dmi'
+ icon_state = "intact_off"
+ density = 1
+
+ name = "Oxygen Generator"
+ desc = ""
+
+ dir = SOUTH
+ initialize_directions = SOUTH
+
+ var/on = 0
+
+ var/oxygen_content = 10
+
+ update_icon()
+ if(node)
+ icon_state = "intact_[on?("on"):("off")]"
+ else
+ icon_state = "exposed_off"
+
+ on = 0
+
+ return
+
+ Initialize()
+ . = ..()
+ air_contents.volume = 50
+
+ machinery_process()
+ ..()
+ if(!on)
+ return 0
+
+ var/total_moles = air_contents.total_moles
+
+ if(total_moles < oxygen_content)
+ var/current_heat_capacity = air_contents.heat_capacity()
+
+ var/added_oxygen = oxygen_content - total_moles
+
+ air_contents.temperature = (current_heat_capacity*air_contents.temperature + 20*added_oxygen*T0C)/(current_heat_capacity+20*added_oxygen)
+ air_contents.adjust_gas("oxygen", added_oxygen)
+
+ if(network)
+ network.update = 1
+
+ return 1
diff --git a/code/ATMOSPHERICS/components/unary/unary_base.dm b/code/ATMOSPHERICS/components/unary/unary_base.dm
index e6681d010ca..1f232b1213a 100644
--- a/code/ATMOSPHERICS/components/unary/unary_base.dm
+++ b/code/ATMOSPHERICS/components/unary/unary_base.dm
@@ -1,102 +1,102 @@
-/obj/machinery/atmospherics/unary
- dir = SOUTH
- initialize_directions = SOUTH
- //layer = TURF_LAYER+0.1
-
- var/datum/gas_mixture/air_contents
-
- var/obj/machinery/atmospherics/node
-
- var/datum/pipe_network/network
-
- Initialize()
- initialize_directions = dir
- air_contents = new
- air_contents.volume = 200
- . = ..()
-
-// Housekeeping and pipe network stuff below
- network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
- if(reference == node)
- network = new_network
-
- if(new_network.normal_members.Find(src))
- return 0
-
- new_network.normal_members += src
-
- return null
-
- Destroy()
- QDEL_NULL(air_contents)
-
- if(node)
- node.disconnect(src)
- QDEL_NULL(network)
-
- node = null
-
- return ..()
-
- atmos_init()
- if(node) return
-
- var/node_connect = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node = target
- break
-
- update_icon()
- update_underlays()
-
- build_network()
- if(!network && node)
- network = new /datum/pipe_network()
- network.normal_members += src
- network.build_network(node, src)
-
-
- return_network(obj/machinery/atmospherics/reference)
- build_network()
-
- if(reference==node)
- return network
-
- return null
-
- reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
- if(network == old_network)
- network = new_network
-
- return 1
-
- return_network_air(datum/pipe_network/reference)
- var/list/results = list()
-
- if(network == reference)
- results += air_contents
-
- return results
-
- disconnect(obj/machinery/atmospherics/reference)
- if(reference==node)
- qdel(network)
- node = null
-
- update_icon()
- update_underlays()
-
- return null
-
-/obj/machinery/atmospherics/unary/vent_pump/proc/is_welded() // TODO: refactor welding into unary
- if (welded > 0)
- return 1
- return 0
-
-/obj/machinery/atmospherics/unary/vent_scrubber/proc/is_welded()
- if (welded > 0)
- return 1
- return 0
+/obj/machinery/atmospherics/unary
+ dir = SOUTH
+ initialize_directions = SOUTH
+ //layer = TURF_LAYER+0.1
+
+ var/datum/gas_mixture/air_contents
+
+ var/obj/machinery/atmospherics/node
+
+ var/datum/pipe_network/network
+
+ Initialize()
+ initialize_directions = dir
+ air_contents = new
+ air_contents.volume = 200
+ . = ..()
+
+// Housekeeping and pipe network stuff below
+ network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+ if(reference == node)
+ network = new_network
+
+ if(new_network.normal_members.Find(src))
+ return 0
+
+ new_network.normal_members += src
+
+ return null
+
+ Destroy()
+ QDEL_NULL(air_contents)
+
+ if(node)
+ node.disconnect(src)
+ QDEL_NULL(network)
+
+ node = null
+
+ return ..()
+
+ atmos_init()
+ if(node) return
+
+ var/node_connect = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node = target
+ break
+
+ update_icon()
+ update_underlays()
+
+ build_network()
+ if(!network && node)
+ network = new /datum/pipe_network()
+ network.normal_members += src
+ network.build_network(node, src)
+
+
+ return_network(obj/machinery/atmospherics/reference)
+ build_network()
+
+ if(reference==node)
+ return network
+
+ return null
+
+ reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
+ if(network == old_network)
+ network = new_network
+
+ return 1
+
+ return_network_air(datum/pipe_network/reference)
+ var/list/results = list()
+
+ if(network == reference)
+ results += air_contents
+
+ return results
+
+ disconnect(obj/machinery/atmospherics/reference)
+ if(reference==node)
+ qdel(network)
+ node = null
+
+ update_icon()
+ update_underlays()
+
+ return null
+
+/obj/machinery/atmospherics/unary/vent_pump/proc/is_welded() // TODO: refactor welding into unary
+ if (welded > 0)
+ return 1
+ return 0
+
+/obj/machinery/atmospherics/unary/vent_scrubber/proc/is_welded()
+ if (welded > 0)
+ return 1
+ return 0
diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm
index 91eaccc1b45..044ee2ae0a8 100644
--- a/code/ATMOSPHERICS/components/unary/vent_pump.dm
+++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm
@@ -1,426 +1,426 @@
-#define DEFAULT_PRESSURE_DELTA 10000
-
-#define EXTERNAL_PRESSURE_BOUND ONE_ATMOSPHERE
-#define INTERNAL_PRESSURE_BOUND 0
-#define PRESSURE_CHECKS 1
-
-#define PRESSURE_CHECK_EXTERNAL 1
-#define PRESSURE_CHECK_INTERNAL 2
-
-/obj/machinery/atmospherics/unary/vent_pump
- icon = 'icons/atmos/vent_pump.dmi'
- icon_state = "map_vent"
-
- name = "Air Vent"
- desc = "Has a valve and pump attached to it"
- use_power = 0
- idle_power_usage = 150 //internal circuitry, friction losses and stuff
- power_rating = 7500 //7500 W ~ 10 HP
-
- connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY //connects to regular and supply pipes
-
- var/area/initial_loc
- level = 1
- var/area_uid
- var/id_tag = null
-
- var/hibernate = 0 //Do we even process?
- var/pump_direction = 1 //0 = siphoning, 1 = releasing
-
- var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
- var/internal_pressure_bound = INTERNAL_PRESSURE_BOUND
-
- var/pressure_checks = PRESSURE_CHECKS
- //1: Do not pass external_pressure_bound
- //2: Do not pass internal_pressure_bound
- //3: Do not pass either
-
- // Used when handling incoming radio signals requesting default settings
- var/external_pressure_bound_default = EXTERNAL_PRESSURE_BOUND
- var/internal_pressure_bound_default = INTERNAL_PRESSURE_BOUND
- var/pressure_checks_default = PRESSURE_CHECKS
-
- var/welded = 0 // Added for aliens -- TLE
-
- var/frequency = 1439
- var/datum/radio_frequency/radio_connection
-
- var/radio_filter_out
- var/radio_filter_in
-
-/obj/machinery/atmospherics/unary/vent_pump/on
- use_power = 1
- icon_state = "map_vent_out"
-
-/obj/machinery/atmospherics/unary/vent_pump/siphon
- pump_direction = 0
-
-/obj/machinery/atmospherics/unary/vent_pump/siphon/on
- use_power = 1
- icon_state = "map_vent_in"
-
-/obj/machinery/atmospherics/unary/vent_pump/siphon/on/atmos
- use_power = 1
- icon_state = "map_vent_in"
- external_pressure_bound = 0
- external_pressure_bound_default = 0
- internal_pressure_bound = 2000
- internal_pressure_bound_default = 2000
- pressure_checks = 2
- pressure_checks_default = 2
-
-/obj/machinery/atmospherics/unary/vent_pump/Initialize()
- . = ..()
- air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP
-
- initial_loc = loc.loc
- area_uid = initial_loc.uid
- if (!id_tag)
- assign_uid()
- id_tag = num2text(uid)
-
- //some vents work his own special way
- radio_filter_in = frequency == 1439 ? (RADIO_FROM_AIRALARM) : null
- radio_filter_out = frequency == 1439 ? (RADIO_TO_AIRALARM) : null
- if(frequency)
- radio_connection = register_radio(src, frequency, frequency, radio_filter_in)
-
-// Different from the above.
-/obj/machinery/atmospherics/unary/vent_pump/atmos_init()
- ..()
- broadcast_status()
-
-/obj/machinery/atmospherics/unary/vent_pump/Destroy()
- unregister_radio(src, frequency)
- return ..()
-
-/obj/machinery/atmospherics/unary/vent_pump/high_volume
- name = "Large Air Vent"
- power_channel = EQUIP
- power_rating = 15000 //15 kW ~ 20 HP
-
-/obj/machinery/atmospherics/unary/vent_pump/high_volume/Initialize()
- . = ..()
- air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
-
-/obj/machinery/atmospherics/unary/vent_pump/engine
- name = "Engine Core Vent"
- power_channel = ENVIRON
- power_rating = 30000 //15 kW ~ 20 HP
-
-/obj/machinery/atmospherics/unary/vent_pump/engine/Initialize()
- . = ..()
- air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 500 //meant to match air injector
-
-/obj/machinery/atmospherics/unary/vent_pump/update_icon(var/safety = 0)
- if (!node)
- use_power = 0
-
- var/vent_icon = ""
-
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
-
- if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
- vent_icon += "h"
-
- if(welded)
- vent_icon += "weld"
- else if(!powered())
- vent_icon += "off"
- else
- vent_icon += "[use_power ? "[pump_direction ? "out" : "in"]" : "off"]"
-
- icon_state = vent_icon
-
- update_underlays()
-
-/obj/machinery/atmospherics/unary/vent_pump/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
- if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
- return
- else
- if(node)
- add_underlay(T, node, dir, node.icon_connect_type)
- else
- add_underlay(T,, dir)
-
-/obj/machinery/atmospherics/unary/vent_pump/hide()
- queue_icon_update()
-
-/obj/machinery/atmospherics/unary/vent_pump/proc/can_pump()
- if(stat & (NOPOWER|BROKEN))
- return 0
- if(!use_power)
- return 0
- if(welded)
- return 0
- return 1
-
-/obj/machinery/atmospherics/unary/vent_pump/machinery_process()
- ..()
-
- if (hibernate > world.time)
- return 1
-
- if (!node)
- use_power = 0
- if(!can_pump())
- return 0
-
- var/datum/gas_mixture/environment = loc.return_air()
-
- var/power_draw = -1
-
- //Figure out the target pressure difference
- var/pressure_delta = get_pressure_delta(environment)
- //src.visible_message("DEBUG >>> [src]: pressure_delta = [pressure_delta]")
-
- if((environment.temperature || air_contents.temperature) && pressure_delta > 0.5)
- if(pump_direction) //internal -> external
- var/transfer_moles = calculate_transfer_moles(air_contents, environment, pressure_delta)
- power_draw = pump_gas(src, air_contents, environment, transfer_moles, power_rating)
- else //external -> internal
- var/transfer_moles = calculate_transfer_moles(environment, air_contents, pressure_delta, (network)? network.volume : 0)
-
- //limit flow rate from turfs
- transfer_moles = min(transfer_moles, environment.total_moles*air_contents.volume/environment.volume) //group_multiplier gets divided out here
- power_draw = pump_gas(src, environment, air_contents, transfer_moles, power_rating)
-
- else
- //If we're in an area that is fucking ideal, and we don't have to do anything, chances are we won't next tick either so why redo these calculations?
- //JESUS FUCK. THERE ARE LITERALLY 250 OF YOU MOTHERFUCKERS ON ZLEVEL ONE AND YOU DO THIS SHIT EVERY TICK WHEN VERY OFTEN THERE IS NO REASON TO
- if(pump_direction && pressure_checks == PRESSURE_CHECK_EXTERNAL) //99% of all vents
- hibernate = world.time + (rand(100,200))
-
-
- if (power_draw >= 0)
- last_power_draw = power_draw
- use_power(power_draw)
- if(network)
- network.update = 1
-
- return 1
-
-/obj/machinery/atmospherics/unary/vent_pump/proc/get_pressure_delta(datum/gas_mixture/environment)
- var/pressure_delta = DEFAULT_PRESSURE_DELTA
- var/environment_pressure = environment.return_pressure()
-
- if(pump_direction) //internal -> external
- if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
- pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here
- if(pressure_checks & PRESSURE_CHECK_INTERNAL)
- pressure_delta = min(pressure_delta, air_contents.return_pressure() - internal_pressure_bound) //decreasing the pressure here
- else //external -> internal
- if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
- pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here
- if(pressure_checks & PRESSURE_CHECK_INTERNAL)
- pressure_delta = min(pressure_delta, internal_pressure_bound - air_contents.return_pressure()) //increasing the pressure here
-
- return pressure_delta
-
-/obj/machinery/atmospherics/unary/vent_pump/proc/broadcast_status()
- if(!radio_connection)
- return 0
-
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.source = src
-
- signal.data = list(
- "area" = src.area_uid,
- "tag" = src.id_tag,
- "device" = "AVP",
- "power" = use_power,
- "direction" = pump_direction?("release"):("siphon"),
- "checks" = pressure_checks,
- "internal" = internal_pressure_bound,
- "external" = external_pressure_bound,
- "timestamp" = world.time,
- "sigtype" = "status",
- "power_draw" = last_power_draw,
- "flow_rate" = last_flow_rate
- )
-
- var/area/A = get_area(src)
- if(!A.air_vent_names[id_tag])
- var/new_name = "[A.name] Vent Pump #[A.air_vent_names.len+1]"
- A.air_vent_names[id_tag] = new_name
- src.name = new_name
- A.air_vent_info[id_tag] = signal.data
-
- radio_connection.post_signal(src, signal, radio_filter_out)
-
- return 1
-
-/obj/machinery/atmospherics/unary/vent_pump/receive_signal(datum/signal/signal)
- if(stat & (NOPOWER|BROKEN))
- return
-
- hibernate = 0
-
- //log_debug("DEBUG \[[world.timeofday]\]: /obj/machinery/atmospherics/unary/vent_pump/receive_signal([signal.debug_print()])")
- if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
- return 0
-
- if(signal.data["purge"] != null)
- pressure_checks &= ~1
- pump_direction = 0
-
- if(signal.data["stabalize"] != null)
- pressure_checks |= 1
- pump_direction = 1
-
- if(signal.data["power"] != null)
- use_power = text2num(signal.data["power"])
-
- if(signal.data["power_toggle"] != null)
- use_power = !use_power
-
- if(signal.data["checks"] != null)
- if (signal.data["checks"] == "default")
- pressure_checks = pressure_checks_default
- else
- pressure_checks = text2num(signal.data["checks"])
-
- if(signal.data["checks_toggle"] != null)
- pressure_checks = (pressure_checks?0:3)
-
- if(signal.data["direction"] != null)
- pump_direction = text2num(signal.data["direction"])
-
- if(signal.data["set_internal_pressure"] != null)
- if (signal.data["set_internal_pressure"] == "default")
- internal_pressure_bound = internal_pressure_bound_default
- else
- internal_pressure_bound = between(
- 0,
- text2num(signal.data["set_internal_pressure"]),
- ONE_ATMOSPHERE*50
- )
-
- if(signal.data["set_external_pressure"] != null)
- if (signal.data["set_external_pressure"] == "default")
- external_pressure_bound = external_pressure_bound_default
- else
- external_pressure_bound = between(
- 0,
- text2num(signal.data["set_external_pressure"]),
- ONE_ATMOSPHERE*50
- )
-
- if(signal.data["adjust_internal_pressure"] != null)
- internal_pressure_bound = between(
- 0,
- internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]),
- ONE_ATMOSPHERE*50
- )
-
- if(signal.data["adjust_external_pressure"] != null)
-
-
- external_pressure_bound = between(
- 0,
- external_pressure_bound + text2num(signal.data["adjust_external_pressure"]),
- ONE_ATMOSPHERE*50
- )
-
- if(signal.data["init"] != null)
- name = signal.data["init"]
- return
-
- if(signal.data["status"] != null)
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- return //do not update_icon
-
- //log_debug("DEBUG \[[world.timeofday]\]: vent_pump/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]")
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
-
- update_icon()
- return
-
-/obj/machinery/atmospherics/unary/vent_pump/attackby(obj/item/W, mob/user)
- if(W.iswelder())
- var/obj/item/weldingtool/WT = W
- if (!WT.welding)
- to_chat(user, "\The [WT] must be turned on!")
- else if (WT.remove_fuel(0,user))
- to_chat(user, "Now welding the vent.")
- if(do_after(user, 30/W.toolspeed))
- if(!src || !WT.isOn()) return
- playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
- if(!welded)
- user.visible_message("\The [user] welds \the [src] shut.", "You weld \the [src] shut.", "You hear welding.")
- welded = 1
- update_icon()
- else
- user.visible_message("[user] unwelds \the [src].", "You unweld \the [src].", "You hear welding.")
- welded = 0
- update_icon()
- else
- to_chat(user, "You fail to complete the welding.")
- else
- to_chat(user, "You need more welding fuel to complete this task.")
- return 1
- else
- ..()
-
-/obj/machinery/atmospherics/unary/vent_pump/examine(mob/user)
- if(..(user, 1))
- to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W")
- else
- to_chat(user, "You are too far away to read the gauge.")
- if(welded)
- to_chat(user, "It seems welded shut.")
-
-/obj/machinery/atmospherics/unary/vent_pump/power_change()
- var/old_stat = stat
- ..()
- if(old_stat != stat)
- update_icon()
-
-/obj/machinery/atmospherics/unary/vent_pump/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if (!W.iswrench())
- return ..()
- if (!(stat & NOPOWER) && use_power)
- to_chat(user, "You cannot unwrench \the [src], turn it off first.")
- return 1
- var/turf/T = src.loc
- if (node && node.level==1 && isturf(T) && !T.is_plating())
- to_chat(user, "You must remove the plating first.")
- return 1
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
- if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
- to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- playsound(src.loc, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, 40/W.toolspeed))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear a ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- qdel(src)
-
-/obj/machinery/atmospherics/unary/vent_pump/Destroy()
- if(initial_loc)
- initial_loc.air_vent_info -= id_tag
- initial_loc.air_vent_names -= id_tag
- return ..()
-
-#undef DEFAULT_PRESSURE_DELTA
-
-#undef EXTERNAL_PRESSURE_BOUND
-#undef INTERNAL_PRESSURE_BOUND
-#undef PRESSURE_CHECKS
-
-#undef PRESSURE_CHECK_EXTERNAL
-#undef PRESSURE_CHECK_INTERNAL
+#define DEFAULT_PRESSURE_DELTA 10000
+
+#define EXTERNAL_PRESSURE_BOUND ONE_ATMOSPHERE
+#define INTERNAL_PRESSURE_BOUND 0
+#define PRESSURE_CHECKS 1
+
+#define PRESSURE_CHECK_EXTERNAL 1
+#define PRESSURE_CHECK_INTERNAL 2
+
+/obj/machinery/atmospherics/unary/vent_pump
+ icon = 'icons/atmos/vent_pump.dmi'
+ icon_state = "map_vent"
+
+ name = "Air Vent"
+ desc = "Has a valve and pump attached to it"
+ use_power = 0
+ idle_power_usage = 150 //internal circuitry, friction losses and stuff
+ power_rating = 7500 //7500 W ~ 10 HP
+
+ connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY //connects to regular and supply pipes
+
+ var/area/initial_loc
+ level = 1
+ var/area_uid
+ var/id_tag = null
+
+ var/hibernate = 0 //Do we even process?
+ var/pump_direction = 1 //0 = siphoning, 1 = releasing
+
+ var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
+ var/internal_pressure_bound = INTERNAL_PRESSURE_BOUND
+
+ var/pressure_checks = PRESSURE_CHECKS
+ //1: Do not pass external_pressure_bound
+ //2: Do not pass internal_pressure_bound
+ //3: Do not pass either
+
+ // Used when handling incoming radio signals requesting default settings
+ var/external_pressure_bound_default = EXTERNAL_PRESSURE_BOUND
+ var/internal_pressure_bound_default = INTERNAL_PRESSURE_BOUND
+ var/pressure_checks_default = PRESSURE_CHECKS
+
+ var/welded = 0 // Added for aliens -- TLE
+
+ var/frequency = 1439
+ var/datum/radio_frequency/radio_connection
+
+ var/radio_filter_out
+ var/radio_filter_in
+
+/obj/machinery/atmospherics/unary/vent_pump/on
+ use_power = 1
+ icon_state = "map_vent_out"
+
+/obj/machinery/atmospherics/unary/vent_pump/siphon
+ pump_direction = 0
+
+/obj/machinery/atmospherics/unary/vent_pump/siphon/on
+ use_power = 1
+ icon_state = "map_vent_in"
+
+/obj/machinery/atmospherics/unary/vent_pump/siphon/on/atmos
+ use_power = 1
+ icon_state = "map_vent_in"
+ external_pressure_bound = 0
+ external_pressure_bound_default = 0
+ internal_pressure_bound = 2000
+ internal_pressure_bound_default = 2000
+ pressure_checks = 2
+ pressure_checks_default = 2
+
+/obj/machinery/atmospherics/unary/vent_pump/Initialize()
+ . = ..()
+ air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP
+
+ initial_loc = loc.loc
+ area_uid = initial_loc.uid
+ if (!id_tag)
+ assign_uid()
+ id_tag = num2text(uid)
+
+ //some vents work his own special way
+ radio_filter_in = frequency == 1439 ? (RADIO_FROM_AIRALARM) : null
+ radio_filter_out = frequency == 1439 ? (RADIO_TO_AIRALARM) : null
+ if(frequency)
+ radio_connection = register_radio(src, frequency, frequency, radio_filter_in)
+
+// Different from the above.
+/obj/machinery/atmospherics/unary/vent_pump/atmos_init()
+ ..()
+ broadcast_status()
+
+/obj/machinery/atmospherics/unary/vent_pump/Destroy()
+ unregister_radio(src, frequency)
+ return ..()
+
+/obj/machinery/atmospherics/unary/vent_pump/high_volume
+ name = "Large Air Vent"
+ power_channel = EQUIP
+ power_rating = 15000 //15 kW ~ 20 HP
+
+/obj/machinery/atmospherics/unary/vent_pump/high_volume/Initialize()
+ . = ..()
+ air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
+
+/obj/machinery/atmospherics/unary/vent_pump/engine
+ name = "Engine Core Vent"
+ power_channel = ENVIRON
+ power_rating = 30000 //15 kW ~ 20 HP
+
+/obj/machinery/atmospherics/unary/vent_pump/engine/Initialize()
+ . = ..()
+ air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 500 //meant to match air injector
+
+/obj/machinery/atmospherics/unary/vent_pump/update_icon(var/safety = 0)
+ if (!node)
+ use_power = 0
+
+ var/vent_icon = ""
+
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+
+ if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
+ vent_icon += "h"
+
+ if(welded)
+ vent_icon += "weld"
+ else if(!powered())
+ vent_icon += "off"
+ else
+ vent_icon += "[use_power ? "[pump_direction ? "out" : "in"]" : "off"]"
+
+ icon_state = vent_icon
+
+ update_underlays()
+
+/obj/machinery/atmospherics/unary/vent_pump/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+ if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
+ return
+ else
+ if(node)
+ add_underlay(T, node, dir, node.icon_connect_type)
+ else
+ add_underlay(T,, dir)
+
+/obj/machinery/atmospherics/unary/vent_pump/hide()
+ queue_icon_update()
+
+/obj/machinery/atmospherics/unary/vent_pump/proc/can_pump()
+ if(stat & (NOPOWER|BROKEN))
+ return 0
+ if(!use_power)
+ return 0
+ if(welded)
+ return 0
+ return 1
+
+/obj/machinery/atmospherics/unary/vent_pump/machinery_process()
+ ..()
+
+ if (hibernate > world.time)
+ return 1
+
+ if (!node)
+ use_power = 0
+ if(!can_pump())
+ return 0
+
+ var/datum/gas_mixture/environment = loc.return_air()
+
+ var/power_draw = -1
+
+ //Figure out the target pressure difference
+ var/pressure_delta = get_pressure_delta(environment)
+ //src.visible_message("DEBUG >>> [src]: pressure_delta = [pressure_delta]")
+
+ if((environment.temperature || air_contents.temperature) && pressure_delta > 0.5)
+ if(pump_direction) //internal -> external
+ var/transfer_moles = calculate_transfer_moles(air_contents, environment, pressure_delta)
+ power_draw = pump_gas(src, air_contents, environment, transfer_moles, power_rating)
+ else //external -> internal
+ var/transfer_moles = calculate_transfer_moles(environment, air_contents, pressure_delta, (network)? network.volume : 0)
+
+ //limit flow rate from turfs
+ transfer_moles = min(transfer_moles, environment.total_moles*air_contents.volume/environment.volume) //group_multiplier gets divided out here
+ power_draw = pump_gas(src, environment, air_contents, transfer_moles, power_rating)
+
+ else
+ //If we're in an area that is fucking ideal, and we don't have to do anything, chances are we won't next tick either so why redo these calculations?
+ //JESUS FUCK. THERE ARE LITERALLY 250 OF YOU MOTHERFUCKERS ON ZLEVEL ONE AND YOU DO THIS SHIT EVERY TICK WHEN VERY OFTEN THERE IS NO REASON TO
+ if(pump_direction && pressure_checks == PRESSURE_CHECK_EXTERNAL) //99% of all vents
+ hibernate = world.time + (rand(100,200))
+
+
+ if (power_draw >= 0)
+ last_power_draw = power_draw
+ use_power(power_draw)
+ if(network)
+ network.update = 1
+
+ return 1
+
+/obj/machinery/atmospherics/unary/vent_pump/proc/get_pressure_delta(datum/gas_mixture/environment)
+ var/pressure_delta = DEFAULT_PRESSURE_DELTA
+ var/environment_pressure = environment.return_pressure()
+
+ if(pump_direction) //internal -> external
+ if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
+ pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here
+ if(pressure_checks & PRESSURE_CHECK_INTERNAL)
+ pressure_delta = min(pressure_delta, air_contents.return_pressure() - internal_pressure_bound) //decreasing the pressure here
+ else //external -> internal
+ if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
+ pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here
+ if(pressure_checks & PRESSURE_CHECK_INTERNAL)
+ pressure_delta = min(pressure_delta, internal_pressure_bound - air_contents.return_pressure()) //increasing the pressure here
+
+ return pressure_delta
+
+/obj/machinery/atmospherics/unary/vent_pump/proc/broadcast_status()
+ if(!radio_connection)
+ return 0
+
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.source = src
+
+ signal.data = list(
+ "area" = src.area_uid,
+ "tag" = src.id_tag,
+ "device" = "AVP",
+ "power" = use_power,
+ "direction" = pump_direction?("release"):("siphon"),
+ "checks" = pressure_checks,
+ "internal" = internal_pressure_bound,
+ "external" = external_pressure_bound,
+ "timestamp" = world.time,
+ "sigtype" = "status",
+ "power_draw" = last_power_draw,
+ "flow_rate" = last_flow_rate
+ )
+
+ var/area/A = get_area(src)
+ if(!A.air_vent_names[id_tag])
+ var/new_name = "[A.name] Vent Pump #[A.air_vent_names.len+1]"
+ A.air_vent_names[id_tag] = new_name
+ src.name = new_name
+ A.air_vent_info[id_tag] = signal.data
+
+ radio_connection.post_signal(src, signal, radio_filter_out)
+
+ return 1
+
+/obj/machinery/atmospherics/unary/vent_pump/receive_signal(datum/signal/signal)
+ if(stat & (NOPOWER|BROKEN))
+ return
+
+ hibernate = 0
+
+ //log_debug("DEBUG \[[world.timeofday]\]: /obj/machinery/atmospherics/unary/vent_pump/receive_signal([signal.debug_print()])")
+ if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
+ return 0
+
+ if(signal.data["purge"] != null)
+ pressure_checks &= ~1
+ pump_direction = 0
+
+ if(signal.data["stabalize"] != null)
+ pressure_checks |= 1
+ pump_direction = 1
+
+ if(signal.data["power"] != null)
+ use_power = text2num(signal.data["power"])
+
+ if(signal.data["power_toggle"] != null)
+ use_power = !use_power
+
+ if(signal.data["checks"] != null)
+ if (signal.data["checks"] == "default")
+ pressure_checks = pressure_checks_default
+ else
+ pressure_checks = text2num(signal.data["checks"])
+
+ if(signal.data["checks_toggle"] != null)
+ pressure_checks = (pressure_checks?0:3)
+
+ if(signal.data["direction"] != null)
+ pump_direction = text2num(signal.data["direction"])
+
+ if(signal.data["set_internal_pressure"] != null)
+ if (signal.data["set_internal_pressure"] == "default")
+ internal_pressure_bound = internal_pressure_bound_default
+ else
+ internal_pressure_bound = between(
+ 0,
+ text2num(signal.data["set_internal_pressure"]),
+ ONE_ATMOSPHERE*50
+ )
+
+ if(signal.data["set_external_pressure"] != null)
+ if (signal.data["set_external_pressure"] == "default")
+ external_pressure_bound = external_pressure_bound_default
+ else
+ external_pressure_bound = between(
+ 0,
+ text2num(signal.data["set_external_pressure"]),
+ ONE_ATMOSPHERE*50
+ )
+
+ if(signal.data["adjust_internal_pressure"] != null)
+ internal_pressure_bound = between(
+ 0,
+ internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]),
+ ONE_ATMOSPHERE*50
+ )
+
+ if(signal.data["adjust_external_pressure"] != null)
+
+
+ external_pressure_bound = between(
+ 0,
+ external_pressure_bound + text2num(signal.data["adjust_external_pressure"]),
+ ONE_ATMOSPHERE*50
+ )
+
+ if(signal.data["init"] != null)
+ name = signal.data["init"]
+ return
+
+ if(signal.data["status"] != null)
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ return //do not update_icon
+
+ //log_debug("DEBUG \[[world.timeofday]\]: vent_pump/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]")
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+
+ update_icon()
+ return
+
+/obj/machinery/atmospherics/unary/vent_pump/attackby(obj/item/W, mob/user)
+ if(W.iswelder())
+ var/obj/item/weldingtool/WT = W
+ if (!WT.welding)
+ to_chat(user, "\The [WT] must be turned on!")
+ else if (WT.remove_fuel(0,user))
+ to_chat(user, "Now welding the vent.")
+ if(do_after(user, 30/W.toolspeed))
+ if(!src || !WT.isOn()) return
+ playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
+ if(!welded)
+ user.visible_message("\The [user] welds \the [src] shut.", "You weld \the [src] shut.", "You hear welding.")
+ welded = 1
+ update_icon()
+ else
+ user.visible_message("[user] unwelds \the [src].", "You unweld \the [src].", "You hear welding.")
+ welded = 0
+ update_icon()
+ else
+ to_chat(user, "You fail to complete the welding.")
+ else
+ to_chat(user, "You need more welding fuel to complete this task.")
+ return 1
+ else
+ ..()
+
+/obj/machinery/atmospherics/unary/vent_pump/examine(mob/user)
+ if(..(user, 1))
+ to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W")
+ else
+ to_chat(user, "You are too far away to read the gauge.")
+ if(welded)
+ to_chat(user, "It seems welded shut.")
+
+/obj/machinery/atmospherics/unary/vent_pump/power_change()
+ var/old_stat = stat
+ ..()
+ if(old_stat != stat)
+ update_icon()
+
+/obj/machinery/atmospherics/unary/vent_pump/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if (!W.iswrench())
+ return ..()
+ if (!(stat & NOPOWER) && use_power)
+ to_chat(user, "You cannot unwrench \the [src], turn it off first.")
+ return 1
+ var/turf/T = src.loc
+ if (node && node.level==1 && isturf(T) && !T.is_plating())
+ to_chat(user, "You must remove the plating first.")
+ return 1
+ var/datum/gas_mixture/int_air = return_air()
+ var/datum/gas_mixture/env_air = loc.return_air()
+ if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
+ to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ playsound(src.loc, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, 40/W.toolspeed))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear a ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ qdel(src)
+
+/obj/machinery/atmospherics/unary/vent_pump/Destroy()
+ if(initial_loc)
+ initial_loc.air_vent_info -= id_tag
+ initial_loc.air_vent_names -= id_tag
+ return ..()
+
+#undef DEFAULT_PRESSURE_DELTA
+
+#undef EXTERNAL_PRESSURE_BOUND
+#undef INTERNAL_PRESSURE_BOUND
+#undef PRESSURE_CHECKS
+
+#undef PRESSURE_CHECK_EXTERNAL
+#undef PRESSURE_CHECK_INTERNAL
diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm
index 7b5be101af0..ffb55d58584 100644
--- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm
+++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm
@@ -1,318 +1,318 @@
-/obj/machinery/atmospherics/unary/vent_scrubber
- icon = 'icons/atmos/vent_scrubber.dmi'
- icon_state = "map_scrubber_off"
-
- name = "Air Scrubber"
- desc = "Has a valve and pump attached to it"
- use_power = 0
- idle_power_usage = 150 //internal circuitry, friction losses and stuff
- power_rating = 7500 //7500 W ~ 10 HP
-
- connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SCRUBBER //connects to regular and scrubber pipes
-
- level = 1
-
- var/area/initial_loc
- var/id_tag = null
- var/frequency = 1439
- var/datum/radio_frequency/radio_connection
-
- var/hibernate = 0 //Do we even process?
- var/scrubbing = 1 //0 = siphoning, 1 = scrubbing
- var/list/scrubbing_gas = list("carbon_dioxide")
-
- var/panic = 0 //is this scrubber panicked?
-
- var/area_uid
- var/radio_filter_out
- var/radio_filter_in
-
- var/welded = 0
-
-/obj/machinery/atmospherics/unary/vent_scrubber/on
- use_power = 1
- icon_state = "map_scrubber_on"
-
-/obj/machinery/atmospherics/unary/vent_scrubber/Initialize()
- . = ..()
- air_contents.volume = ATMOS_DEFAULT_VOLUME_FILTER
-
- initial_loc = get_area(loc)
- area_uid = initial_loc.uid
- if (!id_tag)
- assign_uid()
- id_tag = num2text(uid)
-
- 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)
-
-/obj/machinery/atmospherics/unary/vent_scrubber/atmos_init()
- ..()
- broadcast_status()
-
-/obj/machinery/atmospherics/unary/vent_scrubber/Destroy()
- unregister_radio(src, frequency)
- return ..()
-
-/obj/machinery/atmospherics/unary/vent_scrubber/update_icon(var/safety = 0)
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
-
- if (welded)
- icon_state = "weld"
- return
-
- if (!powered() || !use_power)
- icon_state = "off"
- else if (scrubbing)
- icon_state = "on"
- else
- icon_state = "in"
-
-/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
- if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
- return
- else
- if(node)
- add_underlay(T, node, dir, node.icon_connect_type)
- else
- add_underlay(T,, dir)
-
-/obj/machinery/atmospherics/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/unary/vent_scrubber/proc/broadcast_status()
- if(!radio_connection)
- return 0
-
- var/datum/signal/signal = new
- signal.transmission_method = 1 //radio signal
- signal.source = src
- signal.data = list(
- "area" = area_uid,
- "tag" = id_tag,
- "device" = "AScr",
- "timestamp" = world.time,
- "power" = use_power,
- "scrubbing" = scrubbing,
- "panic" = panic,
- "filter_o2" = ("oxygen" in scrubbing_gas),
- "filter_n2" = ("nitrogen" in scrubbing_gas),
- "filter_co2" = ("carbon_dioxide" in scrubbing_gas),
- "filter_phoron" = ("phoron" in scrubbing_gas),
- "filter_n2o" = ("sleeping_agent" in scrubbing_gas),
- "sigtype" = "status"
- )
-
- var/area/A = get_area(src)
- if(!A.air_scrub_names[id_tag])
- var/new_name = "[A.name] Air Scrubber #[A.air_scrub_names.len+1]"
- A.air_scrub_names[id_tag] = new_name
- src.name = new_name
- A.air_scrub_info[id_tag] = signal.data
- radio_connection.post_signal(src, signal, radio_filter_out)
-
- return 1
-
-/obj/machinery/atmospherics/unary/vent_scrubber/machinery_process()
- ..()
-
- if (hibernate > world.time)
- return 1
-
- if (!node)
- use_power = 0
- //broadcast_status()
- if(!use_power || (stat & (NOPOWER|BROKEN)))
- return 0
- if(welded)
- return 0
-
- var/datum/gas_mixture/environment = loc.return_air()
-
- var/power_draw = -1
- if(scrubbing)
- //limit flow rate from turfs
- var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SCRUBBER_FLOWRATE/environment.volume) //group_multiplier gets divided out here
-
- power_draw = scrub_gas(src, scrubbing_gas, environment, air_contents, transfer_moles, power_rating)
- else //Just siphon all air
- //limit flow rate from turfs
- var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SIPHON_FLOWRATE/environment.volume) //group_multiplier gets divided out here
-
- power_draw = pump_gas(src, environment, air_contents, transfer_moles, power_rating)
-
- if(scrubbing && power_draw <= 0) //99% of all scrubbers
- //Fucking hibernate because you ain't doing shit.
- hibernate = world.time + (rand(100,200))
-
- if (power_draw >= 0)
- last_power_draw = power_draw
- use_power(power_draw)
-
- if(network)
- network.update = 1
-
- return 1
-
-/obj/machinery/atmospherics/unary/vent_scrubber/hide(var/i) //to make the little pipe section invisible, the icon changes.
- update_icon()
- update_underlays()
-
-/obj/machinery/atmospherics/unary/vent_scrubber/receive_signal(datum/signal/signal)
- if(stat & (NOPOWER|BROKEN))
- return
- if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
- return 0
-
- if(signal.data["power"] != null)
- use_power = text2num(signal.data["power"])
- if(signal.data["power_toggle"] != null)
- use_power = !use_power
-
- if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing
- panic = text2num(signal.data["panic_siphon"])
- if(panic)
- use_power = 1
- scrubbing = 0
- else
- scrubbing = 1
- if(signal.data["toggle_panic_siphon"] != null)
- panic = !panic
- if(panic)
- use_power = 1
- scrubbing = 0
- else
- scrubbing = 1
-
- if(signal.data["scrubbing"] != null)
- scrubbing = text2num(signal.data["scrubbing"])
- if(scrubbing)
- panic = 0
- if(signal.data["toggle_scrubbing"])
- scrubbing = !scrubbing
- if(scrubbing)
- panic = 0
-
- var/list/toggle = list()
-
- if(!isnull(signal.data["o2_scrub"]) && text2num(signal.data["o2_scrub"]) != ("oxygen" in scrubbing_gas))
- toggle += "oxygen"
- else if(signal.data["toggle_o2_scrub"])
- toggle += "oxygen"
-
- if(!isnull(signal.data["n2_scrub"]) && text2num(signal.data["n2_scrub"]) != ("nitrogen" in scrubbing_gas))
- toggle += "nitrogen"
- else if(signal.data["toggle_n2_scrub"])
- toggle += "nitrogen"
-
- if(!isnull(signal.data["co2_scrub"]) && text2num(signal.data["co2_scrub"]) != ("carbon_dioxide" in scrubbing_gas))
- toggle += "carbon_dioxide"
- else if(signal.data["toggle_co2_scrub"])
- toggle += "carbon_dioxide"
-
- if(!isnull(signal.data["tox_scrub"]) && text2num(signal.data["tox_scrub"]) != ("phoron" in scrubbing_gas))
- toggle += "phoron"
- else if(signal.data["toggle_tox_scrub"])
- toggle += "phoron"
-
- if(!isnull(signal.data["n2o_scrub"]) && text2num(signal.data["n2o_scrub"]) != ("sleeping_agent" in scrubbing_gas))
- toggle += "sleeping_agent"
- else if(signal.data["toggle_n2o_scrub"])
- toggle += "sleeping_agent"
-
- scrubbing_gas ^= toggle
-
- if(signal.data["init"] != null)
- name = signal.data["init"]
- return
-
- if(signal.data["status"] != null)
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- return //do not update_icon
-
-// log_debug("DEBUG \[[world.timeofday]\]: vent_scrubber/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]")
- addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
- update_icon()
- return
-
-/obj/machinery/atmospherics/unary/vent_scrubber/power_change()
- var/old_stat = stat
- ..()
- if(old_stat != stat)
- update_icon()
-
-/obj/machinery/atmospherics/unary/vent_scrubber/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if (W.iswrench())
- if (!(stat & NOPOWER) && use_power)
- to_chat(user, "You cannot unwrench \the [src], turn it off first.")
- return 1
- var/turf/T = src.loc
- if (node && node.level==1 && isturf(T) && !T.is_plating())
- to_chat(user, "You must remove the plating first.")
- return 1
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
- if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
- to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- playsound(src.loc, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, 40/W.toolspeed, act_target = src))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear a ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- qdel(src)
- return 1
-
- if(W.iswelder())
- var/obj/item/weldingtool/WT = W
- if (!WT.welding)
- to_chat(user, "\The [WT] must be turned on!")
- else if (WT.remove_fuel(0,user))
- to_chat(user, "Now welding \the [src].")
- if(do_after(user, 20/W.toolspeed, act_target = src))
- if(!src || !WT.isOn()) return
- playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
- if(!welded)
- user.visible_message("\The [user] welds \the [src] shut.", "You weld \the [src] shut.", "You hear welding.")
- welded = 1
- update_icon()
- else
- user.visible_message("[user] unwelds \the [src].", "You unweld \the [src].", "You hear welding.")
- welded = 0
- update_icon()
- else
- to_chat(user, "You fail to complete the welding.")
- else
- to_chat(user, "You need more welding fuel to complete this task.")
- return 1
- return ..()
-
-/obj/machinery/atmospherics/unary/vent_scrubber/examine(mob/user)
- if(..(user, 1))
- to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W")
- else
- to_chat(user, "You are too far away to read the gauge.")
- if(welded)
- to_chat(user, "It seems welded shut.")
-
-/obj/machinery/atmospherics/unary/vent_scrubber/Destroy()
- if(initial_loc)
- initial_loc.air_scrub_info -= id_tag
- initial_loc.air_scrub_names -= id_tag
-
- return ..()
+/obj/machinery/atmospherics/unary/vent_scrubber
+ icon = 'icons/atmos/vent_scrubber.dmi'
+ icon_state = "map_scrubber_off"
+
+ name = "Air Scrubber"
+ desc = "Has a valve and pump attached to it"
+ use_power = 0
+ idle_power_usage = 150 //internal circuitry, friction losses and stuff
+ power_rating = 7500 //7500 W ~ 10 HP
+
+ connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SCRUBBER //connects to regular and scrubber pipes
+
+ level = 1
+
+ var/area/initial_loc
+ var/id_tag = null
+ var/frequency = 1439
+ var/datum/radio_frequency/radio_connection
+
+ var/hibernate = 0 //Do we even process?
+ var/scrubbing = 1 //0 = siphoning, 1 = scrubbing
+ var/list/scrubbing_gas = list("carbon_dioxide")
+
+ var/panic = 0 //is this scrubber panicked?
+
+ var/area_uid
+ var/radio_filter_out
+ var/radio_filter_in
+
+ var/welded = 0
+
+/obj/machinery/atmospherics/unary/vent_scrubber/on
+ use_power = 1
+ icon_state = "map_scrubber_on"
+
+/obj/machinery/atmospherics/unary/vent_scrubber/Initialize()
+ . = ..()
+ air_contents.volume = ATMOS_DEFAULT_VOLUME_FILTER
+
+ initial_loc = get_area(loc)
+ area_uid = initial_loc.uid
+ if (!id_tag)
+ assign_uid()
+ id_tag = num2text(uid)
+
+ 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)
+
+/obj/machinery/atmospherics/unary/vent_scrubber/atmos_init()
+ ..()
+ broadcast_status()
+
+/obj/machinery/atmospherics/unary/vent_scrubber/Destroy()
+ unregister_radio(src, frequency)
+ return ..()
+
+/obj/machinery/atmospherics/unary/vent_scrubber/update_icon(var/safety = 0)
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+
+ if (welded)
+ icon_state = "weld"
+ return
+
+ if (!powered() || !use_power)
+ icon_state = "off"
+ else if (scrubbing)
+ icon_state = "on"
+ else
+ icon_state = "in"
+
+/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+ if(!T.is_plating() && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
+ return
+ else
+ if(node)
+ add_underlay(T, node, dir, node.icon_connect_type)
+ else
+ add_underlay(T,, dir)
+
+/obj/machinery/atmospherics/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/unary/vent_scrubber/proc/broadcast_status()
+ if(!radio_connection)
+ return 0
+
+ var/datum/signal/signal = new
+ signal.transmission_method = 1 //radio signal
+ signal.source = src
+ signal.data = list(
+ "area" = area_uid,
+ "tag" = id_tag,
+ "device" = "AScr",
+ "timestamp" = world.time,
+ "power" = use_power,
+ "scrubbing" = scrubbing,
+ "panic" = panic,
+ "filter_o2" = ("oxygen" in scrubbing_gas),
+ "filter_n2" = ("nitrogen" in scrubbing_gas),
+ "filter_co2" = ("carbon_dioxide" in scrubbing_gas),
+ "filter_phoron" = ("phoron" in scrubbing_gas),
+ "filter_n2o" = ("sleeping_agent" in scrubbing_gas),
+ "sigtype" = "status"
+ )
+
+ var/area/A = get_area(src)
+ if(!A.air_scrub_names[id_tag])
+ var/new_name = "[A.name] Air Scrubber #[A.air_scrub_names.len+1]"
+ A.air_scrub_names[id_tag] = new_name
+ src.name = new_name
+ A.air_scrub_info[id_tag] = signal.data
+ radio_connection.post_signal(src, signal, radio_filter_out)
+
+ return 1
+
+/obj/machinery/atmospherics/unary/vent_scrubber/machinery_process()
+ ..()
+
+ if (hibernate > world.time)
+ return 1
+
+ if (!node)
+ use_power = 0
+ //broadcast_status()
+ if(!use_power || (stat & (NOPOWER|BROKEN)))
+ return 0
+ if(welded)
+ return 0
+
+ var/datum/gas_mixture/environment = loc.return_air()
+
+ var/power_draw = -1
+ if(scrubbing)
+ //limit flow rate from turfs
+ var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SCRUBBER_FLOWRATE/environment.volume) //group_multiplier gets divided out here
+
+ power_draw = scrub_gas(src, scrubbing_gas, environment, air_contents, transfer_moles, power_rating)
+ else //Just siphon all air
+ //limit flow rate from turfs
+ var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SIPHON_FLOWRATE/environment.volume) //group_multiplier gets divided out here
+
+ power_draw = pump_gas(src, environment, air_contents, transfer_moles, power_rating)
+
+ if(scrubbing && power_draw <= 0) //99% of all scrubbers
+ //Fucking hibernate because you ain't doing shit.
+ hibernate = world.time + (rand(100,200))
+
+ if (power_draw >= 0)
+ last_power_draw = power_draw
+ use_power(power_draw)
+
+ if(network)
+ network.update = 1
+
+ return 1
+
+/obj/machinery/atmospherics/unary/vent_scrubber/hide(var/i) //to make the little pipe section invisible, the icon changes.
+ update_icon()
+ update_underlays()
+
+/obj/machinery/atmospherics/unary/vent_scrubber/receive_signal(datum/signal/signal)
+ if(stat & (NOPOWER|BROKEN))
+ return
+ if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
+ return 0
+
+ if(signal.data["power"] != null)
+ use_power = text2num(signal.data["power"])
+ if(signal.data["power_toggle"] != null)
+ use_power = !use_power
+
+ if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing
+ panic = text2num(signal.data["panic_siphon"])
+ if(panic)
+ use_power = 1
+ scrubbing = 0
+ else
+ scrubbing = 1
+ if(signal.data["toggle_panic_siphon"] != null)
+ panic = !panic
+ if(panic)
+ use_power = 1
+ scrubbing = 0
+ else
+ scrubbing = 1
+
+ if(signal.data["scrubbing"] != null)
+ scrubbing = text2num(signal.data["scrubbing"])
+ if(scrubbing)
+ panic = 0
+ if(signal.data["toggle_scrubbing"])
+ scrubbing = !scrubbing
+ if(scrubbing)
+ panic = 0
+
+ var/list/toggle = list()
+
+ if(!isnull(signal.data["o2_scrub"]) && text2num(signal.data["o2_scrub"]) != ("oxygen" in scrubbing_gas))
+ toggle += "oxygen"
+ else if(signal.data["toggle_o2_scrub"])
+ toggle += "oxygen"
+
+ if(!isnull(signal.data["n2_scrub"]) && text2num(signal.data["n2_scrub"]) != ("nitrogen" in scrubbing_gas))
+ toggle += "nitrogen"
+ else if(signal.data["toggle_n2_scrub"])
+ toggle += "nitrogen"
+
+ if(!isnull(signal.data["co2_scrub"]) && text2num(signal.data["co2_scrub"]) != ("carbon_dioxide" in scrubbing_gas))
+ toggle += "carbon_dioxide"
+ else if(signal.data["toggle_co2_scrub"])
+ toggle += "carbon_dioxide"
+
+ if(!isnull(signal.data["tox_scrub"]) && text2num(signal.data["tox_scrub"]) != ("phoron" in scrubbing_gas))
+ toggle += "phoron"
+ else if(signal.data["toggle_tox_scrub"])
+ toggle += "phoron"
+
+ if(!isnull(signal.data["n2o_scrub"]) && text2num(signal.data["n2o_scrub"]) != ("sleeping_agent" in scrubbing_gas))
+ toggle += "sleeping_agent"
+ else if(signal.data["toggle_n2o_scrub"])
+ toggle += "sleeping_agent"
+
+ scrubbing_gas ^= toggle
+
+ if(signal.data["init"] != null)
+ name = signal.data["init"]
+ return
+
+ if(signal.data["status"] != null)
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ return //do not update_icon
+
+// log_debug("DEBUG \[[world.timeofday]\]: vent_scrubber/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]")
+ addtimer(CALLBACK(src, .proc/broadcast_status), 2, TIMER_UNIQUE)
+ update_icon()
+ return
+
+/obj/machinery/atmospherics/unary/vent_scrubber/power_change()
+ var/old_stat = stat
+ ..()
+ if(old_stat != stat)
+ update_icon()
+
+/obj/machinery/atmospherics/unary/vent_scrubber/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if (W.iswrench())
+ if (!(stat & NOPOWER) && use_power)
+ to_chat(user, "You cannot unwrench \the [src], turn it off first.")
+ return 1
+ var/turf/T = src.loc
+ if (node && node.level==1 && isturf(T) && !T.is_plating())
+ to_chat(user, "You must remove the plating first.")
+ return 1
+ var/datum/gas_mixture/int_air = return_air()
+ var/datum/gas_mixture/env_air = loc.return_air()
+ if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
+ to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ playsound(src.loc, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, 40/W.toolspeed, act_target = src))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear a ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ qdel(src)
+ return 1
+
+ if(W.iswelder())
+ var/obj/item/weldingtool/WT = W
+ if (!WT.welding)
+ to_chat(user, "\The [WT] must be turned on!")
+ else if (WT.remove_fuel(0,user))
+ to_chat(user, "Now welding \the [src].")
+ if(do_after(user, 20/W.toolspeed, act_target = src))
+ if(!src || !WT.isOn()) return
+ playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
+ if(!welded)
+ user.visible_message("\The [user] welds \the [src] shut.", "You weld \the [src] shut.", "You hear welding.")
+ welded = 1
+ update_icon()
+ else
+ user.visible_message("[user] unwelds \the [src].", "You unweld \the [src].", "You hear welding.")
+ welded = 0
+ update_icon()
+ else
+ to_chat(user, "You fail to complete the welding.")
+ else
+ to_chat(user, "You need more welding fuel to complete this task.")
+ return 1
+ return ..()
+
+/obj/machinery/atmospherics/unary/vent_scrubber/examine(mob/user)
+ if(..(user, 1))
+ to_chat(user, "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W")
+ else
+ to_chat(user, "You are too far away to read the gauge.")
+ if(welded)
+ to_chat(user, "It seems welded shut.")
+
+/obj/machinery/atmospherics/unary/vent_scrubber/Destroy()
+ if(initial_loc)
+ initial_loc.air_scrub_info -= id_tag
+ initial_loc.air_scrub_names -= id_tag
+
+ return ..()
diff --git a/code/ATMOSPHERICS/components/valve.dm b/code/ATMOSPHERICS/components/valve.dm
index 48ca8837bdb..903f09af65d 100644
--- a/code/ATMOSPHERICS/components/valve.dm
+++ b/code/ATMOSPHERICS/components/valve.dm
@@ -1,326 +1,326 @@
-/obj/machinery/atmospherics/valve
- icon = 'icons/atmos/valve.dmi'
- icon_state = "map_valve0"
-
- name = "manual valve"
- desc = "A pipe valve"
-
- level = 1
- dir = SOUTH
- initialize_directions = SOUTH|NORTH
-
- var/open = 0
- var/openDuringInit = 0
-
- var/datum/pipe_network/network_node1
- var/datum/pipe_network/network_node2
-
-/obj/machinery/atmospherics/valve/open
- open = 1
- icon_state = "map_valve1"
-
-/obj/machinery/atmospherics/valve/update_icon(animation)
- if(animation)
- flick("valve[src.open][!src.open]",src)
- else
- icon_state = "valve[open]"
-
-/obj/machinery/atmospherics/valve/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
- add_underlay(T, node1, get_dir(src, node1))
- add_underlay(T, node2, get_dir(src, node2))
-
-/obj/machinery/atmospherics/valve/hide(var/i)
- update_underlays()
-
-/obj/machinery/atmospherics/valve/Initialize()
- switch(dir)
- if(NORTH || SOUTH)
- initialize_directions = NORTH|SOUTH
- if(EAST || WEST)
- initialize_directions = EAST|WEST
- . = ..()
-
-/obj/machinery/atmospherics/valve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
- if(reference == node1)
- network_node1 = new_network
- if(open)
- network_node2 = new_network
- else if(reference == node2)
- network_node2 = new_network
- if(open)
- network_node1 = new_network
-
- if(new_network.normal_members.Find(src))
- return 0
-
- new_network.normal_members += src
-
- if(open)
- if(reference == node1)
- if(node2)
- return node2.network_expand(new_network, src)
- else if(reference == node2)
- if(node1)
- return node1.network_expand(new_network, src)
-
- return null
-
-/obj/machinery/atmospherics/valve/Destroy()
- loc = null
-
- if(node1)
- node1.disconnect(src)
- qdel(network_node1)
- if(node2)
- node2.disconnect(src)
- qdel(network_node2)
-
- node1 = null
- node2 = null
-
- return ..()
-
-/obj/machinery/atmospherics/valve/proc/open()
- if(open) return 0
-
- open = 1
- update_icon()
-
- if(network_node1&&network_node2)
- network_node1.merge(network_node2)
- network_node2 = network_node1
-
- if(network_node1)
- network_node1.update = 1
- else if(network_node2)
- network_node2.update = 1
-
- return 1
-
-/obj/machinery/atmospherics/valve/proc/close()
- if(!open)
- return 0
-
- open = 0
- update_icon()
-
- if(network_node1)
- qdel(network_node1)
- if(network_node2)
- qdel(network_node2)
-
- build_network()
-
- return 1
-
-/obj/machinery/atmospherics/valve/proc/normalize_dir()
- if(dir==3)
- set_dir(1)
- else if(dir==12)
- set_dir(4)
-
-/obj/machinery/atmospherics/valve/attack_ai(mob/user as mob)
- return
-
-/obj/machinery/atmospherics/valve/attack_hand(mob/user as mob)
- src.add_fingerprint(usr)
- update_icon(1)
- sleep(10)
- if (src.open)
- src.close()
- else
- src.open()
-
-/obj/machinery/atmospherics/valve/machinery_process()
- ..()
- return PROCESS_KILL
-
-/obj/machinery/atmospherics/valve/atmos_init()
- normalize_dir()
-
- var/node1_dir
- var/node2_dir
-
- for(var/direction in cardinal)
- if(direction&initialize_directions)
- if (!node1_dir)
- node1_dir = direction
- else if (!node2_dir)
- node2_dir = direction
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- break
- for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node2 = target
- break
-
- build_network()
-
- queue_icon_update()
- update_underlays()
-
- if(openDuringInit)
- close()
- open()
- openDuringInit = 0
-
-/obj/machinery/atmospherics/valve/build_network()
- if(!network_node1 && node1)
- network_node1 = new /datum/pipe_network()
- network_node1.normal_members += src
- network_node1.build_network(node1, src)
-
- if(!network_node2 && node2)
- network_node2 = new /datum/pipe_network()
- network_node2.normal_members += src
- network_node2.build_network(node2, src)
-
-/obj/machinery/atmospherics/valve/return_network(obj/machinery/atmospherics/reference)
- build_network()
-
- if(reference==node1)
- return network_node1
-
- if(reference==node2)
- return network_node2
-
- return null
-
-/obj/machinery/atmospherics/valve/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
- if(network_node1 == old_network)
- network_node1 = new_network
- if(network_node2 == old_network)
- network_node2 = new_network
-
- return 1
-
-/obj/machinery/atmospherics/valve/return_network_air(datum/network/reference)
- return null
-
-/obj/machinery/atmospherics/valve/disconnect(obj/machinery/atmospherics/reference)
- if(reference==node1)
- qdel(network_node1)
- node1 = null
-
- else if(reference==node2)
- qdel(network_node2)
- node2 = null
-
- update_underlays()
-
- return null
-
-/obj/machinery/atmospherics/valve/digital // can be controlled by AI
- name = "digital valve"
- desc = "A digitally controlled valve."
- icon = 'icons/atmos/digital_valve.dmi'
-
- var/frequency = 0
- var/id = null
- var/datum/radio_frequency/radio_connection
-
-/obj/machinery/atmospherics/valve/digital/attack_ai(mob/user as mob)
- return src.attack_hand(user)
-
-/obj/machinery/atmospherics/valve/digital/attack_hand(mob/user as mob)
- if(!powered())
- return
- if(!src.allowed(user))
- to_chat(user, "Access denied.")
- return
- ..()
-
- log_and_message_admins("has [open ? "OPENED" : "closed"] [name].", user)
-
-/obj/machinery/atmospherics/valve/digital/AltClick(var/mob/abstract/observer/admin)
- if (istype(admin))
- if (admin.client && admin.client.holder && ((R_MOD|R_ADMIN) & admin.client.holder.rights))
- if (open)
- close()
- else
- if (alert(admin, "The valve is currently closed. Do you want to open it?", "Open the valve?", "Yes", "No") == "No")
- return
- open()
-
- log_and_message_admins("has [open ? "opened" : "closed"] [name].", admin)
-
-/obj/machinery/atmospherics/valve/digital/open
- open = 1
- icon_state = "map_valve1"
-
-/obj/machinery/atmospherics/valve/digital/power_change()
- var/old_stat = stat
- ..()
- if(old_stat != stat)
- queue_icon_update()
-
-/obj/machinery/atmospherics/valve/digital/update_icon()
- ..()
- if(!powered())
- icon_state = "valve[open]nopower"
-
-/obj/machinery/atmospherics/valve/digital/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/valve/digital/atmos_init()
- ..()
- if(frequency)
- set_frequency(frequency)
-
-/obj/machinery/atmospherics/valve/digital/receive_signal(datum/signal/signal)
- if(!signal.data["tag"] || (signal.data["tag"] != id))
- return 0
-
- switch(signal.data["command"])
- if("valve_open")
- if(!open)
- open()
-
- if("valve_close")
- if(open)
- close()
-
- if("valve_toggle")
- if(open)
- close()
- else
- open()
-
-/obj/machinery/atmospherics/valve/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if (!W.iswrench())
- return ..()
- if (istype(src, /obj/machinery/atmospherics/valve/digital))
- to_chat(user, "You cannot unwrench \the [src], it's too complicated.")
- return 1
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
- if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
- to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- playsound(src.loc, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, 40/W.toolspeed, act_target = src))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear a ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- qdel(src)
-
-/obj/machinery/atmospherics/valve/examine(mob/user)
- ..()
- to_chat(user, "It is [open ? "open" : "closed"].")
+/obj/machinery/atmospherics/valve
+ icon = 'icons/atmos/valve.dmi'
+ icon_state = "map_valve0"
+
+ name = "manual valve"
+ desc = "A pipe valve"
+
+ level = 1
+ dir = SOUTH
+ initialize_directions = SOUTH|NORTH
+
+ var/open = 0
+ var/openDuringInit = 0
+
+ var/datum/pipe_network/network_node1
+ var/datum/pipe_network/network_node2
+
+/obj/machinery/atmospherics/valve/open
+ open = 1
+ icon_state = "map_valve1"
+
+/obj/machinery/atmospherics/valve/update_icon(animation)
+ if(animation)
+ flick("valve[src.open][!src.open]",src)
+ else
+ icon_state = "valve[open]"
+
+/obj/machinery/atmospherics/valve/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+ add_underlay(T, node1, get_dir(src, node1))
+ add_underlay(T, node2, get_dir(src, node2))
+
+/obj/machinery/atmospherics/valve/hide(var/i)
+ update_underlays()
+
+/obj/machinery/atmospherics/valve/Initialize()
+ switch(dir)
+ if(NORTH || SOUTH)
+ initialize_directions = NORTH|SOUTH
+ if(EAST || WEST)
+ initialize_directions = EAST|WEST
+ . = ..()
+
+/obj/machinery/atmospherics/valve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+ if(reference == node1)
+ network_node1 = new_network
+ if(open)
+ network_node2 = new_network
+ else if(reference == node2)
+ network_node2 = new_network
+ if(open)
+ network_node1 = new_network
+
+ if(new_network.normal_members.Find(src))
+ return 0
+
+ new_network.normal_members += src
+
+ if(open)
+ if(reference == node1)
+ if(node2)
+ return node2.network_expand(new_network, src)
+ else if(reference == node2)
+ if(node1)
+ return node1.network_expand(new_network, src)
+
+ return null
+
+/obj/machinery/atmospherics/valve/Destroy()
+ loc = null
+
+ if(node1)
+ node1.disconnect(src)
+ qdel(network_node1)
+ if(node2)
+ node2.disconnect(src)
+ qdel(network_node2)
+
+ node1 = null
+ node2 = null
+
+ return ..()
+
+/obj/machinery/atmospherics/valve/proc/open()
+ if(open) return 0
+
+ open = 1
+ update_icon()
+
+ if(network_node1&&network_node2)
+ network_node1.merge(network_node2)
+ network_node2 = network_node1
+
+ if(network_node1)
+ network_node1.update = 1
+ else if(network_node2)
+ network_node2.update = 1
+
+ return 1
+
+/obj/machinery/atmospherics/valve/proc/close()
+ if(!open)
+ return 0
+
+ open = 0
+ update_icon()
+
+ if(network_node1)
+ qdel(network_node1)
+ if(network_node2)
+ qdel(network_node2)
+
+ build_network()
+
+ return 1
+
+/obj/machinery/atmospherics/valve/proc/normalize_dir()
+ if(dir==3)
+ set_dir(1)
+ else if(dir==12)
+ set_dir(4)
+
+/obj/machinery/atmospherics/valve/attack_ai(mob/user as mob)
+ return
+
+/obj/machinery/atmospherics/valve/attack_hand(mob/user as mob)
+ src.add_fingerprint(usr)
+ update_icon(1)
+ sleep(10)
+ if (src.open)
+ src.close()
+ else
+ src.open()
+
+/obj/machinery/atmospherics/valve/machinery_process()
+ ..()
+ return PROCESS_KILL
+
+/obj/machinery/atmospherics/valve/atmos_init()
+ normalize_dir()
+
+ var/node1_dir
+ var/node2_dir
+
+ for(var/direction in cardinal)
+ if(direction&initialize_directions)
+ if (!node1_dir)
+ node1_dir = direction
+ else if (!node2_dir)
+ node2_dir = direction
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+ for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node2 = target
+ break
+
+ build_network()
+
+ queue_icon_update()
+ update_underlays()
+
+ if(openDuringInit)
+ close()
+ open()
+ openDuringInit = 0
+
+/obj/machinery/atmospherics/valve/build_network()
+ if(!network_node1 && node1)
+ network_node1 = new /datum/pipe_network()
+ network_node1.normal_members += src
+ network_node1.build_network(node1, src)
+
+ if(!network_node2 && node2)
+ network_node2 = new /datum/pipe_network()
+ network_node2.normal_members += src
+ network_node2.build_network(node2, src)
+
+/obj/machinery/atmospherics/valve/return_network(obj/machinery/atmospherics/reference)
+ build_network()
+
+ if(reference==node1)
+ return network_node1
+
+ if(reference==node2)
+ return network_node2
+
+ return null
+
+/obj/machinery/atmospherics/valve/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
+ if(network_node1 == old_network)
+ network_node1 = new_network
+ if(network_node2 == old_network)
+ network_node2 = new_network
+
+ return 1
+
+/obj/machinery/atmospherics/valve/return_network_air(datum/network/reference)
+ return null
+
+/obj/machinery/atmospherics/valve/disconnect(obj/machinery/atmospherics/reference)
+ if(reference==node1)
+ qdel(network_node1)
+ node1 = null
+
+ else if(reference==node2)
+ qdel(network_node2)
+ node2 = null
+
+ update_underlays()
+
+ return null
+
+/obj/machinery/atmospherics/valve/digital // can be controlled by AI
+ name = "digital valve"
+ desc = "A digitally controlled valve."
+ icon = 'icons/atmos/digital_valve.dmi'
+
+ var/frequency = 0
+ var/id = null
+ var/datum/radio_frequency/radio_connection
+
+/obj/machinery/atmospherics/valve/digital/attack_ai(mob/user as mob)
+ return src.attack_hand(user)
+
+/obj/machinery/atmospherics/valve/digital/attack_hand(mob/user as mob)
+ if(!powered())
+ return
+ if(!src.allowed(user))
+ to_chat(user, "Access denied.")
+ return
+ ..()
+
+ log_and_message_admins("has [open ? "OPENED" : "closed"] [name].", user)
+
+/obj/machinery/atmospherics/valve/digital/AltClick(var/mob/abstract/observer/admin)
+ if (istype(admin))
+ if (admin.client && admin.client.holder && ((R_MOD|R_ADMIN) & admin.client.holder.rights))
+ if (open)
+ close()
+ else
+ if (alert(admin, "The valve is currently closed. Do you want to open it?", "Open the valve?", "Yes", "No") == "No")
+ return
+ open()
+
+ log_and_message_admins("has [open ? "opened" : "closed"] [name].", admin)
+
+/obj/machinery/atmospherics/valve/digital/open
+ open = 1
+ icon_state = "map_valve1"
+
+/obj/machinery/atmospherics/valve/digital/power_change()
+ var/old_stat = stat
+ ..()
+ if(old_stat != stat)
+ queue_icon_update()
+
+/obj/machinery/atmospherics/valve/digital/update_icon()
+ ..()
+ if(!powered())
+ icon_state = "valve[open]nopower"
+
+/obj/machinery/atmospherics/valve/digital/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/valve/digital/atmos_init()
+ ..()
+ if(frequency)
+ set_frequency(frequency)
+
+/obj/machinery/atmospherics/valve/digital/receive_signal(datum/signal/signal)
+ if(!signal.data["tag"] || (signal.data["tag"] != id))
+ return 0
+
+ switch(signal.data["command"])
+ if("valve_open")
+ if(!open)
+ open()
+
+ if("valve_close")
+ if(open)
+ close()
+
+ if("valve_toggle")
+ if(open)
+ close()
+ else
+ open()
+
+/obj/machinery/atmospherics/valve/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if (!W.iswrench())
+ return ..()
+ if (istype(src, /obj/machinery/atmospherics/valve/digital))
+ to_chat(user, "You cannot unwrench \the [src], it's too complicated.")
+ return 1
+ var/datum/gas_mixture/int_air = return_air()
+ var/datum/gas_mixture/env_air = loc.return_air()
+ if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
+ to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ playsound(src.loc, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, 40/W.toolspeed, act_target = src))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear a ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ qdel(src)
+
+/obj/machinery/atmospherics/valve/examine(mob/user)
+ ..()
+ to_chat(user, "It is [open ? "open" : "closed"].")
diff --git a/code/ATMOSPHERICS/datum_pipe_network.dm b/code/ATMOSPHERICS/datum_pipe_network.dm
index e952364cb33..a38d42e21db 100644
--- a/code/ATMOSPHERICS/datum_pipe_network.dm
+++ b/code/ATMOSPHERICS/datum_pipe_network.dm
@@ -1,91 +1,91 @@
-/datum/pipe_network
- var/list/datum/gas_mixture/gases = list() //All of the gas_mixtures continuously connected in this network
- var/volume = 0 //caches the total volume for atmos machines to use in gas calculations
-
- var/list/obj/machinery/atmospherics/normal_members = list()
- var/list/datum/pipeline/line_members = list()
- //membership roster to go through for updates and what not
-
- var/update = 1
- //var/datum/gas_mixture/air_transient = null
-
-/*
-/datum/pipe_network/New()
- //air_transient = new()
-
- ..()*/
-
-/datum/pipe_network/process()
- //Equalize gases amongst pipe if called for
- if(update)
- update = 0
- reconcile_air() //equalize_gases(gases)
-
- //Give pipelines their process call for pressure checking and what not. Have to remove pressure checks for the time being as pipes dont radiate heat - Mport
- //for(var/datum/pipeline/line_member in line_members)
- // line_member.process()
-
-/datum/pipe_network/proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference)
- //Purpose: Generate membership roster
- //Notes: Assuming that members will add themselves to appropriate roster in network_expand()
-
- if(!start_normal)
- qdel(src)
-
- start_normal.network_expand(src, reference)
-
- update_network_gases()
-
- if((normal_members.len>0)||(line_members.len>0))
- START_PROCESSING(SSpipenet, src)
- else
- qdel(src)
-
-/datum/pipe_network/proc/merge(datum/pipe_network/giver)
- if(giver==src) return 0
-
- normal_members |= giver.normal_members
-
- line_members |= giver.line_members
-
- for(var/obj/machinery/atmospherics/normal_member in giver.normal_members)
- normal_member.reassign_network(giver, src)
-
- for(var/datum/pipeline/line_member in giver.line_members)
- line_member.network = src
-
- update_network_gases()
- return 1
-
-/datum/pipe_network/proc/update_network_gases()
- //Go through membership roster and make sure gases is up to date
-
- gases = list()
- volume = 0
-
- for(var/obj/machinery/atmospherics/normal_member in normal_members)
- var/result = normal_member.return_network_air(src)
- if(result) gases += result
-
- for(var/datum/pipeline/line_member in line_members)
- gases += line_member.air
-
- for(var/datum/gas_mixture/air in gases)
- volume += air.volume
-
-/datum/pipe_network/proc/reconcile_air()
- equalize_gases(gases)
-
-/datum/pipe_network/Destroy(force = FALSE)
- STOP_PROCESSING(SSpipenet, src)
- for (var/datum/pipeline/pipeline in line_members)
- pipeline.network = null
-
- line_members = null
-
- for (var/obj/machinery/atmospherics/thing in normal_members)
- thing.remove_network(src)
-
- normal_members = null
-
- return ..()
+/datum/pipe_network
+ var/list/datum/gas_mixture/gases = list() //All of the gas_mixtures continuously connected in this network
+ var/volume = 0 //caches the total volume for atmos machines to use in gas calculations
+
+ var/list/obj/machinery/atmospherics/normal_members = list()
+ var/list/datum/pipeline/line_members = list()
+ //membership roster to go through for updates and what not
+
+ var/update = 1
+ //var/datum/gas_mixture/air_transient = null
+
+/*
+/datum/pipe_network/New()
+ //air_transient = new()
+
+ ..()*/
+
+/datum/pipe_network/process()
+ //Equalize gases amongst pipe if called for
+ if(update)
+ update = 0
+ reconcile_air() //equalize_gases(gases)
+
+ //Give pipelines their process call for pressure checking and what not. Have to remove pressure checks for the time being as pipes dont radiate heat - Mport
+ //for(var/datum/pipeline/line_member in line_members)
+ // line_member.process()
+
+/datum/pipe_network/proc/build_network(obj/machinery/atmospherics/start_normal, obj/machinery/atmospherics/reference)
+ //Purpose: Generate membership roster
+ //Notes: Assuming that members will add themselves to appropriate roster in network_expand()
+
+ if(!start_normal)
+ qdel(src)
+
+ start_normal.network_expand(src, reference)
+
+ update_network_gases()
+
+ if((normal_members.len>0)||(line_members.len>0))
+ START_PROCESSING(SSpipenet, src)
+ else
+ qdel(src)
+
+/datum/pipe_network/proc/merge(datum/pipe_network/giver)
+ if(giver==src) return 0
+
+ normal_members |= giver.normal_members
+
+ line_members |= giver.line_members
+
+ for(var/obj/machinery/atmospherics/normal_member in giver.normal_members)
+ normal_member.reassign_network(giver, src)
+
+ for(var/datum/pipeline/line_member in giver.line_members)
+ line_member.network = src
+
+ update_network_gases()
+ return 1
+
+/datum/pipe_network/proc/update_network_gases()
+ //Go through membership roster and make sure gases is up to date
+
+ gases = list()
+ volume = 0
+
+ for(var/obj/machinery/atmospherics/normal_member in normal_members)
+ var/result = normal_member.return_network_air(src)
+ if(result) gases += result
+
+ for(var/datum/pipeline/line_member in line_members)
+ gases += line_member.air
+
+ for(var/datum/gas_mixture/air in gases)
+ volume += air.volume
+
+/datum/pipe_network/proc/reconcile_air()
+ equalize_gases(gases)
+
+/datum/pipe_network/Destroy(force = FALSE)
+ STOP_PROCESSING(SSpipenet, src)
+ for (var/datum/pipeline/pipeline in line_members)
+ pipeline.network = null
+
+ line_members = null
+
+ for (var/obj/machinery/atmospherics/thing in normal_members)
+ thing.remove_network(src)
+
+ normal_members = null
+
+ return ..()
diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm
index de600d78a0b..e4ea98f402b 100644
--- a/code/ATMOSPHERICS/datum_pipeline.dm
+++ b/code/ATMOSPHERICS/datum_pipeline.dm
@@ -1,218 +1,218 @@
-
-/datum/pipeline
- var/datum/gas_mixture/air
-
- var/list/obj/machinery/atmospherics/pipe/members
- var/list/obj/machinery/atmospherics/pipe/edges //Used for building networks
-
- var/datum/pipe_network/network
-
- var/alert_pressure = 0
-
-/datum/pipeline/Destroy()
- if(network)
- QDEL_NULL(network)
-
- if(air && air.volume)
- temporarily_store_air()
- QDEL_NULL(air)
-
- for (var/obj/machinery/atmospherics/pipe/thing in members)
- thing.parent = null
-
- return ..()
-
-/datum/pipeline/process()//This use to be called called from the pipe networks
- //Check to see if pressure is within acceptable limits
- var/pressure = air.return_pressure()
- if(pressure > alert_pressure)
- for(var/obj/machinery/atmospherics/pipe/member in members)
- if(!member.check_pressure(pressure))
- break //Only delete 1 pipe per process
-
-/datum/pipeline/proc/temporarily_store_air()
- //Update individual gas_mixtures by volume ratio
-
- for(var/obj/machinery/atmospherics/pipe/member in members)
- member.air_temporary = new
- member.air_temporary.copy_from(air)
- member.air_temporary.volume = member.volume
- member.air_temporary.multiply(member.volume / air.volume)
-
-/datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/pipe/base)
- air = new
-
- var/list/possible_expansions = list(base)
- members = list(base)
- edges = list()
-
- var/volume = base.volume
- base.parent = src
- alert_pressure = base.alert_pressure
-
- if(base.air_temporary)
- air = base.air_temporary
- base.air_temporary = null
- else
- air = new
-
- while(possible_expansions.len>0)
- for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions)
-
- var/list/result = borderline.pipeline_expansion()
- var/edge_check = result.len
-
- if(result.len>0)
- for(var/obj/machinery/atmospherics/pipe/item in result)
- if(!members.Find(item))
- members += item
- possible_expansions += item
-
- volume += item.volume
- item.parent = src
-
- alert_pressure = min(alert_pressure, item.alert_pressure)
-
- if(item.air_temporary)
- air.merge(item.air_temporary)
-
- edge_check--
-
- if(edge_check>0)
- edges += borderline
-
- possible_expansions -= borderline
-
- air.volume = volume
-
-/datum/pipeline/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
-
- if(new_network.line_members.Find(src))
- return 0
-
- new_network.line_members += src
-
- network = new_network
-
- for(var/obj/machinery/atmospherics/pipe/edge in edges)
- for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion())
- if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference))
- result.network_expand(new_network, edge)
-
- return 1
-
-/datum/pipeline/proc/return_network(obj/machinery/atmospherics/reference)
- if(!network)
- network = new /datum/pipe_network
- network.build_network(src, null)
- //technically passing these parameters should not be allowed
- //however pipe_network.build_network(..) and pipeline.network_extend(...)
- // were setup to properly handle this case
-
- return network
-
-/datum/pipeline/proc/mingle_with_turf(turf/simulated/target, mingle_volume)
- var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
- air_sample.volume = mingle_volume
-
- if(istype(target) && target.zone)
- //Have to consider preservation of group statuses
- var/datum/gas_mixture/turf_copy = new
-
- turf_copy.copy_from(target.zone.air)
- turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group
-
- equalize_gases(list(air_sample, turf_copy))
- air.merge(air_sample)
-
- turf_copy.subtract(target.zone.air)
-
- target.zone.air.merge(turf_copy)
-
- else
- var/datum/gas_mixture/turf_air = target.return_air()
-
- equalize_gases(list(air_sample, turf_air))
- air.merge(air_sample)
- //turf_air already modified by equalize_gases()
-
- if(network)
- network.update = 1
-
-/datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity)
- var/total_heat_capacity = air.heat_capacity()
- var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
-
- if(istype(target, /turf/simulated))
- var/turf/simulated/modeled_location = target
-
- if(modeled_location.blocks_air)
-
- if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0))
- var/delta_temperature = air.temperature - modeled_location.temperature
-
- var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity))
-
- air.temperature -= heat/total_heat_capacity
- modeled_location.temperature += heat/modeled_location.heat_capacity
-
- else
- var/delta_temperature = 0
- var/sharer_heat_capacity = 0
-
- if(modeled_location.zone)
- delta_temperature = (air.temperature - modeled_location.zone.air.temperature)
- sharer_heat_capacity = modeled_location.zone.air.heat_capacity()
- else
- delta_temperature = (air.temperature - modeled_location.air.temperature)
- sharer_heat_capacity = modeled_location.air.heat_capacity()
-
- var/self_temperature_delta = 0
- var/sharer_temperature_delta = 0
-
- 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))
-
- self_temperature_delta = -heat/total_heat_capacity
- sharer_temperature_delta = heat/sharer_heat_capacity
- else
- return 1
-
- air.temperature += self_temperature_delta
-
- if(modeled_location.zone)
- modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier
- else
- modeled_location.air.temperature += sharer_temperature_delta
-
-
- else
- if((target.heat_capacity>0) && (partial_heat_capacity>0))
- var/delta_temperature = air.temperature - target.temperature
-
- var/heat = thermal_conductivity*delta_temperature* \
- (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
-
- air.temperature -= heat/total_heat_capacity
- if(network)
- network.update = 1
-
- //surface must be the surface area in m^2
-/datum/pipeline/proc/radiate_heat_to_space(surface, thermal_conductivity)
- var/gas_density = air.total_moles/air.volume
- thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*GAS_CRITICAL_TEMPERATURE) ), 1) //mult by density ratio
-
- // We only get heat from the star on the exposed surface area.
- // If the HE pipes gain more energy from AVERAGE_SOLAR_RADIATION than they can radiate, then they have a net heat increase.
- var/heat_gain = AVERAGE_SOLAR_RADIATION * (RADIATOR_EXPOSED_SURFACE_AREA_RATIO * surface) * thermal_conductivity
-
- // Previously, the temperature would enter equilibrium at 26C or 294K.
- // Only would happen if both sides (all 2 square meters of surface area) were exposed to sunlight. We now assume it aligned edge on.
- // It currently should stabilise at 129.6K or -143.6C
- heat_gain -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4
-
- air.add_thermal_energy(heat_gain)
- if(network)
- network.update = 1
+
+/datum/pipeline
+ var/datum/gas_mixture/air
+
+ var/list/obj/machinery/atmospherics/pipe/members
+ var/list/obj/machinery/atmospherics/pipe/edges //Used for building networks
+
+ var/datum/pipe_network/network
+
+ var/alert_pressure = 0
+
+/datum/pipeline/Destroy()
+ if(network)
+ QDEL_NULL(network)
+
+ if(air && air.volume)
+ temporarily_store_air()
+ QDEL_NULL(air)
+
+ for (var/obj/machinery/atmospherics/pipe/thing in members)
+ thing.parent = null
+
+ return ..()
+
+/datum/pipeline/process()//This use to be called called from the pipe networks
+ //Check to see if pressure is within acceptable limits
+ var/pressure = air.return_pressure()
+ if(pressure > alert_pressure)
+ for(var/obj/machinery/atmospherics/pipe/member in members)
+ if(!member.check_pressure(pressure))
+ break //Only delete 1 pipe per process
+
+/datum/pipeline/proc/temporarily_store_air()
+ //Update individual gas_mixtures by volume ratio
+
+ for(var/obj/machinery/atmospherics/pipe/member in members)
+ member.air_temporary = new
+ member.air_temporary.copy_from(air)
+ member.air_temporary.volume = member.volume
+ member.air_temporary.multiply(member.volume / air.volume)
+
+/datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/pipe/base)
+ air = new
+
+ var/list/possible_expansions = list(base)
+ members = list(base)
+ edges = list()
+
+ var/volume = base.volume
+ base.parent = src
+ alert_pressure = base.alert_pressure
+
+ if(base.air_temporary)
+ air = base.air_temporary
+ base.air_temporary = null
+ else
+ air = new
+
+ while(possible_expansions.len>0)
+ for(var/obj/machinery/atmospherics/pipe/borderline in possible_expansions)
+
+ var/list/result = borderline.pipeline_expansion()
+ var/edge_check = result.len
+
+ if(result.len>0)
+ for(var/obj/machinery/atmospherics/pipe/item in result)
+ if(!members.Find(item))
+ members += item
+ possible_expansions += item
+
+ volume += item.volume
+ item.parent = src
+
+ alert_pressure = min(alert_pressure, item.alert_pressure)
+
+ if(item.air_temporary)
+ air.merge(item.air_temporary)
+
+ edge_check--
+
+ if(edge_check>0)
+ edges += borderline
+
+ possible_expansions -= borderline
+
+ air.volume = volume
+
+/datum/pipeline/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+
+ if(new_network.line_members.Find(src))
+ return 0
+
+ new_network.line_members += src
+
+ network = new_network
+
+ for(var/obj/machinery/atmospherics/pipe/edge in edges)
+ for(var/obj/machinery/atmospherics/result in edge.pipeline_expansion())
+ if(!istype(result,/obj/machinery/atmospherics/pipe) && (result!=reference))
+ result.network_expand(new_network, edge)
+
+ return 1
+
+/datum/pipeline/proc/return_network(obj/machinery/atmospherics/reference)
+ if(!network)
+ network = new /datum/pipe_network
+ network.build_network(src, null)
+ //technically passing these parameters should not be allowed
+ //however pipe_network.build_network(..) and pipeline.network_extend(...)
+ // were setup to properly handle this case
+
+ return network
+
+/datum/pipeline/proc/mingle_with_turf(turf/simulated/target, mingle_volume)
+ var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
+ air_sample.volume = mingle_volume
+
+ if(istype(target) && target.zone)
+ //Have to consider preservation of group statuses
+ var/datum/gas_mixture/turf_copy = new
+
+ turf_copy.copy_from(target.zone.air)
+ turf_copy.volume = target.zone.air.volume //Copy a good representation of the turf from parent group
+
+ equalize_gases(list(air_sample, turf_copy))
+ air.merge(air_sample)
+
+ turf_copy.subtract(target.zone.air)
+
+ target.zone.air.merge(turf_copy)
+
+ else
+ var/datum/gas_mixture/turf_air = target.return_air()
+
+ equalize_gases(list(air_sample, turf_air))
+ air.merge(air_sample)
+ //turf_air already modified by equalize_gases()
+
+ if(network)
+ network.update = 1
+
+/datum/pipeline/proc/temperature_interact(turf/target, share_volume, thermal_conductivity)
+ var/total_heat_capacity = air.heat_capacity()
+ var/partial_heat_capacity = total_heat_capacity*(share_volume/air.volume)
+
+ if(istype(target, /turf/simulated))
+ var/turf/simulated/modeled_location = target
+
+ if(modeled_location.blocks_air)
+
+ if((modeled_location.heat_capacity>0) && (partial_heat_capacity>0))
+ var/delta_temperature = air.temperature - modeled_location.temperature
+
+ var/heat = thermal_conductivity*delta_temperature* \
+ (partial_heat_capacity*modeled_location.heat_capacity/(partial_heat_capacity+modeled_location.heat_capacity))
+
+ air.temperature -= heat/total_heat_capacity
+ modeled_location.temperature += heat/modeled_location.heat_capacity
+
+ else
+ var/delta_temperature = 0
+ var/sharer_heat_capacity = 0
+
+ if(modeled_location.zone)
+ delta_temperature = (air.temperature - modeled_location.zone.air.temperature)
+ sharer_heat_capacity = modeled_location.zone.air.heat_capacity()
+ else
+ delta_temperature = (air.temperature - modeled_location.air.temperature)
+ sharer_heat_capacity = modeled_location.air.heat_capacity()
+
+ var/self_temperature_delta = 0
+ var/sharer_temperature_delta = 0
+
+ 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))
+
+ self_temperature_delta = -heat/total_heat_capacity
+ sharer_temperature_delta = heat/sharer_heat_capacity
+ else
+ return 1
+
+ air.temperature += self_temperature_delta
+
+ if(modeled_location.zone)
+ modeled_location.zone.air.temperature += sharer_temperature_delta/modeled_location.zone.air.group_multiplier
+ else
+ modeled_location.air.temperature += sharer_temperature_delta
+
+
+ else
+ if((target.heat_capacity>0) && (partial_heat_capacity>0))
+ var/delta_temperature = air.temperature - target.temperature
+
+ var/heat = thermal_conductivity*delta_temperature* \
+ (partial_heat_capacity*target.heat_capacity/(partial_heat_capacity+target.heat_capacity))
+
+ air.temperature -= heat/total_heat_capacity
+ if(network)
+ network.update = 1
+
+ //surface must be the surface area in m^2
+/datum/pipeline/proc/radiate_heat_to_space(surface, thermal_conductivity)
+ var/gas_density = air.total_moles/air.volume
+ thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*GAS_CRITICAL_TEMPERATURE) ), 1) //mult by density ratio
+
+ // We only get heat from the star on the exposed surface area.
+ // If the HE pipes gain more energy from AVERAGE_SOLAR_RADIATION than they can radiate, then they have a net heat increase.
+ var/heat_gain = AVERAGE_SOLAR_RADIATION * (RADIATOR_EXPOSED_SURFACE_AREA_RATIO * surface) * thermal_conductivity
+
+ // Previously, the temperature would enter equilibrium at 26C or 294K.
+ // Only would happen if both sides (all 2 square meters of surface area) were exposed to sunlight. We now assume it aligned edge on.
+ // It currently should stabilise at 129.6K or -143.6C
+ heat_gain -= surface * STEFAN_BOLTZMANN_CONSTANT * thermal_conductivity * (air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4
+
+ air.add_thermal_energy(heat_gain)
+ if(network)
+ network.update = 1
diff --git a/code/ATMOSPHERICS/he_pipes.dm b/code/ATMOSPHERICS/he_pipes.dm
index 51359ff6efb..0a1d923ed54 100644
--- a/code/ATMOSPHERICS/he_pipes.dm
+++ b/code/ATMOSPHERICS/he_pipes.dm
@@ -1,146 +1,146 @@
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging
- icon = 'icons/atmos/heat.dmi'
- icon_state = "intact"
- pipe_icon = "hepipe"
- color = "#404040"
- level = 2
- connect_types = CONNECT_TYPE_HE
- layer = 2.41
- var/initialize_directions_he
- var/surface = 2 //surface area in m^2
- var/icon_temperature = T20C //stop small changes in temperature causing an icon refresh
-
- minimum_temperature_difference = 20
- thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
-
- buckle_lying = 1
-
- // BubbleWrap
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/Initialize()
- . = ..()
- initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe
-// BubbleWrap END
- color = "#404040" //we don't make use of the fancy overlay system for colours, use this to set the default.
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/atmos_init()
- normalize_dir()
- var/node1_dir
- var/node2_dir
-
- for(var/direction in cardinal)
- if(direction&initialize_directions_he)
- if (!node1_dir)
- node1_dir = direction
- else if (!node2_dir)
- node2_dir = direction
-
- for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node1_dir))
- if(target.initialize_directions_he & get_dir(target,src))
- node1 = target
- break
- for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node2_dir))
- if(target.initialize_directions_he & get_dir(target,src))
- node2 = target
- break
- if(!node1 && !node2)
- qdel(src)
- return
-
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/machinery_process()
- if(!parent)
- ..()
- else
- var/datum/gas_mixture/pipe_air = return_air()
- if(istype(loc, /turf/simulated/))
- var/environment_temperature = 0
- if(loc:blocks_air)
- environment_temperature = loc:temperature
- else
- var/datum/gas_mixture/environment = loc.return_air()
- environment_temperature = environment.temperature
- if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
- parent.temperature_interact(loc, volume, thermal_conductivity)
- else if(istype(loc, /turf/space/))
- parent.radiate_heat_to_space(surface, 1)
-
- if(buckled_mob)
- var/hc = pipe_air.heat_capacity()
- var/avg_temp = (pipe_air.temperature * hc + buckled_mob.bodytemperature * 3500) / (hc + 3500)
- pipe_air.temperature = avg_temp
- buckled_mob.bodytemperature = avg_temp
-
- var/heat_limit = 1000
-
- var/mob/living/carbon/human/H = buckled_mob
- if(istype(H) && H.species)
- heat_limit = H.species.heat_level_3
-
- if(pipe_air.temperature > heat_limit + 1)
- buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_CHEST, used_weapon = "Excessive Heat")
-
- //fancy radiation glowing
- if(pipe_air.temperature && (icon_temperature > 500 || pipe_air.temperature > 500)) //start glowing at 500K
- if(abs(pipe_air.temperature - icon_temperature) > 10)
- icon_temperature = pipe_air.temperature
-
- var/h_r = heat2color_r(icon_temperature)
- var/h_g = heat2color_g(icon_temperature)
- var/h_b = heat2color_b(icon_temperature)
-
- if(icon_temperature < 2000) //scale up overlay until 2000K
- var/scale = (icon_temperature - 500) / 1500
- h_r = 64 + (h_r - 64)*scale
- h_g = 64 + (h_g - 64)*scale
- h_b = 64 + (h_b - 64)*scale
-
- var/list/animate_targets = get_above_oo() + src
- for (var/thing in animate_targets)
- var/atom/movable/AM = thing
- animate(AM, color = rgb(h_r, h_g, h_b), time = 20, easing = SINE_EASING)
-
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction
- icon = 'icons/atmos/junction.dmi'
- icon_state = "intact"
- pipe_icon = "hejunction"
- level = 2
- connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_HE
- minimum_temperature_difference = 300
- thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
-
-// BubbleWrap
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/Initialize()
- . = ..()
- switch (dir)
- if (SOUTH)
- initialize_directions = NORTH
- initialize_directions_he = SOUTH
- if (NORTH)
- initialize_directions = SOUTH
- initialize_directions_he = NORTH
- if (EAST)
- initialize_directions = WEST
- initialize_directions_he = EAST
- if (WEST)
- initialize_directions = EAST
- initialize_directions_he = WEST
- // BubbleWrap END
-
-/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/atmos_init()
- for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions))
- if(target.initialize_directions & get_dir(target,src))
- node1 = target
- break
-
- for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,initialize_directions_he))
- if(target.initialize_directions_he & get_dir(target,src))
- node2 = target
- break
-
- if(!node1 && !node2)
- qdel(src)
- return
-
- queue_icon_update()
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging
+ icon = 'icons/atmos/heat.dmi'
+ icon_state = "intact"
+ pipe_icon = "hepipe"
+ color = "#404040"
+ level = 2
+ connect_types = CONNECT_TYPE_HE
+ layer = 2.41
+ var/initialize_directions_he
+ var/surface = 2 //surface area in m^2
+ var/icon_temperature = T20C //stop small changes in temperature causing an icon refresh
+
+ minimum_temperature_difference = 20
+ thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
+
+ buckle_lying = 1
+
+ // BubbleWrap
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/Initialize()
+ . = ..()
+ initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe
+// BubbleWrap END
+ color = "#404040" //we don't make use of the fancy overlay system for colours, use this to set the default.
+
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/atmos_init()
+ normalize_dir()
+ var/node1_dir
+ var/node2_dir
+
+ for(var/direction in cardinal)
+ if(direction&initialize_directions_he)
+ if (!node1_dir)
+ node1_dir = direction
+ else if (!node2_dir)
+ node2_dir = direction
+
+ for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node1_dir))
+ if(target.initialize_directions_he & get_dir(target,src))
+ node1 = target
+ break
+ for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node2_dir))
+ if(target.initialize_directions_he & get_dir(target,src))
+ node2 = target
+ break
+ if(!node1 && !node2)
+ qdel(src)
+ return
+
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/machinery_process()
+ if(!parent)
+ ..()
+ else
+ var/datum/gas_mixture/pipe_air = return_air()
+ if(istype(loc, /turf/simulated/))
+ var/environment_temperature = 0
+ if(loc:blocks_air)
+ environment_temperature = loc:temperature
+ else
+ var/datum/gas_mixture/environment = loc.return_air()
+ environment_temperature = environment.temperature
+ if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
+ parent.temperature_interact(loc, volume, thermal_conductivity)
+ else if(istype(loc, /turf/space/))
+ parent.radiate_heat_to_space(surface, 1)
+
+ if(buckled_mob)
+ var/hc = pipe_air.heat_capacity()
+ var/avg_temp = (pipe_air.temperature * hc + buckled_mob.bodytemperature * 3500) / (hc + 3500)
+ pipe_air.temperature = avg_temp
+ buckled_mob.bodytemperature = avg_temp
+
+ var/heat_limit = 1000
+
+ var/mob/living/carbon/human/H = buckled_mob
+ if(istype(H) && H.species)
+ heat_limit = H.species.heat_level_3
+
+ if(pipe_air.temperature > heat_limit + 1)
+ buckled_mob.apply_damage(4 * log(pipe_air.temperature - heat_limit), BURN, BP_CHEST, used_weapon = "Excessive Heat")
+
+ //fancy radiation glowing
+ if(pipe_air.temperature && (icon_temperature > 500 || pipe_air.temperature > 500)) //start glowing at 500K
+ if(abs(pipe_air.temperature - icon_temperature) > 10)
+ icon_temperature = pipe_air.temperature
+
+ var/h_r = heat2color_r(icon_temperature)
+ var/h_g = heat2color_g(icon_temperature)
+ var/h_b = heat2color_b(icon_temperature)
+
+ if(icon_temperature < 2000) //scale up overlay until 2000K
+ var/scale = (icon_temperature - 500) / 1500
+ h_r = 64 + (h_r - 64)*scale
+ h_g = 64 + (h_g - 64)*scale
+ h_b = 64 + (h_b - 64)*scale
+
+ var/list/animate_targets = get_above_oo() + src
+ for (var/thing in animate_targets)
+ var/atom/movable/AM = thing
+ animate(AM, color = rgb(h_r, h_g, h_b), time = 20, easing = SINE_EASING)
+
+
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction
+ icon = 'icons/atmos/junction.dmi'
+ icon_state = "intact"
+ pipe_icon = "hejunction"
+ level = 2
+ connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_HE
+ minimum_temperature_difference = 300
+ thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT
+
+// BubbleWrap
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/Initialize()
+ . = ..()
+ switch (dir)
+ if (SOUTH)
+ initialize_directions = NORTH
+ initialize_directions_he = SOUTH
+ if (NORTH)
+ initialize_directions = SOUTH
+ initialize_directions_he = NORTH
+ if (EAST)
+ initialize_directions = WEST
+ initialize_directions_he = EAST
+ if (WEST)
+ initialize_directions = EAST
+ initialize_directions_he = WEST
+ // BubbleWrap END
+
+/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/atmos_init()
+ for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions))
+ if(target.initialize_directions & get_dir(target,src))
+ node1 = target
+ break
+
+ for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,initialize_directions_he))
+ if(target.initialize_directions_he & get_dir(target,src))
+ node2 = target
+ break
+
+ if(!node1 && !node2)
+ qdel(src)
+ return
+
+ queue_icon_update()
diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm
index 4700ae62952..69727bce588 100644
--- a/code/ATMOSPHERICS/pipes.dm
+++ b/code/ATMOSPHERICS/pipes.dm
@@ -1,1412 +1,1412 @@
-/obj/machinery/atmospherics/pipe
-
- var/datum/gas_mixture/air_temporary // used when reconstructing a pipeline that broke
- var/datum/pipeline/parent
- var/volume = 0
- force = 20
-
- layer = PIPE_LAYER
- use_power = 0
-
- var/alert_pressure = 80*ONE_ATMOSPHERE
- //minimum pressure before check_pressure(...) should be called
-
- can_buckle = 1
- buckle_require_restraints = 1
- buckle_lying = -1
-
-/obj/machinery/atmospherics/pipe/drain_power()
- return -1
-
-/obj/machinery/atmospherics/pipe/Initialize()
- if(istype(get_turf(src), /turf/simulated/wall) || istype(get_turf(src), /turf/unsimulated/wall))
- level = 1
- . = ..()
-
-/obj/machinery/atmospherics/pipe/hides_under_flooring()
- return level != 2
-
-/obj/machinery/atmospherics/pipe/proc/pipeline_expansion()
- return null
-
-/obj/machinery/atmospherics/pipe/proc/check_pressure(pressure)
- //Return 1 if parent should continue checking other pipes
- //Return null if parent should stop checking other pipes. Recall: qdel(src) will by default return null
-
- return 1
-
-/obj/machinery/atmospherics/pipe/return_air()
- if(!parent)
- parent = new /datum/pipeline()
- parent.build_pipeline(src)
-
- return parent.air
-
-/obj/machinery/atmospherics/pipe/build_network()
- if(!parent)
- parent = new /datum/pipeline()
- parent.build_pipeline(src)
-
- return parent.return_network()
-
-/obj/machinery/atmospherics/pipe/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
- if(!parent)
- parent = new /datum/pipeline()
- parent.build_pipeline(src)
-
- return parent.network_expand(new_network, reference)
-
-/obj/machinery/atmospherics/pipe/return_network(obj/machinery/atmospherics/reference)
- if(!parent)
- parent = new /datum/pipeline()
- parent.build_pipeline(src)
-
- return parent.return_network(reference)
-
-/obj/machinery/atmospherics/pipe/Destroy()
- QDEL_NULL(parent)
- if(air_temporary)
- loc.assume_air(air_temporary)
- QDEL_NULL(air_temporary)
-
- return ..()
-
-/obj/machinery/atmospherics/pipe/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if (istype(src, /obj/machinery/atmospherics/pipe/tank))
- return ..()
- if (istype(src, /obj/machinery/atmospherics/pipe/vent))
- return ..()
-
- if(istype(W,/obj/item/device/pipe_painter))
- return 0
-
- if (!W.iswrench() && !istype(W, /obj/item/pipewrench))
- return ..()
- var/turf/T = src.loc
- if (level==1 && isturf(T) && !T.is_plating())
- to_chat(user, "You must remove the plating first.")
- return 1
- var/datum/gas_mixture/int_air = return_air()
- var/datum/gas_mixture/env_air = loc.return_air()
- if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
- if(!istype(W, /obj/item/pipewrench))
- to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
- add_fingerprint(user)
- return 1
- else
- to_chat(user, "You struggle to unwrench \the [src] with your pipe wrench.")
- playsound(src.loc, W.usesound, 50, 1)
- to_chat(user, "You begin to unfasten \the [src]...")
- if (do_after(user, istype(W, /obj/item/pipewrench) ? 80/W.toolspeed : 40/W.toolspeed, act_target = src))
- user.visible_message( \
- "\The [user] unfastens \the [src].", \
- "You have unfastened \the [src].", \
- "You hear a ratchet.")
- new /obj/item/pipe(loc, make_from=src)
- for (var/obj/machinery/meter/meter in T)
- if (meter.target == src)
- new /obj/item/pipe_meter(T)
- qdel(meter)
- qdel(src)
-
-/obj/machinery/atmospherics/proc/change_color(var/new_color)
- //only pass valid pipe colors please ~otherwise your pipe will turn invisible
- if(!pipe_color_check(new_color))
- return
-
- pipe_color = new_color
- update_icon()
-
-/*
-/obj/machinery/atmospherics/pipe/add_underlay(var/obj/machinery/atmospherics/node, var/direction)
- if(istype(src, /obj/machinery/atmospherics/pipe/tank)) //todo: move tanks to unary devices
- return ..()
-
- if(node)
- var/temp_dir = get_dir(src, node)
- underlays += icon_manager.get_atmos_icon("pipe_underlay_intact", temp_dir, color_cache_name(node))
- return temp_dir
- else if(direction)
- underlays += icon_manager.get_atmos_icon("pipe_underlay_exposed", direction, pipe_color)
- else
- return null
-*/
-
-/obj/machinery/atmospherics/pipe/color_cache_name(var/obj/machinery/atmospherics/node)
- if(istype(src, /obj/machinery/atmospherics/pipe/tank))
- return ..()
-
- if(istype(node, /obj/machinery/atmospherics/pipe/manifold) || istype(node, /obj/machinery/atmospherics/pipe/manifold4w))
- if(pipe_color == node.pipe_color)
- return node.pipe_color
- else
- return null
- else if(istype(node, /obj/machinery/atmospherics/pipe/simple))
- return node.pipe_color
- else
- return pipe_color
-
-/obj/machinery/atmospherics/pipe/simple
- icon = 'icons/atmos/pipes.dmi'
- icon_state = ""
- var/pipe_icon = "" //what kind of pipe it is and from which dmi is the icon manager getting its icons, "" for simple pipes, "hepipe" for HE pipes, "hejunction" for HE junctions
- name = "pipe"
- desc = "A one meter section of regular pipe"
-
- volume = ATMOS_DEFAULT_VOLUME_PIPE
-
- dir = SOUTH
- initialize_directions = SOUTH|NORTH
-
- var/minimum_temperature_difference = 300
- var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No
-
- var/maximum_pressure = 70*ONE_ATMOSPHERE
- var/fatigue_pressure = 55*ONE_ATMOSPHERE
- alert_pressure = 55*ONE_ATMOSPHERE
-
- level = 1
- gfi_layer_rotation = GFI_ROTATION_DEFDIR
-
-/obj/machinery/atmospherics/pipe/simple/Initialize()
-
- // Pipe colors and icon states are handled by an image cache - so color and icon should
- // be null. For mapping purposes color is defined in the object definitions.
- icon = null
- alpha = 255
-
- switch(dir)
- if(SOUTH || NORTH)
- initialize_directions = SOUTH|NORTH
- if(EAST || WEST)
- initialize_directions = EAST|WEST
- if(NORTHEAST)
- initialize_directions = NORTH|EAST
- if(NORTHWEST)
- initialize_directions = NORTH|WEST
- if(SOUTHEAST)
- initialize_directions = SOUTH|EAST
- if(SOUTHWEST)
- initialize_directions = SOUTH|WEST
- . = ..()
-
-/obj/machinery/atmospherics/pipe/simple/hide(var/i)
- if(istype(loc, /turf/simulated))
- invisibility = i ? 101 : 0
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/simple/machinery_process()
- if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle
- ..()
- else
- . = PROCESS_KILL
-
-/obj/machinery/atmospherics/pipe/simple/check_pressure(pressure)
- var/datum/gas_mixture/environment = loc.return_air()
-
- var/pressure_difference = pressure - environment.return_pressure()
-
- if(pressure_difference > maximum_pressure)
- burst()
-
- else if(pressure_difference > fatigue_pressure)
- //TODO: leak to turf, doing pfshhhhh
- if(prob(5))
- burst()
-
- else return 1
-
-/obj/machinery/atmospherics/pipe/simple/proc/burst()
- src.visible_message("\The [src] bursts!");
- playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
- var/datum/effect/effect/system/smoke_spread/smoke = new
- smoke.set_up(1,0, src.loc, 0)
- smoke.start()
- qdel(src)
-
-/obj/machinery/atmospherics/pipe/simple/proc/normalize_dir()
- if(dir==3)
- set_dir(1)
- else if(dir==12)
- set_dir(4)
-
-/obj/machinery/atmospherics/pipe/simple/Destroy()
- if(node1)
- node1.disconnect(src)
- if(node2)
- node2.disconnect(src)
-
- node1 = null
- node2 = null
-
- return ..()
-
-/obj/machinery/atmospherics/pipe/simple/pipeline_expansion()
- return list(node1, node2)
-
-/obj/machinery/atmospherics/pipe/simple/change_color(var/new_color)
- ..()
- //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
- if(node1)
- node1.update_underlays()
- if(node2)
- node2.update_underlays()
-
-/obj/machinery/atmospherics/pipe/simple/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- cut_overlays()
-
- if(!node1 && !node2)
- var/turf/T = get_turf(src)
- new /obj/item/pipe(loc, make_from=src)
- for (var/obj/machinery/meter/meter in T)
- if (meter.target == src)
- new /obj/item/pipe_meter(T)
- qdel(meter)
- qdel(src)
- else if(node1 && node2)
- add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]intact[icon_connect_type]"))
- else
- add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]exposed[node1?1:0][node2?1:0][icon_connect_type]"))
-
-/obj/machinery/atmospherics/pipe/simple/update_underlays()
- return
-
-/obj/machinery/atmospherics/pipe/simple/atmos_init()
- normalize_dir()
- var/node1_dir
- var/node2_dir
-
- for(var/direction in cardinal)
- if(direction&initialize_directions)
- if (!node1_dir)
- node1_dir = direction
- else if (!node2_dir)
- node2_dir = direction
-
- for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- break
- for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node2 = target
- break
-
- if(!node1 && !node2)
- qdel(src)
- return
-
- var/turf/T = loc
- if(level == 1 && !T.is_plating()) hide(1)
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node1)
- if(istype(node1, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node1 = null
-
- if(reference == node2)
- if(istype(node2, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node2 = null
-
- update_icon()
-
- return null
-
-/obj/machinery/atmospherics/pipe/simple/visible
- icon_state = "intact"
- level = 2
-
-/obj/machinery/atmospherics/pipe/simple/visible/scrubbers
- name = "Scrubbers pipe"
- desc = "A one meter section of scrubbers pipe"
- icon_state = "intact-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/simple/visible/supply
- name = "Air supply pipe"
- desc = "A one meter section of supply pipe"
- icon_state = "intact-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/simple/visible/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/simple/visible/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/simple/visible/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/simple/visible/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/simple/visible/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/simple/visible/blue
- color = PIPE_COLOR_BLUE
-
-
-/obj/machinery/atmospherics/pipe/simple/hidden
- icon_state = "intact"
- level = 1
- alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
-
-/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers
- name = "Scrubbers pipe"
- desc = "A one meter section of scrubbers pipe"
- icon_state = "intact-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/simple/hidden/supply
- name = "Air supply pipe"
- desc = "A one meter section of supply pipe"
- icon_state = "intact-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/simple/hidden/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/simple/hidden/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/simple/hidden/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/simple/hidden/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/simple/hidden/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/simple/hidden/blue
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/simple/insulated
- icon = 'icons/obj/atmospherics/red_pipe.dmi'
- icon_state = "intact"
-
- minimum_temperature_difference = 10000
- thermal_conductivity = 0
- maximum_pressure = 1000*ONE_ATMOSPHERE
- fatigue_pressure = 900*ONE_ATMOSPHERE
- alert_pressure = 900*ONE_ATMOSPHERE
-
- level = 2
-
-
-/obj/machinery/atmospherics/pipe/manifold
- icon = 'icons/atmos/manifold.dmi'
- icon_state = ""
- name = "pipe manifold"
- desc = "A manifold composed of regular pipes"
-
- volume = ATMOS_DEFAULT_VOLUME_PIPE * 1.5
-
- dir = SOUTH
- initialize_directions = EAST|NORTH|WEST
-
- var/obj/machinery/atmospherics/node3
-
- level = 1
- layer = 2.4 //under wires with their 2.44
-
- gfi_layer_rotation = GFI_ROTATION_OVERDIR
-
-/obj/machinery/atmospherics/pipe/manifold/Initialize()
- alpha = 255
- icon = null
-
- switch(dir)
- if(NORTH)
- initialize_directions = EAST|SOUTH|WEST
- if(SOUTH)
- initialize_directions = WEST|NORTH|EAST
- if(EAST)
- initialize_directions = SOUTH|WEST|NORTH
- if(WEST)
- initialize_directions = NORTH|EAST|SOUTH
- . = ..()
-
-/obj/machinery/atmospherics/pipe/manifold/hide(var/i)
- if(istype(loc, /turf/simulated))
- invisibility = i ? 101 : 0
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/manifold/pipeline_expansion()
- return list(node1, node2, node3)
-
-/obj/machinery/atmospherics/pipe/manifold/machinery_process()
- if(!parent)
- ..()
- else
- . = PROCESS_KILL
-
-/obj/machinery/atmospherics/pipe/manifold/Destroy()
- if(node1)
- node1.disconnect(src)
- if(node2)
- node2.disconnect(src)
- if(node3)
- node3.disconnect(src)
-
- node1 = null
- node2 = null
- node3 = null
-
- return ..()
-
-/obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node1)
- if(istype(node1, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node1 = null
-
- if(reference == node2)
- if(istype(node2, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node2 = null
-
- if(reference == node3)
- if(istype(node3, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node3 = null
-
- update_icon()
-
- ..()
-
-/obj/machinery/atmospherics/pipe/manifold/change_color(var/new_color)
- ..()
- //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
- if(node1)
- node1.update_underlays()
- if(node2)
- node2.update_underlays()
- if(node3)
- node3.update_underlays()
-
-/obj/machinery/atmospherics/pipe/manifold/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- if(!node1 && !node2 && !node3)
- var/turf/T = get_turf(src)
- new /obj/item/pipe(loc, make_from=src)
- for (var/obj/machinery/meter/meter in T)
- if (meter.target == src)
- new /obj/item/pipe_meter(T)
- qdel(meter)
- qdel(src)
- else
- cut_overlays()
- add_overlay(icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type))
- add_overlay(icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type))
-
- // Can't handle underlays with SSoverlay.
- underlays.Cut()
-
- var/turf/T = get_turf(src)
- var/list/directions = list(NORTH, SOUTH, EAST, WEST)
- var/node1_direction = get_dir(src, node1)
- var/node2_direction = get_dir(src, node2)
- var/node3_direction = get_dir(src, node3)
-
- directions -= dir
-
- directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
- directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
- directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
-
- for(var/D in directions)
- add_underlay(T,,D,icon_connect_type)
-
-
-/obj/machinery/atmospherics/pipe/manifold/update_underlays()
- ..()
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/manifold/atmos_init()
- var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir)
-
- for(var/direction in cardinal)
- if(direction&connect_directions)
- for(var/obj/machinery/atmospherics/target in get_step(src,direction))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- connect_directions &= ~direction
- break
- if (node1)
- break
-
-
- for(var/direction in cardinal)
- if(direction&connect_directions)
- for(var/obj/machinery/atmospherics/target in get_step(src,direction))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node2 = target
- connect_directions &= ~direction
- break
- if (node2)
- break
-
-
- for(var/direction in cardinal)
- if(direction&connect_directions)
- for(var/obj/machinery/atmospherics/target in get_step(src,direction))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node3 = target
- connect_directions &= ~direction
- break
- if (node3)
- break
-
- if(!node1 && !node2 && !node3)
- qdel(src)
- return
-
- var/turf/T = get_turf(src)
- if(level == 1 && !T.is_plating()) hide(1)
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/manifold/visible
- icon_state = "map"
- level = 2
-
-/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers
- name="Scrubbers pipe manifold"
- desc = "A manifold composed of scrubbers pipes"
- icon_state = "map-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold/visible/supply
- name="Air supply pipe manifold"
- desc = "A manifold composed of supply pipes"
- icon_state = "map-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold/visible/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/manifold/visible/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/manifold/visible/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/manifold/visible/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/manifold/visible/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold/visible/blue
- color = PIPE_COLOR_BLUE
-
-
-/obj/machinery/atmospherics/pipe/manifold/hidden
- icon_state = "map"
- level = 1
- alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers
- name="Scrubbers pipe manifold"
- desc = "A manifold composed of scrubbers pipes"
- icon_state = "map-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/supply
- name="Air supply pipe manifold"
- desc = "A manifold composed of supply pipes"
- icon_state = "map-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold/hidden/blue
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold4w
- icon = 'icons/atmos/manifold.dmi'
- icon_state = ""
- name = "4-way pipe manifold"
- desc = "A manifold composed of regular pipes"
-
- volume = ATMOS_DEFAULT_VOLUME_PIPE * 2
-
- dir = SOUTH
- initialize_directions = NORTH|SOUTH|EAST|WEST
-
- var/obj/machinery/atmospherics/node3
- var/obj/machinery/atmospherics/node4
-
- level = 1
- layer = 2.4 //under wires with their 2.44
-
-/obj/machinery/atmospherics/pipe/manifold4w/Initialize()
- . = ..()
- alpha = 255
- icon = null
-
-/obj/machinery/atmospherics/pipe/manifold4w/pipeline_expansion()
- return list(node1, node2, node3, node4)
-
-/obj/machinery/atmospherics/pipe/manifold4w/machinery_process()
- if(!parent)
- ..()
- else
- . = PROCESS_KILL
-
-/obj/machinery/atmospherics/pipe/manifold4w/Destroy()
- if(node1)
- node1.disconnect(src)
- if(node2)
- node2.disconnect(src)
- if(node3)
- node3.disconnect(src)
- if(node4)
- node4.disconnect(src)
-
- node1 = null
- node2 = null
- node3 = null
- node4 = null
-
- return ..()
-
-/obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node1)
- if(istype(node1, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node1 = null
-
- if(reference == node2)
- if(istype(node2, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node2 = null
-
- if(reference == node3)
- if(istype(node3, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node3 = null
-
- if(reference == node4)
- if(istype(node4, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node4 = null
-
- update_icon()
-
- ..()
-
-/obj/machinery/atmospherics/pipe/manifold4w/change_color(var/new_color)
- ..()
- //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
- if(node1)
- node1.update_underlays()
- if(node2)
- node2.update_underlays()
- if(node3)
- node3.update_underlays()
- if(node4)
- node4.update_underlays()
-
-/obj/machinery/atmospherics/pipe/manifold4w/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- if(!node1 && !node2 && !node3 && !node4)
- var/turf/T = get_turf(src)
- new /obj/item/pipe(loc, make_from=src)
- for (var/obj/machinery/meter/meter in T)
- if (meter.target == src)
- new /obj/item/pipe_meter(T)
- qdel(meter)
- qdel(src)
- else
- cut_overlays()
- add_overlay(icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type))
- add_overlay(icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type))
-
- underlays.Cut()
-
- /*
- var/list/directions = list(NORTH, SOUTH, EAST, WEST)
-
-
- directions -= add_underlay(node1)
- directions -= add_underlay(node2)
- directions -= add_underlay(node3)
- directions -= add_underlay(node4)
-
- for(var/D in directions)
- add_underlay(,D)
- */
-
- var/turf/T = get_turf(src)
- var/list/directions = list(NORTH, SOUTH, EAST, WEST)
- var/node1_direction = get_dir(src, node1)
- var/node2_direction = get_dir(src, node2)
- var/node3_direction = get_dir(src, node3)
- var/node4_direction = get_dir(src, node4)
-
- directions -= dir
-
- directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
- directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
- directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
- directions -= add_underlay(T,node4,node4_direction,icon_connect_type)
-
- for(var/D in directions)
- add_underlay(T,,D,icon_connect_type)
-
-
-/obj/machinery/atmospherics/pipe/manifold4w/update_underlays()
- ..()
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/manifold4w/hide(var/i)
- if(istype(loc, /turf/simulated))
- invisibility = i ? 101 : 0
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/manifold4w/atmos_init()
-
- for(var/obj/machinery/atmospherics/target in get_step(src,1))
- if(target.initialize_directions & 2)
- if (check_connect_types(target,src))
- node1 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,2))
- if(target.initialize_directions & 1)
- if (check_connect_types(target,src))
- node2 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,4))
- if(target.initialize_directions & 8)
- if (check_connect_types(target,src))
- node3 = target
- break
-
- for(var/obj/machinery/atmospherics/target in get_step(src,8))
- if(target.initialize_directions & 4)
- if (check_connect_types(target,src))
- node4 = target
- break
-
- if(!node1 && !node2 && !node3 && !node4)
- qdel(src)
- return
-
- var/turf/T = get_turf(src)
- if(level == 1 && !T.is_plating()) hide(1)
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible
- icon_state = "map_4way"
- level = 2
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers
- name="4-way scrubbers pipe manifold"
- desc = "A manifold composed of scrubbers pipes"
- icon_state = "map_4way-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/supply
- name="4-way air supply pipe manifold"
- desc = "A manifold composed of supply pipes"
- icon_state = "map_4way-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold4w/visible/blue
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden
- icon_state = "map_4way"
- level = 1
- alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers
- name="4-way scrubbers pipe manifold"
- desc = "A manifold composed of scrubbers pipes"
- icon_state = "map_4way-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply
- name="4-way air supply pipe manifold"
- desc = "A manifold composed of supply pipes"
- icon_state = "map_4way-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow
- color = PIPE_COLOR_YELLOW
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/cyan
- color = PIPE_COLOR_CYAN
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/green
- color = PIPE_COLOR_GREEN
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/black
- color = PIPE_COLOR_BLACK
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/red
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/manifold4w/hidden/blue
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/cap
- name = "pipe endcap"
- desc = "An endcap for pipes"
- icon = 'icons/atmos/pipes.dmi'
- icon_state = ""
- level = 2
- layer = 2.4 //under wires with their 2.44
-
- volume = 35
-
- dir = SOUTH
- initialize_directions = SOUTH
-
- var/obj/machinery/atmospherics/node
-
-/obj/machinery/atmospherics/pipe/cap/Initialize()
- initialize_directions = dir
- . = ..()
-
-/obj/machinery/atmospherics/pipe/cap/hide(var/i)
- if(istype(loc, /turf/simulated))
- invisibility = i ? 101 : 0
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/cap/pipeline_expansion()
- return list(node)
-
-/obj/machinery/atmospherics/pipe/cap/machinery_process()
- if(!parent)
- ..()
- else
- . = PROCESS_KILL
-/obj/machinery/atmospherics/pipe/cap/Destroy()
- if(node)
- node.disconnect(src)
-
- node = null
-
- return ..()
-
-/obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node)
- if(istype(node, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node = null
-
- update_icon()
-
- ..()
-
-/obj/machinery/atmospherics/pipe/cap/change_color(var/new_color)
- ..()
- //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
- if(node)
- node.update_underlays()
-
-/obj/machinery/atmospherics/pipe/cap/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- cut_overlays()
- add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "cap"))
-
-/obj/machinery/atmospherics/pipe/cap/atmos_init()
- for(var/obj/machinery/atmospherics/target in get_step(src, dir))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node = target
- break
-
- var/turf/T = src.loc // hide if turf is not intact
- if(level == 1 && !T.is_plating()) hide(1)
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/cap/visible
- level = 2
- icon_state = "cap"
-
-/obj/machinery/atmospherics/pipe/cap/visible/scrubbers
- name = "scrubbers pipe endcap"
- desc = "An endcap for scrubbers pipes"
- icon_state = "cap-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/cap/visible/supply
- name = "supply pipe endcap"
- desc = "An endcap for supply pipes"
- icon_state = "cap-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-/obj/machinery/atmospherics/pipe/cap/hidden
- level = 1
- icon_state = "cap"
- alpha = 128
-
-/obj/machinery/atmospherics/pipe/cap/hidden/scrubbers
- name = "scrubbers pipe endcap"
- desc = "An endcap for scrubbers pipes"
- icon_state = "cap-f-scrubbers"
- connect_types = CONNECT_TYPE_SCRUBBER
- layer = 2.38
- icon_connect_type = "-scrubbers"
- color = PIPE_COLOR_RED
-
-/obj/machinery/atmospherics/pipe/cap/hidden/supply
- name = "supply pipe endcap"
- desc = "An endcap for supply pipes"
- icon_state = "cap-f-supply"
- connect_types = CONNECT_TYPE_SUPPLY
- layer = 2.39
- icon_connect_type = "-supply"
- color = PIPE_COLOR_BLUE
-
-
-/obj/machinery/atmospherics/pipe/tank
- icon = 'icons/atmos/tank.dmi'
- icon_state = "air_map"
-
- name = "Pressure Tank"
- desc = "A large vessel containing pressurized gas."
-
- volume = 10000 //in liters, 1 meters by 1 meters by 2 meters ~tweaked it a little to simulate a pressure tank without needing to recode them yet
- var/start_pressure = 25*ONE_ATMOSPHERE
-
- level = 1
- dir = SOUTH
- initialize_directions = SOUTH
- density = 1
-
-/obj/machinery/atmospherics/pipe/tank/Initialize()
- icon_state = "air"
- initialize_directions = dir
- . = ..()
-
-/obj/machinery/atmospherics/pipe/tank/machinery_process()
- if(!parent)
- ..()
- else
- . = PROCESS_KILL
-
-/obj/machinery/atmospherics/pipe/tank/Destroy()
- if(node1)
- node1.disconnect(src)
-
- node1 = null
-
- return ..()
-
-/obj/machinery/atmospherics/pipe/tank/pipeline_expansion()
- return list(node1)
-
-/obj/machinery/atmospherics/pipe/tank/update_underlays()
- if(..())
- underlays.Cut()
- var/turf/T = get_turf(src)
- if(!istype(T))
- return
- add_underlay(T, node1, dir)
-
-/obj/machinery/atmospherics/pipe/tank/hide()
- update_underlays()
-
-/obj/machinery/atmospherics/pipe/tank/atmos_init()
- var/connect_direction = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- break
-
- update_underlays()
-
-/obj/machinery/atmospherics/pipe/tank/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node1)
- if(istype(node1, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node1 = null
-
- update_underlays()
-
- return null
-
-/obj/machinery/atmospherics/pipe/tank/attackby(var/obj/item/W as obj, var/mob/user as mob)
- if(istype(W, /obj/item/device/pipe_painter))
- return
-
- if(istype(W, /obj/item/device/analyzer) && in_range(user, src))
- var/obj/item/device/analyzer/A = W
- A.analyze_gases(src, user)
-
-/obj/machinery/atmospherics/pipe/tank/air
- name = "Pressure Tank (Air)"
- icon_state = "air_map"
-
-/obj/machinery/atmospherics/pipe/tank/air/Initialize()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T20C
-
- air_temporary.adjust_multi("oxygen", (start_pressure*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature), \
- "nitrogen",(start_pressure*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
-
- . = ..()
- icon_state = "air"
-
-/obj/machinery/atmospherics/pipe/tank/oxygen
- name = "Pressure Tank (Oxygen)"
- icon_state = "o2_map"
-
-/obj/machinery/atmospherics/pipe/tank/oxygen/Initialize()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T20C
-
- air_temporary.adjust_gas("oxygen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
- . = ..()
- icon_state = "o2"
-
-/obj/machinery/atmospherics/pipe/tank/nitrogen
- name = "Pressure Tank (Nitrogen)"
- icon_state = "n2_map"
-
-/obj/machinery/atmospherics/pipe/tank/nitrogen/Initialize()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T20C
-
- air_temporary.adjust_gas("nitrogen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
- . = ..()
- icon_state = "n2"
-
-/obj/machinery/atmospherics/pipe/tank/carbon_dioxide
- name = "Pressure Tank (Carbon Dioxide)"
- icon_state = "co2_map"
-
-/obj/machinery/atmospherics/pipe/tank/carbon_dioxide/Initialize()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T20C
-
- air_temporary.adjust_gas("carbon_dioxide", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
- . = ..()
- icon_state = "co2"
-
-/obj/machinery/atmospherics/pipe/tank/phoron
- name = "Pressure Tank (Phoron)"
- icon_state = "phoron_map"
-
-/obj/machinery/atmospherics/pipe/tank/phoron/Initialize()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T20C
-
- air_temporary.adjust_gas("phoron", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
- . = ..()
- icon_state = "phoron"
-
-/obj/machinery/atmospherics/pipe/tank/nitrous_oxide
- name = "Pressure Tank (Nitrous Oxide)"
- icon_state = "n2o_map"
-
-/obj/machinery/atmospherics/pipe/tank/nitrous_oxide/Initialize()
- air_temporary = new
- air_temporary.volume = volume
- air_temporary.temperature = T0C
-
- air_temporary.adjust_gas("sleeping_agent", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
-
- . = ..()
- icon_state = "n2o"
-
-/obj/machinery/atmospherics/pipe/vent
- icon = 'icons/obj/atmospherics/pipe_vent.dmi'
- icon_state = "intact"
-
- name = "Vent"
- desc = "A large air vent"
-
- level = 1
-
- volume = 250
-
- dir = SOUTH
- initialize_directions = SOUTH
-
- var/build_killswitch = 1
-
-/obj/machinery/atmospherics/pipe/vent/Initialize()
- initialize_directions = dir
- . = ..()
-
-/obj/machinery/atmospherics/pipe/vent/high_volume
- name = "Larger vent"
- volume = 1000
-
-/obj/machinery/atmospherics/pipe/vent/machinery_process()
- if(!parent)
- if(build_killswitch <= 0)
- . = PROCESS_KILL
- else
- build_killswitch--
- ..()
- return
- else
- parent.mingle_with_turf(loc, volume)
-
-/obj/machinery/atmospherics/pipe/vent/Destroy()
- if(node1)
- node1.disconnect(src)
-
- node1 = null
-
- return ..()
-
-/obj/machinery/atmospherics/pipe/vent/pipeline_expansion()
- return list(node1)
-
-/obj/machinery/atmospherics/pipe/vent/update_icon()
- if(node1)
- icon_state = "intact"
-
- set_dir(get_dir(src, node1))
-
- else
- icon_state = "exposed"
-
-/obj/machinery/atmospherics/pipe/vent/atmos_init()
- var/connect_direction = dir
-
- for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
- if(target.initialize_directions & get_dir(target,src))
- if (check_connect_types(target,src))
- node1 = target
- break
-
- queue_icon_update()
-
-/obj/machinery/atmospherics/pipe/vent/disconnect(obj/machinery/atmospherics/reference)
- if(reference == node1)
- if(istype(node1, /obj/machinery/atmospherics/pipe))
- QDEL_NULL(parent)
- node1 = null
-
- update_icon()
-
- return null
-
-/obj/machinery/atmospherics/pipe/vent/hide(var/i) //to make the little pipe section invisible, the icon changes.
- if(node1)
- icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact"
- set_dir(get_dir(src, node1))
- else
- icon_state = "exposed"
-
-
-/obj/machinery/atmospherics/pipe/simple/visible/universal
- name="Universal pipe adapter"
- desc = "An adapter for regular, supply and scrubbers pipes"
- connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
- icon_state = "map_universal"
- gfi_layer_rotation = GFI_ROTATION_OVERDIR
-
-/obj/machinery/atmospherics/pipe/simple/visible/universal/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- cut_overlays()
- add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "universal"))
- underlays.Cut()
-
- if (node1)
- universal_underlays(node1)
- if(node2)
- universal_underlays(node2)
- else
- var/node1_dir = get_dir(node1,src)
- universal_underlays(,node1_dir)
- else if (node2)
- universal_underlays(node2)
- else
- universal_underlays(,dir)
- universal_underlays(,turn(dir, -180))
-
-/obj/machinery/atmospherics/pipe/simple/visible/universal/update_underlays()
- ..()
- queue_icon_update()
-
-
-
-/obj/machinery/atmospherics/pipe/simple/hidden/universal
- name="Universal pipe adapter"
- desc = "An adapter for regular, supply and scrubbers pipes"
- connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
- icon_state = "map_universal"
- gfi_layer_rotation = GFI_ROTATION_OVERDIR
-
-/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(var/safety = 0)
- if(!check_icon_cache())
- return
-
- alpha = 255
-
- cut_overlays()
- add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "universal"))
-
- underlays.Cut()
-
- if (node1)
- universal_underlays(node1)
- if(node2)
- universal_underlays(node2)
- else
- var/node2_dir = turn(get_dir(src,node1),-180)
- universal_underlays(,node2_dir)
- else if (node2)
- universal_underlays(node2)
- var/node1_dir = turn(get_dir(src,node2),-180)
- universal_underlays(,node1_dir)
- else
- universal_underlays(,dir)
- universal_underlays(,turn(dir, -180))
-
-/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_underlays()
- ..()
- queue_icon_update()
-
-/obj/machinery/atmospherics/proc/universal_underlays(var/obj/machinery/atmospherics/node, var/direction)
- var/turf/T = loc
- if(node)
- var/node_dir = get_dir(src,node)
- if(node.icon_connect_type == "-supply")
- add_underlay_adapter(T, , node_dir, "")
- add_underlay_adapter(T, node, node_dir, "-supply")
- add_underlay_adapter(T, , node_dir, "-scrubbers")
- else if (node.icon_connect_type == "-scrubbers")
- add_underlay_adapter(T, , node_dir, "")
- add_underlay_adapter(T, , node_dir, "-supply")
- add_underlay_adapter(T, node, node_dir, "-scrubbers")
- else
- add_underlay_adapter(T, node, node_dir, "")
- add_underlay_adapter(T, , node_dir, "-supply")
- add_underlay_adapter(T, , node_dir, "-scrubbers")
- else
- add_underlay_adapter(T, , direction, "-supply")
- add_underlay_adapter(T, , direction, "-scrubbers")
- add_underlay_adapter(T, , direction, "")
-
-/obj/machinery/atmospherics/proc/add_underlay_adapter(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type) //modified from add_underlay, does not make exposed underlays
- if(node)
- if(!T.is_plating() && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
- else
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
- else
- underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "retracted" + icon_connect_type)
+/obj/machinery/atmospherics/pipe
+
+ var/datum/gas_mixture/air_temporary // used when reconstructing a pipeline that broke
+ var/datum/pipeline/parent
+ var/volume = 0
+ force = 20
+
+ layer = PIPE_LAYER
+ use_power = 0
+
+ var/alert_pressure = 80*ONE_ATMOSPHERE
+ //minimum pressure before check_pressure(...) should be called
+
+ can_buckle = 1
+ buckle_require_restraints = 1
+ buckle_lying = -1
+
+/obj/machinery/atmospherics/pipe/drain_power()
+ return -1
+
+/obj/machinery/atmospherics/pipe/Initialize()
+ if(istype(get_turf(src), /turf/simulated/wall) || istype(get_turf(src), /turf/unsimulated/wall))
+ level = 1
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/hides_under_flooring()
+ return level != 2
+
+/obj/machinery/atmospherics/pipe/proc/pipeline_expansion()
+ return null
+
+/obj/machinery/atmospherics/pipe/proc/check_pressure(pressure)
+ //Return 1 if parent should continue checking other pipes
+ //Return null if parent should stop checking other pipes. Recall: qdel(src) will by default return null
+
+ return 1
+
+/obj/machinery/atmospherics/pipe/return_air()
+ if(!parent)
+ parent = new /datum/pipeline()
+ parent.build_pipeline(src)
+
+ return parent.air
+
+/obj/machinery/atmospherics/pipe/build_network()
+ if(!parent)
+ parent = new /datum/pipeline()
+ parent.build_pipeline(src)
+
+ return parent.return_network()
+
+/obj/machinery/atmospherics/pipe/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
+ if(!parent)
+ parent = new /datum/pipeline()
+ parent.build_pipeline(src)
+
+ return parent.network_expand(new_network, reference)
+
+/obj/machinery/atmospherics/pipe/return_network(obj/machinery/atmospherics/reference)
+ if(!parent)
+ parent = new /datum/pipeline()
+ parent.build_pipeline(src)
+
+ return parent.return_network(reference)
+
+/obj/machinery/atmospherics/pipe/Destroy()
+ QDEL_NULL(parent)
+ if(air_temporary)
+ loc.assume_air(air_temporary)
+ QDEL_NULL(air_temporary)
+
+ return ..()
+
+/obj/machinery/atmospherics/pipe/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if (istype(src, /obj/machinery/atmospherics/pipe/tank))
+ return ..()
+ if (istype(src, /obj/machinery/atmospherics/pipe/vent))
+ return ..()
+
+ if(istype(W,/obj/item/device/pipe_painter))
+ return 0
+
+ if (!W.iswrench() && !istype(W, /obj/item/pipewrench))
+ return ..()
+ var/turf/T = src.loc
+ if (level==1 && isturf(T) && !T.is_plating())
+ to_chat(user, "You must remove the plating first.")
+ return 1
+ var/datum/gas_mixture/int_air = return_air()
+ var/datum/gas_mixture/env_air = loc.return_air()
+ if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
+ if(!istype(W, /obj/item/pipewrench))
+ to_chat(user, "You cannot unwrench \the [src], it is too exerted due to internal pressure.")
+ add_fingerprint(user)
+ return 1
+ else
+ to_chat(user, "You struggle to unwrench \the [src] with your pipe wrench.")
+ playsound(src.loc, W.usesound, 50, 1)
+ to_chat(user, "You begin to unfasten \the [src]...")
+ if (do_after(user, istype(W, /obj/item/pipewrench) ? 80/W.toolspeed : 40/W.toolspeed, act_target = src))
+ user.visible_message( \
+ "\The [user] unfastens \the [src].", \
+ "You have unfastened \the [src].", \
+ "You hear a ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ for (var/obj/machinery/meter/meter in T)
+ if (meter.target == src)
+ new /obj/item/pipe_meter(T)
+ qdel(meter)
+ qdel(src)
+
+/obj/machinery/atmospherics/proc/change_color(var/new_color)
+ //only pass valid pipe colors please ~otherwise your pipe will turn invisible
+ if(!pipe_color_check(new_color))
+ return
+
+ pipe_color = new_color
+ update_icon()
+
+/*
+/obj/machinery/atmospherics/pipe/add_underlay(var/obj/machinery/atmospherics/node, var/direction)
+ if(istype(src, /obj/machinery/atmospherics/pipe/tank)) //todo: move tanks to unary devices
+ return ..()
+
+ if(node)
+ var/temp_dir = get_dir(src, node)
+ underlays += icon_manager.get_atmos_icon("pipe_underlay_intact", temp_dir, color_cache_name(node))
+ return temp_dir
+ else if(direction)
+ underlays += icon_manager.get_atmos_icon("pipe_underlay_exposed", direction, pipe_color)
+ else
+ return null
+*/
+
+/obj/machinery/atmospherics/pipe/color_cache_name(var/obj/machinery/atmospherics/node)
+ if(istype(src, /obj/machinery/atmospherics/pipe/tank))
+ return ..()
+
+ if(istype(node, /obj/machinery/atmospherics/pipe/manifold) || istype(node, /obj/machinery/atmospherics/pipe/manifold4w))
+ if(pipe_color == node.pipe_color)
+ return node.pipe_color
+ else
+ return null
+ else if(istype(node, /obj/machinery/atmospherics/pipe/simple))
+ return node.pipe_color
+ else
+ return pipe_color
+
+/obj/machinery/atmospherics/pipe/simple
+ icon = 'icons/atmos/pipes.dmi'
+ icon_state = ""
+ var/pipe_icon = "" //what kind of pipe it is and from which dmi is the icon manager getting its icons, "" for simple pipes, "hepipe" for HE pipes, "hejunction" for HE junctions
+ name = "pipe"
+ desc = "A one meter section of regular pipe"
+
+ volume = ATMOS_DEFAULT_VOLUME_PIPE
+
+ dir = SOUTH
+ initialize_directions = SOUTH|NORTH
+
+ var/minimum_temperature_difference = 300
+ var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No
+
+ var/maximum_pressure = 70*ONE_ATMOSPHERE
+ var/fatigue_pressure = 55*ONE_ATMOSPHERE
+ alert_pressure = 55*ONE_ATMOSPHERE
+
+ level = 1
+ gfi_layer_rotation = GFI_ROTATION_DEFDIR
+
+/obj/machinery/atmospherics/pipe/simple/Initialize()
+
+ // Pipe colors and icon states are handled by an image cache - so color and icon should
+ // be null. For mapping purposes color is defined in the object definitions.
+ icon = null
+ alpha = 255
+
+ switch(dir)
+ if(SOUTH || NORTH)
+ initialize_directions = SOUTH|NORTH
+ if(EAST || WEST)
+ initialize_directions = EAST|WEST
+ if(NORTHEAST)
+ initialize_directions = NORTH|EAST
+ if(NORTHWEST)
+ initialize_directions = NORTH|WEST
+ if(SOUTHEAST)
+ initialize_directions = SOUTH|EAST
+ if(SOUTHWEST)
+ initialize_directions = SOUTH|WEST
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/simple/hide(var/i)
+ if(istype(loc, /turf/simulated))
+ invisibility = i ? 101 : 0
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/simple/machinery_process()
+ if(!parent) //This should cut back on the overhead calling build_network thousands of times per cycle
+ ..()
+ else
+ . = PROCESS_KILL
+
+/obj/machinery/atmospherics/pipe/simple/check_pressure(pressure)
+ var/datum/gas_mixture/environment = loc.return_air()
+
+ var/pressure_difference = pressure - environment.return_pressure()
+
+ if(pressure_difference > maximum_pressure)
+ burst()
+
+ else if(pressure_difference > fatigue_pressure)
+ //TODO: leak to turf, doing pfshhhhh
+ if(prob(5))
+ burst()
+
+ else return 1
+
+/obj/machinery/atmospherics/pipe/simple/proc/burst()
+ src.visible_message("\The [src] bursts!");
+ playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
+ var/datum/effect/effect/system/smoke_spread/smoke = new
+ smoke.set_up(1,0, src.loc, 0)
+ smoke.start()
+ qdel(src)
+
+/obj/machinery/atmospherics/pipe/simple/proc/normalize_dir()
+ if(dir==3)
+ set_dir(1)
+ else if(dir==12)
+ set_dir(4)
+
+/obj/machinery/atmospherics/pipe/simple/Destroy()
+ if(node1)
+ node1.disconnect(src)
+ if(node2)
+ node2.disconnect(src)
+
+ node1 = null
+ node2 = null
+
+ return ..()
+
+/obj/machinery/atmospherics/pipe/simple/pipeline_expansion()
+ return list(node1, node2)
+
+/obj/machinery/atmospherics/pipe/simple/change_color(var/new_color)
+ ..()
+ //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
+ if(node1)
+ node1.update_underlays()
+ if(node2)
+ node2.update_underlays()
+
+/obj/machinery/atmospherics/pipe/simple/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ cut_overlays()
+
+ if(!node1 && !node2)
+ var/turf/T = get_turf(src)
+ new /obj/item/pipe(loc, make_from=src)
+ for (var/obj/machinery/meter/meter in T)
+ if (meter.target == src)
+ new /obj/item/pipe_meter(T)
+ qdel(meter)
+ qdel(src)
+ else if(node1 && node2)
+ add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]intact[icon_connect_type]"))
+ else
+ add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "[pipe_icon]exposed[node1?1:0][node2?1:0][icon_connect_type]"))
+
+/obj/machinery/atmospherics/pipe/simple/update_underlays()
+ return
+
+/obj/machinery/atmospherics/pipe/simple/atmos_init()
+ normalize_dir()
+ var/node1_dir
+ var/node2_dir
+
+ for(var/direction in cardinal)
+ if(direction&initialize_directions)
+ if (!node1_dir)
+ node1_dir = direction
+ else if (!node2_dir)
+ node2_dir = direction
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+ for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node2 = target
+ break
+
+ if(!node1 && !node2)
+ qdel(src)
+ return
+
+ var/turf/T = loc
+ if(level == 1 && !T.is_plating()) hide(1)
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/simple/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node1)
+ if(istype(node1, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node1 = null
+
+ if(reference == node2)
+ if(istype(node2, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node2 = null
+
+ update_icon()
+
+ return null
+
+/obj/machinery/atmospherics/pipe/simple/visible
+ icon_state = "intact"
+ level = 2
+
+/obj/machinery/atmospherics/pipe/simple/visible/scrubbers
+ name = "Scrubbers pipe"
+ desc = "A one meter section of scrubbers pipe"
+ icon_state = "intact-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/simple/visible/supply
+ name = "Air supply pipe"
+ desc = "A one meter section of supply pipe"
+ icon_state = "intact-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/simple/visible/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/simple/visible/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/simple/visible/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/simple/visible/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/simple/visible/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/simple/visible/blue
+ color = PIPE_COLOR_BLUE
+
+
+/obj/machinery/atmospherics/pipe/simple/hidden
+ icon_state = "intact"
+ level = 1
+ alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
+
+/obj/machinery/atmospherics/pipe/simple/hidden/scrubbers
+ name = "Scrubbers pipe"
+ desc = "A one meter section of scrubbers pipe"
+ icon_state = "intact-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/simple/hidden/supply
+ name = "Air supply pipe"
+ desc = "A one meter section of supply pipe"
+ icon_state = "intact-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/simple/hidden/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/simple/hidden/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/simple/hidden/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/simple/hidden/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/simple/hidden/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/simple/hidden/blue
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/simple/insulated
+ icon = 'icons/obj/atmospherics/red_pipe.dmi'
+ icon_state = "intact"
+
+ minimum_temperature_difference = 10000
+ thermal_conductivity = 0
+ maximum_pressure = 1000*ONE_ATMOSPHERE
+ fatigue_pressure = 900*ONE_ATMOSPHERE
+ alert_pressure = 900*ONE_ATMOSPHERE
+
+ level = 2
+
+
+/obj/machinery/atmospherics/pipe/manifold
+ icon = 'icons/atmos/manifold.dmi'
+ icon_state = ""
+ name = "pipe manifold"
+ desc = "A manifold composed of regular pipes"
+
+ volume = ATMOS_DEFAULT_VOLUME_PIPE * 1.5
+
+ dir = SOUTH
+ initialize_directions = EAST|NORTH|WEST
+
+ var/obj/machinery/atmospherics/node3
+
+ level = 1
+ layer = 2.4 //under wires with their 2.44
+
+ gfi_layer_rotation = GFI_ROTATION_OVERDIR
+
+/obj/machinery/atmospherics/pipe/manifold/Initialize()
+ alpha = 255
+ icon = null
+
+ switch(dir)
+ if(NORTH)
+ initialize_directions = EAST|SOUTH|WEST
+ if(SOUTH)
+ initialize_directions = WEST|NORTH|EAST
+ if(EAST)
+ initialize_directions = SOUTH|WEST|NORTH
+ if(WEST)
+ initialize_directions = NORTH|EAST|SOUTH
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/manifold/hide(var/i)
+ if(istype(loc, /turf/simulated))
+ invisibility = i ? 101 : 0
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/manifold/pipeline_expansion()
+ return list(node1, node2, node3)
+
+/obj/machinery/atmospherics/pipe/manifold/machinery_process()
+ if(!parent)
+ ..()
+ else
+ . = PROCESS_KILL
+
+/obj/machinery/atmospherics/pipe/manifold/Destroy()
+ if(node1)
+ node1.disconnect(src)
+ if(node2)
+ node2.disconnect(src)
+ if(node3)
+ node3.disconnect(src)
+
+ node1 = null
+ node2 = null
+ node3 = null
+
+ return ..()
+
+/obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node1)
+ if(istype(node1, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node1 = null
+
+ if(reference == node2)
+ if(istype(node2, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node2 = null
+
+ if(reference == node3)
+ if(istype(node3, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node3 = null
+
+ update_icon()
+
+ ..()
+
+/obj/machinery/atmospherics/pipe/manifold/change_color(var/new_color)
+ ..()
+ //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
+ if(node1)
+ node1.update_underlays()
+ if(node2)
+ node2.update_underlays()
+ if(node3)
+ node3.update_underlays()
+
+/obj/machinery/atmospherics/pipe/manifold/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ if(!node1 && !node2 && !node3)
+ var/turf/T = get_turf(src)
+ new /obj/item/pipe(loc, make_from=src)
+ for (var/obj/machinery/meter/meter in T)
+ if (meter.target == src)
+ new /obj/item/pipe_meter(T)
+ qdel(meter)
+ qdel(src)
+ else
+ cut_overlays()
+ add_overlay(icon_manager.get_atmos_icon("manifold", , pipe_color, "core" + icon_connect_type))
+ add_overlay(icon_manager.get_atmos_icon("manifold", , , "clamps" + icon_connect_type))
+
+ // Can't handle underlays with SSoverlay.
+ underlays.Cut()
+
+ var/turf/T = get_turf(src)
+ var/list/directions = list(NORTH, SOUTH, EAST, WEST)
+ var/node1_direction = get_dir(src, node1)
+ var/node2_direction = get_dir(src, node2)
+ var/node3_direction = get_dir(src, node3)
+
+ directions -= dir
+
+ directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
+ directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
+ directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
+
+ for(var/D in directions)
+ add_underlay(T,,D,icon_connect_type)
+
+
+/obj/machinery/atmospherics/pipe/manifold/update_underlays()
+ ..()
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/manifold/atmos_init()
+ var/connect_directions = (NORTH|SOUTH|EAST|WEST)&(~dir)
+
+ for(var/direction in cardinal)
+ if(direction&connect_directions)
+ for(var/obj/machinery/atmospherics/target in get_step(src,direction))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ connect_directions &= ~direction
+ break
+ if (node1)
+ break
+
+
+ for(var/direction in cardinal)
+ if(direction&connect_directions)
+ for(var/obj/machinery/atmospherics/target in get_step(src,direction))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node2 = target
+ connect_directions &= ~direction
+ break
+ if (node2)
+ break
+
+
+ for(var/direction in cardinal)
+ if(direction&connect_directions)
+ for(var/obj/machinery/atmospherics/target in get_step(src,direction))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node3 = target
+ connect_directions &= ~direction
+ break
+ if (node3)
+ break
+
+ if(!node1 && !node2 && !node3)
+ qdel(src)
+ return
+
+ var/turf/T = get_turf(src)
+ if(level == 1 && !T.is_plating()) hide(1)
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/manifold/visible
+ icon_state = "map"
+ level = 2
+
+/obj/machinery/atmospherics/pipe/manifold/visible/scrubbers
+ name="Scrubbers pipe manifold"
+ desc = "A manifold composed of scrubbers pipes"
+ icon_state = "map-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold/visible/supply
+ name="Air supply pipe manifold"
+ desc = "A manifold composed of supply pipes"
+ icon_state = "map-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold/visible/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/manifold/visible/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/manifold/visible/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/manifold/visible/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/manifold/visible/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold/visible/blue
+ color = PIPE_COLOR_BLUE
+
+
+/obj/machinery/atmospherics/pipe/manifold/hidden
+ icon_state = "map"
+ level = 1
+ alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/scrubbers
+ name="Scrubbers pipe manifold"
+ desc = "A manifold composed of scrubbers pipes"
+ icon_state = "map-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/supply
+ name="Air supply pipe manifold"
+ desc = "A manifold composed of supply pipes"
+ icon_state = "map-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold/hidden/blue
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold4w
+ icon = 'icons/atmos/manifold.dmi'
+ icon_state = ""
+ name = "4-way pipe manifold"
+ desc = "A manifold composed of regular pipes"
+
+ volume = ATMOS_DEFAULT_VOLUME_PIPE * 2
+
+ dir = SOUTH
+ initialize_directions = NORTH|SOUTH|EAST|WEST
+
+ var/obj/machinery/atmospherics/node3
+ var/obj/machinery/atmospherics/node4
+
+ level = 1
+ layer = 2.4 //under wires with their 2.44
+
+/obj/machinery/atmospherics/pipe/manifold4w/Initialize()
+ . = ..()
+ alpha = 255
+ icon = null
+
+/obj/machinery/atmospherics/pipe/manifold4w/pipeline_expansion()
+ return list(node1, node2, node3, node4)
+
+/obj/machinery/atmospherics/pipe/manifold4w/machinery_process()
+ if(!parent)
+ ..()
+ else
+ . = PROCESS_KILL
+
+/obj/machinery/atmospherics/pipe/manifold4w/Destroy()
+ if(node1)
+ node1.disconnect(src)
+ if(node2)
+ node2.disconnect(src)
+ if(node3)
+ node3.disconnect(src)
+ if(node4)
+ node4.disconnect(src)
+
+ node1 = null
+ node2 = null
+ node3 = null
+ node4 = null
+
+ return ..()
+
+/obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node1)
+ if(istype(node1, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node1 = null
+
+ if(reference == node2)
+ if(istype(node2, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node2 = null
+
+ if(reference == node3)
+ if(istype(node3, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node3 = null
+
+ if(reference == node4)
+ if(istype(node4, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node4 = null
+
+ update_icon()
+
+ ..()
+
+/obj/machinery/atmospherics/pipe/manifold4w/change_color(var/new_color)
+ ..()
+ //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
+ if(node1)
+ node1.update_underlays()
+ if(node2)
+ node2.update_underlays()
+ if(node3)
+ node3.update_underlays()
+ if(node4)
+ node4.update_underlays()
+
+/obj/machinery/atmospherics/pipe/manifold4w/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ if(!node1 && !node2 && !node3 && !node4)
+ var/turf/T = get_turf(src)
+ new /obj/item/pipe(loc, make_from=src)
+ for (var/obj/machinery/meter/meter in T)
+ if (meter.target == src)
+ new /obj/item/pipe_meter(T)
+ qdel(meter)
+ qdel(src)
+ else
+ cut_overlays()
+ add_overlay(icon_manager.get_atmos_icon("manifold", , pipe_color, "4way" + icon_connect_type))
+ add_overlay(icon_manager.get_atmos_icon("manifold", , , "clamps_4way" + icon_connect_type))
+
+ underlays.Cut()
+
+ /*
+ var/list/directions = list(NORTH, SOUTH, EAST, WEST)
+
+
+ directions -= add_underlay(node1)
+ directions -= add_underlay(node2)
+ directions -= add_underlay(node3)
+ directions -= add_underlay(node4)
+
+ for(var/D in directions)
+ add_underlay(,D)
+ */
+
+ var/turf/T = get_turf(src)
+ var/list/directions = list(NORTH, SOUTH, EAST, WEST)
+ var/node1_direction = get_dir(src, node1)
+ var/node2_direction = get_dir(src, node2)
+ var/node3_direction = get_dir(src, node3)
+ var/node4_direction = get_dir(src, node4)
+
+ directions -= dir
+
+ directions -= add_underlay(T,node1,node1_direction,icon_connect_type)
+ directions -= add_underlay(T,node2,node2_direction,icon_connect_type)
+ directions -= add_underlay(T,node3,node3_direction,icon_connect_type)
+ directions -= add_underlay(T,node4,node4_direction,icon_connect_type)
+
+ for(var/D in directions)
+ add_underlay(T,,D,icon_connect_type)
+
+
+/obj/machinery/atmospherics/pipe/manifold4w/update_underlays()
+ ..()
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/manifold4w/hide(var/i)
+ if(istype(loc, /turf/simulated))
+ invisibility = i ? 101 : 0
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/manifold4w/atmos_init()
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,1))
+ if(target.initialize_directions & 2)
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,2))
+ if(target.initialize_directions & 1)
+ if (check_connect_types(target,src))
+ node2 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,4))
+ if(target.initialize_directions & 8)
+ if (check_connect_types(target,src))
+ node3 = target
+ break
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,8))
+ if(target.initialize_directions & 4)
+ if (check_connect_types(target,src))
+ node4 = target
+ break
+
+ if(!node1 && !node2 && !node3 && !node4)
+ qdel(src)
+ return
+
+ var/turf/T = get_turf(src)
+ if(level == 1 && !T.is_plating()) hide(1)
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible
+ icon_state = "map_4way"
+ level = 2
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/scrubbers
+ name="4-way scrubbers pipe manifold"
+ desc = "A manifold composed of scrubbers pipes"
+ icon_state = "map_4way-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/supply
+ name="4-way air supply pipe manifold"
+ desc = "A manifold composed of supply pipes"
+ icon_state = "map_4way-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold4w/visible/blue
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden
+ icon_state = "map_4way"
+ level = 1
+ alpha = 128 //set for the benefit of mapping - this is reset to opaque when the pipe is spawned in game
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/scrubbers
+ name="4-way scrubbers pipe manifold"
+ desc = "A manifold composed of scrubbers pipes"
+ icon_state = "map_4way-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/supply
+ name="4-way air supply pipe manifold"
+ desc = "A manifold composed of supply pipes"
+ icon_state = "map_4way-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/yellow
+ color = PIPE_COLOR_YELLOW
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/cyan
+ color = PIPE_COLOR_CYAN
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/green
+ color = PIPE_COLOR_GREEN
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/black
+ color = PIPE_COLOR_BLACK
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/red
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/manifold4w/hidden/blue
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/cap
+ name = "pipe endcap"
+ desc = "An endcap for pipes"
+ icon = 'icons/atmos/pipes.dmi'
+ icon_state = ""
+ level = 2
+ layer = 2.4 //under wires with their 2.44
+
+ volume = 35
+
+ dir = SOUTH
+ initialize_directions = SOUTH
+
+ var/obj/machinery/atmospherics/node
+
+/obj/machinery/atmospherics/pipe/cap/Initialize()
+ initialize_directions = dir
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/cap/hide(var/i)
+ if(istype(loc, /turf/simulated))
+ invisibility = i ? 101 : 0
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/cap/pipeline_expansion()
+ return list(node)
+
+/obj/machinery/atmospherics/pipe/cap/machinery_process()
+ if(!parent)
+ ..()
+ else
+ . = PROCESS_KILL
+/obj/machinery/atmospherics/pipe/cap/Destroy()
+ if(node)
+ node.disconnect(src)
+
+ node = null
+
+ return ..()
+
+/obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node)
+ if(istype(node, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node = null
+
+ update_icon()
+
+ ..()
+
+/obj/machinery/atmospherics/pipe/cap/change_color(var/new_color)
+ ..()
+ //for updating connected atmos device pipes (i.e. vents, manifolds, etc)
+ if(node)
+ node.update_underlays()
+
+/obj/machinery/atmospherics/pipe/cap/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ cut_overlays()
+ add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "cap"))
+
+/obj/machinery/atmospherics/pipe/cap/atmos_init()
+ for(var/obj/machinery/atmospherics/target in get_step(src, dir))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node = target
+ break
+
+ var/turf/T = src.loc // hide if turf is not intact
+ if(level == 1 && !T.is_plating()) hide(1)
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/cap/visible
+ level = 2
+ icon_state = "cap"
+
+/obj/machinery/atmospherics/pipe/cap/visible/scrubbers
+ name = "scrubbers pipe endcap"
+ desc = "An endcap for scrubbers pipes"
+ icon_state = "cap-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/cap/visible/supply
+ name = "supply pipe endcap"
+ desc = "An endcap for supply pipes"
+ icon_state = "cap-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+/obj/machinery/atmospherics/pipe/cap/hidden
+ level = 1
+ icon_state = "cap"
+ alpha = 128
+
+/obj/machinery/atmospherics/pipe/cap/hidden/scrubbers
+ name = "scrubbers pipe endcap"
+ desc = "An endcap for scrubbers pipes"
+ icon_state = "cap-f-scrubbers"
+ connect_types = CONNECT_TYPE_SCRUBBER
+ layer = 2.38
+ icon_connect_type = "-scrubbers"
+ color = PIPE_COLOR_RED
+
+/obj/machinery/atmospherics/pipe/cap/hidden/supply
+ name = "supply pipe endcap"
+ desc = "An endcap for supply pipes"
+ icon_state = "cap-f-supply"
+ connect_types = CONNECT_TYPE_SUPPLY
+ layer = 2.39
+ icon_connect_type = "-supply"
+ color = PIPE_COLOR_BLUE
+
+
+/obj/machinery/atmospherics/pipe/tank
+ icon = 'icons/atmos/tank.dmi'
+ icon_state = "air_map"
+
+ name = "Pressure Tank"
+ desc = "A large vessel containing pressurized gas."
+
+ volume = 10000 //in liters, 1 meters by 1 meters by 2 meters ~tweaked it a little to simulate a pressure tank without needing to recode them yet
+ var/start_pressure = 25*ONE_ATMOSPHERE
+
+ level = 1
+ dir = SOUTH
+ initialize_directions = SOUTH
+ density = 1
+
+/obj/machinery/atmospherics/pipe/tank/Initialize()
+ icon_state = "air"
+ initialize_directions = dir
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/tank/machinery_process()
+ if(!parent)
+ ..()
+ else
+ . = PROCESS_KILL
+
+/obj/machinery/atmospherics/pipe/tank/Destroy()
+ if(node1)
+ node1.disconnect(src)
+
+ node1 = null
+
+ return ..()
+
+/obj/machinery/atmospherics/pipe/tank/pipeline_expansion()
+ return list(node1)
+
+/obj/machinery/atmospherics/pipe/tank/update_underlays()
+ if(..())
+ underlays.Cut()
+ var/turf/T = get_turf(src)
+ if(!istype(T))
+ return
+ add_underlay(T, node1, dir)
+
+/obj/machinery/atmospherics/pipe/tank/hide()
+ update_underlays()
+
+/obj/machinery/atmospherics/pipe/tank/atmos_init()
+ var/connect_direction = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+
+ update_underlays()
+
+/obj/machinery/atmospherics/pipe/tank/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node1)
+ if(istype(node1, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node1 = null
+
+ update_underlays()
+
+ return null
+
+/obj/machinery/atmospherics/pipe/tank/attackby(var/obj/item/W as obj, var/mob/user as mob)
+ if(istype(W, /obj/item/device/pipe_painter))
+ return
+
+ if(istype(W, /obj/item/device/analyzer) && in_range(user, src))
+ var/obj/item/device/analyzer/A = W
+ A.analyze_gases(src, user)
+
+/obj/machinery/atmospherics/pipe/tank/air
+ name = "Pressure Tank (Air)"
+ icon_state = "air_map"
+
+/obj/machinery/atmospherics/pipe/tank/air/Initialize()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T20C
+
+ air_temporary.adjust_multi("oxygen", (start_pressure*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature), \
+ "nitrogen",(start_pressure*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+
+ . = ..()
+ icon_state = "air"
+
+/obj/machinery/atmospherics/pipe/tank/oxygen
+ name = "Pressure Tank (Oxygen)"
+ icon_state = "o2_map"
+
+/obj/machinery/atmospherics/pipe/tank/oxygen/Initialize()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T20C
+
+ air_temporary.adjust_gas("oxygen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+ . = ..()
+ icon_state = "o2"
+
+/obj/machinery/atmospherics/pipe/tank/nitrogen
+ name = "Pressure Tank (Nitrogen)"
+ icon_state = "n2_map"
+
+/obj/machinery/atmospherics/pipe/tank/nitrogen/Initialize()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T20C
+
+ air_temporary.adjust_gas("nitrogen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+ . = ..()
+ icon_state = "n2"
+
+/obj/machinery/atmospherics/pipe/tank/carbon_dioxide
+ name = "Pressure Tank (Carbon Dioxide)"
+ icon_state = "co2_map"
+
+/obj/machinery/atmospherics/pipe/tank/carbon_dioxide/Initialize()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T20C
+
+ air_temporary.adjust_gas("carbon_dioxide", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+ . = ..()
+ icon_state = "co2"
+
+/obj/machinery/atmospherics/pipe/tank/phoron
+ name = "Pressure Tank (Phoron)"
+ icon_state = "phoron_map"
+
+/obj/machinery/atmospherics/pipe/tank/phoron/Initialize()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T20C
+
+ air_temporary.adjust_gas("phoron", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+ . = ..()
+ icon_state = "phoron"
+
+/obj/machinery/atmospherics/pipe/tank/nitrous_oxide
+ name = "Pressure Tank (Nitrous Oxide)"
+ icon_state = "n2o_map"
+
+/obj/machinery/atmospherics/pipe/tank/nitrous_oxide/Initialize()
+ air_temporary = new
+ air_temporary.volume = volume
+ air_temporary.temperature = T0C
+
+ air_temporary.adjust_gas("sleeping_agent", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature))
+
+ . = ..()
+ icon_state = "n2o"
+
+/obj/machinery/atmospherics/pipe/vent
+ icon = 'icons/obj/atmospherics/pipe_vent.dmi'
+ icon_state = "intact"
+
+ name = "Vent"
+ desc = "A large air vent"
+
+ level = 1
+
+ volume = 250
+
+ dir = SOUTH
+ initialize_directions = SOUTH
+
+ var/build_killswitch = 1
+
+/obj/machinery/atmospherics/pipe/vent/Initialize()
+ initialize_directions = dir
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/vent/high_volume
+ name = "Larger vent"
+ volume = 1000
+
+/obj/machinery/atmospherics/pipe/vent/machinery_process()
+ if(!parent)
+ if(build_killswitch <= 0)
+ . = PROCESS_KILL
+ else
+ build_killswitch--
+ ..()
+ return
+ else
+ parent.mingle_with_turf(loc, volume)
+
+/obj/machinery/atmospherics/pipe/vent/Destroy()
+ if(node1)
+ node1.disconnect(src)
+
+ node1 = null
+
+ return ..()
+
+/obj/machinery/atmospherics/pipe/vent/pipeline_expansion()
+ return list(node1)
+
+/obj/machinery/atmospherics/pipe/vent/update_icon()
+ if(node1)
+ icon_state = "intact"
+
+ set_dir(get_dir(src, node1))
+
+ else
+ icon_state = "exposed"
+
+/obj/machinery/atmospherics/pipe/vent/atmos_init()
+ var/connect_direction = dir
+
+ for(var/obj/machinery/atmospherics/target in get_step(src,connect_direction))
+ if(target.initialize_directions & get_dir(target,src))
+ if (check_connect_types(target,src))
+ node1 = target
+ break
+
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/vent/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node1)
+ if(istype(node1, /obj/machinery/atmospherics/pipe))
+ QDEL_NULL(parent)
+ node1 = null
+
+ update_icon()
+
+ return null
+
+/obj/machinery/atmospherics/pipe/vent/hide(var/i) //to make the little pipe section invisible, the icon changes.
+ if(node1)
+ icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact"
+ set_dir(get_dir(src, node1))
+ else
+ icon_state = "exposed"
+
+
+/obj/machinery/atmospherics/pipe/simple/visible/universal
+ name="Universal pipe adapter"
+ desc = "An adapter for regular, supply and scrubbers pipes"
+ connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
+ icon_state = "map_universal"
+ gfi_layer_rotation = GFI_ROTATION_OVERDIR
+
+/obj/machinery/atmospherics/pipe/simple/visible/universal/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ cut_overlays()
+ add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "universal"))
+ underlays.Cut()
+
+ if (node1)
+ universal_underlays(node1)
+ if(node2)
+ universal_underlays(node2)
+ else
+ var/node1_dir = get_dir(node1,src)
+ universal_underlays(,node1_dir)
+ else if (node2)
+ universal_underlays(node2)
+ else
+ universal_underlays(,dir)
+ universal_underlays(,turn(dir, -180))
+
+/obj/machinery/atmospherics/pipe/simple/visible/universal/update_underlays()
+ ..()
+ queue_icon_update()
+
+
+
+/obj/machinery/atmospherics/pipe/simple/hidden/universal
+ name="Universal pipe adapter"
+ desc = "An adapter for regular, supply and scrubbers pipes"
+ connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER
+ icon_state = "map_universal"
+ gfi_layer_rotation = GFI_ROTATION_OVERDIR
+
+/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_icon(var/safety = 0)
+ if(!check_icon_cache())
+ return
+
+ alpha = 255
+
+ cut_overlays()
+ add_overlay(icon_manager.get_atmos_icon("pipe", , pipe_color, "universal"))
+
+ underlays.Cut()
+
+ if (node1)
+ universal_underlays(node1)
+ if(node2)
+ universal_underlays(node2)
+ else
+ var/node2_dir = turn(get_dir(src,node1),-180)
+ universal_underlays(,node2_dir)
+ else if (node2)
+ universal_underlays(node2)
+ var/node1_dir = turn(get_dir(src,node2),-180)
+ universal_underlays(,node1_dir)
+ else
+ universal_underlays(,dir)
+ universal_underlays(,turn(dir, -180))
+
+/obj/machinery/atmospherics/pipe/simple/hidden/universal/update_underlays()
+ ..()
+ queue_icon_update()
+
+/obj/machinery/atmospherics/proc/universal_underlays(var/obj/machinery/atmospherics/node, var/direction)
+ var/turf/T = loc
+ if(node)
+ var/node_dir = get_dir(src,node)
+ if(node.icon_connect_type == "-supply")
+ add_underlay_adapter(T, , node_dir, "")
+ add_underlay_adapter(T, node, node_dir, "-supply")
+ add_underlay_adapter(T, , node_dir, "-scrubbers")
+ else if (node.icon_connect_type == "-scrubbers")
+ add_underlay_adapter(T, , node_dir, "")
+ add_underlay_adapter(T, , node_dir, "-supply")
+ add_underlay_adapter(T, node, node_dir, "-scrubbers")
+ else
+ add_underlay_adapter(T, node, node_dir, "")
+ add_underlay_adapter(T, , node_dir, "-supply")
+ add_underlay_adapter(T, , node_dir, "-scrubbers")
+ else
+ add_underlay_adapter(T, , direction, "-supply")
+ add_underlay_adapter(T, , direction, "-scrubbers")
+ add_underlay_adapter(T, , direction, "")
+
+/obj/machinery/atmospherics/proc/add_underlay_adapter(var/turf/T, var/obj/machinery/atmospherics/node, var/direction, var/icon_connect_type) //modified from add_underlay, does not make exposed underlays
+ if(node)
+ if(!T.is_plating() && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
+ underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "down" + icon_connect_type)
+ else
+ underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "intact" + icon_connect_type)
+ else
+ underlays += icon_manager.get_atmos_icon("underlay", direction, color_cache_name(node), "retracted" + icon_connect_type)
diff --git a/code/__defines/_compile_options.dm b/code/__defines/_compile_options.dm
index c54c5376a22..74ed9385558 100644
--- a/code/__defines/_compile_options.dm
+++ b/code/__defines/_compile_options.dm
@@ -1,5 +1,5 @@
-#define BACKGROUND_ENABLED 0 // The default value for all uses of set background. Set background can cause gradual lag and is recommended you only turn this on if necessary.
- // 1 will enable set background. 0 will disable set background.
-
-// If defined, the sunlight system is enabled. Caution: this uses a LOT of memory.
-//#define ENABLE_SUNLIGHT
+#define BACKGROUND_ENABLED 0 // The default value for all uses of set background. Set background can cause gradual lag and is recommended you only turn this on if necessary.
+ // 1 will enable set background. 0 will disable set background.
+
+// If defined, the sunlight system is enabled. Caution: this uses a LOT of memory.
+//#define ENABLE_SUNLIGHT
diff --git a/code/__defines/_macros.dm b/code/__defines/_macros.dm
index 05dd7e8685e..f5dad3c6bac 100644
--- a/code/__defines/_macros.dm
+++ b/code/__defines/_macros.dm
@@ -22,6 +22,8 @@
#define ishuman(A) istype(A, /mob/living/carbon/human)
+#define ismech(A) istype(A, /mob/living/heavy_vehicle)
+
#define isliving(A) istype(A, /mob/living)
#define israt(A) istype(A, /mob/living/simple_animal/rat)
diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm
index 6221e24bdd0..d1c05df0574 100644
--- a/code/__defines/damage_organs.dm
+++ b/code/__defines/damage_organs.dm
@@ -5,11 +5,12 @@
#define TOX "tox"
#define OXY "oxy"
#define CLONE "clone"
-#define HALLOSS "halloss"
+#define PAIN "pain"
#define CUT "cut"
#define BRUISE "bruise"
#define PIERCE "pierce"
+#define LASER "laser"
#define DAM_LASER 1
#define DAM_BULLET 2
@@ -18,7 +19,6 @@
#define WEAKEN "weaken"
#define PARALYZE "paralize"
#define IRRADIATE "irradiate"
-#define AGONY "agony" // Added in PAIN!
#define SLUR "slur"
#define STUTTER "stutter"
#define EYE_BLUR "eye_blur"
@@ -63,3 +63,10 @@
#define BLOOD_VOLUME_OKAY 70
#define BLOOD_VOLUME_BAD 60
#define BLOOD_VOLUME_SURVIVE 30
+
+// These control the amount of blood lost from burns. The loss is calculated so
+// that dealing just enough burn damage to kill the player will cause the given
+// proportion of their max blood volume to be lost
+// (e.g. 0.6 == 60% lost if 200 burn damage is taken).
+#define FLUIDLOSS_WIDE_BURN 0.6 //for burns from heat applied over a wider area, like from fire
+#define FLUIDLOSS_CONC_BURN 0.4 //for concentrated burns, like from lasers
diff --git a/code/__defines/dna.dm b/code/__defines/dna.dm
index 1655659da68..1be4cd0e1fa 100644
--- a/code/__defines/dna.dm
+++ b/code/__defines/dna.dm
@@ -11,7 +11,7 @@
#define FAT 6
#define HUSK 7
#define NOCLONE 8
-#define LASER 9 // Harm intent - click anywhere to shoot lasers from eyes.
+#define LASER_EYES 9 // Harm intent - click anywhere to shoot lasers from eyes.
#define HEAL 10 // Healing people with hands.
#define SKELETON 29
diff --git a/code/__defines/lighting.dm b/code/__defines/lighting.dm
index d4097da3e59..8ee5fbc5fae 100644
--- a/code/__defines/lighting.dm
+++ b/code/__defines/lighting.dm
@@ -1,141 +1,141 @@
-#define LIGHTING_INTERVAL 1 // Frequency, in 1/10ths of a second, of the lighting process.
-
-#define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone
-#define LIGHTING_Z_FACTOR 10 // Z diff is multiplied by this and LIGHTING_HEIGHT to get the final height of a light source. Affects how much darker A Z light gets with each level transitioned.
-#define LIGHTING_ROUND_VALUE 1 / 200 //Value used to round lumcounts, values smaller than 1/255 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY.
-
-#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects
-#define LIGHTING_BASE_ICON_STATE "matrix" // icon_state used for normal color-matrix based lighting overlays.
-#define LIGHTING_STATION_ICON_STATE "tubedefault" // icon_state used for lighting overlays that are just displaying standard station lighting.
-#define LIGHTING_DARKNESS_ICON_STATE "black" // icon_state used for lighting overlays with no luminosity.
-#define LIGHTING_TRANSPARENT_ICON_STATE "blank"
-
-#define LIGHTING_SOFT_THRESHOLD 0.001 // If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting overlays.
-#define LIGHTING_BLOCKED_FACTOR 0.5 // How much the range of a directional light will be reduced while facing a wall.
-
-// If defined, instant updates will be used whenever server load permits. Otherwise queued updates are always used.
-#define USE_INTELLIGENT_LIGHTING_UPDATES
-
-// If defined, lighting corners will 'bleed' luminosity to corners above them to simulate cross-Z lighting upwards. Downwards Z-lighting will continue to work with this disabled.
-#define USE_CORNER_ZBLEED
-
-#define TURF_IS_DYNAMICALLY_LIT(T) (isturf(T) && T:dynamic_lighting && T:loc:dynamic_lighting)
-// mostly identical to above, but doesn't make sure T is valid first. Should only be used by lighting code.
-#define TURF_IS_DYNAMICALLY_LIT_UNSAFE(T) (T:dynamic_lighting && T:loc:dynamic_lighting)
-
-// If I were you I'd leave this alone.
-#define LIGHTING_BASE_MATRIX \
- list \
- ( \
- 1, 1, 1, 0, \
- 1, 1, 1, 0, \
- 1, 1, 1, 0, \
- 1, 1, 1, 0, \
- 0, 0, 0, 1 \
- ) \
-
-// Helpers so we can (more easily) control the colour matrices.
-#define CL_MATRIX_RR 1
-#define CL_MATRIX_RG 2
-#define CL_MATRIX_RB 3
-#define CL_MATRIX_RA 4
-#define CL_MATRIX_GR 5
-#define CL_MATRIX_GG 6
-#define CL_MATRIX_GB 7
-#define CL_MATRIX_GA 8
-#define CL_MATRIX_BR 9
-#define CL_MATRIX_BG 10
-#define CL_MATRIX_BB 11
-#define CL_MATRIX_BA 12
-#define CL_MATRIX_AR 13
-#define CL_MATRIX_AG 14
-#define CL_MATRIX_AB 15
-#define CL_MATRIX_AA 16
-#define CL_MATRIX_CR 17
-#define CL_MATRIX_CG 18
-#define CL_MATRIX_CB 19
-#define CL_MATRIX_CA 20
-
-// Higher numbers override lower.
-#define LIGHTING_NO_UPDATE 0
-#define LIGHTING_VIS_UPDATE 1
-#define LIGHTING_CHECK_UPDATE 2
-#define LIGHTING_FORCE_UPDATE 3
-
-// This color of overlay is very common - most of the station is this color when lit fully.
-// Tube lights are a bluish-white, so we can't just assume 1-1-1 is full-illumination.
-#define LIGHTING_DEFAULT_TUBE_R 0.96
-#define LIGHTING_DEFAULT_TUBE_G 1
-#define LIGHTING_DEFAULT_TUBE_B 1
-
-//Some defines to generalise colours used in lighting.
-//Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated
-#define LIGHT_COLOR_RED "#FA8282" //Warm but extremely diluted red. rgb(250, 130, 130)
-#define LIGHT_COLOR_GREEN "#64C864" //Bright but quickly dissipating neon green. rgb(100, 200, 100)
-#define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250)
-
-#define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225)
-#define LIGHT_COLOR_PINK "#E17DE1" //Diluted, mid-warmth pink. rgb(225, 125, 225)
-#define LIGHT_COLOR_YELLOW "#E1E17D" //Dimmed yellow, leaning kaki. rgb(225, 225, 125)
-#define LIGHT_COLOR_BROWN "#966432" //Clear brown, mostly dim. rgb(150, 100, 50)
-#define LIGHT_COLOR_ORANGE "#FA9632" //Mostly pure orange. rgb(250, 150, 50)
-#define LIGHT_COLOR_PURPLE "#A97FAA" //Soft purple. rgb(169, 127, 170)
-#define LIGHT_COLOR_VIOLET "#B43CB8" //Deep purple. rgb(180, 60, 184)
-#define LIGHT_COLOR_SCARLET "#E85656" //Light red. rgb(232, 86, 86)
-
-//These ones aren't a direct colour like the ones above, because nothing would fit
-#define LIGHT_COLOR_FIRE "#FAA019" //Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25)
-#define LIGHT_COLOR_LAVA "#C48A18" //Very warm yellow, leaning slightly towards orange. rgb(196, 138, 24)
-#define LIGHT_COLOR_FLARE "#FA644B" //Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75)
-#define LIGHT_COLOR_SLIME_LAMP "#AFC84B" //Weird color, between yellow and green, very slimy. rgb(175, 200, 75)
-#define LIGHT_COLOR_TUNGSTEN "#FAE1AF" //Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175)
-#define LIGHT_COLOR_HALOGEN "#F0FAFA" //Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250)
-#define LIGHT_COLOR_EMERGENCY "#FF3232" //Red color used by emergency lighting. rgb(255, 50, 50)
-
-//Defines for lighting status, see power/lighting.dm
-#define LIGHT_OK 0
-#define LIGHT_EMPTY 1
-#define LIGHT_BROKEN 2
-#define LIGHT_BURNED 3
-
-#define LIGHT_EMERGENCY_POWER_USE 0.2 //How much power emergency lights will consume per tick
-
-// Some angle presets for directional lighting.
-#define LIGHT_OMNI null
-#define LIGHT_SEMI 180
-#define LIGHT_WIDE 90
-#define LIGHT_NARROW 45
-
-// Night lighting controller times
-// The time (in hours based on worldtime2hours()) that various actions trigger
-#define MORNING_LIGHT_RESET 7 // 7am or 07:00 - lighting restores to normal in morning
-#define NIGHT_LIGHT_ACTIVE 18 // 6pm or 18:00 - night lighting mode activates
-
-// Some brightness/range defines for objects.
-#define L_WALLMOUNT_POWER 0.4
-#define L_WALLMOUNT_RANGE 2
-#define L_WALLMOUNT_HI_POWER 1 // For red/delta alert on fire alarms.
-#define L_WALLMOUNT_HI_RANGE 4
-// This controls by how much console sprites are dimmed before being overlayed.
-#define HOLOSCREEN_ADDITION_FACTOR 1
-#define HOLOSCREEN_MULTIPLICATION_FACTOR 0.5
-#define HOLOSCREEN_ADDITION_OPACITY 0.8
-#define HOLOSCREEN_MULTIPLICATION_OPACITY 1
-
-// Just so we can avoid unneeded proc calls when profiling is disabled.
-#define L_PROF(O,T) if (lighting_profiling) {lprof_write(O,T);}
-
-// -- Ambient Occlusion --
-
-// Not handled by the lighting engine, but related. Controls the alpha of the ambient occlusion effect on opaque atoms and openturfs.
-#define WALL_AO_ALPHA 80
-
-#define AO_UPDATE_NONE 0
-#define AO_UPDATE_OVERLAY 1
-#define AO_UPDATE_REBUILD 2
-
-// If ao_neighbors equals this, no AO shadows are present.
-#define AO_ALL_NEIGHBORS 1910
-
-// If defined, integrate with the lighting engine and use its opacity value. Otherwise a simple turf opacity check is used. This may cause visual artifacts with opaque non-square movables.
-//#define AO_USE_LIGHTING_OPACITY
+#define LIGHTING_INTERVAL 1 // Frequency, in 1/10ths of a second, of the lighting process.
+
+#define LIGHTING_HEIGHT 1 // height off the ground of light sources on the pseudo-z-axis, you should probably leave this alone
+#define LIGHTING_Z_FACTOR 10 // Z diff is multiplied by this and LIGHTING_HEIGHT to get the final height of a light source. Affects how much darker A Z light gets with each level transitioned.
+#define LIGHTING_ROUND_VALUE 1 / 200 //Value used to round lumcounts, values smaller than 1/255 don't matter (if they do, thanks sinking points), greater values will make lighting less precise, but in turn increase performance, VERY SLIGHTLY.
+
+#define LIGHTING_ICON 'icons/effects/lighting_overlay.dmi' // icon used for lighting shading effects
+#define LIGHTING_BASE_ICON_STATE "matrix" // icon_state used for normal color-matrix based lighting overlays.
+#define LIGHTING_STATION_ICON_STATE "tubedefault" // icon_state used for lighting overlays that are just displaying standard station lighting.
+#define LIGHTING_DARKNESS_ICON_STATE "black" // icon_state used for lighting overlays with no luminosity.
+#define LIGHTING_TRANSPARENT_ICON_STATE "blank"
+
+#define LIGHTING_SOFT_THRESHOLD 0.001 // If the max of the lighting lumcounts of each spectrum drops below this, disable luminosity on the lighting overlays.
+#define LIGHTING_BLOCKED_FACTOR 0.5 // How much the range of a directional light will be reduced while facing a wall.
+
+// If defined, instant updates will be used whenever server load permits. Otherwise queued updates are always used.
+#define USE_INTELLIGENT_LIGHTING_UPDATES
+
+// If defined, lighting corners will 'bleed' luminosity to corners above them to simulate cross-Z lighting upwards. Downwards Z-lighting will continue to work with this disabled.
+#define USE_CORNER_ZBLEED
+
+#define TURF_IS_DYNAMICALLY_LIT(T) (isturf(T) && T:dynamic_lighting && T:loc:dynamic_lighting)
+// mostly identical to above, but doesn't make sure T is valid first. Should only be used by lighting code.
+#define TURF_IS_DYNAMICALLY_LIT_UNSAFE(T) (T:dynamic_lighting && T:loc:dynamic_lighting)
+
+// If I were you I'd leave this alone.
+#define LIGHTING_BASE_MATRIX \
+ list \
+ ( \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 1, 1, 1, 0, \
+ 0, 0, 0, 1 \
+ ) \
+
+// Helpers so we can (more easily) control the colour matrices.
+#define CL_MATRIX_RR 1
+#define CL_MATRIX_RG 2
+#define CL_MATRIX_RB 3
+#define CL_MATRIX_RA 4
+#define CL_MATRIX_GR 5
+#define CL_MATRIX_GG 6
+#define CL_MATRIX_GB 7
+#define CL_MATRIX_GA 8
+#define CL_MATRIX_BR 9
+#define CL_MATRIX_BG 10
+#define CL_MATRIX_BB 11
+#define CL_MATRIX_BA 12
+#define CL_MATRIX_AR 13
+#define CL_MATRIX_AG 14
+#define CL_MATRIX_AB 15
+#define CL_MATRIX_AA 16
+#define CL_MATRIX_CR 17
+#define CL_MATRIX_CG 18
+#define CL_MATRIX_CB 19
+#define CL_MATRIX_CA 20
+
+// Higher numbers override lower.
+#define LIGHTING_NO_UPDATE 0
+#define LIGHTING_VIS_UPDATE 1
+#define LIGHTING_CHECK_UPDATE 2
+#define LIGHTING_FORCE_UPDATE 3
+
+// This color of overlay is very common - most of the station is this color when lit fully.
+// Tube lights are a bluish-white, so we can't just assume 1-1-1 is full-illumination.
+#define LIGHTING_DEFAULT_TUBE_R 0.96
+#define LIGHTING_DEFAULT_TUBE_G 1
+#define LIGHTING_DEFAULT_TUBE_B 1
+
+//Some defines to generalise colours used in lighting.
+//Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated
+#define LIGHT_COLOR_RED "#FA8282" //Warm but extremely diluted red. rgb(250, 130, 130)
+#define LIGHT_COLOR_GREEN "#64C864" //Bright but quickly dissipating neon green. rgb(100, 200, 100)
+#define LIGHT_COLOR_BLUE "#6496FA" //Cold, diluted blue. rgb(100, 150, 250)
+
+#define LIGHT_COLOR_CYAN "#7DE1E1" //Diluted cyan. rgb(125, 225, 225)
+#define LIGHT_COLOR_PINK "#E17DE1" //Diluted, mid-warmth pink. rgb(225, 125, 225)
+#define LIGHT_COLOR_YELLOW "#E1E17D" //Dimmed yellow, leaning kaki. rgb(225, 225, 125)
+#define LIGHT_COLOR_BROWN "#966432" //Clear brown, mostly dim. rgb(150, 100, 50)
+#define LIGHT_COLOR_ORANGE "#FA9632" //Mostly pure orange. rgb(250, 150, 50)
+#define LIGHT_COLOR_PURPLE "#A97FAA" //Soft purple. rgb(169, 127, 170)
+#define LIGHT_COLOR_VIOLET "#B43CB8" //Deep purple. rgb(180, 60, 184)
+#define LIGHT_COLOR_SCARLET "#E85656" //Light red. rgb(232, 86, 86)
+
+//These ones aren't a direct colour like the ones above, because nothing would fit
+#define LIGHT_COLOR_FIRE "#FAA019" //Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25)
+#define LIGHT_COLOR_LAVA "#C48A18" //Very warm yellow, leaning slightly towards orange. rgb(196, 138, 24)
+#define LIGHT_COLOR_FLARE "#FA644B" //Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75)
+#define LIGHT_COLOR_SLIME_LAMP "#AFC84B" //Weird color, between yellow and green, very slimy. rgb(175, 200, 75)
+#define LIGHT_COLOR_TUNGSTEN "#FAE1AF" //Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175)
+#define LIGHT_COLOR_HALOGEN "#F0FAFA" //Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250)
+#define LIGHT_COLOR_EMERGENCY "#FF3232" //Red color used by emergency lighting. rgb(255, 50, 50)
+
+//Defines for lighting status, see power/lighting.dm
+#define LIGHT_OK 0
+#define LIGHT_EMPTY 1
+#define LIGHT_BROKEN 2
+#define LIGHT_BURNED 3
+
+#define LIGHT_EMERGENCY_POWER_USE 0.2 //How much power emergency lights will consume per tick
+
+// Some angle presets for directional lighting.
+#define LIGHT_OMNI null
+#define LIGHT_SEMI 180
+#define LIGHT_WIDE 90
+#define LIGHT_NARROW 45
+
+// Night lighting controller times
+// The time (in hours based on worldtime2hours()) that various actions trigger
+#define MORNING_LIGHT_RESET 7 // 7am or 07:00 - lighting restores to normal in morning
+#define NIGHT_LIGHT_ACTIVE 18 // 6pm or 18:00 - night lighting mode activates
+
+// Some brightness/range defines for objects.
+#define L_WALLMOUNT_POWER 0.4
+#define L_WALLMOUNT_RANGE 2
+#define L_WALLMOUNT_HI_POWER 1 // For red/delta alert on fire alarms.
+#define L_WALLMOUNT_HI_RANGE 4
+// This controls by how much console sprites are dimmed before being overlayed.
+#define HOLOSCREEN_ADDITION_FACTOR 1
+#define HOLOSCREEN_MULTIPLICATION_FACTOR 0.5
+#define HOLOSCREEN_ADDITION_OPACITY 0.8
+#define HOLOSCREEN_MULTIPLICATION_OPACITY 1
+
+// Just so we can avoid unneeded proc calls when profiling is disabled.
+#define L_PROF(O,T) if (lighting_profiling) {lprof_write(O,T);}
+
+// -- Ambient Occlusion --
+
+// Not handled by the lighting engine, but related. Controls the alpha of the ambient occlusion effect on opaque atoms and openturfs.
+#define WALL_AO_ALPHA 80
+
+#define AO_UPDATE_NONE 0
+#define AO_UPDATE_OVERLAY 1
+#define AO_UPDATE_REBUILD 2
+
+// If ao_neighbors equals this, no AO shadows are present.
+#define AO_ALL_NEIGHBORS 1910
+
+// If defined, integrate with the lighting engine and use its opacity value. Otherwise a simple turf opacity check is used. This may cause visual artifacts with opaque non-square movables.
+//#define AO_USE_LIGHTING_OPACITY
diff --git a/code/__defines/lists.dm b/code/__defines/lists.dm
index 3b928f5f50c..b2c5d72042c 100644
--- a/code/__defines/lists.dm
+++ b/code/__defines/lists.dm
@@ -12,7 +12,10 @@
#define LAZYDISTINCTADD(L, I) if(!L) { L = list(); } L |= I;
// Shims for some list procs in lists.dm.
-#define islist(L) istype(L,/list)
#define isemptylist(L) (!LAZYLEN(L))
#define safepick(L) LAZYPICK(L,null)
#define listgetindex(L,I) LAZYACCESS(L,I)
+
+#if DM_VERSION < 513
+#define islist(L) istype(L,/list)
+#endif
\ No newline at end of file
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index cb51216bedc..32ba09fbbcd 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -273,8 +273,16 @@
// Used for creating soft references to objects. A manner of storing an item reference
// as text so you don't necessarily fuck with an object's ability to be garbage collected.
+#if DM_VERSION < 513
+
#define SOFTREF(A) "\ref[A]"
+#else
+
+#define SOFTREF(A) ref(A)
+
+#endif
+
// This only works on 511 because it relies on 511's `var/something = foo = bar` syntax.
#define WEAKREF(D) (istype(D, /datum) && !D:gcDestroyed ? (D:weakref || (D:weakref = new(D))) : null)
diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 5a1804262d8..02fa9e20e0d 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -69,6 +69,7 @@
#define BP_IS_ROBOTIC(org) (org.status & ORGAN_ROBOT)
//Generic organs
+#define BP_MOUTH "mouth"
#define BP_EYES "eyes"
#define BP_HEART "heart"
#define BP_LUNGS "lungs"
diff --git a/code/__defines/qdel.dm b/code/__defines/qdel.dm
index b7cf56b65b0..ac86f23ef8a 100644
--- a/code/__defines/qdel.dm
+++ b/code/__defines/qdel.dm
@@ -20,3 +20,4 @@
#define QDEL_IN(item, time) addtimer(CALLBACK(GLOBAL_PROC, .proc/qdel, item), time, TIMER_STOPPABLE)
#define QDEL_NULL(item) qdel(item); item = null
+#define QDEL_NULL_LIST(x) if(x) { for(var/y in x) { qdel(y) }}; if(x) {x.Cut(); x = null } // Second x check to handle items that LAZYREMOVE on qdel.
diff --git a/code/_helpers/atmospherics.dm b/code/_helpers/atmospherics.dm
index 97f01868175..9c4302cdbd2 100644
--- a/code/_helpers/atmospherics.dm
+++ b/code/_helpers/atmospherics.dm
@@ -1,47 +1,47 @@
-/obj/proc/analyze_gases(var/obj/A, var/mob/user)
- if(src != A)
- user.visible_message("\The [user] has used \an [src] on \the [A]")
-
- A.add_fingerprint(user)
- var/list/result = A.atmosanalyze(user)
- if(result && result.len)
- to_chat(user, "Results of the analysis[src == A ? "" : " of \the [A]"]")
- for(var/line in result)
- to_chat(user, "[line]")
- return 1
-
- to_chat(user, "Your [src] flashes a red light as it fails to analyze \the [A].")
- return 0
-
-/proc/atmosanalyzer_scan(var/obj/target, var/datum/gas_mixture/mixture, var/mob/user)
- var/pressure = mixture.return_pressure()
- var/total_moles = mixture.total_moles
-
- var/list/results = list()
- if (total_moles>0)
- results += "Pressure: [round(pressure,0.1)] kPa"
- for(var/mix in mixture.gas)
- results += "[gas_data.name[mix]]: [round((mixture.gas[mix] / total_moles) * 100)]%"
- results += "Temperature: [round(mixture.temperature-T0C)]°C"
- else
- results += "\The [target] is empty!"
-
- return results
-
-/obj/proc/atmosanalyze(var/mob/user)
- return
-
-/obj/item/tank/atmosanalyze(var/mob/user)
- return atmosanalyzer_scan(src, src.air_contents, user)
-
-/obj/machinery/portable_atmospherics/atmosanalyze(var/mob/user)
- return atmosanalyzer_scan(src, src.air_contents, user)
-
-/obj/machinery/atmospherics/pipe/atmosanalyze(var/mob/user)
- return atmosanalyzer_scan(src, src.parent.air, user)
-
-/obj/machinery/power/rad_collector/atmosanalyze(var/mob/user)
- if(P) return atmosanalyzer_scan(src, src.P.air_contents, user)
-
-/obj/item/flamethrower/atmosanalyze(var/mob/user)
- if(ptank) return atmosanalyzer_scan(src, ptank.air_contents, user)
+/obj/proc/analyze_gases(var/obj/A, var/mob/user)
+ if(src != A)
+ user.visible_message("\The [user] has used \an [src] on \the [A]")
+
+ A.add_fingerprint(user)
+ var/list/result = A.atmosanalyze(user)
+ if(result && result.len)
+ to_chat(user, "Results of the analysis[src == A ? "" : " of \the [A]"]")
+ for(var/line in result)
+ to_chat(user, "[line]")
+ return 1
+
+ to_chat(user, "Your [src] flashes a red light as it fails to analyze \the [A].")
+ return 0
+
+/proc/atmosanalyzer_scan(var/obj/target, var/datum/gas_mixture/mixture, var/mob/user)
+ var/pressure = mixture.return_pressure()
+ var/total_moles = mixture.total_moles
+
+ var/list/results = list()
+ if (total_moles>0)
+ results += "Pressure: [round(pressure,0.1)] kPa"
+ for(var/mix in mixture.gas)
+ results += "[gas_data.name[mix]]: [round((mixture.gas[mix] / total_moles) * 100)]%"
+ results += "Temperature: [round(mixture.temperature-T0C)]°C"
+ else
+ results += "\The [target] is empty!"
+
+ return results
+
+/obj/proc/atmosanalyze(var/mob/user)
+ return
+
+/obj/item/tank/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.air_contents, user)
+
+/obj/machinery/portable_atmospherics/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.air_contents, user)
+
+/obj/machinery/atmospherics/pipe/atmosanalyze(var/mob/user)
+ return atmosanalyzer_scan(src, src.parent.air, user)
+
+/obj/machinery/power/rad_collector/atmosanalyze(var/mob/user)
+ if(P) return atmosanalyzer_scan(src, src.P.air_contents, user)
+
+/obj/item/flamethrower/atmosanalyze(var/mob/user)
+ if(ptank) return atmosanalyzer_scan(src, ptank.air_contents, user)
diff --git a/code/_helpers/files.dm b/code/_helpers/files.dm
index 388b2db4ed3..73c470da363 100644
--- a/code/_helpers/files.dm
+++ b/code/_helpers/files.dm
@@ -1,60 +1,60 @@
-//checks if a file exists and contains text
-//returns text as a string if these conditions are met
-/proc/return_file_text(filename)
- if(fexists(filename) == 0)
- error("File not found ([filename])")
- return
-
- var/text = file2text(filename)
- if(!text)
- error("File empty ([filename])")
- return
-
- return text
-
-//Sends resource files to client cache
-/client/proc/getFiles()
- for(var/file in args)
- to_chat(src, browse_rsc(file))
-
-/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm"))
- var/path = root
-
- for(var/i=0, iError: browse_files(): File not found/Invalid file([path]).")
- return
-
- return path
-
-#define FTPDELAY 200 //200 tick delay to discourage spam
-/* This proc is a failsafe to prevent spamming of file requests.
- It is just a timer that only permits a download every [FTPDELAY] ticks.
- This can be changed by modifying FTPDELAY's value above.
-
- PLEASE USE RESPONSIBLY, Some log files canr each sizes of 4MB! */
-/client/proc/file_spam_check()
- var/time_to_wait = fileaccess_timer - world.time
- if(time_to_wait > 0)
- to_chat(src, "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.")
- return 1
- fileaccess_timer = world.time + FTPDELAY
- return 0
-#undef FTPDELAY
+//checks if a file exists and contains text
+//returns text as a string if these conditions are met
+/proc/return_file_text(filename)
+ if(fexists(filename) == 0)
+ error("File not found ([filename])")
+ return
+
+ var/text = file2text(filename)
+ if(!text)
+ error("File empty ([filename])")
+ return
+
+ return text
+
+//Sends resource files to client cache
+/client/proc/getFiles()
+ for(var/file in args)
+ to_chat(src, browse_rsc(file))
+
+/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list(".txt",".log",".htm"))
+ var/path = root
+
+ for(var/i=0, iError: browse_files(): File not found/Invalid file([path]).")
+ return
+
+ return path
+
+#define FTPDELAY 200 //200 tick delay to discourage spam
+/* This proc is a failsafe to prevent spamming of file requests.
+ It is just a timer that only permits a download every [FTPDELAY] ticks.
+ This can be changed by modifying FTPDELAY's value above.
+
+ PLEASE USE RESPONSIBLY, Some log files canr each sizes of 4MB! */
+/client/proc/file_spam_check()
+ var/time_to_wait = fileaccess_timer - world.time
+ if(time_to_wait > 0)
+ to_chat(src, "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.")
+ return 1
+ fileaccess_timer = world.time + FTPDELAY
+ return 0
+#undef FTPDELAY
diff --git a/code/_helpers/functional.dm b/code/_helpers/functional.dm
index 231b8a4d261..114913f7c3a 100644
--- a/code/_helpers/functional.dm
+++ b/code/_helpers/functional.dm
@@ -1,24 +1,24 @@
-/proc/all_predicates_true(var/list/input, var/list/predicates)
- functional_sanity(input, predicates)
-
- for(var/i = 1 to predicates.len)
- if(!call(predicates[i])(arglist(input)))
- return FALSE
- return TRUE
-
-/proc/any_predicate_true(var/list/input, var/list/predicates)
- functional_sanity(input, predicates)
-
- if(!predicates.len)
- return TRUE
-
- for(var/i = 1 to predicates.len)
- if(call(predicates[i])(arglist(input)))
- return TRUE
- return FALSE
-
-/proc/functional_sanity(var/list/input, var/list/predicates)
- if(!istype(input))
- CRASH("Expected list input. Was [input ? "[input.type]" : "null"]")
- if(!istype(predicates))
- CRASH("Expected predicate list. Was [predicates ? "[predicates.type]" : "null"]")
+/proc/all_predicates_true(var/list/input, var/list/predicates)
+ functional_sanity(input, predicates)
+
+ for(var/i = 1 to predicates.len)
+ if(!call(predicates[i])(arglist(input)))
+ return FALSE
+ return TRUE
+
+/proc/any_predicate_true(var/list/input, var/list/predicates)
+ functional_sanity(input, predicates)
+
+ if(!predicates.len)
+ return TRUE
+
+ for(var/i = 1 to predicates.len)
+ if(call(predicates[i])(arglist(input)))
+ return TRUE
+ return FALSE
+
+/proc/functional_sanity(var/list/input, var/list/predicates)
+ if(!istype(input))
+ CRASH("Expected list input. Was [input ? "[input.type]" : "null"]")
+ if(!istype(predicates))
+ CRASH("Expected predicate list. Was [predicates ? "[predicates.type]" : "null"]")
diff --git a/code/_helpers/game.dm b/code/_helpers/game.dm
index 254b60ea552..f54f2f615da 100644
--- a/code/_helpers/game.dm
+++ b/code/_helpers/game.dm
@@ -1,547 +1,547 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
-
-/proc/dopage(src,target)
- var/href_list
- var/href
- href_list = params2list("src=\ref[src]&[target]=1")
- href = "src=\ref[src];[target]=1"
- src:temphtml = null
- src:Topic(href, href_list)
- return null
-
-/proc/is_on_same_plane_or_station(var/z1, var/z2)
- if(z1 == z2)
- return 1
- if(isStationLevel(z1) && isStationLevel(z2))
- return 1
- return 0
-
-/proc/max_default_z_level()
- var/max_z = 0
- for(var/z in current_map.station_levels)
- max_z = max(z, max_z)
- for(var/z in current_map.admin_levels)
- max_z = max(z, max_z)
- for(var/z in current_map.player_levels)
- max_z = max(z, max_z)
- return max_z
-
-/proc/get_area(O)
- var/turf/loc = get_turf(O)
- if(loc)
- .= loc.loc
-
-/proc/get_area_name(N) //get area by its name
- for(var/area/A in all_areas)
- if(A.name == N)
- return A
- return 0
-
-/proc/get_area_master(const/O)
- var/area/A = get_area(O)
- if (isarea(A))
- return A
-
-/proc/in_range(source, user)
- if(get_dist(source, user) <= 1)
- return 1
-
- return 0 //not in range and not telekinetic
-
-// Like view but bypasses luminosity check
-
-/proc/hear(var/range, var/atom/source)
-
- var/lum = source.luminosity
- source.luminosity = 6
-
- var/list/heard = view(range, source)
- source.luminosity = lum
-
- return heard
-
-/proc/circlerange(center=usr,radius=3)
-
- var/turf/centerturf = get_turf(center)
- var/list/turfs = new/list()
- var/rsq = radius * (radius+0.5)
-
- for(var/atom/T in range(radius, centerturf))
- var/dx = T.x - centerturf.x
- var/dy = T.y - centerturf.y
- if(dx*dx + dy*dy <= rsq)
- turfs += T
-
- //turfs += centerturf
- return turfs
-
-/proc/circleview(center=usr,radius=3)
-
- var/turf/centerturf = get_turf(center)
- var/list/atoms = new/list()
- var/rsq = radius * (radius+0.5)
-
- for(var/atom/A in view(radius, centerturf))
- var/dx = A.x - centerturf.x
- var/dy = A.y - centerturf.y
- if(dx*dx + dy*dy <= rsq)
- atoms += A
-
- //turfs += centerturf
- return atoms
-
-/proc/get_dist_euclidian(atom/Loc1 as turf|mob|obj,atom/Loc2 as turf|mob|obj)
- var/dx = Loc1.x - Loc2.x
- var/dy = Loc1.y - Loc2.y
-
- var/dist = sqrt(dx**2 + dy**2)
-
- return dist
-
-/proc/circlerangeturfs(center=usr,radius=3)
-
- var/turf/centerturf = get_turf(center)
- var/list/turfs = new/list()
- var/rsq = radius * (radius+0.5)
-
- for(var/turf/T in range(radius, centerturf))
- var/dx = T.x - centerturf.x
- var/dy = T.y - centerturf.y
- if(dx*dx + dy*dy <= rsq)
- turfs += T
- return turfs
-
-/proc/circleviewturfs(center=usr,radius=3) //Is there even a diffrence between this proc and circlerangeturfs()?
-
- var/turf/centerturf = get_turf(center)
- var/list/turfs = new/list()
- var/rsq = radius * (radius+0.5)
-
- for(var/turf/T in view(radius, centerturf))
- var/dx = T.x - centerturf.x
- var/dy = T.y - centerturf.y
- if(dx*dx + dy*dy <= rsq)
- turfs += T
- return turfs
-
-
-
-//var/debug_mob = 0
-
-// Will recursively loop through an atom's contents and check for mobs, then it will loop through every atom in that atom's contents.
-// It will keep doing this until it checks every content possible. This will fix any problems with mobs, that are inside objects,
-// being unable to hear people due to being in a box within a bag.
-
-/proc/recursive_content_check(var/atom/O, var/list/L = list(), var/recursion_limit = 3, var/client_check = 1, var/sight_check = 1, var/include_mobs = 1, var/include_objects = 1)
-
- if(!recursion_limit)
- return L
-
- for(var/I in O.contents)
-
- if(ismob(I))
- if(!sight_check || isInSight(I, O))
- L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects)
- if(include_mobs)
- if(client_check)
- var/mob/M = I
- if(M.client)
- L |= M
- else
- L |= I
-
- else if(istype(I,/obj/))
- if(!sight_check || isInSight(I, O))
- L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects)
- if(include_objects)
- L |= I
-
- return L
-
-// Returns a list of mobs and/or objects in range of R from source. Used in radio and say code.
-
-/proc/get_mobs_or_objects_in_view(var/R, var/atom/source, var/include_mobs = 1, var/include_objects = 1)
-
- var/turf/T = get_turf(source)
- var/list/hear = list()
-
- if(!T)
- return hear
-
- var/list/range = hear(R, T)
-
- for(var/I in range)
- if(ismob(I))
- hear |= recursive_content_check(I, hear, 3, 1, 0, include_mobs, include_objects)
- if(include_mobs)
- var/mob/M = I
- if(M.client)
- hear += M
- else if(istype(I,/obj/))
- hear |= recursive_content_check(I, hear, 3, 1, 0, include_mobs, include_objects)
- if(include_objects)
- hear += I
-
- return hear
-
-
-/proc/get_mobs_in_radio_ranges(var/list/obj/item/device/radio/radios)
-
- set background = 1
-
- . = list()
- // Returns a list of mobs who can hear any of the radios given in @radios
- var/list/speaker_coverage = list()
- for(var/obj/item/device/radio/R in radios)
- if(R)
- //Cyborg checks. Receiving message uses a bit of cyborg's charge.
- var/obj/item/device/radio/borg/BR = R
- if(istype(BR) && BR.myborg)
- var/mob/living/silicon/robot/borg = BR.myborg
- var/datum/robot_component/CO = borg.get_component("radio")
- if(!CO)
- continue //No radio component (Shouldn't happen)
- if(!borg.is_component_functioning("radio") || !borg.cell_use_power(CO.active_usage))
- continue //No power.
-
- var/turf/speaker = get_turf(R)
- if(speaker)
- for(var/turf/T in hear(R.canhear_range,speaker))
- speaker_coverage[T] = T
-
-
- // Try to find all the players who can hear the message
- for(var/i = 1; i <= player_list.len; i++)
- var/mob/M = player_list[i]
- if(M)
- var/turf/ear = get_turf(M)
- if(ear)
- // Ghostship is magic: Ghosts can hear radio chatter from anywhere
- if(speaker_coverage[ear] || (istype(M, /mob/abstract/observer) && (M.client) && (M.client.prefs.toggles & CHAT_GHOSTRADIO)))
- . += M
- return .
-
-/proc/get_mobs_and_objs_in_view_fast(turf/T, range, list/mobs, list/objs, checkghosts = GHOSTS_ALL_HEAR)
- var/list/hear = list()
- DVIEW(hear, range, T, INVISIBILITY_MAXIMUM)
- var/list/hearturfs = list()
-
- for(var/am in hear)
- var/atom/movable/AM = am
- if (!AM.loc)
- continue
-
- if(ismob(AM))
- mobs[AM] = TRUE
- hearturfs[AM.locs[1]] = TRUE
- else if(isobj(AM))
- objs[AM] = TRUE
- hearturfs[AM.locs[1]] = TRUE
-
- for(var/m in player_list)
- var/mob/M = m
- if(istype(M, /mob/living/test))
- if (!mobs[M])
- mobs[M] = TRUE
- continue
- if(checkghosts == GHOSTS_ALL_HEAR && M.stat == DEAD && !isnewplayer(M) && (M.client && M.client.prefs.toggles & CHAT_GHOSTEARS))
- if (!mobs[M])
- mobs[M] = TRUE
- continue
- if(M.loc && hearturfs[M.locs[1]])
- if (!mobs[M])
- mobs[M] = TRUE
-
- for(var/o in listening_objects)
- var/obj/O = o
- if(O && O.loc && hearturfs[O.locs[1]])
- if (!objs[O])
- objs[O] = TRUE
-
-#define SIGN(X) ((X<0)?-1:1)
-
-proc
- inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5)
- var/turf/T
- if(X1==X2)
- if(Y1==Y2)
- return 1 //Light cannot be blocked on same tile
- else
- var/s = SIGN(Y2-Y1)
- Y1+=s
- while(Y1!=Y2)
- T=locate(X1,Y1,Z)
- if(T.opacity)
- return 0
- Y1+=s
- else
- var/m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1))
- var/b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles
- var/signX = SIGN(X2-X1)
- var/signY = SIGN(Y2-Y1)
- if(X1 abs (dx)) //slope is above 1:1 (move horizontally in a tie)
- if(dy > 0)
- return get_step(start, SOUTH)
- else
- return get_step(start, NORTH)
- else
- if(dx > 0)
- return get_step(start, WEST)
- else
- return get_step(start, EAST)
-
-/proc/get_mob_by_key(var/key)
- for(var/mob/M in mob_list)
- if(M.ckey == lowertext(key))
- return M
- return null
-
-
-// Will return a list of active candidates. It increases the buffer 5 times until it finds a candidate which is active within the buffer.
-/proc/get_active_candidates(var/buffer = 1)
-
- var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn
- var/i = 0
- while(candidates.len <= 0 && i < 5)
- for(var/mob/abstract/observer/G in player_list)
- if(((G.client.inactivity/10)/60) <= buffer + i) // the most active players are more likely to become an alien
- if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
- candidates += G.key
- i++
- return candidates
-
-// Same as above but for alien candidates.
-
-/proc/ScreenText(obj/O, maptext="", screen_loc="CENTER-7,CENTER-7", maptext_height=480, maptext_width=480)
- if(!isobj(O)) O = new /obj/screen/text()
- O.maptext = maptext
- O.maptext_height = maptext_height
- O.maptext_width = maptext_width
- O.screen_loc = screen_loc
- return O
-
-/proc/Show2Group4Delay(obj/O, list/group, delay=0)
- if(!isobj(O)) return
- if(!group) group = clients
- for(var/client/C in group)
- C.screen += O
- if(delay)
- spawn(delay)
- for(var/client/C in group)
- C.screen -= O
-
-datum/projectile_data
- var/src_x
- var/src_y
- var/time
- var/distance
- var/power_x
- var/power_y
- var/dest_x
- var/dest_y
-
-/datum/projectile_data/New(var/src_x, var/src_y, var/time, var/distance, \
- var/power_x, var/power_y, var/dest_x, var/dest_y)
- src.src_x = src_x
- src.src_y = src_y
- src.time = time
- src.distance = distance
- src.power_x = power_x
- src.power_y = power_y
- src.dest_x = dest_x
- src.dest_y = dest_y
-
-/proc/projectile_trajectory(var/src_x, var/src_y, var/rotation, var/angle, var/power)
-
- var/g = 9.81
- var/h = 10
- var/power_x = power * cos(angle)
- var/power_y = power * sin(angle)
- var/time = (power_y + sqrt((power_y*power_y)+(2*g*h)))/g
- var/distance = time * power_x
-
- var/dest_x = src_x + distance*sin(rotation);
- var/dest_y = src_y + distance*cos(rotation);
-
- return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y)
-
-/proc/GetRedPart(const/hexa)
- return hex2num(copytext(hexa,2,4))
-
-/proc/GetGreenPart(const/hexa)
- return hex2num(copytext(hexa,4,6))
-
-/proc/GetBluePart(const/hexa)
- return hex2num(copytext(hexa,6,8))
-
-/proc/GetHexColors(const/hexa)
- return list(
- GetRedPart(hexa),
- GetGreenPart(hexa),
- GetBluePart(hexa)
- )
-
-/proc/MixColors(const/list/colors)
- var/list/reds = list()
- var/list/blues = list()
- var/list/greens = list()
- var/list/weights = list()
-
- for (var/i = 0, ++i <= colors.len)
- reds.Add(GetRedPart(colors[i]))
- blues.Add(GetBluePart(colors[i]))
- greens.Add(GetGreenPart(colors[i]))
- weights.Add(1)
-
- var/r = mixOneColor(weights, reds)
- var/g = mixOneColor(weights, greens)
- var/b = mixOneColor(weights, blues)
- return rgb(r,g,b)
-
-/proc/mixOneColor(var/list/weight, var/list/color)
- if (!weight || !color || length(weight)!=length(color))
- return 0
-
- var/contents = length(weight)
- var/i
-
- //normalize weights
- var/listsum = 0
- for(i=1; i<=contents; i++)
- listsum += weight[i]
- for(i=1; i<=contents; i++)
- weight[i] /= listsum
-
- //mix them
- var/mixedcolor = 0
- for(i=1; i<=contents; i++)
- mixedcolor += weight[i]*color[i]
- mixedcolor = round(mixedcolor)
-
- //until someone writes a formal proof for this algorithm, let's keep this in
-// if(mixedcolor<0x00 || mixedcolor>0xFF)
-// return 0
- //that's not the kind of operation we are running here, nerd
- mixedcolor=min(max(mixedcolor,0),255)
-
- return mixedcolor
-
-/**
-* Gets the highest and lowest pressures from the tiles in cardinal directions
-* around us, then checks the difference.
-*/
-/proc/getOPressureDifferential(var/turf/loc)
- var/minp=16777216;
- var/maxp=0;
- for(var/dir in cardinal)
- var/turf/simulated/T=get_turf(get_step(loc,dir))
- var/cp=0
- if(T && istype(T) && T.zone)
- var/datum/gas_mixture/environment = T.return_air()
- cp = environment.return_pressure()
- else
- if(istype(T,/turf/simulated))
- continue
- if(cpmaxp)maxp=cp
- return abs(minp-maxp)
-
-/proc/convert_k2c(var/temp)
- return ((temp - T0C))
-
-/proc/convert_c2k(var/temp)
- return ((temp + T0C))
-
-/proc/getCardinalAirInfo(var/turf/loc, var/list/stats=list("temperature"))
- var/list/temps = new/list(4)
- for(var/dir in cardinal)
- var/direction
- switch(dir)
- if(NORTH)
- direction = 1
- if(SOUTH)
- direction = 2
- if(EAST)
- direction = 3
- if(WEST)
- direction = 4
- var/turf/simulated/T=get_turf(get_step(loc,dir))
- var/list/rstats = new /list(stats.len)
- if(T && istype(T) && T.zone)
- var/datum/gas_mixture/environment = T.return_air()
- for(var/i=1;i<=stats.len;i++)
- if(stats[i] == "pressure")
- rstats[i] = environment.return_pressure()
- else
- rstats[i] = environment.vars[stats[i]]
- else if(istype(T, /turf/simulated))
- rstats = null // Exclude zone (wall, door, etc).
- else if(istype(T, /turf))
- // Should still work. (/turf/return_air())
- var/datum/gas_mixture/environment = T.return_air()
- for(var/i=1;i<=stats.len;i++)
- if(stats[i] == "pressure")
- rstats[i] = environment.return_pressure()
- else
- rstats[i] = environment.vars[stats[i]]
- temps[direction] = rstats
- return temps
-
-/proc/MinutesToTicks(var/minutes)
- return SecondsToTicks(60 * minutes)
-
-/proc/SecondsToTicks(var/seconds)
- return seconds * 10
-
-/proc/round_is_spooky(var/spookiness_threshold = config.cult_ghostwriter_req_cultists)
- if(enabled_spooking)
- return 1
- else
- return (cult.current_antagonists.len > spookiness_threshold)
-
-/proc/remove_images_from_clients(image/I, list/show_to)
- for(var/client/C in show_to)
- C.images -= I
-
-/proc/flick_overlay(image/I, list/show_to, duration)
- for(var/client/C in show_to)
- C.images += I
- addtimer(CALLBACK(GLOBAL_PROC, /.proc/remove_images_from_clients, I, show_to), duration)
-
-/proc/flick_overlay_view(image/I, atom/target, duration) //wrapper for the above, flicks to everyone who can see the target atom
- var/list/viewing = list()
- for(var/m in viewers(target))
- var/mob/M = m
- if(M.client)
- viewing += M.client
- flick_overlay(I, viewing, duration)
+//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
+
+/proc/dopage(src,target)
+ var/href_list
+ var/href
+ href_list = params2list("src=\ref[src]&[target]=1")
+ href = "src=\ref[src];[target]=1"
+ src:temphtml = null
+ src:Topic(href, href_list)
+ return null
+
+/proc/is_on_same_plane_or_station(var/z1, var/z2)
+ if(z1 == z2)
+ return 1
+ if(isStationLevel(z1) && isStationLevel(z2))
+ return 1
+ return 0
+
+/proc/max_default_z_level()
+ var/max_z = 0
+ for(var/z in current_map.station_levels)
+ max_z = max(z, max_z)
+ for(var/z in current_map.admin_levels)
+ max_z = max(z, max_z)
+ for(var/z in current_map.player_levels)
+ max_z = max(z, max_z)
+ return max_z
+
+/proc/get_area(O)
+ var/turf/loc = get_turf(O)
+ if(loc)
+ .= loc.loc
+
+/proc/get_area_name(N) //get area by its name
+ for(var/area/A in all_areas)
+ if(A.name == N)
+ return A
+ return 0
+
+/proc/get_area_master(const/O)
+ var/area/A = get_area(O)
+ if (isarea(A))
+ return A
+
+/proc/in_range(source, user)
+ if(get_dist(source, user) <= 1)
+ return 1
+
+ return 0 //not in range and not telekinetic
+
+// Like view but bypasses luminosity check
+
+/proc/hear(var/range, var/atom/source)
+
+ var/lum = source.luminosity
+ source.luminosity = 6
+
+ var/list/heard = view(range, source)
+ source.luminosity = lum
+
+ return heard
+
+/proc/circlerange(center=usr,radius=3)
+
+ var/turf/centerturf = get_turf(center)
+ var/list/turfs = new/list()
+ var/rsq = radius * (radius+0.5)
+
+ for(var/atom/T in range(radius, centerturf))
+ var/dx = T.x - centerturf.x
+ var/dy = T.y - centerturf.y
+ if(dx*dx + dy*dy <= rsq)
+ turfs += T
+
+ //turfs += centerturf
+ return turfs
+
+/proc/circleview(center=usr,radius=3)
+
+ var/turf/centerturf = get_turf(center)
+ var/list/atoms = new/list()
+ var/rsq = radius * (radius+0.5)
+
+ for(var/atom/A in view(radius, centerturf))
+ var/dx = A.x - centerturf.x
+ var/dy = A.y - centerturf.y
+ if(dx*dx + dy*dy <= rsq)
+ atoms += A
+
+ //turfs += centerturf
+ return atoms
+
+/proc/get_dist_euclidian(atom/Loc1 as turf|mob|obj,atom/Loc2 as turf|mob|obj)
+ var/dx = Loc1.x - Loc2.x
+ var/dy = Loc1.y - Loc2.y
+
+ var/dist = sqrt(dx**2 + dy**2)
+
+ return dist
+
+/proc/circlerangeturfs(center=usr,radius=3)
+
+ var/turf/centerturf = get_turf(center)
+ var/list/turfs = new/list()
+ var/rsq = radius * (radius+0.5)
+
+ for(var/turf/T in range(radius, centerturf))
+ var/dx = T.x - centerturf.x
+ var/dy = T.y - centerturf.y
+ if(dx*dx + dy*dy <= rsq)
+ turfs += T
+ return turfs
+
+/proc/circleviewturfs(center=usr,radius=3) //Is there even a diffrence between this proc and circlerangeturfs()?
+
+ var/turf/centerturf = get_turf(center)
+ var/list/turfs = new/list()
+ var/rsq = radius * (radius+0.5)
+
+ for(var/turf/T in view(radius, centerturf))
+ var/dx = T.x - centerturf.x
+ var/dy = T.y - centerturf.y
+ if(dx*dx + dy*dy <= rsq)
+ turfs += T
+ return turfs
+
+
+
+//var/debug_mob = 0
+
+// Will recursively loop through an atom's contents and check for mobs, then it will loop through every atom in that atom's contents.
+// It will keep doing this until it checks every content possible. This will fix any problems with mobs, that are inside objects,
+// being unable to hear people due to being in a box within a bag.
+
+/proc/recursive_content_check(var/atom/O, var/list/L = list(), var/recursion_limit = 3, var/client_check = 1, var/sight_check = 1, var/include_mobs = 1, var/include_objects = 1)
+
+ if(!recursion_limit)
+ return L
+
+ for(var/I in O.contents)
+
+ if(ismob(I))
+ if(!sight_check || isInSight(I, O))
+ L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects)
+ if(include_mobs)
+ if(client_check)
+ var/mob/M = I
+ if(M.client)
+ L |= M
+ else
+ L |= I
+
+ else if(istype(I,/obj/))
+ if(!sight_check || isInSight(I, O))
+ L |= recursive_content_check(I, L, recursion_limit - 1, client_check, sight_check, include_mobs, include_objects)
+ if(include_objects)
+ L |= I
+
+ return L
+
+// Returns a list of mobs and/or objects in range of R from source. Used in radio and say code.
+
+/proc/get_mobs_or_objects_in_view(var/R, var/atom/source, var/include_mobs = 1, var/include_objects = 1)
+
+ var/turf/T = get_turf(source)
+ var/list/hear = list()
+
+ if(!T)
+ return hear
+
+ var/list/range = hear(R, T)
+
+ for(var/I in range)
+ if(ismob(I))
+ hear |= recursive_content_check(I, hear, 3, 1, 0, include_mobs, include_objects)
+ if(include_mobs)
+ var/mob/M = I
+ if(M.client)
+ hear += M
+ else if(istype(I,/obj/))
+ hear |= recursive_content_check(I, hear, 3, 1, 0, include_mobs, include_objects)
+ if(include_objects)
+ hear += I
+
+ return hear
+
+
+/proc/get_mobs_in_radio_ranges(var/list/obj/item/device/radio/radios)
+
+ set background = 1
+
+ . = list()
+ // Returns a list of mobs who can hear any of the radios given in @radios
+ var/list/speaker_coverage = list()
+ for(var/obj/item/device/radio/R in radios)
+ if(R)
+ //Cyborg checks. Receiving message uses a bit of cyborg's charge.
+ var/obj/item/device/radio/borg/BR = R
+ if(istype(BR) && BR.myborg)
+ var/mob/living/silicon/robot/borg = BR.myborg
+ var/datum/robot_component/CO = borg.get_component("radio")
+ if(!CO)
+ continue //No radio component (Shouldn't happen)
+ if(!borg.is_component_functioning("radio") || !borg.cell_use_power(CO.active_usage))
+ continue //No power.
+
+ var/turf/speaker = get_turf(R)
+ if(speaker)
+ for(var/turf/T in hear(R.canhear_range,speaker))
+ speaker_coverage[T] = T
+
+
+ // Try to find all the players who can hear the message
+ for(var/i = 1; i <= player_list.len; i++)
+ var/mob/M = player_list[i]
+ if(M)
+ var/turf/ear = get_turf(M)
+ if(ear)
+ // Ghostship is magic: Ghosts can hear radio chatter from anywhere
+ if(speaker_coverage[ear] || (istype(M, /mob/abstract/observer) && (M.client) && (M.client.prefs.toggles & CHAT_GHOSTRADIO)))
+ . += M
+ return .
+
+/proc/get_mobs_and_objs_in_view_fast(turf/T, range, list/mobs, list/objs, checkghosts = GHOSTS_ALL_HEAR)
+ var/list/hear = list()
+ DVIEW(hear, range, T, INVISIBILITY_MAXIMUM)
+ var/list/hearturfs = list()
+
+ for(var/am in hear)
+ var/atom/movable/AM = am
+ if (!AM.loc)
+ continue
+
+ if(ismob(AM))
+ mobs[AM] = TRUE
+ hearturfs[AM.locs[1]] = TRUE
+ else if(isobj(AM))
+ objs[AM] = TRUE
+ hearturfs[AM.locs[1]] = TRUE
+
+ for(var/m in player_list)
+ var/mob/M = m
+ if(istype(M, /mob/living/test))
+ if (!mobs[M])
+ mobs[M] = TRUE
+ continue
+ if(checkghosts == GHOSTS_ALL_HEAR && M.stat == DEAD && !isnewplayer(M) && (M.client && M.client.prefs.toggles & CHAT_GHOSTEARS))
+ if (!mobs[M])
+ mobs[M] = TRUE
+ continue
+ if(M.loc && hearturfs[M.locs[1]])
+ if (!mobs[M])
+ mobs[M] = TRUE
+
+ for(var/o in listening_objects)
+ var/obj/O = o
+ if(O && O.loc && hearturfs[O.locs[1]])
+ if (!objs[O])
+ objs[O] = TRUE
+
+#define SIGN(X) ((X<0)?-1:1)
+
+proc
+ inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5)
+ var/turf/T
+ if(X1==X2)
+ if(Y1==Y2)
+ return 1 //Light cannot be blocked on same tile
+ else
+ var/s = SIGN(Y2-Y1)
+ Y1+=s
+ while(Y1!=Y2)
+ T=locate(X1,Y1,Z)
+ if(T.opacity)
+ return 0
+ Y1+=s
+ else
+ var/m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1))
+ var/b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles
+ var/signX = SIGN(X2-X1)
+ var/signY = SIGN(Y2-Y1)
+ if(X1 abs (dx)) //slope is above 1:1 (move horizontally in a tie)
+ if(dy > 0)
+ return get_step(start, SOUTH)
+ else
+ return get_step(start, NORTH)
+ else
+ if(dx > 0)
+ return get_step(start, WEST)
+ else
+ return get_step(start, EAST)
+
+/proc/get_mob_by_key(var/key)
+ for(var/mob/M in mob_list)
+ if(M.ckey == lowertext(key))
+ return M
+ return null
+
+
+// Will return a list of active candidates. It increases the buffer 5 times until it finds a candidate which is active within the buffer.
+/proc/get_active_candidates(var/buffer = 1)
+
+ var/list/candidates = list() //List of candidate KEYS to assume control of the new larva ~Carn
+ var/i = 0
+ while(candidates.len <= 0 && i < 5)
+ for(var/mob/abstract/observer/G in player_list)
+ if(((G.client.inactivity/10)/60) <= buffer + i) // the most active players are more likely to become an alien
+ if(!(G.mind && G.mind.current && G.mind.current.stat != DEAD))
+ candidates += G.key
+ i++
+ return candidates
+
+// Same as above but for alien candidates.
+
+/proc/ScreenText(obj/O, maptext="", screen_loc="CENTER-7,CENTER-7", maptext_height=480, maptext_width=480)
+ if(!isobj(O)) O = new /obj/screen/text()
+ O.maptext = maptext
+ O.maptext_height = maptext_height
+ O.maptext_width = maptext_width
+ O.screen_loc = screen_loc
+ return O
+
+/proc/Show2Group4Delay(obj/O, list/group, delay=0)
+ if(!isobj(O)) return
+ if(!group) group = clients
+ for(var/client/C in group)
+ C.screen += O
+ if(delay)
+ spawn(delay)
+ for(var/client/C in group)
+ C.screen -= O
+
+datum/projectile_data
+ var/src_x
+ var/src_y
+ var/time
+ var/distance
+ var/power_x
+ var/power_y
+ var/dest_x
+ var/dest_y
+
+/datum/projectile_data/New(var/src_x, var/src_y, var/time, var/distance, \
+ var/power_x, var/power_y, var/dest_x, var/dest_y)
+ src.src_x = src_x
+ src.src_y = src_y
+ src.time = time
+ src.distance = distance
+ src.power_x = power_x
+ src.power_y = power_y
+ src.dest_x = dest_x
+ src.dest_y = dest_y
+
+/proc/projectile_trajectory(var/src_x, var/src_y, var/rotation, var/angle, var/power)
+
+ var/g = 9.81
+ var/h = 10
+ var/power_x = power * cos(angle)
+ var/power_y = power * sin(angle)
+ var/time = (power_y + sqrt((power_y*power_y)+(2*g*h)))/g
+ var/distance = time * power_x
+
+ var/dest_x = src_x + distance*sin(rotation);
+ var/dest_y = src_y + distance*cos(rotation);
+
+ return new /datum/projectile_data(src_x, src_y, time, distance, power_x, power_y, dest_x, dest_y)
+
+/proc/GetRedPart(const/hexa)
+ return hex2num(copytext(hexa,2,4))
+
+/proc/GetGreenPart(const/hexa)
+ return hex2num(copytext(hexa,4,6))
+
+/proc/GetBluePart(const/hexa)
+ return hex2num(copytext(hexa,6,8))
+
+/proc/GetHexColors(const/hexa)
+ return list(
+ GetRedPart(hexa),
+ GetGreenPart(hexa),
+ GetBluePart(hexa)
+ )
+
+/proc/MixColors(const/list/colors)
+ var/list/reds = list()
+ var/list/blues = list()
+ var/list/greens = list()
+ var/list/weights = list()
+
+ for (var/i = 0, ++i <= colors.len)
+ reds.Add(GetRedPart(colors[i]))
+ blues.Add(GetBluePart(colors[i]))
+ greens.Add(GetGreenPart(colors[i]))
+ weights.Add(1)
+
+ var/r = mixOneColor(weights, reds)
+ var/g = mixOneColor(weights, greens)
+ var/b = mixOneColor(weights, blues)
+ return rgb(r,g,b)
+
+/proc/mixOneColor(var/list/weight, var/list/color)
+ if (!weight || !color || length(weight)!=length(color))
+ return 0
+
+ var/contents = length(weight)
+ var/i
+
+ //normalize weights
+ var/listsum = 0
+ for(i=1; i<=contents; i++)
+ listsum += weight[i]
+ for(i=1; i<=contents; i++)
+ weight[i] /= listsum
+
+ //mix them
+ var/mixedcolor = 0
+ for(i=1; i<=contents; i++)
+ mixedcolor += weight[i]*color[i]
+ mixedcolor = round(mixedcolor)
+
+ //until someone writes a formal proof for this algorithm, let's keep this in
+// if(mixedcolor<0x00 || mixedcolor>0xFF)
+// return 0
+ //that's not the kind of operation we are running here, nerd
+ mixedcolor=min(max(mixedcolor,0),255)
+
+ return mixedcolor
+
+/**
+* Gets the highest and lowest pressures from the tiles in cardinal directions
+* around us, then checks the difference.
+*/
+/proc/getOPressureDifferential(var/turf/loc)
+ var/minp=16777216;
+ var/maxp=0;
+ for(var/dir in cardinal)
+ var/turf/simulated/T=get_turf(get_step(loc,dir))
+ var/cp=0
+ if(T && istype(T) && T.zone)
+ var/datum/gas_mixture/environment = T.return_air()
+ cp = environment.return_pressure()
+ else
+ if(istype(T,/turf/simulated))
+ continue
+ if(cpmaxp)maxp=cp
+ return abs(minp-maxp)
+
+/proc/convert_k2c(var/temp)
+ return ((temp - T0C))
+
+/proc/convert_c2k(var/temp)
+ return ((temp + T0C))
+
+/proc/getCardinalAirInfo(var/turf/loc, var/list/stats=list("temperature"))
+ var/list/temps = new/list(4)
+ for(var/dir in cardinal)
+ var/direction
+ switch(dir)
+ if(NORTH)
+ direction = 1
+ if(SOUTH)
+ direction = 2
+ if(EAST)
+ direction = 3
+ if(WEST)
+ direction = 4
+ var/turf/simulated/T=get_turf(get_step(loc,dir))
+ var/list/rstats = new /list(stats.len)
+ if(T && istype(T) && T.zone)
+ var/datum/gas_mixture/environment = T.return_air()
+ for(var/i=1;i<=stats.len;i++)
+ if(stats[i] == "pressure")
+ rstats[i] = environment.return_pressure()
+ else
+ rstats[i] = environment.vars[stats[i]]
+ else if(istype(T, /turf/simulated))
+ rstats = null // Exclude zone (wall, door, etc).
+ else if(istype(T, /turf))
+ // Should still work. (/turf/return_air())
+ var/datum/gas_mixture/environment = T.return_air()
+ for(var/i=1;i<=stats.len;i++)
+ if(stats[i] == "pressure")
+ rstats[i] = environment.return_pressure()
+ else
+ rstats[i] = environment.vars[stats[i]]
+ temps[direction] = rstats
+ return temps
+
+/proc/MinutesToTicks(var/minutes)
+ return SecondsToTicks(60 * minutes)
+
+/proc/SecondsToTicks(var/seconds)
+ return seconds * 10
+
+/proc/round_is_spooky(var/spookiness_threshold = config.cult_ghostwriter_req_cultists)
+ if(enabled_spooking)
+ return 1
+ else
+ return (cult.current_antagonists.len > spookiness_threshold)
+
+/proc/remove_images_from_clients(image/I, list/show_to)
+ for(var/client/C in show_to)
+ C.images -= I
+
+/proc/flick_overlay(image/I, list/show_to, duration)
+ for(var/client/C in show_to)
+ C.images += I
+ addtimer(CALLBACK(GLOBAL_PROC, /.proc/remove_images_from_clients, I, show_to), duration)
+
+/proc/flick_overlay_view(image/I, atom/target, duration) //wrapper for the above, flicks to everyone who can see the target atom
+ var/list/viewing = list()
+ for(var/m in viewers(target))
+ var/mob/M = m
+ if(M.client)
+ viewing += M.client
+ flick_overlay(I, viewing, duration)
diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm
index b62f5ad05e9..1f24828c151 100644
--- a/code/_helpers/global_lists.dm
+++ b/code/_helpers/global_lists.dm
@@ -1,225 +1,225 @@
-var/list/clients = list() //list of all clients
-var/list/staff = list() //list of all clients who have any permissions
-var/list/directory = list() //list of all ckeys with associated client
-
-//Since it didn't really belong in any other category, I'm putting this here
-//This is for procs to replace all the goddamn 'in world's that are chilling around the code
-
-var/global/list/player_list = list() //List of all mobs **with clients attached**. Excludes /mob/abstract/new_player
-var/global/list/mob_list = list() //List of all mobs, including clientless
-var/global/list/human_mob_list = list() //List of all human mobs and sub-types, including clientless
-var/global/list/silicon_mob_list = list() //List of all silicon mobs, including clientless
-var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/abstract/new_player
-var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/abstract/new_player
-var/global/list/topic_commands = list() //List of all API commands available
-var/global/list/topic_commands_names = list() //List of all API commands available
-
-var/global/list/landmarks_list = list() //list of all landmarks created
-var/global/list/surgery_steps = list() //list of all surgery steps |BS12
-var/global/list/side_effects = list() //list of all medical sideeffects types by thier names |BS12
-var/global/list/mechas_list = list() //list of all mechs. Used by hostile mobs target tracking.
-var/global/list/joblist = list() //list of all jobstypes, minus borg and AI
-var/global/list/brig_closets = list() //list of all brig secure_closets. Used by brig timers. Probably should be converted to use SSwireless eventually.
-
-var/global/list/teleportlocs = list()
-var/global/list/ghostteleportlocs = list()
-var/global/list/centcom_areas = list()
-var/global/list/the_station_areas = list()
-
-var/global/list/implants = list()
-
-var/global/list/turfs = list() //list of all turfs
-var/global/list/areas_by_type = list()
-var/global/list/all_areas = list()
-
-//Languages/species/whitelist.
-var/global/list/all_species = list()
-var/global/list/all_languages = list()
-var/global/list/language_keys = list() // Table of say codes for all languages
-var/global/list/whitelisted_species = list("Human") // Species that require a whitelist check.
-var/global/list/playable_species = list("Human") // A list of ALL playable species, whitelisted, latejoin or otherwise.
-
-// Posters
-var/global/list/poster_designs = list()
-
-// Uplinks
-var/list/obj/item/device/uplink/world_uplinks = list()
-
-//Preferences stuff
- //Hairstyles
-var/global/list/hair_styles_list = list() //stores /datum/sprite_accessory/hair indexed by name
-var/global/list/hair_styles_male_list = list()
-var/global/list/hair_styles_female_list = list()
-var/global/list/facial_hair_styles_list = list() //stores /datum/sprite_accessory/facial_hair indexed by name
-var/global/list/facial_hair_styles_male_list = list()
-var/global/list/facial_hair_styles_female_list = list()
-var/global/list/skin_styles_female_list = list() //unused
-var/global/list/body_marking_styles_list = list()
-var/global/list/chargen_disabilities_list = list()
-
- //Underwear
-var/global/list/underwear_m = list("White" = "m1", "Grey" = "m2", "Green" = "m3", "Blue" = "m4", "Black" = "m5", "Mankini" = "m6", "Boxers" = "boxers", "Green and blue boxers" = "boxers_green_and_blue","Loveheart boxers" = "boxers_loveheart","None") //Curse whoever made male/female underwear diffrent colours
-var/global/list/underwear_f = list("Red" = "f1", "White" = "f2", "Yellow" = "f3", "Blue" = "f4", "Black" = "f5", "Thong" = "f6", "Black Sports" = "f7","White Sports" = "f8","None")
- //undershirt
-var/global/list/undershirt_t = list(
- "White tank top" = "u1", "Black tank top" = "u2", "Black shirt" = "u3", "White shirt" = "u4",
- "Polo" = "polo", "Blue polo" = "bluepolo_s", "Red polo" = "redpolo_s", "Yellow polo" = "grayyellowpolo_s",
- "Striped shirt" = "shirt_stripes_s", "NanoTrasen shirt" = "shirt_nano_s", "Tiedye shirt" = "shirt_tiedye_s",
- "Green sport shirt" = "greenshirtsport_s", "Red sport shirt" = "redshirtsport_s", "Blue sport shirt" = "blueshirtsport_s",
- "Striped tank top " = "tank_stripes_s", "Rainbow tank top" = "tank_rainbow_s", "Longsleeve shirt" = "undershirt_long",
- "Striped longsleve shirt" = "longstripe", "Blue striped longsleve shirt" = "longstripe_blue", "None")
-
- //socks
-var/global/list/socks_f = list(
- "White normal" = "white_norm", "White short" = "white_short", "White knee" = "white_knee",
- "White thigh" = "white_thigh", "Black normal" = "black_norm", "Black short" = "black_short",
- "Black knee" = "black_knee", "Black thigh" = "black_thigh", "Striped normal" = "striped_norm",
- "Striped short" = "striped_short", "Striped knee" = "striped_knee", "Striped thigh" = "striped_thigh",
- "Rainbow normal" = "rainbow_norm", "Rainbow short" = "rainbow_short", "Rainbow knee" = "rainbow_knee",
- "Rainbow thigh" = "rainbow_thigh", "Pantyhose" = "pantyhose", "None")
-
-var/global/list/socks_m = list(
- "White normal" = "white_norm", "White short" = "white_short", "White knee" = "white_knee",
- "Black normal" = "black_norm", "Black short" = "black_short", "Black knee" = "black_knee",
- "Striped normal" = "striped_norm", "Striped short" = "striped_short", "Striped knee" = "striped_knee",
- "Rainbow normal" = "rainbow_norm", "Rainbow short" = "rainbow_short", "Rainbow knee" = "rainbow_knee", "None")
-
- //Backpacks
-var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt", "Duffel Bag", "Messenger Bag")
-var/global/list/backbagstyles = list("Job-specific", "Grey")
-var/global/list/exclude_jobs = list(/datum/job/ai,/datum/job/cyborg, /datum/job/merchant)
-
-// Visual nets
-var/list/datum/visualnet/visual_nets = list()
-var/datum/visualnet/camera/cameranet = new()
-
-// Runes
-var/global/list/rune_list = new()
-var/global/list/escape_list = list()
-var/global/list/endgame_exits = list()
-var/global/list/endgame_safespawns = list()
-
-var/global/list/syndicate_access = list(access_maint_tunnels, access_syndicate, access_external_airlocks)
-
-//Cloaking devices
-var/global/list/cloaking_devices = list()
-
-//////////////////////////
-/////Initial Building/////
-//////////////////////////
-
-/proc/makeDatumRefLists()
- var/list/paths
-
- //Hair - Initialise all /datum/sprite_accessory/hair into an list indexed by hair-style name
- paths = subtypesof(/datum/sprite_accessory/hair)
- for(var/path in paths)
- var/datum/sprite_accessory/hair/H = new path()
- hair_styles_list[H.name] = H
- switch(H.gender)
- if(MALE) hair_styles_male_list += H.name
- if(FEMALE) hair_styles_female_list += H.name
- else
- hair_styles_male_list += H.name
- hair_styles_female_list += H.name
-
- sortTim(hair_styles_list, /proc/cmp_text_asc)
- sortTim(hair_styles_male_list, /proc/cmp_text_asc)
- sortTim(hair_styles_female_list, /proc/cmp_text_asc)
-
- //Facial Hair - Initialise all /datum/sprite_accessory/facial_hair into an list indexed by facialhair-style name
- paths = subtypesof(/datum/sprite_accessory/facial_hair)
- for(var/path in paths)
- var/datum/sprite_accessory/facial_hair/H = new path()
- facial_hair_styles_list[H.name] = H
- switch(H.gender)
- if(MALE) facial_hair_styles_male_list += H.name
- if(FEMALE) facial_hair_styles_female_list += H.name
- else
- facial_hair_styles_male_list += H.name
- facial_hair_styles_female_list += H.name
-
- sortTim(facial_hair_styles_list, /proc/cmp_text_asc)
- sortTim(facial_hair_styles_male_list, /proc/cmp_text_asc)
- sortTim(facial_hair_styles_female_list, /proc/cmp_text_asc)
-
- //Body markings
- paths = subtypesof(/datum/sprite_accessory/marking)
- for(var/path in paths)
- var/datum/sprite_accessory/marking/M = new path()
- body_marking_styles_list[M.name] = M
-
- sortTim(body_marking_styles_list, /proc/cmp_text_asc)
-
- //Disability datums
- paths = subtypesof(/datum/character_disabilities)
- for(var/path in paths)
- var/datum/character_disabilities/T = new path()
- chargen_disabilities_list[T.name] = T
-
- sortTim(chargen_disabilities_list, /proc/cmp_text_asc)
-
- //Surgery Steps - Initialize all /datum/surgery_step into a list
- paths = subtypesof(/datum/surgery_step)
- for(var/T in paths)
- var/datum/surgery_step/S = new T
- surgery_steps += S
-
- sortTim(surgery_steps, /proc/cmp_surgery)
-
- //List of job. I can't believe this was calculated multiple times per tick!
- paths = subtypesof(/datum/job)
- paths -= exclude_jobs
- for(var/T in paths)
- var/datum/job/J = new T
- joblist[J.title] = J
-
- //Languages and species.
- paths = subtypesof(/datum/language)
- for(var/T in paths)
- var/datum/language/L = new T
- all_languages[L.name] = L
-
- for (var/language_name in all_languages)
- var/datum/language/L = all_languages[language_name]
- if(!(L.flags & NONGLOBAL))
- language_keys[lowertext(L.key)] = L
-
- var/rkey = 0
- paths = subtypesof(/datum/species)
- for(var/T in paths)
- rkey++
- var/datum/species/S = new T
- S.race_key = rkey //Used in mob icon caching.
- all_species[S.name] = S
-
- sortTim(all_species, /proc/cmp_text_asc)
-
- // The other lists are generated *after* we sort the main one so they don't need sorting too.
- for (var/thing in all_species)
- var/datum/species/S = all_species[thing]
-
- if (!(S.spawn_flags & IS_RESTRICTED))
- playable_species += S.name
- if(S.spawn_flags & IS_WHITELISTED)
- whitelisted_species += S.name
-
- //Posters
- paths = subtypesof(/datum/poster)
- for(var/T in paths)
- var/datum/poster/P = new T
- poster_designs += P
-
- return 1
-
-/* // Uncomment to debug chemical reaction list.
-/client/verb/debug_chemical_list()
-
- for (var/reaction in SSchemistry.chemical_reactions)
- . += "SSchemistry.chemical_reactions\[\"[reaction]\"\] = \"[SSchemistry.chemical_reactions[reaction]]\"\n"
- if(islist(SSchemistry.chemical_reactions[reaction]))
- var/list/L = SSchemistry.chemical_reactions[reaction]
- for(var/t in L)
- . += " has: [t]\n"
- world << .
-*/
+var/list/clients = list() //list of all clients
+var/list/staff = list() //list of all clients who have any permissions
+var/list/directory = list() //list of all ckeys with associated client
+
+//Since it didn't really belong in any other category, I'm putting this here
+//This is for procs to replace all the goddamn 'in world's that are chilling around the code
+
+var/global/list/player_list = list() //List of all mobs **with clients attached**. Excludes /mob/abstract/new_player
+var/global/list/mob_list = list() //List of all mobs, including clientless
+var/global/list/human_mob_list = list() //List of all human mobs and sub-types, including clientless
+var/global/list/silicon_mob_list = list() //List of all silicon mobs, including clientless
+var/global/list/living_mob_list = list() //List of all alive mobs, including clientless. Excludes /mob/abstract/new_player
+var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/abstract/new_player
+var/global/list/topic_commands = list() //List of all API commands available
+var/global/list/topic_commands_names = list() //List of all API commands available
+
+var/global/list/landmarks_list = list() //list of all landmarks created
+var/global/list/surgery_steps = list() //list of all surgery steps |BS12
+var/global/list/side_effects = list() //list of all medical sideeffects types by thier names |BS12
+var/global/list/mechas_list = list() //list of all mechs. Used by hostile mobs target tracking.
+var/global/list/joblist = list() //list of all jobstypes, minus borg and AI
+var/global/list/brig_closets = list() //list of all brig secure_closets. Used by brig timers. Probably should be converted to use SSwireless eventually.
+
+var/global/list/teleportlocs = list()
+var/global/list/ghostteleportlocs = list()
+var/global/list/centcom_areas = list()
+var/global/list/the_station_areas = list()
+
+var/global/list/implants = list()
+
+var/global/list/turfs = list() //list of all turfs
+var/global/list/areas_by_type = list()
+var/global/list/all_areas = list()
+
+//Languages/species/whitelist.
+var/global/list/all_species = list()
+var/global/list/all_languages = list()
+var/global/list/language_keys = list() // Table of say codes for all languages
+var/global/list/whitelisted_species = list("Human") // Species that require a whitelist check.
+var/global/list/playable_species = list("Human") // A list of ALL playable species, whitelisted, latejoin or otherwise.
+
+// Posters
+var/global/list/poster_designs = list()
+
+// Uplinks
+var/list/obj/item/device/uplink/world_uplinks = list()
+
+//Preferences stuff
+ //Hairstyles
+var/global/list/hair_styles_list = list() //stores /datum/sprite_accessory/hair indexed by name
+var/global/list/hair_styles_male_list = list()
+var/global/list/hair_styles_female_list = list()
+var/global/list/facial_hair_styles_list = list() //stores /datum/sprite_accessory/facial_hair indexed by name
+var/global/list/facial_hair_styles_male_list = list()
+var/global/list/facial_hair_styles_female_list = list()
+var/global/list/skin_styles_female_list = list() //unused
+var/global/list/body_marking_styles_list = list()
+var/global/list/chargen_disabilities_list = list()
+
+ //Underwear
+var/global/list/underwear_m = list("White" = "m1", "Grey" = "m2", "Green" = "m3", "Blue" = "m4", "Black" = "m5", "Mankini" = "m6", "Boxers" = "boxers", "Green and blue boxers" = "boxers_green_and_blue","Loveheart boxers" = "boxers_loveheart","None") //Curse whoever made male/female underwear diffrent colours
+var/global/list/underwear_f = list("Red" = "f1", "White" = "f2", "Yellow" = "f3", "Blue" = "f4", "Black" = "f5", "Thong" = "f6", "Black Sports" = "f7","White Sports" = "f8","None")
+ //undershirt
+var/global/list/undershirt_t = list(
+ "White tank top" = "u1", "Black tank top" = "u2", "Black shirt" = "u3", "White shirt" = "u4",
+ "Polo" = "polo", "Blue polo" = "bluepolo_s", "Red polo" = "redpolo_s", "Yellow polo" = "grayyellowpolo_s",
+ "Striped shirt" = "shirt_stripes_s", "NanoTrasen shirt" = "shirt_nano_s", "Tiedye shirt" = "shirt_tiedye_s",
+ "Green sport shirt" = "greenshirtsport_s", "Red sport shirt" = "redshirtsport_s", "Blue sport shirt" = "blueshirtsport_s",
+ "Striped tank top " = "tank_stripes_s", "Rainbow tank top" = "tank_rainbow_s", "Longsleeve shirt" = "undershirt_long",
+ "Striped longsleve shirt" = "longstripe", "Blue striped longsleve shirt" = "longstripe_blue", "None")
+
+ //socks
+var/global/list/socks_f = list(
+ "White normal" = "white_norm", "White short" = "white_short", "White knee" = "white_knee",
+ "White thigh" = "white_thigh", "Black normal" = "black_norm", "Black short" = "black_short",
+ "Black knee" = "black_knee", "Black thigh" = "black_thigh", "Striped normal" = "striped_norm",
+ "Striped short" = "striped_short", "Striped knee" = "striped_knee", "Striped thigh" = "striped_thigh",
+ "Rainbow normal" = "rainbow_norm", "Rainbow short" = "rainbow_short", "Rainbow knee" = "rainbow_knee",
+ "Rainbow thigh" = "rainbow_thigh", "Pantyhose" = "pantyhose", "None")
+
+var/global/list/socks_m = list(
+ "White normal" = "white_norm", "White short" = "white_short", "White knee" = "white_knee",
+ "Black normal" = "black_norm", "Black short" = "black_short", "Black knee" = "black_knee",
+ "Striped normal" = "striped_norm", "Striped short" = "striped_short", "Striped knee" = "striped_knee",
+ "Rainbow normal" = "rainbow_norm", "Rainbow short" = "rainbow_short", "Rainbow knee" = "rainbow_knee", "None")
+
+ //Backpacks
+var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Alt", "Duffel Bag", "Messenger Bag")
+var/global/list/backbagstyles = list("Job-specific", "Grey")
+var/global/list/exclude_jobs = list(/datum/job/ai,/datum/job/cyborg, /datum/job/merchant)
+
+// Visual nets
+var/list/datum/visualnet/visual_nets = list()
+var/datum/visualnet/camera/cameranet = new()
+
+// Runes
+var/global/list/rune_list = new()
+var/global/list/escape_list = list()
+var/global/list/endgame_exits = list()
+var/global/list/endgame_safespawns = list()
+
+var/global/list/syndicate_access = list(access_maint_tunnels, access_syndicate, access_external_airlocks)
+
+//Cloaking devices
+var/global/list/cloaking_devices = list()
+
+//////////////////////////
+/////Initial Building/////
+//////////////////////////
+
+/proc/makeDatumRefLists()
+ var/list/paths
+
+ //Hair - Initialise all /datum/sprite_accessory/hair into an list indexed by hair-style name
+ paths = subtypesof(/datum/sprite_accessory/hair)
+ for(var/path in paths)
+ var/datum/sprite_accessory/hair/H = new path()
+ hair_styles_list[H.name] = H
+ switch(H.gender)
+ if(MALE) hair_styles_male_list += H.name
+ if(FEMALE) hair_styles_female_list += H.name
+ else
+ hair_styles_male_list += H.name
+ hair_styles_female_list += H.name
+
+ sortTim(hair_styles_list, /proc/cmp_text_asc)
+ sortTim(hair_styles_male_list, /proc/cmp_text_asc)
+ sortTim(hair_styles_female_list, /proc/cmp_text_asc)
+
+ //Facial Hair - Initialise all /datum/sprite_accessory/facial_hair into an list indexed by facialhair-style name
+ paths = subtypesof(/datum/sprite_accessory/facial_hair)
+ for(var/path in paths)
+ var/datum/sprite_accessory/facial_hair/H = new path()
+ facial_hair_styles_list[H.name] = H
+ switch(H.gender)
+ if(MALE) facial_hair_styles_male_list += H.name
+ if(FEMALE) facial_hair_styles_female_list += H.name
+ else
+ facial_hair_styles_male_list += H.name
+ facial_hair_styles_female_list += H.name
+
+ sortTim(facial_hair_styles_list, /proc/cmp_text_asc)
+ sortTim(facial_hair_styles_male_list, /proc/cmp_text_asc)
+ sortTim(facial_hair_styles_female_list, /proc/cmp_text_asc)
+
+ //Body markings
+ paths = subtypesof(/datum/sprite_accessory/marking)
+ for(var/path in paths)
+ var/datum/sprite_accessory/marking/M = new path()
+ body_marking_styles_list[M.name] = M
+
+ sortTim(body_marking_styles_list, /proc/cmp_text_asc)
+
+ //Disability datums
+ paths = subtypesof(/datum/character_disabilities)
+ for(var/path in paths)
+ var/datum/character_disabilities/T = new path()
+ chargen_disabilities_list[T.name] = T
+
+ sortTim(chargen_disabilities_list, /proc/cmp_text_asc)
+
+ //Surgery Steps - Initialize all /datum/surgery_step into a list
+ paths = subtypesof(/datum/surgery_step)
+ for(var/T in paths)
+ var/datum/surgery_step/S = new T
+ surgery_steps += S
+
+ sortTim(surgery_steps, /proc/cmp_surgery)
+
+ //List of job. I can't believe this was calculated multiple times per tick!
+ paths = subtypesof(/datum/job)
+ paths -= exclude_jobs
+ for(var/T in paths)
+ var/datum/job/J = new T
+ joblist[J.title] = J
+
+ //Languages and species.
+ paths = subtypesof(/datum/language)
+ for(var/T in paths)
+ var/datum/language/L = new T
+ all_languages[L.name] = L
+
+ for (var/language_name in all_languages)
+ var/datum/language/L = all_languages[language_name]
+ if(!(L.flags & NONGLOBAL))
+ language_keys[lowertext(L.key)] = L
+
+ var/rkey = 0
+ paths = subtypesof(/datum/species)
+ for(var/T in paths)
+ rkey++
+ var/datum/species/S = new T
+ S.race_key = rkey //Used in mob icon caching.
+ all_species[S.name] = S
+
+ sortTim(all_species, /proc/cmp_text_asc)
+
+ // The other lists are generated *after* we sort the main one so they don't need sorting too.
+ for (var/thing in all_species)
+ var/datum/species/S = all_species[thing]
+
+ if (!(S.spawn_flags & IS_RESTRICTED))
+ playable_species += S.name
+ if(S.spawn_flags & IS_WHITELISTED)
+ whitelisted_species += S.name
+
+ //Posters
+ paths = subtypesof(/datum/poster)
+ for(var/T in paths)
+ var/datum/poster/P = new T
+ poster_designs += P
+
+ return 1
+
+/* // Uncomment to debug chemical reaction list.
+/client/verb/debug_chemical_list()
+
+ for (var/reaction in SSchemistry.chemical_reactions)
+ . += "SSchemistry.chemical_reactions\[\"[reaction]\"\] = \"[SSchemistry.chemical_reactions[reaction]]\"\n"
+ if(islist(SSchemistry.chemical_reactions[reaction]))
+ var/list/L = SSchemistry.chemical_reactions[reaction]
+ for(var/t in L)
+ . += " has: [t]\n"
+ world << .
+*/
diff --git a/code/_helpers/icons.dm b/code/_helpers/icons.dm
index 7f372cf1fd8..df15e18a07b 100644
--- a/code/_helpers/icons.dm
+++ b/code/_helpers/icons.dm
@@ -1,966 +1,966 @@
-/*
-IconProcs README
-
-A BYOND library for manipulating icons and colors
-
-by Lummox JR
-
-version 1.0
-
-The IconProcs library was made to make a lot of common icon operations much easier. BYOND's icon manipulation
-routines are very capable but some of the advanced capabilities like using alpha transparency can be unintuitive to beginners.
-
-CHANGING ICONS
-
-Several new procs have been added to the /icon datum to simplify working with icons. To use them,
-remember you first need to setup an /icon var like so:
-
-var/icon/my_icon = new('iconfile.dmi')
-
-icon/ChangeOpacity(amount = 1)
- A very common operation in DM is to try to make an icon more or less transparent. Making an icon more
- transparent is usually much easier than making it less so, however. This proc basically is a frontend
- for MapColors() which can change opacity any way you like, in much the same way that SetIntensity()
- can make an icon lighter or darker. If amount is 0.5, the opacity of the icon will be cut in half.
- If amount is 2, opacity is doubled and anything more than half-opaque will become fully opaque.
-icon/GrayScale()
- Converts the icon to grayscale instead of a fully colored icon. Alpha values are left intact.
-icon/ColorTone(tone)
- Similar to GrayScale(), this proc converts the icon to a range of black -> tone -> white, where tone is an
- RGB color (its alpha is ignored). This can be used to create a sepia tone or similar effect.
- See also the global ColorTone() proc.
-icon/MinColors(icon)
- The icon is blended with a second icon where the minimum of each RGB pixel is the result.
- Transparency may increase, as if the icons were blended with ICON_ADD. You may supply a color in place of an icon.
-icon/MaxColors(icon)
- The icon is blended with a second icon where the maximum of each RGB pixel is the result.
- Opacity may increase, as if the icons were blended with ICON_OR. You may supply a color in place of an icon.
-icon/Opaque(background = "#000000")
- All alpha values are set to 255 throughout the icon. Transparent pixels become black, or whatever background color you specify.
-icon/BecomeAlphaMask()
- You can convert a simple grayscale icon into an alpha mask to use with other icons very easily with this proc.
- The black parts become transparent, the white parts stay white, and anything in between becomes a translucent shade of white.
-icon/AddAlphaMask(mask)
- The alpha values of the mask icon will be blended with the current icon. Anywhere the mask is opaque,
- the current icon is untouched. Anywhere the mask is transparent, the current icon becomes transparent.
- Where the mask is translucent, the current icon becomes more transparent.
-icon/UseAlphaMask(mask, mode)
- Sometimes you may want to take the alpha values from one icon and use them on a different icon.
- This proc will do that. Just supply the icon whose alpha mask you want to use, and src will change
- so it has the same colors as before but uses the mask for opacity.
-
-COLOR MANAGEMENT AND HSV
-
-RGB isn't the only way to represent color. Sometimes it's more useful to work with a model called HSV, which stands for hue, saturation, and value.
-
- * The hue of a color describes where it is along the color wheel. It goes from red to yellow to green to
- cyan to blue to magenta and back to red.
- * The saturation of a color is how much color is in it. A color with low saturation will be more gray,
- and with no saturation at all it is a shade of gray.
- * The value of a color determines how bright it is. A high-value color is vivid, moderate value is dark,
- and no value at all is black.
-
-Just as BYOND uses "#rrggbb" to represent RGB values, a similar format is used for HSV: "#hhhssvv". The hue is three
-hex digits because it ranges from 0 to 0x5FF.
-
- * 0 to 0xFF - red to yellow
- * 0x100 to 0x1FF - yellow to green
- * 0x200 to 0x2FF - green to cyan
- * 0x300 to 0x3FF - cyan to blue
- * 0x400 to 0x4FF - blue to magenta
- * 0x500 to 0x5FF - magenta to red
-
-Knowing this, you can figure out that red is "#000ffff" in HSV format, which is hue 0 (red), saturation 255 (as colorful as possible),
-value 255 (as bright as possible). Green is "#200ffff" and blue is "#400ffff".
-
-More than one HSV color can match the same RGB color.
-
-Here are some procs you can use for color management:
-
-ReadRGB(rgb)
- Takes an RGB string like "#ffaa55" and converts it to a list such as list(255,170,85). If an RGBA format is used
- that includes alpha, the list will have a fourth item for the alpha value.
-hsv(hue, sat, val, apha)
- Counterpart to rgb(), this takes the values you input and converts them to a string in "#hhhssvv" or "#hhhssvvaa"
- format. Alpha is not included in the result if null.
-ReadHSV(rgb)
- Takes an HSV string like "#100FF80" and converts it to a list such as list(256,255,128). If an HSVA format is used that
- includes alpha, the list will have a fourth item for the alpha value.
-RGBtoHSV(rgb)
- Takes an RGB or RGBA string like "#ffaa55" and converts it into an HSV or HSVA color such as "#080aaff".
-HSVtoRGB(hsv)
- Takes an HSV or HSVA string like "#080aaff" and converts it into an RGB or RGBA color such as "#ff55aa".
-BlendRGB(rgb1, rgb2, amount)
- Blends between two RGB or RGBA colors using regular RGB blending. If amount is 0, the first color is the result;
- if 1, the second color is the result. 0.5 produces an average of the two. Values outside the 0 to 1 range are allowed as well.
- The returned value is an RGB or RGBA color.
-BlendHSV(hsv1, hsv2, amount)
- Blends between two HSV or HSVA colors using HSV blending, which tends to produce nicer results than regular RGB
- blending because the brightness of the color is left intact. If amount is 0, the first color is the result; if 1,
- the second color is the result. 0.5 produces an average of the two. Values outside the 0 to 1 range are allowed as well.
- The returned value is an HSV or HSVA color.
-BlendRGBasHSV(rgb1, rgb2, amount)
- Like BlendHSV(), but the colors used and the return value are RGB or RGBA colors. The blending is done in HSV form.
-HueToAngle(hue)
- Converts a hue to an angle range of 0 to 360. Angle 0 is red, 120 is green, and 240 is blue.
-AngleToHue(hue)
- Converts an angle to a hue in the valid range.
-RotateHue(hsv, angle)
- Takes an HSV or HSVA value and rotates the hue forward through red, green, and blue by an angle from 0 to 360.
- (Rotating red by 60� produces yellow.) The result is another HSV or HSVA color with the same saturation and value
- as the original, but a different hue.
-GrayScale(rgb)
- Takes an RGB or RGBA color and converts it to grayscale. Returns an RGB or RGBA string.
-ColorTone(rgb, tone)
- Similar to GrayScale(), this proc converts an RGB or RGBA color to a range of black -> tone -> white instead of
- using strict shades of gray. The tone value is an RGB color; any alpha value is ignored.
-*/
-
-/*
-Get Flat Icon DEMO by DarkCampainger
-
-This is a test for the get flat icon proc, modified approprietly for icons and their states.
-Probably not a good idea to run this unless you want to see how the proc works in detail.
-mob
- icon = 'old_or_unused.dmi'
- icon_state = "green"
-
- Login()
- // Testing image underlays
- underlays += image(icon='old_or_unused.dmi',icon_state="red")
- underlays += image(icon='old_or_unused.dmi',icon_state="red", pixel_x = 32)
- underlays += image(icon='old_or_unused.dmi',icon_state="red", pixel_x = -32)
-
- // Testing image overlays
- overlays += image(icon='old_or_unused.dmi',icon_state="green", pixel_x = 32, pixel_y = -32)
- overlays += image(icon='old_or_unused.dmi',icon_state="green", pixel_x = 32, pixel_y = 32)
- overlays += image(icon='old_or_unused.dmi',icon_state="green", pixel_x = -32, pixel_y = -32)
-
- // Testing icon file overlays (defaults to mob's state)
- overlays += '_flat_demoIcons2.dmi'
-
- // Testing icon_state overlays (defaults to mob's icon)
- overlays += "white"
-
- // Testing dynamic icon overlays
- var/icon/I = icon('old_or_unused.dmi', icon_state="aqua")
- I.Shift(NORTH,16,1)
- overlays+=I
-
- // Testing dynamic image overlays
- I=image(icon=I,pixel_x = -32, pixel_y = 32)
- overlays+=I
-
- // Testing object types (and layers)
- overlays+=/obj/effect/overlayTest
-
- loc = locate (10,10,1)
- verb
- Browse_Icon()
- set name = "1. Browse Icon"
- // Give it a name for the cache
- var/iconName = "[ckey(src.name)]_flattened.dmi"
- // Send the icon to src's local cache
- src<