diff --git a/auxmos.dll b/auxmos.dll
index eb7e3b71fc..4e0687fa2b 100644
Binary files a/auxmos.dll and b/auxmos.dll differ
diff --git a/auxmos.pdb b/auxmos.pdb
index 5d005d3689..da06980179 100644
Binary files a/auxmos.pdb and b/auxmos.pdb differ
diff --git a/code/__DEFINES/reactions.dm b/code/__DEFINES/reactions.dm
index fad53e4830..d1329060eb 100644
--- a/code/__DEFINES/reactions.dm
+++ b/code/__DEFINES/reactions.dm
@@ -42,3 +42,5 @@
#define FUSION_RAD_MAX 2000
#define FUSION_RAD_COEFFICIENT (-1000)
#define FUSION_INSTABILITY_ENDOTHERMALITY 2
+// Snowflake fire product types
+#define FIRE_PRODUCT_PLASMA 0
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index 0c4a886b9f..c8791eabb8 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -179,6 +179,8 @@
#define TRAIT_DWARF "dwarf"
#define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance"
#define TRAIT_AGEUSIA "ageusia"
+#define TRAIT_ANOSMIA "anosmia"
+#define TRAIT_GOODSMELL "super_smeller"
#define TRAIT_HEAVY_SLEEPER "heavy_sleeper"
#define TRAIT_NIGHT_VISION "night_vision"
#define TRAIT_LIGHT_STEP "light_step"
diff --git a/code/datums/mutations/actions.dm b/code/datums/mutations/actions.dm
index 8f7d67abb8..dad5237aa5 100644
--- a/code/datums/mutations/actions.dm
+++ b/code/datums/mutations/actions.dm
@@ -205,6 +205,16 @@
synchronizer_coeff = 1
var/reek = 200
+/datum/mutation/human/olfaction/on_acquiring(mob/living/carbon/human/owner)
+ if(..() || HAS_TRAIT(owner, TRAIT_ANOSMIA))
+ return TRUE
+ ADD_TRAIT(owner, TRAIT_GOODSMELL, GENETIC_MUTATION)
+
+/datum/mutation/human/olfaction/on_losing(mob/living/carbon/human/owner)
+ if(..())
+ return
+ REMOVE_TRAIT(owner, TRAIT_GOODSMELL, GENETIC_MUTATION)
+
/datum/mutation/human/olfaction/modify()
if(power)
var/obj/effect/proc_holder/spell/targeted/olfaction/S = power
diff --git a/code/datums/traits/negative.dm b/code/datums/traits/negative.dm
index 10f66fce0c..8958226ff4 100644
--- a/code/datums/traits/negative.dm
+++ b/code/datums/traits/negative.dm
@@ -416,3 +416,12 @@ GLOBAL_LIST_EMPTY(family_heirlooms)
. = ..()
var/mob/living/carbon/human/H = quirk_holder
H?.cure_trauma_type(/datum/brain_trauma/severe/monophobia, TRAUMA_RESILIENCE_ABSOLUTE)
+
+/datum/quirk/no_smell
+ name = "Anosmia"
+ desc = "You can't smell anything! You won't be able to detect certain colorless gases."
+ value = -1
+ mob_trait = TRAIT_ANOSMIA
+ gain_text = "You can't smell anything!"
+ lose_text = "You can smell again!"
+ medical_record_text = "Patient suffers from anosmia and is incapable of smelling gases or particulates."
diff --git a/code/modules/atmospherics/auxgm/gas_types.dm b/code/modules/atmospherics/auxgm/gas_types.dm
index 4e42b3392a..f037e1bfab 100644
--- a/code/modules/atmospherics/auxgm/gas_types.dm
+++ b/code/modules/atmospherics/auxgm/gas_types.dm
@@ -7,6 +7,9 @@
heat_penalty = 1
transmit_modifier = 1.5
+/datum/gas/oxygen/generate_TLV()
+ return new/datum/tlv(16, 19, 40, 50)
+
/datum/gas/nitrogen
id = GAS_N2
specific_heat = 20
@@ -48,6 +51,9 @@
fusion_power = 3
enthalpy = -393500
+/datum/gas/carbon_dioxide/generate_TLV()
+ return new/datum/tlv(-1, -1, 5, 10)
+
/datum/gas/plasma
id = GAS_PLASMA
specific_heat = 200
@@ -60,19 +66,16 @@
powermix = 1
fire_burn_rate = OXYGEN_BURN_RATE_BASE // named when plasma fires were the only fires, surely
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
- fire_products = "plasma_fire"
+ fire_products = FIRE_PRODUCT_PLASMA
enthalpy = FIRE_PLASMA_ENERGY_RELEASED // 3000000, 3 megajoules, 3000 kj
-/datum/gas/plasma/New()
- if(world.system_type == UNIX)
- fire_temperature = null
-
/datum/gas/water_vapor
id = GAS_H2O
specific_heat = 40
name = "Water Vapor"
gas_overlay = "water_vapor"
moles_visible = MOLES_GAS_VISIBLE
+ flags = GAS_FLAG_DANGEROUS
fusion_power = 8
heat_penalty = 8
enthalpy = -241800 // FIRE_HYDROGEN_ENERGY_RELEASED is actually what this was supposed to be
@@ -92,10 +95,30 @@
enthalpy = 81600
heat_resistance = 6
+/datum/gas/tritium
+ id = GAS_TRITIUM
+ specific_heat = 10
+ name = "Tritium"
+ gas_overlay = "tritium"
+ moles_visible = MOLES_GAS_VISIBLE
+ flags = GAS_FLAG_DANGEROUS
+ fusion_power = 1
+ powermix = 1
+ heat_penalty = 10
+ transmit_modifier = 30
+ fire_products = list(GAS_H2O = 1)
+ enthalpy = 300000
+ fire_burn_rate = 2
+ fire_radiation_released = 50 // arbitrary number, basically 60 moles of trit burning will just barely start to harm you
+ fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
+
/datum/gas/nitric_oxide
id = GAS_NITRIC
specific_heat = 20
name = "Nitric oxide"
+ flags = GAS_FLAG_DANGEROUS
+ odor = "sharp sweetness"
+ odor_strength = 1
fusion_power = 15
enthalpy = 91290
heat_resistance = 2
@@ -104,7 +127,7 @@
id = GAS_NITRYL
specific_heat = 20
name = "Nitrogen dioxide"
- gas_overlay = "nitryl"
+ color = "#963"
moles_visible = MOLES_GAS_VISIBLE
flags = GAS_FLAG_DANGEROUS
fusion_power = 15
@@ -124,6 +147,8 @@
specific_heat = 10
name = "Hydrogen"
flags = GAS_FLAG_DANGEROUS
+ moles_visible = MOLES_GAS_VISIBLE
+ color = "#ffe"
fusion_power = 0
powermix = 1
heat_penalty = 3
@@ -132,27 +157,6 @@
fire_burn_rate = 2
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
-/datum/gas/tritium
- id = GAS_TRITIUM
- specific_heat = 10
- name = "Tritium"
- gas_overlay = "tritium"
- moles_visible = MOLES_GAS_VISIBLE
- flags = GAS_FLAG_DANGEROUS
- fusion_power = 1
- powermix = 1
- heat_penalty = 10
- transmit_modifier = 30
- fire_products = list(GAS_H2O = 1)
- enthalpy = 300000
- fire_burn_rate = 2
- fire_radiation_released = 50 // arbitrary number, basically 60 moles of trit burning will just barely start to harm you
- fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
-
-/datum/gas/tritium/New()
- if(world.system_type == UNIX)
- fire_temperature = null
-
/datum/gas/bz
id = GAS_BZ
specific_heat = 20
@@ -168,6 +172,8 @@
/datum/gas/stimulum
id = GAS_STIMULUM
specific_heat = 5
+ odor = "the color blue" // fast
+ odor_strength = 10
name = "Stimulum"
fusion_power = 7
@@ -184,10 +190,15 @@
transmit_modifier = -5
heat_resistance = 3
+/datum/gas/pluoxium/generate_TLV()
+ return new/datum/tlv(-1, -1, 5, 6)
+
/datum/gas/miasma
id = GAS_MIASMA
specific_heat = 20
fusion_power = 50
+ flags = GAS_FLAG_DANGEROUS
+ // snowflaked odor
name = "Miasma"
gas_overlay = "miasma"
moles_visible = MOLES_GAS_VISIBLE * 60
@@ -196,6 +207,9 @@
id = GAS_METHANE
specific_heat = 30
name = "Methane"
+ odor = "natural gas"
+ odor_strength = 2
+ flags = GAS_FLAG_DANGEROUS
powerloss_inhibition = 1
heat_resistance = 3
breath_results = GAS_METHYL_BROMIDE
@@ -234,14 +248,18 @@
fire_products = list(GAS_CO2 = 1, GAS_H2O = 1.5, GAS_BROMINE = 0.5)
enthalpy = -35400
fire_burn_rate = 4 / 7 // oh no
- fire_temperature = 808 // its autoignition, it apparently doesn't spark readily, so i don't put it lower
+ fire_temperature = 808 // its autoignition; it apparently doesn't spark readily, so i don't put it lower
/datum/gas/bromine
id = GAS_BROMINE
specific_heat = 76
name = "Bromine"
- flags = GAS_FLAG_DANGEROUS
+ flags = GAS_FLAG_DANGEROUS | GAS_FLAG_CHEMICAL
group = GAS_GROUP_CHEMICALS
+ color = "#6e1f00"
+ moles_visible = MOLES_GAS_VISIBLE
+ odor = "bromine" // it's a very recognizable smell
+ odor_strength = 0.1
enthalpy = 193 // yeah it's small but it's good to include it
breath_reagent = /datum/reagent/bromine
@@ -249,7 +267,9 @@
id = GAS_AMMONIA
specific_heat = 35
name = "Ammonia"
- flags = GAS_FLAG_DANGEROUS
+ odor = "ammonia"
+ odor_strength = 0.01
+ flags = GAS_FLAG_DANGEROUS | GAS_FLAG_CHEMICAL
group = GAS_GROUP_CHEMICALS
enthalpy = -45900
breath_reagent = /datum/reagent/ammonia
diff --git a/code/modules/atmospherics/gasmixtures/auxgm.dm b/code/modules/atmospherics/gasmixtures/auxgm.dm
index 2e5dd716ed..d3de583f04 100644
--- a/code/modules/atmospherics/gasmixtures/auxgm.dm
+++ b/code/modules/atmospherics/gasmixtures/auxgm.dm
@@ -25,6 +25,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
var/list/ids = list()
var/list/typepaths = list()
var/list/fusion_powers = list()
+ var/list/TLV = list()
var/list/breathing_classes = list()
var/list/breath_results = list()
var/list/breath_reagents = list()
@@ -39,13 +40,18 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
var/list/supermatter = list()
var/list/groups_by_gas = list()
var/list/groups = list()
+ var/list/TLVs = list()
+ var/list/odors = list()
+ var/list/odor_strengths = list()
/datum/gas
var/id = ""
var/specific_heat = 0
var/name = ""
- var/gas_overlay = "" //icon_state in icons/effects/atmospherics.dmi
- var/color = "#ffff"
+ var/gas_overlay = "generic" //icon_state in icons/effects/atmospherics.dmi
+ var/color = "#ffff" // Tints the overlay by this color. Use instead of gas_overlay, usually (but not necessarily).
+ var/odor = null // Odor string. Null means none; if not null, anyone who breathes the gas will smell it.
+ var/odor_strength = INFINITY // How strong the odor is; minimal partial pressure to smell, so lower = more.
var/moles_visible = null
var/flags = NONE //currently used by canisters
var/group = null // groups for scrubber/filter listing
@@ -68,6 +74,12 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
var/heat_resistance = 0 // makes the crystal more resistant against heat damage.
var/powerloss_inhibition = 0 // Reduces how much power the supermatter loses each tick
+/datum/gas/proc/generate_TLV()
+ if(flags & GAS_FLAG_DANGEROUS)
+ return new/datum/tlv/dangerous
+ else
+ return new/datum/tlv(-1, -1, 1000, 1000)
+
/datum/gas/proc/breath(partial_pressure, light_threshold, heavy_threshold, moles, mob/living/carbon/C, obj/item/organ/lungs/lungs)
// This is only called on gases with the GAS_FLAG_BREATH_PROC flag. When possible, do NOT use this--
// greatly prefer just adding a reagent. This is mostly around for legacy reasons.
@@ -79,11 +91,15 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
datums[g] = gas
specific_heats[g] = gas.specific_heat
names[g] = gas.name
+ TLVs[g] = gas.generate_TLV()
if(gas.moles_visible)
visibility[g] = gas.moles_visible
overlays[g] = new /list(FACTOR_GAS_VISIBLE_MAX)
for(var/i in 1 to FACTOR_GAS_VISIBLE_MAX)
- overlays[g][i] = new /obj/effect/overlay/gas(gas.gas_overlay, i * 255 / FACTOR_GAS_VISIBLE_MAX)
+ var/obj/effect/overlay/gas/overlay = new(gas.gas_overlay)
+ overlay.color = gas.color
+ overlay.alpha = i * 255 / FACTOR_GAS_VISIBLE_MAX
+ overlays[g][i] = overlay
else
visibility[g] = 0
overlays[g] = 0
@@ -114,8 +130,11 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
if(gas.group)
if(!(gas.group in groups))
groups[gas.group] = list()
- groups[gas.group] += gas
+ groups[gas.group] += g
groups_by_gas[g] = gas.group
+ if(gas.odor)
+ odor_strengths[g] = gas.odor_strength
+ odors[g] = gas.odor
add_supermatter_properties(gas)
_auxtools_register_gas(gas)
if(done_initializing)
@@ -145,6 +164,17 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
done_initializing = TRUE
finalize_gas_refs()
+/datum/auxgm/proc/get_by_flag(flag)
+ var/static/list/gases_by_flag
+ if(!gases_by_flag)
+ gases_by_flag = list()
+ if(!(flag in gases_by_flag))
+ gases_by_flag += flag
+ gases_by_flag[flag] = list()
+ for(var/g in flags)
+ if(flags[g] & flag)
+ gases_by_flag[flag] += g
+ return gases_by_flag[flag]
GLOBAL_DATUM_INIT(gas_data, /datum/auxgm, new)
@@ -156,7 +186,6 @@ GLOBAL_DATUM_INIT(gas_data, /datum/auxgm, new)
appearance_flags = TILE_BOUND
vis_flags = NONE
-/obj/effect/overlay/gas/New(state, alph)
+/obj/effect/overlay/gas/New(state)
. = ..()
icon_state = state
- alpha = alph
diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
index b670baaae7..56820d2836 100644
--- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm
+++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm
@@ -135,6 +135,7 @@ we use a hook instead
/datum/gas_mixture/proc/set_temperature(new_temp)
/datum/gas_mixture/proc/set_volume(new_volume)
/datum/gas_mixture/proc/get_moles(gas_type)
+/datum/gas_mixture/proc/get_by_flag(flag)
/datum/gas_mixture/proc/set_moles(gas_type, moles)
// VV WRAPPERS - EXTOOLS HOOKED PROCS DO NOT TAKE ARGUMENTS FROM CALL() FOR SOME REASON.
@@ -152,13 +153,20 @@ we use a hook instead
/datum/gas_mixture/proc/scrub_into(datum/gas_mixture/target, ratio, list/gases)
/datum/gas_mixture/proc/mark_immutable()
/datum/gas_mixture/proc/get_gases()
+/datum/gas_mixture/proc/add(amt)
+/datum/gas_mixture/proc/subtract(amt)
/datum/gas_mixture/proc/multiply(factor)
+/datum/gas_mixture/proc/divide(factor)
/datum/gas_mixture/proc/get_last_share()
/datum/gas_mixture/proc/clear()
/datum/gas_mixture/proc/adjust_moles(gas_type, amt = 0)
set_moles(gas_type, clamp(get_moles(gas_type) + amt,0,INFINITY))
+/datum/gas_mixture/proc/adjust_moles_temp(gas_type, amt, temperature)
+
+/datum/gas_mixture/proc/adjust_multi()
+
/datum/gas_mixture/proc/return_volume() //liters
/datum/gas_mixture/proc/thermal_energy() //joules
@@ -175,6 +183,10 @@ we use a hook instead
//Removes amount of gas from the gas_mixture
//Returns: gas_mixture with the gases removed
+/datum/gas_mixture/proc/remove_by_flag(flag, amount)
+ //Removes amount of gas from the gas mixture by flag
+ //Returns: gas_mixture with gases that match the flag removed
+
/datum/gas_mixture/proc/transfer_to(datum/gas_mixture/target, amount)
//Transfers amount of gas to target. Equivalent to target.merge(remove(amount)) but faster.
@@ -235,6 +247,14 @@ we use a hook instead
//Makes every gas in the given list have the same pressure, temperature and gas proportions.
//Returns: null
+/datum/gas_mixture/proc/__remove_by_flag()
+
+/datum/gas_mixture/remove_by_flag(flag, amount)
+ var/datum/gas_mixture/removed = new type
+ __remove_by_flag(removed, flag, amount)
+
+ return removed
+
/datum/gas_mixture/proc/__remove()
/datum/gas_mixture/remove(amount)
var/datum/gas_mixture/removed = new type
diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm
index 85593cf0e0..122d30f33e 100644
--- a/code/modules/atmospherics/gasmixtures/reactions.dm
+++ b/code/modules/atmospherics/gasmixtures/reactions.dm
@@ -117,7 +117,6 @@
id = "tritfire"
/datum/gas_reaction/tritfire/init_reqs()
- exclude = world.system_type == MS_WINDOWS // temporary stopgap until generic fires work on linux
min_requirements = list(
"TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST,
GAS_TRITIUM = MINIMUM_MOLE_COUNT,
@@ -199,7 +198,6 @@
id = "plasmafire"
/datum/gas_reaction/plasmafire/init_reqs()
- exclude = world.system_type == MS_WINDOWS // temporary stopgap until generic fires work on linux
min_requirements = list(
"TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST,
GAS_PLASMA = MINIMUM_MOLE_COUNT,
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index d6e48daff0..66b8277273 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -90,7 +90,6 @@
var/frequency = FREQ_ATMOS_CONTROL
var/alarm_frequency = FREQ_ATMOS_ALARMS
var/datum/radio_frequency/radio_connection
-
var/list/TLV = list( // Breathable air.
"pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa
"temperature" = new/datum/tlv(T0C, T0C+10, T0C+40, T0C+66),
@@ -108,9 +107,17 @@
GAS_NITRYL = new/datum/tlv/dangerous,
GAS_PLUOXIUM = new/datum/tlv(-1, -1, 5, 6), // Unlike oxygen, pluoxium does not fuel plasma/tritium fires
GAS_METHANE = new/datum/tlv(-1, -1, 3, 6),
- GAS_METHYL_BROMIDE = new/datum/tlv/dangerous
+ GAS_METHYL_BROMIDE = new/datum/tlv/dangerous,
+ GAS_AMMONIA = new/datum/tlv/dangerous,
+ GAS_BROMINE = new/datum/tlv/dangerous,
+
)
+/obj/machinery/airalarm/proc/regenerate_TLV()
+ var/list/TLVs = GLOB.gas_data.TLVs
+ for(var/g in TLVs)
+ TLV[g] = TLVs[g]
+
/obj/machinery/airalarm/server // No checks here.
TLV = list(
"pressure" = new/datum/tlv/no_checks,
@@ -132,6 +139,11 @@
GAS_METHYL_BROMIDE = new/datum/tlv/no_checks
)
+/obj/machinery/airalarm/server/regenerate_TLV()
+ var/list/TLVs = GLOB.gas_data.TLVs
+ for(var/g in TLVs)
+ TLV[g] = new/datum/tlv/no_checks
+
/obj/machinery/airalarm/kitchen_cold_room // Copypasta: to check temperatures.
TLV = list(
"pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE* 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa
@@ -203,6 +215,8 @@
/obj/machinery/airalarm/Initialize(mapload, ndir, nbuild)
. = ..()
+ regenerate_TLV()
+ RegisterSignal(SSdcs,COMSIG_GLOB_NEW_GAS,.proc/regenerate_TLV)
wires = new /datum/wires/airalarm(src)
if(ndir)
@@ -535,7 +549,7 @@
for(var/device_id in A.air_scrub_names)
send_signal(device_id, list(
"power" = 1,
- "set_filters" = list(GAS_CO2, GAS_METHANE, GAS_METHYL_BROMIDE, GAS_MIASMA, GAS_GROUP_CHEMICALS),
+ "set_filters" = list(GAS_CO2, GAS_MIASMA, GAS_GROUP_CHEMICALS),
"scrubbing" = 1,
"widenet" = 0,
))
@@ -546,26 +560,11 @@
"set_external_pressure" = ONE_ATMOSPHERE
))
if(AALARM_MODE_CONTAMINATED)
+ var/list/all_gases = GLOB.gas_data.get_by_flag(GAS_FLAG_DANGEROUS)
for(var/device_id in A.air_scrub_names)
send_signal(device_id, list(
"power" = 1,
- "set_filters" = list(
- GAS_CO2,
- GAS_MIASMA,
- GAS_PLASMA,
- GAS_H2O,
- GAS_HYDROGEN,
- GAS_HYPERNOB,
- GAS_NITROUS,
- GAS_NITRYL,
- GAS_TRITIUM,
- GAS_BZ,
- GAS_STIMULUM,
- GAS_PLUOXIUM,
- GAS_METHANE,
- GAS_METHYL_BROMIDE,
- GAS_GROUP_CHEMICALS
- ),
+ "set_filters" = all_gases,
"scrubbing" = 1,
"widenet" = 1,
))
@@ -599,7 +598,7 @@
for(var/device_id in A.air_scrub_names)
send_signal(device_id, list(
"power" = 1,
- "set_filters" = list(GAS_CO2, GAS_MIASMA),
+ "set_filters" = list(GAS_CO2, GAS_MIASMA, GAS_GROUP_CHEMICALS),
"scrubbing" = 1,
"widenet" = 0,
))
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
index 025435929a..4ced6c0554 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm
@@ -42,7 +42,7 @@
clean_filter_types = list()
for(var/id in filter_types)
if(id in GLOB.gas_data.groups)
- clean_filter_types += GLOB.gas_data.groups[id]
+ clean_filter_types |= GLOB.gas_data.groups[id]
else
clean_filter_types += id
diff --git a/code/modules/mob/living/smell.dm b/code/modules/mob/living/smell.dm
new file mode 100644
index 0000000000..bc82fe5ccb
--- /dev/null
+++ b/code/modules/mob/living/smell.dm
@@ -0,0 +1,62 @@
+#define DEFAULT_SMELL_SENSITIVITY 1
+
+/mob/living
+ var/last_smell_time
+ var/last_smell_text
+
+/mob/living/proc/get_smell_sensitivity()
+ return DEFAULT_SMELL_SENSITIVITY
+
+/mob/living/carbon/get_smell_sensitivity()
+ . = DEFAULT_SMELL_SENSITIVITY
+ var/obj/item/organ/lungs/lungs = getorganslot(ORGAN_SLOT_LUNGS) // don't think about it too hard
+ if(istype(lungs))
+ . = lungs.smell_sensitivity
+ if(HAS_TRAIT(src, TRAIT_ANOSMIA))
+ . *= 0
+ else if(HAS_TRAIT(src, TRAIT_GOODSMELL))
+ . *= 2
+
+/mob/living/proc/smell(datum/gas_mixture/from)
+ if(last_smell_time + 50 > world.time)
+ return FALSE
+ var/smell_sensitivity = get_smell_sensitivity()
+
+ if(smell_sensitivity == 0)
+ return FALSE
+
+ var/pressure = from.return_pressure()
+ var/total_moles = from.total_moles()
+
+ #define PP_MOLES(X) ((X / total_moles) * pressure)
+
+ #define PP(air, gas) PP_MOLES(air.get_moles(gas))
+
+ var/list/odors = GLOB.gas_data.odors
+ var/list/odor_strengths = GLOB.gas_data.odor_strengths
+ var/list/odors_found = list()
+ for(var/gas in from.get_gases())
+ if(!(gas in odors))
+ continue
+ var/pp = PP(from, gas)
+ var/strength = (odor_strengths[gas] / smell_sensitivity)
+ if(pp > 2*strength)
+ odors_found += "[odors[gas]]"
+ else if(pp > strength)
+ odors_found += "a hint of [odors[gas]]"
+ if(!length(odors_found))
+ return FALSE
+ var/text_output = ""
+ if(hallucination > 50 && prob(25))
+ text_output = pick("", "spiders","dreams","nightmares","the future","the past","victory",\
+ "defeat","pain","bliss","chaos","revenge","cold","rotten glass","poison","time","space","death","life","truth","lies","justice","memory",\
+ "regrets","your soul","suffering","magic","music","noise","blood","hunger","the american way")
+ else
+ text_output = english_list(odors_found, "something indescribable")
+ if(text_output != last_smell_text || last_smell_time + 100 < world.time)
+ to_chat(src, "You can smell [text_output].")
+ last_smell_time = world.time
+ last_smell_text = text_output
+
+ #undef PP_MOLES
+ #undef PP
diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm
index 8d009ffb2e..0bb847a573 100644
--- a/code/modules/reagents/chemistry/reagents.dm
+++ b/code/modules/reagents/chemistry/reagents.dm
@@ -273,6 +273,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
G.color = color
G.breath_reagent = src.type
G.group = GAS_GROUP_CHEMICALS
+ G.moles_visible = MOLES_GAS_VISIBLE
return G
/datum/reagent/proc/create_gas()
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index d4d3cf7e7e..abe3aef82d 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -1497,6 +1497,13 @@
myseed.adjust_yield(1)
myseed.adjust_instability(1)
+/datum/reagent/ammonia/reaction_mob(mob/living/M, method=TOUCH, reac_volume, touch_protection)
+ if(method == VAPOR)
+ M.adjustOrganLoss(ORGAN_SLOT_LUNGS, ((100-touch_protection)/100)*reac_volume*REAGENTS_EFFECT_MULTIPLIER * 0.25)
+ if(prob(reac_volume))
+ to_chat(M, "Your lungs hurt!")
+ return ..()
+
/datum/reagent/diethylamine
name = "Diethylamine"
description = "A secondary amine, mildly corrosive."
@@ -1807,6 +1814,10 @@
boiling_point = 332
pH = 7.8
+/datum/reagent/bromine/on_mob_life(mob/living/carbon/C)
+ C.adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.2, 99)
+ ..()
+
/datum/reagent/phenol
name = "Phenol"
description = "An aromatic ring of carbon with a hydroxyl group. A useful precursor to some medicines, but has no healing properties on its own."
diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm
index aad33c4e92..cb2c02fa7c 100644
--- a/code/modules/surgery/organs/lungs.dm
+++ b/code/modules/surgery/organs/lungs.dm
@@ -76,6 +76,8 @@
var/heat_level_3_damage = HEAT_GAS_DAMAGE_LEVEL_3
var/heat_damage_type = BURN
+ var/smell_sensitivity = 1
+
var/crit_stabilizing_reagent = /datum/reagent/medicine/epinephrine
/obj/item/organ/lungs/New()
@@ -245,12 +247,16 @@
else if(alert_category)
H.clear_alert(alert_category)
var/list/breath_reagents = GLOB.gas_data.breath_reagents
+ var/static/datum/reagents/reagents_holder = new
+ reagents_holder.clear_reagents()
+ reagents_holder.chem_temp = breath.return_temperature()
for(var/gas in breath.get_gases())
if(gas in breath_reagents)
var/datum/reagent/R = breath_reagents[gas]
- H.reagents.add_reagent(R, breath.get_moles(gas) * initial(R.molarity))
+ reagents_holder.add_reagent(R, breath.get_moles(gas) * initial(R.molarity))
mole_adjustments[gas] = (gas in mole_adjustments) ? mole_adjustments[gas] - breath.get_moles(gas) : -breath.get_moles(gas)
-
+ reagents_holder.reaction(H, VAPOR, from_gas = 1)
+ H.smell(breath)
for(var/gas in mole_adjustments)
breath.adjust_moles(gas, mole_adjustments[gas])
@@ -523,6 +529,7 @@
safe_breath_min = 13
safe_breath_max = 100
emp_vulnerability = 2
+ smell_sensitivity = 1.5
/obj/item/organ/lungs/cybernetic/tier3
name = "upgraded cybernetic lungs"
@@ -540,6 +547,7 @@
SA_sleep_min = 50
BZ_brain_damage_min = 30
emp_vulnerability = 3
+ smell_sensitivity = 2
cold_level_1_threshold = 200
cold_level_2_threshold = 140
diff --git a/code/modules/vore/eating/living.dm b/code/modules/vore/eating/living.dm
index 1f4950eaa7..99c1236d9c 100644
--- a/code/modules/vore/eating/living.dm
+++ b/code/modules/vore/eating/living.dm
@@ -18,7 +18,7 @@
// Hook for generic creation of stuff on new creatures
//
/hook/living_new/proc/vore_setup(mob/living/M)
- add_verb(M, list(/mob/living/proc/preyloop_refresh, /mob/living/proc/lick, /mob/living/proc/smell, /mob/living/proc/escapeOOC))
+ add_verb(M, list(/mob/living/proc/preyloop_refresh, /mob/living/proc/lick, /mob/living/proc/smell_someone, /mob/living/proc/escapeOOC))
if(M.vore_flags & NO_VORE) //If the mob isn't supposed to have a stomach, let's not give it an insidepanel so it can make one for itself, or a stomach.
return TRUE
@@ -394,7 +394,7 @@
//
// Equally important as the above
//
-/mob/living/proc/smell()
+/mob/living/proc/smell_someone()
set name = "Smell Someone"
set category = "Vore"
set desc = "Smell someone nearby!"
diff --git a/dependencies.sh b/dependencies.sh
index 0a27dd623f..7943782996 100644
--- a/dependencies.sh
+++ b/dependencies.sh
@@ -21,7 +21,7 @@ export SPACEMAN_DMM_VERSION=suite-1.7
export PYTHON_VERSION=3.7.9
# Auxmos git tag
-export AUXMOS_VERSION=v0.3.0
+export AUXMOS_VERSION=v1.1.1
# Extools git tag
export EXTOOLS_VERSION=v0.0.7
diff --git a/icons/effects/atmospherics.dmi b/icons/effects/atmospherics.dmi
index acf48a0bd0..6c2412c04b 100644
Binary files a/icons/effects/atmospherics.dmi and b/icons/effects/atmospherics.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index b148d8324f..e33a3644d6 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2588,6 +2588,7 @@
#include "code\modules\mob\living\login.dm"
#include "code\modules\mob\living\logout.dm"
#include "code\modules\mob\living\say.dm"
+#include "code\modules\mob\living\smell.dm"
#include "code\modules\mob\living\stamina_buffer.dm"
#include "code\modules\mob\living\status_procs.dm"
#include "code\modules\mob\living\taste.dm"