Creating a custom liquid

1. Defining your liquid

A liquid is a class that is only instantiated once. All liquids derive from the Liquid class. This class is abstract and requires the implementation of the following:

// Called when this liquid enters a limb. Note that this may be called quite often for the same container as liquid quickly moves in and out of it.
public abstract void OnEnterLimb(LimbBehaviour limb);

// Called when this liquid enters a container. Limbs are also containers. Note that this may be called quite often for the same container as liquid quickly moves in and out of it.
public abstract void OnEnterContainer(BloodContainer container);

// Called when this liquid exits a container. Note that this may be called quite often for the same container as liquid quickly moves in and out of it.
public abstract void OnExitContainer(BloodContainer container);

These are required. They can be left empty if there is nothing to do. A few optional members can also be implemented that provide additional functionality that your liquid may require.

1.1 OnUpdate

The OnUpdate method is an empty virtual method that can be overridden. It's called every second for every liquid inside every container. The relevant BloodContainer is given.

A common implementation looks like this:

public override void OnUpdate(BloodContainer container)
{
    base.OnUpdate(container); //just in case whatever you're deriving from does anything

    if (container is CirculationBehaviour circ) //is the container a limb?
    {
        var limb = circ.Limb;
        //do stuff with limb
    }
}

1.2 GetDisplayName

This is a getter method that should return the display name of your liquid. This string will be displayed wherever your liquid is supposed to be represented by text, most notably in the Liquidentifier. If this method is unimplemented, it will return the liquid ID string. If the liquid hasn't even been registered, the base implementation will return the type name.

Example implementation of this method:

public override string GetDisplayName() => "Human blood";

1.3 Full example

As a full example, this is coagulation serum:

public class CoagulationLiquid : TemporaryBodyLiquid
{
    public const string ID = "COAGULATION SERUM";
    public override string GetDisplayName() => "Coagulation serum";

    public CoagulationLiquid()
    {
        //The color of the liquid is usually set in the constructor, but can be changed anytime. 
        //Do note, however, that liquid containers cache their liquid colour for performance reasons. 
        //Changing the colour outside the constructor is not recommended.
        Color = new UnityEngine.Color(1, 1, 0);
    }

    public override void OnEnterContainer(BloodContainer container)
    {

    }

    public override void OnEnterLimb(LimbBehaviour limb)
    {

    }

    public override void OnUpdate(BloodContainer c)
    {
        base.OnUpdate(c);
        if (c is CirculationBehaviour circ)
        {
            var limb = circ.Limb;

            if (limb.SpeciesIdentity == Species.Android)
                return;

            limb.CirculationBehaviour.HealBleeding();
        }
    }

    public override void OnExitContainer(BloodContainer container)
    {

    }
}

2. Registering a custom liquid

Before any liquid can be used, it has to be registered to the liquid registry. More information here.

To summarise, all liquids have a unique ID string. This is usually some variation of the liquid name, but it can be a completely random string too. Just make sure it's globally unique.

In short, add ModAPI.RegisterLiquid(DurabilitySyringe.DurabilitySerum.ID, new DurabilitySyringe.DurabilitySerum()); before anything in your Main method, like so:

using UnityEngine; 

namespace Mod
{
    public class Mod
    {
        public static void Main()
        {
            ModAPI.RegisterLiquid(DurabilitySyringe.DurabilitySerum.ID, new DurabilitySyringe.DurabilitySerum());
            ...
Attention!

This member is obsolete and should not be used. It is a remnant from the past.

bi bij bibi