Hello and welcome to the articy:draft X Basics tutorial series. This time we will take a close look at story logic and controlling interactivity not by player input, but with help of scripting.
Let’s start by looking at the first dialogue. It is the first encounter between Mina and Dracula. Going out from the player choice we have two branches, in one Mina’s name is mentioned in the conversation, and in the other it stays hidden from Dracula. Wouldn’t it be nice if we could pick up this little fact again at a later stage, so that the conversation will be different depending on whether Dracula knows Mina’s name or not?
This is where variables in combination with articy’s scripting language come into play. Don’t worry, you don’t need any programming background to be able to follow along. We will look at a simple use case. Simple, but used in almost all game stories – the yes-no or true-false situation. Did the character already talk to the quest giver, do they have a specific item in their inventory? – things like that.
Global variables
Before we can use a variable, we have to create it first. We can access Global Variables via the Jumpstart page (1) or through the Global Variables system folder in the Navigator (3). Global variables are organized into Variable sets, which you can see as a subfolder or a namespace for your variables. Depending on the project structure, we could create variable sets for gamestate and inventory for example, or we could group our variables into sets for each game chapter or location.
Create a new variable set by clicking the icon in the top left.
Give it a name, and if you like a description. As both variable sets and variables are used in scripts their naming needs to follow certain rules – no spaces or special characters. You will receive an error message if you try to create an invalid name. I would advise for a telling name, especially if the project grows it will get tedious trying to manage set1, set2, and so on.
Now that we have a variable set we can create global variables in it, by clicking the icon in the top left (1). Variables have a name (2), a description (3), a type (4), and a default value (5).
We went over restrictions in regards to naming, but apart from these you can use any type of naming convention you like or that your overall project uses. I went with upper camel case for the variable set (1), as I see this as the particular namespace, and will use lower camel case for the variables themselves (2). I can enter an optional description, if I want to provide some extra information.
Variable types
There are three types of global variables available in articy:draft – Boolean, Integer, and String. Booleans (1) are probably used most often in the game writing environment and we will use this variable type in this basics series as well. A Boolean can either be true or false, exactly the type we need for this situation. Either Dracula knows Mina’s identity or not, nothing in-between. Integers (2) are whole numbers without any decimal places and can be used for anything countable, like experience or morale points. A String (3) is made up of characters, and can include letters, words, or whole sentences. Strings are usually used less within articy than the other variable types, but they have their use cases, for example to store the name of the player’s space ship, or a pass phrase to open a secret vault.
The last thing we can adjust is the default value the variable starts out with. Here I would go with the default state that Mina’s name isn’t known to Dracula and only change that fact – and the variable with it – if the player experiences a specific story branch, therefore I will set the default value to false. That’s it for this stage.
Setting up an Instruction
Now back to the dialogue. In the Flow we can place story logic in the form of scripts into node pins or specific Instruction or Condition nodes. With a Condition we check the state of a global variable, with an Instruction we can change its value.
The bottom branch after the player choice has Dracula recalling Mina’s name. To store this information and be able to use it again at some point, we will change the value of the variable we created earlier with an instruction. Using a pin or a node is often interchangeable and comes down to personal preference, although there are a few cases where choosing one over the other definitely makes sense.
Here I am going to use an Instruction node, as I want it to be obvious with a glance at the Flow that some value is altered at this point. Delete the connection between Mina’s and Dracula’s node (1). Then drag an instruction node from the toolbar (2) and place it in the middle between these nodes (3). Now connect the nodes (4).
The Instruction itself has to be written in form of a command-like expression. Please bear with me, it might look daunting at first glance, but my promise from the beginning still stands – programming knowledge is not required. If you understand the syntax for setting the value of a Boolean variable and how to check for a specific value, you are already able to cover a lot of the bases regarding story logic for narrative games.
The expression is constructed as follows: <variable set name>.<variable name> <assignment operator> <value>
. Articy actually helps you when writing these expressions with auto completion and syntax highlighting.
As soon as you start typing a list will appear where you can choose the correct entry with the cursor keys and confirm with tab or enter. In the rare case that auto completion and syntax highlighting do not work, click the Settings folder in the Navigator (1) and go to the Flow tab (2). Make sure that “Use built-in scripting support” (3) is checked.
If you add the dot after the variable set name you are immediately presented a list of variable names belonging to this set – which currently is just the one variable we created. Next comes the assignment operator which in our case is an equal sign. That means the value of the variable will be set to the value that comes after this operator. When creating the isNameRevealed
variable we set the default value to false, so we need to set the value to true now.
If any mistake was made while writing, like a typo or trying to assign values that are not possible for the selected variable type, the faulty part will be underlined in red and a warning symbol appears at the top of the node. If you hover over this symbol a help text is displayed that indicates the type of error.
The Instruction is complete now. If the player chooses the first or middle option the variable stays unchanged, if they choose the third option the variable value will be set to true at the end of the branch.
Setting up a Condition
Now we can check for the value of this variable with a Condition and depending on the result have the player experience different paths of the story. If you have completed the “Flow III” lesson, you might already suspect where this might be. If we submerge into the “Final Confrontation” Dialogue node we already have the structure prepared with a Condition node, the only thing missing is the condition statement.
The basic syntax of a condition is similar to an instruction, the main difference is the kind of operators that are used. The syntax we used in the instruction was: <variable set name>.<variable name> <assignment operator> <value>
. The beginning is the same as before: GameState.isNameRevealed
. To now check for a value we need a so called relational operator. We want to check if the value of the variable is equal to what comes after the operator and for this we use double equal signs (==). The value we are checking against is true so our complete condition reads: Is the value of the variable equal to true? GameState.isNameRevealed == true
.
If the result of the statement within the Condition node is true then the Flow will continue through the green output pin (1), if the result is false it will go through the red pin (2).
For our example it means that if the player chose the option where Mina’s name came up in the first meeting dialogue, the variable value was set to true in the Instruction, which now leads to a true result for the Condition. If the other branch was followed the variable value was not modified and stayed at its default value, which was false. False is not equal to True, that means the entire Condition statement returns false.
A Condition statements always leads to a True or False result, not only because we are working with a Boolean variable we check against here. Say we want to tie our choice of dialogue path here to the level the player has. To store a number we need a variable playerLevel
of type Integer.
If we want to send the player to the first option when they are level 3 or higher, our Condition would look like this: <variable set name>.<variable name> <relational operator> <value>
GameState.playerLevel >= 3
.
The variable we check against is an Integer, but the condition statement still results in a Boolean true or false. Either the player is level three or higher, resulting in the green option (1), or lower than three which sends them down the red path (2).
You probably noticed the new relational operator used here (>=). Depending on variable type we have more or less options to compare values. For a complete list of all operators usable in articy scripting please check out Scripting Help Center entry or search for “Scripting” in the In-App help.
More scripting examples
Let’s dive into the “Name unknown” node to look at some more scripting examples. If we scan over the dialogue we see a condition node leading to a reaction point and some orange pins at the player choice point.
If a pin is highlighted orange it means it has content within, if we hover over one we can see that it contains a comment, describing what is supposed to happen here.
In case you are not familiar with terminology choice and reaction point: At a choice point, the player actively has to make a decision.
At a reaction point the flow is controlled by the current value of the variable. This happens automatically in the background, so the player is not even aware that there are multiple ways to continue at this point.
Choice points are usually used when the player character is involved, reaction points can be valid for players and NPCs alike, but in the end it is up to the developer and how they interpret these points during implementation.
To set up the scripting expressions according to the comments we are going to need additional variables. To not always having to swap between Flow and Global Variables folder, I collapse the Navigator to get some additional space and drag out a second view pane, where I select Global Variables from the Jumpstart page. Now I have the Flow on the left side and can create necessary variables on the fly on the right side. We can either select a specific variable set (1) or stay on the Global variables level (2). That allows us to create variables for all existing sets and also to create new variable sets. Downside is that we need to be careful to create variables into the correct set, which automatically happens when on set level.
Currently we only have one set, which is automatically selected for “Create in”.
What do we need? We want to check if the player defeated Renfield. Another yes/no, true/false decision, making a Boolean the obvious choice. Default value I leave at false.
As the dialogue following the Condition already exist, we need to make sure to phrase the statement in a way that fits the story flow. <variable set name>.<variable name> <relational operator> <value>
GameState.isRenfieldDefeated == true
. Remember for comparing values we need to use ==. Does this work? Say we did not manage to defeat Renfield, which technically we cannot do currently as the encounter is not implemented. That means the variable value stays on its default value which we set as false. False equals True results in False, which then continues the dialogue through the red output pin. Looks good.
What’s next. At the choice point, let’s look at the bottom branch first, the one directly leading to the fight that is supposed to conclude this part of the game. By double clicking on the pin I open the pin editor. The comment says that this option is only supposed to be visible if the player either has a stake item, or their level is 3 or higher.
Sounds like we need two separate variables here. We simulate a simple item system with variables in articy. For this I create (1) a dedicated variable set Inventory (2), to have everything nice and sorted, and a Boolean variable stake (3), with a default value of true (4) for testing purposes.
For level I use the Integer playerLevel
we created earlier to demonstrate an example. Now to the Condition. Inventory.stake == true
, Gamestate.playerLevel > 2
, right? Yes and no. Viewed individually the statements are absolutely fine, the thing is, we cannot have multiple statements in a condition.
There is a solution, however: There are so called “logical operators” we can use to combine multiple comparisons into one statement. There is the logical AND (&&). If we use this all parts must resolve to true for the result to be true. If we have the stake, but are only level 2, no dice.
But that is not want we want here, we are looking for either the weapon or the level requirement. This we can do with the logical OR (||). Now the result of the statement is true if at least one of the parts resolves to true.
An Instruction, by the way, is able to hold multiple statements. They just need to be separated by semicolons.
Before we go to the other options, I’d like to make a little structural change for this branch. I will reposition the connection to the node in front of the Hub. If the Condition is met and this branch is chosen it will give the player an advantage in the upcoming fight encounter. If any other conversation topic is chosen this initial advantage should be gone, this is why I want this option to only be available the first time the player is presented with this choice point.
Now we can take a closer look at the remaining three options. We have one orange input pin, meaning there is a comment waiting for us with an explanation what we are supposed to do with this condition. The last option, with the alternative path to the fight encounter should only be visible when the other two options above this node have been visited. In addition we want to hide the branches we already visited, to avoid asking the same question multiple times.
A standard use case in almost every game project with dialogue. It can be realized with the help of Boolean variables as well, but patch 4.1 for articy:draft X brought in some new toys, which make handling these situations easier and more flexible. We can use the unseen
keyword on the two question branches. unseen
hides a branch after it was visited once. Well, technically it sets the branch to invalid, which is a small but important distinction when it comes to using your data in a game engine. For example in Unity the default setting is to ignore invalid branches and don’t show them. But you could choose to change that and with some custom code instead have the already visited nodes displayed greyed out instead of hidden entirely.
On the third option, we use the fallback()
keyword. fallback()
marks a node that is only shown if all other current branch options are invalid.
That is just one example of the new scripting functionality. In addition to unseen
and fallback()
there is also a seen
keyword and seenCounter
you can in theory access for each and every node in the Flow. Far too much for the scope of the basics series, please check out the Help Center entry to learn more. Alternatively search for “Scripting Unseen” in the In-App Help.
Testing story logic
But now, let’s see how it plays out. You can start a presentation from anywhere in the Flow, right-click the desired node and select “Start presentation from here”.
Select Player Mode (1) which will hide invalid branching options and only shows what a player would see at this moment. Navigate with the arrow buttons (2). For an in-depth look please check out the presentation view lesson.
First time around we see three options. The “Are you ready to die?” branch (1), because we set the default value of the stake variable to true when creating it, which means we satisfy the Condition for the shortcut to the fight. Plus the branches where Mina asks what Dracula is doing in London (3) and why her husband was killed (3).
If we select one of the question branches we receive an answer from Dracula and then jump back to the Hub, meaning we can ask another question.
This time around, we automatically follow the only valid branch of the other question. The shortcut is no longer an option because this branch isn’t connected to the Hub we jumped back to, and the question we asked first is now hidden thanks to the unseen
keyword.
If we follow this path and jump back a last time, both question branches with the unseen
keyword are now invalid, which means that now we see the fallback()
branch and will follow it.
I already mentioned it a bit earlier, but as it is somewhat important, I will say it again: The logic we set up in this little project is not only for internal testing within articy, it is part of data exports and can be used in the game engine. If you are using Unreal or Unity, take a look at our dedicated and free articy Importers for these engine, which come with built-in support for the scripting set up in articy:draft.
This concludes this introduction to scripting in articy:draft. It was focused mainly on Global Variables, but with those alone you can already set up a lot of the basic story logic needed in a game project. Additionally, you can use template properties in scripting and even call custom methods within articy, but this is beyond the scope of this Basics series. For more info please check out the scripting help center entry. There you will also find more advanced videos on the topic.
GO TO “PROPERTY INSPECTOR” LESSON
Useful links:
Help Center: Scripting
Help Center: unseen/seen
Unreal Importer for articy
Unity Importer for articy
Don’t have articy:draft X yet? Get the free version now!
Get articy:draft X FREE
*No Payment information required
Follow us on Twitter, Facebook and LinkedIn to keep yourself up to date and informed. To exchange ideas and interact with other articy:draft users, join our communities on reddit and discord.