No scripting is required in the Dialogue System. However, the Dialogue System does offer a general-purpose scripting language called Lua that provides a very powerful method of controlling the flow of conversations, checking and changing quest states, and more. In most cases, you can use simple point-and-click menus.
The Dialogue System uses the data model established by Chat Mapper, another professional dialogue authoring tool commonly used in the industry. Information about all actors, items, locations, variables, and conversations is stored in Lua tables. You can control conversations by specifying Lua conditions and scripts, typically by using point-and-click menus. For those who are interested, the Chat Mapper manual has more background info about Lua and the tables that the Dialogue System uses, in the section titled Scripting with Lua.
You can use Lua in the following areas of the Dialogue System:
In most places where you can enter Lua code manually (if you prefer), you can also click a '...' button to switch the field into point-and-click mode. In this mode, you can use dropdown menus without having to type any code:
Click '+' to add new conditions or actions. Click Revert to cancel or Apply to apply your selections, which will close the dropdown menus and write the Lua code for you:
If you prefer to write Lua code directly, you'll find that it's similar to C# or UnityScript. For more information on Lua, see www.lua.org. There are a few syntax differences to be aware of:
Operator | C#/UnityScript | Lua | Lua Example |
---|---|---|---|
Not equal | != | ~= | Quest["Kill_5_Rats"].State ~= "success" |
Logical AND | && | and | Variable["HasCoke"] and Variable["HasMentos"] |
Logical OR | || | or | (Actor["Player"].Age > 21) or Item["Beverage"].IsNonalcoholic |
String concatenation | + | .. | Actor["Player"].FullTitle = "Dread Lord " .. Actor["Player"].Name .. " of Skull Island" |
if | if(x==y) | if (x==y) (blank space req'd) | if (x == y) then foo() end |
Special Exception: LuaInterpreter "and not"
The default Lua implementation that ships with the Dialogue System is LuaInterpreter. This is a fast, lightweight C# implementation of Lua. However, it does not parse one valid Lua syntax:
X and not Y
. You can work around this limit by modifying your syntax slightly or by switching to a different Lua implementation.
Note that Lua, like C# and UnityScript, is case-sensitive.
Here are some examples that you can use in a dialogue entry's Conditions field or the Condition section of a Dialogue System Trigger component.
Check if a Boolean variable has been set true (note the use of double equals "==" to test equality):
Variable["flippedSwitch"] == true
Check if a quest is in a specific state:
CurrentQuestState("Kill 5 Rats") == "success"
Check if the player is at least 21 and has at least one beer:
(Actor["Player"].Age >= 21) and (Item["Beer"].Count > 0)
Here are some examples of setting values. You can use them in a dialogue entry's Script field or in the Lua Code action of a Dialogue System Trigger
Set variables (note the use of single equals "=" for assignment):
Variable["spokeToKing"] = true; Variable["Gold"] = Variable["Gold"] + 50
Set a quest to a specific state:
SetQuestState("Kill 5 Rats", "active")
Combining two strings (using Lua's '..' notation):
Actor["Player"].FullTitle = "Dread Lord " .. Actor["Player"].Name .. " of Skull Island"
A table in Lua is similar to an array or dictionary in C# or UnityScript. The following Dialogue Systemspecific tables are available to your Lua scripts:
Table | Description | Example |
---|---|---|
Actor[] | Two-dimensional table containing all actors. | Actor["Player"].Age |
Item[] | Two-dimensional table containing all items/quests. | Item["Anvil"].Weight |
Quest[] | An alias for the Item[] table. | — |
Location[] | Two-dimensional table containing all locations. | Location["Starbase"].Description |
Conversation[] | Two-dimensional table containing all conversations, indexed by ID. | Conversation[9].Title |
Variable[] | One-dimensional table containing user variables. | Variable["Alert"] = "Hello!" |
In this Lua code:
Actor["Player"].Age = 21
the string "Player" is the key or index. The Actor["Player"] part is the table element. This is sometimes called a record in Lua guides. The Age part is the field. The code above sets the player's Age field to 21.
The Dialogue System also manages these variables in the Variable[] table:
Variable | Description |
---|---|
Variable["Alert"] | Set to tell the Dialogue System display an alert message. |
Variable["Actor"] | The name of the actor in the current conversation (if any) |
Variable["Conversant"] | The name of the conversant in the current conversation (if any) |
Variable["ActorIndex"] | The actor's index in the Actor[] Lua table |
Variable["ConversantIndex"] | The conversant's index in the Actor[] Lua table |
The variables Variable["Actor"] and Variable["Conversant"] contain the display names of the participants. The variables Variable["ActorIndex"] and Variable["ConversantIndex"] are the indices in the Lua Actor[] table. You can use them in your dialogue entries' Conditions and Script fields. For example, to check if the current conversant is at least 21 years old:
Actor[ Variable["ConversantIndex"] ].Age >= 21
Table keys and field names are generically called indices. The Dialogue System follows a convention established by Chat Mapper:
In Chat Mapper tables, replace all space characters and hyphens with underscores in indices.*
Here are some examples:
In the Dialogue Database | In Lua |
---|---|
A variable named Kissed the Frog | Variable["Kissed_the_Frog"] |
An actor named Mister Big | Actor["Mister_Big"] |
The actor's Favorite Color field | Actor["Mister_Big"].Favorite_Color |
The Dialogue System adds several useful functions to Lua, including:
These Chat Mapper functions are available in Lua to record statuses and relationship values. The descriptions of these functions come from the Chat Mapper documentation:
Chat Mapper can track a status that is defined between any two assets, which is referred to as a mutual status. To set or access a mutual status, use the following two functions:
Chat Mapper can also track numerical relationship values between any two actors. Relationships can be used to control NPC responses based on a relationship value. These are the relationship fuinctions:
The Dialogue System does not support the Chat Mapper functions below, which have have no meaning outside Chat Mapper:
To show an alert message:
To get and set quest states (described in more detail in Quests):
While you can technically set quest states by setting the Quest[] Lua table directly, it's better to use these functions because they also update the quest tracker HUD and send OnQuestStateChange messages that your scripts can listen for.
The function GetLocalizedText() retrieves localized versions of fields in the Actor, Item, Quest, or Location tables. For information about setting up localized fields, see Appendix 1: Localization.
where:
GetLocalizedText() Example:
Say your actors have a "Nickname" field and a Spanish-localized field named "Nickname es". To use the localized version in a conversation, use the [lua(...)] tag to call GetLocalizedText():
The function RandomElement() returns a random element from a list. It's commonly used in [lua()] tags to add variety to your dialogue text.
where string is a string of elements separated by the horizontal bar character ('|').
RandomElement() Example:
Say you have an NPC that greets the character with a random honorific title. In your dialogue database, click on the Variables tab and define a variable named Honorifics that contains this list:
"Esteemed|Revered|Great|Magnificent"
Or, to set it in Lua code:
Variable["Honorifics"] = "Esteemed|Revered|Great|Magnificent"
In the dialogue entry, set the text to:
The result is that the NPC will randomly use one of the element in the Honorifics list, such as "Greetings, Esteemed One!" or "Greetings, Great One!"
The source string doesn't have to be set at design time. You can generate it dynamically during gameplay. You can use RandomElement() for other purposes, too, such giving the player a random item upon completion of a quest, or even choosing a random quest out of a list.
The Dialogue System includes Lua functions that synchronize variables and quest states to all clients using Unity Networking's High Level API (UNET HLAPI). To make these functions available:
USE_UNET
The functions above set a variable locally and on all other clients. Use in place of Variable["foo"] = value when you want all clients to receive the value of the variable.
The functions above set a quest state or quest entry state on all clients. Use in place of SetQuestState() and SetQuestEntryState().
The PixelCrushers.DialogueSystem.DialogueLua class is the easiest way to access Lua data.
The PixelCrushers.DialogueSystem.DialogueLua class is the easiest way to access Lua data.
To get and set data in the standard Dialogue System Lua tables – Actor[]
, Item[]
, Location[]
and Variable[]
– use these methods:
Method | Description | Example |
---|---|---|
GetVariable() | Get the value of a variable | bool hasBox = DialogueLua.GetVariable("hasBox").asBool |
SetVariable() | Set the value of a variable | DialogueLua.SetVariable("hasBox", true); |
GetActorField() | Get the value of a field in an actor | int xp = DialogueLua.GetActorField("Player", "XP").asInt; |
SetActorField() | Set the value of a field in an actor | DialogueLua.SetActorField("Player", "Intoxicated", true); |
GetItemField() | Get the value of a field in an item | float weight = DialogueLua.GetItemField("Anvil", "Weight").asFloat; |
SetItemField() | Set the value of a field in an item | DialogueLua.SetItemField("Anvil", "Cost", 50); |
GetQuestField() | Get the value of a field in a quest. Equivalent to GetItemField() | string state = DialogueLua.GetQuestField("Kill 5 Rats", "State").asString; |
SetQuestField() | Set the value of a field in a quest. Equivalent to SetItemField() | DialogueLua.SetQuestField("Kill 5 Rats", "State", "success"); |
GetLocationField() | Get the value of a field in a location | string desc = DialogueLua.GetLocationField("Moonbase", "Description").asString; |
SetLocationField() | Set the value of a field in a location | DialogueLua.SetLocationField("Moonbase", "Description", "A desolate lunar spaceport."); |
The DialogueLua class automatically converts table indices' spaces and hyphens to underscores. When using the DialogueLua class, you can ignore the note in Important Note About Table Indices. (However, when bypassing the DialogueLua class and using the Lua class directly, you must remember to convert spaces and hyphens to underscores yourself. You can use the DialogueLua.StringToTableIndex() function to do this.)
The DialogueLua.GetXXX()
methods return a Lua.Result
value. To get a basic data type, use properties such as asString
, asInt
, asFloat
, and asBool
. For example:
The Actor[]
, Item[]
, and Location[]
tables are two-dimensional, meaning each element in the table has fields. Use the DialogueLua.GetXXXField()
methods to access their fields.
The Variable[]
table, on the other hand, is one-dimensional. The elements are regular data types (Boolean, string, number, etc.), so you cannot use the DialogueLua.GetXXXField()
methods. Instead, use DialogueLua.GetVariable()
.
The PixelCrushers.DialogueSystem.QuestLog class provides simpler functions to work with quests. (See Quests.)
To get the version of a field for the current language, use the localized versions of these methods:
Method | Description |
---|---|
GetLocalizedActorField() | Get the value of a localized field in an actor (e.g., "Description es" for Spanish) |
SetLocalizedActorField() | Set the value of a localized field in an actor |
GetLocalizedItemField() | Get the value of a localized field in an item |
SetLocalizedItemField() | Set the value of a localized field in an item |
GetLocalizedQuestField() | Get the value of a localized field in a quest. Equivalent to GetLocalizedItemField() |
SetLocalizedQuestField() | Set the value of a localized field in a quest. Equivalent to SetLocalizedItemField() |
GetLocalizedLocationField() | Get the value of a localized field in a location |
SetLocalizedLocationField() | Set the value of a localized field in a location |
For example:
The PixelCrushers.DialogueSystem.Lua class provides lower-level access to the Lua environment through these functions:
Method | Description | Example |
---|---|---|
Run() | Run Lua code and return a Lua.Result structure | int nextYear = Lua.Run("return Actor['Player'].Age + 1").AsInt; |
IsTrue() | Run Lua code and return true if the Lua result is true, otherwise false | if (Lua.IsTrue("Actor['Player'].Age >= 21")) {...} |
RegisterFunction() | Register a C# method as a Lua function | Lua.RegisterFunction("Exists", null, typeof(MyClass).GetMethod("Exists")); (*see below) |
Remember that Lua.Run()
returns a Lua.Result
that can be a Boolean, string, number, or table. To get the Boolean value, you need to add ".AsBool", as in this example:
Similarly, if your variable is a number, you can do this:
Since Lua.IsTrue()
always returns a Boolean value (true
or false
), you don't need to add as
XXX to the end:
The RegisterFunction()
method lets you tie your own C# code into the Lua environment. This is extremely handy to add new capabilities to your dialogue entry Conditions and Scripts. Use the corresponding UnregisterFunction()
method to unregister the C# method from Lua.
For example, say you want a dialogue entry to be available only when a certain GameObject named "White Elephant" is in the scene. You want to be able to set the dialogue entry's Conditions field to this:
GameObjectExists("White Elephant")
Simply add this class to your scene:
IMPORTANT: C# methods registered with Lua must use double
for numbers, not float
or int
.
Only use these types in your Lua functions' parameters and return values:
Type | Notes |
---|---|
double | LuaInterpreter uses doubles for all number types; you can cast to (int), (float), etc inside your function if necessary |
bool | Use as normal |
string | Use as normal |
Important Notes:
double
. In your C# methods, use double
instead of float
or int
.You can find a starter template script in Templates ► TemplateCustomLua.cs. To add your own Lua functions, make a copy of this template and customize it as indicated by the comments in the script.
For Universal Windows Platform compatibility, or to enforce type validation on the function's parameters, use this alternate format to register Lua functions:
In some cases, you may want to be notified when the value of a Lua variable changes.
The DialogueManager class lets you manage observers on Lua expressions using these methods:
Method | Description | Example |
---|---|---|
DialogueManager.AddLuaObserver() | Add an observer on a Lua expression | DialogueManager.AddLuaObserver("Variable['Credits']", LuaWatchFrequency.EveryDialogueEntry, OnCreditsChanged); |
DialogueManager.RemoveLuaObserver() | Remove an observer | DialogueManager.RemoveLuaObserver("Variable['Credits']"); |
DialogueManager.RemoveAllLuaObservers() | Remove all observers | DialogueManager.RemoveAllLuaObservers(); |
AddLuaObserver() adds an observer on a Lua expression that will be checked on a specified frequency. The frequency can be EveryUpdate, EveryDialogueEntry, or EndOfConversation. If the expression changes, the Dialogue System will invoke a delegate that takes the form:
Example:
Note: For best performance, limit the number of observers you set, especially when the frequency is EveryUpdate. Each observer requires an extra Lua call to evaluate the current state of the Lua expression.
RemoveLuaObserver() removes an observer. The observer is identified by the Lua expression, which should exactly match the same string that you passed to AddLuaObserver()
. RemoveAllLuaObservers() removes all observers.
The Lua Console component adds an in-game console in which you can run Lua expressions. By default, the console is mapped to ~+L but you can change the key binding.
The Dialogue System uses Liu Junfeng's Lua Interpreter under MIT License. The included version has been modified to be compatible with UWP projects. It does not implement the following functions:
The Dialogue System provides a PixelCrushers.DialogueSystem.Lua wrapper class which isolates the actual Lua implementation from the rest of the Dialogue System. If you want to use a different Lua implementation, you only need to replace these classes:
<< Welcome to the Dialogue System for Unity! | Cutscene Sequences >>