feat: added example + tutorial

(also did some fixes)
This commit is contained in:
Bram Dingelstad 2021-11-27 22:05:24 +01:00
parent 1cae6b75cc
commit 0fd71a9940
12 changed files with 343 additions and 111 deletions

View file

@ -5,7 +5,7 @@ func _ready():
$VBoxContainer/ButtonTemplate.hide() $VBoxContainer/ButtonTemplate.hide()
$Wol.connect('line', self, '_on_line') $Wol.connect('line', self, '_on_line')
$Wol.connect('option', self, '_on_option') $Wol.connect('options', self, '_on_options')
$Wol.connect('finished', self, '_on_finished') $Wol.connect('finished', self, '_on_finished')
func continue_dialogue(): func continue_dialogue():

View file

@ -0,0 +1,24 @@
extends Node2D
var current_dialogue
func _ready():
$Sally/DialogueStarter.connect('body_entered', self, '_on_player_near_dialogue', [$Sally, true])
$Sally/DialogueStarter.connect('body_exited', self, '_on_player_near_dialogue', [$Sally, false])
$Ship/DialogueStarter.connect('body_entered', self, '_on_player_near_dialogue', [$Ship, true])
$Ship/DialogueStarter.connect('body_exited', self, '_on_player_near_dialogue', [$Ship, false])
func _on_player_near_dialogue(_player, node, entered):
print('body entered?', entered)
if entered:
current_dialogue = node.name
else:
current_dialogue = null
func _process(_delta):
if Input.is_action_just_released('ui_accept') and current_dialogue and not $Dialogue/Wol.running:
print(current_dialogue)
$Dialogue/Wol.starting_node = current_dialogue
$Dialogue/Wol.path = 'res://ExampleDialogue/%s.yarn' % current_dialogue
$Dialogue/Wol.start()
print($Dialogue/Wol.variable_storage)

View file

@ -0,0 +1,232 @@
[gd_scene load_steps=7 format=2]
[ext_resource path="res://Dialogue.tscn" type="PackedScene" id=1]
[ext_resource path="res://ExampleDialogue/Player.gd" type="Script" id=2]
[ext_resource path="res://addons/Wol/Wol.gd" type="Script" id=3]
[ext_resource path="res://ExampleDialogue/ExampleScene.gd" type="Script" id=4]
[sub_resource type="RectangleShape2D" id=1]
[sub_resource type="CircleShape2D" id=2]
radius = 62.2013
[node name="ExampleScene" type="Node2D"]
script = ExtResource( 4 )
[node name="Dialogue" parent="." instance=ExtResource( 1 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 1024.0
margin_bottom = 600.0
[node name="Wol" type="Node" parent="Dialogue"]
script = ExtResource( 3 )
variable_storage = {
}
[node name="Player" type="KinematicBody2D" parent="."]
position = Vector2( 360, 488 )
script = ExtResource( 2 )
[node name="Visuals" type="Node2D" parent="Player"]
[node name="ColorRect" type="ColorRect" parent="Player/Visuals"]
margin_left = -21.0
margin_top = -52.0
margin_right = 19.0
margin_bottom = -12.0
color = Color( 0, 0, 0, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect2" type="ColorRect" parent="Player/Visuals"]
margin_left = -8.0
margin_top = -47.0
margin_bottom = -28.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect4" type="ColorRect" parent="Player/Visuals"]
margin_top = -23.0
margin_right = 8.0
margin_bottom = -19.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect3" type="ColorRect" parent="Player/Visuals"]
margin_left = 7.0
margin_top = -47.0
margin_right = 15.0
margin_bottom = -28.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LeftFoot" type="ColorRect" parent="Player"]
margin_left = -12.0
margin_top = -14.0
margin_right = -8.0
margin_bottom = 5.0
color = Color( 0, 0, 0, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="RightFoot" type="ColorRect" parent="Player"]
margin_left = 5.0
margin_top = -14.0
margin_right = 9.0
margin_bottom = 5.0
color = Color( 0, 0, 0, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"]
position = Vector2( -1, -9 )
shape = SubResource( 1 )
[node name="Sally" type="KinematicBody2D" parent="."]
position = Vector2( 755, 595 )
[node name="DialogueStarter" type="Area2D" parent="Sally"]
collision_layer = 0
monitorable = false
[node name="CollisionShape2D" type="CollisionShape2D" parent="Sally/DialogueStarter"]
shape = SubResource( 2 )
[node name="Visuals" type="Node2D" parent="Sally"]
position = Vector2( 1, 3 )
scale = Vector2( -1, 1 )
[node name="ColorRect" type="ColorRect" parent="Sally/Visuals"]
margin_left = -21.0
margin_top = -52.0
margin_right = 19.0
margin_bottom = -12.0
color = Color( 0.729412, 0.160784, 0.160784, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect2" type="ColorRect" parent="Sally/Visuals"]
margin_left = -8.0
margin_top = -47.0
margin_bottom = -28.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect4" type="ColorRect" parent="Sally/Visuals"]
margin_top = -23.0
margin_right = 8.0
margin_bottom = -19.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect3" type="ColorRect" parent="Sally/Visuals"]
margin_left = 7.0
margin_top = -47.0
margin_right = 15.0
margin_bottom = -28.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LeftFoot" type="ColorRect" parent="Sally"]
margin_left = -12.0
margin_top = -14.0
margin_right = -8.0
margin_bottom = 5.0
color = Color( 0.729412, 0.160784, 0.160784, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="RightFoot" type="ColorRect" parent="Sally"]
margin_left = 5.0
margin_top = -14.0
margin_right = 9.0
margin_bottom = 5.0
color = Color( 0.729412, 0.160784, 0.160784, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Ship" type="KinematicBody2D" parent="."]
position = Vector2( 43, 595 )
[node name="DialogueStarter" type="Area2D" parent="Ship"]
collision_layer = 0
monitorable = false
[node name="CollisionShape2D" type="CollisionShape2D" parent="Ship/DialogueStarter"]
shape = SubResource( 2 )
[node name="Visuals" type="Node2D" parent="Ship"]
position = Vector2( 1, 3 )
[node name="ColorRect" type="ColorRect" parent="Ship/Visuals"]
margin_left = -21.0
margin_top = -52.0
margin_right = 19.0
margin_bottom = -12.0
color = Color( 0.329412, 0.231373, 1, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect2" type="ColorRect" parent="Ship/Visuals"]
margin_left = -8.0
margin_top = -47.0
margin_bottom = -28.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect4" type="ColorRect" parent="Ship/Visuals"]
margin_top = -23.0
margin_right = 8.0
margin_bottom = -19.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect3" type="ColorRect" parent="Ship/Visuals"]
margin_left = 7.0
margin_top = -47.0
margin_right = 15.0
margin_bottom = -28.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LeftFoot" type="ColorRect" parent="Ship"]
margin_left = -12.0
margin_top = -14.0
margin_right = -8.0
margin_bottom = 5.0
color = Color( 0.329412, 0.231373, 1, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="RightFoot" type="ColorRect" parent="Ship"]
margin_left = 5.0
margin_top = -14.0
margin_right = 9.0
margin_bottom = 5.0
color = Color( 0.329412, 0.231373, 1, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="StaticBody2D" type="StaticBody2D" parent="."]
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="StaticBody2D"]
polygon = PoolVector2Array( -3, 427, -40, 426, -40, 648, 838, 647, 838, 419, 787, 420, 788, 600, 2, 600, 0, 420 )

32
ExampleDialogue/Player.gd Normal file
View file

@ -0,0 +1,32 @@
extends KinematicBody2D
var velocity = Vector2.ZERO
var time = .0
func _physics_process(_delta):
var gravity = Vector2.DOWN * 9.81
velocity += gravity
move_and_slide(velocity, Vector2.UP)
func _process(delta):
var direction = Input.get_vector('ui_left', 'ui_right', 'ui_select', 'ui_select')
# Jump
if Input.is_action_just_released('ui_select') and is_on_floor():
velocity += Vector2.UP * 9.81 * 50
velocity.x = direction.x * 200
if direction.x != 0:
time += delta
$LeftFoot.visible = fmod(time * 4, 2) > 1
$RightFoot.visible = not $LeftFoot.visible
else:
$LeftFoot.visible = true
$RightFoot.visible = true
$Visuals.scale.x = -1 if velocity.x < 0 else 1

View file

@ -1,66 +0,0 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://addons/Wol/Wol.gd" type="Script" id=1]
[ext_resource path="res://Dialogue.tscn" type="PackedScene" id=2]
[sub_resource type="RectangleShape2D" id=1]
[node name="ExampleScene" type="Node2D"]
[node name="Dialogue" parent="." instance=ExtResource( 2 )]
anchor_right = 0.0
anchor_bottom = 0.0
margin_right = 1024.0
margin_bottom = 600.0
[node name="Wol" type="Node" parent="Dialogue"]
script = ExtResource( 1 )
variable_storage = {
}
[node name="Player" type="KinematicBody2D" parent="."]
position = Vector2( 360, 488 )
[node name="ColorRect" type="ColorRect" parent="Player"]
margin_left = -21.0
margin_top = -52.0
margin_right = 19.0
margin_bottom = -12.0
color = Color( 0, 0, 0, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect2" type="ColorRect" parent="Player"]
margin_left = -8.0
margin_top = -47.0
margin_bottom = -28.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect4" type="ColorRect" parent="Player"]
margin_top = -23.0
margin_right = 8.0
margin_bottom = -19.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ColorRect3" type="ColorRect" parent="Player"]
margin_left = 7.0
margin_top = -47.0
margin_right = 15.0
margin_bottom = -28.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="CollisionShape2D" type="CollisionShape2D" parent="Player"]
position = Vector2( -1, -9 )
shape = SubResource( 1 )
[node name="StaticBody2D" type="StaticBody2D" parent="."]
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="StaticBody2D"]
polygon = PoolVector2Array( -3, 427, -40, 426, -40, 648, 838, 647, 838, 419, 787, 420, 788, 600, 2, 600, 0, 420 )

View file

@ -37,13 +37,11 @@ Unfortunately, this option isn't available yet. Stay tuned!
There are few things that need to be ironed out to be 100% feature compatible with the original YarnSpinner. There are few things that need to be ironed out to be 100% feature compatible with the original YarnSpinner.
- [ ] Integration with Godot's translation/localization system. - [ ] Integration with Godot's translation/localization system.
- [ ] Full support for [format functions](https://yarnspinner.dev/docs/syntax/#format-functions). - [ ] Auto generation for `#line:` suffixes
- [ ] Support for [format functions](https://yarnspinner.dev/docs/syntax/#format-functions).
- [ ] Support for conditional options.
- [ ] In-editor dialogue editor with preview. - [ ] In-editor dialogue editor with preview.
- [ ] Fully extend the documentation of this project. - [x] Fully extend the documentation of this project.
- [ ] Replicate the files needed for the Yarn Spinner tutorial.
- [x] Document the [Option](README.md#Option) object.
- [x] Write the method descriptions for the `Wol` node.
- [x] Provide helpful anchors in the documentation.
- [x] Porting to usable signals in Godot. - [x] Porting to usable signals in Godot.
- [x] Providing helpful errors when failing to compile. - [x] Providing helpful errors when failing to compile.
- [x] Having a working repository with example code. - [x] Having a working repository with example code.
@ -280,10 +278,10 @@ It has a reference to a [Line](README.md#Line) with it's `line` property so you
# Tutorial # Tutorial
Welcome to Yarn Spinner! In this tutorial, youll learn how to use Wol in a Godot project to create interactive dialogue. Welcome to Wol! In this tutorial, youll learn how to use Wol in a Godot project to create interactive dialogue.
Well start by downloading and installing Yarn Spinner. Well then take a look at the core concepts that power Yarn Spinner, and write some dialogue. Well start by downloading and installing Wol. Well then take a look at the core concepts that power Wol / Yarn, and write some dialogue.
After that, well explore some of the more advanced features of Yarn Spinner. After that, well explore some of the more advanced features of Wol & Yarn.
## Introducing Yarn Spinner ## Introducing Yarn Spinner
@ -311,8 +309,8 @@ Well begin by playing the example game that comes with Wol. Its very short
1. Create a new empty Godot project. 1. Create a new empty Godot project.
2. Download and install Wol. Go to the [Getting started section](#README.md#Getting-Started), and follow the directions there. 2. Download and install Wol. Go to the [Getting started section](#README.md#Getting-Started), and follow the directions there.
3. Open the example scene. 3. Open the example scene (`res://ExampleDialogue/ExampleScene.tscn`).
4. Play the game. Use the left and right arrow keys to move, and the space bar to talk to characters. 4. Play the game. Use the left and right arrow keys to move, and the enter key to talk to characters.
Were now ready to start looking under the hood, to see how Wol & Yarn power this game. Were now ready to start looking under the hood, to see how Wol & Yarn power this game.
@ -320,7 +318,7 @@ Were now ready to start looking under the hood, to see how Wol & Yarn power t
Wol & Yarn Spinner stores its dialogue in .yarn (or .wol) files. These are plain text files, which means you can edit them in any plain text editor (Visual Studio Code is a good option, and Secret Labs offers a syntax highlighting extension to make it nice to use!) Wol & Yarn Spinner stores its dialogue in .yarn (or .wol) files. These are plain text files, which means you can edit them in any plain text editor (Visual Studio Code is a good option, and Secret Labs offers a syntax highlighting extension to make it nice to use!)
You can also use the Wol Editor, which is a tool in the Godot editor for working with Yarn code. This editor is useful because it lets you view the structure of your dialogue in a very visual way. You can also use the Wol Editor, which is a tool in the Godot editor for working with Yarn code. This editor is useful because it lets you view the structure of your dialogue in a very visual way. (This is not completed yet however)
### Reading Yarn ### Reading Yarn
@ -328,7 +326,7 @@ In this section of the tutorial, were going to open the file Sally.yarn, and
#### Open Sally.yarn in your editor of choice. #### Open Sally.yarn in your editor of choice.
Yarn Spinner groups all of its dialogue into nodes. Nodes contain everything: your lines of dialogue, the choices you show to the player, and the commands that you send to the game. The Sally.yarn file contains four of them: Sally, Sally.Watch, Sally.Exit, and Sally.Sorry. The example game is set up so that when you walk up to Sally and press the spacebar, the game will start running the Sally node. Wol & Yarn groups all of its dialogue into nodes. Nodes contain everything: your lines of dialogue, the choices you show to the player, and the commands that you send to the game. The Sally.yarn file contains four of them: Sally, Sally.Watch, Sally.Exit, and Sally.Sorry. The example game is set up so that when you walk up to Sally and press the spacebar, the game will start running the Sally node.
#### Go to the Sally node. #### Go to the Sally node.
@ -373,14 +371,16 @@ Well now take a closer look at each part of this code, and explain whats g
<<endif>> <<endif>>
``` ```
The first line of code in this node checks to see if Yarn Spinner has already run this node. visited is a function that this example game has defined - it isnt built into Yarn Spinner. It returns true if the node you specify has been run before. Youll notice that this line is wrapped in << and >> symbols. This tells Yarn Spinner that its control code, and not meant to be shown to the player. The first line of code in this node checks to see if Wol has already run this node. `visited` is a function that
is built into Wol. It returns true if the node you specify has been run before.
Youll notice that this line is wrapped in `<<` and `>>` symbols. This tells Wol that its control code, and not meant to be shown to the player.
If they havent run the Sally node yet, it means that this is the first time that weve spoken to Sally in this game. As a result, we run lines in which Sally and the player character meet. Otherwise, we instead run some shorter lines. If they havent run the `Sally` node yet, it means that this is the first time that weve spoken to `Sally` in this game. As a result, we run lines in which Sally and the player character meet. Otherwise, we instead run some shorter lines.
Each line in Wol is just a run of text, which is sent directly to the game. Its up to the game to decide how it wants to display it; in the example game, its shown at the top of the screen.
Each line in Yarn Spinner is just a run of text, which is sent directly to the game. Its up to the game to decide how it wants to display it; in the example game, its shown at the top of the screen. At the end of each line, youll see a `#line:` tag. This tag lets Wol identify lines across multiple translations, and is optional if you arent translating your game into other languages. Wol can automatically generate them for you (not supported yet however).
At the end of each line, youll see a #line: tag. This tag lets Yarn Spinner identify lines across multiple translations, and is optional if you arent translating your game into other languages. Yarn Spinner can automatically generate them for you. #### Options
Options
Heres the next part of the code. Heres the next part of the code.
@ -396,11 +396,11 @@ Heres the next part of the code.
In the next part of the code, we do a check, and if it passes, we add an option. Options are things that the player can select; in this game, theyre things the player can say, but like lines, its up to the game to decide what to do with them. Options are shown to the player when the end of a node is reached. In the next part of the code, we do a check, and if it passes, we add an option. Options are things that the player can select; in this game, theyre things the player can say, but like lines, its up to the game to decide what to do with them. Options are shown to the player when the end of a node is reached.
The first couple of lines here test to see whether the player has run the node Sally.Watch. If they havent, then the code adds a new option. Options are wrapped with [[ and ]]. The text before the | is shown to the player, and the text after is the name of the node that will be run if the player chooses the option. Like lines, options can have line tags for localisation. The first couple of lines here test to see whether the player has run the node `Sally.Watch`. If they havent, then the code adds a new option. Options are wrapped with `[[` and `]]`. The text before the `|` is shown to the player, and the text after is the name of the node that will be run if the player chooses the option. Like lines, options can have line tags for localisation.
If the player has run the Sally.Watch node before, this code wont be run, which means that the option to run it again wont appear. If the player has run the `Sally.Watch` node before, this code wont be run, which means that the option to run it again wont appear.
The rest of this part does a similar thing as the first: it does a check, and adds another option if the check passes. In this case, it checks to see if the variable $sally_warning is true, and if the player has not yet run the Sally.Sorry node. $sally_warning is set in a different node - its in the node Ship, which is stored in the file Ship.yarn. The rest of this part does a similar thing as the first: it does a check, and adds another option if the check passes. In this case, it checks to see if the variable `$sally_warning` is `true`, and if the player has not yet run the `Sally.Sorry` node. `$sally_warning` is set in a different node - its in the node Ship, which is stored in the file `Ship.yarn`.
```yarn ```yarn
[[See you later.|Sally.Exit]] #line:0facf7 [[See you later.|Sally.Exit]] #line:0facf7
@ -408,23 +408,25 @@ The rest of this part does a similar thing as the first: it does a check, and ad
The very last line of the node adds an option, which takes the player to the Sally.Exit line. Because this option isnt inside an if statement, its always added. The very last line of the node adds an option, which takes the player to the Sally.Exit line. Because this option isnt inside an if statement, its always added.
When Yarn Spinner hits the end of the node, all of the options that have been accumulated so far will be shown to the player. Yarn Spinner will then wait for the player to make a selection, and then start running the node that they selected. When Wol hits the end of the node, all of the options that have been accumulated so far will be shown to the player. Wol will then wait for the player to make a selection, and then start running the node that they selected.
And thats how the node works! And thats how the node works!
Writing Some Dialogue
### Writing Some Dialogue
Lets write some dialogue! Well add a couple of lines to the Ship. Lets write some dialogue! Well add a couple of lines to the Ship.
Open the file Ship.yarn. It contains a single node, called Ship - go to it. > Open the file Ship.yarn. It contains a single node, called Ship - go to it.
This code uses couple of features that we didnt see in Sally: commands, and variables. This code uses couple of features that we didnt see in Sally: commands, and variables.
Commands
Commands are messages that Yarn Spinner sends to your game, but arent intended to be shown to the player. Commands let you control things in your scene, like moving the camera around, or instructing a character to move to another point. #### Commands
Because every game is different, Yarn Spinner leaves the task of defining most commands to you. Yarn Spinner defines two built-in commands: wait, which pauses the dialogue for a certain number of seconds, and stop, which ends the dialogue immediately. Commands are messages that Wol sends to your game, but arent intended to be shown to the player. Commands let you control things in your scene, like moving the camera around, or instructing a character to move to another point.
The example game defines its own command, setsprite, which is used to change the sprite that the Ship characters face is displaying. You can see this in action in the file Ship.yarn: Because every game is different, Wol leaves the task of defining most commands to you. Wol defines two built-in commands: wait, which pauses the dialogue for a certain number of seconds, and stop, which ends the dialogue immediately.
The example game defines its own command, `setsprite`, which is used to change the sprite that the Ship characters face is displaying. You can see this in action in the file `Ship.yarn`:
```yarn ```yarn
Player: How's space? Player: How's space?
@ -434,12 +436,14 @@ Ship: It's HUGE!
<<setsprite ShipFace neutral>> <<setsprite ShipFace neutral>>
``` ```
You can learn how to define your own custom commands in Working With Commands. <!-- TODO: make tutorial about setting up commands
Variables You can learn how to define your own custom commands in Working With Commands. -->
Variables are how you store information about what the player has done in the game. We saw variables in use in the Sally node, where the variable $sally_warning was used to control whether some content was shown or not. This variable is set in here, in the Ship node - it represents whether or not the player has heard Sallys warning about the console from the Ship. #### Variables
Variables in Yarn Spinner start with a $, and can store text, numbers, booleans (true or false values), or null. If you try and access a variable that hasnt been set, youll get the value null, which represents “no value”. Variables are how you store information about what the player has done in the game. We saw variables in use in the `Sally` node, where the variable `$sally_warning` was used to control whether some content was shown or not. This variable is set in here, in the `Ship` node - it represents whether or not the player has heard Sallys warning about the console from the Ship.
Variables in Wol start with a `$`, and can store text, numbers, booleans (`true` or `false` values), or `null`. If you try and access a variable that hasnt been set, youll get the value `null`, which represents “no value”.
Adding Some Content Adding Some Content
#### Add some new dialogue. Add the following text to the end of the node: #### Add some new dialogue. Add the following text to the end of the node:
@ -457,7 +461,7 @@ Ship: Bye!
#### Shortcut Options #### Shortcut Options
The `->` items that we just added are called shortcut options. Shortcut options let you put choices in your node without having to create new nodes, which you link to through the [[Option]] syntax. They exist in-line with the rest of your node. The `->` items that we just added are called shortcut options. Shortcut options let you put choices in your node without having to create new nodes, which you link to through the `[[Option]]` syntax. They exist in-line with the rest of your node.
To use a shortcut option, you write a `->`, followed by the text that you want to display. Then, on the next lines, indent the code a few spaces (it doesnt matter how many, as long as youre consistent.) The indented lines will run if the option theyre attached to is selected. Shortcut options can be nested, which means you can put a group of shortcut options inside another. You can put any kind of code inside a shortcut options lines. To use a shortcut option, you write a `->`, followed by the text that you want to display. Then, on the next lines, indent the code a few spaces (it doesnt matter how many, as long as youre consistent.) The indented lines will run if the option theyre attached to is selected. Shortcut options can be nested, which means you can put a group of shortcut options inside another. You can put any kind of code inside a shortcut options lines.
@ -469,4 +473,4 @@ Save the file, and go back to the game. Play the game again, and talk to the Shi
The example game is set up so that when you talk to Sally, the node Sally is run, and when you talk to the Ship, the node Ship is run. With this in mind, change the story so that after you get told off by Sally, she asks you to go and fix a problem with the Ship. The example game is set up so that when you talk to Sally, the node Sally is run, and when you talk to the Ship, the node Ship is run. With this in mind, change the story so that after you get told off by Sally, she asks you to go and fix a problem with the Ship.
You can also read the Syntax Reference for Yarn Spinner. You can also read the [Syntax Reference](https://yarnspinner.dev/docs/syntax/) for Yarn.

View file

@ -24,6 +24,8 @@ export var auto_substitute = true
export(Dictionary) var variable_storage = {} export(Dictionary) var variable_storage = {}
var running = false
const Constants = preload('res://addons/Wol/core/Constants.gd') const Constants = preload('res://addons/Wol/core/Constants.gd')
const Compiler = preload('res://addons/Wol/core/compiler/Compiler.gd') const Compiler = preload('res://addons/Wol/core/compiler/Compiler.gd')
const Library = preload('res://addons/Wol/core/Library.gd') const Library = preload('res://addons/Wol/core/Library.gd')
@ -49,7 +51,7 @@ func _ready():
func set_path(_path): func set_path(_path):
path = _path path = _path
if not Engine.editor_hint and virtual_machine: if not Engine.editor_hint and virtual_machine and not path.empty():
var compiler = Compiler.new(path) var compiler = Compiler.new(path)
virtual_machine.program = compiler.compile() virtual_machine.program = compiler.compile()
@ -80,6 +82,7 @@ func _on_options(options):
return Constants.HandlerState.PauseExecution return Constants.HandlerState.PauseExecution
func _on_dialogue_finished(): func _on_dialogue_finished():
running = false
emit_signal('finished') emit_signal('finished')
func _on_node_start(node): func _on_node_start(node):
@ -98,6 +101,7 @@ func pause():
func start(node = starting_node): func start(node = starting_node):
emit_signal('started') emit_signal('started')
running = true
virtual_machine.set_node(node) virtual_machine.set_node(node)
virtual_machine.start() virtual_machine.start()

View file

@ -69,8 +69,8 @@ func set_node(name):
if not dialogue.variable_storage[program.filename].has(name): if not dialogue.variable_storage[program.filename].has(name):
dialogue.variable_storage[program.filename][name] = 0 dialogue.variable_storage[program.filename][name] = 0
else:
dialogue.variable_storage[program.filename][name] += 1 dialogue.variable_storage[program.filename][name] += 1
return true return true
func pause(): func pause():
@ -229,8 +229,11 @@ func run_instruction(instruction):
Constants.ByteCode.PushVariable: Constants.ByteCode.PushVariable:
var name = instruction.operands[0].value var name = instruction.operands[0].value
var value = dialogue.variable_storage[name.replace('$', '')] if dialogue.variable_storage.has(name.replace('$', '')):
state.push_value(value) var value = dialogue.variable_storage[name.replace('$', '')]
state.push_value(value)
else:
state.push_value(null)
Constants.ByteCode.StoreVariable: Constants.ByteCode.StoreVariable:
var value = state.peek_value() var value = state.peek_value()

View file

@ -45,7 +45,7 @@ func createstates():
patterns[Constants.TokenType.Text] = ['.*', 'any text'] patterns[Constants.TokenType.Text] = ['.*', 'any text']
patterns[Constants.TokenType.Number] = ['\\-?[0-9]+(\\.[0-9+])?', 'any number'] patterns[Constants.TokenType.Number] = ['\\-?[0-9]+(\\.[0-9+])?', 'any number']
patterns[Constants.TokenType.Str] = ['\'([^\'\\\\]*(?:\\.[^\'\\\\]*)*)\'', 'any text'] patterns[Constants.TokenType.Str] = ['\"([^\"\\\\]*(?:\\.[^\"\\\\]*)*)\"', 'any text']
patterns[Constants.TokenType.TagMarker] = ['\\#', 'a tag #'] patterns[Constants.TokenType.TagMarker] = ['\\#', 'a tag #']
patterns[Constants.TokenType.LeftParen] = ['\\(', 'left parenthesis ('] patterns[Constants.TokenType.LeftParen] = ['\\(', 'left parenthesis (']
patterns[Constants.TokenType.RightParen] = ['\\)', 'right parenthesis )'] patterns[Constants.TokenType.RightParen] = ['\\)', 'right parenthesis )']

View file

@ -37,11 +37,10 @@ func next_symbols_are(valid_types):
func expect_symbol(token_types = []): func expect_symbol(token_types = []):
var token = tokens.pop_front() as Lexer.Token var token = tokens.pop_front() as Lexer.Token
if token_types.size() == 0: if token_types.size() == 0:
if token.type == Constants.TokenType.EndOfInput: if token.type == Constants.TokenType.EndOfInput:
assert(false, 'Unexpected end of input') assert(false, 'Unexpected end of input')
return null
return token return token
for type in token_types: for type in token_types:
@ -153,7 +152,7 @@ class FormatFunctionNode extends ParseNode:
format_text="[" format_text="["
parser.expect_symbol([Constants.TokenType.FormatFunctionStart]) parser.expect_symbol([Constants.TokenType.FormatFunctionStart])
while !parser.next_symbol_is([Constants.TokenType.FormatFunctionEnd]): while not parser.next_symbol_is([Constants.TokenType.FormatFunctionEnd]):
if parser.next_symbol_is([Constants.TokenType.Text]): if parser.next_symbol_is([Constants.TokenType.Text]):
format_text += parser.expect_symbol().value format_text += parser.expect_symbol().value
@ -849,7 +848,7 @@ class ExpressionNode extends ParseNode:
#we should have a single root expression left #we should have a single root expression left
#if more then we failed ---- NANI #if more then we failed ---- NANI
if eval_stack.size() != 1: if eval_stack.size() != 1:
printerr('[%s] Error parsing expression (stack did not reduce correctly )' % first.name) printerr('[%s] Error parsing expression (stack did not reduce correctly )' % first)
return eval_stack.pop_back() return eval_stack.pop_back()