From e6e95f4c40345ef319c3749836f29742cb83d6d6 Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Thu, 1 Jan 2026 17:20:54 -0500 Subject: [PATCH] Make gases use alist --- code/__defines/_byond_version_compat.dm | 4 +- code/__defines/math_physics.dm | 2 +- code/_helpers/lists.dm | 7 + code/game/machinery/air_sensor.dm | 6 +- .../atmoalter/portable_atmospherics.dm | 6 +- .../objects/effects/spawners/bombspawner.dm | 4 +- .../game/objects/items/weapons/tanks/tanks.dm | 6 +- code/game/objects/structures/fires.dm | 4 +- .../turfs/floors/subtypes/floor_circuit.dm | 2 +- .../turfs/floors/subtypes/floor_reinforced.dm | 16 +- code/game/turfs/turf.dm | 2 +- code/game/turfs/turf_enter.dm | 6 +- code/modules/ZAS/Diagnostic.dm | 4 +- code/modules/ZAS/Fire.dm | 64 +++---- code/modules/ZAS/Turf.dm | 2 +- code/modules/ZAS/Zone.dm | 16 +- code/modules/admin/verbs/debug.dm | 4 +- code/modules/atmospherics/atmos_primitives.dm | 146 ++++++-------- .../components/unary/unary_base.dm | 6 +- .../random_exoplanet/flora_generator.dm | 6 +- code/modules/materials/_materials.dm | 3 + code/modules/mechs/components/body.dm | 4 +- code/modules/mob/living/human/life.dm | 6 +- .../living/silicon/pai/software_modules.dm | 6 +- .../living/simple_animal/_simple_animal.dm | 7 +- code/modules/multiz/level_data.dm | 8 +- code/modules/organs/internal/lungs.dm | 6 +- .../modules/overmap/planetoids/_planetoids.dm | 6 +- .../overmap/planetoids/planetoid_skybox.dm | 6 +- .../ships/device_types/gas_thruster.dm | 6 +- code/modules/power/fusion/core/core_field.dm | 10 +- code/modules/power/singularity/collector.dm | 7 +- code/modules/scanners/gas.dm | 8 +- code/modules/xgm/xgm_gas_mixture.dm | 178 +++++++++--------- code/unit_tests/atmospherics_tests.dm | 20 +- maps/away/bearcat/bearcat.dm | 8 +- maps/planets/test_planet/test_planet.dm | 2 +- .../exoplanet_ruins/lodge/lodge.dm | 2 +- maps/shaded_hills/levels/_levels.dm | 2 +- .../ruins/ec_old_crash/ec_old_crash.dm | 4 +- mods/species/ascent/turfs/ship.dm | 4 +- 41 files changed, 281 insertions(+), 335 deletions(-) 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 )