To make an entity a solution container, give add a SolutionContainerManager
. For example here is an empty stomach solution:
- type: SolutionContainerManager
solutions:
stomach:
maxVol: 200
and here is for example solution
- type: SolutionContainerManager
solutions:
drink:
maxVol: 20
reagents:
- ReagentId: Cola
Quantity: 20
type
: The component type. Should always be SolutionContainerManager
.
solutions
: A map of solution name and the Solution
described below.
Solutions have several fields, all of them optional.
maxVol
: The maximum volume of solution it can hold. Once reagent Quantity sum reaches maxVol
, no more reagents can be added. It's full.
reagents
: List of Reagent
s it should hold by default. Each Reagent
has a string ReagentId
and Quantity
which is a d.
With introduction of SolutionContainerManager
there is no longer a simple 1:1 mapping of solution and list of reagents.
Each SolutionContainerManager
can contain any number of solutions. To solve this problem instead of Capabilities flag, a set of Capability-like components are introduced. Each such capability has a a string solution
that tells SolutionContainerManager
which solution it targets.
Here is a list of them:
DrainableSolutionComponent
for solutions that can be easily removed through any reagent container. E.g. draining water from a water tankDrawableSolutionComponent
for solutions that can be drawn with syringes. E.g. humans or syringe bottles with rubber caps.ExaminableSolutionComponent
for solutions that can be examined by hand.FitsInDispenserComponent
notes that the component fits in dispenser and tells ReagentDispenser/ChemMaster which solution to target.InjectableSolutionComponent
for solutions that can be injected into with syringes.RefillableSolutionComponent
for solutions that can be added easily.Other components like DrinkComponent
or FoodComponent
may have special predefined solutions they target and expect to see. For example a DrinkComponent
will try to create drink
solution if there isn't an easily accessed DrainableSolutionComponent
already available.
Here is a full example of an entity with some Solutions:
- type: entity
id: DrinkColaCan
name: space cola
description: A refreshing beverage.
components:
- type: Sprite
sprite: Objects/Consumable/Drinks/cola.rsi
- type: SolutionContainerManager
solutions:
drink:
reagents:
- ReagentId: Cola
Quantity: 20
maxVol: 20
- type: Drink
Reagents are substances which comprise solution and which can react to create new Reagents.
Their definition consists of:
type
: The component name. Should always be reagent
.
id
: Unique id for this reagent. Used in reactions and other locations to identify the reagents. For example Iodine
or WeldingFuel
. They are PascalCase
.
name
: Id with spaces for displaying in tooltips. E.g. iodine
and welding fuel
.
parent
: What reagent to inherit properties from. Used for things like BaseDrink.
desc
: A human friendly description of the chemical.
color
: Hex color of the reagent. Used for mixing and chemical display in containers.
spritePath
: A sprite specifying the icon used for the reagent, starting from Textures/Objects/Consumable/Drinks
.
physicalDesc
: Vague desscription potentially useful when identifying it.
boilingPoint
: Temperature in Celsius, at which reagent goes from liquid into gas.
meltingPoint
: Temperature in Celsius, at which reagent goes from solid into liquid.
metabolisms
: A dict of MetabolismGroup->List<ReagentEffect> to apply when the reagent is consumed.
- type: reagent
id: Lemonade
name: lemonade
parent: BaseDrink
desc: Drink using lemon juice, water, and a sweetener such as cane sugar or honey.
physicalDesc: tart
color: "#FFFF00"
spritePath: lemonadeglass.rsi
metabolisms:
Drink:
effects:
- !type:SatiateThirst
factor: 2
For more info see: SS14 Content: Reagent folder or SS14 Content:ReagentPrototype.cs
Metabolism in SS14 is very different to metabolism in SS13. In SS13, reagents simply had a proc on_mob_life
that was called to determine what should happen. Our system is much more modular and allows for things like different organs metabolizing different reagents, and species-specific metabolisms, as well as overdoses or underdoses without any hassle.
In SS14, organs are entities with a MechanismComponent
(mechanism just being a catch-all term for 'organ'.) Organs also have other components that give them decoupled behavior; StomachComponent
, CirculatorComponent
, RespiratorComponent
, and so on. However, the important one here is MetabolizerComponent.
Metabolizers (organs with that component) define a list of 'metabolism groups' that they metabolize. 'Metabolism groups' are things like 'Narcotic', or 'Food', or 'Medicine'. This allows us to define how organs metabolize different chemicals.
This is on OrganHumanStomach
. Meaning, the stomach processes any reagents with a Food
metabolism, or a Drink
metabolism:
- type: Metabolizer
# mm yummy
maxReagents: 3
metabolizerTypes: [Human]
groups:
- id: Food
- id: Drink
Metabolizers can only process so many reagents at once, to avoid the common situation in SS13 where stacking a ton of poisons on one entity would damage it significantly more than just one concentrated poison.
Metabolism rate is defined on the organ. Generally, its once per second, and chems are taken from the bloodstream.
Defining how different species react to different chemicals is quite easy. Metabolizers are tagged with 'organ types', which is essentially a species marker, but localized to the organ (so if you swap out your heart for a gorilla heart, you'll metabolize medicines/poisons/etc in the same way a gorilla does). Then, you can use the OrganType
condition to check. Here's an example in the codebase, of theobromine (a chemical found in chocolate):
metabolisms:
Poison:
effects:
- !type:HealthChange
conditions:
- !type:ReagentThreshold
min: 1
- !type:OrganType
type: Animal # Applying damage to the mobs with lower metabolism capabilities
damage:
types:
Poison: 4
As the comment suggests, to humans this chemical does nothing, but to animals (things with animal organs) it can be deadly.
ReagentEffect
s are described in C#. For example, SatiateThirst
and HealthChange
. This allows you to easily reuse code that has similar effects. Many things use reagent effects--metabolisms, plant metabolisms, and reagent entity reactions (touch/injection-based effects). ReagentEffect
s also have a prob
field, which is the chance that the effect will run from 0 to 1. The reason these are so generalized is because many things that need the data can use them.
ReagentEffectCondition
s are attached to each effect in the metabolizer list. By default, there are none; so they're always ran. However, you can easily add custom behavior to determine when an effect will actually occur. For instance, ReagentThreshold
allows you to very easily define overdose behavior. Here's Methamphetamine:
metabolisms:
Poison:
effects:
- !type:HealthChange
damage:
types:
Poison: 2.5
- !type:HealthChange
conditions:
- !type:ReagentThreshold
min: 10
damage:
types:
Poison: 4 # this is added to the base damage of the meth.
Narcotic:
effects:
- !type:MovespeedModifier
walkSpeedModifier: 1.3
sprintSpeedModifier: 1.3
This means that the overdose behavior HealthChange only occurs when there is at minimum 10u in your system. It has two different groups, 'Poison' and 'Narcotic'. These are both metabolized by the heart, generally.
Reaction prototypes define recipes with ratios of reagents required to cause a chemical reaction. Below are the reaction yaml config values:
type
: The prototype type. Should always be reaction
.
id
: Unique id used by the game to identify the reaction. In PasacalCase
reactants
: A list of reactants required for the reaction to occur. Each reactant specifies it’s ratio and if it’s a catalyst. See the example below for more info.
products
: A list of reagents created as a result of the reaction. They will be add to the solution container the reaction occurs in if there is room.
effects
: A list of effects and their properties. Each effect corresponds to a C# class that implements IReactionEffect. See the example below for more info.
- type: reaction
id: PotassiumExplosion
reactants:
Water:
amount: 1
Potassium:
amount: 1
effects: # Reaction effects
- !type:ExplosionReactionEffect
# Ranges used when 1 potassium + 1 water react (A unit reaction)
devastationRange: 0.05
heavyImpactRange: 0.1
lightImpactRange: 0.15
flashRange: 0.2
scaled: true # Scaled proportionally to amount of potassium and water
maxScale: 30 # Explosion strength stops scaling at 30 potassium + 30 water
Here’s another example. This one has a catalyst, and some chemical products, but no reaction effect. Note that reactants are only catalysts if directly specified, and will be consumed otherwise.
- type: reaction
id: PolytrinicAcid
reactants:
SulfuricAcid:
amount: 1
Chlorine:
amount: 1
catalyst: True # False if not specified
Potassium:
amount: 1
products:
PolytrinicAcid: 3