Skip to content

Script Expressions

When writing naninovel scripts, you can inject expression constructs to command parameter values and generic text lines using curly braces {}:

nani
One plus two equals {1 + 2}.

— will print "One plus two equals 3" when running the script.

You can use any math and logical operators, as well as some math functions from the UnityEngine.Mathf ↗ namespace:

nani
@char Kohaku scale:{pow(cos(33.5), 3) % log(0.5)}

— will scale character with ID "Kohaku" to the reminder from dividing cosine of 33.5 angle increased to power of 3 by natural logarithm of 0.5.

The expression is evaluated at the moment the command is executed, which allows using custom variables inside the expressions:

nani
@input color summary:"What's your favorite color?"
@stop
{color}, huh? { color == "orange" ? "Mine too!" : (color == "black" ? "That's depressing." : "I see...") }

— will show an input UI allowing player to input their favorite color, assigning it to color custom variable, then print the inputted color, followed by either "Mine too!" in case it's "orange", "That's depressing." in case it's "black" or "I see..." in the other cases.

To distinguish a plain text value from a variable name, wrap the value in double quotes ":

nani
This is just a plain text: { "score" }.
And this is the value of "score" variable: { score }.

In case you wish to include the double quotes in the expression, escape them:

nani
Saying { \"Stop the car\" } was a mistake.

Script expressions used in @set and @if commands (as well as set and if parameters in other commands), doesn't require curly braces:

nani
@set randomScore=random(-100,100)
@goto EpicLabel if:abs(randomScore)>=50

Though, just like with all the other parameter values, in case you wish to use spaces inside the expressions, you should wrap them in double quotes:

nani
@set "randomScore = random(-100, 100)"
@goto EpicLabel if:"abs(randomScore) >= 50"

To print curly braces inside a generic text line and prevent them from being recognized as an expression start and end literals, escape the braces with backslashes, eg:

nani
Some text \{ text inside braces \}

— will print "Some text { text inside braces }" in-game.

Expression Functions

The following functions can also be used inside the script expressions.

SignatureDescriptionExample
random(min, max)Return a random integer number between min [inclusive] and max [inclusive].random(0, 100)
random(args)Return a string chosen from one of the provided strings.random("foo", "bar", "baz")
calculateProgress()Returns scenario completion ratio, in 0.0 to 1.0 range, where 1.0 means all the script lines were executed at least once.calculateProgress()
isUnlocked(id)Checks whether an unlockable item with the provided ID is currently unlocked.isUnlocked("Tips/MyTip")
hasPlayed()Checks whether currently played command has ever been played before.hasPlayed()
hasPlayed(script)Checks whether script with the provided name has ever been played before.hasPlayed("MyScript")
getName(id)Returns author name of a character actor with the provided ID.getName("Kohaku")
pow(num, pow)Returns num raised to power.pow(2, 3)
sqrt(num)Returns square root of num.sqrt(2)
cos(num)Returns the cosine of angle.cos(180)
sin(num)Returns the sine of angle.sin(90)
log(num)Returns the natural (base e) logarithm of a specified number.log(0.5)
abs(num)Returns the absolute value of f.abs(0.5)
max(nums)Returns largest of two or more values.max(1, 10, -9)
min(nums)Returns the smallest of two or more values.min(1, 10, -9)
round(num)Returns num rounded to the nearest integer.round(0.9)
approx(a, b)Compares two floating point values and returns true if they are similar.approx(0.15, 0.15)

Adding Custom Functions

It's possible to add custom expression functions by assigning ExpressionFunction attribute to a public static C# method with compatible signatures, which will then automatically become available in script expressions.

Only simple ↗ and string types are supported as argument and return types. It's also possible to use a single variadic (params keyword) argument; mixing a variadic with other arguments is not supported.

csharp
public static class CustomFunctions
{
	// Returns the provided string with all characters converted to lower-case.
	[ExpressionFunction("toLower")]
    public static string ToLower (string content) => content.ToLower();

    // Returns the sum of the provided numbers.
    [ExpressionFunction("add")]
    public static int Add (int a, int b) => a + b;

    // Returns the remainder resulting from dividing the provided numbers.
    [ExpressionFunction("mod")]
    public static double Modulus (double a, double b) => a % b;

    // Returns a string randomly chosen from one of the provided strings.
    [ExpressionFunction("random")]
    public static string Random (params string[] args)
	{
		if (args == null || args.Length == 0)
			return default;

        var randomIndex = UnityEngine.Random.Range(0, args.Length);
		return args[randomIndex];
	}
}

The ExpressionFunction attribute has following optional parameters:

  • Alias By default, method name is used as function identifier (the way function is referenced in scripts); assign alias to change the identifier.
  • Summary Documentation shown in IDE extension and visual editor.
  • Remarks Additional information shown in IDE extension and visual editor.
  • Example Usage examples shown in IDE extension and visual editor.

EXAMPLE

Another example of adding custom expression functions to check whether an item exists in an inventory can be found in the inventory example project on GitHub ↗.

Specifically, the custom functions are implemented via InventoryFunctions.cs ↗ runtime script.