Custom Commands
When no built-in Command does what a Dialogue needs, add your own. There are two ways:
| A Command script | A Custom event |
| What it is | A new Command, with its own name and keys. | A value of the Custom command's Command key. |
| Its script | In Scripts/Commands, extends CandyCommand. | In Scripts/Custom_Events, extends CandyCustomEvent. |
| Its data | As many keys as you want. | A single value, the Data key. |
| In Candy Dialogue Creator | Needs a Line Schema for its own button and fields. | Nothing to configure: the Custom line serves it. |
A Custom event is the quickest, for code that requires little or no data. A Command script suits a Command used often, or one with several values.
Command Scripts
Every Command is a script in the Candy_DE/Scripts/Commands folder, or one of its sub-folders: the built-in Commands are the models to start from. To add a Command, add a script there. Its file name is the Command's name, which isn't case-sensitive. The scripts you add are 'safe': updates never modify them. The built-in Commands are 'unsafe': updates overwrite the changes you make to them.
The script extends CandyCommand and declares one function, execute(). This Give_Item.gd script adds a Give_Item command:
extends CandyCommand
func execute(engine: CandyEngine, command_value: Variant, _ctx: CandyContext) -> String:
var symbol: String = candy_de.candy_ref_symbol
var item: String = str(engine.candy_ref.resolve_value(engine, engine, command_value.get("Item", ""), symbol))
var amount: int = int(str(engine.candy_ref.resolve_value(engine, engine, command_value.get("Amount", "1"), symbol)))
Inventory.add(item, amount)
return "Continue"
In a Dialogue, the Line is written like any other:
{"Give_Item": {"Item": "Potion", "Amount": "2"}}
Arguments
| Argument | Value |
| engine | The Engine running the Dialogue. Its variables and functions are reached through it. |
| command_value | The Command's data, as written in the Line: usually a Dictionary of its keys. |
| ctx | The Line being run, a CandyContext: conversation, block, line_index, and line_data (the whole Line). Name them in your error messages, to say which Line has a problem. |
Reading values
- Every value is a String, as Candy Dialogue Creator writes them: convert numbers yourself (
"2"), and read on / off as "1" / "0". - Read keys with get() and a default value, so that a Line where a key is missing doesn't stop your game.
- For a key to accept expressions, pass its value through engine.candy_ref.resolve_value(), as above: a value that starts with the CandyRef symbol is evaluated, and any other is returned as it is.
Return value
The value execute() returns decides what the Engine does next:
| Returns | Effect |
"Continue" | The Dialogue carries on with the next Line. |
"END" | The Dialogue ends. |
"Return" | The Dialogue returns from the current Block, as a Return command does. |
Waiting
execute() can use await: the Dialogue waits for it to return. If your Command waits for something, check the Engine's killswitch afterwards. It's true when the Dialogue was interrupted in the meantime, and the Command must then stop:
await engine.get_tree().create_timer(2.0).timeout
if engine.killswitch == true:
return "END"
Running other Commands
A Command can run another one with engine.commands(), which takes the Command's name, its data and the context. Return what it returns, so that a transition or the end of the Dialogue is carried out:
return await engine.commands("Jump", {"Conversation": "", "Block": "Shop_Closed", "Line": "0"}, ctx)
No state in the script
An Engine runs a single instance of your script for every Line. Store what your Command works with in local variables, never in member variables of the script.
Names
Name your Commands differently from every built-in Command. If two scripts of the folder have the same name, a warning names them and only one is loaded. To change what a built-in Command does, edit its script instead (see Updates, on the Code Modification page).
Adding the Command to Candy Dialogue Creator
Candy Dialogue Creator doesn't know your Command until you describe it: its keys, their fields and their default values. This is done with a Line Schema, a text file that needs no coding. The Command then receives its own button and its own fields, like the built-in ones.
See the Candy Dialogue Creator documentation, under Customization > Line Schemas.
Custom Events
The Custom command runs a script named by its Command key, and passes it its Data key:
{"Custom": {"Command": "open_shop", "Data": "Blacksmith"}}
The script is saved in the Candy_DE/Scripts/Custom_Events folder, named after the Command value: Open_Shop.gd here. It extends CandyCustomEvent and declares one function, handle():
extends CandyCustomEvent
func handle(_engine: CandyEngine, data: Variant, _ctx: CandyContext) -> String:
Shop.open(str(data))
return "Continue"
- data is the Data value. If it was written as an expression, it's already evaluated, so it can be any type of value.
- The return values are the same as a Command script's:
"Continue", "END" or "Return". - handle() can use
await, and run other Commands with engine.commands(). - A Command value with no script is reported, and the Dialogue carries on.
- The scripts you add to Custom_Events are 'safe': updates never modify them.
CS Move
One built-in Command relies on scripts of yours in the same way: CS_Move, which moves nodes during cutscenes. Candy Dialogue Engine can't know how your game moves its characters, so it ships no movement. Each movement is a script that you add to the Candy_DE/Scripts/Move_Events folder, extending CandyMoveEvent, and a target's Movement key names the script that moves it. The scripts you add there are 'safe'. See CS Move.