How to make fermi reactions from a code perspective 
How purity worksPurity by default only splits on a mob’s consumption unless reaction_flags in the recipe is set to one of the CLEAR_CONVERT defines. Here is a bad flowchart for the on mob process. I am not good at flowcharts sorry.
Essentially For purity: If 1: normal If above inverse_chem_val: normal + impure If below: inverse How reactions mechanics workFor the effects starting/during/at the end of a reaction see below:
Maybe this makes no sense. In brief: Holder.dm now sets up reactions, while equilibrium.dm runs them. Holder itself is processed when there is a list of reactions, but the equilibrium does the calculating. In essence, it holds onto a list of objects to run. Handle_reactions() is used to update the reaction list, with a few checks at the start to prevent any unnecessary updates. When a reaction is detected:
When holder is processing:
How a holder stops reacting:When one of the checks fails in the equilibrium object, it is flagged for deletion. The holder will detect this and call reaction_finish() and delete the equilibrium object – ending that reaction. Recipe and processing mechanicsLets go over the reaction vars below. These can be edited and set on a per chemical_reaction basis
How temperature ranges are set and how reaction rate is determinedReaction rates are determined by the current temperature of the reagents holder. There are a few variables related to this:
The amount added is based off the recipies’ required_temp, optimal_temp, overheat_temp and temp_exponent_factor. See below:
the y axis is the normalised value of growth, which is then muliplied by the rate_up_lim. You can see that temperatures below the required_temp produce no result (the reaction doesn't start, or if it is reacting, the reaction will stop). Between the required and optimal is a region that is defined by the temp_exponent_factor, so in this case the value is ^2, so we see exponential growth. Between the optimal_temp and the overheat_temp is the optimal phase - where the rate factor is 1. After that it continues to react, but will call overheated() per timestep. Presently the default for overheated() is to reduce the yield of the product (i.e. it's faster but you get less). The rate_up_lim is the maximum rate the reaction can go at optimal temperatures, so in this case a rate factor of 1 i.e. a temperature between 500+ will produce 10u, or a temperature of 400 will roughly produce 4u per step (independant of product ratio produced, if you put 10, it will only create 10 maximum regardless of how much product is defined in the results list). How pH ranges are set and what pH mechanics doOptimal pH ranges are set on a per recipe basis - though at the moment all recipes use a default recipe, so they all have the same window (except for the buffers). Hopefully either as a community effort/or in future PRs we can create unique profiles for the present reactions in the game. As for how you define the reaction variables for a reaction, there are a few new variables for the chemical_recipe datum. I'll go over specifically how pH works for the default reaction.
For this default reaction, the curve looks like this:
The y axis is the purity of the product made for that time step. This is recalculated based off the beaker's sum pH for every tick in the reaction. The rate in which your product is made based off the temperature (If you want me to describe that too I can.) So say our reaction has 10u of a purity 1 of product in there, and for our step we're making another 10u with our pH at (roughly) 3, from the curve our purity is (roughly) 0.5. So we will be adding 10u of 0.5 purity to 10u of 1 purity, resulting in 20u of 0.75 purity product. (Though - to note the reactant's purities also modify the purity of volume created on top of this). If you're designing a reaction you can define an optimal range between the OptimalpHMin to OptimalpHMax (5 - 7 in this case) and a deterministic region set by the ReactpHLim (5 - 4, 9 + 4 aka between 1 to 5 and 9 to 13). This deterministic region is exponential, so if you set it to 2 then it’ll exponentially grow, but since our CurveSharpph = 1, it’s linear (basically normalise the range in the determinsitic region, then put that to the power of CurveSharppH). Finally values outside of these ranges will prevent reactions from starting, but if a reaction drifts out during a reaction, the purity of volume created for each step will be 0 (It does not stop ongoing reactions). It’s entirely possible to design a reaction without a deterministic or optimal phase if you wanted. Though to note; if your purity dips below the PurityMin of a reaction it’ll call the overly_impure() function – which by default reduces the purity of all reagents in the beaker. Additionally, if the purity at the end of a reaction is below the PurityMin, it’ll convert into the failed chem defined by the product’s failed_chem defined in its reagent datum. For default the PurityMin is 0.15, and is pretty difficult to fail. This is all customisable however, if you wanted to use these hooks to design a even more unique reaction, just don’t call the parent proc when using methods. Conditional changes in reagents datum per timestep
The thermic_constant is how much the temperature changes per u created, so for 10u created the temperature will increase by 10K. The H_ion_release is how much the pH changes per u created, for 10u created the pH will increase by 0.1. During a reaction this is the only factor in pH changes - presently the addition/removal of reagents tie to the reaction won't affect this, though other reactions ongoing in the beaker will also affect pH, as well as the removal/addition of reagents outside of the reaction. Reaction flagsReaction_flags can be used to set these defines:
For REACTION_CLEAR – this causes the purity mechanics to resolve in the beaker at the end of the reaction, instead of when added to a mob. A note on cold recipiesIs_cold_recipie requires you to set your overheat_temp and optimal_temp descend instead. Eg:
ReagentsThe new vars that are introduced are below:
When writing any reagent code ALWAYS use creation_purity. Purity is kept for internal mechanics only and won’t reflect the purity on creation. See above for purity mechanics, but this is where you set the reagents that are created. If you’re making an impure reagent I recommend looking at impure_reagents.dm to see how they’re set up and consider using the The flags you can set for
While you might think reagent_flags is a more sensible name - it is already used for beakers. Hopefully this doesn't trip anyone up. Relivant vars from the holder.dm / reagents datumThere are a few variables that are useful to know about
|



