ChatMapper Cookbook

Table of contents

Part 1. Introduction

1.1. An overview of scripting

1.1.1. Boolean operations

1.1.2. Variables and operations

1.1.3. Special variables

1.2. Dialogue and Group nodes

1.2.1. Conversation node

1.2.2. Dialogue nodes

1.2.3. Group nodes

1.3 Custom Asset Fields (CAFs)

1.3.1. Voice

1.3.2. Voice pitch/rate/volume

1.3.3. Autoplay

1.3.4. Location

1.3.5. Choice caption

Part 2. The Cookbook

2.1. The “Start” node

2.2. The “Replay” node

2.3. Loops

2.4. Assigning and using variables

2.5. Using variables in dialogue

2.6. Random variables

2.7. User input

Part 1. Introduction

The real power of ChatMapper can only be harnessed through the use of scripting. Specifically, Lua (for ChatMapper) and JavaScript (for HTML5 previews/online publishing).

Now, since we already hear some of you running for the nearest fire exit, let me say one thing: don’t be afraid! The building blocks of scripting in ChatMapper are really easy to learn. Sure you can use them creatively to do amazing things, but you will see from even the more advanced examples that it’s child’s play, nothing that requires arcane programming knowledge, so don’t you worry!

Before we begin, let’s take a look at the ChatMapper window as a whole, and name a few things.

Fig.1.1.jpg

Fig.1.1 – An overview of the ChatMapper interface.

  1. The main canvas. The nodes of a conversation will be displayed here. If you open more than one conversation, additional tabs will appear.
  2. Assets: Every actor, item, location and variable is saved under “Assets”, while conversations are saved in the other tab, “Conversations”. 
  3. Scripts and conditions: Most things related to scripting go in one of these two panels.
  4. Overview and properties: Overview shows an image of the whole conversation, with a handle which you can drag and drop to move quickly between areas of bigger conversations. The properties panel is unique for each thing you can click on (actors, dialogue nodes, conversations, items, locations, etc.), and contains – you guessed it – the selected object’s properties.
  5. Menus and shortcuts: pretty self explanatory.

We’ll be referring to these areas many times in this document, so you can use this image as a general reference.

As an aside, please keep in mind that while we will explain the basic functions of ChatMapper briefly, this is only intended as a refresher: We assume you have opened ChatMapper at least once, and played around a bit (even if you did nothing complex).

1.1. An overview of scripting

At the highest level, scripting in ChatMapper can be divided in two parts: “Scripts” and “Conditions”.

  • Scripts are things you want to do. Assign or increment a variable, calculate something, anything active. When you reach a dialogue node, everything in the “Script Editor” tab will be executed. They are by default on the left side of the “Scripts and conditions” area of the interface.
  • Conditions, on the other hand, are evaluated before a node is displayed, and based on the result of that evaluation the node will be visualized, or not. They are by default on the right side of the “Scripts and conditions” area of the interface.

Fig.1.2.jpg

Fig.1.2 – The “Scripts” and “Conditions” panels, with some example expressions.

1.1.1. Boolean operations

There are a few things going on in the image. First of all, when the node is reached, the expression in Conditions is evaluated.

That type of expression, which is either TRUE or FALSE, is called a boolean expression. An example to understand this better would be:

“Are apples the same as oranges?”

Since apples and oranges are different, the answer is no. In boolean terms, the statement is false.

To test if two things are equal, you use the == operator, while the operator ~= means you’re testing if two things are different. So to recap,

apples == oranges → FALSE (it’s false that are apples the same as oranges)

apples ~= oranges → TRUE (it’s true that apples are different from oranges)

Let’s step things up a notch, with the example in the image.

Is 1+1 > 2?

2 is not higher than 2, so the answer is no. Therefore the expression evaluates to FALSE.

Is 1/2 < 3?

0.5 is lower than 3, so the answer is yes. Therefore the expression evaluates to TRUE. 

The or in the middle unites the two expressions, meaning that for the node to be visualized, either the first or the second expression must be true.

In programming this is called boolean logic. You can sum it up to two operators, and and or:

  • and: the condition is true only if both expressions are true. It’s false in all other cases.
  • or: the condition is true if one or both expressions are true. If they’re both false, it’s false.

Will the node in the image, then, be displayed? Yes, because the condition is an or, which means only one of the two expressions must be true (in this case, the second one).

The operators you use to evaluate these conditions are the usual mathematical ones: > (more than), >= (more than or equal to), < (less than), <= (less than or equal to), == (equal), ~= (different).

1.1.2. Variables and operations

The expression in the Scripting panel is straightforward too: it is assigning a variable called result the value of 1 + 1. From then on, whenever we access result its value will be 2.

How do you create a variable? You can do that by clicking the gear icon in the Assets pane under “Variables”, and select “New User Variable”, or by pressing CTRL + SHIFT + U.  You will then be able to add a name (result in the earlier example), an initial value, and if you want a description of what the variable does.

A type for the variable will automatically be selected based on the initial value:

  • Text if the field is left empty or if it contains a letter, a word or a sentence.
  • Number if the initial value is a number.
  • Boolean if the initial value given is true or false.

When the variable has been created, you can use it in scripts or conditions by using Variable[“name”], where name is of course the name of the variable.

A few simple things you can do with variables:

  • Create a “counter” by incrementing a variable each time something happens (a note for programmers: there’s no ++ or — operator in Lua!)

Variable[“counter”] = Variable[“counter”] + 1

  • Check if two variables are the same

Variable[“var1”] == Variable[“var2”]

  • Use them in operations

Variable[“result”] = Variable[“operand 1”] + Variable[“operand 2”]

1.1.3. Special variables

There are a few “specialized” variables, each referring to a certain type of asset:

  • Actor: Actor[“name”]
  • Item: Item[“name”]
  • Location: Location[“name”]
  • Conversation: Conversation[id]
  • Dialog: Dialog[id]

Note that Conversation and Dialog use IDs as identifiers, not names. The ID of a conversation can be found in the “Conversations” tab, while the ID of a node is displayed on the upper left corner of each node

Fig.1.3.jpg

Fig.1.3 – Conversation ID and Dialog ID are circled in red

1.2. Dialogue and Group nodes

Dialogue and group nodes are the bread and butter of Chat Mapper. They are the main elements of a conversation: the first holding all information, the latter as an organizational aid. There is also a third type of node, a conversation node (the root node at the beginning of every conversation), but there’s just one for each conversation and it’s put there automatically, so you don’t really need to worry about it.

Fig.1.4.jpg

Fig.1.4 – Conversation, Dialogue and Group nodes

You can colour any node by clicking one of the 7 colored circles in the menu bar, right above the main canvas.

1.2.1. Conversation node

The conversation node displays the title of the conversation (“New Conversation” by default), and the name of the actor and conversant (in this case “New Player” and “New NPC”).

Fig.1.5.jpg

Fig.1.5 – A conversation node

The green “plus” button (“New Child Dialog”) will create a dialogue node, and parent it to the root.

The “chain” button (“Link to Dialog”) will parent the next node you click on to this node, creating a link (an arrow) between them, going from the root to the new child node.

You can also fold the entire conversation tree by clicking the “-” button in the lower right of the node.

That’s it. See? We told you they were not complicated!

1.2.2. Dialogue nodes

Dialogue nodes contain all the important information in a conversation.

Fig.1.6.jpg

Fig.1.6 – A dialogue node

You can think of them as an interaction in the back-and-forth of a conversation. In the case above, the actor “New NPC” is saying “Hello!” to their conversant, “New Player”.

Functionality-wise, dialogue nodes have an additional button, a folder with a green plus (“New Child Group”): this creates a new group node as a child.

There are a few standard parameters that are fundamental to every demo:

  • Actor: the actor who is speaking in the node. Their name will appear before the sentence, so you should make sure that the correct value is assigned to this field.
  • Menu Text: in the example image, “[f]Choice” is the menu text. this is the text that will appear on the buttons when the player is presented in a choice. Take the below image as an example: the text in this field appears, in the HTML5 preview, as the text on the two choice buttons.

Fig.1.7.jpg

Fig.1.7 – Representation of menu text in the HTML5 preview.

Usually, a single choice will be selected automatically. To force ChatMapper to visualize it, you can add [f] before the menu text.

  • Dialogue: the text that will be spoken by the character

Those are the main features of Dialogue nodes. There are also two small circles on the upper left corner of the node: the small pink one with an S indicates that the node contains a script, while the blue one with a C indicates that there is a condition.

1.2.3. Group nodes

Group nodes are mostly an organizational tool (to, you guessed it, group other nodes), but they also have an important function in conversations, that of giving an anchor for repeating choices.

Fig.1.8.jpg

Fig.1.8 – A group node

Any time you want the user to be given a list of choices until they get the right one, parenting all the children “choice” nodes to another dialogue node will make the text in the parent be spoken every time the user goes through it again. Moreover, the choices won’t appear before an additional click/tap is made by the user, even if the “dialogue” field is empty in the parent. For that reason, by inserting a group node between the dialogue parent and the choice children, you can link back the children to the group node, and no additional clicks will be required, the choices will just appear again, without a hitch.

As you can see in Fig. 8, group nodes have script and condition indicators similar to those in dialogue nodes (again, pink for scripts and pale blue for conditions).

1.3 Custom Asset Fields (CAFs)

CAFs are a way to add functionality to your conversations and demos. They can be seen by going to Project → Project Settings → Custom Asset Fields. By selecting the correct asset tab (actors, items, locations, etc.) and clicking on “Add New Field”, you will be able to create your very own!

CAFs can be of many different types, but the ones most frequently used will be:

  • Number: any numeric CAF will be, of course, of this type. It can be an integer, a decimal number, positive or negative.
  • Text: any CAF using the name of something, or that needs certain “keywords”, will be of type text.
  • Boolean: like with the operations with the same name, CAFs that should be either true or false will be of type boolean. Default value is false.
  • Files: all collections of files (actor pictures, videos, etc.) are of this type. Assigning this type to a CAF (don’t forget the [] default value!) will make you able to add or remove files at will, by letting you browse your hard drive looking for a file and then saving its path when you select it.
  • Location: any field with this type will become a dropdown with a list of the Location assets in your current project. Very useful to change the background of conversations.

There are also a few “special” CAFs, which enable entirely new features in your demo. Their name and type must be exactly the one listed below, and the values you assign to them are very strict too!

Fig.1.9.jpg

Fig.1.9 – Before and after adding the Voice CAF to Actors, with a screenshot of the values used.

1.3.1. Voice

  • Tab: Actors
  • Title: Voice
  • Type: Text

The ResponsiveVoice voice that will be used in HTML5 previews and when publishing. All voice names (which are to be used as the value of this CAF) and their genre are listed here.

1.3.2. Voice pitch/rate/volume

  • Tab: Actors
  • Title: Voice_parameters
  • Type: Text

Most voices support three additional parameters: pitch, rate of speech, and volume. These vary from 0.5 to 1.5, and must be included as a single string formatted like follows (where VAL is of course the value given to that parameter). The default value of each parameter is 1.

{ rate: VAL, pitch: VAL, volume: VAL }

Not all parameters need to be included. If for instance the only parameters wanted are rate (1.3) and volume (0.9), the following can be used:

{ rate: 1.3, volume: 0.9 }

1.3.3. Autoplay

  • Tab: Conversations
  • Title: Autoplay
  • Type: Boolean

When this CAF is added to conversations, the conversation in which this is set as true (it must be only one, otherwise the conversation selector will be shown like always) will begin on its own, without having to choose which conversation to play. Especially useful if you want your conversation to begin from a specific point.

1.3.4. Location

  • Tab: Conversations
  • Title: location
  • Type: Location

This will make you able to assign a location to a conversation, so that the image of that location will automatically appear as the background of that conversation.

1.3.5. Choice caption

  • Tab: Dialogue Nodes
  • Title: choiceCaption
  • Type: Text

If you add text to this field in a node that has Menu Text, it will be visualized above the choice buttons when that part of the conversation is reached. This is useful if you want to add the text of a question above the list of choices, for example, to remind players what they’re deciding on.

Part 2. The Cookbook

What follows is a list of “recipes” for ChatMapper. Each one contains the instructions to create a certain kind of element or structure in a conversation, similar to the recipe for a certain dish!

2.1. The “Start” node

A starting point is very important for users. Consider a scenario in which you have Autoplay on for a conversation, and the user loads your demo for the first time: without an “anchor”, the dialogue will begin without the user expecting it! This can be extremely damaging to the overall experience, and for that reason we suggest implementing the Start node.

The Start node is simply a dialogue node, at the beginning of a conversation (before anything is said by the actors of course, otherwise it would be kind of pointless!), that forces its menu text to display.

Fig.2.1.jpg

Fig. 2.1 – Properties panel of the Start node. Yes, it’s that easy!

As you can see from the image, to force the display of a choice you just need to add [f] at the beginning of its menu text. If you don’t, the node will be automatically selected (since it’s the only possible choice) and you won’t have a starting point.

With Autoplay and the Start node you can do all sorts of wonderful things. At LearnBrite, for instance, we often use it for setup to set all variables to the correct starting value (so that, when we link back to it at the end, variables are reset automatically), or to run some additional Javascript.

2.2. The “Replay” node

Like the Start node, the Replay node is very useful, and we include it in almost every demo we create.

The concept is fairly similar: it’s a single node, used as both an anchor (for the player) and to execute a script behind the scenes (for the developer). In this case, the script resets every important SimStatus to “Untouched” and every variable to to their initial value. It also sets any values used to display or hide the conversations, so that the next node visualized will be either the Start node or the node from which you want players to begin the experience again.

Fig.2.2 – The key to the Replay node is the link back to a node at the beginning.Fig.2.2.jpg

To reset variables, you can include a line like this in the Replay node’s script:

Variable[“name”] = initial value

Where name is the variable’s name (which has to go between quotes) and initial value is, well, the initial value of the variable.

If you set a node to only be visualized once, remember to set its SimStatus to Untouched, otherwise it won’t show up on replays! You can do so by adding this line to the Replay script:

Dialog[id] = “Untouched”

Where id is the number on the upper left corner of the node the SimStatus of which you want to reset.

2.3. Loops

A loop is a conversational structure in which you go from a node to its parent, and then back to the node. It’s very useful, for instance, if you want to ask a series of questions to an NPC, but you want to let the player decide in which order.

In the example, the player is asked to list the first five colours of the rainbow. Here is the canvas:

Fig.2.3.jpg

Fig.2.3 – A  colorful loop.

The trick here is that each of the coloured nodes is linking back to their parent group node (so that the text in node 1 is not repeated every time), and disappears from the choices after being selected once (through the condition Dialog[id] ~= “WasDisplayed”, where id is each node’s ID (the number on the upper left corner of each node: red is 3, orange is 4, etc.).

Node 9, in which the NPC says “Fine, you can go!” has a different condition, which is

Dialog[3].SimStatus == "WasDisplayed" and

Dialog[4].SimStatus == "WasDisplayed" and

Dialog[5].SimStatus == "WasDisplayed" and

Dialog[6].SimStatus == "WasDisplayed" and

Dialog[7].SimStatus == "WasDisplayed"       .

That means that it will only be displayed when all the nodes listed has been displayed (which in this case means that we answered the NPC’s question).

There is one other thing going on, which is the [f] in all menu texts. We’re forcing the display of every choice, even if there is only one. If you want the last one to be picked automatically, without having to click it, you can simply forego the [f]s in your implementation.

2.4. Assigning and using variables

Now that we understand how conditions and loops work, how about we do something more interesting with them?

Fig.2.4 – A simple escape.Fig.2.4.jpg

In this example, the player has to open a door, but the door is locked; they won’t be given the possibility to unlock it until after they have searched the room and found the key.

By creating a boolean variable called hasKey (false by default), we’re already halfway done. What’s left after is to check in relevant nodes whether we have said key or not, or in the case of node 2 set hasKey to true, because we just found the key!

  • Node 3 condition, Variable["hasKey"] == false: The player can try the door an infinite number of times, but as long as they don’t have the key it won’t budge. When the player finds the key, this choice will disappear.

  • Node 2
  • Script, Variable["hasKey"] = true: we found the key, so we change the value of hasKey to true.
  • Condition, Dialog[2].SimStatus ~= "WasDisplayed": no need to search the room multiple times, so we only let the player go through this node once.

  • Node 5 condition, Variable["hasKey"] == true: when the player has found the key, we let them go through the door, and the demo ends.

To recap:

  1. First we create a boolean variable, that expresses whether or not the player has found the key.
  2. Then we set up a loop through node 3, so that the player can’t progress until they search for the key.
  3. When the player searches for the key nodes 3 and 2 disappear (as node 3 is only visualized if the player doesn’t have the key and node 2 is only visualized once), but node 5 – freedom – appears (through checking that the player has found the key).


Easy peasy!

2.5. Using variables in dialogue

Variables are not only very useful to control the flow of the conversation, you can actually include their value in the text! Say you want your player to change a number from a list of three, but you don’t know which number they’ll choose. Either every time that number comes up you create three different dialogue nodes, one for each possible choice, or you simply include the variable itself in the dialogue!

Let me illustrate: on the left the nodes in the conversation, and on the right (highlighter in black) what the dialogue is like when previewing it. Note that you can also see the line of code I included in node 2, for reference.

Fig.2.5.jpg

Fig.2.5 – The initial value, changed to 7, and then displayed again.

As you can see we have the variable magicNumber, whose default value was set to 1, mentioned in the text of two dialogue nodes. The syntax is fairly straightforward, you just insert the name of the variable in [var=name], and that will be substituted for the value itself when previewing or publishing.

2.6. Random variables

Now that we know how to assign a variable, we can step up and create a variable that will have a random value every time we start the conversation. This is really useful if you have a repetitive scenario (for instance a training scenario), and you want to change the choices the player has to make in order to succeed (e.g. the client you’re training has a random disposition towards you at the beginning of the conversation, so how you talk to them changes even if the scenario itself is the same).

To do this, we first have to go over a bit of ChatMapper’s inner workings: while ChatMapper itself and the simulator work with Lua, when previewing in HTML5 or publishing a build all the code you wrote is converted in JavaScript (otherwise it wouldn’t work online). You can exploit this to your advantage, and use the features of JavaScript (like we do in section 2.7) not native to ChatMapper; for this section, though, we will limit ourselves to analyzing the interplay between Lua and JavaScript.

If you want this randomization to work on previews and builds, you insert this in the script where you want that value to be calculated:

var jsVariable = Math.random();    .

Variable["cmVariable"] = jsVariable;

What this does is create a JavaScript variable, called jsVariable, and uses the JavaScript Math library (a collection of scripts to calculate many mathematical operations, like square roots, medians, etc.) to create a random number. This returns a floating-point, pseudo-random number in the range [0, 1]; that is, from 0 (inclusive) up to but not including 1 (exclusive)

If you want your random number to be between two inclusive numbers, you can do it like so:

window.getRandomIntInclusive = new Function('min','max','{min = Math.ceil(min);max = Math.floor(max);return Math.floor(Math.random() * (max – min + 1)) + min;}');

var jsVariable = getRandomIntInclusive(min, max);

Where min is the lower whole number value and max is the higher one. After that, we assign that to a variable we created  in ChatMapper, called cmVariable, and now you can do whatever you want with it, it’s a variable like any other. You can display it in dialogue, or use it in some other script or condition, or anything else you’d do with another variable.

If you’re working only with Lua and the simulator, you can tweak that code a bit. Since you don’t need to use Javascript, you can simply use the Lua math library and that’s that:

Variable["randomVariable"] = math.random(min, max);

“Why doesn’t this work in the preview?” We hear you ask. “Isn’t Lua code translated into JavaScript?”. Well, yes and no. When it comes to variables, operations, conditionals, etc., Lua code is translated without a hitch. Unfortunately, since libraries change for each language (a library that exists in a language may be absent in another, or have a completely different name), it’s impossible to translate them. It will work if they have the same exact name, but as you can see even having different capitalization (the Lua library is math, the JavaScript library is Math) will stop this mechanism from working. Be sure to always check out the name of any library you want to use!

2.7. User input

If you’re working with HTML5 (i.e. if you are previewing and publishing your work), you can ask the user for input!

Fig.2.6 – On the right, the box displayed through prompt();Fig.2.6.jpg

You can do many different things with JavaScript, one of which is displaying the box on the right of Fig.2.6. How? It’s easy!

var name = prompt("What's your name?");

Variable["name"] = name;              .

By adding these two lines of code a node (node 2 in the image) you can display a box with a text field. At the same time, we’re saving the contents of that text field to the JavaScript variable name when the user clicks okay, and then copying those to its Lua twin, Variable[“name”], so that we can use it in the dialogue itself.

Note that if the user doesn’t input anything, the variable will be empty, and the sentence will come out like this:

Fig.2.7 – The player has not given any input.Fig.2.7.jpg

It’s fairly easy to prevent that by adding a few more lines of code (in bold), which will assign a default name in case the user leaves the field empty:

var name = prompt("What's your name?");

if (name == "") {                     .

        Variable["name"] = "Hayden";         .

}else{                                .

   Variable["name"] = name;        .

}                                     .

This structure is called an if-else: if the condition between parenthesis is true (in this case name == "", i.e. name is empty), execute the instructions between the following brackets (i.e. assign “Hayden” as a name); otherwise (else) execute the instructions between the last pair of brackets (i.e. assign to the variable what the user wrote).

How useful was this article?

Click on a star to rate it!

We are sorry that this article was not useful for you!

Let us improve this article!