diff --git a/code/__defines/_byond_version_compat.dm b/code/__defines/_byond_version_compat.dm
index 61d61853a893..8e843d66d713 100644
--- a/code/__defines/_byond_version_compat.dm
+++ b/code/__defines/_byond_version_compat.dm
@@ -1,5 +1,5 @@
-#define REQUIRED_DM_VERSION 515
+#define REQUIRED_DM_VERSION 516
#if DM_VERSION < REQUIRED_DM_VERSION
-#warn Nebula is not tested on BYOND versions older than 515. The code may not compile, and if it does compile it may have severe problems.
+#warn Nebula is not tested on BYOND versions older than 516. The code may not compile, and if it does compile it may have severe problems.
#endif
\ No newline at end of file
diff --git a/code/__defines/math_physics.dm b/code/__defines/math_physics.dm
index 4edf99ad88af..64dd03e8c1d3 100644
--- a/code/__defines/math_physics.dm
+++ b/code/__defines/math_physics.dm
@@ -27,7 +27,7 @@
#define ATM *ONE_ATMOSPHERE
#define ATMOS_PRECISION 0.0001
-#define QUANTIZE(variable) (round(variable, ATMOS_PRECISION))
+#define QUANTIZE(variable) (NONUNIT_FLOOR(variable, ATMOS_PRECISION))
#define INFINITY 1.#INF
diff --git a/code/_helpers/lists.dm b/code/_helpers/lists.dm
index a39367a43233..0a0c554c5fb0 100644
--- a/code/_helpers/lists.dm
+++ b/code/_helpers/lists.dm
@@ -272,6 +272,13 @@ Checks if a list has the same entries and values as an element of big.
else
.[key] = call(merge_method)(.[key], b_value)
+// Picks a key in an alist. This is awful but hey, what can you do?
+/proc/apick(alist/target_alist)
+ var/index = rand(1, length(target_alist))
+ for(var/key in target_alist)
+ if(--index == 0)
+ return key
+
//Pretends to pick an element based on its weight but really just seems to pick a random element.
/proc/pickweight(list/target_list)
var/total = 0
diff --git a/code/game/machinery/air_sensor.dm b/code/game/machinery/air_sensor.dm
index bfbb9236ed3e..6a4774c0759b 100644
--- a/code/game/machinery/air_sensor.dm
+++ b/code/game/machinery/air_sensor.dm
@@ -46,9 +46,9 @@
if(total_moles <= 0)
return
. = list()
- for(var/gas in air_sample.gas)
- var/decl/material/mat = GET_DECL(gas)
- var/gaspercent = round(air_sample.gas[gas]*100/total_moles,0.01)
+ for(var/gas_type, gas_amount in air_sample.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ var/gaspercent = round(gas_amount*100/total_moles,0.01)
var/gas_list = list("symbol" = mat.gas_symbol_html, "percent" = gaspercent)
. += list(gas_list)
diff --git a/code/game/machinery/atmoalter/portable_atmospherics.dm b/code/game/machinery/atmoalter/portable_atmospherics.dm
index 3de7c00f4368..b788ebfe1e8a 100644
--- a/code/game/machinery/atmoalter/portable_atmospherics.dm
+++ b/code/game/machinery/atmoalter/portable_atmospherics.dm
@@ -12,9 +12,9 @@
/obj/machinery/portable_atmospherics/get_single_monetary_worth()
. = ..()
- for(var/gas in air_contents?.gas)
- var/decl/material/gas_data = GET_DECL(gas)
- . += gas_data.get_value() * air_contents.gas[gas] * GAS_WORTH_MULTIPLIER
+ for(var/gas_type, gas_amount in air_contents?.gas)
+ var/decl/material/gas_data = GET_DECL(gas_type)
+ . += gas_data.get_value() * gas_amount * GAS_WORTH_MULTIPLIER
. = max(1, round(.))
/obj/machinery/portable_atmospherics/Initialize()
diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm
index 9528d9d7b556..1716a5662e97 100644
--- a/code/game/objects/effects/spawners/bombspawner.dm
+++ b/code/game/objects/effects/spawners/bombspawner.dm
@@ -75,7 +75,7 @@
OT.master = V
PT.valve_welded = TRUE
- PT.air_contents.gas = list()
+ PT.air_contents.gas = alist()
PT.air_contents.gas[accelerant_type] = accelerant_amount
PT.air_contents.gas[filler_type] = filler_amount
PT.air_contents.total_moles = accelerant_amount + filler_amount
@@ -83,7 +83,7 @@
PT.air_contents.update_values()
OT.valve_welded = TRUE
- OT.air_contents.gas = list()
+ OT.air_contents.gas = alist()
OT.air_contents.gas[oxidizer_type] = oxidizer_amount
OT.air_contents.total_moles = oxidizer_amount
OT.air_contents.temperature = FLAMMABLE_GAS_MINIMUM_BURN_TEMPERATURE+1
diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm
index 9af831affc7d..6ed1525cc0ee 100644
--- a/code/game/objects/items/weapons/tanks/tanks.dm
+++ b/code/game/objects/items/weapons/tanks/tanks.dm
@@ -80,9 +80,9 @@ var/global/list/global/tank_gauge_cache = list()
/obj/item/tank/get_single_monetary_worth()
. = ..()
- for(var/gas in air_contents?.gas)
- var/decl/material/gas_data = GET_DECL(gas)
- . += gas_data.get_value() * air_contents.gas[gas] * GAS_WORTH_MULTIPLIER
+ for(var/gas_type, gas_amount in air_contents?.gas)
+ var/decl/material/gas_data = GET_DECL(gas_type)
+ . += gas_data.get_value() * gas_amount * GAS_WORTH_MULTIPLIER
. = max(1, round(.))
/obj/item/tank/get_examine_strings(mob/user, distance, infix, suffix)
diff --git a/code/game/objects/structures/fires.dm b/code/game/objects/structures/fires.dm
index 48f1205c014c..92d705df3b7c 100644
--- a/code/game/objects/structures/fires.dm
+++ b/code/game/objects/structures/fires.dm
@@ -151,8 +151,8 @@
/obj/structure/fire_source/proc/check_atmos()
var/datum/gas_mixture/GM = loc?.return_air()
- for(var/g in GM?.gas)
- var/decl/material/oxidizer = GET_DECL(g)
+ for(var/gas_type in GM?.gas)
+ var/decl/material/oxidizer = GET_DECL(gas_type)
if(oxidizer.gas_flags & XGM_GAS_OXIDIZER)
return TRUE
diff --git a/code/game/turfs/floors/subtypes/floor_circuit.dm b/code/game/turfs/floors/subtypes/floor_circuit.dm
index 7684009c32a4..c4bc0b4b577c 100644
--- a/code/game/turfs/floors/subtypes/floor_circuit.dm
+++ b/code/game/turfs/floors/subtypes/floor_circuit.dm
@@ -25,7 +25,7 @@
temperature = TCMB
/turf/floor/greengrid/nitrogen
- initial_gas = list(/decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/nitrogen = MOLES_N2STANDARD)
/turf/floor/blackgrid
name = "mainframe floor"
diff --git a/code/game/turfs/floors/subtypes/floor_reinforced.dm b/code/game/turfs/floors/subtypes/floor_reinforced.dm
index 551786ed357b..a322fb767ce0 100644
--- a/code/game/turfs/floors/subtypes/floor_reinforced.dm
+++ b/code/game/turfs/floors/subtypes/floor_reinforced.dm
@@ -8,32 +8,32 @@
initial_gas = null
/turf/floor/reinforced/airmix
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = MOLES_O2ATMOS,
/decl/material/gas/nitrogen = MOLES_N2ATMOS
)
/turf/floor/reinforced/nitrogen
- initial_gas = list(/decl/material/gas/nitrogen = ATMOSTANK_NITROGEN)
+ initial_gas = alist(/decl/material/gas/nitrogen = ATMOSTANK_NITROGEN)
/turf/floor/reinforced/hydrogen
- initial_gas = list(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN)
+ initial_gas = alist(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN)
/turf/floor/reinforced/oxygen
- initial_gas = list(/decl/material/gas/oxygen = ATMOSTANK_OXYGEN)
+ initial_gas = alist(/decl/material/gas/oxygen = ATMOSTANK_OXYGEN)
/turf/floor/reinforced/nitrogen/engine
name = "engine floor"
- initial_gas = list(/decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/nitrogen = MOLES_N2STANDARD)
/turf/floor/reinforced/hydrogen/fuel
- initial_gas = list(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN_FUEL)
+ initial_gas = alist(/decl/material/gas/hydrogen = ATMOSTANK_HYDROGEN_FUEL)
/turf/floor/reinforced/carbon_dioxide
- initial_gas = list(/decl/material/gas/carbon_dioxide = ATMOSTANK_CO2)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = ATMOSTANK_CO2)
/turf/floor/reinforced/n20
- initial_gas = list(/decl/material/gas/nitrous_oxide = ATMOSTANK_NITROUSOXIDE)
+ initial_gas = alist(/decl/material/gas/nitrous_oxide = ATMOSTANK_NITROUSOXIDE)
/turf/floor/reinforced/airless
name = "vacuum floor"
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 33828543cd5d..3b575e2d243b 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -15,7 +15,7 @@
var/turf_flags
/// Either a mapping of material decls to mol amounts, or a reserved initial gas define like GAS_STANDARD_AIRMIX.
- var/list/initial_gas
+ var/alist/initial_gas
//Properties for airtight tiles (/wall)
var/thermal_conductivity = 0.05
diff --git a/code/game/turfs/turf_enter.dm b/code/game/turfs/turf_enter.dm
index cb1849868ab6..f419ff75cc63 100644
--- a/code/game/turfs/turf_enter.dm
+++ b/code/game/turfs/turf_enter.dm
@@ -59,9 +59,9 @@
var/datum/gas_mixture/env = return_air(1)
if(!env)
return
- for(var/g in env.gas)
- var/decl/material/mat = GET_DECL(g)
- if((mat.gas_flags & XGM_GAS_CONTAMINANT) && env.gas[g] > mat.gas_overlay_limit + 1)
+ for(var/gas_type, gas_amount in env.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ if((mat.gas_flags & XGM_GAS_CONTAMINANT) && gas_amount > mat.gas_overlay_limit + 1)
I.contaminate()
break
diff --git a/code/modules/ZAS/Diagnostic.dm b/code/modules/ZAS/Diagnostic.dm
index 71641a66eef1..4892aa15e51b 100644
--- a/code/modules/ZAS/Diagnostic.dm
+++ b/code/modules/ZAS/Diagnostic.dm
@@ -10,8 +10,8 @@
to_chat(mob, "ZONE: No zone here.")
var/datum/gas_mixture/mix = T.return_air()
to_chat(mob, "ZONE: [mix.return_pressure()] kPa [mix.temperature] k")
- for(var/g in mix.gas)
- to_chat(mob, "ZONE GASES: [g]: [mix.gas[g]]\n")
+ for(var/gas_type, gas_amount in mix.gas)
+ to_chat(mob, "ZONE GASES: [gas_type]: [gas_amount]\n")
/client/proc/Test_ZAS_Connection(var/turf/T)
set category = "Debug"
diff --git a/code/modules/ZAS/Fire.dm b/code/modules/ZAS/Fire.dm
index 8e68d92a22f9..d6365ddce8df 100644
--- a/code/modules/ZAS/Fire.dm
+++ b/code/modules/ZAS/Fire.dm
@@ -187,12 +187,12 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
var/total_oxidizers = 0
//*** Get the fuel and oxidizer amounts
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
+ for(var/gas_type, gas_amount in gas)
+ var/decl/material/mat = GET_DECL(gas_type)
if(mat.gas_flags & XGM_GAS_FUEL)
- total_fuel += gas[g]
+ total_fuel += gas_amount
if(mat.gas_flags & XGM_GAS_OXIDIZER)
- total_oxidizers += gas[g]
+ total_oxidizers += gas_amount
total_fuel *= group_multiplier
total_oxidizers *= group_multiplier
@@ -233,9 +233,9 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
//remove_by_flag() and adjust_gas() handle the group_multiplier for us.
remove_by_flag(XGM_GAS_OXIDIZER, used_oxidizers)
var/datum/gas_mixture/burned_fuel = remove_by_flag(XGM_GAS_FUEL, used_fuel)
- for(var/g in burned_fuel.gas)
- var/decl/material/mat = GET_DECL(g)
- mat.add_burn_product(src, burned_fuel.gas[g])
+ for(var/gas_type, gas_amount in burned_fuel.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ mat.add_burn_product(src, gas_amount)
//calculate the energy produced by the reaction and then set the new temperature of the mix
temperature = (starting_energy + vsc.fire_fuel_energy_release * used_fuel) / heat_capacity()
@@ -249,44 +249,32 @@ If it gains pressure too slowly, it may leak or just rupture instead of explodin
return firelevel
/datum/gas_mixture/proc/check_recombustibility()
+ var/const/HAS_OXIDIZER = BITFLAG(0)
+ var/const/HAS_FUEL = BITFLAG(1)
. = 0
- for(var/g in gas)
- if(gas[g] >= 0.1)
- var/decl/material/gas = GET_DECL(g)
+ for(var/gas_type, gas_amount in gas)
+ if(gas_amount >= 0.1)
+ var/decl/material/gas = GET_DECL(gas_type)
if(gas.gas_flags & XGM_GAS_OXIDIZER)
- . = 1
- break
-
- if(!.)
- return 0
-
- . = 0
- for(var/g in gas)
- if(gas[g] >= 0.1)
- var/decl/material/gas = GET_DECL(g)
- if(gas.gas_flags & XGM_GAS_OXIDIZER)
- . = 1
- break
+ . |= HAS_OXIDIZER
+ if(gas.gas_flags & XGM_GAS_FUEL)
+ . |= HAS_FUEL
+ if(. == (HAS_OXIDIZER|HAS_FUEL))
+ return TRUE
/datum/gas_mixture/proc/check_combustibility()
+ var/const/HAS_OXIDIZER = BITFLAG(0)
+ var/const/HAS_FUEL = BITFLAG(1)
. = 0
- for(var/g in gas)
- if(QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1)
- var/decl/material/gas = GET_DECL(g)
+ for(var/gas_type, gas_amount in gas)
+ if(QUANTIZE(gas_amount * vsc.fire_consuption_rate) >= 0.1)
+ var/decl/material/gas = GET_DECL(gas_type)
if(gas.gas_flags & XGM_GAS_OXIDIZER)
- . = 1
- break
-
- if(!.)
- return 0
-
- . = 0
- for(var/g in gas)
- if(QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1)
- var/decl/material/gas = GET_DECL(g)
+ . |= HAS_OXIDIZER
if(gas.gas_flags & XGM_GAS_FUEL)
- . = 1
- break
+ . |= HAS_FUEL
+ if(. == (HAS_OXIDIZER|HAS_FUEL))
+ return TRUE
//returns a value between 0 and vsc.fire_firelevel_multiplier
/datum/gas_mixture/proc/calculate_firelevel(total_fuel, total_oxidizers, reaction_limit, gas_volume)
diff --git a/code/modules/ZAS/Turf.dm b/code/modules/ZAS/Turf.dm
index 016d69b4c53e..95f4c9c6f34e 100644
--- a/code/modules/ZAS/Turf.dm
+++ b/code/modules/ZAS/Turf.dm
@@ -223,7 +223,7 @@
return TRUE
return FALSE
-var/global/list/STANDARD_AIRMIX = list(
+var/global/alist/STANDARD_AIRMIX = alist(
/decl/material/gas/oxygen = MOLES_O2STANDARD,
/decl/material/gas/nitrogen = MOLES_N2STANDARD
)
diff --git a/code/modules/ZAS/Zone.dm b/code/modules/ZAS/Zone.dm
index cac84cb69bf5..10fab6f56161 100644
--- a/code/modules/ZAS/Zone.dm
+++ b/code/modules/ZAS/Zone.dm
@@ -180,26 +180,26 @@ Class Procs:
/zone/proc/handle_condensation()
set waitfor = FALSE
condensing = TRUE
- for(var/g in air.gas)
- var/decl/material/mat = GET_DECL(g)
+ for(var/gas_type, gas_amount in air.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
if(!isnull(mat.gas_condensation_point) && (air.temperature <= mat.gas_condensation_point))
var/condensation_area = air.group_multiplier / length(air.gas)
while(condensation_area > 0 && length(contents))
condensation_area--
var/turf/flooding = pick(contents)
- var/condense_amt = min(air.gas[g], rand(1,3))
+ var/condense_amt = min(gas_amount, rand(1,3))
if(condense_amt < 1)
break
- air.adjust_gas(g, -condense_amt)
- flooding.add_to_reagents(g, condense_amt * REAGENT_UNITS_PER_GAS_MOLE)
+ air.adjust_gas(gas_type, -condense_amt)
+ flooding.add_to_reagents(gas_type, condense_amt * REAGENT_UNITS_PER_GAS_MOLE)
CHECK_TICK
condensing = FALSE
/zone/proc/dbg_data(mob/M)
to_chat(M, name)
- for(var/g in air.gas)
- var/decl/material/mat = GET_DECL(g)
- to_chat(M, "[capitalize(mat.gas_name)]: [air.gas[g]]")
+ for(var/gas_type, gas_amount in air.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ to_chat(M, "[capitalize(mat.gas_name)]: [gas_amount]")
to_chat(M, "P: [air.return_pressure()] kPa V: [air.total_volume]L T: [air.temperature]°K ([air.temperature - T0C]°C)")
to_chat(M, "O2 per N2: [(air.gas[/decl/material/gas/nitrogen] ? air.gas[/decl/material/gas/oxygen]/air.gas[/decl/material/gas/nitrogen] : "N/A")] Moles: [air.total_moles]")
to_chat(M, "Simulated: [contents.len] ([air.group_multiplier])")
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index 8ff55c421dea..4e3f4a70b54b 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -16,8 +16,8 @@
var/t = "Coordinates: [T.x],[T.y],[T.z]\n"
t += "Temperature: [env.temperature]\n"
t += "Pressure: [env.return_pressure()]kPa\n"
- for(var/g in env.gas)
- t += "[g]: [env.gas[g]] / [env.gas[g] * R_IDEAL_GAS_EQUATION * env.temperature / env.total_volume]kPa\n"
+ for(var/gas_type, gas_amount in env.gas)
+ t += "[gas_type]: [gas_amount] / [gas_amount * R_IDEAL_GAS_EQUATION * env.temperature / env.total_volume]kPa\n"
usr.show_message(t, 1)
SSstatistics.add_field_details("admin_verb","ASL") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/atmospherics/atmos_primitives.dm b/code/modules/atmospherics/atmos_primitives.dm
index 6a09490b3251..13a0044acfc6 100644
--- a/code/modules/atmospherics/atmos_primitives.dm
+++ b/code/modules/atmospherics/atmos_primitives.dm
@@ -110,27 +110,28 @@
if (source.total_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
- filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
+ // this takes the associated values of the left side, e.g. source.gas
+ filtering = source.gas & filtering //only filter gasses that are actually there. DO NOT USE &=
//Determine the specific power of each filterable gas type, and the total amount of filterable gas (gasses selected to be scrubbed)
- var/total_filterable_moles = 0 //the total amount of filterable gas
- var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type
- for (var/g in filtering)
- if (source.gas[g] < MINIMUM_MOLES_TO_FILTER)
+ var/total_filterable_moles = 0 //the total amount of filterable gas
+ var/alist/specific_power_gas = alist() //the power required to remove one mole of pure gas, for each gas type
+ ///the power required to scrub one mol of input gas
+ var/power_per_mol = 0
+ for (var/gas_type, gas_amount in filtering)
+ if (gas_amount < MINIMUM_MOLES_TO_FILTER)
continue
- var/specific_power = calculate_specific_power_gas(g, source, sink)/ATMOS_FILTER_EFFICIENCY
- specific_power_gas[g] = specific_power
- total_filterable_moles += source.gas[g]
+ var/specific_power = calculate_specific_power_gas(gas_type, source, sink)/ATMOS_FILTER_EFFICIENCY
+ specific_power_gas[gas_type] = specific_power
+ power_per_mol += gas_amount * specific_power
+ total_filterable_moles += gas_amount
if (total_filterable_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
//now that we know the total amount of filterable gas, we can calculate the amount of power needed to scrub one mole of gas
- var/total_specific_power = 0 //the power required to remove one mole of filterable gas
- for (var/g in filtering)
- var/ratio = source.gas[g]/total_filterable_moles //this converts the specific power per mole of pure gas to specific power per mole of scrubbed gas
- total_specific_power += specific_power_gas[g]*ratio
+ power_per_mol /= total_filterable_moles //this converts the specific power per mole of pure gas to specific power per mole of scrubbed gas
//Figure out how much of each gas to filter
if (isnull(total_transfer_moles))
@@ -139,8 +140,8 @@
total_transfer_moles = min(total_transfer_moles, total_filterable_moles)
//limit transfer_moles based on available power
- if (!isnull(available_power) && total_specific_power > 0)
- total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power)
+ if (!isnull(available_power) && power_per_mol > 0)
+ total_transfer_moles = min(total_transfer_moles, available_power/power_per_mol)
if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
@@ -154,16 +155,15 @@
P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.total_volume //group_multiplier gets divided out here
var/power_draw = 0
- for (var/g in filtering)
- var/transfer_moles = source.gas[g]
+ for (var/gas_type, gas_amount in filtering)
//filter gas in proportion to the mole ratio
- transfer_moles = min(transfer_moles, total_transfer_moles*(source.gas[g]/total_filterable_moles))
+ var/transfer_moles = min(gas_amount, total_transfer_moles*(gas_amount/total_filterable_moles))
//use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
- source.adjust_gas(g, -transfer_moles, update=0)
- sink.adjust_gas_temp(g, transfer_moles, source.temperature, update=0)
+ source.adjust_gas(gas_type, -transfer_moles, update=0)
+ sink.adjust_gas_temp(gas_type, transfer_moles, source.temperature, update=0)
- power_draw += specific_power_gas[g]*transfer_moles
+ power_draw += specific_power_gas[gas_type]*transfer_moles
//Remix the resulting gases
sink.update_values()
@@ -181,25 +181,16 @@
if (source.total_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
- filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
+ filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
- var/total_specific_power = 0 //the power required to remove one mole of input gas
- var/total_filterable_moles = 0 //the total amount of filterable gas
- var/total_unfilterable_moles = 0 //the total amount of non-filterable gas
- var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type
- for (var/g in source.gas)
- if (source.gas[g] < MINIMUM_MOLES_TO_FILTER)
+ var/power_per_mol = 0
+ for (var/gas_type, gas_amount in source.gas)
+ if (gas_amount < MINIMUM_MOLES_TO_FILTER)
continue
+ //the power required to move all the moles of this gas from source to sink
+ power_per_mol += gas_amount * calculate_specific_power_gas(gas_type, source, (gas_type in filtering) ? sink_filtered : sink_clean)/ATMOS_FILTER_EFFICIENCY
- if (g in filtering)
- specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_filtered)/ATMOS_FILTER_EFFICIENCY
- total_filterable_moles += source.gas[g]
- else
- specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_clean)/ATMOS_FILTER_EFFICIENCY
- total_unfilterable_moles += source.gas[g]
-
- var/ratio = source.gas[g]/source.total_moles //converts the specific power per mole of pure gas to specific power per mole of input gas mix
- total_specific_power += specific_power_gas[g]*ratio
+ power_per_mol /= source.total_moles //converts the sum of specific powers per mole of pure gas to specific power per mole of input gas mix
//Figure out how much of each gas to filter
if (isnull(total_transfer_moles))
@@ -208,8 +199,8 @@
total_transfer_moles = min(total_transfer_moles, source.total_moles)
//limit transfer_moles based on available power
- if (!isnull(available_power) && total_specific_power > 0)
- total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power)
+ if (!isnull(available_power) && power_per_mol > 0)
+ total_transfer_moles = min(total_transfer_moles, available_power/power_per_mol)
if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
@@ -223,28 +214,21 @@
P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.total_volume //group_multiplier gets divided out here
var/datum/gas_mixture/removed = source.remove(total_transfer_moles)
- if (!removed) //Just in case
+ if (!removed?.total_moles) //Just in case
return -1
- var/filtered_power_used = 0 //power used to move filterable gas to sink_filtered
- var/unfiltered_power_used = 0 //power used to move unfilterable gas to sink_clean
- for (var/g in removed.gas)
- var/power_used = specific_power_gas[g]*removed.gas[g]
-
- if (g in filtering)
- //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
- sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=0)
- removed.adjust_gas(g, -removed.gas[g], update=0)
- filtered_power_used += power_used
- else
- unfiltered_power_used += power_used
+ // total power draw
+ . = power_per_mol * removed.total_moles
+ for (var/gas_type, gas_amount in removed.gas & filtering) // only the filtered gases
+ //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
+ sink_filtered.adjust_gas_temp(gas_type, gas_amount, removed.temperature, update=0)
+ removed.adjust_gas(gas_type, -gas_amount, update=0)
sink_filtered.update_values()
removed.update_values()
-
sink_clean.merge(removed)
- return filtered_power_used + unfiltered_power_used
+ return .
//For omni devices. Instead filtering is an associative list mapping gasids to gas mixtures.
//I don't like the copypasta, but I decided to keep both versions of gas filtering as filter_gas is slightly faster (doesn't create as many temporary lists, doesn't call update_values() as much)
@@ -253,26 +237,15 @@
if (source.total_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
- filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
+ filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &=
- var/total_specific_power = 0 //the power required to remove one mole of input gas
- var/total_filterable_moles = 0 //the total amount of filterable gas
- var/total_unfilterable_moles = 0 //the total amount of non-filterable gas
- var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type
- for (var/g in source.gas)
- if (source.gas[g] < MINIMUM_MOLES_TO_FILTER)
+ var/power_per_mol = 0
+ for (var/gas_type, gas_amount in source.gas)
+ if (gas_amount < MINIMUM_MOLES_TO_FILTER)
continue
-
- if (g in filtering)
- var/datum/gas_mixture/sink_filtered = filtering[g]
- specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_filtered)/ATMOS_FILTER_EFFICIENCY
- total_filterable_moles += source.gas[g]
- else
- specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_clean)/ATMOS_FILTER_EFFICIENCY
- total_unfilterable_moles += source.gas[g]
-
- var/ratio = source.gas[g]/source.total_moles //converts the specific power per mole of pure gas to specific power per mole of input gas mix
- total_specific_power += specific_power_gas[g]*ratio
+ power_per_mol += gas_amount * (calculate_specific_power_gas(gas_type, source, filtering[gas_type] || sink_clean)/ATMOS_FILTER_EFFICIENCY)
+ //converts the sum of specific powers per mole of pure gas to specific power per mole of input gas mix
+ power_per_mol /= source.total_moles
//Figure out how much of each gas to filter
if (isnull(total_transfer_moles))
@@ -281,8 +254,8 @@
total_transfer_moles = min(total_transfer_moles, source.total_moles)
//limit transfer_moles based on available power
- if (!isnull(available_power) && total_specific_power > 0)
- total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power)
+ if (!isnull(available_power) && power_per_mol > 0)
+ total_transfer_moles = min(total_transfer_moles, available_power/power_per_mol)
if (total_transfer_moles < MINIMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
return -1
@@ -299,27 +272,14 @@
if (!removed) //Just in case
return -1
- var/list/filtered_power_used = list() //power used to move filterable gas to the filtered gas mixes
- var/unfiltered_power_used = 0 //power used to move unfilterable gas to sink_clean
- for (var/g in removed.gas)
- var/power_used = specific_power_gas[g]*removed.gas[g]
-
- if (g in filtering)
- var/datum/gas_mixture/sink_filtered = filtering[g]
- //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
- sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=1)
- removed.adjust_gas(g, -removed.gas[g], update=0)
- if (power_used)
- filtered_power_used[sink_filtered] = power_used
- else
- unfiltered_power_used += power_used
-
+ // for some reason we used to separate filtered and unfiltered power but then we just added it back up anyway??
+ var/power_draw = power_per_mol * removed.total_moles
+ for (var/gas_type, gas_amount in removed.gas & filtering) // keys in both with the values of the former
+ var/datum/gas_mixture/sink_filtered = filtering[gas_type]
+ //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop.
+ sink_filtered.adjust_gas_temp(gas_type, gas_amount, removed.temperature, update=1)
+ removed.adjust_gas(gas_type, -gas_amount, update=FALSE)
removed.update_values()
-
- var/power_draw = unfiltered_power_used
- for (var/datum/gas_mixture/sink_filtered in filtered_power_used)
- power_draw += filtered_power_used[sink_filtered]
-
sink_clean.merge(removed)
return power_draw
diff --git a/code/modules/atmospherics/components/unary/unary_base.dm b/code/modules/atmospherics/components/unary/unary_base.dm
index 6cbe3cb184b6..21734409daa8 100644
--- a/code/modules/atmospherics/components/unary/unary_base.dm
+++ b/code/modules/atmospherics/components/unary/unary_base.dm
@@ -12,9 +12,9 @@
/obj/machinery/atmospherics/unary/get_single_monetary_worth()
. = ..()
- for(var/gas in air_contents?.gas)
- var/decl/material/gas_data = GET_DECL(gas)
- . += gas_data.get_value() * air_contents.gas[gas] * GAS_WORTH_MULTIPLIER
+ for(var/gas_type, gas_amount in air_contents?.gas)
+ var/decl/material/gas_data = GET_DECL(gas_type)
+ . += gas_data.get_value() * gas_amount * GAS_WORTH_MULTIPLIER
. = max(1, round(.))
/obj/machinery/atmospherics/unary/Initialize()
diff --git a/code/modules/maps/template_types/random_exoplanet/flora_generator.dm b/code/modules/maps/template_types/random_exoplanet/flora_generator.dm
index 75c97b70ffc0..1ee8cf4f83cf 100644
--- a/code/modules/maps/template_types/random_exoplanet/flora_generator.dm
+++ b/code/modules/maps/template_types/random_exoplanet/flora_generator.dm
@@ -71,9 +71,9 @@
S.exude_gasses -= exuded_gases_exclusions
if(length(atmos.gas))
if(S.consume_gasses)
- S.consume_gasses = list(pick(atmos.gas)) // ensure that if the plant consumes a gas, the atmosphere will have it
- for(var/g in atmos.gas)
- var/decl/material/mat = GET_DECL(g)
+ S.consume_gasses = list(apick(atmos.gas)) // ensure that if the plant consumes a gas, the atmosphere will have it
+ for(var/gas_type in atmos.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
if(mat.gas_flags & XGM_GAS_CONTAMINANT)
S.set_trait(TRAIT_TOXINS_TOLERANCE, rand(10,15))
if(prob(50))
diff --git a/code/modules/materials/_materials.dm b/code/modules/materials/_materials.dm
index 2ed880fd3b89..b49912026930 100644
--- a/code/modules/materials/_materials.dm
+++ b/code/modules/materials/_materials.dm
@@ -373,6 +373,9 @@ var/global/list/materials_by_gas_symbol = list()
else if(isnull(ignition_point) || (new_temperature_damage_threshold > ignition_point))
temperature_damage_threshold = new_temperature_damage_threshold
+ global.cached_specific_heat[type] = gas_specific_heat
+ global.cached_molar_mass[type] = molar_mass
+
if(!shard_icon)
shard_icon = shard_name
if(!burn_armor)
diff --git a/code/modules/mechs/components/body.dm b/code/modules/mechs/components/body.dm
index 90890403e105..83869776a9c4 100644
--- a/code/modules/mechs/components/body.dm
+++ b/code/modules/mechs/components/body.dm
@@ -57,8 +57,8 @@
var/datum/gas_mixture/air = loc.return_air()
if(air)
//Essentially at this point its like we created a vacuum, but realistically making a bottle doesnt actually increase volume of a room and neither should a mech
- for(var/g in air.gas)
- cockpit.gas[g] = (air.gas[g] / air.total_volume) * cockpit.total_volume
+ for(var/gas_type, gas_amount in air.gas)
+ cockpit.gas[gas_type] = (gas_amount / air.total_volume) * cockpit.total_volume
cockpit.temperature = air.temperature
cockpit.update_values()
diff --git a/code/modules/mob/living/human/life.dm b/code/modules/mob/living/human/life.dm
index 21aa9577627e..b5588d76bde8 100644
--- a/code/modules/mob/living/human/life.dm
+++ b/code/modules/mob/living/human/life.dm
@@ -157,9 +157,9 @@
var/adjusted_pressure = calculate_affecting_pressure(pressure)
//Check for contaminants before anything else because we don't want to skip it.
- for(var/g in environment.gas)
- var/decl/material/mat = GET_DECL(g)
- if((mat.gas_flags & XGM_GAS_CONTAMINANT) && environment.gas[g] > mat.gas_overlay_limit + 1)
+ for(var/gas_type, gas_amount in environment.gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ if((mat.gas_flags & XGM_GAS_CONTAMINANT) && gas_amount > mat.gas_overlay_limit + 1)
handle_contaminants()
break
diff --git a/code/modules/mob/living/silicon/pai/software_modules.dm b/code/modules/mob/living/silicon/pai/software_modules.dm
index b113096f13be..53c6a4859bfe 100644
--- a/code/modules/mob/living/silicon/pai/software_modules.dm
+++ b/code/modules/mob/living/silicon/pai/software_modules.dm
@@ -234,11 +234,11 @@
var/t_moles = env.total_moles
var/gases[0]
- for(var/g in env.gas)
+ for(var/gas_type, gas_amount in env.gas)
var/gas[0]
- var/decl/material/mat = GET_DECL(g)
+ var/decl/material/mat = GET_DECL(gas_type)
gas["name"] = capitalize(mat.gas_name)
- gas["percent"] = round((env.gas[g] / t_moles) * 100)
+ gas["percent"] = round((gas_amount / t_moles) * 100)
gases[++gases.len] = gas
data["gas"] = gases
diff --git a/code/modules/mob/living/simple_animal/_simple_animal.dm b/code/modules/mob/living/simple_animal/_simple_animal.dm
index ab53e5630e3f..a48ea0560da5 100644
--- a/code/modules/mob/living/simple_animal/_simple_animal.dm
+++ b/code/modules/mob/living/simple_animal/_simple_animal.dm
@@ -495,12 +495,11 @@ var/global/list/simplemob_icon_bitflag_cache = list()
if(!level_data.exterior_atmosphere)
return
- for(var/gas in level_data.exterior_atmosphere.gas)
- var/gas_amt = level_data.exterior_atmosphere.gas[gas]
+ for(var/gas_type, gas_amt in level_data.exterior_atmosphere.gas)
if(min_gas)
- min_gas[gas] = round(gas_amt * 0.5)
+ min_gas[gas_type] = round(gas_amt * 0.5)
if(max_gas)
- min_gas[gas] = round(gas_amt * 1.5)
+ min_gas[gas_type] = round(gas_amt * 1.5)
// Simple filler bodytype so animals get offsets for their inventory slots.
/decl/bodytype/animal
diff --git a/code/modules/multiz/level_data.dm b/code/modules/multiz/level_data.dm
index 389f3e24923b..6583ca7fd9d8 100644
--- a/code/modules/multiz/level_data.dm
+++ b/code/modules/multiz/level_data.dm
@@ -389,11 +389,11 @@
exterior_atmosphere.update_values() //Might as well update
exterior_atmosphere.check_tile_graphic()
return
- var/list/exterior_atmos_composition = exterior_atmosphere
+ var/alist/exterior_atmos_composition = exterior_atmosphere
exterior_atmosphere = new
- if(islist(exterior_atmos_composition))
- for(var/gas in exterior_atmos_composition)
- exterior_atmosphere.adjust_gas(gas, exterior_atmos_composition[gas], FALSE)
+ if(istype(exterior_atmos_composition, /alist))
+ for(var/gas, gas_amount in exterior_atmos_composition)
+ exterior_atmosphere.adjust_gas(gas, gas_amount, FALSE)
exterior_atmosphere.temperature = exterior_atmos_temp
exterior_atmosphere.update_values()
exterior_atmosphere.check_tile_graphic()
diff --git a/code/modules/organs/internal/lungs.dm b/code/modules/organs/internal/lungs.dm
index fa5cbde82863..6c025fc5fd2a 100644
--- a/code/modules/organs/internal/lungs.dm
+++ b/code/modules/organs/internal/lungs.dm
@@ -200,9 +200,9 @@
if(!failed_inhale) // Enough gas to tell we're being poisoned via chemical burns or whatever.
var/poison_total = 0
if(poison_types)
- for(var/gname in breath.gas)
- if(poison_types[gname])
- poison_total += breath.gas[gname]
+ for(var/gas_type, gas_amount in breath.gas)
+ if(poison_types[gas_type])
+ poison_total += gas_amount
if(((poison_total/breath.total_moles)*breath_pressure) > safe_toxins_max)
SET_HUD_ALERT(owner, HUD_TOX, 1)
diff --git a/code/modules/overmap/planetoids/_planetoids.dm b/code/modules/overmap/planetoids/_planetoids.dm
index 16ea48dfe92b..f28b871ef26b 100644
--- a/code/modules/overmap/planetoids/_planetoids.dm
+++ b/code/modules/overmap/planetoids/_planetoids.dm
@@ -56,9 +56,9 @@
if(atmosphere)
if(user.skill_check(SKILL_SCIENCE, SKILL_EXPERT) || user.skill_check(SKILL_ATMOS, SKILL_EXPERT))
var/list/gases = list()
- for(var/g in atmosphere.gas)
- if(atmosphere.gas[g] > atmosphere.total_moles * 0.05)
- var/decl/material/mat = GET_DECL(g)
+ for(var/gas_type, gas_amount in atmosphere.gas)
+ if(gas_amount > atmosphere.total_moles * 0.05)
+ var/decl/material/mat = GET_DECL(gas_type)
gases += mat.gas_name
. += "Atmosphere composition: [english_list(gases)]
"
var/inaccuracy = rand(8,12)/10
diff --git a/code/modules/overmap/planetoids/planetoid_skybox.dm b/code/modules/overmap/planetoids/planetoid_skybox.dm
index d9528a9bfc38..f0b30e4bc25b 100644
--- a/code/modules/overmap/planetoids/planetoid_skybox.dm
+++ b/code/modules/overmap/planetoids/planetoid_skybox.dm
@@ -27,10 +27,8 @@
var/list/colors = list()
for(var/lvl in map_z)
var/datum/level_data/level_data = SSmapping.levels_by_z[lvl]
- ///#TODO: Check if the z-level is visible from space
- for(var/g in level_data.exterior_atmosphere?.gas)
- var/decl/material/mat = GET_DECL(g)
- colors += mat.color
+ if(level_data.exterior_atmosphere)
+ colors += level_data.exterior_atmosphere.get_overall_color()
if(length(colors))
return MixColors(colors)
diff --git a/code/modules/overmap/ships/device_types/gas_thruster.dm b/code/modules/overmap/ships/device_types/gas_thruster.dm
index 1f09c65b3187..1c9c32381827 100644
--- a/code/modules/overmap/ships/device_types/gas_thruster.dm
+++ b/code/modules/overmap/ships/device_types/gas_thruster.dm
@@ -74,12 +74,12 @@
if(!propellant || !length(propellant.gas) || !propellant.total_moles)
return 0.01 // Divide by zero protection.
- for(var/mat in propellant.gas)
+ for(var/mat, amt in propellant.gas)
var/decl/material/gas/G = GET_DECL(mat)
// 0.08 chosen to get the RATIO of the specific heat, we don't have cV/cP here, so this is a rough approximate.
var/ratio = (G.gas_specific_heat / 25) + 0.8// These numbers are meaningless, just magic numbers to calibrate range.
- ratio_specific_heat += ratio * (propellant.gas[mat] / propellant.total_moles)
- ratio_specific_heat = ratio_specific_heat / length(propellant.gas)
+ ratio_specific_heat += ratio * (amt / propellant.total_moles)
+ ratio_specific_heat /= length(propellant.gas)
if(ratio_specific_heat == 0 || ratio_specific_heat == 1)
// rare case of avoiding a divide by zero error.
ratio_specific_heat += 0.01
diff --git a/code/modules/power/fusion/core/core_field.dm b/code/modules/power/fusion/core/core_field.dm
index f9c366bc4960..fdd171b839c2 100644
--- a/code/modules/power/fusion/core/core_field.dm
+++ b/code/modules/power/fusion/core/core_field.dm
@@ -100,11 +100,11 @@
var/datum/gas_mixture/uptake_gas = owned_core.loc.return_air()
if(uptake_gas)
uptake_gas = uptake_gas.remove_by_flag(MAT_FLAG_FUSION_FUEL, rand(50,100), TRUE)
- if(uptake_gas && uptake_gas.total_moles)
- for(var/gasname in uptake_gas.gas)
- if(uptake_gas.gas[gasname]*10 > reactants[gasname])
- AddParticles(gasname, uptake_gas.gas[gasname]*10)
- uptake_gas.adjust_gas(gasname, -(uptake_gas.gas[gasname]), update=FALSE)
+ if(uptake_gas?.total_moles)
+ for(var/gas_type, gas_amount in uptake_gas.gas)
+ if(gas_amount*10 > reactants[gas_type])
+ AddParticles(gas_type, gas_amount*10)
+ uptake_gas.adjust_gas(gas_type, -gas_amount, update=FALSE)
added_particles = TRUE
if(added_particles)
uptake_gas.update_values()
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index f85c32b16eb0..fa558379729e 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -64,7 +64,7 @@ var/global/list/rad_collectors = list()
receive_pulse(12.5*(last_rads/max_rads)/(0.3+(last_rads/max_rads)))
if(loaded_tank)
- if(loaded_tank.air_contents.gas[/decl/material/gas/hydrogen] == 0)
+ if(!loaded_tank.air_contents.get_gas(/decl/material/gas/hydrogen))
investigate_log("out of fuel.","singulo")
eject()
else
@@ -85,7 +85,8 @@ var/global/list/rad_collectors = list()
toggle_power()
user.visible_message("[user.name] turns \the [src] [active? "on":"off"].", \
"You turn \the [src] [active? "on":"off"].")
- investigate_log("turned [active?"on":"off"] by [user.key]. [loaded_tank?"Fuel: [round(loaded_tank.air_contents.gas[/decl/material/gas/hydrogen]/0.29)]%":"It is empty"].","singulo")
+ // WHY DOES THIS DIVIDE BY 0.29
+ investigate_log("turned [active?"on":"off"] by [user.key]. [loaded_tank?"Fuel: [round(loaded_tank.air_contents.get_gas(/decl/material/gas/hydrogen)/0.29)]%":"It is empty"].","singulo")
else
to_chat(user, "The controls are locked!")
@@ -178,7 +179,7 @@ var/global/list/rad_collectors = list()
/obj/machinery/rad_collector/proc/receive_pulse(var/pulse_strength)
if(loaded_tank && active)
var/power_produced = 0
- power_produced = min(100*loaded_tank.air_contents.gas[/decl/material/gas/hydrogen]*pulse_strength*pulse_coeff,max_power)
+ power_produced = min(100*loaded_tank.air_contents.get_gas(/decl/material/gas/hydrogen)*pulse_strength*pulse_coeff,max_power)
generate_power(power_produced)
last_power_new = power_produced
return
diff --git a/code/modules/scanners/gas.dm b/code/modules/scanners/gas.dm
index 397ea46d74bf..3637da7d02e4 100644
--- a/code/modules/scanners/gas.dm
+++ b/code/modules/scanners/gas.dm
@@ -57,14 +57,14 @@
. += "Pressure: [round(pressure,0.01)] kPa"
var/perGas_add_string = ""
- for(var/mix in mixture.gas)
- var/percentage = round(mixture.gas[mix]/total_moles * 100, 0.01)
+ for(var/gas_type, gas_moles in mixture.gas)
+ var/percentage = round(gas_moles/total_moles * 100, 0.01)
if(!percentage)
continue
- var/decl/material/mat = GET_DECL(mix)
+ var/decl/material/mat = GET_DECL(gas_type)
switch(mode)
if(MV_MODE)
- perGas_add_string = ", Moles: [round(mixture.gas[mix], 0.01)]"
+ perGas_add_string = ", Moles: [round(gas_moles, 0.01)]"
if(MAT_TRAIT_MODE)
var/list/traits = list()
if(mat.gas_flags & XGM_GAS_FUEL)
diff --git a/code/modules/xgm/xgm_gas_mixture.dm b/code/modules/xgm/xgm_gas_mixture.dm
index d88010d37564..59b19c52794e 100644
--- a/code/modules/xgm/xgm_gas_mixture.dm
+++ b/code/modules/xgm/xgm_gas_mixture.dm
@@ -1,7 +1,16 @@
+// These variables are used to speed up certain calculations by using dot products.
+var/global/alist/cached_specific_heat = alist()
+var/global/alist/cached_molar_mass = alist()
+var/global/alist/cached_mat_r = alist()
+var/global/alist/cached_mat_g = alist()
+var/global/alist/cached_mat_b = alist()
+var/global/alist/cached_mat_a = alist()
+var/global/alist/cached_mat_color_weight = alist()
+
/datum/gas_mixture
//Associative list of gas moles.
//Gases with 0 moles are not tracked and are pruned by update_values()
- var/list/gas = list()
+ var/alist/gas = alist()
//Temperature in Kelvin of this gas mix.
var/temperature = 0
@@ -86,11 +95,12 @@
temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity
if((group_multiplier != 1)||(giver.group_multiplier != 1))
- for(var/g in giver.gas)
- gas[g] += giver.gas[g] * giver.group_multiplier / group_multiplier
+ var/scale_factor = giver.group_multiplier / group_multiplier
+ for(var/gas_type, gas_amount in giver.gas)
+ gas[gas_type] += gas_amount * scale_factor
else
- for(var/g in giver.gas)
- gas[g] += giver.gas[g]
+ for(var/gas_type, gas_amount in giver.gas)
+ gas[gas_type] += gas_amount
update_values()
return TRUE
@@ -105,11 +115,13 @@
gas.Cut()
sharer.gas.Cut()
- for(var/g in gas|sharer.gas)
- var/comb = gas[g] + sharer.gas[g]
- comb /= total_volume + sharer.total_volume
- gas[g] = comb * total_volume
- sharer.gas[g] = comb * sharer.total_volume
+ var/scale_factor = total_volume + sharer.total_volume
+ var/origin_scale_factor = total_volume / scale_factor
+ var/sharer_scale_factor = sharer.total_volume / scale_factor
+ for(var/gas_type in gas|sharer.gas) // we can only iterate keys here since merging alists doesn't combine values
+ var/comb = gas[gas_type] + sharer.gas[gas_type]
+ gas[gas_type] = comb * origin_scale_factor
+ sharer.gas[gas_type] = comb * sharer_scale_factor
if(our_heatcap + share_heatcap)
temperature = ((temperature * our_heatcap) + (sharer.temperature * share_heatcap)) / (our_heatcap + share_heatcap)
@@ -123,12 +135,7 @@
//Returns the heat capacity of the gas mix based on the specific heat of the gases.
/datum/gas_mixture/proc/heat_capacity()
- . = 0
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
- . += mat.gas_specific_heat * gas[g]
- . *= max(1, group_multiplier)
-
+ return values_dot(gas, global.cached_specific_heat) * max(1, group_multiplier)
//Adds or removes thermal energy. Returns the actual thermal energy change, as in the case of removing energy we can't go below TCMB.
/datum/gas_mixture/proc/add_thermal_energy(var/thermal_energy)
@@ -152,7 +159,6 @@
/datum/gas_mixture/proc/get_thermal_energy_change(var/new_temperature)
return heat_capacity()*(max(new_temperature, 0) - temperature)
-
//Technically vacuum doesn't have a specific entropy. Just use a really big number (infinity would be ideal) here so that it's easy to add gas to vacuum and hard to take gas out.
#define SPECIFIC_ENTROPY_VACUUM 150000
@@ -197,13 +203,8 @@
//Updates the total_moles count and trims any empty gases.
/datum/gas_mixture/proc/update_values()
- total_moles = 0
- for(var/g in gas)
- if(gas[g] <= 0)
- gas -= g
- else
- total_moles += gas[g]
-
+ values_cut_under(gas, ATMOS_PRECISION)
+ total_moles = values_sum(gas)
//Mark the cached color for update
cached_mix_color = null
@@ -222,9 +223,9 @@
var/datum/gas_mixture/removed = new
- for(var/g in gas)
- removed.gas[g] = QUANTIZE((gas[g] / total_moles) * amount)
- gas[g] -= removed.gas[g] / group_multiplier
+ for(var/gas_type, gas_amount in gas)
+ removed.gas[gas_type] = QUANTIZE((gas_amount / total_moles) * amount)
+ gas[gas_type] -= removed.gas[gas_type] / group_multiplier
removed.temperature = temperature
update_values()
@@ -244,9 +245,9 @@
var/datum/gas_mixture/removed = new
removed.group_multiplier = out_group_multiplier
- for(var/g in gas)
- removed.gas[g] = (gas[g] * ratio * group_multiplier / out_group_multiplier)
- gas[g] = gas[g] * (1 - ratio)
+ for(var/gas_type, gas_amount in gas)
+ removed.gas[gas_type] = (gas_amount * ratio * group_multiplier / out_group_multiplier)
+ gas[gas_type] = gas_amount * (1 - ratio)
removed.temperature = temperature
removed.total_volume = total_volume * group_multiplier / out_group_multiplier
@@ -269,18 +270,18 @@
return removed
var/sum = 0
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
- var/list/check = mat_flag ? mat.flags : mat.gas_flags
+ for(var/gas_type, gas_amount in gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ var/check = mat_flag ? mat.flags : mat.gas_flags
if(check & flag)
- sum += gas[g]
+ sum += gas_amount
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
- var/list/check = mat_flag ? mat.flags : mat.gas_flags
+ for(var/gas_type, gas_amount in gas)
+ var/decl/material/mat = GET_DECL(gas_type)
+ var/check = mat_flag ? mat.flags : mat.gas_flags
if(check & flag)
- removed.gas[g] = QUANTIZE((gas[g] / sum) * amount)
- gas[g] -= removed.gas[g] / group_multiplier
+ removed.gas[gas_type] = QUANTIZE((gas_amount / sum) * amount)
+ gas[gas_type] -= removed.gas[gas_type] / group_multiplier
removed.temperature = temperature
update_values()
@@ -291,10 +292,10 @@
//Returns the amount of gas that has the given flag, in moles
/datum/gas_mixture/proc/get_by_flag(flag)
. = 0
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
+ for(var/gas_type, gas_amount in gas)
+ var/decl/material/mat = GET_DECL(gas_type)
if(mat.gas_flags & flag)
- . += gas[g]
+ . += gas_amount
//Copies gas and temperature from another gas_mixture.
/datum/gas_mixture/proc/copy_from(const/datum/gas_mixture/sample)
@@ -324,22 +325,22 @@
if(total_moles == 0 && sample.total_moles != 0 || sample.total_moles == 0 && total_moles != 0)
return 0
- var/list/marked = list()
- for(var/g in gas)
- if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \
- ((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \
- (gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g])))
+ var/alist/marked = alist()
+ for(var/gas_type, gas_amount in gas)
+ if((abs(gas_amount - sample.gas[gas_type]) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((gas_amount < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[gas_type]) || \
+ (gas_amount > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[gas_type])))
return 0
- marked[g] = 1
+ marked[gas_type] = 1
if(abs(return_pressure() - sample.return_pressure()) > MINIMUM_PRESSURE_DIFFERENCE_TO_SUSPEND)
return 0
- for(var/g in sample.gas)
- if(!marked[g])
- if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \
- ((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \
- (gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g])))
+ for(var/sample_type, sample_moles in sample.gas)
+ if(!marked[sample_type])
+ if((abs(gas[sample_type] - sample_moles) > MINIMUM_AIR_TO_SUSPEND) && \
+ ((gas[sample_type] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample_moles) || \
+ (gas[sample_type] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample_moles)))
return 0
if(total_moles > MINIMUM_AIR_TO_SUSPEND)
@@ -358,13 +359,13 @@
for(var/obj/effect/gas_overlay/O in graphic)
if(gas[O.material.type] <= O.material.gas_overlay_limit)
LAZYADD(graphic_remove, O)
- for(var/g in gas)
+ for(var/gas_type, gas_amount in gas)
+ var/decl/material/mat = GET_DECL(gas_type)
//Overlay isn't applied for this gas, check if it's valid and needs to be added.
- var/decl/material/mat = GET_DECL(g)
- if(!isnull(mat.gas_overlay_limit) && gas[g] > mat.gas_overlay_limit)
- if(!LAZYACCESS(tile_overlay_cache, g))
- LAZYSET(tile_overlay_cache, g, new /obj/effect/gas_overlay(null, g))
- var/tile_overlay = tile_overlay_cache[g]
+ if(!isnull(mat.gas_overlay_limit) && gas_amount > mat.gas_overlay_limit)
+ if(!LAZYACCESS(tile_overlay_cache, gas_type))
+ LAZYSET(tile_overlay_cache, gas_type, new /obj/effect/gas_overlay(null, gas_type))
+ var/tile_overlay = tile_overlay_cache[gas_type]
if(!(tile_overlay in graphic))
LAZYADD(graphic_add, tile_overlay)
. = FALSE
@@ -413,16 +414,16 @@
var/full_heat_capacity = heat_capacity()
var/s_full_heat_capacity = other.heat_capacity()
- var/list/avg_gas = list()
+ var/alist/avg_gas = alist()
+ var/scale_factor = (size + share_size)
+ var/self_scale_factor = size / scale_factor
+ var/other_scale_factor = share_size / scale_factor
- for(var/g in gas)
- avg_gas[g] += gas[g] * size
+ for(var/gas_type, gas_moles in gas)
+ avg_gas[gas_type] += gas_moles * self_scale_factor
- for(var/g in other.gas)
- avg_gas[g] += other.gas[g] * share_size
-
- for(var/g in avg_gas)
- avg_gas[g] /= (size + share_size)
+ for(var/gas_type, gas_moles in other.gas)
+ avg_gas[gas_type] += gas_moles * other_scale_factor
var/temp_avg = 0
if(full_heat_capacity + s_full_heat_capacity)
@@ -433,10 +434,10 @@
ratio = sharing_lookup_table[connecting_tiles]
//WOOT WOOT DO NOT TOUCH THIS.
- for(var/g in avg_gas)
- gas[g] = max(0, (gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g])
+ for(var/gas_type, gas_amount in avg_gas)
+ gas[gas_type] = max(0, (gas[gas_type] - gas_amount) * (1 - ratio) + gas_amount)
if(!one_way)
- other.gas[g] = max(0, (other.gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g])
+ other.gas[gas_type] = max(0, (other.gas[gas_type] - gas_amount) * (1 - ratio) + gas_amount)
temperature = max(0, (temperature - temp_avg) * (1-ratio) + temp_avg)
if(!one_way)
@@ -459,14 +460,14 @@
var/total_thermal_energy = 0
var/total_heat_capacity = 0
- var/list/total_gas = list()
+ var/alist/total_gas = alist()
for(var/datum/gas_mixture/gasmix in gases)
total_volume += gasmix.total_volume
var/temp_heatcap = gasmix.heat_capacity()
total_thermal_energy += gasmix.temperature * temp_heatcap
total_heat_capacity += temp_heatcap
- for(var/g in gasmix.gas)
- total_gas[g] += gasmix.gas[g]
+ for(var/gas_type, gas_amount in gasmix.gas)
+ total_gas[gas_type] += gas_amount
if(total_volume > 0)
var/datum/gas_mixture/combined = new(total_volume)
@@ -481,8 +482,7 @@
combined.react()
//Average out the gases
- for(var/g in combined.gas)
- combined.gas[g] /= total_volume
+ combined.divide(total_volume)
//Update individual gas_mixtures
for(var/datum/gas_mixture/gasmix in gases)
@@ -493,10 +493,7 @@
return 1
/datum/gas_mixture/proc/get_mass()
- . = 0
- for(var/g in gas)
- var/decl/material/mat = GET_DECL(g)
- . += gas[g] * mat.molar_mass * group_multiplier
+ return values_dot(gas, global.cached_molar_mass) * group_multiplier
/datum/gas_mixture/proc/specific_mass()
var/M = get_total_moles()
@@ -507,30 +504,23 @@
///Returns a color blended from all materials the gas mixture contains
/datum/gas_mixture/proc/get_overall_color()
if(!cached_mix_color)
- if(!LAZYLEN(gas))
+ if(!length(gas))
cached_mix_color = "#ffffffff"
return cached_mix_color
- if(LAZYLEN(gas) == 1)
- var/decl/material/G = GET_DECL(gas[1])
- cached_mix_color = G.color + num2hex(G.opacity * 255)
+ if(length(gas) == 1)
+ for(var/gas_type in gas)
+ var/decl/material/G = GET_DECL(gas_type)
+ cached_mix_color = G.color + num2hex(G.opacity * 255)
return cached_mix_color
//If we really have to, add up all colors
- var/list/colors = list(0, 0, 0, 0)
- var/total_color_weight = 0
-
- for(var/mat_path in gas)
+ cached_mix_color = rgb(255,255,255,255)
+ for(var/mat_path, mat_moles in gas)
var/decl/material/G = GET_DECL(mat_path)
if(G.color_weight <= 0)
continue
var/hex = uppertext(G.color) + num2hex(G.opacity * 255)
- var/mod = gas[mat_path] * G.color_weight
- colors[1] += HEX_RED(hex) * mod
- colors[2] += HEX_GREEN(hex) * mod
- colors[3] += HEX_BLUE(hex) * mod
- colors[4] += HEX_ALPHA(hex) * mod
- total_color_weight += mod
- cached_mix_color = rgb(colors[1] / total_color_weight, colors[2] / total_color_weight, colors[3] / total_color_weight, colors[4] / total_color_weight)
+ cached_mix_color = BlendHSV(cached_mix_color, hex, (mat_moles * G.color_weight) / total_moles)
return cached_mix_color
diff --git a/code/unit_tests/atmospherics_tests.dm b/code/unit_tests/atmospherics_tests.dm
index 0fa4febe7d55..121bf2d15fd8 100644
--- a/code/unit_tests/atmospherics_tests.dm
+++ b/code/unit_tests/atmospherics_tests.dm
@@ -62,7 +62,7 @@
test_cases = list(
uphill = list(
source = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 5,
/decl/material/gas/nitrogen = 10,
/decl/material/gas/carbon_dioxide = 5,
@@ -72,7 +72,7 @@
temperature = T20C - 5,
),
sink = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
@@ -84,7 +84,7 @@
),
downhill = list(
source = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
@@ -94,7 +94,7 @@
temperature = T20C + 5,
),
sink = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 5,
/decl/material/gas/nitrogen = 10,
/decl/material/gas/carbon_dioxide = 5,
@@ -106,7 +106,7 @@
),
flat = list(
source = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
@@ -116,7 +116,7 @@
temperature = T20C,
),
sink = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
@@ -128,7 +128,7 @@
),
vacuum_sink = list(
source = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
@@ -138,17 +138,17 @@
temperature = T20C,
),
sink = list(
- initial_gas = list(),
+ initial_gas = alist(),
temperature = 0,
),
),
vacuum_source = list(
source = list(
- initial_gas = list(),
+ initial_gas = alist(),
temperature = 0,
),
sink = list(
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/oxygen = 10,
/decl/material/gas/nitrogen = 20,
/decl/material/gas/carbon_dioxide = 10,
diff --git a/maps/away/bearcat/bearcat.dm b/maps/away/bearcat/bearcat.dm
index dc13ca07d873..c022e64c5308 100644
--- a/maps/away/bearcat/bearcat.dm
+++ b/maps/away/bearcat/bearcat.dm
@@ -89,16 +89,16 @@
door_color = COLOR_AMBER
/turf/floor/usedup
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
/turf/floor/tiled/usedup
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
/turf/floor/tiled/dark/usedup
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
/turf/floor/tiled/white/usedup
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
/obj/abstract/landmark/corpse/deadcap
name = "Dead Captain"
diff --git a/maps/planets/test_planet/test_planet.dm b/maps/planets/test_planet/test_planet.dm
index 83c42703e654..9d7d0f324d71 100644
--- a/maps/planets/test_planet/test_planet.dm
+++ b/maps/planets/test_planet/test_planet.dm
@@ -7,7 +7,7 @@
/datum/gas_mixture/atmos_neutralia
temperature = T20C
- gas = list(
+ gas = alist(
/decl/material/gas/oxygen = MOLES_O2STANDARD,
/decl/material/gas/nitrogen = MOLES_N2STANDARD,
)
diff --git a/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm b/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm
index 893ebdb5c648..b92079557e2e 100644
--- a/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm
+++ b/maps/random_ruins/exoplanet_ruins/lodge/lodge.dm
@@ -7,4 +7,4 @@
template_tags = TEMPLATE_TAG_HUMAN|TEMPLATE_TAG_HABITAT
/turf/floor/wood/usedup
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
\ No newline at end of file
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD, /decl/material/gas/nitrogen = MOLES_N2STANDARD)
\ No newline at end of file
diff --git a/maps/shaded_hills/levels/_levels.dm b/maps/shaded_hills/levels/_levels.dm
index dc2d59ddcc52..0cf8a1ff78a7 100644
--- a/maps/shaded_hills/levels/_levels.dm
+++ b/maps/shaded_hills/levels/_levels.dm
@@ -9,7 +9,7 @@
ambient_light_level = 1
ambient_light_color = "#f3e6ca"
strata = /decl/strata/shaded_hills
- exterior_atmosphere = list(
+ exterior_atmosphere = alist(
/decl/material/gas/oxygen = MOLES_O2STANDARD,
/decl/material/gas/nitrogen = MOLES_N2STANDARD
)
diff --git a/mods/content/government/ruins/ec_old_crash/ec_old_crash.dm b/mods/content/government/ruins/ec_old_crash/ec_old_crash.dm
index bc42e4e157af..4942a9d83b02 100644
--- a/mods/content/government/ruins/ec_old_crash/ec_old_crash.dm
+++ b/mods/content/government/ruins/ec_old_crash/ec_old_crash.dm
@@ -43,10 +43,10 @@
external_pressure_bound = 0.25 ATM
/turf/floor/tiled/lowpressure
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD)
/turf/floor/tiled/white/lowpressure
- initial_gas = list(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD)
+ initial_gas = alist(/decl/material/gas/carbon_dioxide = MOLES_O2STANDARD)
/obj/item/disk/astrodata
name = "astronomical data disk"
diff --git a/mods/species/ascent/turfs/ship.dm b/mods/species/ascent/turfs/ship.dm
index 320a2d8c30e2..03e991d57619 100644
--- a/mods/species/ascent/turfs/ship.dm
+++ b/mods/species/ascent/turfs/ship.dm
@@ -43,7 +43,7 @@
_base_flooring = /decl/flooring/plating/ascent
icon_state = "curvy"
icon = 'icons/turf/flooring/alium.dmi'
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/methyl_bromide = MOLES_CELLSTANDARD * 0.5,
/decl/material/gas/oxygen = MOLES_CELLSTANDARD * 0.5
)
@@ -58,7 +58,7 @@
icon_state = "jaggy"
color = COLOR_GRAY40
_flooring = /decl/flooring/tiling_ascent
- initial_gas = list(
+ initial_gas = alist(
/decl/material/gas/methyl_bromide = MOLES_CELLSTANDARD * 0.5,
/decl/material/gas/oxygen = MOLES_CELLSTANDARD * 0.5
)