diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index 67d16e6687..1c6b7c21d4 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -155,10 +155,10 @@ //LAVALAND #define LAVALAND_EQUIPMENT_EFFECT_PRESSURE 50 //what pressure you have to be under to increase the effect of equipment meant for lavaland -#define LAVALAND_DEFAULT_ATMOS "o2=14;n2=23;TEMP=300" +#define LAVALAND_DEFAULT_ATMOS "LAVALAND_ATMOS" //SNOSTATION -#define ICEMOON_DEFAULT_ATMOS "o2=17;n2=63;TEMP=180" +#define ICEMOON_DEFAULT_ATMOS "ICEMOON_ATMOS" //ATMOSIA GAS MONITOR TAGS #define ATMOS_GAS_MONITOR_INPUT_O2 "o2_in" diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index ebba9b80e5..260a4c1b29 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -37,7 +37,8 @@ SUBSYSTEM_DEF(air) //atmos singletons var/list/gas_reactions = list() - + var/list/atmos_gen + var/list/planetary = list() //auxmos already caches static planetary mixes but could be convenient to do so here too //Special functions lists var/list/turf/open/high_pressure_delta = list() @@ -475,6 +476,20 @@ SUBSYSTEM_DEF(air) return pipe_init_dirs_cache[type]["[dir]"] +/datum/controller/subsystem/air/proc/generate_atmos() + atmos_gen = list() + for(var/T in subtypesof(/datum/atmosphere)) + var/datum/atmosphere/atmostype = T + atmos_gen[initial(atmostype.id)] = new atmostype + +/datum/controller/subsystem/air/proc/preprocess_gas_string(gas_string) + if(!atmos_gen) + generate_atmos() + if(!atmos_gen[gas_string]) + return gas_string + var/datum/atmosphere/mix = atmos_gen[gas_string] + return mix.gas_string + #undef SSAIR_PIPENETS #undef SSAIR_ATMOSMACHINERY #undef SSAIR_EXCITEDGROUPS diff --git a/code/datums/atmosphere/_atmosphere.dm b/code/datums/atmosphere/_atmosphere.dm new file mode 100644 index 0000000000..5323b070cd --- /dev/null +++ b/code/datums/atmosphere/_atmosphere.dm @@ -0,0 +1,60 @@ +/datum/atmosphere + var/gas_string + var/id + + var/list/base_gases // A list of gases to always have + var/list/normal_gases // A list of allowed gases:base_amount + var/list/restricted_gases // A list of allowed gases like normal_gases but each can only be selected a maximum of one time + var/restricted_chance = 10 // Chance per iteration to take from restricted gases + + var/minimum_pressure + var/maximum_pressure + + var/minimum_temp + var/maximum_temp + +/datum/atmosphere/New() + generate_gas_string() + +/datum/atmosphere/proc/generate_gas_string() + var/list/spicy_gas = restricted_gases.Copy() + var/target_pressure = rand(minimum_pressure, maximum_pressure) + var/pressure_scale = target_pressure / maximum_pressure + + // First let's set up the gasmix and base gases for this template + // We make the string from a gasmix in this proc because gases need to calculate their pressure + var/datum/gas_mixture/gasmix = new + gasmix.set_temperature(rand(minimum_temp, maximum_temp)) + for(var/i in base_gases) + gasmix.set_moles(i, base_gases[i]) + + // Now let the random choices begin + var/gastype + var/amount + while(gasmix.return_pressure() < target_pressure) + if(!prob(restricted_chance) || !length(spicy_gas)) + gastype = pick(normal_gases) + amount = normal_gases[gastype] + else + gastype = pick(spicy_gas) + amount = spicy_gas[gastype] + spicy_gas -= gastype //You can only pick each restricted gas once + + amount *= rand(50, 200) / 100 // Randomly modifes the amount from half to double the base for some variety + amount *= pressure_scale // If we pick a really small target pressure we want roughly the same mix but less of it all + amount = CEILING(amount, 0.1) + + gasmix.adjust_moles(gastype, amount) + + // That last one put us over the limit, remove some of it + if(gasmix.return_pressure() > target_pressure) + var/moles_to_remove = (1 - target_pressure / gasmix.return_pressure()) * gasmix.total_moles() + gasmix.adjust_moles(gastype, -moles_to_remove) + gasmix.set_moles(gastype, FLOOR(gasmix.get_moles(gastype), 0.1)) + + // Now finally lets make that string + var/list/gas_string_builder = list() + for(var/id in gasmix.get_gases()) + gas_string_builder += "[id]=[gasmix.get_moles(id)]" + gas_string_builder += "TEMP=[gasmix.return_temperature()]" + gas_string = gas_string_builder.Join(";") diff --git a/code/datums/atmosphere/planetary.dm b/code/datums/atmosphere/planetary.dm new file mode 100644 index 0000000000..248873562f --- /dev/null +++ b/code/datums/atmosphere/planetary.dm @@ -0,0 +1,52 @@ +// Atmos types used for planetary airs +/datum/atmosphere/lavaland + id = LAVALAND_DEFAULT_ATMOS + + base_gases = list( + GAS_O2=5, + GAS_N2=10, + ) + normal_gases = list( + GAS_O2=10, + GAS_N2=10, + GAS_CO2=10, + ) + restricted_gases = list( + GAS_PLASMA=0.1, + GAS_BZ=1.2, + GAS_METHANE=1.0, + GAS_METHYL_BROMIDE=0.1, + ) + restricted_chance = 30 + + minimum_pressure = HAZARD_LOW_PRESSURE + 10 + maximum_pressure = LAVALAND_EQUIPMENT_EFFECT_PRESSURE - 1 + + minimum_temp = BODYTEMP_COLD_DAMAGE_LIMIT + 1 + maximum_temp = 350 + +/datum/atmosphere/icemoon + id = ICEMOON_DEFAULT_ATMOS + + base_gases = list( + GAS_O2=5, + GAS_N2=10, + ) + normal_gases = list( + GAS_O2=10, + GAS_N2=10, + GAS_CO2=10, + ) + restricted_gases = list( + GAS_PLASMA=0.1, + GAS_METHANE=1.0, + GAS_METHYL_BROMIDE=0.1, + ) + restricted_chance = 10 + + minimum_pressure = HAZARD_LOW_PRESSURE + 10 + maximum_pressure = LAVALAND_EQUIPMENT_EFFECT_PRESSURE - 1 + + minimum_temp = 180 + maximum_temp = 180 + diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index 3a3ba555de..a0665707ff 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -32,6 +32,11 @@ if(!blocks_air) air = new(2500,src) air.copy_from_turf(src) + if(planetary_atmos && !(initial_gas_mix in SSair.planetary)) + var/datum/gas_mixture/mix = new + mix.parse_gas_string(initial_gas_mix) + mix.mark_immutable() + SSair.planetary[initial_gas_mix] = mix update_air_ref(planetary_atmos ? 1 : 2) . = ..() diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm index ed4b1f63c2..b670baaae7 100644 --- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm +++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm @@ -261,6 +261,8 @@ we use a hook instead return 1 /datum/gas_mixture/parse_gas_string(gas_string) + gas_string = SSair.preprocess_gas_string(gas_string) + var/list/gas = params2list(gas_string) if(gas["TEMP"]) var/temp = text2num(gas["TEMP"]) diff --git a/code/modules/surgery/organs/lungs.dm b/code/modules/surgery/organs/lungs.dm index 93f88192e5..e10b05822b 100644 --- a/code/modules/surgery/organs/lungs.dm +++ b/code/modules/surgery/organs/lungs.dm @@ -54,7 +54,8 @@ var/SA_para_min = 1 //nitrous values var/SA_sleep_min = 5 - var/BZ_trip_balls_min = 1 //BZ gas + var/BZ_trip_balls_min = 0.1 //BZ gas + var/BZ_brain_damage_min = 1 var/gas_stimulation_min = 0.002 //Nitryl and Stimulum var/cold_message = "your face freezing and an icicle forming" @@ -269,13 +270,13 @@ // BZ var/bz_pp = PP(breath, GAS_BZ) - if(bz_pp > BZ_trip_balls_min) + if(bz_pp > BZ_brain_damage_min) H.hallucination += 10 H.reagents.add_reagent(/datum/reagent/bz_metabolites,5) if(prob(33)) H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 3, 150) - else if(bz_pp > 0.01) + else if(bz_pp > BZ_trip_balls_min) H.hallucination += 5 H.reagents.add_reagent(/datum/reagent/bz_metabolites,1) @@ -476,7 +477,7 @@ ) SA_para_min = 30 SA_sleep_min = 50 - BZ_trip_balls_min = 30 + BZ_brain_damage_min = 30 emp_vulnerability = 3 cold_level_1_threshold = 200 @@ -509,8 +510,29 @@ heat_level_2_threshold = 600 // up 200 from level 1, 1000 is silly but w/e for level 3 /obj/item/organ/lungs/ashwalker/populate_gas_info() + // humans usually breathe 21 but require 16/17, so 80% - 1, which is more lenient but it's fine + #define SAFE_THRESHOLD_RATIO 0.8 + var/datum/gas_mixture/breath = SSair.planetary[LAVALAND_DEFAULT_ATMOS] // y'all know + var/pressure = breath.return_pressure() + var/total_moles = breath.total_moles() + for(var/id in breath.get_gases()) + var/this_pressure = PP(breath, id) + var/req_pressure = (this_pressure * SAFE_THRESHOLD_RATIO) - 1 + if(req_pressure > 0) + gas_min[id] = req_pressure + if(id in gas_max) + gas_max[id] += this_pressure + var/bz = breath.get_moles(GAS_BZ) + if(bz) + BZ_trip_balls_min += bz + BZ_brain_damage_min += bz + + gas_max[GAS_N2] = PP(breath, GAS_N2) + 5 + var/o2_pp = PP(breath, GAS_O2) + safe_breath_min = 0.3 * o2_pp + safe_breath_max = 1.3 * o2_pp ..() - gas_max[GAS_N2] = 28 + #undef SAFE_THRESHOLD_RATIO /obj/item/organ/lungs/slime name = "vacuole" diff --git a/tgstation.dme b/tgstation.dme index 1d8f600059..578cdb87ea 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -462,6 +462,8 @@ #include "code\datums\achievements\skill_achievements.dm" #include "code\datums\actions\beam_rifle.dm" #include "code\datums\actions\ninja.dm" +#include "code\datums\atmosphere\_atmosphere.dm" +#include "code\datums\atmosphere\planetary.dm" #include "code\datums\brain_damage\brain_trauma.dm" #include "code\datums\brain_damage\hypnosis.dm" #include "code\datums\brain_damage\imaginary_friend.dm"