Index
Page Contents

Conversation Scripts

This file briefly describes how to write NPC conversation scripts and the features available through them.


Conversation scripts consist of a header portion followed by a list of conversation nodes. Conversation scripts are stored as plain text files with the txt extension.

Conversation scripts are composed from lines. Each line provides a directive followed by parameters. Some directives can be expanded upon with more directives placed on the following line with one tab character preceeding them.

Warning:It is critical for some directives to work that they be placed immediately following their parent directive on a new line (with no blank lines preceding them and a single tab character before the directive. Hitting space multiple times to look like a tab will not work, it must be the tab character.
Info:Why not JSON?
A JSON version of conversation scripts exists as well, but is better suited for editors than hand-authored files. For hand-authored files the txt format is smaller, easier to read and write, and far less error prone (no tabbing or brackets to keep track of).

Sample Conversation Script File

.start say: Hello there, my name is Torliila, but most everyone calls me "hey you, bait girl". option: Nice to meet you, Torliila link: .kind-greeting option: Hi bait girl! link: .rude-greeting .kind-greeting say: Would you like to buy some fishing gear? ... .rude-greeting say: Yes.. I am "bait girl". pose: Bemused

Author Remarks

Remarks or comments can be indicated with two hyphens. During parsing anything that follows two hyphens on a line will be ignored.

Tip:Be careful to avoid two hyphens appearing in a row in character dialog. A character cannot say the text "Go over there ----->" for example.

Sample:

-- Text Styles include: data/conversation-styles/isle-of-kasau/torliila.txt .start ------------------------------------------------------ say: Hello!

In this example the line "-- Text Styles" is completely ignored.
Also the hyphens following the .start node declaration are ignored, as it starts with '--', and can be used to provide a nice visual break between conversation nodes.

Include Directive

The include: directive simply takes the contents of one file and inserts it into another where the 'include:' directive appears. Includes are currently limited to 5 files deep.

Includes are the recommended way of placing a character's text styles into their conversation file. There is no reason text styles cannot be defined in the conversation file directly (they can), but including styles allows for styles to be referenced by multiple files.

Use of the include directive is also recommended for conversations involving multiple characters and for quest-related dialog. For example if the characters Torllia and Ramasu were to have a conversation together it is recommended that a new conversation script be created named "ramasu-torliila.txt" with a node named ".ramasu-torliila-start". Both torliila and ramasu's conversation scripts could then include "ramasu-torliila.txt" and each file could have it's own .start node and conversation tree. Each character might have their own line of dialog, and then have a player response link the conversation to ".ramasu-torliila-start". See the "Multi-Character Conversations" heading below for more information.

Likewise for quests it may make it easier for editing to place quest-related dialog into their own files, and have the player's primary conversation script determine if a quest is active and if a link into that quest's conversation nodes is appropriate.

Warning:Be careful when using includes to keep node identifiers unique. Don't have torliila.txt provide a node named ".about-torliila" and then also define ".about-torliila" in a shared conversation like "ramasu-torliila.txt". Whichever node is defined last will override the first.

Sample Script

include: data/conversation-styles/torliila.txt

In this sample the contents of the linked file are read and inserted in place of the include:... line.

Conversation Nodes

Nodes are the primary building block of conversations. Each node has an identifier that always begins with a period, such as ".start". New conversation nodes are defined by simply placing the node identifier on a new line.

Special Nodes

.start Node

When a player speaks to an NPC for the very first time the conversation will automatically open at the .start node. Like other nodes the .start node can contain scripts that send the conversation to another node before speaking begins.

.familiar Node

When a player returns to an NPC they have met before the conversation will start at the .familiar node.

Displaying Dialog

The say: directive displays a single "page" of dialog to the player. Care should be taken to ensure the text is short enough to appear in the text box in-game. (About 2 sentences max, depending on font size).

The pose: directive can be added after a say: or more: directive to set the character's pose for that page of text.

Example

say: Hello there, it is good to see you again! pose: Happy

Random Flavor Text

Multiple say: directives can be used in a node to denote variations of text. Only a single say: directive will be presented to the player. Conditions can be placed on say: directives to determine if a text variation should be included in the pool for random selection.

Info:In the future nodes will have a mode setting that toggles them between "first to pass conditions" or "random variation" mode. In "first to pass" mode the first instance of the say: directive that passes it's check: directive will be displayed.

Example

say: Hello there, it is good to see you again! pose: Happy say: A pleasant day for you! pose: Smug

In this example the character may say "Hello there, it is good..." or they may say "A pleasant day for you!". If those say: directives are expanded with multiple pages using more: a single variation including it's additional pages will be picked.

Adding Dialog Pages

Additional pages of dialog can be added to a say: directive with the more: directive. Each more: will appear as it's own step in the conversation. Each page defined via more: can have it's own speaker and pose set.

Example:

say: Hello there, it is good to see you again! pose: Happy more: Will you be going to the festival today?

In this example the first page of dialog "Hello there, it is good..." will appear, and the player will be presented with a button to display the next page of text. When the player presses the button the next page will display "Will you be going to the festival today?"

Multi-Character Conversations

speaker: directive

camera: direction

Player Responses

After a say: directive the player can be prompted to provide a response via the option: directive. Up to 6 response options can be defined per node.

The option: directive is usually followed by the link: directive on the next line. The link directive sets where the option will take the conversation if the player selects that response. If no link is provided for the option then the player's character will speak their response and then the conversation will end.

Note:Technically more than 6 can be defined, but only the first 6 will be displayed. There may be case where this is used in combination with the check: directive to provide a changing set of options to the player.

Example

say: Would you like to join the Guild of Mages? option: Yes, that sounds good. link: .join-mages-guild-yes option: This isn't the right guild for me. link: .join-mages-guild-no

Lua Scripting

A lot more functionality is available to the conversation system through lua scripting.

The run: directive is used on a node to execute lua code when conversation enters the node. The code will be executed before any say: or option: directives, in case the lua code needs to change the current conversation node.

Each line of lua code must be preceded by the lua: directive.

Info:In the future there may be a lua-include: directive that allows lua code to be imported which can define additional functions. At that time it may make sense to start create a lua file for each character and use the run: directive to execute functions, rather than embed multiple lines of code in the conversation script.

LUA code defined across multiple run: directives on a node will be combined into a single script before execution, so loops and if statements should work fine.

Example

.give-quest -------------------------------------------------------------------------------------- -- Run lua code to give the player the quest and set some variables run: GiveQuest("torliilas-fishing-boutique", pc_id) run: SetConversationVar(pc_id, "gave-quest", true) run: SetPersistentClientVar("isle-of-kasau.fishing-contest.stage", "preparation" ) say: Wonderful, I look forward to your help with this.

In this example when the conversation reaches the .give-quest node the quest will be given to the player, a conversation variable will be set, and a persistent client-side variable will be set that could affect all player clients.

Basic Conversation Redirection

The link: directive can be used on a node without player response to say some dialog then link to a node that provides a common menu of responses.

Additionally lua scripting can use the SetCurrentConversationNode function to set the current conversation node using conditional logic.

Conditions on Player Options

The check: directive can be added to player response options to enabledisable or showhide a dialog response option. When using the check: directive the LUA script must end with a call to "return " with two boolean parameters. The first determines if the option is available to the player (or grayed out), the second determines if the option is visible to the player at all.

Example

.mynode say Are you a member of the Security Guild? option: Yes, I am check: reputation = GetParticipantGuildReputation(pc_id, "taipii-security-guild") check: return repuation > 0, true link: .is-member option: No, I'm not a member. link: .is-not-member

In this example the "Yes I am" response is always visible to the player, but only enabled if the character's reputation in the guild is above zero.

Special LUA Functions

The following functions are available to LUA script when used in a conversation script.

Note:These functions can only be used in conversation scripts. Calling these functions from LUA code outside of a conversation will result in an error.
  • GetCurrentConversationNode(pccharacterid) - Gets the current conversation node id.
  • SetCurrentConversationNode(pccharacterid) - Moves the conversation to a new conversation node id.
  • GetNPCVariable(name) - Gets a custom variable placed on the NPC. (Any conversation can read/write this variable.)
  • SetNPCVariable(name,value) - Sets a custom variable on the NPC. (Any conversation can read/write this variable.)
  • GetConversationVariable(pccharacterid,name) - Gets a custom variable set on the conversation (distinct for the pc + npc pairing)
  • SetConversationVariable(pccharacterid,name,value) - Sets a custom variable set on the conversation (distinct for the pc + npc pairing)

Give Items to Character

give-items: directive

Sell Items to Character

sell-items: directive

Defining Text Styles

Text styling can be defined using the style: directive.

style: mystyle [f:robot:20|c:rgba:1.0,1.0,0.7,1|fx:typewriter(100,0)]

Each style is defined with the style: directive, followed by a style name, followed by a text style inside square brackets.

In this case the style name is "mystyle", and the formatting includes:

  • f:robot:20 - Set font to 'robot', font size 20
  • c:rgba:1.0,1.0,0.8,1 - Set text color to these rgba values: red: 1.0, green: 1.0, blue: 0.8, alpha: 1.0
  • fx:typewriter(100,0) - Add the Typewriter effect. 100 characters per second, 0 fade-in
Tip:See the "Text Styling" header below for more information about text styling options.

After defining the style, the new style can be used in dialog like this:

say: Hello there, what a [mystyle]strange[] day!

In this case the word "strange" would appear with the text style defined for "mystyle". The empty style brackets [] always set the style back to "default". "default" is a style that can be defined for each character using the style: directive.

Setting up Per-Speaker Styles

When each style is declared it is associated with the current speaker. Therefore it is important to set the speaker to the appropriate character before defining styles, otherwise you will be changing the player's text style.

To set up styles for a character use the speaker: directive before the style directive thusly:

speaker: ramasu style: default [f:robot:20|c:rgba:1.0,1.0,0.7,1|fx:typewriter(100,0)] style: item-type [default|c:blue] style: character [default|c:green] style: keyword [default|c:gold] ...

Now these styles will be used whenever "ramasu" is speaking.

It is good practice to put each character's text style into it's own file in the data/conversation-styles/... path and include it from the player's conversation file. Also be sure to include it any any multi-character conversation files that include that character, in case they were not the NPC the player interacted with to start the conversation. (There's generally no harm including the style file multiple times like this.)

The Player's Text Style

All conversation scripts are automatically prepended with the contents of data/conversation-styles/_common.txt followed by data/conversation-scripts/_common.txt.

The common style file defines styles for the player's characters, denoted by the speaker set to "". It's probably best to just leave these files alone for now, but be aware that's where those styles come from if there is an issue.

Text Style Options

Text that is displayed using the say:, more:, and option: directives can include additional formatting including font changes, text color, and animated effects.

Each character of text that is displayed has a style associated with it. At the start of the line the style is set to the text style defined as "default" for the current speaker. The style can be changed by placing a new set of style instructions inside of square brackets in the dialog.

Example:

say: Hello there, [c:red]it is hot today![].

For this example the text "it is hot today!" will appear red.

Directly setting the style "in-line" like this is discouraged. The preferred way of changing styles is through speaker-associated defined styles. See the heading "Defining Text Styles". Defining styles simply provides a reusable style associated with a name.

speaker: ramasu style angry [c:red] ... say: Hello there, [angry]it is hot today[].

This example does the same thing as the one above, except this time the style is given the name "angry", and we can make text red by adding [angry]..[] around the text.

The advantage to using named styles is that we can easily change the style in one place and everything that references updates. If for example we wanted to change the color from red to orange to indicate that the character is angry we now only have to do it in one place. Styles should ideally describe an emotion or intent, rather than simply naming the style something like "red".

Basic Text Formatting Options

Inside the square brackets of a style a variety of text settings can be changed. A style can modify multiple settings, with subsequent settings separated by a pipe character like this: [f:robot:10|c:red].

Formatting options include:

Setting Syntax Description
font f:font-name:font-sizeSets the font and font size.  Available Fonts
kerning adjustk:spacing Adjust the font kerning, or the distance between characters.
text color c:color-name Set the text to one of several available named colors. Options: white, gray, pink, red, purple, magenta, violet, blue, cyan, green, yellow, orange, gold
text color c:rgb:r,g,b Set the color to rgb values. R, G, and B are in the range of 0-1 (floating point).
text color c:rgba:r,g,b,aSet the color to rgb values plus alpha. R, G, B, and A are in the range of 0-1.
text color c:hsl:h,s,l Set the color to hue, saturation, luminescence values. H, S, and L are in the range of 0-1.
text color c:hsla:h,s,l,a Set the color to hue, saturation, luminescence values plus alpha. H, S, L, and A are in the range of 0-1.
fx fx:effect_name(...)Adds an effect to the text style. See list of effects below.

Text Effects

Available text effects include:

Name Syntax Description
jiggle fx:jiggle(amount) Characters randomly jiggle around by amount pixels.
wave fx:wave(speed,frequency,amount)Characters bob up and down by amount pixels. frequency controls length of wave, speed controls how quickly they bob up/down.
typewriter fx:typerwriter(speed,fade)Characters appear one at a time. speed is how many characters appear per second. fade controls if the characters appear immediately (0), fade in based on speed (1), or fade in more slowly (>1)
shadow fx:shadow(alpha,blur,offset-x,offset-y)Renders a shadow under the text. Alpha and blur control appearance, while the offset parameters control the x/y offset of where the shadow appears.