Loading and Running Yarn Scripts
Welcome to the YarnRunner library usage tutorial. In this guide, we'll show you how to load and run the Yarn narrative script you wrote in the previous tutorial.
1. Initializing YarnRunner
- Lua
- Teal
- TypeScript
- YueScript
First, make sure you have imported all the necessary modules. Here's the list of modules we will use in this example:
local Content <const> = require("Content")
local Path <const> = require("Path")
local Node <const> = require("Node")
local Director <const> = require("Director")
local YarnRunner <const> = require("YarnRunner")
To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:
local path = Path:getScriptPath(...)
Content:insertSearchPath(1, path)
Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:
local runner = YarnRunner("tutorial.yarn", "Start")
First, make sure you have imported all the necessary modules. Here's the list of modules we will use in this example:
local Content <const> = require("Content")
local Path <const> = require("Path")
local Node <const> = require("Node")
local Director <const> = require("Director")
local YarnRunner <const> = require("YarnRunner")
To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:
local path = Path:getScriptPath(...)
Content:insertSearchPath(1, path)
Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:
local runner = YarnRunner("tutorial.yarn", "Start")
First, make sure you have imported all the necessary modules. Here's the list of modules we will use in this example:
import { Content, Path, Node, Director, YarnRunner } from "Dora";
To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:
const path = Path.getScriptPath(...);
Content.insertSearchPath(1, path);
Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:
const runner = YarnRunner("tutorial.yarn", "Start");
First, make sure you have imported all the necessary modules.
_ENV = Dora
import "YarnRunner"
To ensure we can locate the Yarn script, we need to set the correct search path. If the Yarn script and program modules are in the same directory, you can add the following code:
path = Path\getScriptPath ...
Content\insertSearchPath 1, path
Next, assuming our Yarn file is named "tutorial.yarn" and the starting node title is "Start", we write the following code:
runner = YarnRunner "tutorial.yarn", "Start"
2. Executing and Displaying Narrative Content
We define an advance
function that can read and display text or options from the Yarn script. Based on the content, it can also display the character's name:
- Lua
- Teal
- TypeScript
- YueScript
-- The advance function takes an optional integer representing the player's choice index.
-- For the first call or when no choice is needed, we pass nil.
local function advance(option)
-- First, we call runner:advance(option) to get the next part of the Yarn script.
-- This returns two values: an action type and a result.
local action, result = runner:advance(option)
-- Handle the result based on the action type.
if action == "Text" then
-- If the action is "Text", the result will be a TextResult object,
-- containing the text and any associated markers (e.g., character names).
-- Check the markers, extract the character's name (if present), and print the text.
local characterName = ""
local marks = result.marks
if marks then
for i = 1, #marks do
local mark = marks[i]
if mark.name == "char" then
characterName = mark.attrs.name .. ": "
end
end
end
print(characterName .. result.text)
elseif action == "Option" then
-- If the action is "Option", the result will be an OptionResult object,
-- containing one or more options. Iterate over the options and print them,
-- allowing the player to select them later.
for i, op in ipairs(result) do
if op then
print("[" .. tostring(i) .. "]: " .. op.text)
end
end
else
-- For other actions (like errors), print the result directly.
print(result)
end
end
-- The advance function takes an optional integer representing the player's choice index.
-- For the first call or when no choice is needed, we pass nil.
local function advance(option?: integer)
-- First, we call runner:advance(option) to get the next part of the Yarn script.
-- This returns two values: an action type and a result.
local action, result = runner:advance(option)
-- Handle the result based on the action type.
if action == "Text" then
-- If the action is "Text", the result will be a TextResult object,
-- containing the text and any associated markers (e.g., character names).
local textResult = result as YarnRunner.TextResult
-- Check the markers, extract the character's name (if present), and print the text.
local characterName = ""
local marks = textResult.marks
if not (marks is nil) then
for i = 1, #marks do
local mark = marks[i]
if mark.name == "char" then
characterName = tostring(mark.attrs.name) .. ": "
end
end
end
print(characterName .. textResult.text)
elseif action == "Option" then
-- If the action is "Option", the result will be an OptionResult object,
-- containing one or more options. Iterate over the options and print them,
-- allowing the player to select them later.
local optionResult = result as YarnRunner.OptionResult
for i, op in ipairs(optionResult) do
if op and not (op is boolean) then
print("[" .. tostring(i) .. "]: " .. op.text)
end
end
else
-- For other actions (like errors), print the result directly.
print(result)
end
end
// The advance function takes an optional integer representing the player's choice index.
// For the first call or when no choice is needed, we pass null.
function advance(option?: number): void {
// First, we call runner.advance(option) to get the next part of the Yarn script.
// This returns two values: an action type and a result.
const [action, result] = runner.advance(option);
// Handle the result based on the action type.
switch (action) {
case "Text":
// If the action is "Text", the result will be a TextResult object,
// containing the text and any associated markers (e.g., character names).
// Check the markers, extract the character's name (if present), and print the text.
let characterName = "";
const marks = result.marks;
if (marks) {
for (const mark of marks) {
if (mark.name === "char") {
characterName = `${mark.attrs?.name}: `;
}
}
}
print(characterName + result.text);
break;
case "Option":
// If the action is "Option", the result will be an OptionResult object,
// containing one or more options. Iterate over the options and print them,
// allowing the player to select them later.
const optionResult = result;
for (let i = 0; i < optionResult.length; i++) {
const op = optionResult[i];
if (op && op !== true) {
print(`[${i}]: ${op.text}`);
}
}
break;
default:
// For other actions (like errors), print the result directly.
print(result);
break;
}
}
-- The advance function takes an optional integer representing the player's choice index.
-- For the first call or when no choice is needed, we pass nil.
advance = (option) ->
-- First, call runner\advance to get the next part of the Yarn script.
-- This returns two values: an action type and a result.
action, result = runner\advance option
-- Handle the result based on the action type.
switch action when "Text"
-- If the action is "Text", the result will be a TextResult object,
-- containing the text and any associated markers (e.g., character names).
-- Check the markers, extract the character's name (if present), and print the text.
charName = ""
if result.marks
for mark in *result.marks
switch mark when {name: attr, attrs: {:name}}
charName = "#{name}: " if attr == "char"
print charName .. result.text
when "Option"
-- If the action is "Option", the result will be an OptionResult object,
-- containing one or more options. Iterate over the options and print them,
-- allowing the player to select them later.
for i, op in ipairs result
print "[#{i}]: #{op.text}" if op
else
-- For other actions (like errors), print the result directly.
print result
3. Starting the Narrative
To start the narrative, simply call the advance
function without any arguments:
- Lua
- Teal
- TypeScript
- YueScript
advance()
advance()
advance();
advance!
4. Handling User Input
To enable player interaction, we need a node to capture and respond to user input. We create a node and assign it a signal slot named "go". When this signal is triggered, it will call the advance
function again, passing the player's choice:
- Lua
- Teal
- TypeScript
- YueScript
local node = Node()
node:gslot("go", function(option)
advance(option)
end)
node:addTo(Director.entry)
local node = Node()
node:gslot("go", function(option: nil | integer)
advance(option)
end)
node:addTo(Director.entry)
const node = Node();
node.gslot("go", (option: number | null) => {
advance(option);
});
node.addTo(Director.entry);
with Node!
\gslot "go", (option) -> advance option
\addTo Director.entry
Here, we registered a global event listener for quick testing. In actual game development, you'd need to write the UI interaction logic. Once this "go" global event listener is set, you can use the Dora SSR console to input emit 'go'
to continue the dialogue, or emit 'go', 1
to select dialogue branches for interactive test runs.
5. Adding Custom Commands and State
You can add custom commands and initial state variables by passing the command
and state
parameters to YarnRunner
. The command
parameter is a Lua table containing callback functions for commands, and state
is a table with predefined variables. Here’s an example:
- Lua
- Teal
- TypeScript
- YueScript
local runner = YarnRunner("tutorial.yarn", "Start", {
playerScore = 100
}, {
print = print
})
local runner = YarnRunner("tutorial.yarn", "Start", {
playerScore = 100
}, {
print = print
})
const runner = YarnRunner("tutorial.yarn", "Start", {
playerScore: 100
}, {
print: print
})
runner = YarnRunner "tutorial.yarn", "Start", {
playerScore: 100
}, {
print: print
}
Then, in the Yarn script, you can modify initial variable values using <<set $variable = expression>>
and print variables using the custom command <<print $variable>>
:
<<set $playerScore = $playerScore + 200>>
<<print $playerScore>>
6. Conclusion
Now, you have set up all the necessary code to load and run Yarn narrative scripts. You can run the above script to begin your interactive narrative, where players can interact by selecting options. Happy creating!