Functions

A Function lets a Yarn Script ask your game for a value, like how many coins the player has, or whether they’re carrying a key. You call it by name, with any arguments in brackets, and your game sends back the answer:

title: FunctionsDemo
---
<<if has_item("brass key")>>
    Rosa: Good, you've got the key.
<<else>>
    Rosa: You'll need a key to get up the stairs.
<<endif>>
<<set $coin_total to coin_count()>>
Rosa: You've got {$coin_total} coins.
===
Two Functions in a node. has_item decides which line Rosa says, and coin_count’s value is shown in a line.

Where a Command tells your game to do something, a Function asks it a question. The dialogue uses the answer and carries on.

sequenceDiagram
  participant R as Dialogue Runner
  participant G as Your game code
  Note over R: #60;#60;if has_item("brass key")#62;#62;
  R->>G: HasItem("brass key")
  G-->>R: returns false
  Note over R: Shows "You'll need a key to get up the stairs."
  Note over R: #60;#60;set $coin_total to coin_count()#62;#62;
  R->>G: CoinCount()
  G-->>R: returns 15
  Note over R: Shows "You've got 15 coins."
The Dialogue Runner calls the Function’s method in your game, and the value it returns is used in the Yarn Script.

Using Functions in Yarn

You can use a Function anywhere Yarn expects a value:

  • in a condition: <<if has_item("brass key")>>,
  • in a <<set>>: <<set $coin_total to coin_count()>>,
  • in an expression with other values: <<if coin_count() >= 10>>.

Put text arguments in double quotes, like "brass key". Numbers, true and false, and variables go in as they are: has_item($chosen_item).

A Function can go directly inside a line, like Rosa: You've got {coin_count()} coins. When your C# scripts compile, Yarn Spinner tells the Yarn compiler about the Functions you’ve marked with [YarnFunction], including what each one returns.

Writing a Function

Functions marked with an attribute

Add the [YarnFunction] attribute to a static method, and give the attribute the Function’s name in Yarn:

using Yarn.Unity;

public static class TextFunctions
{
    [YarnFunction("shout")]
    public static string Shout(string text)
    {
        return text.ToUpperInvariant();
    }
}
A static Function that returns its text in capitals.

If you leave the name out, the method’s name is used. Yarn Spinner finds these methods when your scripts compile, in the same way as it finds Commands, and adds them to every Dialogue Runner. See How attributed Commands are found.

The method has to be static, and it has to be public, in a public class. If it isn’t static, you’ll see error YS1006 in the Console when your scripts compile. If it isn’t public, you’ll see error YS1001.

Functions that use your game’s state

A static method can’t read the fields on a component, like an inventory. For a Function that needs to, add it to the Dialogue Runner with AddFunction():

using System.Collections.Generic;
using UnityEngine;
using Yarn.Unity;

public class PlayerState : MonoBehaviour
{
    [SerializeField] DialogueRunner dialogueRunner;

    readonly List<string> inventory = new List<string> { "lantern" };
    int coins = 15;

    void Awake()
    {
        dialogueRunner.AddFunction<string, bool>("has_item", HasItem);
        dialogueRunner.AddFunction<int>("coin_count", CoinCount);
    }

    bool HasItem(string itemName)
    {
        return inventory.Contains(itemName);
    }

    int CoinCount()
    {
        return coins;
    }
}
Line 7 The Dialogue Runner. Drag it into this field in the Inspector.
Lines 9–10 The game state the Functions read. A static method couldn’t see these.
Lines 12–16 Add both Functions when the scene starts. The first argument is each one’s name in Yarn. The types in angle brackets are the method’s parameter types, then its return type.
Lines 18–21 has_item("brass key") in Yarn calls this. It returns a bool, so it can be used in an <<if>>.
Lines 23–26 coin_count() returns a number.
Adding two Functions that read the player’s inventory and coins.

When you pass a method by name, list its parameter types and then its return type in angle brackets, like AddFunction<string, bool>. You can pass a lambda instead, giving its parameters types: dialogueRunner.AddFunction("double", (float n) => n * 2);.

To remove a Function, call dialogueRunner.RemoveFunction("has_item").

Two Functions can’t have the same name, and a Function can’t use the name of a built-in one. If you add a Function with a name that’s already taken, or one with a space in it, the Dialogue Runner logs an error and ignores it.

Values going in and out

A Function has to return one of the kinds of value Yarn understands:

Return typeIn Yarn
booltrue or false.
int, float, double and other number typesA number.
stringText.
What a Function can return.

A Function marked with [YarnFunction] that returns anything else gives you error YS1004 when your scripts compile.

A Function must return its value immediately. It can’t make the dialogue wait, so it can’t be a coroutine or an async method.

Arguments are converted to the types of the method’s parameters. A Yarn number becomes an int, float or whichever number type the parameter has, and true and false become a bool.

Built-in Functions

These Functions are always available:

FunctionWhat it returns
visited("NodeName")true if the node has been run before.
visited_count("NodeName")How many times the node has been run.
random()A random number between 0 and 1.
random_range(1, 6)A random whole number from the first number to the second, including both.
dice(6)A random whole number from 1 to the number you give it, like rolling a die.
round(n), floor(n), ceil(n)The number rounded to the nearest whole number, down, or up.
min(a, b), max(a, b)The smaller or larger of two numbers.
Some of the built-in Functions.

For maths there are also random_range_float, round_places, inc, dec, decimal and int. For converting between types there are string, number and bool.

Autocomplete in VS Code

The Yarn Spinner extension for VS Code suggests your Functions as you type, along with what they return. It reads them from the .ysls.json file that Yarn Spinner writes when your C# scripts compile. See The .ysls.json file.

For a scene that uses Commands and Functions together, see Putting It Together.

Next step Putting It Together A small scene that uses Commands and Functions together.