-
Notifications
You must be signed in to change notification settings - Fork 0
03 Scripting
The plugin uses a domain-specific language for its core functionality. The basic building blocks are
# this sets the current dialog box. `someBoxScene` needs to be an initialized scene
[someBoxScene]
# this displays the output to the player
# `somesprite` is used for the portrait and `sometext` is the message, both can be expressions
# the dictionary after it is passed as `options`. if omitted, an empty dictionary is passed
somesprite: sometext {
someparam = somevalue
}
# this creates an input for the player to respond to in accordance to the `someInputType` descriptor
# after that, `somevar` is assigned to the player's output
# the dictionary literal is passed as `options` to the dialog box
# `somevar` is optional and if omitted the result is not assigned
# the dictionary containing `options` is optional. an empty dictionary is passed if none present
somevar <- someInputType {
someparam = somevalue
}
# matching by value after input is also optional
- somebranch1 # branch executed if player's output is same as `somebranch1`
do1
- somebranch2 ? condition # this branch is only created if `condition` is true
do2
--
dodefault
# matching uses the same syntax
somevalue:
- somematch1 # branch executed if `somevalue == somematch1`
do1
# in this case, because `?` is an operator, the branch equals `somematch2` if `condition` is true and `null` otherwise
# if `somevalue` is `null`, it might still match this branch
- somematch2 ? conditon
do2
--
dodefault
# if statements are
? somecond1
do1
# multiple conditional statements in a row get joined into if-else chains
? elsecond2
doelse2
?! # the else branch terminates the chain of conditionals
doelse
? cond1
do1
. # the dot terminates the chain of conditionals
? cond2 # checked independantly of `cond1` branch
do2
.
# any other line is treated as an expression
somevar = someval1 + someval2Numbers can only be digits 0-9, with optional period. For example 12345, 12.34.
.5 or 1. are not valid numerals. Different bases, such as hex 0xae, binary 0b1001 or octal 0x765 are not currently supported
Strings are quoted with either " or '. String interpolation is supported: a part of a string can be delimitered by {}. In which case, the contents are executed as an expression, for example
somevar = "a"
somevar2 = "b"
edwin: "Vars {a} {b} {a + b} {2 ** 4 + 3}" # outputs "Vars a b ab 19"
edwin: "No vars \{a} \{2 ** 4 + 3}" # backslash escapes interpolation, so output is "No vars {a} {2 ** 4 + 3}"
All strings are interpolated in the context they are used in.
Resources can be loaded using ^"res://path/to/resource" syntax. For example ^"res://sprites/portraits.edwin.png", ^"res://scripts/cutscene.gd", ^"res://dialogBoxes/default.tscn". If the loaded resource is a script or a scene, it is instantiated automatically.
This means, a script can be imported by binding = ^"res://path/to/script.gd" and setting a dialog box is possible via [^"res://path/to/dialogBox.tscn"].
For most scenarios, no special naming conventions or prefixes are required. Valid names are somevar, somevar123, _othervar.
However, a local variable might shadow a global one. To force accessing a global variable, its name can be prefixed with %, for example, %Inventory will not look for a local variable named Inventory.
Most of Godot's built-in functions, objects and types are accessible by the same identifier with the DSL
Any expression written in the DSL can both access Godot's internal operators and use overloads. First, overloads are checked, and if any are present, that method is executed. Otherwise, execution falls back to Godot's built-in operators.
All operators in the DSL are:
| Operator | Overload | Note |
|---|---|---|
| a in b | _in | |
| a () b | _call | |
| a [] b | none | Accessing a member |
| a . b | none | Accessing a member |
| a ** b | _pow | |
| a */ b | _root | Falls back to a ** (1.0 / b)
|
| a * b | _mul | |
| a / b | _div | True division(not rounded) if both a and b are integer |
| a % b | _mod | |
| a // b | _floor_div | |
| a + b | _add | |
| a - b | _sub | |
| a > b | _gt | |
| a < b | _lt | |
| a >= b | _ge | |
| a <= b | _le | |
| a == b | _eq | |
| a != b | _ne | |
| a && b | _land | Can convert a and b to bool if they implement _to_bool method |
| a | b | |
| a ^^ b | _lxor | Can convert a and b to bool if they implement _to_bool method. Falls back to bool(a) != bool(b)
|
| a & b | _and | |
| a | b | _xor |
| a ^ b | _xor | |
| a = b | none | |
| a ? b | none | if b is falsey, returns a. b can reference a as _ *note
|
| a ?! b | none | if a is null, returns b |
Any overloadable operator can have a secondary method prefixed with _r for when self is the right hand side. For example, for 5 + someCustomClass, int does not implement _add. If CustomClass impelemnts _add_r, that method is called with 5 as the argument. Otherwise, the interpreter falls back to using Godot's native addition
*note: For example, "Red" ? prevColor != _ will return null if prevColor == "Red". This is primarily used for branches in input statements(any branch matching a null is ignored). If the right hand size of the ? has a _, _ is substituted with the left hand side value. If no _ is present, left hand side is not evaluated unless right hand side is true.
The language supports scoped goto's. This means that it is possible to jump to any label within the current scope or any parent scope.
|-> label is used for declaring a label, |<- label is used for jumping to that label, for example
test: "Which?" {
autoconfirm = true
}
flavor <- option
- "Cinnamon"
- "Chocolate"
- "Banana"
- "Plain"
repeating = false
test: "Topping?" {
autoconfirm = true
}
|-> "Repeat topping" # declaring a label to jump to
topping <- option {
noSelectionReset = repeating
}
- "Cinnamon" ? _ != flavor ?! "[color=gray]Cinnamon\n[font_size=16]already main flavor[/font_size][/color]"
- "Chocolate" ? _ != flavor ?! "[color=gray]Chocolate\n[font_size=16]already main flavor[/font_size][/color]"
- "Banana" ? _ != flavor ?! "[color=gray]Banana\n[font_size=16]already main flavor[/font_size][/color]"
- "Plain" ? _ != flavor ?! "[color=gray]Plain\n[font_size=16]already main flavor[/font_size][/color]"
? flavor in topping
repeating = true
|<- "Repeat topping" # jumping to force selecting a different option
test: "Selected {flavor} with \{{topping}}"
Note that all labels are hoisted, meaning, the value of the label is determined before any other code runs. This means that using dynamically set variables in a label is impossible. It is, however, possible to use dynamic values in jumps