Scripting and how to use it

articy:draft features its own scripting language, called "articy:expresso". In articy:draft, it is most useful when combined with Global Variables, built-in functions, and the Simulation mode, allowing users to test the logic of their narrative.

The ArticyImporter plugin imports your scripts into Unity, providing you with the flexibility to apply them as you see fit. Additionally, the ArticyFlowPlayer will use the scripts found inside the flow when traversing it.

This guide provides an overview on how to take advantage of articy:expresso and how to make use of the scripts within Unity.

This topic contains the following sections:

Scripting with articy:expresso

In case you are unfamiliar with articy:expresso and how to use it inside of articy:draft, consider the summary below, or head directly to the more exhaustive HelpCenter documentation.

We distinguish between two types of scripts in articy:expresso:

  • Condition: A boolean expression
  • Instructions: A set of statements, separated by semicolon, usually used to change the state of variables or invoke functions

articy:draft users can define scripts in three different contexts:

  • Pins: Conditions are used in InputPins to constrain flow execution on a given path, while instructions are defined on OutpuPins.
  • Condition and Instructions nodes: Similar to Input- and OutputPins, there are two dedicated node types in articy:draft to define the two respective types of scripts.
  • Script template properties: Users can define template properties of type "script" and assign a script type ("condition", "instructions", or "no error validation"), which only affects the script validation internal to articy:draft.

Condition scripts

edit pin

A condition script is an arbitrary boolean expression, i.e. an expression that evaluates to either the value "True" or "False". An empty condition script is evaluated to "True". Here are some example condition scripts:

Expresso
true
Expresso
GameState.awake
Expresso
!Inventory.hasKey || Inventory.lockPicks == 0
Expresso
Resources.woodSupply > 100 && Resources.ironSupply > 50

articy:expresso supports commonly known operators and their semantics, including comparison operators (<, <=, ==, !=, >, >=), logical operators (&& / AND, || / OR) and the logical negation operator (!). Additionally, operands can be calculated values, based off of function calls and arithmetic expressions.

Instructions scripts

edit pin instruction

Instructions are a set of assignment statements in the form <l-value> <assignment-operator> <r-value>.

Expresso
GameState.awake = true;
Expresso
Resources.woodSupply -= 100;
Resources.ironSupply -= 50;

playSound("forge_build.wav");

articy:expresso supports commonly known assignment operators and their semantics (=, +=, -=, *=, /=, %=). While the l-value has to be a defined, mutable variable, the r-value can be an arbitrary expression of the same type as the l-value (otherwise, type validation will report an error in articy:draft).

Accessing objects, properties and templates

Historically, articy:expresso was designed to be used in conjunction with Global Variables. While this was sufficient for a lot of use cases, it can be more useful to store the data alongside the objects directly. Especially given the flexibility that was added with the template system, we introduced specialized functions to the scripting system to access properties and the template data of objects. Additionally, there exist several convenience functions and keywords in articy:expresso to facilitate common tasks.

Overview over built-in functions (detailed explanations and samples in the next section):

  Note

Note that the Variable type wraps values of supported types for those functions where it is used. For example, isInRange can be used with integer, floating, and string values, as long as the types of the lowerBound and upperBound arguments can be treated the same way as the type of the value argument.
Expresso
getObj(identifier : string, instanceId : int = 0) : ObjectRef

getProp(obj : ObjectRef, propertyName : string) : Variable

setProp(obj : ObjectRef, propertyName : string, value : Variable)

incrementProp(obj : ObjectRef, propertyName : string, value : Variable = 1)

decrementProp(obj : ObjectRef, propertyName : string, value : Variable = 1)

isPropInRange(obj : ObjectRef, propertyName : string, lowerBound : Variable, upperBound : Variable) : bool

isInRange(value : Variable, lowerBound : Variable, upperBound : Variable) : bool           

random(min : Variable, max : Variable) : Variable

print(s : string)

getSeenCounter(obj : ObjectRef) : int

setSeenCounter(obj : ObjectRef, count : int)

resetAllSeenCounters()

fallback(branchingPointRef : ObjectRef = null) : boolean
Overview over built-in convenience keywords:
  • speaker : ObjectRef: inside a DialogueFragment, this is an automatic reference to the current speaker object.
  • self : ObjectRef: this references the current object that this script is called on.
  • seen : boolean: indicates if this object has been visited (true) or not (false) by the player in a given session. It is the inverse of unseen.
  • unseen : boolean: indicates if this object has not been visited (false) or not (true) by the player in a given session. It is the inverse of seen.
  • seenCounter : int: the number of times the corresponding object has been visited. Number can be set. The following statements are equivalent:
    Expresso
    print(seenCounter);
    print(getSeenCounter(self));
    // --
    seenCounter = 42;
    setSeenCounter(self, 42);

  Caution

Remember that a Condition script must be a boolean expression. Hence, certain functions or keywords like print(...), setProp(...) or setSeenCounter(...) cannot be used in Condition scripts.

Utility functions reference

getObj(identifier : string, instanceId : int = 0) : ObjectRef

This function is used in conjunction with functions like getProp() and setProp().

You can access an object via its technical name or id.

Expresso
getObj("Chr_Manfred")

getObj("0x01000001000010C6")

Optionally, you can specify the instance id to access another clone of the object.

Expresso
getObj("NPC_Guard", 1)

getProp(obj : ObjectRef, propertyName : string) : Variable

To access a property you have to provide a reference to a specific object (obj) and the propertyName as a string.

Expresso
getProp( getObj("Chr_Manfred"), "DisplayName")

The property name is just the C# property name. For example DisplayName, Speaker, BackgroundColor etc.

You can access the template data of the object by writing the feature name and the property name separated by a dot.

Expresso
getProp( getObj("Chr_Manfred"), "Morale.MoraleValue" ) > 10
Here we used getProp() in a condition, testing the returned value.

Remember that you can use keywords like self or speaker to ease accessing objects:

Expresso
getProp( speaker, "Player_Character.Morale" ) > 10

setProp(obj : ObjectRef, propertyName : string, value : Variable)

To change the value of a property you have to provide a refernce to a specific object (obj), the property name, and the new value.

Expresso
setProp( getObj("Chr_Manfred"), "DisplayName", "Player1" )

Changing a template property is achieved accordingly:

Expresso
setProp( getObj("Chr_Manfred"), "Player_Character.Morale", 100 )

Remember that you can use keywords like self or speaker to ease accessing objects:

Expresso
setProp( speaker, "Morale.MoraleValue", 100 )

incrementProp(obj : ObjectRef, propertyName : string, value : Variable = 1) and decrementProp(obj : ObjectRef, propertyName : string, value : Variable = 1)

Instead of nesting setProp and getProp to increment or decrement a value, you can use these convenience functions.

Expresso
incrementProp(getObj("Chr_Manfred"), "Player_Character.Morale", 10)
decrementProp(speaker, "Player_Character.Morale", 20)

If no change value is specified, the value will be increased or decreased by 1.

Expresso
incrementProp(speaker, "Attributes.Strength")

isPropInRange(obj : ObjectRef, propertyName : string, lowerBound : Variable, upperBound : Variable) : bool

A convenience function to check if a property value is in a specific range. The bounds are both inclusive.

Expresso
isPropInRange(getObj("Chr_Manfred"), "Morale.MoraleValue", 50, 100)

isInRange(value : Variable, lowerBound : Variable, upperBound : Variable) : bool

Similar to isPropInRange(...), but not restricted to property values. The bounds are both inclusive.

It can be used for global variables ...

Expresso
isInRange(Resources.ironSupply, 500, 1000)

... or even with custom methods:

Expresso
isInRange(getTime(), 6, 12)

random(min : Variable, max : Variable) : Variable

Can be used to work with random values.

Expresso
incrementProp(getObj("Player"), "Inventory.Gold", random(50, 100));

print(s : string)

Useful as a debug tool. Use this to write into the Unity console log, like Debug.Log(). Similarly to String.Format(), strings can be formatted.

Expresso
print( "Hello" )

print( "Number {0}", 42 ) 

print( getProp( speaker, "Morale.MoraleValue" ) )

getSeenCounter(obj : ObjectRef) : int

Returns how many times the given obj target has been visited.

Expresso
getSeenCounter(self) > 12

setSeenCounter(obj : ObjectRef, count : int)

Sets the seenCounter to count for the given obj target .

Expresso
setSeenCounter(self, 2)

resetAllSeenCounters()

Resets all non-zero "seen counter values" to zero.

Expresso
resetAllSeenCounters()

fallback(branchingPointRef : ObjectRef = null) : boolean

Evaluates to false if any other non-fallback branch in reference to the given branchingPointRef is currently valid. By default (i.e. without an explicit branchingPointRef argument), the branchingPoint is determined by the ArticyFlowPlayer.

Expresso
fallback()
fallback(getObj("0x01000000000008B1"))

See Also