Merge pull request #15370 from Putnam3145/genericized-plasma-trit

Total fire overhaul + new atmos stuff + uh oh stinky toxins nerf + sauna buff + ??
This commit is contained in:
Lin
2022-01-03 22:31:40 +00:00
committed by GitHub
25 changed files with 393 additions and 124 deletions
+51 -11
View File
@@ -43,6 +43,7 @@
)
)
fusion_power = 3
enthalpy = -393500
/datum/gas/plasma
id = GAS_PLASMA
@@ -54,7 +55,10 @@
heat_penalty = 15
transmit_modifier = 4
powermix = 1
// no fire info cause it has its own bespoke reaction for trit generation reasons
fire_burn_rate = OXYGEN_BURN_RATE_BASE // named when plasma fires were the only fires, surely
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
fire_products = "plasma_fire"
enthalpy = FIRE_PLASMA_ENERGY_RELEASED // 3000000, 3 megajoules, 3000 kj
/datum/gas/water_vapor
id = GAS_H2O
@@ -64,6 +68,7 @@
moles_visible = MOLES_GAS_VISIBLE
fusion_power = 8
heat_penalty = 8
enthalpy = -241800 // FIRE_HYDROGEN_ENERGY_RELEASED is actually what this was supposed to be
powermix = 1
breath_reagent = /datum/reagent/water
@@ -84,6 +89,7 @@
fire_products = list(GAS_N2 = 1)
oxidation_rate = 0.5
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST + 100
enthalpy = 81600
heat_resistance = 6
/datum/gas/nitryl
@@ -95,8 +101,22 @@
flags = GAS_FLAG_DANGEROUS
fusion_power = 15
fire_products = list(GAS_N2 = 0.5)
enthalpy = 33200
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
/datum/gas/hydrogen
id = GAS_HYDROGEN
specific_heat = 10
name = "Hydrogen"
flags = GAS_FLAG_DANGEROUS
fusion_power = 0
powermix = 1
heat_penalty = 3
transmit_modifier = 10
fire_products = list(GAS_H2O = 2)
fire_burn_rate = 2
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
/datum/gas/tritium
id = GAS_TRITIUM
specific_heat = 10
@@ -108,13 +128,10 @@
powermix = 1
heat_penalty = 10
transmit_modifier = 30
/*
these are for when we add hydrogen, trit gets to keep its hardcoded fire for legacy reasons
fire_provides = list(GAS_H2O = 2)
fire_products = list(GAS_H2O = 2)
fire_burn_rate = 2
fire_energy_released = FIRE_HYDROGEN_ENERGY_RELEASED
fire_radiation_released = 50 // arbitrary number, basically 60 moles of trit burning will just barely start to harm you
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST - 50
*/
/datum/gas/bz
id = GAS_BZ
@@ -124,6 +141,7 @@
fusion_power = 8
powermix = 1
heat_penalty = 5
enthalpy = FIRE_CARBON_ENERGY_RELEASED // it is a mystery
transmit_modifier = -2
radioactivity_modifier = 5
@@ -139,7 +157,8 @@
name = "Pluoxium"
fusion_power = 10
oxidation_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST * 1000 // it is VERY stable
oxidation_rate = 8
oxidation_rate = 8 // when it can oxidize, it can oxidize a LOT
enthalpy = -50000 // but it reduces the heat output a bit
powermix = -1
heat_penalty = -1
transmit_modifier = -5
@@ -172,7 +191,7 @@
alert_type = /atom/movable/screen/alert/too_much_ch4
)
)
fire_energy_released = FIRE_CARBON_ENERGY_RELEASED
enthalpy = -74600
fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
/datum/gas/methyl_bromide
@@ -192,7 +211,28 @@
alert_type = /atom/movable/screen/alert/too_much_ch3br
)
)
fire_products = list(GAS_CO2 = 1, GAS_H2O = 1.5, GAS_BZ = 0.5)
fire_energy_released = FIRE_CARBON_ENERGY_RELEASED
fire_burn_rate = 0.5
fire_products = list(GAS_CO2 = 1, GAS_H2O = 1.5, GAS_BROMINE = 0.5)
enthalpy = -35400
fire_burn_rate = 4 / 7 // oh no
fire_temperature = 808 // its autoignition, it apparently doesn't spark readily, so i don't put it lower
/datum/gas/bromine
id = GAS_BROMINE
specific_heat = 76
name = "Bromine"
flags = GAS_FLAG_DANGEROUS
group = GAS_GROUP_CHEMICALS
enthalpy = 193 // yeah it's small but it's good to include it
breath_reagent = /datum/reagent/bromine
/datum/gas/ammonia
id = GAS_AMMONIA
specific_heat = 35
name = "Ammonia"
flags = GAS_FLAG_DANGEROUS
group = GAS_GROUP_CHEMICALS
enthalpy = -45900
breath_reagent = /datum/reagent/ammonia
fire_products = list(GAS_H2O = 1.5, GAS_N2 = 0.5)
fire_burn_rate = 4/3
fire_temperature = 924
+24 -8
View File
@@ -15,6 +15,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
/proc/_auxtools_register_gas(datum/gas/gas) // makes sure auxtools knows stuff about this gas
/datum/auxgm
var/done_initializing = FALSE
var/list/datums = list()
var/list/specific_heats = list()
var/list/names = list()
@@ -32,30 +33,34 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
var/list/oxidation_temperatures = list()
var/list/oxidation_rates = list()
var/list/fire_temperatures = list()
var/list/fire_enthalpies = list()
var/list/enthalpies = list()
var/list/fire_products = list()
var/list/fire_burn_rates = list()
var/list/supermatter = list()
var/list/groups_by_gas = list()
var/list/groups = list()
/datum/gas
var/id = ""
var/specific_heat = 0
var/name = ""
var/gas_overlay = "" //icon_state in icons/effects/atmospherics.dmi
var/color = "#ffff"
var/moles_visible = null
var/flags = NONE //currently used by canisters
var/group = null // groups for scrubber/filter listing
var/fusion_power = 0 // How much the gas destabilizes a fusion reaction
var/breath_results = GAS_CO2 // what breathing this breathes out
var/breath_reagent = null // what breathing this adds to your reagents
var/breath_reagent_dangerous = null // what breathing this adds to your reagents IF it's above a danger threshold
var/datum/reagent/breath_reagent = null // what breathing this adds to your reagents
var/datum/reagent/breath_reagent_dangerous = null // what breathing this adds to your reagents IF it's above a danger threshold
var/list/breath_alert_info = null // list for alerts that pop up when you have too much/not enough of something
var/oxidation_temperature = null // temperature above which this gas is an oxidizer; null for none
var/oxidation_rate = 1 // how many moles of this can oxidize how many moles of material
var/fire_temperature = null // temperature above which gas may catch fire; null for none
var/list/fire_products = null // what results when this gas is burned (oxidizer or fuel); null for none
var/fire_energy_released = 0 // how much energy is released per mole of fuel burned
var/enthalpy = 0 // Standard enthalpy of formation in joules, used for fires
var/fire_burn_rate = 1 // how many moles are burned per product released
var/fire_radiation_released = 0 // How much radiation is released when this gas burns
var/powermix = 0 // how much this gas contributes to the supermatter's powermix ratio
var/heat_penalty = 0 // heat and waste penalty from having the supermatter crystal surrounded by this gas; negative numbers reduce
var/transmit_modifier = 0 // bonus to supermatter power generation (multiplicative, since it's % based, and divided by 10)
@@ -94,21 +99,31 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
breath_reagents[g] = gas.breath_reagent
if(gas.breath_reagent_dangerous)
breath_reagents_dangerous[g] = gas.breath_reagent_dangerous
if(gas.oxidation_temperature)
oxidation_temperatures[g] = gas.oxidation_temperature
oxidation_rates[g] = gas.oxidation_rate
if(gas.fire_products)
fire_products[g] = gas.fire_products
fire_enthalpies[g] = gas.fire_energy_released
enthalpies[g] = gas.enthalpy
else if(gas.fire_temperature)
fire_temperatures[g] = gas.fire_temperature
fire_burn_rates[g] = gas.fire_burn_rate
if(gas.fire_products)
fire_products[g] = gas.fire_products
fire_enthalpies[g] = gas.fire_energy_released
enthalpies[g] = gas.enthalpy
if(gas.group)
if(!(gas.group in groups))
groups[gas.group] = list()
groups[gas.group] += gas
groups_by_gas[g] = gas.group
add_supermatter_properties(gas)
_auxtools_register_gas(gas)
if(done_initializing)
for(var/r in SSair.gas_reactions)
var/datum/gas_reaction/R = r
R.init_reqs()
SSair.auxtools_update_reactions()
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_GAS, g)
/proc/finalize_gas_refs()
@@ -127,6 +142,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA
for(var/breathing_class_path in subtypesof(/datum/breathing_class))
var/datum/breathing_class/class = new breathing_class_path
breathing_classes[breathing_class_path] = class
done_initializing = TRUE
finalize_gas_refs()
@@ -53,23 +53,68 @@
id = "vapor"
/datum/gas_reaction/water_vapor/init_reqs()
min_requirements = list(GAS_H2O = MOLES_GAS_VISIBLE)
min_requirements = list(
GAS_H2O = MOLES_GAS_VISIBLE,
"MAX_TEMP" = T0C + 40
)
/datum/gas_reaction/water_vapor/react(datum/gas_mixture/air, datum/holder)
var/turf/open/location = isturf(holder) ? holder : null
. = NO_REACTION
var/turf/open/location = holder
if(!istype(location))
return NO_REACTION
if (air.return_temperature() <= WATER_VAPOR_FREEZE)
if(location && location.freon_gas_act())
. = REACTING
return REACTING
else if(location && location.water_vapor_gas_act())
air.adjust_moles(GAS_H2O,-MOLES_GAS_VISIBLE)
. = REACTING
return REACTING
// no test cause it's entirely based on location
/datum/gas_reaction/condensation
priority = 0
name = "Condensation"
id = "condense"
exclude = TRUE
var/datum/reagent/condensing_reagent
/datum/gas_reaction/condensation/New(datum/reagent/R)
. = ..()
if(!istype(R))
return
min_requirements = list(
"MAX_TEMP" = initial(R.boiling_point)
)
min_requirements[R.get_gas()] = MOLES_GAS_VISIBLE
name = "[R.name] condensation"
id = "[R.type] condensation"
condensing_reagent = R
exclude = FALSE
/datum/gas_reaction/condensation/react(datum/gas_mixture/air, datum/holder)
. = NO_REACTION
var/turf/open/location = holder
if(!istype(location))
return
var/temperature = air.return_temperature()
var/static/datum/reagents/reagents_holder = new
reagents_holder.clear_reagents()
reagents_holder.chem_temp = temperature
var/G = condensing_reagent.get_gas()
var/amt = air.get_moles(G)
air.adjust_moles(G, -min(initial(condensing_reagent.condensation_amount), amt))
reagents_holder.add_reagent(condensing_reagent, amt)
. = REACTING
for(var/atom/movable/AM in location)
if(location.intact && AM.level == 1)
continue
reagents_holder.reaction(AM, TOUCH)
reagents_holder.reaction(location, TOUCH)
//tritium combustion: combustion of oxygen and tritium (treated as hydrocarbons). creates hotspots. exothermic
/datum/gas_reaction/tritfire
priority = -1 //fire should ALWAYS be last, but tritium fires happen before plasma fires
exclude = TRUE // generic fire now takes care of this
name = "Tritium Combustion"
id = "tritfire"
@@ -88,9 +133,9 @@
item.temperature_expose(air, temperature, CELL_VOLUME)
location.temperature_expose(air, temperature, CELL_VOLUME)
/proc/radiation_burn(turf/open/location, energy_released)
/proc/radiation_burn(turf/open/location, rad_power)
if(istype(location) && prob(10))
radiation_pulse(location, energy_released/TRITIUM_BURN_RADIOACTIVITY_FACTOR)
radiation_pulse(location, rad_power)
/datum/gas_reaction/tritfire/react(datum/gas_mixture/air, datum/holder)
var/energy_released = 0
@@ -151,6 +196,7 @@
/datum/gas_reaction/plasmafire
priority = -2 //fire should ALWAYS be last, but plasma fires happen after tritium fires
name = "Plasma Combustion"
exclude = TRUE // generic fire now takes care of this
id = "plasmafire"
/datum/gas_reaction/plasmafire/init_reqs()
@@ -300,7 +346,7 @@
fuels[fuel] *= oxidation_ratio
fuels += oxidizers
var/list/fire_products = GLOB.gas_data.fire_products
var/list/fire_enthalpies = GLOB.gas_data.fire_enthalpies
var/list/fire_enthalpies = GLOB.gas_data.enthalpies
for(var/fuel in fuels + oxidizers)
var/amt = fuels[fuel]
if(!burn_results[fuel])
@@ -535,7 +535,7 @@
for(var/device_id in A.air_scrub_names)
send_signal(device_id, list(
"power" = 1,
"set_filters" = list(GAS_CO2, GAS_MIASMA),
"set_filters" = list(GAS_CO2, GAS_MIASMA, GAS_GROUP_CHEMICALS),
"scrubbing" = 1,
"widenet" = 0,
))
@@ -554,6 +554,7 @@
GAS_MIASMA,
GAS_PLASMA,
GAS_H2O,
GAS_HYDROGEN,
GAS_HYPERNOB,
GAS_NITROUS,
GAS_NITRYL,
@@ -562,7 +563,8 @@
GAS_STIMULUM,
GAS_PLUOXIUM,
GAS_METHANE,
GAS_METHYL_BROMIDE
GAS_METHYL_BROMIDE,
GAS_GROUP_CHEMICALS
),
"scrubbing" = 1,
"widenet" = 1,
@@ -582,9 +584,16 @@
))
for(var/device_id in A.air_vent_names)
send_signal(device_id, list(
"is_pressurizing" = 1,
"power" = 1,
"checks" = 1,
"set_external_pressure" = ONE_ATMOSPHERE*2
"set_external_pressure" = ONE_ATMOSPHERE*1.4
))
send_signal(device_id, list(
"is_siphoning" = 1,
"power" = 1,
"checks" = 1,
"set_external_pressure" = ONE_ATMOSPHERE/1.4
))
if(AALARM_MODE_REFILL)
for(var/device_id in A.air_scrub_names)
@@ -596,10 +605,15 @@
))
for(var/device_id in A.air_vent_names)
send_signal(device_id, list(
"is_pressurizing" = 1,
"power" = 1,
"checks" = 1,
"set_external_pressure" = ONE_ATMOSPHERE * 3
))
send_signal(device_id, list(
"is_siphoning" = 1,
"power" = 0,
))
if(AALARM_MODE_PANIC,
AALARM_MODE_REPLACEMENT)
for(var/device_id in A.air_scrub_names)
@@ -610,8 +624,14 @@
))
for(var/device_id in A.air_vent_names)
send_signal(device_id, list(
"is_pressurizing" = 1,
"power" = 0
))
send_signal(device_id, list(
"is_siphoning" = 1,
"power" = 1,
"checks" = 0
))
if(AALARM_MODE_SIPHON)
for(var/device_id in A.air_scrub_names)
send_signal(device_id, list(
@@ -621,9 +641,14 @@
))
for(var/device_id in A.air_vent_names)
send_signal(device_id, list(
"is_pressurizing" = 1,
"power" = 0
))
send_signal(device_id, list(
"is_siphoning" = 1,
"power" = 1,
"checks" = 0
))
if(AALARM_MODE_OFF)
for(var/device_id in A.air_scrub_names)
send_signal(device_id, list(
@@ -641,8 +666,12 @@
for(var/device_id in A.air_vent_names)
send_signal(device_id, list(
"power" = 1,
"checks" = 2,
"set_internal_pressure" = 0
"checks" = 0,
"is_pressurizing" = 1
))
send_signal(device_id, list(
"power" = 0,
"is_siphoning" = 1
))
/obj/machinery/airalarm/update_icon_state()
@@ -100,7 +100,10 @@
if(transfer_ratio > 0)
if(filter_type && air2.return_pressure() <= 9000)
air1.scrub_into(air2, transfer_ratio, list(filter_type))
if(filter_type in GLOB.gas_data.groups)
air1.scrub_into(air2, transfer_ratio, GLOB.gas_data.groups[filter_type])
else
air1.scrub_into(air2, transfer_ratio, list(filter_type))
if(air3.return_pressure() <= 9000)
air1.transfer_ratio_to(air3, transfer_ratio)
@@ -125,8 +128,10 @@
data["filter_types"] = list()
data["filter_types"] += list(list("name" = "Nothing", "id" = "", "selected" = !filter_type))
for(var/id in GLOB.gas_data.ids)
data["filter_types"] += list(list("name" = GLOB.gas_data.names[id], "id" = id, "selected" = (id == filter_type)))
if(!(id in GLOB.gas_data.groups_by_gas))
data["filter_types"] += list(list("name" = GLOB.gas_data.names[id], "id" = id, "selected" = (id == filter_type)))
for(var/group in GLOB.gas_data.groups)
data["filter_types"] += list(list("name" = group, "id" = group, "selected" = (group == filter_type)))
return data
/obj/machinery/atmospherics/components/trinary/filter/ui_act(action, params)
@@ -178,6 +178,9 @@
var/mob/signal_sender = signal.data["user"]
if((("is_siphoning" in signal.data) && pump_direction == RELEASING) || (("is_pressurizing" in signal.data) && pump_direction == SIPHONING))
return
if("purge" in signal.data)
pressure_checks &= ~EXT_BOUND
pump_direction = SIPHONING
@@ -18,7 +18,8 @@
var/id_tag = null
var/scrubbing = SCRUBBING //0 = siphoning, 1 = scrubbing
var/filter_types = list(GAS_CO2)
var/filter_types = list(GAS_CO2, GAS_MIASMA, GAS_GROUP_CHEMICALS)
var/list/clean_filter_types = null
var/volume_rate = 200
var/widenet = 0 //is this scrubber acting on the 3x3 area around it.
var/list/turf/adjacent_turfs = list()
@@ -34,6 +35,16 @@
..()
if(!id_tag)
id_tag = assign_uid_vents()
generate_clean_filter_types()
RegisterSignal(SSdcs,COMSIG_GLOB_NEW_GAS,.proc/generate_clean_filter_types)
/obj/machinery/atmospherics/components/unary/vent_scrubber/proc/generate_clean_filter_types()
clean_filter_types = list()
for(var/id in filter_types)
if(id in GLOB.gas_data.groups)
clean_filter_types += GLOB.gas_data.groups[id]
else
clean_filter_types += id
/obj/machinery/atmospherics/components/unary/vent_scrubber/Destroy()
var/area/A = get_base_area(src)
@@ -95,7 +106,11 @@
var/list/f_types = list()
for(var/id in GLOB.gas_data.ids)
f_types += list(list("gas_id" = id, "gas_name" = GLOB.gas_data.names[id], "enabled" = (id in filter_types)))
if(!(id in GLOB.gas_data.groups_by_gas))
f_types += list(list("gas_id" = id, "gas_name" = GLOB.gas_data.names[id], "enabled" = (id in filter_types)))
for(var/group in GLOB.gas_data.groups)
f_types += list(list("gas_id" = group, "gas_name" = group, "enabled" = (group in filter_types)))
var/datum/signal/signal = new(list(
"tag" = id_tag,
@@ -147,11 +162,11 @@
var/datum/gas_mixture/environment = tile.return_air()
var/datum/gas_mixture/air_contents = airs[1]
if(air_contents.return_pressure() >= 50*ONE_ATMOSPHERE || !islist(filter_types))
if(air_contents.return_pressure() >= 50*ONE_ATMOSPHERE || !islist(clean_filter_types))
return FALSE
if(scrubbing & SCRUBBING)
environment.scrub_into(air_contents, volume_rate/environment.return_volume(), filter_types)
environment.scrub_into(air_contents, volume_rate/environment.return_volume(), clean_filter_types)
tile.air_update_turf()
@@ -205,11 +220,13 @@
if("toggle_filter" in signal.data)
filter_types ^= signal.data["toggle_filter"]
generate_clean_filter_types()
if("set_filters" in signal.data)
filter_types = list()
for(var/gas in signal.data["set_filters"])
filter_types += gas
generate_clean_filter_types()
if("init" in signal.data)
name = signal.data["init"]
+6 -7
View File
@@ -825,7 +825,7 @@
pH = REAGENT_NORMAL_PH
return 0
/datum/reagents/proc/reaction(atom/A, method = TOUCH, volume_modifier = 1, show_message = 1)
/datum/reagents/proc/reaction(atom/A, method = TOUCH, volume_modifier = 1, show_message = 1, from_gas = 0)
var/react_type
if(isliving(A))
react_type = "LIVING"
@@ -849,7 +849,7 @@
touch_protection = L.get_permeability_protection()
R.reaction_mob(A, method, R.volume * volume_modifier, show_message, touch_protection)
if("TURF")
R.reaction_turf(A, R.volume * volume_modifier, show_message)
R.reaction_turf(A, R.volume * volume_modifier, show_message, from_gas)
if("OBJ")
R.reaction_obj(A, R.volume * volume_modifier, show_message)
@@ -859,17 +859,16 @@
return FALSE
//Returns the average specific heat for all reagents currently in this holder.
/datum/reagents/proc/specific_heat()
/datum/reagents/proc/heat_capacity()
. = 0
var/cached_amount = total_volume //cache amount
var/list/cached_reagents = reagent_list //cache reagents
for(var/I in cached_reagents)
var/datum/reagent/R = I
. += R.specific_heat * (R.volume / cached_amount)
. += R.specific_heat * R.volume
/datum/reagents/proc/adjust_thermal_energy(J, min_temp = 2.7, max_temp = 1000)
var/S = specific_heat()
chem_temp = clamp(chem_temp + (J / (S * total_volume)), min_temp, max_temp)
var/S = heat_capacity()
chem_temp = clamp(chem_temp + (J / S), min_temp, max_temp)
if(istype(my_atom, /obj/item/reagent_containers))
var/obj/item/reagent_containers/RC = my_atom
RC.temp_check()
@@ -390,11 +390,11 @@
var/datum/reagent/R = GLOB.chemical_reagents_list[reagent]
if(R)
var/state = "Unknown"
if(initial(R.reagent_state) == 1)
if(initial(R.reagent_state) == SOLID)
state = "Solid"
else if(initial(R.reagent_state) == 2)
else if(initial(R.reagent_state) == LIQUID)
state = "Liquid"
else if(initial(R.reagent_state) == 3)
else if(initial(R.reagent_state) == GAS)
state = "Gas"
var/const/P = 3 //The number of seconds between life ticks
var/T = initial(R.metabolization_rate) * (60 / P)
+58 -3
View File
@@ -53,6 +53,10 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
var/chemical_flags = REAGENT_ORGANIC_PROCESS // See fermi/readme.dm REAGENT_DEAD_PROCESS, REAGENT_DONOTSPLIT, REAGENT_ONLYINVERSE, REAGENT_ONMOBMERGE, REAGENT_INVISIBLE, REAGENT_FORCEONNEW, REAGENT_SNEAKYNAME, REAGENT_ORGANIC_PROCESS, REAGENT_ROBOTIC_PROCESS
var/value = REAGENT_VALUE_NONE //How much does it sell for in cargo?
var/datum/material/material //are we made of material?
var/gas = null //do we have an associated gas? (expects a string, not a datum typepath!)
var/boiling_point = null // point at which this gas boils; if null, will never boil (and thus not become a gas)
var/condensation_amount = 1
var/molarity = 5 // How many units per mole of this reagent. Technically this is INVERSE molarity, but hey.
/datum/reagent/New()
. = ..()
@@ -77,10 +81,23 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
return 1
/datum/reagent/proc/reaction_obj(obj/O, volume)
return
if(O && volume && boiling_point)
var/temp = holder ? holder.chem_temp : T20C
if(temp > boiling_point)
O.atmos_spawn_air("[get_gas()]=[volume/molarity];TEMP=[temp]")
/datum/reagent/proc/reaction_turf(turf/T, volume)
return
/datum/reagent/proc/reaction_turf(turf/T, volume, show_message, from_gas)
if(!from_gas && boiling_point)
var/temp = holder?.chem_temp
if(!temp)
if(isopenturf(T))
var/turf/open/O = T
var/datum/gas_mixture/air = O.return_air()
temp = air.return_temperature()
else
temp = T20C
if(temp > boiling_point)
T.atmos_spawn_air("[get_gas()]=[volume/molarity];TEMP=[temp]")
/datum/reagent/proc/on_mob_life(mob/living/carbon/M)
current_cycle++
@@ -235,6 +252,44 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
return rs.Join(" | ")
/datum/reagent/proc/define_gas()
if(reagent_state == SOLID)
return null // doesn't make that much sense
var/list/cached_reactions = GLOB.chemical_reactions_list
for(var/reaction in cached_reactions[src.type])
var/datum/chemical_reaction/C = reaction
if(!istype(C))
continue
if(C.required_reagents.len < 2) // no reagents that react on their own
return null
var/datum/gas/G = new
G.id = "[src.type]"
G.name = name
G.specific_heat = specific_heat / 10
G.color = color
G.breath_reagent = src.type
G.group = GAS_GROUP_CHEMICALS
return G
/datum/reagent/proc/create_gas()
var/datum/gas/G = define_gas()
if(istype(G)) // if this reagent should never be a gas, define_gas may return null
GLOB.gas_data.add_gas(G)
var/datum/gas_reaction/condensation/condensation_reaction = new(src) // did you know? you can totally just add new reactions at runtime. it's allowed
SSair.add_reaction(condensation_reaction)
return G
/datum/reagent/proc/get_gas()
if(gas)
return gas
else
var/datum/auxgm/cached_gas_data = GLOB.gas_data
. = "[src.type]"
if(!(. in cached_gas_data.ids))
create_gas()
//For easy bloodsucker disgusting and blood removal
/datum/reagent/proc/disgust_bloodsucker(mob/living/carbon/C, disgust, blood_change, blood_puke = TRUE, force)
if(AmBloodsucker(C))
@@ -14,6 +14,7 @@
taste_description = "alcohol"
var/boozepwr = 65 //Higher numbers equal higher hardness, higher hardness equals more intense alcohol poisoning
pH = 7.33
boiling_point = 351.38
value = REAGENT_VALUE_VERY_COMMON //don't bother tweaking all drinks values, way too many can easily be done roundstart or with an upgraded dispenser.
/*
@@ -85,6 +86,31 @@ All effects don't start immediately, but rather get worse over time; the rate is
// +10% success propability on each step, useful while operating in less-than-perfect conditions
return ..()
/datum/reagent/consumable/ethanol/define_gas() // So that all alcohols have the same gas, i.e. "ethanol"
var/datum/gas/G = new
G.id = GAS_ETHANOL
G.name = "Ethanol"
G.enthalpy = -234800
G.specific_heat = 38
G.fire_products = list(GAS_CO2 = 1, GAS_H2O = 1.5)
G.fire_burn_rate = 1 / 3
G.fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
G.color = "#404030"
G.breath_reagent = /datum/reagent/consumable/ethanol
G.group = GAS_GROUP_CHEMICALS
return G
/datum/reagent/consumable/ethanol/get_gas()
var/datum/auxgm/cached_gas_data = GLOB.gas_data
. = GAS_ETHANOL
if(!(. in cached_gas_data.ids))
var/datum/gas/G = define_gas()
if(istype(G))
cached_gas_data.add_gas(G)
else // this codepath should probably not happen at all, since we never use get_gas() on anything with no boiling point
return null
/datum/reagent/consumable/ethanol/beer
name = "Beer"
description = "An alcoholic beverage brewed since ancient times on Old Earth. Still popular today."
@@ -909,20 +909,11 @@
description = "A colorless, odorless gas. Grows on trees but is still pretty valuable."
reagent_state = GAS
color = "#808080" // rgb: 128, 128, 128
gas = GAS_O2
boiling_point = 90.188
taste_mult = 0 // oderless and tasteless
pH = 9.2//It's acutally a huge range and very dependant on the chemistry but pH is basically a made up var in it's implementation anyways
/datum/reagent/oxygen/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
return 0
var/temp = holder ? holder.chem_temp : T20C
O.atmos_spawn_air("o2=[reac_volume/2];TEMP=[temp]")
/datum/reagent/oxygen/reaction_turf(turf/open/T, reac_volume)
if(istype(T))
var/temp = holder ? holder.chem_temp : T20C
T.atmos_spawn_air("o2=[reac_volume/2];TEMP=[temp]")
return
molarity = 2
/datum/reagent/copper
name = "Copper"
@@ -943,26 +934,18 @@
name = "Nitrogen"
description = "A colorless, odorless, tasteless gas. A simple asphyxiant that can silently displace vital oxygen."
reagent_state = GAS
gas = GAS_N2
boiling_point = 77.355
color = "#808080" // rgb: 128, 128, 128
taste_mult = 0
/datum/reagent/nitrogen/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
return 0
var/temp = holder ? holder.chem_temp : T20C
O.atmos_spawn_air("n2=[reac_volume/2];TEMP=[temp]")
/datum/reagent/nitrogen/reaction_turf(turf/open/T, reac_volume)
if(istype(T))
var/temp = holder ? holder.chem_temp : T20C
T.atmos_spawn_air("n2=[reac_volume/2];TEMP=[temp]")
return
molarity = 2
/datum/reagent/hydrogen
name = "Hydrogen"
description = "A colorless, odorless, nonmetallic, tasteless, highly combustible diatomic gas."
reagent_state = GAS
gas = GAS_HYDROGEN
boiling_point = 20.271
color = "#808080" // rgb: 128, 128, 128
taste_mult = 0
pH = 0.1//Now I'm stuck in a trap of my own design. Maybe I should make -ve pHes? (not 0 so I don't get div/0 errors)
@@ -1015,9 +998,10 @@
name = "Chlorine"
description = "A pale yellow gas that's well known as an oxidizer. While it forms many harmless molecules in its elemental form it is far from harmless."
reagent_state = GAS
color = "#808080" // rgb: 128, 128, 128
color = "#c0c0a0" // rgb: 192, 192, 160
taste_description = "chlorine"
pH = 7.4
boiling_point = 239.11
// You're an idiot for thinking that one of the most corrosive and deadly gasses would be beneficial
/datum/reagent/chlorine/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user)
@@ -1291,7 +1275,15 @@
glass_name = "glass of welder fuel"
glass_desc = "Unless you're an industrial tool, this is probably not safe for consumption."
pH = 4
boiling_point = 400
/datum/reagent/fuel/define_gas()
var/datum/gas/G = ..()
G.enthalpy = 227400
G.fire_burn_rate = 2 / 5
G.fire_products = list(GAS_CO2 = 2, GAS_H2O = 1)
G.fire_temperature = T0C+300
return G
/datum/reagent/fuel/reaction_mob(mob/living/M, method=TOUCH, reac_volume)//Splashing people with welding fuel to make them easy to ignite!
if(method == TOUCH || method == VAPOR)
@@ -1309,6 +1301,7 @@
description = "A compound used to clean things. Now with 50% more sodium hypochlorite!"
color = "#A5F0EE" // rgb: 165, 240, 238
taste_description = "sourness"
boiling_point = T0C+50
pH = 5.5
/datum/reagent/space_cleaner/reaction_obj(obj/O, reac_volume)
@@ -1321,6 +1314,7 @@
O.clean_blood()
/datum/reagent/space_cleaner/reaction_turf(turf/T, reac_volume)
..()
if(reac_volume >= 1)
T.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
SEND_SIGNAL(T, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_WEAK)
@@ -1488,6 +1482,7 @@
name = "Ammonia"
description = "A caustic substance commonly used in fertilizer or household cleaners."
reagent_state = GAS
gas = GAS_AMMONIA
color = "#404030" // rgb: 64, 64, 48
taste_description = "mordant"
pH = 11.6
@@ -1506,8 +1501,17 @@
description = "A secondary amine, mildly corrosive."
color = "#604030" // rgb: 96, 64, 48
taste_description = "iron"
boiling_point = 328
pH = 12
/datum/reagent/diethylamine/define_gas()
var/datum/gas/G = ..()
G.fire_burn_rate = 1 / 6
G.fire_products = list(GAS_H2O = 4, GAS_AMMONIA = 1, GAS_CO2 = 4)
G.enthalpy = -131000
G.fire_temperature = FIRE_MINIMUM_TEMPERATURE_TO_EXIST
return G
// This is more bad ass, and pests get hurt by the corrosive nature of it, not the plant. The new trade off is it culls stability.
/datum/reagent/diethylamine/on_hydroponics_apply(obj/item/seeds/myseed, datum/reagents/chems, obj/machinery/hydroponics/mytray, mob/user)
. = ..()
@@ -1524,40 +1528,23 @@
description = "A gas commonly produced by burning carbon fuels. You're constantly producing this in your lungs."
color = "#B0B0B0" // rgb : 192, 192, 192
taste_description = "something unknowable"
boiling_point = 195.68 // technically sublimation, not boiling, but same deal
molarity = 5
gas = GAS_CO2
pH = 6
/datum/reagent/carbondioxide/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
return 0
var/temp = holder ? holder.chem_temp : T20C
O.atmos_spawn_air("co2=[reac_volume/5];TEMP=[temp]")
/datum/reagent/carbondioxide/reaction_turf(turf/open/T, reac_volume)
if(istype(T))
var/temp = holder ? holder.chem_temp : T20C
T.atmos_spawn_air("co2=[reac_volume/5];TEMP=[temp]")
return
/datum/reagent/nitrous_oxide
name = "Nitrous Oxide"
description = "A potent oxidizer used as fuel in rockets and as an anaesthetic during surgery."
reagent_state = LIQUID
metabolization_rate = 1.5 * REAGENTS_METABOLISM
color = "#808080"
boiling_point = 184.67
molarity = 5
gas = GAS_NITROUS
taste_description = "sweetness"
pH = 5.8
/datum/reagent/nitrous_oxide/reaction_obj(obj/O, reac_volume)
if((!O) || (!reac_volume))
return 0
var/temp = holder ? holder.chem_temp : T20C
O.atmos_spawn_air("n2o=[reac_volume/5];TEMP=[temp]")
/datum/reagent/nitrous_oxide/reaction_turf(turf/open/T, reac_volume)
if(istype(T))
var/temp = holder ? holder.chem_temp : T20C
T.atmos_spawn_air("n2o=[reac_volume/5];TEMP=[temp]")
/datum/reagent/nitrous_oxide/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
if(method == VAPOR)
M.drowsyness += max(round(reac_volume, 1), 2)
@@ -1576,9 +1563,11 @@
name = "Stimulum"
description = "An unstable experimental gas that greatly increases the energy of those that inhale it"
reagent_state = GAS
gas = GAS_STIMULUM
metabolization_rate = 1.5 * REAGENTS_METABOLISM
chemical_flags = REAGENT_ALL_PROCESS
color = "E1A116"
boiling_point = 150
taste_description = "sourness"
value = REAGENT_VALUE_EXCEPTIONAL
@@ -1602,9 +1591,11 @@
name = "Nitryl"
description = "A highly reactive gas that makes you feel faster"
reagent_state = GAS
gas = GAS_NITRYL
metabolization_rate = REAGENTS_METABOLISM
color = "90560B"
color = "#90560B"
taste_description = "burning"
boiling_point = 294.3
pH = 2
value = REAGENT_VALUE_VERY_RARE
@@ -1811,6 +1802,8 @@
reagent_state = LIQUID
color = "#b37740"
taste_description = "chemicals"
gas = GAS_BROMINE
boiling_point = 332
pH = 7.8
/datum/reagent/phenol
@@ -2482,6 +2475,7 @@
var/decal_path = /obj/effect/decal/cleanable/semen
/datum/reagent/consumable/semen/reaction_turf(turf/T, reac_volume)
..()
if(!istype(T))
return
if(reac_volume < 10)
@@ -47,6 +47,10 @@
metabolization_rate = 4
chemical_flags = REAGENT_ALL_PROCESS
taste_description = "burning"
/* no gaseous CLF3 until i can think of a good way to get it to burn that doesn't destroy matter in mysterious ways
boiling_point = 289.4
*/
condensation_amount = 2
value = REAGENT_VALUE_COMMON
/datum/reagent/clf3/on_mob_life(mob/living/carbon/M)
@@ -84,6 +88,12 @@
if(!locate(/obj/effect/hotspot) in M.loc)
new /obj/effect/hotspot(M.loc)
/datum/reagent/clf3/define_gas()
var/datum/gas/G = ..()
G.enthalpy = -163200
G.oxidation_temperature = T0C - 50
return G
/datum/reagent/sorium
name = "Sorium"
description = "Sends everything flying from the detonation point."
@@ -152,8 +162,17 @@
reagent_state = LIQUID
color = "#FA00AF"
taste_description = "burning"
boiling_point = T20C-10
value = REAGENT_VALUE_UNCOMMON
/datum/reagent/phlogiston/define_gas()
var/datum/gas/G = ..()
G.enthalpy = FIRE_PLASMA_ENERGY_RELEASED / 100
G.fire_products = list(GAS_O2 = 0.25, GAS_METHANE = 0.75) // meanwhile this is just magic
G.fire_burn_rate = 1
G.fire_temperature = T20C+1
return G
/datum/reagent/phlogiston/reaction_mob(mob/living/M, method=TOUCH, reac_volume)
M.adjust_fire_stacks(1)
var/burndmg = max(0.3*M.fire_stacks, 0.3)
@@ -288,6 +307,9 @@
taste_description = "the inside of a fire extinguisher"
value = REAGENT_VALUE_UNCOMMON
/datum/reagent/firefighting_foam/define_gas()
return null
/datum/reagent/firefighting_foam/reaction_turf(turf/open/T, reac_volume)
if (!istype(T))
return
+1 -1
View File
@@ -248,7 +248,7 @@
for(var/gas in breath.get_gases())
if(gas in breath_reagents)
var/datum/reagent/R = breath_reagents[gas]
H.reagents.add_reagent(R, PP(breath,gas))
H.reagents.add_reagent(R, breath.get_moles(gas) * initial(R.molarity))
mole_adjustments[gas] = (gas in mole_adjustments) ? mole_adjustments[gas] - breath.get_moles(gas) : -breath.get_moles(gas)
for(var/gas in mole_adjustments)
+5 -4
View File
@@ -1,6 +1,7 @@
/datum/unit_test/reactions/Run()
for(var/datum/gas_reaction/G in SSair.gas_reactions)
var/test_info = G.test()
if(!test_info["success"])
var/message = test_info["message"]
Fail("Gas reaction [G.name] is failing its unit test with the following message: [message]")
if(!G.exclude)
var/test_info = G.test()
if(!test_info["success"])
var/message = test_info["message"]
Fail("Gas reaction [G.name] is failing its unit test with the following message: [message]")