diff --git a/aurorastation.dme b/aurorastation.dme
index e8326169285..d38d5971b4e 100644
--- a/aurorastation.dme
+++ b/aurorastation.dme
@@ -1731,6 +1731,7 @@
#include "code\modules\atmospherics\datum_pipeline.dm"
#include "code\modules\atmospherics\he_pipes.dm"
#include "code\modules\atmospherics\pipes.dm"
+#include "code\modules\atmospherics\vent_passive.dm"
#include "code\modules\atmospherics\components\portables_connector.dm"
#include "code\modules\atmospherics\components\tvalve.dm"
#include "code\modules\atmospherics\components\valve.dm"
diff --git a/code/__DEFINES/pipes.dm b/code/__DEFINES/pipes.dm
index 2ff6e02caf7..02a3c30cf54 100644
--- a/code/__DEFINES/pipes.dm
+++ b/code/__DEFINES/pipes.dm
@@ -74,3 +74,5 @@
#define PIPE_CONNECTOR_AUX 63
#define PIPE_AUX_UVENT 64
+
+#define PIPE_PVENT 65
diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm
index 5da8708081a..a6e2fea6acb 100644
--- a/code/game/machinery/pipe/construction.dm
+++ b/code/game/machinery/pipe/construction.dm
@@ -168,6 +168,8 @@
src.pipe_type = PIPE_OMNI_MIXER
else if(istype(make_from, /obj/machinery/atmospherics/omni/filter))
src.pipe_type = PIPE_OMNI_FILTER
+ else if(istype(make_from, /obj/machinery/atmospherics/pipe/vent_passive))
+ src.pipe_type = PIPE_PVENT
///// Z-Level stuff
else if(istype(make_from, /obj/machinery/atmospherics/pipe/zpipe/up/supply))
src.pipe_type = PIPE_SUPPLY_UP
@@ -306,7 +308,8 @@
"auxiliary gas pump",
"fuel connector",
"auxiliary connector",
- "auxiliary unary vent"
+ "auxiliary unary vent",
+ "passive vent"
)
name = nlist[pipe_type+1] + " fitting"
var/list/islist = list(
@@ -378,7 +381,8 @@
"pump",
"connector",
"connector",
- "uvent"
+ "uvent",
+ "pvent"
)
icon_state = islist[pipe_type + 1]
@@ -449,7 +453,7 @@
return dir|flip
if(PIPE_SIMPLE_BENT, PIPE_HE_BENT, PIPE_SUPPLY_BENT, PIPE_SCRUBBERS_BENT, PIPE_FUEL_BENT, PIPE_AUX_BENT)
return dir //dir|acw
- if(PIPE_CONNECTOR,PIPE_CONNECTOR_FUEL,PIPE_CONNECTOR_AUX,PIPE_UVENT,PIPE_AUX_UVENT,PIPE_SCRUBBER,PIPE_HEAT_EXCHANGE)
+ if(PIPE_CONNECTOR,PIPE_CONNECTOR_FUEL,PIPE_CONNECTOR_AUX,PIPE_UVENT,PIPE_AUX_UVENT,PIPE_SCRUBBER,PIPE_HEAT_EXCHANGE,PIPE_PVENT)
return dir
if(PIPE_MANIFOLD4W, PIPE_SUPPLY_MANIFOLD4W, PIPE_SCRUBBERS_MANIFOLD4W, PIPE_FUEL_MANIFOLD4W, PIPE_AUX_MANIFOLD4W, PIPE_OMNI_MIXER, PIPE_OMNI_FILTER)
return dir|flip|cw|acw
@@ -1075,6 +1079,20 @@
V.node2.atmos_init()
V.node2.build_network()
+ if(PIPE_PVENT) //passive vent
+ var/obj/machinery/atmospherics/pipe/vent_passive/V = new (src.loc)
+ V.set_dir(dir)
+ V.initialize_directions = pipe_dir
+ if(pipename)
+ V.name = pipename
+ var/turf/T = V.loc
+ V.level = !T.is_plating() ? 2 : 1
+ V.build_network()
+ V.atmos_init()
+ if (V.node1)
+ V.node1.atmos_init()
+ V.node1.build_network()
+
if(PIPE_PUMP) //gas pump
var/obj/machinery/atmospherics/binary/pump/P = new(src.loc)
P.set_dir(dir)
diff --git a/code/game/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm
index fcbae191325..5056e8f4c68 100644
--- a/code/game/machinery/pipe/pipe_dispenser.dm
+++ b/code/game/machinery/pipe/pipe_dispenser.dm
@@ -70,6 +70,7 @@
Auxiliary Connector
Unary Vent
Auxiliary Unary Vent
+ Passive Vent
Gas Pump
Fuel Gas Pump
Auxiliary Gas Pump
diff --git a/code/modules/atmospherics/components/unary/unary_base.dm b/code/modules/atmospherics/components/unary/unary_base.dm
index 7f24679fd40..39ab9d0bc2d 100644
--- a/code/modules/atmospherics/components/unary/unary_base.dm
+++ b/code/modules/atmospherics/components/unary/unary_base.dm
@@ -92,15 +92,11 @@
return null
-/obj/machinery/atmospherics/unary/proc/is_welded()
+/obj/machinery/atmospherics/proc/is_welded()
return FALSE
/obj/machinery/atmospherics/unary/vent_pump/is_welded()
- if (welded > 0)
- return TRUE
- return FALSE
+ return welded
/obj/machinery/atmospherics/unary/vent_scrubber/is_welded()
- if (welded > 0)
- return TRUE
- return FALSE
+ return welded
diff --git a/code/modules/atmospherics/datum_pipeline.dm b/code/modules/atmospherics/datum_pipeline.dm
index 8375d58f3d2..d284eab01a6 100644
--- a/code/modules/atmospherics/datum_pipeline.dm
+++ b/code/modules/atmospherics/datum_pipeline.dm
@@ -115,24 +115,28 @@
return network
/datum/pipeline/proc/mingle_with_turf(turf/simulated/target, mingle_volume)
+ if(!isturf(target))
+ return
+
var/datum/gas_mixture/air_sample = air.remove_ratio(mingle_volume/air.volume)
air_sample.volume = mingle_volume
- if(istype(target) && target.zone)
+ if(target.zone)
//Have to consider preservation of group statuses
var/datum/gas_mixture/turf_copy = new
+ var/datum/gas_mixture/turf_original = 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
+ turf_original.copy_from(turf_copy)
equalize_gases(list(air_sample, turf_copy))
air.merge(air_sample)
- turf_copy.subtract(target.zone.air)
-
+ target.zone.air.remove(turf_original.total_moles)
target.zone.air.merge(turf_copy)
- else if(target)
+ else
var/datum/gas_mixture/turf_air = target.return_air()
equalize_gases(list(air_sample, turf_air))
diff --git a/code/modules/atmospherics/vent_passive.dm b/code/modules/atmospherics/vent_passive.dm
new file mode 100644
index 00000000000..72e75775b7c
--- /dev/null
+++ b/code/modules/atmospherics/vent_passive.dm
@@ -0,0 +1,178 @@
+/obj/machinery/atmospherics/pipe/vent_passive
+ name = "passive vent"
+ desc = ""
+ icon = 'icons/atmos/vent_passive.dmi'
+ icon_state = "map_vent"
+
+ connect_types = CONNECT_TYPE_REGULAR|CONNECT_TYPE_SUPPLY|CONNECT_TYPE_SCRUBBER|CONNECT_TYPE_AUX|CONNECT_TYPE_FUEL //connects to all pipes except HE
+
+ level = 1
+
+ volume = 250
+
+ dir = SOUTH
+ initialize_directions = SOUTH
+
+ var/obj/machinery/atmospherics/node
+ var/welded = FALSE
+
+/obj/machinery/atmospherics/pipe/vent_passive/Initialize()
+ initialize_directions = dir
+ . = ..()
+
+/obj/machinery/atmospherics/pipe/vent_passive/hide(var/i)
+ if(istype(loc, /turf/simulated))
+ set_invisibility(i ? 101 : 0)
+ queue_icon_update()
+
+/obj/machinery/atmospherics/pipe/vent_passive/mechanics_hints(mob/user, distance, is_adjacent)
+ . = ..()
+ . += "This passively outputs the contents of the attached pipe out into the atmosphere."
+
+/obj/machinery/atmospherics/pipe/vent_passive/feedback_hints(mob/user, distance, is_adjacent)
+ . = list()
+ if(welded)
+ . += "It seems welded shut."
+
+/obj/machinery/atmospherics/pipe/vent_passive/update_icon(safety = 0)
+
+ var/vent_icon = ""
+
+ if(welded)
+ vent_icon += "weld"
+ else
+ vent_icon += "vent"
+
+ icon_state = vent_icon
+
+ update_underlays()
+
+/obj/machinery/atmospherics/pipe/vent_passive/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)
+ underlays += "frame"
+
+/obj/machinery/atmospherics/pipe/vent_passive/process(seconds_per_tick)
+ if(!parent)
+ ..()
+ else
+ parent.mingle_with_turf(loc, volume)
+
+/obj/machinery/atmospherics/pipe/vent_passive/Destroy()
+ if(node)
+ node.disconnect(src)
+
+ node = null
+
+ return ..()
+
+/obj/machinery/atmospherics/pipe/vent_passive/pipeline_expansion()
+ return list(node)
+
+/obj/machinery/atmospherics/pipe/vent_passive/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
+
+ atmos_initialised = TRUE
+ SSicon_update.add_to_queue(src)
+
+/obj/machinery/atmospherics/pipe/vent_passive/disconnect(obj/machinery/atmospherics/reference)
+ if(reference == node)
+ if(istype(node, /obj/machinery/atmospherics/pipe))
+ qdel(parent)
+ node = null
+
+ update_icon()
+
+ return null
+
+/obj/machinery/atmospherics/pipe/vent_passive/attackby(obj/item/attacking_item, mob/user)
+
+ if(attacking_item.tool_behaviour == TOOL_WELDER)
+ var/obj/item/weldingtool/WT = attacking_item
+ if (!WT.welding)
+ to_chat(user, SPAN_DANGER("\The [WT] must be turned on!"))
+ else if (WT.use(0,user))
+ to_chat(user, SPAN_NOTICE("Now welding the vent."))
+ if(attacking_item.use_tool(src, user, 30, volume = 50))
+ if(!src || !WT.isOn())
+ return TRUE
+ welded = !welded
+ update_icon()
+ playsound(src, 'sound/items/welder_pry.ogg', 50, 1)
+ user.visible_message(SPAN_NOTICE("\The [user] [welded ? "welds \the [src] shut" : "unwelds \the [src]"]."), \
+ SPAN_NOTICE("You [welded ? "weld \the [src] shut" : "unweld \the [src]"]."), \
+ "You hear welding.")
+ else
+ to_chat(user, SPAN_NOTICE("You fail to complete the welding."))
+ else
+ to_chat(user, SPAN_WARNING("You need more welding fuel to complete this task."))
+ return TRUE
+
+
+ else if(istype(attacking_item, /obj/item/melee/arm_blade))
+ if(!welded)
+ to_chat(user, SPAN_WARNING("\The [attacking_item] can only be used to tear open welded air vents!"))
+ return TRUE
+ user.visible_message(SPAN_WARNING("\The [user] starts using \the [attacking_item] to hack open \the [src]!"), SPAN_NOTICE("You start hacking open \the [src] with \the [attacking_item]..."))
+ user.do_attack_animation(src, attacking_item)
+ playsound(loc, 'sound/weapons/smash.ogg', 60, TRUE)
+ var/cut_amount = 3
+ for(var/i = 0; i <= cut_amount; i++)
+ if(!attacking_item || !do_after(user, 30, src))
+ return TRUE
+ user.do_attack_animation(src, attacking_item)
+ user.visible_message(SPAN_WARNING("\The [user] smashes \the [attacking_item] into \the [src]!"), SPAN_NOTICE("You smash \the [attacking_item] into \the [src]."))
+ playsound(loc, 'sound/weapons/smash.ogg', 60, TRUE)
+ if(i == cut_amount)
+ welded = FALSE
+ spark(get_turf(src), 3, GLOB.alldirs)
+ playsound(loc, 'sound/items/welder_pry.ogg', 50, TRUE)
+ update_icon()
+
+ else if(attacking_item.tool_behaviour == TOOL_WRENCH)
+ var/turf/T = src.loc
+
+ if(level==1 && isturf(T) && !T.is_plating())
+ to_chat(user, SPAN_WARNING("You must remove the plating first."))
+
+ else if(loc)
+ 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()) > PRESSURE_EXERTED)
+ to_chat(user, SPAN_WARNING("You cannot unwrench \the [src], it is too exerted due to internal pressure."))
+ add_fingerprint(user)
+
+ else
+ to_chat(user, SPAN_NOTICE("You begin to unfasten \the [src]..."))
+
+ if(attacking_item.use_tool(src, user, istype(attacking_item, /obj/item/pipewrench) ? 80 : 40, volume = 50))
+ user.visible_message(SPAN_NOTICE("\The [user] unfastens \the [src]."), \
+ SPAN_NOTICE("You have unfastened \the [src]."), \
+ "You hear a ratchet.")
+ new /obj/item/pipe(loc, make_from=src)
+ qdel(src)
+
+ else if(istype(attacking_item, /obj/item/analyzer) && in_range(user, src))
+ var/obj/item/analyzer/A = attacking_item
+ A.analyze_gases(src, user)
+ return TRUE
+
+ return ..()
+
+/obj/machinery/atmospherics/pipe/vent_passive/is_welded()
+ return welded
diff --git a/html/changelogs/GeneralCamo - Passive Vent.yml b/html/changelogs/GeneralCamo - Passive Vent.yml
new file mode 100644
index 00000000000..4c46f9b01e4
--- /dev/null
+++ b/html/changelogs/GeneralCamo - Passive Vent.yml
@@ -0,0 +1,59 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# - (fixes bugs)
+# wip
+# - (work in progress)
+# qol
+# - (quality of life)
+# soundadd
+# - (adds a sound)
+# sounddel
+# - (removes a sound)
+# rscadd
+# - (adds a feature)
+# rscdel
+# - (removes a feature)
+# imageadd
+# - (adds an image or sprite)
+# imagedel
+# - (removes an image or sprite)
+# spellcheck
+# - (fixes spelling or grammar)
+# experiment
+# - (experimental change)
+# balance
+# - (balance changes)
+# code_imp
+# - (misc internal code change)
+# refactor
+# - (refactors code)
+# config
+# - (makes a change to the config files)
+# admin
+# - (makes changes to administrator tools)
+# server
+# - (miscellaneous changes to server)
+#################################
+
+# Your name.
+author: GeneralCamo
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
+# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Added passive vents, that passively interact with the air outside of them."
+ - bugfix: "Vent and scrubber items will now use the correct icons."
diff --git a/icons/atmos/vent_passive.dmi b/icons/atmos/vent_passive.dmi
new file mode 100644
index 00000000000..83acbff7544
Binary files /dev/null and b/icons/atmos/vent_passive.dmi differ
diff --git a/icons/obj/pipe-item.dmi b/icons/obj/pipe-item.dmi
index 00984305fc4..4ce6b034d5c 100644
Binary files a/icons/obj/pipe-item.dmi and b/icons/obj/pipe-item.dmi differ