dev 2020-06-09
This page is not meant for users.
Discussions
For discussions the TALK adapter is preferred. The adapter takes an optional 2-letter language tag. This reference uses the onTalk event which is fired on talk interactions, but you may start a discussion from any event offering the char parameter.
The following example shows a simple dialogue with 3 reply options:
function onTalk( char )
{
/*TALK en
# NAME this Zelda
user: Hello, I'm [user]. Who are you?
this: My name is [this] and I rule this kingdom. What are you going to do?
Fight Ganon
user: I'm here to fight Ganon!
this: Foolish you! Ganondorf is too strong.
user: No I'm the hero!
this: Oh, really? I hear this once a day, at least.
Destroy you
user: I'm here to fight you!
this: ...
this: Guards!
Nothing
user: I'm sorry. Nevermind.
TALK*/
}
Branches are intended by tabs as shown in the example. After 2 lines of introduction the discussion offers 3 different branches the user may choose from.
The example assigns the name Zelda to the speaker referred by this. Likewise the engine automatically assigns user to the user's name. Names and faces can be changed during the discussion.
To avoid confusion you should not place any code after the TALK blocks. Such code would be executed immediately (before the actual discussion starts), not after the discussion.
Conditions
The talk adapter supports numerous commands to script discussions.The following example shows a changing welcome after the first meeting:
function onTalk( char )
{
/*TALK en
# NAME this Traveller
user: Hi there!
# IF met
this: Oh it's you again.
# ELSE
# SET met
this: Hello, nice to meet you.
# END
TALK*/
}
The example checks whether the met flag was set. If so, the player had this talk before and is welcomen back. Otherwise the met flag is set and the user is initially greeted. To swap the unnatural order of this discussion the NOT or NIF command could be used instead of IF.
First meeting
The FIRST command acts like a shortcut to the above. Here's the same example code:function onTalk( char )
{
/*TALK en
# NAME this Traveller
user: Hi there!
# FIRST met
this: Hello, nice to meet you.
# ELSE
this: Oh it's you again.
# END
TALK*/
}
Note that the ELSE part could easily be left out.
Different names
If you don't want the player to know the NPC's name by default you may either change the name by using the NAME command or assign multiple names from the beginning. A good way to implement the first meeting is by defining the first name in addition to this as shown below:function onTalk( char )
{
/*TALK en
# NAME first Traveller
# NAME this Olivia
# FIRST met
first: Yes please?
user: Hello! I'm [user] and who are you?
first: My name is [this]
user: Nice to meet you, [this]!
this: Same here!
# ELSE
this: Oh it's you again.
user: Yes, I'm back!
# END
this: What do you need?
TALK*/
}
In this example the first: lines will be spoken by Traveller whilst this: is assigned Olivia. The change happens right before the ELSE line.
Switch
The following example achieves a similar effect, but counts the times met:function onTalk( char )
{
/*TALK en
# NAME this Stranger
user: Hi there!
# ADD counter
# SWITCH counter
# IS 1
this: First time we meet.
# IS 2
this: Second time you're talking to me.
# IS 3
this: Talking to me again?
# DEFAULT
this: You again..? We already met [counter] times! Get lost.
# END
TALK*/
}
Note that ADD automatically initializes the counter. Furthermore DEFAULT handles all unspecified cases.
Rand
If you just want to output a random text use RAND instead of SWITCH:function onTalk( char )
{
/*TALK en
# NAME this Innkeeper
# RAND
# IS
this: Welcome!
# IS
this: Hello!
# IS
this: Come in!
# END
this: How can I help you?
Rent a room
# RAND
# IS
user: I'd like to rent a room, please.
# IS
user: I need a room for tonight.
# IS
user: Give me a room, please.
# END
this: Very nice! Here's your key!
user: Thank you.
Leave
user: Sorry, wrong door.
this: Bye!
TALK*/
}
Likewise the STEP command will advance through the set of outputs each time.
Note that the IS values are automatically counted and filled in. Since this might not work for complex scripts you can also specify the number of cases and their values manually (see reference).
Hide replies
To hide or disable discussion replies use conditional scripting for replies.The following example shows and hides replies:
function onTalk( char )
{
/*TALK en
# NAME this Dealer
user: Hey there!
this: Hello... what'ya want?
user: I wanna buy stuff.
this: What's the password?
# IF known
Shroomz
user: Shroomz
this: That's right.
# NOT known
Onion
user: Onion?
this: No, it's not.
user. So what is the damn password?
this: It's "shroomz" you fool.
# SET known
# NOT known
Cheese
user: Cheese?
this: Not quite...
user. So what is the damn password?
this: It's "shroomz" dude.
# SET known
TALK*/
}
Notice how parts of the code are duplicated for each reply. To avoid duplicating large parts (and to make complex dialogues cleaner) discussions can be split over multiple events.
Splitting discussions
The following example shows how to split discussions using CONTINUE:function onTalk( char )
{
/*TALK en
# NAME this Shopkeeper
this: Hey there! Need a potion?
Yes!
# CONTINUE mySecondTalk
Gimme!
# CONTINUE mySecondTalk
O'course!
# CONTINUE mySecondTalk
TALK*/
}
function mySecondTalk( char )
{
/*TALK en
this: Great, here you are!
# char.inventory.createItem( "potion" );
user: Thank you.
TALK*/
}
Notice how NAME is not set again in the second function because it's kept during the whole discussion.
Breaks
Important: In the last example you'll notice a # followed by generic JS code. Despite it's position after the first line of talk this code gets executed before any output starts. Add a break if you want the item to be created after a certain line was spoken:function onTalk( char )
{
/*TALK en
this: I've got something for you.
user: What is it?
# .
# char.inventory.createItem( "potion" );
user: A potion! Enjoy.
TALK*/
}
In general use breaks to execute scripts after a certain line of discussion. To keep this in mind it's good practice to place all instantly executed code at the very top of each branch.
Waiting
To pause the discussion (eg. while moving the camera) the WAIT command can be used. This will disable the discussion and set an internal timer to resume the branch after the given delay.function onTalk( char )
{
/*TALK en
# NAME this Narrator
user: Let me wait for 3 seconds.
this: Alright, let's begin.
# .
# WAIT 3
this: How was that?
user: Great!
TALK*/
}
Notice that before the WAIT command there's a single dot breaking the discussion. Without the dot the WAIT timer would be executed too early. Since there's no output between . and WAIT nothing (except the greyed-out "X") will be shown while waiting.
Known bug: If the user reloads while waiting the last message (instead of nothing) will be displayed.
To display a message put it between these lines:
function onTalk( char )
{
/*TALK en
# NAME this Narrator
this: You know...
# .
this: This message will display for 5 seconds and you can't cancel it.
# WAIT 5
this: Okay. That was boring.
TALK*/
}
Facesets
Similar to names facesets can be applied during discussion. When set, faces can be selected by either naming an emotion or providing the x/y position in brackets. If not given the default face at 0,0 is displayed.function onTalk( char )
{
/*TALK en
# NAME this Batman
# FACE this batman.png
this: Hey I'm Batman!
this (blush): *cough cough* ... I mean...
this (evil): I'm Batman.
this (3,1): And I'm gone.
TALK*/
}
Handling languages
You don't have to set NAME and FACE for each language when applying these before the discussion part:function onTalk( char )
{
char.talkSetName( "this", "Mario" );
char.talkSetFace( "this", "mario.png" );
/*TALK en
this: Hello I'm [this].
TALK*/
/*TALK de
this: Hallo ich bin [this].
TALK*/
}
Note that the name property is automatically taken from this.values if possible.
For heavily scripted parts languages may also be scripted inline:
function onTalk( char )
{
/*TALK **
[de] this: Guten abend.
[en] this: Good evening!
TALK*/
}
The language can also be set to ** which applies to all language settings.
Discussion script reference
SET name [value=1] | If name contains a dot a custom namespace is used and can be accessed from other instances (eg. "SET torial.guard"). Otherwise the current target's class values are accessed. Special case: level.name gives you access to the map's class values. |
FIRST name | Run once; effectively a shortcut for "IF NOT name; SET name" |
SWAP name | Swaps the values 0 and 1. |
ADD name [value=1] | Increases the value. |
SUB name [value=1] | Decreases the value. |
DEL name | Removes the value. |
IF [!]name [==] [comp=1] | |
NOT name [comp=1] | This is a shortcut for IF !name. |
OR [!]name ... | At least two name must be specified. |
AND [!]name ... | At least two name must be specified. |
RANGE value min max | Runs when value is between min and max (both inclusively). |
ELSE [name] | Counterpart for IF, allows checking for another value. |
END | |
CIF code | Evaluates if( code ) |
ECIF code | Evaluates else if( code ) |
SWITCH name | |
RAND [max] | Randomizes from 1 to max (if given). |
STEP [count] | Steps through the cases by increasing an internal counter each time. |
IS [value] | The value is optional for #STEP# and #RAND# switches. |
DEFAULT | |
NAME target value | |
FACE target filename | |
PITCH target [soundname] mul | |
GIVE [name] [count=1] | Create item in player inventory. |
TAKE [name] [count=1] | Remove item from inventory. |
GOT [CAT] [name] [count=1] | Check availability of ITEM (default), YOT, SKILL, INFO |
LACK [CAT] [name] [count=1] | Inverse of GOT. |
EVENT name | Executes this.doEvent( name, char );. |
CONTINUE name | Executes this.doEvent( name, char ); return;. |
WAIT [seconds] | Actually creates a new branch. Thus not allowed within conditions. |
. | Shortcut of WAIT. Use this to prevent early discussion scripts execution. |
RETURN [value] | |
MARK name | Always place marks at the beginning of a branch. |
JUMP [mark] | Continue discussion from mark (from start, if not given). |
REPEAT [mark] | Continue discussion from mark (from start, if not given) keeping the current output. |
# code | Executes code. |
The following commands of the above list are available in replies, too:
- IF
- NOT
- OR
- AND
- RANGE
- CIF
- SET
- GOT
- LACK
Multiple conditions can be combined by listing them in multiple lines:
function onTalk( char )
{
/*TALK en
this: Are you ready?
# IF prepared
# IF equipped
# GOT ITEM armor
Show equipment
user: Yes, let's go!
TALK*/
}
In this example the Show equipment line only shows up when all 3 conditions are met.