diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm index a990ed34c1..55c7fc9a48 100644 --- a/code/__DEFINES/atmospherics.dm +++ b/code/__DEFINES/atmospherics.dm @@ -265,6 +265,8 @@ #define GAS_METHANE "methane" #define GAS_METHYL_BROMIDE "methyl_bromide" #define GAS_BROMINE "bromine" +#define GAS_AMMONIA "ammonia" +#define GAS_FLUORINE "fluorine" #define GAS_GROUP_CHEMICALS "Chemicals" diff --git a/code/modules/atmospherics/gasmixtures/auxgm.dm b/code/modules/atmospherics/gasmixtures/auxgm.dm index ddf97da76f..7fb8f97093 100644 --- a/code/modules/atmospherics/gasmixtures/auxgm.dm +++ b/code/modules/atmospherics/gasmixtures/auxgm.dm @@ -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() @@ -24,6 +25,7 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA var/list/ids = list() var/list/typepaths = list() var/list/fusion_powers = list() + var/list/turf_reagents = list() var/list/breathing_classes = list() var/list/breath_results = list() var/list/breath_reagents = list() @@ -39,19 +41,20 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA 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/turf_reagent = null + 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 @@ -98,7 +101,8 @@ 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.turf_reagent) + turf_reagents[g] = gas.turf_reagent if(gas.oxidation_temperature) oxidation_temperatures[g] = gas.oxidation_temperature oxidation_rates[g] = gas.oxidation_rate @@ -118,6 +122,11 @@ GLOBAL_LIST_INIT(nonreactive_gases, typecacheof(list(GAS_O2, GAS_N2, GAS_CO2, GA 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() /proc/finalize_gas_refs() @@ -136,6 +145,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() diff --git a/code/modules/atmospherics/gasmixtures/reactions.dm b/code/modules/atmospherics/gasmixtures/reactions.dm index a3012d9399..9a1f1a7d41 100644 --- a/code/modules/atmospherics/gasmixtures/reactions.dm +++ b/code/modules/atmospherics/gasmixtures/reactions.dm @@ -59,17 +59,62 @@ ) /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/reagent_stuff + priority = 0 + name = "Condensation" + id = "condense" + +/datum/gas_reaction/condensation/init_reqs() + var/highest_condensation_temp = -INFINITY + var/list/reagents = GLOB.gas_data.turf_reagents + for(var/gas in reagents) + var/datum/reagent/R = reagents[gas] + highest_condensation_temp = max(highest_condensation_temp, initial(R.boiling_point)) + min_requirements = list( + "MAX_TEMP" = highest_condensation_temp, + "ANY_REAGENT" = 1 + ) + +/datum/gas_reaction/condensation/react(datum/gas_mixture/air, datum/holder) + var/turf/open/location = holder + if(!istype(location)) + return NO_REACTION + var/list/gas_reagents = GLOB.gas_data.turf_reagents + var/temperature = air.return_temperature() + . = NO_REACTION + var/static/datum/reagents/reagents_holder = new + reagents_holder.clear_reagents() + reagents_holder.chem_temp = temperature + for(var/G in air.get_gases()) + if(G in gas_reagents) + var/datum/reagent/R = gas_reagents[G] + if(temperature < initial(R.boiling_point)) + var/amt = air.get_moles(G) + air.adjust_moles(G, -min(initial(R.condensation_amount), amt)) + reagents_holder.add_reagent(R, amt) + . = REACTING + if(. == REACTING) + for(var/atom/movable/AM in location) + if(location.intact && AM.level == 1) //hidden under the floor + 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 diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm index 922e14e580..9280f28bf9 100644 --- a/code/modules/reagents/chemistry/holder.dm +++ b/code/modules/reagents/chemistry/holder.dm @@ -823,7 +823,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" @@ -847,7 +847,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) @@ -857,17 +857,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() diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm index 285ef70433..eb4a8f265b 100644 --- a/code/modules/reagents/chemistry/machinery/chem_master.dm +++ b/code/modules/reagents/chemistry/machinery/chem_master.dm @@ -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) diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm index 154a58cdfd..534dc924fe 100644 --- a/code/modules/reagents/chemistry/reagents.dm +++ b/code/modules/reagents/chemistry/reagents.dm @@ -53,6 +53,9 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) var/chemical_flags // See fermi/readme.dm REAGENT_DEAD_PROCESS, REAGENT_DONOTSPLIT, REAGENT_ONLYINVERSE, REAGENT_ONMOBMERGE, REAGENT_INVISIBLE, REAGENT_FORCEONNEW, REAGENT_SNEAKYNAME var/value = REAGENT_VALUE_NONE //How much does it sell for in cargo? var/datum/material/material //are we made of material? + var/gas //do we have an associated gas? + 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 /datum/reagent/New() . = ..() @@ -79,8 +82,18 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent()) /datum/reagent/proc/reaction_obj(obj/O, volume) return -/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/2];TEMP=[temp]") /datum/reagent/proc/on_mob_life(mob/living/carbon/M) current_cycle++ @@ -230,6 +243,46 @@ 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.turf_reagent = src.type + 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) + +/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)) + 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 + + + + //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)) diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 72112d9a65..afc983d0d3 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -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. /* diff --git a/code/modules/reagents/chemistry/reagents/drug_reagents.dm b/code/modules/reagents/chemistry/reagents/drug_reagents.dm index 4848347df2..fe6676e813 100644 --- a/code/modules/reagents/chemistry/reagents/drug_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drug_reagents.dm @@ -2,6 +2,7 @@ name = "Drug" metabolization_rate = 0.5 * REAGENTS_METABOLISM taste_description = "bitterness" + boiling_point = T0C + 100 var/trippy = TRUE //Does this drug make you trip? /datum/reagent/drug/on_mob_end_metabolize(mob/living/M) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index e1f8d5366c..f4b672d35c 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -8,6 +8,7 @@ /datum/reagent/medicine name = "Medicine" taste_description = "bitterness" + boiling_point = T0C + 100 value = REAGENT_VALUE_VERY_COMMON //Low prices, spess medical companies are cheapstakes and products are taxed honk... /datum/reagent/medicine/on_mob_life(mob/living/carbon/M) diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm index a378880567..1798f3a15b 100644 --- a/code/modules/reagents/chemistry/reagents/other_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm @@ -1008,6 +1008,7 @@ color = "#808080" // rgb: 128, 128, 128 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) @@ -1274,7 +1275,14 @@ 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 = 189 +/datum/reagent/fuel/define_gas() + var/datum/gas/G = ..() + G.fire_energy_released = 200000 + G.fire_products = list(GAS_CO2 = 1) + G.fire_temperature = T20C+30 + 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) @@ -1292,6 +1300,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) @@ -1304,6 +1313,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) @@ -2456,6 +2466,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) diff --git a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm index 2e05f66cf8..32c564a071 100644 --- a/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/pyrotechnic_reagents.dm @@ -45,6 +45,8 @@ color = "#FFC8C8" metabolization_rate = 4 taste_description = "burning" + boiling_point = 289.4 + condensation_amount = 2 value = REAGENT_VALUE_COMMON /datum/reagent/clf3/on_mob_life(mob/living/carbon/M) @@ -82,6 +84,14 @@ if(!locate(/obj/effect/hotspot) in M.loc) new /obj/effect/hotspot(M.loc) +/datum/reagent/clf3/define_gas() + var/datum/gas/G = ..() + G.fire_energy_released = 123000 + G.oxidation_rate = 4 + G.oxidation_temperature = T0C - 50 + G.turf_reagent = src.type + return G + /datum/reagent/sorium name = "Sorium" description = "Sends everything flying from the detonation point." @@ -149,8 +159,16 @@ 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.fire_energy_released = FIRE_PLASMA_ENERGY_RELEASED / 100 + 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) @@ -281,6 +299,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 diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 7cefc48159..124d8e60a5 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -8,6 +8,7 @@ taste_description = "bitterness" taste_mult = 1.2 value = REAGENT_VALUE_COMMON //Encouraging people to mix toxins for reasons beyond harming each other or mixing reagents such as pen acid. + boiling_point = T0C + 100 var/toxpwr = 1.5 // Are you a bad enough dude to poison your own plants?