Files
GS13NG/code/modules/atmospherics/gasmixtures/reactions.dm
T

234 lines
8.8 KiB
Plaintext

#define NO_REACTION 0
#define REACTING 1
/datum/controller/subsystem/air/var/list/gas_reactions //this is our singleton of all reactions
/proc/init_gas_reactions()
var/list/reaction_types = list()
for(var/r in subtypesof(/datum/gas_reaction))
var/datum/gas_reaction/reaction = r
if(!initial(reaction.exclude))
reaction_types += reaction
reaction_types = sortList(reaction_types, /proc/cmp_gas_reactions)
. = list()
for(var/path in reaction_types)
. += new path
/proc/cmp_gas_reactions(datum/gas_reaction/a, datum/gas_reaction/b) //sorts in descending order of priority
return initial(b.priority) - initial(a.priority)
/datum/gas_reaction
//regarding the requirements lists: the minimum or maximum requirements must be non-zero.
//when in doubt, use MINIMUM_HEAT_CAPACITY.
var/list/min_requirements
var/list/max_requirements
var/exclude = FALSE //do it this way to allow for addition/removal of reactions midmatch in the future
var/priority = 100 //lower numbers are checked/react later than higher numbers. if two reactions have the same priority they may happen in either order
var/name = "reaction"
var/id = "r"
/datum/gas_reaction/New()
init_reqs()
/datum/gas_reaction/proc/init_reqs()
/datum/gas_reaction/proc/react(datum/gas_mixture/air, atom/location)
return NO_REACTION
//agent b: converts hot co2 and agent b to oxygen. requires plasma as a catalyst. endothermic
/datum/gas_reaction/agent_b
priority = 2
name = "Agent B"
id = "agent_b"
/datum/gas_reaction/agent_b/init_reqs()
min_requirements = list(
"TEMP" = 900,
"agent_b" = MINIMUM_HEAT_CAPACITY,
"plasma" = MINIMUM_HEAT_CAPACITY,
"co2" = MINIMUM_HEAT_CAPACITY
)
/datum/gas_reaction/agent_b/react(datum/gas_mixture/air)
var/list/cached_gases = air.gases
var/reaction_rate = min(cached_gases["co2"][MOLES]*0.75, cached_gases["plasma"][MOLES]*0.25, cached_gases["agent_b"][MOLES]*0.05)
cached_gases["co2"][MOLES] -= reaction_rate
cached_gases["agent_b"][MOLES] -= reaction_rate*0.05
air.assert_gas("o2") //only need to assert oxygen, as this reaction doesn't occur without the other gases existing
cached_gases["o2"][MOLES] += reaction_rate
air.temperature -= (reaction_rate*20000)/air.heat_capacity()
return REACTING
//freon: does a freezy thing?
/datum/gas_reaction/freon
priority = 1
name = "Freon"
id = "freon"
/datum/gas_reaction/freon/init_reqs()
min_requirements = list("freon" = MOLES_PLASMA_VISIBLE)
/datum/gas_reaction/freon/react(datum/gas_mixture/air, turf/open/location)
. = NO_REACTION
if(location && location.freon_gas_act())
. = REACTING
//water vapor: puts out fires?
/datum/gas_reaction/water_vapor
priority = 1
name = "Water Vapor"
id = "vapor"
/datum/gas_reaction/water_vapor/init_reqs()
min_requirements = list("water_vapor" = MOLES_PLASMA_VISIBLE)
/datum/gas_reaction/water_vapor/react(datum/gas_mixture/air, turf/open/location)
. = NO_REACTION
if(location && location.water_vapor_gas_act())
air.gases["water_vapor"][MOLES] -= MOLES_PLASMA_VISIBLE
. = REACTING
//fire: combustion of plasma and volatile fuel (treated as hydrocarbons). creates hotspots. exothermic
/datum/gas_reaction/fire
priority = -1 //fire should ALWAYS be last
name = "Hydrocarbon Combustion"
id = "fire"
/datum/gas_reaction/fire/init_reqs()
min_requirements = list("TEMP" = FIRE_MINIMUM_TEMPERATURE_TO_EXIST) //doesn't include plasma reqs b/c of volatile fuel stuff - consider finally axing volatile fuel
/datum/gas_reaction/fire/react(datum/gas_mixture/air, turf/open/location)
var/energy_released = 0
var/old_heat_capacity = air.heat_capacity()
var/list/cached_gases = air.gases //this speeds things up because accessing datum vars is slow
var/temperature = air.temperature
var/list/cached_results = air.reaction_results
//to_chat(world, "pre [temperature], [cached_gases["o2"][MOLES]], [cached_gases["plasma"][MOLES]]")
cached_results[id] = 0
//General volatile gas burn
if(cached_gases["v_fuel"] && cached_gases["v_fuel"][MOLES])
var/burned_fuel
if(!cached_gases["o2"])
burned_fuel = 0
else if(cached_gases["o2"][MOLES] < cached_gases["v_fuel"][MOLES])
burned_fuel = cached_gases["o2"][MOLES]
cached_gases["v_fuel"][MOLES] -= burned_fuel
cached_gases["o2"][MOLES] = 0
else
burned_fuel = cached_gases["v_fuel"][MOLES]
cached_gases["o2"][MOLES] -= cached_gases["v_fuel"][MOLES]
if(burned_fuel)
energy_released += FIRE_CARBON_ENERGY_RELEASED * burned_fuel
air.assert_gas("co2")
cached_gases["co2"][MOLES] += burned_fuel
cached_results[id] += burned_fuel
//Handle plasma burning
if(cached_gases["plasma"] && cached_gases["plasma"][MOLES] > MINIMUM_HEAT_CAPACITY)
var/plasma_burn_rate = 0
var/oxygen_burn_rate = 0
//more plasma released at higher temperatures
var/temperature_scale
if(temperature > PLASMA_UPPER_TEMPERATURE)
temperature_scale = 1
else
temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE)
if(temperature_scale > 0)
air.assert_gas("o2")
oxygen_burn_rate = OXYGEN_BURN_RATE_BASE - temperature_scale
if(cached_gases["o2"][MOLES] > cached_gases["plasma"][MOLES]*PLASMA_OXYGEN_FULLBURN)
plasma_burn_rate = (cached_gases["plasma"][MOLES]*temperature_scale)/PLASMA_BURN_RATE_DELTA
else
plasma_burn_rate = (temperature_scale*(cached_gases["o2"][MOLES]/PLASMA_OXYGEN_FULLBURN))/PLASMA_BURN_RATE_DELTA
if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY)
air.assert_gas("co2")
cached_gases["plasma"][MOLES] = QUANTIZE(cached_gases["plasma"][MOLES] - plasma_burn_rate)
cached_gases["o2"][MOLES] = QUANTIZE(cached_gases["o2"][MOLES] - (plasma_burn_rate * oxygen_burn_rate))
cached_gases["co2"][MOLES] += plasma_burn_rate
energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate)
cached_results[id] += (plasma_burn_rate)*(1+oxygen_burn_rate)
if(energy_released > 0)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
air.temperature = (temperature*old_heat_capacity + energy_released)/new_heat_capacity
//to_chat(world, "post [temperature], [cached_gases["o2"][MOLES]], [cached_gases["plasma"][MOLES]]")
//let the floor know a fire is happening
if(istype(location))
temperature = air.temperature
if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST)
location.hotspot_expose(temperature, CELL_VOLUME)
for(var/I in location)
var/atom/movable/item = I
item.temperature_expose(air, temperature, CELL_VOLUME)
location.temperature_expose(air, temperature, CELL_VOLUME)
return cached_results[id] ? REACTING : NO_REACTION
//fusion: a terrible idea that was fun to try. turns co2 and plasma into REALLY HOT oxygen and nitrogen. super exothermic lol
/datum/gas_reaction/fusion
exclude = TRUE
priority = 2
name = "Plasmic Fusion"
id = "fusion"
/datum/gas_reaction/fusion/init_reqs()
min_requirements = list(
"ENER" = PLASMA_BINDING_ENERGY * 10,
"plasma" = MINIMUM_HEAT_CAPACITY,
"co2" = MINIMUM_HEAT_CAPACITY
)
/datum/gas_reaction/fusion/react(datum/gas_mixture/air)
var/list/cached_gases = air.gases
var/temperature = air.temperature
if((cached_gases["plasma"][MOLES]+cached_gases["co2"][MOLES])/air.total_moles() < FUSION_PURITY_THRESHOLD)
//Fusion wont occur if the level of impurities is too high.
return NO_REACTION
//to_chat(world, "pre [temperature, [cached_gases["plasma"][MOLES]], [cached_gases["co2"][MOLES]])
var/old_heat_capacity = air.heat_capacity()
var/carbon_efficency = min(cached_gases["plasma"][MOLES]/cached_gases["co2"][MOLES],MAX_CARBON_EFFICENCY)
var/reaction_energy = air.thermal_energy()
var/moles_impurities = air.total_moles()-(cached_gases["plasma"][MOLES]+cached_gases["co2"][MOLES])
var/plasma_fused = (PLASMA_FUSED_COEFFICENT*carbon_efficency)*(temperature/PLASMA_BINDING_ENERGY)
var/carbon_catalyzed = (CARBON_CATALYST_COEFFICENT*carbon_efficency)*(temperature/PLASMA_BINDING_ENERGY)
var/oxygen_added = carbon_catalyzed
var/nitrogen_added = (plasma_fused-oxygen_added)-(air.thermal_energy()/PLASMA_BINDING_ENERGY)
reaction_energy = max(reaction_energy+((carbon_efficency*cached_gases["plasma"][MOLES])/((moles_impurities/carbon_efficency)+2)*10)+((plasma_fused/(moles_impurities/carbon_efficency))*PLASMA_BINDING_ENERGY),0)
air.assert_gases("o2", "n2")
cached_gases["plasma"][MOLES] -= plasma_fused
cached_gases["co2"][MOLES] -= carbon_catalyzed
cached_gases["o2"][MOLES] += oxygen_added
cached_gases["n2"][MOLES] += nitrogen_added
if(reaction_energy > 0)
var/new_heat_capacity = air.heat_capacity()
if(new_heat_capacity > MINIMUM_HEAT_CAPACITY)
air.temperature = max(((temperature*old_heat_capacity + reaction_energy)/new_heat_capacity),TCMB)
//Prevents whatever mechanism is causing it to hit negative temperatures.
//to_chat(world, "post [temperature], [cached_gases["plasma"][MOLES]], [cached_gases["co2"][MOLES]])
return REACTING
#undef REACTING
#undef NO_REACTION