Original Post
Making your own tutorials with Toribash 5.4+
Starting with version 5.4, Toribash features a new way to create and run tutorials which doesn't require extensive Lua scripting knowledge.
This guide expands on how to create your own tutorials, what they can be used for and how to run them afterwards.

This guide has been updated as per Toribash 5.60 (build 230522) which brought several changes to how custom tutorials testing works compared to method described in the original guide.

New tutorial system basics

New system allows (relatively) simple creation of new tutorials / events which may feature replay cutscenes, load various mods, display messages and so on. You can see it in action by loading any tutorial or in-game event (e.g. Hole in the Wall).

Any tutorial consists of minimum 2 data files, one of which contains tutorial instructions and the other is a localization file for messages. Instructions are then loaded by tutorials manager class and run as an actual tutorial. This means that for simpler tutorials you won't need any Lua coding knowledge.

Tutorials consist of steps and use a specific set of instructions which are similar to Toribash chat commands or Toribash-specific Lua functions. All instructions can be roughly divided into two groups: those that act as conditions to pass to next step and those which don't (this is also expanded upon below). Once all requirements to end the step are met, current step is finished and the next one begins automatically.

Creating your first tutorial

Let's say we want to make a simple tutorial that plays 150 frames of a replay, then shows a message and then asks the player to move one of Tori's bodyparts.
To do that, we first create two data files which will be used for the tutorial. Say the tutorial is going to be called mytutorial1, this means we make two files named the following way:
  • mytutorial1.dat - this file will contain all tutorial instructions.
  • mytutorial1_english.txt - this file will contain all tutorial messages in English
One thing to keep in mind - your tutorial must have an English localization. You can add other localization files (and may define all the messages there), but tutorialname_english.txt file has to exist.

After these files are created, open .dat file with any text editor.

With the first step, we want to load a replay. We'll also hide hud and make sure current player's character is displayed on Tori spot:
OPT hud 0;
LOADREPLAY mytutorial_replay.rpl;
Every step has to begin with STEP; instruction. After that, we use OPT instruction to set hud to 0, load our replay and load PLAYER (current user) on spot 0 (Tori). Note that LOADREPLAY doesn't automatically start the replay - it will be paused instantly after loading.

For second step, we play 150 frames of the replay:
This one is pretty obvious, PLAYFRAMES 150; instruction plays 150 frames and then pauses the replay.

Third step we display our message. There are two ways of showing messages to user: we can show a general "hint" message or make it look like that's some tutorial character speaking. For this one, we'll go with a character line:
SAY mtCharacter;
SHOWSAYMESSAGE; command triggers message box. You only need to run this before showing your first message to user - if we wanted to display another message instantly after this one, having this command among step instructions won't do anything.
SAY [characterName]; commands sets message author to display their name and head texture (if found in customs folder). Here's an example of how it looks.
After that, we set the message that's going to be shown to the user: MESSAGE [messageStringName];. Message string name should correspond to one of text strings from tutorial localization file - see more below.
Last command we add is WAITBUTTON; which pauses tutorial execution until user presses enter or clicks "Continue" button. This is optional, but giving user some time to make sure they've read the message is usually the way to go.

After the message is shown, we need to hide message box and enter edit mode to later wait for user to move a bodypart on their character's body:

OPT tooltip 1;
With the first step, we hide say message box, simple.
After that, we enter edit game mode (as we previously were in replay mode), enable tooltip (optional) and set joint movement requirement with MOVEJOINT [jointName] [jointState]; command. This one specifically, would require the user to change their right knee's joint state to "Extending".

That's it, now we're finished with the .dat file. The only thing that remains now is to set the intro message in localization file. To do that, we put the following line in mytutorial_english.txt file:
INTROMSG	Hi, this is my first tutorial!
Pay attention to the fact that string name and the message must be separated by tab and not just any whitespace character.

And now the tutorial is ready to be run! You can read on how to run it below.

Data file syntax

Below you can see a complete list of all currently available commands as of Toribash 5.60.

Notice: all commands must be followed by semicolon (;)

Command arguments preceded with ? are optional.
Commands marked with * act as conditions to pass to next step.
Commands marked with * are optional conditions and require a proper condition to pass to next step to work correctly.

List of available commands

Using custom Lua functions

As the title suggests, you can use custom Lua code within your tutorials.
To do that, you first need to create a [mytutorialname].lua file in same location as other tutorial data files.
This file is loaded on tutorial launch; any functions you want to run with .dat file should be returned at the end of the file or put in a global functions table (legacy method):
lua code:
local function myFunction(viewElement, reqTable)
echo("Hello world")

return {
MyFunc = myFunction

All custom functions will always receive two arguments by default, viewElement and reqTable. You can safely ignore them in some cases, but they'll be of great use if you want to expand your tutorial gui or add custom step completion conditions.
  • First argument passed to the function is a UIElement object that exists while current step is active and is destroyed once it's over. You'd typically want to attach any custom UI elements to this object as it ensures they'll only exist during current step.
  • Second argument is a list of current step requirements (serialized as TutorialStepRequirement[] with EmmyLua annotations) to move on to the next step (or fall back). By adding elements to this list, you can add your own custom requirements or modify existing requirements and/or their completion states.

There are also two hook namespaces that may come in handy: tbTutorialsCustom and tbTutorialsCustomStatic.
First one is used for hooks that you only want to run while current step is active, second one will keep hooks running until tutorial ends.
Here's an example of tbTutorialsCustom usage to wait for player to press a specific key as it's used in Punching Tutorial:

Tutorials, UIElement, UIElement3D, Files, MoveMemory and Tooltip classes will be always available for your custom Lua code, but if you want to use functions from other Toribash classes or other Lua files make sure to include them separately to be sure they're available.

Tutorials class itself is defined in data/script/system/tutorial_manager.lua.
If you're looking for more examples of how custom Lua code can be used for tutorials or events, feel free to check existing game tutorials (data files are located in data/tutorials and custom Lua code for them is located in data/script/tutorial/data) or events (all files located in data/script/event/).

Running your tutorial

Alright, so you got your files in one place, now you only need to run it as an actual whole thing.
Your whole tutorial can be loaded with a single Lua call:
lua code:
Tutorials:loadTutorial(tutorialName, tutorialPath)

You can also download this script that will allow you to launch the tutorial with a custom name / path: runTutorial.lua
To use it, run /ls runTutorial.lua test mytutorials to load "test" tutorial from data/script/mytutorials folder. Alternatively, you can load the same tutorial by its absolute path by adding the ../ prefix to the path: /ls runTutorial.lua test ../data/script/mytutorials.
Last edited by sir; May 23, 2023 at 09:36 AM.