diff --git a/code/__DEFINES/atmospherics_defines.dm b/code/__DEFINES/atmospherics_defines.dm index b1be1764c82..90800af7945 100644 --- a/code/__DEFINES/atmospherics_defines.dm +++ b/code/__DEFINES/atmospherics_defines.dm @@ -4,6 +4,7 @@ #define GAS_CO2 (1 << 3) #define GAS_N2O (1 << 4) #define GAS_A_B (1 << 5) +#define GAS_H2 (1 << 6) //ATMOS //stuff you should probably leave well alone! @@ -75,6 +76,10 @@ #define MAX_TOXIC_GAS_DAMAGE 10 #define MOLES_PLASMA_VISIBLE 0.5 //Moles in a standard cell after which plasma is visible +//HYDROGEN +#define HYDROGEN_BURN_ENERGY 2500000 +#define HYDROGEN_MIN_IGNITE_TEMP 500 + // Pressure limits. #define HAZARD_HIGH_PRESSURE 550 //This determins at what pressure the ultra-high pressure red icon is displayed. (This one is set as a constant) #define WARNING_HIGH_PRESSURE 325 //This determins when the orange pressure icon is displayed (it is 0.7 * HAZARD_HIGH_PRESSURE) diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm index 0edeabbc864..af350730d81 100644 --- a/code/__DEFINES/misc_defines.dm +++ b/code/__DEFINES/misc_defines.dm @@ -545,6 +545,7 @@ #define LINDA_SPAWN_AGENT_B (1<<7) #define LINDA_SPAWN_AIR (1<<8) #define LINDA_SPAWN_COLD (1<<9) +#define LINDA_SPAWN_HYDROGEN (1<<10) #define MAPROTATION_MODE_NORMAL_VOTE "Vote" #define MAPROTATION_MODE_NO_DUPLICATES "Nodupes" diff --git a/code/__DEFINES/rust.dm b/code/__DEFINES/rust.dm index 9386b982629..abc893fd4e4 100644 --- a/code/__DEFINES/rust.dm +++ b/code/__DEFINES/rust.dm @@ -71,8 +71,8 @@ ASSERT(istype(high_corner)) return RUSTLIB_CALL(milla_load_turfs, "milla_data", low_corner, high_corner) -/proc/set_tile_atmos(turf/T, airtight_north, airtight_east, airtight_south, airtight_west, atmos_mode, environment_id, oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, temperature, innate_heat_capacity, hotspot_temperature, hotspot_volume) - return RUSTLIB_CALL(milla_set_tile, T, airtight_north, airtight_east, airtight_south, airtight_west, atmos_mode, environment_id, oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, temperature, innate_heat_capacity, hotspot_temperature, hotspot_volume) +/proc/set_tile_atmos(turf/T, airtight_north, airtight_east, airtight_south, airtight_west, atmos_mode, environment_id, oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, hydrogen, temperature, innate_heat_capacity, hotspot_temperature, hotspot_volume) + return RUSTLIB_CALL(milla_set_tile, T, airtight_north, airtight_east, airtight_south, airtight_west, atmos_mode, environment_id, oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, hydrogen, temperature, innate_heat_capacity, hotspot_temperature, hotspot_volume) /proc/get_tile_atmos(turf/T, list/L) return RUSTLIB_CALL(milla_get_tile, T, L) @@ -119,8 +119,8 @@ /proc/get_random_interesting_tile() return RUSTLIB_CALL(milla_get_random_interesting_tile) -/proc/create_environment(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, temperature) - return RUSTLIB_CALL(milla_create_environment, oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, temperature) +/proc/create_environment(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, hydrogen, temperature) + return RUSTLIB_CALL(milla_create_environment, oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, hydrogen, temperature) /proc/set_zlevel_freeze(z, bool_frozen) return RUSTLIB_CALL(milla_set_zlevel_frozen, z, bool_frozen) @@ -258,28 +258,29 @@ #define MILLA_INDEX_TOXINS 5 #define MILLA_INDEX_SLEEPING_AGENT 6 #define MILLA_INDEX_AGENT_B 7 -#define MILLA_INDEX_ATMOS_MODE 8 -#define MILLA_INDEX_ENVIRONMENT_ID 9 -#define MILLA_INDEX_SUPERCONDUCTIVITY_NORTH 10 -#define MILLA_INDEX_SUPERCONDUCTIVITY_EAST 11 -#define MILLA_INDEX_SUPERCONDUCTIVITY_SOUTH 12 -#define MILLA_INDEX_SUPERCONDUCTIVITY_WEST 13 -#define MILLA_INDEX_INNATE_HEAT_CAPACITY 14 -#define MILLA_INDEX_TEMPERATURE 15 -#define MILLA_INDEX_HOTSPOT_TEMPERATURE 16 -#define MILLA_INDEX_HOTSPOT_VOLUME 17 -#define MILLA_INDEX_WIND_X 18 -#define MILLA_INDEX_WIND_Y 19 -#define MILLA_INDEX_FUEL_BURNT 20 +#define MILLA_INDEX_HYDROGEN 8 +#define MILLA_INDEX_ATMOS_MODE 9 +#define MILLA_INDEX_ENVIRONMENT_ID 10 +#define MILLA_INDEX_SUPERCONDUCTIVITY_NORTH 11 +#define MILLA_INDEX_SUPERCONDUCTIVITY_EAST 12 +#define MILLA_INDEX_SUPERCONDUCTIVITY_SOUTH 13 +#define MILLA_INDEX_SUPERCONDUCTIVITY_WEST 14 +#define MILLA_INDEX_INNATE_HEAT_CAPACITY 15 +#define MILLA_INDEX_TEMPERATURE 16 +#define MILLA_INDEX_HOTSPOT_TEMPERATURE 17 +#define MILLA_INDEX_HOTSPOT_VOLUME 18 +#define MILLA_INDEX_WIND_X 19 +#define MILLA_INDEX_WIND_Y 20 +#define MILLA_INDEX_FUEL_BURNT 21 /// The number of values per tile. #define MILLA_TILE_SIZE MILLA_INDEX_FUEL_BURNT // These are only for InterestingTiles. -#define MILLA_INDEX_TURF 21 -#define MILLA_INDEX_INTERESTING_REASONS 22 -#define MILLA_INDEX_AIRFLOW_X 23 -#define MILLA_INDEX_AIRFLOW_Y 24 +#define MILLA_INDEX_TURF 22 +#define MILLA_INDEX_INTERESTING_REASONS 23 +#define MILLA_INDEX_AIRFLOW_X 24 +#define MILLA_INDEX_AIRFLOW_Y 25 /// The number of values per interesting tile. #define MILLA_INTERESTING_TILE_SIZE MILLA_INDEX_AIRFLOW_Y diff --git a/code/game/gamemodes/miniantags/guardian/types/gaseous.dm b/code/game/gamemodes/miniantags/guardian/types/gaseous.dm index 4c43fe98f15..6599a85db13 100644 --- a/code/game/gamemodes/miniantags/guardian/types/gaseous.dm +++ b/code/game/gamemodes/miniantags/guardian/types/gaseous.dm @@ -12,14 +12,15 @@ var/moles_of_gas = null ///Linda flag for the expelled gas because we need to use special flags for it that are not readable in game well. var/linda_flags = null - /// Possible gases to expel, with how much moles they create. + /// Possible gases to expel, with how many moles they create. var/static/list/possible_gases = list( "Oxygen" = 50, "Nitrogen" = 750, //overpressurizing is hard!. "N2O" = 15, "CO2" = 50, "Plasma" = 5, - "Agent B" = 5 + "Agent B" = 5, + "Hydrogen" = 15 ) /mob/living/simple_animal/hostile/guardian/gaseous/Initialize(mapload, mob/living/host) @@ -66,6 +67,8 @@ linda_flags = LINDA_SPAWN_TOXINS | LINDA_SPAWN_20C if("Agent B") linda_flags = LINDA_SPAWN_AGENT_B | LINDA_SPAWN_20C + if("Hydrogen") + linda_flags = LINDA_SPAWN_HYDROGEN | LINDA_SPAWN_20C /mob/living/simple_animal/hostile/guardian/gaseous/experience_pressure_difference(flow_x, flow_y) return // Immune to gas flow. diff --git a/code/game/machinery/computer/atmos_controllers.dm b/code/game/machinery/computer/atmos_controllers.dm index 5dc70d59b80..252ce34672a 100644 --- a/code/game/machinery/computer/atmos_controllers.dm +++ b/code/game/machinery/computer/atmos_controllers.dm @@ -7,6 +7,7 @@ GLOBAL_LIST_EMPTY(gas_sensors) #define SENSOR_N2 (1<<4) #define SENSOR_CO2 (1<<5) #define SENSOR_N2O (1<<6) +#define SENSOR_H2 (1<<7) /obj/machinery/atmospherics/air_sensor icon_state = "gsensor1" @@ -62,6 +63,7 @@ GLOBAL_LIST_EMPTY(gas_sensors) "Nitrogen: [ONOFF_TOGGLE(SENSOR_N2)]" = SENSOR_N2, "Carbon Dioxide: [ONOFF_TOGGLE(SENSOR_CO2)]" = SENSOR_CO2, "Nitrous Oxide: [ONOFF_TOGGLE(SENSOR_N2O)]" = SENSOR_N2O, + "Hydrogen: [ONOFF_TOGGLE(SENSOR_H2)]" = SENSOR_H2, "-SAVE TO BUFFER-" = "multitool" ) @@ -86,6 +88,8 @@ GLOBAL_LIST_EMPTY(gas_sensors) output ^= SENSOR_CO2 if(SENSOR_N2O) output ^= SENSOR_N2O + if(SENSOR_H2) + output ^= SENSOR_H2 if("multitool") if(!ismultitool(I)) // Should never happen return @@ -258,6 +262,11 @@ GLOBAL_LIST_EMPTY(gas_sensors) else sensor_data -= "n2o" + if(AS.output & SENSOR_H2) + sensor_data["h2"] = round(100 * air_sample.hydrogen() / total_moles, 0.1) + else + sensor_data -= "h2" + else if(istype(AM, /obj/machinery/atmospherics/meter)) var/list/meter_data = sensor_name_data_map[sensor_name] var/obj/machinery/atmospherics/meter/the_meter = AM @@ -350,7 +359,8 @@ GLOBAL_LIST_EMPTY(gas_sensors) "filter_n2" = scrubber.scrub_N2, "filter_co2" = scrubber.scrub_CO2, "filter_toxins" = scrubber.scrub_Toxins, - "filter_n2o" = scrubber.scrub_N2O)) + "filter_n2o" = scrubber.scrub_N2O, + "filter_h2" = scrubber.scrub_H2)) /obj/machinery/computer/general_air_control/large_tank_control/multitool_act(mob/living/user, obj/item/I) @@ -477,7 +487,8 @@ GLOBAL_LIST_EMPTY(gas_sensors) "filter_n2" = scrubber.scrub_N2, "filter_co2" = scrubber.scrub_CO2, "filter_toxins" = scrubber.scrub_Toxins, - "filter_n2o" = scrubber.scrub_N2O)) + "filter_n2o" = scrubber.scrub_N2O, + "filter_h2" = scrubber.scrub_H2)) refresh_outlets() to_chat(user, "Successfully added an outlet scrubber") return @@ -565,6 +576,7 @@ GLOBAL_LIST_EMPTY(gas_sensors) outlet_scrubber_data[uid]["filter_co2"] = scrubber.scrub_CO2 outlet_scrubber_data[uid]["filter_toxins"] = scrubber.scrub_Toxins outlet_scrubber_data[uid]["filter_n2o"] = scrubber.scrub_N2O + outlet_scrubber_data[uid]["filter_h2"] = scrubber.scrub_H2 /obj/machinery/computer/general_air_control/large_tank_control/refresh_all() ..() @@ -650,6 +662,8 @@ GLOBAL_LIST_EMPTY(gas_sensors) scrubber.scrub_N2 = !scrubber.scrub_N2 if("o2_scrub") scrubber.scrub_O2 = !scrubber.scrub_O2 + if("scrub_h2") + scrubber.scrub_H2 = !scrubber.scrub_H2 if("widenet") scrubber.widenet = !scrubber.widenet if("scrubbing") @@ -704,3 +718,4 @@ GLOBAL_LIST_EMPTY(gas_sensors) #undef SENSOR_N2 #undef SENSOR_CO2 #undef SENSOR_N2O +#undef SENSOR_H2 diff --git a/code/game/machinery/computer/sm_monitor.dm b/code/game/machinery/computer/sm_monitor.dm index 766227f68b8..9d162474913 100644 --- a/code/game/machinery/computer/sm_monitor.dm +++ b/code/game/machinery/computer/sm_monitor.dm @@ -67,6 +67,7 @@ gasdata.Add(list(list("name"= "Plasma", "amount" = air.toxins(), "portion" = round(100 * air.toxins() / TM, 0.01)))) gasdata.Add(list(list("name"= "Nitrous Oxide", "amount" = air.sleeping_agent(), "portion" = round(100 * air.sleeping_agent() / TM, 0.01)))) gasdata.Add(list(list("name"= "Agent B", "amount" = air.agent_b(), "portion" = round(100 * air.agent_b() / TM, 0.01)))) + gasdata.Add(list(list("name"= "Hydrogen", "amount" = air.hydrogen(), "portion" = round(100 * air.hydrogen() / TM, 0.01)))) else gasdata.Add(list(list("name"= "Oxygen", "amount" = 0, "portion" = 0))) gasdata.Add(list(list("name"= "Carbon Dioxide", "amount" = 0,"portion" = 0))) @@ -74,6 +75,7 @@ gasdata.Add(list(list("name"= "Plasma", "amount" = 0,"portion" = 0))) gasdata.Add(list(list("name"= "Nitrous Oxide", "amount" = 0,"portion" = 0))) gasdata.Add(list(list("name"= "Agent B", "amount" = 0,"portion" = 0))) + gasdata.Add(list(list("name"= "Hydrogen", "amount" = 0,"portion" = 0))) data["gases"] = gasdata else var/list/SMS = list() diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm index 7f1cd544af3..7029fe8923e 100644 --- a/code/game/objects/items/devices/scanners.dm +++ b/code/game/objects/items/devices/scanners.dm @@ -749,6 +749,7 @@ SLIME SCANNER var/carbon_dioxide = 0 var/sleeping_agent = 0 var/agent_b = 0 + var/hydrogen = 0 if(detailed)// Present all mixtures one by one for(var/datum/gas_mixture/air as anything in airs) @@ -771,6 +772,8 @@ SLIME SCANNER message += " Nitrous Oxide: [round(air.sleeping_agent(), 0.01)] moles ([round(air.sleeping_agent() / total_moles * 100, 0.01)] %)" if(air.agent_b() && (milla_turf_details || air.agent_b() / total_moles > 0.01)) message += " Agent B: [round(air.agent_b(), 0.01)] moles ([round(air.agent_b() / total_moles * 100, 0.01)] %)" + if(air.hydrogen() && (milla_turf_details || air.hydrogen() / total_moles > 0.01)) + message += " Hydrogen: [round(air.hydrogen(), 0.01)] moles ([round(air.hydrogen() / total_moles * 100, 0.01)] %)" message += "Temperature: [round(air.temperature()-T0C)] °C ([round(air.temperature())] K)" message += "Volume: [round(volume)] Liters" message += "Pressure: [round(pressure, 0.1)] kPa" @@ -794,6 +797,7 @@ SLIME SCANNER carbon_dioxide += air.carbon_dioxide() sleeping_agent += air.sleeping_agent() agent_b += air.agent_b() + hydrogen += air.hydrogen() var/temperature = heat_capacity ? thermal_energy / heat_capacity : 0 pressure = volume ? total_moles * R_IDEAL_GAS_EQUATION * temperature / volume : 0 @@ -812,6 +816,8 @@ SLIME SCANNER message += " Nitrous Oxide: [round(sleeping_agent, 0.01)] moles ([round(sleeping_agent / total_moles * 100, 0.01)] %)" if(agent_b && (milla_turf_details || agent_b / total_moles > 0.01)) message += " Agent B: [round(agent_b, 0.01)] moles ([round(agent_b / total_moles * 100, 0.01)] %)" + if(hydrogen && (milla_turf_details || hydrogen / total_moles > 0.01)) + message += " Hydrogen: [round(hydrogen, 0.01)] moles ([round(hydrogen / total_moles * 100, 0.01)] %)" message += "Temperature: [round(temperature-T0C)] °C ([round(temperature)] K)" message += "Volume: [round(volume)] Liters" message += "Pressure: [round(pressure, 0.1)] kPa" diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index b9ec81b5f22..fc536d8cd8c 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -303,6 +303,18 @@ oxygen = 2644 nitrogen = 10580 +/turf/simulated/floor/engine/agent_b + name = "\improper agent B floor" + agent_b = 10000 + oxygen = 0 + nitrogen = 0 + +/turf/simulated/floor/engine/hydrogen + name = "\improper H2 floor" + hydrogen = 100000 + oxygen = 0 + nitrogen = 0 + /turf/simulated/floor/engine/xenobio oxygen = 0 temperature = 80 diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 10282872bbc..78640958434 100644 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -24,6 +24,7 @@ var/toxins = 0 var/sleeping_agent = 0 var/agent_b = 0 + var/hydrogen = 0 //Properties for airtight tiles (/wall) var/thermal_conductivity = 0.05 @@ -448,6 +449,7 @@ merged.set_toxins(merged.toxins() / turf_count) merged.set_sleeping_agent(merged.sleeping_agent() / turf_count) merged.set_agent_b(merged.agent_b() / turf_count) + merged.set_hydrogen(merged.hydrogen() / turf_count) get_turf_air(self).copy_from(merged) /turf/proc/ReplaceWithLattice() diff --git a/code/modules/admin/verbs/diagnostics.dm b/code/modules/admin/verbs/diagnostics.dm index 34e7bb65561..744096a688d 100644 --- a/code/modules/admin/verbs/diagnostics.dm +++ b/code/modules/admin/verbs/diagnostics.dm @@ -15,7 +15,7 @@ if(T.active_hotspot) burning = 1 - to_chat(usr, "@[target.x],[target.y]: O:[GM.oxygen()] T:[GM.toxins()] N:[GM.nitrogen()] C:[GM.carbon_dioxide()] N2O: [GM.sleeping_agent()] Agent B: [GM.agent_b()] w [GM.temperature()] Kelvin, [GM.return_pressure()] kPa [(burning)?("BURNING"):(null)]") + to_chat(usr, "@[target.x],[target.y]: O:[GM.oxygen()] T:[GM.toxins()] N:[GM.nitrogen()] C:[GM.carbon_dioxide()] N2O: [GM.sleeping_agent()] Agent B: [GM.agent_b()] Hydrogen: [GM.hydrogen()] w [GM.temperature()] Kelvin, [GM.return_pressure()] kPa [(burning)?("BURNING"):(null)]") message_admins("[key_name_admin(usr)] has checked the air status of [target]") log_admin("[key_name(usr)] has checked the air status of [target]") diff --git a/code/modules/atmospherics/environmental/LINDA_system.dm b/code/modules/atmospherics/environmental/LINDA_system.dm index b1baf850601..10aa4e130bb 100644 --- a/code/modules/atmospherics/environmental/LINDA_system.dm +++ b/code/modules/atmospherics/environmental/LINDA_system.dm @@ -144,4 +144,7 @@ G.set_oxygen(G.oxygen() + MOLES_O2STANDARD * amount) G.set_nitrogen(G.nitrogen() + MOLES_N2STANDARD * amount) + if(flag & LINDA_SPAWN_HYDROGEN) + G.set_hydrogen(G.hydrogen() + amount) + blind_release_air(G) diff --git a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm index 2ac805842ae..68262625f94 100644 --- a/code/modules/atmospherics/environmental/LINDA_turf_tile.dm +++ b/code/modules/atmospherics/environmental/LINDA_turf_tile.dm @@ -12,6 +12,7 @@ air.set_toxins(toxins) air.set_sleeping_agent(sleeping_agent) air.set_agent_b(agent_b) + air.set_hydrogen(hydrogen) air.set_temperature(temperature) else air.set_oxygen(0) @@ -20,6 +21,7 @@ air.set_toxins(0) air.set_sleeping_agent(0) air.set_agent_b(0) + air.set_hydrogen(0) air.set_temperature(0) return air @@ -178,7 +180,7 @@ /turf/proc/Initialize_Atmos(milla_tick) // This is one of two places expected to call this otherwise-unsafe method. var/list/connectivity = private_unsafe_recalculate_atmos_connectivity() - var/list/air = list(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, temperature) + var/list/air = list(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, hydrogen, temperature) milla_data = connectivity[1] + list(atmos_mode, SSmapping.environments[atmos_environment]) + air + connectivity[2] /turf/simulated/Initialize_Atmos(milla_tick) diff --git a/code/modules/atmospherics/gasmixtures/gas_mixture.dm b/code/modules/atmospherics/gasmixtures/gas_mixture.dm index 92f20f384d6..839068f7514 100644 --- a/code/modules/atmospherics/gasmixtures/gas_mixture.dm +++ b/code/modules/atmospherics/gasmixtures/gas_mixture.dm @@ -8,9 +8,16 @@ What are the archived variables for? #define SPECIFIC_HEAT_CDO 30 #define SPECIFIC_HEAT_N2O 40 #define SPECIFIC_HEAT_AGENT_B 300 +#define SPECIFIC_HEAT_HYDROGEN 15 -#define HEAT_CAPACITY_CALCULATION(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, innate_heat_capacity) \ - (carbon_dioxide * SPECIFIC_HEAT_CDO + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + toxins * SPECIFIC_HEAT_TOXIN + sleeping_agent * SPECIFIC_HEAT_N2O + agent_b * SPECIFIC_HEAT_AGENT_B + innate_heat_capacity) +#define HEAT_CAPACITY_CALCULATION(oxygen, carbon_dioxide, nitrogen, toxins, sleeping_agent, agent_b, hydrogen, innate_heat_capacity) \ + (carbon_dioxide * SPECIFIC_HEAT_CDO + \ + (oxygen + nitrogen) * SPECIFIC_HEAT_AIR + \ + toxins * SPECIFIC_HEAT_TOXIN + \ + sleeping_agent * SPECIFIC_HEAT_N2O + \ + agent_b * SPECIFIC_HEAT_AGENT_B + \ + hydrogen * SPECIFIC_HEAT_HYDROGEN + \ + innate_heat_capacity) #define MINIMUM_HEAT_CAPACITY 0.0003 #define MINIMUM_MOLE_COUNT 0.01 @@ -32,6 +39,7 @@ What are the archived variables for? var/private_toxins = 0 var/private_sleeping_agent = 0 var/private_agent_b = 0 + var/private_hydrogen = 0 var/private_temperature = 0 //in Kelvin var/private_hotspot_temperature = 0 var/private_hotspot_volume = 0 @@ -45,6 +53,7 @@ What are the archived variables for? var/private_toxins_archived = 0 var/private_sleeping_agent_archived = 0 var/private_agent_b_archived = 0 + var/private_hydrogen_archived = 0 var/private_temperature_archived = 0 /// Is this mixture currently synchronized with MILLA? Always true for non-bound mixtures. @@ -120,6 +129,18 @@ What are the archived variables for? stack_trace("Out-of-bounds value [value] clamped to [clamped].") private_agent_b = clamped +/datum/gas_mixture/proc/hydrogen() + return private_hydrogen + +/datum/gas_mixture/proc/set_hydrogen(value) + if(isnan(value) || !isnum(value)) + CRASH("Bad value: [value]") + var/clamped = clamp(value, 0, 1e10) + if(value != clamped) + stack_trace("Out-of-bounds value [value] clamped to [clamped].") + private_hydrogen = clamped + + /datum/gas_mixture/proc/temperature() return private_temperature @@ -142,14 +163,14 @@ What are the archived variables for? ///joules per kelvin /datum/gas_mixture/proc/heat_capacity() - return HEAT_CAPACITY_CALCULATION(private_oxygen, private_carbon_dioxide, private_nitrogen, private_toxins, private_sleeping_agent, private_agent_b, innate_heat_capacity) + return HEAT_CAPACITY_CALCULATION(private_oxygen, private_carbon_dioxide, private_nitrogen, private_toxins, private_sleeping_agent, private_agent_b, private_hydrogen, innate_heat_capacity) /datum/gas_mixture/proc/heat_capacity_archived() - return HEAT_CAPACITY_CALCULATION(private_oxygen_archived, private_carbon_dioxide_archived, private_nitrogen_archived, private_toxins_archived, private_sleeping_agent_archived, private_agent_b_archived, innate_heat_capacity) + return HEAT_CAPACITY_CALCULATION(private_oxygen_archived, private_carbon_dioxide_archived, private_nitrogen_archived, private_toxins_archived, private_sleeping_agent_archived, private_agent_b_archived, private_hydrogen_archived, innate_heat_capacity) /// Calculate moles /datum/gas_mixture/proc/total_moles() - return private_oxygen + private_carbon_dioxide + private_nitrogen + private_toxins + private_sleeping_agent + private_agent_b + return private_oxygen + private_carbon_dioxide + private_nitrogen + private_toxins + private_sleeping_agent + private_agent_b + private_hydrogen /datum/gas_mixture/proc/total_trace_moles() return private_agent_b @@ -176,6 +197,7 @@ What are the archived variables for? private_toxins_archived = private_toxins private_sleeping_agent_archived = private_sleeping_agent private_agent_b_archived = private_agent_b + private_hydrogen_archived = private_hydrogen private_temperature_archived = private_temperature @@ -200,6 +222,7 @@ What are the archived variables for? private_toxins += giver.private_toxins private_sleeping_agent += giver.private_sleeping_agent private_agent_b += giver.private_agent_b + private_hydrogen += giver.private_hydrogen set_dirty() return TRUE @@ -228,6 +251,7 @@ What are the archived variables for? removed.private_toxins = QUANTIZE((private_toxins / sum) * amount) removed.private_sleeping_agent = QUANTIZE((private_sleeping_agent / sum) * amount) removed.private_agent_b = QUANTIZE((private_agent_b / sum) * amount) + removed.private_hydrogen = QUANTIZE((private_hydrogen / sum) * amount) private_oxygen = max(private_oxygen - removed.private_oxygen, 0) private_nitrogen = max(private_nitrogen - removed.private_nitrogen, 0) @@ -235,6 +259,7 @@ What are the archived variables for? private_toxins = max(private_toxins - removed.private_toxins, 0) private_sleeping_agent = max(private_sleeping_agent - removed.private_sleeping_agent, 0) private_agent_b = max(private_agent_b - removed.private_agent_b, 0) + private_hydrogen = max(private_hydrogen - removed.private_hydrogen, 0) removed.private_temperature = private_temperature @@ -258,6 +283,7 @@ What are the archived variables for? removed.private_toxins = QUANTIZE(private_toxins * ratio) removed.private_sleeping_agent = QUANTIZE(private_sleeping_agent * ratio) removed.private_agent_b = QUANTIZE(private_agent_b * ratio) + removed.private_hydrogen = QUANTIZE(private_hydrogen * ratio) private_oxygen = max(private_oxygen - removed.private_oxygen, 0) private_nitrogen = max(private_nitrogen - removed.private_nitrogen, 0) @@ -265,6 +291,7 @@ What are the archived variables for? private_toxins = max(private_toxins - removed.private_toxins, 0) private_sleeping_agent = max(private_sleeping_agent - removed.private_sleeping_agent, 0) private_agent_b = max(private_agent_b - removed.private_agent_b, 0) + private_hydrogen = max(private_hydrogen - removed.private_hydrogen, 0) removed.private_temperature = private_temperature set_dirty() @@ -279,6 +306,7 @@ What are the archived variables for? private_toxins = sample.private_toxins private_sleeping_agent = sample.private_sleeping_agent private_agent_b = sample.private_agent_b + private_hydrogen = sample.private_hydrogen private_temperature = sample.private_temperature set_dirty() @@ -294,6 +322,7 @@ What are the archived variables for? private_toxins = model.toxins private_sleeping_agent = model.sleeping_agent private_agent_b = model.agent_b + private_hydrogen = model.hydrogen //acounts for changes in temperature var/turf/model_parent = model.parent_type @@ -318,6 +347,7 @@ What are the archived variables for? var/delta_toxins = QUANTIZE(private_toxins_archived - sharer.private_toxins_archived) / (atmos_adjacent_turfs + 1) var/delta_sleeping_agent = QUANTIZE(private_sleeping_agent_archived - sharer.private_sleeping_agent_archived) / (atmos_adjacent_turfs + 1) var/delta_agent_b = QUANTIZE(private_agent_b_archived - sharer.private_agent_b_archived) / (atmos_adjacent_turfs + 1) + var/delta_hydrogen = QUANTIZE(private_hydrogen_archived - sharer.private_hydrogen_archived) / (atmos_adjacent_turfs + 1) var/delta_temperature = (private_temperature_archived - sharer.private_temperature_archived) @@ -365,6 +395,13 @@ What are the archived variables for? else heat_capacity_sharer_to_self -= agent_b_heat_capacity + if(delta_hydrogen) + var/hydrogen_heat_capacity = SPECIFIC_HEAT_HYDROGEN * delta_hydrogen + if(delta_hydrogen > 0) + heat_capacity_self_to_sharer += hydrogen_heat_capacity + else + heat_capacity_sharer_to_self -= hydrogen_heat_capacity + old_self_heat_capacity = heat_capacity() old_sharer_heat_capacity = sharer.heat_capacity() @@ -386,7 +423,10 @@ What are the archived variables for? private_agent_b -= delta_agent_b sharer.private_agent_b += delta_agent_b - var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins + delta_sleeping_agent + delta_agent_b) + private_hydrogen -= delta_hydrogen + sharer.private_hydrogen += delta_hydrogen + + var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins + delta_sleeping_agent + delta_agent_b + delta_hydrogen) if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) var/new_self_heat_capacity = old_self_heat_capacity + heat_capacity_sharer_to_self - heat_capacity_self_to_sharer @@ -416,6 +456,7 @@ What are the archived variables for? var/delta_toxins = QUANTIZE(private_toxins_archived - model.toxins) / (atmos_adjacent_turfs + 1) var/delta_sleeping_agent = QUANTIZE(private_sleeping_agent_archived - model.sleeping_agent) / (atmos_adjacent_turfs + 1) var/delta_agent_b = QUANTIZE(private_agent_b_archived - model.agent_b) / (atmos_adjacent_turfs + 1) + var/delta_hydrogen = QUANTIZE(private_hydrogen_archived - model.hydrogen) / (atmos_adjacent_turfs + 1) var/delta_temperature = (private_temperature_archived - model.temperature) @@ -451,6 +492,11 @@ What are the archived variables for? heat_transferred -= agent_b_heat_capacity * model.temperature heat_capacity_transferred -= agent_b_heat_capacity + if(delta_hydrogen) + var/hydrogen_heat_capacity = SPECIFIC_HEAT_HYDROGEN * delta_hydrogen + heat_transferred -= hydrogen_heat_capacity * model.temperature + heat_capacity_transferred -= hydrogen_heat_capacity + old_self_heat_capacity = heat_capacity() private_oxygen -= delta_oxygen @@ -459,8 +505,9 @@ What are the archived variables for? private_toxins -= delta_toxins private_sleeping_agent -= delta_sleeping_agent private_agent_b -= delta_agent_b + private_hydrogen -= delta_hydrogen - var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins + delta_sleeping_agent + delta_agent_b) + var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins + delta_sleeping_agent + delta_agent_b + delta_hydrogen) if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) var/new_self_heat_capacity = old_self_heat_capacity - heat_capacity_transferred @@ -471,7 +518,7 @@ What are the archived variables for? set_dirty() if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE) - var/delta_pressure = private_temperature_archived * (total_moles() + moved_moles) - model.temperature * (model.oxygen + model.carbon_dioxide + model.nitrogen + model.toxins + model.sleeping_agent + model.agent_b) + var/delta_pressure = private_temperature_archived * (total_moles() + moved_moles) - model.temperature * (model.oxygen + model.carbon_dioxide + model.nitrogen + model.toxins + model.sleeping_agent + model.agent_b + model.hydrogen) return delta_pressure * R_IDEAL_GAS_EQUATION / volume else return 0 @@ -484,6 +531,7 @@ What are the archived variables for? var/delta_toxins = (private_toxins_archived - model.toxins) / (atmos_adjacent_turfs + 1) var/delta_sleeping_agent = (private_sleeping_agent_archived - model.sleeping_agent) / (atmos_adjacent_turfs + 1) var/delta_agent_b = (private_agent_b_archived - model.agent_b) / (atmos_adjacent_turfs + 1) + var/delta_hydrogen = (private_hydrogen_archived - model.hydrogen) / (atmos_adjacent_turfs + 1) var/delta_temperature = (private_temperature_archived - model.temperature) @@ -492,7 +540,8 @@ What are the archived variables for? || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= private_nitrogen_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= private_toxins_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((abs(delta_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_sleeping_agent) >= private_sleeping_agent_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= private_agent_b_archived * MINIMUM_AIR_RATIO_TO_SUSPEND))) + || ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= private_agent_b_archived * MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_hydrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_hydrogen) >= private_hydrogen_archived * MINIMUM_AIR_RATIO_TO_SUSPEND))) return FALSE if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) return FALSE @@ -561,6 +610,9 @@ What are the archived variables for? if((abs(private_agent_b - sample.private_agent_b) > MINIMUM_AIR_TO_SUSPEND) && \ ((private_agent_b < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_agent_b) || (private_agent_b > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_agent_b))) return FALSE + if((abs(private_hydrogen - sample.private_hydrogen) > MINIMUM_AIR_TO_SUSPEND) && \ + ((private_hydrogen < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_hydrogen) || (private_hydrogen > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.private_hydrogen))) + return FALSE if(total_moles() > MINIMUM_AIR_TO_SUSPEND) if((abs(private_temperature - sample.private_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \ @@ -575,6 +627,7 @@ What are the archived variables for? var/delta_toxins = (private_toxins - model.toxins) var/delta_sleeping_agent = (private_sleeping_agent - model.sleeping_agent) var/delta_agent_b = (private_agent_b - model.agent_b) + var/delta_hydrogen = (private_hydrogen - model.hydrogen) var/delta_temperature = (private_temperature - model.temperature) @@ -583,7 +636,8 @@ What are the archived variables for? || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= private_nitrogen * MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= private_toxins * MINIMUM_AIR_RATIO_TO_SUSPEND)) \ || ((abs(delta_sleeping_agent) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_sleeping_agent) >= private_sleeping_agent * MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= private_agent_b * MINIMUM_AIR_RATIO_TO_SUSPEND))) + || ((abs(delta_agent_b) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_agent_b) >= private_agent_b * MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_hydrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_hydrogen) >= private_hydrogen * MINIMUM_AIR_RATIO_TO_SUSPEND))) return FALSE if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) return FALSE @@ -668,6 +722,34 @@ What are the archived variables for? if(fuel_burnt) reacting = TRUE + // handles hydrogen burning + if((private_hydrogen >= 0) && (private_oxygen >= 0) && private_temperature > HYDROGEN_MIN_IGNITE_TEMP) + // Calculate the reaction rate based on temperature and pressure + var/reaction_rate = (private_temperature / (private_temperature + 2000)) * (return_pressure() / (return_pressure() + 100)) + // Burn a portion of our hydrogen equal to reaction_rate, but no more than we have or have oxygen for. + var/burned_hydrogen = min(reaction_rate * private_hydrogen, private_hydrogen, private_oxygen * 2) + var/burned_oxygen = min(burned_hydrogen / 2, private_oxygen) + // var/produced_water_vapor = (burned_hydrogen / H2_NEEDED_FOR_H2O) + + + var/old_heat_capacity = heat_capacity() + + // Burn gasses + private_hydrogen -= burned_hydrogen + private_oxygen -= burned_oxygen + // private_water_vapor += produced_water_vapor + + // Calculate gained energy + var/energy_released = HYDROGEN_BURN_ENERGY * burned_hydrogen + // Calculate post-burn heat capacity + var/new_heat_capacity = heat_capacity() + // Calculate new temperature + if(new_heat_capacity > MINIMUM_HEAT_CAPACITY) + private_temperature = (private_temperature * old_heat_capacity + energy_released) / new_heat_capacity + + if(fuel_burnt) + reacting = TRUE + set_dirty() return reacting @@ -691,6 +773,7 @@ What are the archived variables for? private_toxins = milla[MILLA_INDEX_TOXINS] private_sleeping_agent = milla[MILLA_INDEX_SLEEPING_AGENT] private_agent_b = milla[MILLA_INDEX_AGENT_B] + private_hydrogen = milla[MILLA_INDEX_HYDROGEN] innate_heat_capacity = milla[MILLA_INDEX_INNATE_HEAT_CAPACITY] private_temperature = milla[MILLA_INDEX_TEMPERATURE] private_hotspot_temperature = milla[MILLA_INDEX_HOTSPOT_TEMPERATURE] @@ -705,6 +788,7 @@ What are the archived variables for? var/total_carbon_dioxide = 0 var/total_sleeping_agent = 0 var/total_agent_b = 0 + var/total_hydrogen = 0 var/must_share = FALSE // Collect all the cheap data and check if there's a significant temperature difference. @@ -725,11 +809,12 @@ What are the archived variables for? total_carbon_dioxide += G.private_carbon_dioxide total_sleeping_agent += G.private_sleeping_agent total_agent_b += G.private_agent_b + total_hydrogen += G.private_hydrogen if(total_volume == 0) return - if(total_volume < 0 || isnan(total_volume) || !isnum(total_volume) || total_oxygen < 0 || isnan(total_oxygen) || !isnum(total_oxygen) || total_nitrogen < 0 || isnan(total_nitrogen) || !isnum(total_nitrogen) || total_toxins < 0 || isnan(total_toxins) || !isnum(total_toxins) || total_carbon_dioxide < 0 || isnan(total_carbon_dioxide) || !isnum(total_carbon_dioxide) || total_sleeping_agent < 0 || isnan(total_sleeping_agent) || !isnum(total_sleeping_agent) || total_agent_b < 0 || isnan(total_agent_b) || !isnum(total_agent_b)) + if(total_volume < 0 || isnan(total_volume) || !isnum(total_volume) || total_oxygen < 0 || isnan(total_oxygen) || !isnum(total_oxygen) || total_nitrogen < 0 || isnan(total_nitrogen) || !isnum(total_nitrogen) || total_toxins < 0 || isnan(total_toxins) || !isnum(total_toxins) || total_carbon_dioxide < 0 || isnan(total_carbon_dioxide) || !isnum(total_carbon_dioxide) || total_sleeping_agent < 0 || isnan(total_sleeping_agent) || !isnum(total_sleeping_agent) || total_agent_b < 0 || isnan(total_agent_b) || !isnum(total_agent_b) || total_hydrogen < 0 || isnan(total_hydrogen) || !isnum(total_hydrogen)) CRASH("A pipenet with [length(mixtures)] connected airs is corrupt and cannot flow safely. Pipenet root is [root] at ([root.x], [root.y], [root.z]).") // If we don't have a significant temperature difference, check for a significant gas amount difference. @@ -755,6 +840,9 @@ What are the archived variables for? if(abs(G.private_agent_b - total_agent_b * G.volume / total_volume) > 0.1) must_share = TRUE break + if(abs(G.private_hydrogen - total_hydrogen * G.volume / total_volume) > 0.1) + must_share = TRUE + break if(!must_share) // Nothing significant, don't do any more work. @@ -788,6 +876,7 @@ What are the archived variables for? G.private_carbon_dioxide = total_carbon_dioxide * G.volume / total_volume G.private_sleeping_agent = total_sleeping_agent * G.volume / total_volume G.private_agent_b = total_agent_b * G.volume / total_volume + G.private_hydrogen = total_hydrogen * G.volume / total_volume G.private_temperature = temperature // In theory, we should G.set_dirty() here, but that's only useful for bound mixtures, and these can't be. @@ -800,6 +889,7 @@ What are the archived variables for? #undef SPECIFIC_HEAT_CDO #undef SPECIFIC_HEAT_N2O #undef SPECIFIC_HEAT_AGENT_B +#undef SPECIFIC_HEAT_HYDROGEN #undef HEAT_CAPACITY_CALCULATION #undef MINIMUM_HEAT_CAPACITY #undef MINIMUM_MOLE_COUNT @@ -826,6 +916,7 @@ What are the archived variables for? readonly.private_toxins = private_toxins readonly.private_sleeping_agent = private_sleeping_agent readonly.private_agent_b = private_agent_b + readonly.private_hydrogen = private_hydrogen readonly.private_temperature = private_temperature readonly.private_hotspot_temperature = private_hotspot_temperature readonly.private_hotspot_volume = private_hotspot_volume @@ -860,6 +951,10 @@ What are the archived variables for? private_agent_b = value set_dirty() +/datum/gas_mixture/bound_to_turf/set_hydrogen(value) + private_hydrogen = value + set_dirty() + /datum/gas_mixture/bound_to_turf/set_temperature(value) private_temperature = value set_dirty() @@ -871,8 +966,17 @@ What are the archived variables for? private_hotspot_volume = max(private_hotspot_volume, (volume / CELL_VOLUME)) /datum/gas_mixture/bound_to_turf/proc/private_unsafe_write() - set_tile_atmos(bound_turf, oxygen = private_oxygen, carbon_dioxide = private_carbon_dioxide, nitrogen = private_nitrogen, toxins = private_toxins, sleeping_agent = private_sleeping_agent, agent_b = private_agent_b, temperature = private_temperature) - + set_tile_atmos( + bound_turf, + oxygen = private_oxygen, + carbon_dioxide = private_carbon_dioxide, + nitrogen = private_nitrogen, + toxins = private_toxins, + sleeping_agent = private_sleeping_agent, + agent_b = private_agent_b, + hydrogen = private_hydrogen, + temperature = private_temperature + ) /datum/gas_mixture/bound_to_turf/proc/get_readonly() if(isnull(readonly)) readonly = new(src) @@ -888,6 +992,7 @@ What are the archived variables for? private_toxins = parent.private_toxins private_sleeping_agent = parent.private_sleeping_agent private_agent_b = parent.private_agent_b + private_hydrogen = parent.private_hydrogen private_temperature = parent.private_temperature private_hotspot_temperature = parent.private_hotspot_temperature @@ -915,5 +1020,8 @@ What are the archived variables for? /datum/gas_mixture/readonly/set_agent_b(value) CRASH("Attempted to modify a readonly gas_mixture.") +/datum/gas_mixture/readonly/set_hydrogen(value) + CRASH("Attempted to modify a readonly gas_mixture.") + /datum/gas_mixture/readonly/set_temperature(value) CRASH("Attempted to modify a readonly gas_mixture.") diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index bf5446df903..a81e022a6cd 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -151,6 +151,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( "carbon dioxide" = new/datum/tlv(-1.0, -1.0, 5, 10), // Partial pressure, kpa "plasma" = new/datum/tlv(-1.0, -1.0, 0.2, 0.5), // Partial pressure, kpa "nitrous oxide" = new/datum/tlv(-1.0, -1.0, 0.2, 0.5), // Partial pressure, kpa + "hydrogen" = new/datum/tlv(-1.0, -1.0, 0.2, 0.5), // Partial pressure, kpa "other" = new/datum/tlv(-1.0, -1.0, 0.5, 1.0), // Partial pressure, kpa "pressure" = new/datum/tlv(ONE_ATMOSPHERE*0.80,ONE_ATMOSPHERE*0.90,ONE_ATMOSPHERE*1.10,ONE_ATMOSPHERE*1.20), /* kpa */ "temperature" = new/datum/tlv(T0C, T0C+10, T0C+40, T0C+66), // K @@ -163,6 +164,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( "carbon dioxide" = new/datum/tlv(-1.0, -1.0, 5, 10), // Partial pressure, kpa "plasma" = new/datum/tlv(-1.0, -1.0, 0.2, 0.5), // Partial pressure, kpa "nitrous oxide" = new/datum/tlv(-1.0, -1.0, 0.2, 0.5), // Partial pressure, kpa + "hydrogen" = new/datum/tlv(-1.0, -1.0, 0.2, 0.5), // Partial pressure, kpa "other" = new/datum/tlv(-1.0, -1.0, 0.5, 1.0), // Partial pressure, kpa "pressure" = new/datum/tlv(ONE_ATMOSPHERE*0.80,ONE_ATMOSPHERE*0.90,ONE_ATMOSPHERE*1.10,ONE_ATMOSPHERE*1.20), /* kpa */ "temperature" = new/datum/tlv(T0C, T0C+10, T0C+40, T0C+66), // K @@ -174,6 +176,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( "carbon dioxide" = new/datum/tlv(-1.0, -1.0, 5, 10), // Partial pressure, kpa "plasma" = new/datum/tlv(-1.0, -1.0, 0.2, 0.5), // Partial pressure, kpa "nitrous oxide" = new/datum/tlv(-1.0, -1.0, 0.2, 0.5), // Partial pressure, kpa + "hydrogen" = new/datum/tlv(-1.0, -1.0, 0.2, 0.5), // Partial pressure, kpa "other" = new/datum/tlv(-1.0, -1.0, 0.5, 1.0), // Partial pressure, kpa "pressure" = new/datum/tlv(ONE_ATMOSPHERE*0.80,ONE_ATMOSPHERE*0.90,ONE_ATMOSPHERE*1.50,ONE_ATMOSPHERE*1.60), /* kpa */ "temperature" = new/datum/tlv(T0C-50, T0C-20, T0C, T20C), // K @@ -185,6 +188,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( "carbon dioxide" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // Partial pressure, kpa "plasma" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // Partial pressure, kpa "nitrous oxide" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // Partial pressure, kpa + "hydrogen" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // Partial pressure, kpa "other" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // Partial pressure, kpa "pressure" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), /* kpa */ "temperature" = new/datum/tlv(0, 0, T20C + 5, T20C + 15), // K @@ -197,6 +201,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( "carbon dioxide" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // Partial pressure, kpa "plasma" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // Partial pressure, kpa "nitrous oxide" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // Partial pressure, kpa + "hydrogen" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // Partial pressure, kpa "other" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // Partial pressure, kpa "pressure" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), /* kpa */ "temperature" = new/datum/tlv(-1.0, -1.0, -1.0, -1.0), // K @@ -294,6 +299,9 @@ GLOBAL_LIST_INIT(aalarm_modes, list( cur_tlv = TLV["nitrous oxide"] var/sleeping_agent_dangerlevel = cur_tlv.get_danger_level(environment.sleeping_agent() * GET_PP) + cur_tlv = TLV["hydrogen"] + var/hydrogen_dangerlevel = cur_tlv.get_danger_level(environment.hydrogen() * GET_PP) + cur_tlv = TLV["other"] var/other_dangerlevel = cur_tlv.get_danger_level(environment.total_trace_moles() * GET_PP) @@ -308,6 +316,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( co2_dangerlevel, plasma_dangerlevel, sleeping_agent_dangerlevel, + hydrogen_dangerlevel, other_dangerlevel, temperature_dangerlevel ) @@ -410,6 +419,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( S.scrub_CO2 = TRUE S.scrub_Toxins = FALSE S.scrub_N2O = FALSE + S.scrub_H2 = FALSE S.scrubbing = TRUE S.widenet = FALSE S.update_icon(UPDATE_ICON_STATE) @@ -431,6 +441,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( S.scrub_CO2 = TRUE S.scrub_Toxins = TRUE S.scrub_N2O = TRUE + S.scrub_H2 = TRUE S.scrubbing = TRUE S.widenet = TRUE S.update_icon(UPDATE_ICON_STATE) @@ -470,6 +481,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( S.scrub_CO2 = TRUE S.scrub_Toxins = FALSE S.scrub_N2O = FALSE + S.scrub_H2 = FALSE S.scrubbing = TRUE S.widenet = FALSE S.update_icon(UPDATE_ICON_STATE) @@ -619,6 +631,10 @@ GLOBAL_LIST_INIT(aalarm_modes, list( var/sleeping_agent_dangerlevel = cur_tlv.get_danger_level(environment.sleeping_agent() * GET_PP) var/sleeping_agent_percent = total ? environment.sleeping_agent() / total * 100 : 0 + cur_tlv = TLV["hydrogen"] + var/hydrogen_dangerlevel = cur_tlv.get_danger_level(environment.hydrogen() * GET_PP) + var/hydrogen_percent = total ? environment.hydrogen() / total * 100 : 0 + cur_tlv = TLV["other"] var/other_moles = total - known_total var/other_dangerlevel = cur_tlv.get_danger_level(other_moles*GET_PP) @@ -639,6 +655,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( percentages["co2"] = co2_percent percentages["plasma"] = plasma_percent percentages["n2o"] = sleeping_agent_percent + percentages["hydrogen"] = hydrogen_percent percentages["other"] = other_percent data["contents"] = percentages @@ -650,8 +667,9 @@ GLOBAL_LIST_INIT(aalarm_modes, list( danger["co2"] = co2_dangerlevel danger["plasma"] = plasma_dangerlevel danger["n2o"] = sleeping_agent_dangerlevel + danger["hydrogen"] = hydrogen_dangerlevel danger["other"] = other_dangerlevel - danger["overall"] = max(pressure_dangerlevel,oxygen_dangerlevel,nitrogen_dangerlevel,co2_dangerlevel,plasma_dangerlevel,other_dangerlevel,temperature_dangerlevel) + danger["overall"] = max(pressure_dangerlevel,oxygen_dangerlevel,nitrogen_dangerlevel,co2_dangerlevel,plasma_dangerlevel,hydrogen_dangerlevel,other_dangerlevel,temperature_dangerlevel) data["danger"] = danger return data @@ -725,6 +743,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( scrubber_info["filter_co2"] = S.scrub_CO2 scrubber_info["filter_toxins"] = S.scrub_Toxins scrubber_info["filter_n2o"] = S.scrub_N2O + scrubber_info["filter_h2"] = S.scrub_H2 scrubbers += list(scrubber_info) data["scrubbers"] = scrubbers return data @@ -752,6 +771,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( "carbon dioxide" = "CO2", "plasma" = "Toxin", "nitrous oxide" = "N2O", + "hydrogen" = "H2", "other" = "Other") for(var/g in gas_names) thresholds += list(list("name" = gas_names[g], "settings" = list())) @@ -865,6 +885,7 @@ GLOBAL_LIST_INIT(aalarm_modes, list( "n2o_scrub", "n2_scrub", "o2_scrub", + "h2_scrub", "widenet", "scrubbing", "direction") @@ -927,6 +948,8 @@ GLOBAL_LIST_INIT(aalarm_modes, list( S.scrub_N2 = val if("o2_scrub") S.scrub_O2 = val + if("h2_scrub") + S.scrub_H2 = val if("widenet") S.widenet = val if("scrubbing") diff --git a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm index 02cc58cb03b..7ebe8573deb 100644 --- a/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm +++ b/code/modules/atmospherics/machinery/components/trinary_devices/filter.dm @@ -11,6 +11,8 @@ #define FILTER_CO2 3 /// Nitrous oxide only. #define FILTER_N2O 4 +/// Hydrogen only. +#define FILTER_H2 5 /obj/machinery/atmospherics/trinary/filter name = "gas filter" @@ -28,7 +30,8 @@ "O2" = FILTER_OXYGEN, "N2" = FILTER_NITROGEN, "CO2" = FILTER_CO2, - "N2O" = FILTER_N2O + "N2O" = FILTER_N2O, + "H2" = FILTER_H2, ) // So we can CtrlClick without triggering the anchored message. @@ -144,6 +147,10 @@ if(FILTER_N2O) filtered_out.set_sleeping_agent(removed.sleeping_agent()) removed.set_sleeping_agent(0) + + if(FILTER_H2) + filtered_out.set_hydrogen(removed.hydrogen()) + removed.set_hydrogen(0) else filtered_out = null @@ -240,3 +247,4 @@ #undef FILTER_NITROGEN #undef FILTER_CO2 #undef FILTER_N2O +#undef FILTER_H2 diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm index 53f14f61477..cf5e1bb589f 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm @@ -23,6 +23,7 @@ var/scrub_CO2 = TRUE var/scrub_Toxins = FALSE var/scrub_N2O = FALSE + var/scrub_H2 = FALSE var/volume_rate = 200 var/widenet = FALSE //is this scrubber acting on the 3x3 area around it. @@ -165,6 +166,8 @@ return TRUE if(environment.agent_b() > 0.001) return TRUE + if(environment.hydrogen() > 0.001) + return TRUE return FALSE @@ -209,6 +212,10 @@ filtered_out.set_sleeping_agent(removed.sleeping_agent()) removed.set_sleeping_agent(0) + if(scrubber.scrub_H2) + filtered_out.set_hydrogen(removed.hydrogen()) + removed.set_hydrogen(0) + //Remix the resulting gases scrubber.air_contents.merge(filtered_out) diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index 475134099ef..169fd9dd854 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -7,6 +7,7 @@ list("name" = "\[O2\]", "icon" = "blue"), list("name" = "\[Toxin (Bio)\]", "icon" = "orange"), list("name" = "\[CO2\]", "icon" = "black"), + list("name" = "\[H2\]", "icon" = "white"), list("name" = "\[Air\]", "icon" = "grey"), list("name" = "\[CAUTION\]", "icon" = "yellow"), list("name" = "\[SPECIAL\]", "icon" = "whiters") @@ -114,7 +115,7 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new()) /obj/machinery/atmospherics/portable/canister/examine(mob/user) . = ..() - . += "Connect a canister to a connector port using a wrench. To fill a tank, attach it to the caniser, increase the \ + . += "Connect a canister to a connector port using a wrench. To fill a tank, attach it to the canister, increase the \ release pressure, and open the valve. Alt-click to eject the tank, or use another to hot-swap. A gas analyzer can be used to check \ the contents of the canister." if(isAntag(user)) @@ -373,6 +374,11 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new()) log_admin("[key_name(ui.user)] opened a canister that contains N2O at [get_area(src)]: [x], [y], [z]") ui.user.create_log(MISC_LOG, "has opened a canister of N2O") + if(air_contents.hydrogen() > 0) + message_admins("[key_name_admin(ui.user)] opened a canister that contains Hydrogen in [get_area(src)]! (JMP)") + log_admin("[key_name(ui.user)] opened a canister that contains Hydrogen at [get_area(src)]: [x], [y], [z]") + ui.user.create_log(MISC_LOG, "has opened a canister of Hydrogen") + else logmsg = "Valve was closed by [key_name(ui.user)], stopping the transfer into the [holding_tank || "air"].
" @@ -435,6 +441,10 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new()) name = "Canister \[CO2\]" icon_state = "black" //See Initialize() can_label = FALSE +/obj/machinery/atmospherics/portable/canister/hydrogen + name = "Canister \[H2\]" + icon_state = "white" //See Initialize() + can_label = FALSE /obj/machinery/atmospherics/portable/canister/air name = "Canister \[Air\]" icon_state = "grey" //See Initialize() @@ -486,6 +496,14 @@ GLOBAL_DATUM_INIT(canister_icon_container, /datum/canister_icons, new()) update_icon() +/obj/machinery/atmospherics/portable/canister/hydrogen/Initialize(mapload) + . = ..() + + canister_color["prim"] = "white" + air_contents.set_hydrogen((maximum_pressure * filled) * air_contents.volume / (R_IDEAL_GAS_EQUATION * air_contents.temperature())) + + update_icon() + /obj/machinery/atmospherics/portable/canister/air/Initialize(mapload) . = ..() diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm index 355f3fbfd6b..48af0a88068 100644 --- a/code/modules/atmospherics/machinery/portable/scrubber.dm +++ b/code/modules/atmospherics/machinery/portable/scrubber.dm @@ -90,6 +90,9 @@ filtered_out.set_agent_b(removed.agent_b()) removed.set_agent_b(0) + filtered_out.set_hydrogen(removed.hydrogen()) + removed.set_hydrogen(0) + //Remix the resulting gases air_contents.merge(filtered_out) diff --git a/code/modules/buildmode/submodes/atmos.dm b/code/modules/buildmode/submodes/atmos.dm index 7ed0c890290..cad31662182 100644 --- a/code/modules/buildmode/submodes/atmos.dm +++ b/code/modules/buildmode/submodes/atmos.dm @@ -10,6 +10,7 @@ var/cdiox = 0 var/nitrox = 0 var/agentbx = 0 + var/hydrogen = 0 /datum/buildmode_mode/atmos/show_help(mob/user) @@ -31,6 +32,7 @@ cdiox = tgui_input_number(user, "CO2 ratio", "Input", 0, 100000, 0, round_value = FALSE) nitrox = tgui_input_number(user, "N2O ratio", "Input", 0, 100000, 0, round_value = FALSE) agentbx = tgui_input_number(user, "Agent B ratio", "Input", 0, 100000, 0, round_value = FALSE) + hydrogen = tgui_input_number(user, "Hydrogen ratio", "Input", 0, 100000, 0, round_value = FALSE) /datum/buildmode_mode/atmos/proc/ppratio_to_moles(ppratio) // ideal gas equation: Pressure * Volume = Moles * r * Temperature @@ -51,6 +53,7 @@ air.set_carbon_dioxide(ppratio_to_moles(cdiox)) air.set_sleeping_agent(ppratio_to_moles(nitrox)) air.set_agent_b(ppratio_to_moles(agentbx)) + air.set_hydrogen(ppratio_to_moles(hydrogen)) for(var/turf/T in block(cornerA,cornerB)) if(issimulatedturf(T)) @@ -66,6 +69,7 @@ T.carbon_dioxide = air.carbon_dioxide() T.sleeping_agent = air.sleeping_agent() T.agent_b = air.agent_b() + T.hydrogen = air.hydrogen() // admin log log_admin("Build Mode: [key_name(user)] changed the atmos of region [COORD(cornerA)] to [COORD(cornerB)]. T: [temperature], P: [pressure], Ox: [oxygen]%, N2: [nitrogen]%, Plsma: [plasma]%, CO2: [cdiox]%, N2O: [nitrox]%. [ctrl_click ? "Overwrote base space turf gases." : ""]") diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 209aeefc97a..cf29d23642a 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -111,6 +111,7 @@ t+= "Carbon Dioxide: [environment.carbon_dioxide()] \n" t+= "N2O: [environment.sleeping_agent()] \n" t+= "Agent B: [environment.agent_b()] \n" + t+= "Hydrogen: [environment.hydrogen()] \n" usr.show_message(t, EMOTE_VISIBLE) diff --git a/code/modules/pda/core_apps.dm b/code/modules/pda/core_apps.dm index fabff30eac9..11c1d00fc1e 100644 --- a/code/modules/pda/core_apps.dm +++ b/code/modules/pda/core_apps.dm @@ -114,7 +114,8 @@ var/co2_level = environment.carbon_dioxide() / total_moles var/plasma_level = environment.toxins() / total_moles var/n2o_level = environment.sleeping_agent() / total_moles - var/unknown_level = 1 - (o2_level + n2_level + co2_level + plasma_level + n2o_level) + var/h2_level = environment.hydrogen() / total_moles + var/unknown_level = 1 - (o2_level + n2_level + co2_level + plasma_level + n2o_level + h2_level) results = list( list("entry" = "Pressure", "units" = "kPa", "val" = "[round(pressure,0.1)]", "bad_high" = 120, "poor_high" = 110, "poor_low" = 95, "bad_low" = 80), list("entry" = "Temperature", "units" = "C", "val" = "[round(environment.temperature()-T0C,0.1)]", "bad_high" = 35, "poor_high" = 25, "poor_low" = 15, "bad_low" = 5), @@ -123,6 +124,7 @@ list("entry" = "Carbon Dioxide", "units" = "%", "val" = "[round(co2_level*100,0.1)]", "bad_high" = 10, "poor_high" = 5, "poor_low" = 0, "bad_low" = 0), list("entry" = "Plasma", "units" = "%", "val" = "[round(plasma_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0), list("entry" = "Nitrous Oxide", "units" = "%", "val" = "[round(n2o_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0), + list("entry" = "Hydrogen", "units" = "%", "val" = "[round(h2_level*100,0.01)]", "bad_high" = 0.5, "poor_high" = 0, "poor_low" = 0, "bad_low" = 0), list("entry" = "Other", "units" = "%", "val" = "[round(unknown_level*100,0.01)]", "bad_high" = 1, "poor_high" = 0.5, "poor_low" = 0, "bad_low" = 0) ) diff --git a/code/modules/power/engines/supermatter/supermatter.dm b/code/modules/power/engines/supermatter/supermatter.dm index 27edef2575f..4ca433d3072 100644 --- a/code/modules/power/engines/supermatter/supermatter.dm +++ b/code/modules/power/engines/supermatter/supermatter.dm @@ -15,9 +15,11 @@ #define OXYGEN_HEAT_PENALTY 1 #define CO2_HEAT_PENALTY 0.1 #define NITROGEN_HEAT_PENALTY -1.5 +#define HYDROGEN_HEAT_PENALTY 20 #define OXYGEN_TRANSMIT_MODIFIER 1.5 //Higher == Bigger bonus to power generation. #define PLASMA_TRANSMIT_MODIFIER 4 +#define HYDROGEN_TRANSMIT_MODIFIER 3 #define N2O_HEAT_RESISTANCE 6 //Higher == Gas makes the crystal more resistant against heat damage. @@ -30,6 +32,7 @@ #define N2_CRUNCH 0.55 #define N2O_CRUNCH 0.55 #define PLASMA_CRUNCH 4 +#define HYDROGEN_CRUNCH 2 #define MOLE_CRUNCH_THRESHOLD 1700 //Above this value we can get lord singulo and #define MOLE_PENALTY_THRESHOLD 1800 //Above this value we can get lord singulo and independent mol damage, below it we can heal damage @@ -152,6 +155,7 @@ var/o2comp = 0 var/co2comp = 0 var/n2ocomp = 0 + var/h2comp = 0 ///The last air sample's total molar count, will always be above or equal to 0 var/combined_gas = 0 @@ -517,10 +521,11 @@ co2comp = max(removed.carbon_dioxide() / combined_gas, 0) n2ocomp = max(removed.sleeping_agent() / combined_gas, 0) n2comp = max(removed.nitrogen() / combined_gas, 0) + h2comp = max(removed.hydrogen() / combined_gas, 0) - gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp - n2comp, 0), 1) + gasmix_power_ratio = min(max(plasmacomp + o2comp + co2comp + h2comp - n2comp, 0), 1) - dynamic_heat_modifier = max((plasmacomp * PLASMA_HEAT_PENALTY) + (o2comp * OXYGEN_HEAT_PENALTY) + (co2comp * CO2_HEAT_PENALTY) + (n2comp * NITROGEN_HEAT_PENALTY), 0.5) + dynamic_heat_modifier = max((plasmacomp * PLASMA_HEAT_PENALTY) + (o2comp * OXYGEN_HEAT_PENALTY) + (co2comp * CO2_HEAT_PENALTY) + (n2comp * NITROGEN_HEAT_PENALTY) + (h2comp * HYDROGEN_HEAT_PENALTY), 0.5) dynamic_heat_resistance = max(n2ocomp * N2O_HEAT_RESISTANCE, 1) power_transmission_bonus = max((plasmacomp * PLASMA_TRANSMIT_MODIFIER) + (o2comp * OXYGEN_TRANSMIT_MODIFIER), 0) @@ -563,7 +568,7 @@ var/crush_ratio = combined_gas / MOLE_CRUNCH_THRESHOLD - gas_coefficient = 1 + (crush_ratio ** 2 * (crush_ratio <= 1) + (crush_ratio > 1) * 2 * crush_ratio / (crush_ratio + 1)) * (plasmacomp * PLASMA_CRUNCH + o2comp * O2_CRUNCH + co2comp * CO2_CRUNCH + n2comp * N2_CRUNCH + n2ocomp * N2O_CRUNCH) + gas_coefficient = 1 + (crush_ratio ** 2 * (crush_ratio <= 1) + (crush_ratio > 1) * 2 * crush_ratio / (crush_ratio + 1)) * (plasmacomp * PLASMA_CRUNCH + o2comp * O2_CRUNCH + co2comp * CO2_CRUNCH + n2comp * N2_CRUNCH + n2ocomp * N2O_CRUNCH + h2comp * HYDROGEN_CRUNCH) radiation_pulse(src, 6 * power * (gas_coefficient + max(0, ((power_transmission_bonus / 10)))), GAMMA_RAD) @@ -1276,8 +1281,10 @@ #undef OXYGEN_HEAT_PENALTY #undef CO2_HEAT_PENALTY #undef NITROGEN_HEAT_PENALTY +#undef HYDROGEN_HEAT_PENALTY #undef OXYGEN_TRANSMIT_MODIFIER #undef PLASMA_TRANSMIT_MODIFIER +#undef HYDROGEN_TRANSMIT_MODIFIER #undef N2O_HEAT_RESISTANCE #undef POWERLOSS_INHIBITION_GAS_THRESHOLD #undef POWERLOSS_INHIBITION_MOLE_THRESHOLD @@ -1320,3 +1327,4 @@ #undef N2_CRUNCH #undef N2O_CRUNCH #undef PLASMA_CRUNCH +#undef HYDROGEN_CRUNCH diff --git a/code/modules/power/engines/supermatter/supermatter_event.dm b/code/modules/power/engines/supermatter/supermatter_event.dm index 50802099024..eb02a554b33 100644 --- a/code/modules/power/engines/supermatter/supermatter_event.dm +++ b/code/modules/power/engines/supermatter/supermatter_event.dm @@ -111,6 +111,15 @@ /datum/engi_event/supermatter_event/charlie_tier/heat_penalty_threshold/on_start() supermatter.heat_penalty_threshold -= 173 +// hydrogen +/datum/engi_event/supermatter_event/charlie_tier/hydrogen + name = "C-4" + +/datum/engi_event/supermatter_event/charlie_tier/hydrogen/on_start() + var/datum/gas_mixture/air = new() + air.set_hydrogen(2000) + supermatter_turf.blind_release_air(air) + //Class B events /datum/engi_event/supermatter_event/bravo_tier threat_level = SM_EVENT_THREAT_B diff --git a/code/modules/procedural_mapping/mapGeneratorModules/mapgen_helpers.dm b/code/modules/procedural_mapping/mapGeneratorModules/mapgen_helpers.dm index c04bd76573a..e47e123bb7f 100644 --- a/code/modules/procedural_mapping/mapGeneratorModules/mapgen_helpers.dm +++ b/code/modules/procedural_mapping/mapGeneratorModules/mapgen_helpers.dm @@ -18,6 +18,7 @@ air.set_toxins(T.toxins) air.set_sleeping_agent(T.sleeping_agent) air.set_agent_b(T.agent_b) + air.set_hydrogen(T.hydrogen) air.set_temperature(T.temperature) T.blind_set_air(air) diff --git a/code/modules/station_goals/bluespace_tap_events.dm b/code/modules/station_goals/bluespace_tap_events.dm index f67541db730..1f308c44f7a 100644 --- a/code/modules/station_goals/bluespace_tap_events.dm +++ b/code/modules/station_goals/bluespace_tap_events.dm @@ -30,7 +30,7 @@ /datum/engi_event/bluespace_tap_event/gas/on_start() var/datum/gas_mixture/air = new() - var/picked_gas = pick("N2O", "N2", "O2", "CO2", "Plasma", "Unknown") + var/picked_gas = pick("N2O", "N2", "O2", "CO2", "Plasma", "Unknown", "H2") switch(picked_gas) if("N2") name = "G-1" @@ -50,6 +50,9 @@ if("Unknown") name = "G-6" air.set_agent_b(250) + if("Hydrogen") + name = "G-7" + air.set_hydrogen(250) air.set_temperature(T20C) var/turf/tap_turf = get_turf(tap) diff --git a/icons/effects/tile_effects.dmi b/icons/effects/tile_effects.dmi index 2576505954c..ee2cabbaa42 100644 Binary files a/icons/effects/tile_effects.dmi and b/icons/effects/tile_effects.dmi differ diff --git a/icons/obj/atmos.dmi b/icons/obj/atmos.dmi index b781a5c3c7e..a6fe8518251 100644 Binary files a/icons/obj/atmos.dmi and b/icons/obj/atmos.dmi differ diff --git a/rust/src/milla/api.rs b/rust/src/milla/api.rs index da7db273280..c7985912e29 100644 --- a/rust/src/milla/api.rs +++ b/rust/src/milla/api.rs @@ -47,6 +47,7 @@ fn milla_create_environment( toxins: ByondValue, sleeping_agent: ByondValue, agent_b: ByondValue, + hydrogen: ByondValue, temperature: ByondValue, ) -> eyre::Result { logging::setup_panic_handler(); @@ -57,6 +58,7 @@ fn milla_create_environment( conversion::byond_to_option_f32(toxins)?, conversion::byond_to_option_f32(sleeping_agent)?, conversion::byond_to_option_f32(agent_b)?, + conversion::byond_to_option_f32(hydrogen)?, conversion::byond_to_option_f32(temperature)?, ) as f32)) } @@ -69,6 +71,7 @@ pub(crate) fn internal_create_environment( toxins: Option, sleeping_agent: Option, agent_b: Option, + hydrogen: Option, temperature: Option, ) -> u8 { let mut tile = Tile::new(); @@ -90,6 +93,9 @@ pub(crate) fn internal_create_environment( if let Some(value) = agent_b { tile.gases.set_agent_b(value); } + if let Some(value) = hydrogen { + tile.gases.set_hydrogen(value); + } if let Some(value) = temperature { tile.thermal_energy = value * tile.heat_capacity(); } @@ -112,7 +118,7 @@ fn milla_load_turfs( let data = property.get_list_values()?; property.decrement_tempref(); - if data.len() != 17 { + if data.len() != 18 { return Err(eyre!( "data property has the wrong length: {} vs {}", data.len(), @@ -137,6 +143,7 @@ fn milla_load_turfs( conversion::bounded_byond_to_option_f32(data[10], 0.0, f32::INFINITY)?, conversion::bounded_byond_to_option_f32(data[11], 0.0, f32::INFINITY)?, conversion::bounded_byond_to_option_f32(data[12], 0.0, f32::INFINITY)?, + conversion::bounded_byond_to_option_f32(data[13], 0.0, f32::INFINITY)?, None, Some(0.0), Some(0.0), @@ -148,10 +155,10 @@ fn milla_load_turfs( x as i32 - 1, y as i32 - 1, z as i32 - 1, - conversion::bounded_byond_to_option_f32(data[13], 0.0, 1.0)?, conversion::bounded_byond_to_option_f32(data[14], 0.0, 1.0)?, conversion::bounded_byond_to_option_f32(data[15], 0.0, 1.0)?, conversion::bounded_byond_to_option_f32(data[16], 0.0, 1.0)?, + conversion::bounded_byond_to_option_f32(data[17], 0.0, 1.0)?, )?; } Ok(ByondValue::null()) @@ -173,6 +180,7 @@ fn milla_set_tile( toxins: ByondValue, sleeping_agent: ByondValue, agent_b: ByondValue, + hydrogen: ByondValue, temperature: ByondValue, _innate_heat_capacity: ByondValue, hotspot_temperature: ByondValue, @@ -196,6 +204,7 @@ fn milla_set_tile( conversion::bounded_byond_to_option_f32(toxins, 0.0, f32::INFINITY)?, conversion::bounded_byond_to_option_f32(sleeping_agent, 0.0, f32::INFINITY)?, conversion::bounded_byond_to_option_f32(agent_b, 0.0, f32::INFINITY)?, + conversion::bounded_byond_to_option_f32(hydrogen, 0.0, f32::INFINITY)?, conversion::bounded_byond_to_option_f32(temperature, 0.0, f32::INFINITY)?, None, // Temporarily disabled to better match the existing system. @@ -240,6 +249,7 @@ fn milla_set_tile_airtight( None, None, None, + None, )?; Ok(ByondValue::null()) } @@ -262,6 +272,7 @@ pub(crate) fn internal_set_tile( toxins: Option, sleeping_agent: Option, agent_b: Option, + hydrogen: Option, temperature: Option, thermal_energy: Option, innate_heat_capacity: Option, @@ -332,6 +343,9 @@ pub(crate) fn internal_set_tile( if let Some(value) = agent_b { tile.gases.set_agent_b(value); } + if let Some(value) = hydrogen { + tile.gases.set_hydrogen(value); + } // Done sooner because we need innate heat capacity to calculate thermal energy from // temperature. if let Some(value) = innate_heat_capacity { @@ -763,6 +777,7 @@ mod tests { Some(1.0), None, None, + None, Some(1.0), None, Some(1.0), @@ -803,6 +818,7 @@ mod tests { Some(1.0), None, None, + None, Some(1.0), None, Some(1.0), diff --git a/rust/src/milla/constants.rs b/rust/src/milla/constants.rs index 75ba648af5d..c0015bb591e 100644 --- a/rust/src/milla/constants.rs +++ b/rust/src/milla/constants.rs @@ -59,8 +59,11 @@ pub(crate) const GAS_SLEEPING_AGENT: usize = 4; /// Index for agent b in gas list. pub(crate) const GAS_AGENT_B: usize = 5; +/// Index for hydrogen in gas list. +pub(crate) const GAS_HYDROGEN: usize = 6; + /// How many gases are there? -pub(crate) const GAS_COUNT: usize = GAS_AGENT_B + 1; +pub(crate) const GAS_COUNT: usize = GAS_HYDROGEN + 1; // should contain the gas right above it /// The two axes, Y and X. The order is arbitrary, but may break things if changed. pub(crate) const AXES: [(i32, i32); 2] = [(1, 0), (0, 1)]; @@ -103,6 +106,9 @@ pub(crate) const SPECIFIC_HEAT_SLEEPING_AGENT: f32 = 40.0; // The specific heat of agent b, in joules per kelvin-mole. pub(crate) const SPECIFIC_HEAT_AGENT_B: f32 = 300.0; +// The specific heat of hydrogen, in joules per kelvin-mole. +pub(crate) const SPECIFIC_HEAT_HYDROGEN: f32 = 15.0; + // Convenience array, so we can add loop through gases and calculate heat capacity. pub(crate) const SPECIFIC_HEATS: [f32; GAS_COUNT] = [ SPECIFIC_HEAT_OXYGEN, @@ -111,6 +117,7 @@ pub(crate) const SPECIFIC_HEATS: [f32; GAS_COUNT] = [ SPECIFIC_HEAT_TOXINS, SPECIFIC_HEAT_SLEEPING_AGENT, SPECIFIC_HEAT_AGENT_B, + SPECIFIC_HEAT_HYDROGEN, ]; /// How hot does it need to be for a plasma fire to start? @@ -131,6 +138,18 @@ pub(crate) const PLASMA_BURN_HOTSPOT_RATIO_BOOST: f32 = 10.0; /// How much oxygen do we use per plasma? pub(crate) const PLASMA_BURN_OXYGEN_PER_PLASMA: f32 = 0.4; +/// How hot does hydrogen need to be for it to ignite? +pub(crate) const HYDROGEN_MIN_IGNITE_TEMP: f32 = 500.0 + T0C; + +/// How hot does hydrogen need to be for it to burn as well as possible? +pub(crate) const HYDROGEN_OPTIMAL_BURN_TEMP: f32 = 2500.0 + T0C; + +/// How much of the hydrogen are we willing to burn each tick? +pub(crate) const HYDROGEN_BURN_MAX_RATIO: f32 = 0.07; + +/// How much oxygen do we consume for every hydrogen? +pub(crate) const HYDROGEN_BURN_OXYGEN_PER_HYDROGEN: f32 = 0.5; + /// How much thermal energy is produced, in joules per mole of agent b. pub(crate) const AGENT_B_CONVERSION_ENERGY: f32 = 20_000.0; @@ -140,6 +159,9 @@ pub(crate) const NITROUS_BREAKDOWN_ENERGY: f32 = 200_000.0; /// How much thermal energy is produced, in joules per mole of sleeping toxins. pub(crate) const PLASMA_BURN_ENERGY: f32 = 3_000_000.0; +/// How much thermal energy is produced, in joules per mole of hydrogen. +pub(crate) const HYDROGEN_BURN_ENERGY: f32 = 2_500_000.0; + /// We allow small deviations in tests as our spring chain solution is not exact. #[cfg(test)] pub(crate) const TEST_TOLERANCE: f32 = 0.1; diff --git a/rust/src/milla/model.rs b/rust/src/milla/model.rs index 838bb090cce..7c26286db47 100644 --- a/rust/src/milla/model.rs +++ b/rust/src/milla/model.rs @@ -68,6 +68,13 @@ impl GasSet { self.values[GAS_AGENT_B] = value; self.dirty.store(true, Relaxed); } + pub(crate) fn hydrogen(&self) -> f32 { + self.values[GAS_HYDROGEN] + } + pub(crate) fn set_hydrogen(&mut self, value: f32) { + self.values[GAS_HYDROGEN] = value; + self.dirty.store(true, Relaxed); + } pub(crate) fn set_dirty(&mut self) { self.dirty.store(true, Relaxed); } @@ -333,6 +340,7 @@ impl From<&Tile> for Vec { ByondValue::from(value.gases.toxins()), ByondValue::from(value.gases.sleeping_agent()), ByondValue::from(value.gases.agent_b()), + ByondValue::from(value.gases.hydrogen()), ByondValue::from(value.mode), ByondValue::from(environment_id as f32), ByondValue::from(value.superconductivity.north), @@ -413,7 +421,7 @@ impl ZLevel { ZLevel { tiles: unbuilt.into_boxed_slice().try_into().unwrap(), active_pressure_chunks: HashSet::new(), - frozen: false, + frozen: false, } } @@ -457,7 +465,7 @@ impl ZLevel { self.tiles[i].copy_from(&other.tiles[i]); } self.active_pressure_chunks = other.active_pressure_chunks.clone(); - self.frozen = other.frozen; + self.frozen = other.frozen; } } diff --git a/rust/src/milla/simulate.rs b/rust/src/milla/simulate.rs index 05cd43bd537..4c4a29fa8bd 100644 --- a/rust/src/milla/simulate.rs +++ b/rust/src/milla/simulate.rs @@ -636,13 +636,64 @@ pub(crate) fn react(my_next_tile: &mut Tile, hotspot_step: bool) { cached_heat_capacity = fraction * my_next_tile.heat_capacity(); // THEN we can add in the new thermal energy. thermal_energy += PLASMA_BURN_ENERGY * plasma_burnt; - // Recalculate temperature for any subsequent reactions. + // (or we would, but this is the last reaction) //cached_temperature = thermal_energy / cached_heat_capacity; my_next_tile.fuel_burnt += plasma_burnt; } + // Hydrogen BURNING, also know as Knallgas, which is Swedish. The more you know. + if cached_temperature > HYDROGEN_MIN_IGNITE_TEMP + && my_next_tile.gases.hydrogen() > 0.0 + && my_next_tile.gases.oxygen() > 0.0 + { + // How efficient is the burn? + // Linear scaling fom 0 to 1 as temperatue goes from minimum to optimal. + let efficiency = ((cached_temperature - HYDROGEN_MIN_IGNITE_TEMP) + / (HYDROGEN_OPTIMAL_BURN_TEMP - HYDROGEN_MIN_IGNITE_TEMP)) + .max(0.5) + .min(1.0); + + // How much hydrogen is available to burn? + let burnable_hydrogen = my_next_tile.gases.hydrogen(); + + // Actual burn amount. + let mut hydrogen_burnt = + efficiency * 2.0 * HYDROGEN_BURN_MAX_RATIO * hotspot_boost * burnable_hydrogen; + if hydrogen_burnt < PLASMA_BURN_MIN_MOLES { + // Boost up to the minimum. + hydrogen_burnt = PLASMA_BURN_MIN_MOLES.min(burnable_hydrogen); + } + if hydrogen_burnt * HYDROGEN_BURN_OXYGEN_PER_HYDROGEN + > fraction * my_next_tile.gases.oxygen() + { + // Restrict based on available oxygen. + hydrogen_burnt = + fraction * my_next_tile.gases.oxygen() / HYDROGEN_BURN_OXYGEN_PER_HYDROGEN; + } + + my_next_tile + .gases + .set_hydrogen(my_next_tile.gases.hydrogen() - hydrogen_burnt); + my_next_tile.gases.set_oxygen( + my_next_tile.gases.oxygen() - hydrogen_burnt * HYDROGEN_BURN_OXYGEN_PER_HYDROGEN, + ); + // my_next_tile + // .gases + // .set_water_vapor(my_next_tile.gases.water_vapor() + hydrogen_burnt); + + // Recalculate heat capacity. + cached_heat_capacity = fraction * my_next_tile.heat_capacity(); + // THEN we can add in the new thermal energy. + thermal_energy += HYDROGEN_BURN_ENERGY * hydrogen_burnt; + // Recalculate temperature for any subsequent reactions. + // (or we would, but this is the last reaction) + //cached_temperature = thermal_energy / cached_heat_capacity; + + my_next_tile.fuel_burnt += hydrogen_burnt; + } + if hotspot_step { adjust_hotspot(my_next_tile, thermal_energy - initial_thermal_energy); } else { diff --git a/rust/src/milla/tick.rs b/rust/src/milla/tick.rs index 971d5962e79..54d36914020 100644 --- a/rust/src/milla/tick.rs +++ b/rust/src/milla/tick.rs @@ -176,6 +176,7 @@ mod tests { .toxins(0.0) .sleeping_agent(0.0) .agent_b(0.0) + .hydrogen(0.0) .thermal_energy(100.0), '0' => TileChecker::new() // .oxygen(0.0) @@ -184,6 +185,7 @@ mod tests { .toxins(0.0) .sleeping_agent(0.0) .agent_b(0.0) + .hydrogen(0.0) .thermal_energy(0.0), '#' => TileChecker::new(), ' ' => TileChecker::new(), @@ -282,6 +284,10 @@ mod tests { self.0.gases.set_agent_b(value); self } + fn hydrogen(mut self, value: f32) -> Self { + self.0.gases.set_hydrogen(value); + self + } fn thermal_energy(mut self, value: f32) -> Self { self.0.thermal_energy = value; self @@ -306,6 +312,7 @@ mod tests { toxins_: Option, sleeping_agent_: Option, agent_b_: Option, + hydrogen: Option, thermal_energy_: Option, temperature_: Option, } @@ -319,6 +326,7 @@ mod tests { toxins_: None, sleeping_agent_: None, agent_b_: None, + hydrogen: None, thermal_energy_: None, temperature_: None, } @@ -384,6 +392,16 @@ mod tests { y ); } + if let Some(value) = self.hydrogen_ { + assert!( + (tile.gases.hydrogen() - value).abs() < TEST_TOLERANCE, + "{} != {} @ ({}, {})", + tile.gases.hydrogen(), + value, + x, + y + ); + } if let Some(value) = self.thermal_energy_ { assert!( (tile.thermal_energy - value).abs() < TEST_TOLERANCE, @@ -429,6 +447,10 @@ mod tests { self.agent_b_ = Some(value); self } + fn hydrogen(mut self, value: f32) -> Self { + self.hydrogen_ = Some(value); + self + } fn thermal_energy(mut self, value: f32) -> Self { self.thermal_energy_ = Some(value); self diff --git a/rustlibs.dll b/rustlibs.dll index 3b3eaa6a8c8..0d9effc5e87 100644 Binary files a/rustlibs.dll and b/rustlibs.dll differ diff --git a/rustlibs_prod.dll b/rustlibs_prod.dll index 0c762a6a6fa..0c3ec080181 100644 Binary files a/rustlibs_prod.dll and b/rustlibs_prod.dll differ diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-default.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-default.scss index 702640a1cb3..330d81a6491 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-default.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-default.scss @@ -747,6 +747,10 @@ span.body .coderesponses { color: teal; } +.hydrogen { + color: #997379; +} + // MARK: Boxed messages .boxed_message { background: hsl(220, 10%, 10%); diff --git a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss index 71e01498a6c..0bc8b3884a3 100644 --- a/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss +++ b/tgui/packages/tgui-panel/styles/tgchat/chat-light.scss @@ -345,6 +345,10 @@ span.body .coderesponses { color: #004d4d; } +.hydrogen { + color: #997379; +} + // MARK: Boxed messages .boxed_message { background: hsl(220, 100%, 97.5%); diff --git a/tgui/packages/tgui/constants.ts b/tgui/packages/tgui/constants.ts index 83280339c28..a20a64dbc6c 100644 --- a/tgui/packages/tgui/constants.ts +++ b/tgui/packages/tgui/constants.ts @@ -231,7 +231,7 @@ const GASES = [ 'id': 'hydrogen', 'name': 'Hydrogen', 'label': 'H₂', - 'color': 'white', + 'color': '#997379', }, { 'id': 'ab', diff --git a/tgui/packages/tgui/interfaces/AirAlarm.jsx b/tgui/packages/tgui/interfaces/AirAlarm.jsx index 5651d715734..3c41407983c 100644 --- a/tgui/packages/tgui/interfaces/AirAlarm.jsx +++ b/tgui/packages/tgui/interfaces/AirAlarm.jsx @@ -112,6 +112,11 @@ const AirStatus = (props) => { )} + {air.contents.h2 > 0.1 && ( + + + + )} {air.contents.other > 0.1 && ( { }) } /> +