Fix various DialogueTree ("Yarn") bugs (#1671)

* Fix command at the start of a node merges its text with the node that linked to it
* Fix Yarn skipping text results when commands are used in some cases
* Fix setting/getting variables
* Fix text failing to load when first node is of type text
* Add internal debug mode logging to Yarn
* Fix isdialoguelinetype command never true
* Fix new lines in text not properly detected
* Increase strictness on scrolling so it never overflows
* Fix command call detection for non scrolling text
* Fix: add back autoscroll commands, but make it safer and move it to the scroll function
* Use explicit variable types when setting bondagejs state
* Fix command not getting called sometimes 
* Fix text not terminating sometimes
This commit is contained in:
Todor Imreorov
2020-05-08 11:14:14 +01:00
committed by GitHub
parent dd771ea3d1
commit 394eb9488c
13 changed files with 1096 additions and 263 deletions

View File

@@ -45,7 +45,7 @@ module.exports = {
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/DialogueTree/dialoguetools.js')
.addIncludeFile('Extensions/DialogueTree/bondage.min.js')
.addIncludeFile('Extensions/DialogueTree/bondage.js/dist/bondage.min.js')
.setFunctionName('gdjs.dialogueTree.loadFromSceneVariable');
extension
@@ -69,7 +69,7 @@ module.exports = {
)
.getCodeExtraInformation()
.setIncludeFile('Extensions/DialogueTree/dialoguetools.js')
.addIncludeFile('Extensions/DialogueTree/bondage.min.js')
.addIncludeFile('Extensions/DialogueTree/bondage.js/dist/bondage.min.js')
.setFunctionName('gdjs.dialogueTree.loadFromJsonFile');
extension
@@ -209,21 +209,55 @@ module.exports = {
extension
.addAction(
'SetVariable',
_('Set dialogue state variable'),
'SetStringVariable',
_('Set dialogue state string variable'),
_(
'Set dialogue state variable. Use this to set a variable that the dialogue data is using.'
'Set dialogue state string variable. Use this to set a variable that the dialogue data is using.'
),
_('Set dialogue state variable _PARAM0_ to _PARAM1_'),
_('Set dialogue state string variable _PARAM0_ to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('State Variable Name'), '', false)
.addParameter('expression', _('Variable Value'), '', false)
.addParameter('string', _('Variable string value'), '', false)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.setVariable');
extension
.addAction(
'SetNumberVariable',
_('Set dialogue state number variable'),
_(
'Set dialogue state number variable. Use this to set a variable that the dialogue data is using.'
),
_('Set dialogue state number variable _PARAM0_ to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('State Variable Name'), '', false)
.addParameter('expression', _('Variable number value'), '', true)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.setVariable');
extension
.addAction(
'SetBooleanVariable',
_('Set dialogue state boolean variable'),
_(
'Set dialogue state boolean variable. Use this to set a variable that the dialogue data is using.'
),
_('Set dialogue state boolean variable _PARAM0_ to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('State Variable Name'), '', false)
.addParameter('trueorfalse', _('Variable boolean value'), '', false)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.setVariable');
extension
.addAction(
'SaveState',
@@ -591,9 +625,9 @@ module.exports = {
extension
.addCondition(
'WasBranchVisited',
_('Branch title has been visited before'),
_('Check if the current branch has been visited before'),
_('Branch title _PARAM0_ has been visited before'),
_('Branch title has been visited'),
_('Check if a branch has been visited'),
_('Branch title _PARAM0_ has been visited'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
@@ -604,12 +638,12 @@ module.exports = {
extension
.addCondition(
'CompareDialogueStateVariable',
_('Compare dialogue state variable'),
'CompareDialogueStateStringVariable',
_('Compare dialogue state string variable'),
_(
'Compare dialogue state variable. Use this to trigger game events via dialogue variables.'
'Compare dialogue state string variable. Use this to trigger game events via dialogue variables.'
),
_('Dialogue state variable _PARAM0_ is equal to _PARAM1_'),
_('Dialogue state string variable _PARAM0_ is equal to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
@@ -619,6 +653,40 @@ module.exports = {
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.compareVariable');
extension
.addCondition(
'CompareDialogueStateNumberVariable',
_('Compare dialogue state number variable'),
_(
'Compare dialogue state number variable. Use this to trigger game events via dialogue variables.'
),
_('Dialogue state number variable _PARAM0_ is equal to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('State variable'), '', false)
.addParameter('expression', _('Equal to'), '', false)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.compareVariable');
extension
.addCondition(
'CompareDialogueStateBooleanVariable',
_('Compare dialogue state boolean variable'),
_(
'Compare dialogue state variable. Use this to trigger game events via dialogue variables.'
),
_('Dialogue state boolean variable _PARAM0_ is equal to _PARAM1_'),
_('Dialogue Tree (experimental)'),
'JsPlatform/Extensions/yarn24.png',
'JsPlatform/Extensions/yarn32.png'
)
.addParameter('string', _('State variable'), '', false)
.addParameter('trueorfalse', _('Equal to'), '', false)
.getCodeExtraInformation()
.setFunctionName('gdjs.dialogueTree.compareVariable');
extension
.addCondition(
'HasClippedTextScrollingCompleted',

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2017 j hayley
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,66 @@
# bondage.js [![Build Status](https://travis-ci.org/jhayley/bondage.js.svg?branch=master)](https://travis-ci.org/jhayley/bondage.js)
[Yarn](https://github.com/InfiniteAmmoInc/Yarn) parser for Javascript, in the same vein as [YarnSpinner](https://github.com/thesecretlab/YarnSpinner).
# Usage
#### As a Web Tool
To run through your yarn files in your browser, go to http://hayley.zone/bondage.js, paste your yarn data in the field, then hit "compile".
#### As a Command Line Tool
Installation: `npm install -g bondage`
Now you can use the `bondage` command to run through Yarn files from the command line. You can load one or multiple files at a time. If you load multiple files and a two nodes are encountered with the same name, the node will be overwritten.
**Examples**
* Running a single file from the default start node (named "Start"): `bondage run yarnfile.json`
* Running a single file from the specified node name: `bondage run -s StartNode yarnfile.json`
* Running multiple files from the specified node name: `bondage run -s StartNode yarnfile1.json yarnfile2.json ...`
* See the compiled ast: `bondage compile --ast yarnfile.json`
* See the tokenized input: `bondage compile --tokens yarnfile.json`
#### As a Library
**Web**
Include [dist/bondage.min.js](https://github.com/jhayley/bondage.js/blob/master/dist/bondage.min.js) somewhere in your html, and the `bondage` variable will be added to the global scope. You can then access everything in the example below (such as `bondage.Runner`) through that variable.
**Node**
Installation: `npm install bondage`
```javascript
const fs = require('fs');
const bondage = require('bondage');
const runner = new bondage.Runner();
const yarnData = JSON.parse(fs.readFileSync('yarnFile.json'));
runner.load(yarnData);
// Loop over the dialogue from the node titled 'Start'
for (const result of runner.run('Start')) {
// Do something else with the result
if (result instanceof bondage.TextResult) {
console.log(result.text);
} else if (result instanceof bondage.OptionsResult) {
// This works for both links between nodes and shortcut options
console.log(result.options);
// Select based on the option's index in the array (if you don't select an option, the dialog will continue past them)
result.select(1);
} else if (result instanceof bondage.CommandResult) {
// If the text was inside <<here>>, it will get returned as a CommandResult string, which you can use in any way you want
console.log(result.text);
}
}
// Advance the dialogue manually from the node titled 'Start'
const d = runner.run('Start')
let result = d.next().value;
let nextResult = d.next().value;
// And so on
```
For usage of the yarn format itself, please see the [YarnSpinner Documentation](https://github.com/thesecretlab/YarnSpinner/tree/master/Documentation), everything there should carry here too (if something does not match up, please open an issue).

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,5 @@
This extension is using bondage.js library to parse yarn syntax.
https://github.com/hylyh/bondage.js
The current build used is built from commit 3c63e21

View File

@@ -101,7 +101,20 @@ gdjs.dialogueTree.isRunning = function() {
gdjs.dialogueTree.scrollClippedText = function() {
if (this.pauseScrolling || !this.dialogueIsRunning) return;
if (this.dialogueText) {
// Autoscroll commands so the user doesnt have to press again
if (
gdjs.dialogueTree._isLineTypeCommand() &&
this.dialogueDataType === 'text' &&
this.dialogueBranchTitle === this.dialogueData.data.title &&
this.lineNum === this.dialogueData.lineNum &&
gdjs.dialogueTree.hasClippedScrollingCompleted()
) {
gdjs.dialogueTree.goToNextDialogueLine();
return
}
// Increment scrolling of clipped text
if (this.dialogueText && this.dialogueDataType === 'text' && this.clipTextEnd < this.dialogueText.length) {
this.clipTextEnd += 1;
}
};
@@ -110,7 +123,7 @@ gdjs.dialogueTree.scrollClippedText = function() {
* Scroll the clipped text to its end, so the entire text is printed. This can be useful in keeping the event sheet logic simpler, while supporting more variation.
*/
gdjs.dialogueTree.completeClippedTextScrolling = function() {
if (this.pauseScrolling || !this.dialogueIsRunning || !this.dialogueText)
if (this.pauseScrolling || !this.dialogueIsRunning || !this.dialogueText || this.dialogueDataType !== 'text')
return;
this.clipTextEnd = this.dialogueText.length;
};
@@ -120,9 +133,11 @@ gdjs.dialogueTree.completeClippedTextScrolling = function() {
* Useful to prevent the user from skipping to next line before the current one has been printed fully.
*/
gdjs.dialogueTree.hasClippedScrollingCompleted = function() {
if (!this.dialogueIsRunning) return false;
if (this.dialogueData && this.dialogueText.length) {
return this.clipTextEnd >= this.dialogueText.length;
if (!this.dialogueIsRunning || this.dialogueDataType === '') return false;
if (this.dialogueData && this.dialogueText.length > 0 && this.clipTextEnd >= this.dialogueText.length) {
if (gdjs.dialogueTree.getVariable('debug')) console.warn('Scroll completed:', this.clipTextEnd,'/', this.dialogueText.length);
return true;
}
return false;
};
@@ -142,7 +157,6 @@ gdjs.dialogueTree.getClippedLineText = function() {
* Note that using this instead getClippedLineText will skip any <<wait>> commands entirely.
*/
gdjs.dialogueTree.getLineText = function() {
this.completeClippedTextScrolling();
return this.dialogueIsRunning && this.dialogueText.length
? this.dialogueText
: '';
@@ -163,6 +177,7 @@ gdjs.dialogueTree.commandParametersCount = function() {
* @param {number} paramIndex The index of the parameter to get.
*/
gdjs.dialogueTree.getCommandParameter = function(paramIndex) {
if (paramIndex === -1 && this.commandParameters.length > 0) return this.commandParameters[0];
if (
this.commandParameters &&
this.commandParameters.length >= paramIndex + 1
@@ -188,17 +203,20 @@ gdjs.dialogueTree.isCommandCalled = function(command) {
if (this.pauseScrolling || !commandCalls) return false;
return this.commandCalls.some(function(call, index) {
if (clipTextEnd < call.time) return false;
if (call.cmd === 'wait' && clipTextEnd !== dialogueText.length) {
if (clipTextEnd !== 0 && clipTextEnd < call.time) return false;
if (call.cmd === 'wait' && (clipTextEnd === 0 || clipTextEnd !== dialogueText.length)) {
gdjs.dialogueTree.pauseScrolling = true;
setTimeout(function() {
gdjs.dialogueTree.pauseScrolling = false;
commandCalls.splice(index, 1);
if (gdjs.dialogueTree.getVariable('debug')) console.info('CMD:', call);
}, parseInt(call.params[1], 10));
}
if (call.cmd === command) {
gdjs.dialogueTree.commandParameters = call.params;
commandCalls.splice(index, 1);
if (gdjs.dialogueTree.getVariable('debug')) console.info('CMD:', call);
return true;
}
});
@@ -384,16 +402,21 @@ gdjs.dialogueTree.hasSelectedOptionChanged = function() {
* @param {string} type The type you want to check for ( one of the three above )
*/
gdjs.dialogueTree.isDialogueLineType = function(type) {
if (
this.commandCalls &&
this.commandCalls.some(function(call) {
return gdjs.dialogueTree.clipTextEnd > call.time && call.cmd === 'wait';
})
) {
return !this.pauseScrolling;
if (!this.dialogueIsRunning) return false;
if (this.commandCalls && type === 'command') {
if (
this.commandCalls.some(function(call) {
return gdjs.dialogueTree.clipTextEnd > call.time && call.cmd === 'wait';
})
) {
return !this.pauseScrolling;
}
if (this.commandCalls.length > 0 && this.commandParameters.length > 0) {
return true;
}
}
return this.dialogueIsRunning ? this.dialogueDataType === type : false;
return this.dialogueDataType === type;
};
/**
@@ -420,19 +443,27 @@ gdjs.dialogueTree.startFrom = function(startDialogueNode) {
if (!this.hasDialogueBranch(startDialogueNode)) return;
this.optionsCount = 0;
this.options = [];
this.dialogueBranchTitle = '';
this.dialogueBranchBody = '';
this.dialogueBranchTags = [];
this.tagParameters = [];
this.dialogue = this.runner.run(startDialogueNode);
this.dialogueData = null;
this.dialogueDataType = '';
this.dialogueText = '';
this.clipTextEnd = 0;
this.commandCalls = [];
this.commandParameters = [];
this.pauseScrolling = false;
this.dialogueData = this.dialogue.next().value;
this.dialogueBranchTags = this.dialogueData.data.tags;
this.dialogueBranchTitle = this.dialogueData.data.title;
this.dialogueBranchBody = this.dialogueData.data.body;
this.lineNum = this.dialogueData.lineNum;
if (gdjs.dialogueTree._isLineTypeText()){
this.dialogueDataType = 'text';
} else if (gdjs.dialogueTree._isLineTypeOptions()){
this.dialogueDataType = 'options';
} else {
this.dialogueDataType = 'command';
};
this.dialogueIsRunning = true;
gdjs.dialogueTree.goToNextDialogueLine();
};
@@ -462,26 +493,29 @@ gdjs.dialogueTree.goToNextDialogueLine = function() {
this.selectedOption = -1;
this.selectedOptionUpdated = false;
if (gdjs.dialogueTree._isLineTypeText()) {
if (
this.dialogueDataType === 'options' ||
this.dialogueDataType === 'text' ||
!this.dialogueDataType
) {
this.clipTextEnd = 0;
this.dialogueText = this.dialogueData.text;
this.commandCalls = [];
} else {
if (gdjs.dialogueTree.getVariable('debug')) console.info('parsing:', this.dialogueData);
if (!this.dialogueData) {
gdjs.dialogueTree.stopRunningDialogue();
} else if (gdjs.dialogueTree._isLineTypeText()) {
if (this.lineNum === this.dialogueData.lineNum && this.dialogueBranchTitle === this.dialogueData.data.title){
this.clipTextEnd = this.dialogueText.length - 1;
this.dialogueText +=
(this.dialogueText === '' ? '' : ' ') + this.dialogueData.text;
} else {
this.clipTextEnd = 0;
this.dialogueText = this.dialogueData.text;
}
this.dialogueDataType = 'text';
this.dialogueBranchTags = this.dialogueData.data.tags;
this.dialogueBranchTitle = this.dialogueData.data.title;
this.dialogueBranchBody = this.dialogueData.data.body;
this.lineNum = this.dialogueData.lineNum;
this.dialogueDataType = 'text';
this.dialogueData = this.dialogue.next().value;
} else if (gdjs.dialogueTree._isLineTypeOptions()) {
this.commandCalls = [];
this.dialogueDataType = 'options';
this.dialogueText = '';
this.clipTextEnd = 0;
@@ -490,8 +524,6 @@ gdjs.dialogueTree.goToNextDialogueLine = function() {
this.selectedOptionUpdated = true;
} else if (gdjs.dialogueTree._isLineTypeCommand()) {
this.dialogueDataType = 'command';
this.clipTextEnd = 0;
var command = this.dialogueData.text.split(' ');
// If last command was to wait, increase time by one
var offsetTime =
@@ -509,11 +541,6 @@ gdjs.dialogueTree.goToNextDialogueLine = function() {
} else {
this.dialogueDataType = 'unknown';
}
if (gdjs.dialogueTree._isLineTypeCommand()) {
this.dialogueDataType = 'command';
gdjs.dialogueTree.goToNextDialogueLine();
}
};
/**
@@ -631,7 +658,7 @@ gdjs.dialogueTree.getBranchText = function() {
*/
gdjs.dialogueTree.getVariable = function(key) {
if (this.dialogueIsRunning && key in this.runner.variables.data) {
return this.runner.variables.data[key];
return this.runner.variables.get(key);
}
return '';
};
@@ -639,11 +666,11 @@ gdjs.dialogueTree.getVariable = function(key) {
/**
* Check if a specific variable created by the Dialogue parses exists and is equal to a specific value.
* @param {string} key The name of the variable you want to check the value of
* @param {string} value The value you want to check against
* @param {string|boolean|number} value The value you want to check against
*/
gdjs.dialogueTree.compareVariable = function(key, value) {
if (this.dialogueIsRunning && key in this.runner.variables.data) {
return this.runner.variables.data[key].toString() === value;
return this.runner.variables.get(key) === value;
}
return false;
};
@@ -651,11 +678,11 @@ gdjs.dialogueTree.compareVariable = function(key, value) {
/**
* Set a specific variable created by the Dialogue parser to a specific value.
* @param {string} key The name of the variable you want to set the value of
* @param {string} value The value you want to set
* @param {string|boolean|number} value The value you want to set
*/
gdjs.dialogueTree.setVariable = function(key, value) {
if (this.dialogueIsRunning && this.runner.variables.data) {
this.runner.variables.data[key] = value;
if (this.runner.variables) {
this.runner.variables.set(key, value);
}
};
@@ -666,7 +693,7 @@ gdjs.dialogueTree.setVariable = function(key, value) {
* @param {gdjs.Variable} outputVariable The variable where to store the State
*/
gdjs.dialogueTree.saveState = function(outputVariable) {
const dialogueState = {
var dialogueState = {
variables: gdjs.dialogueTree.runner.variables.data,
visited: gdjs.dialogueTree.runner.visited,
};
@@ -677,17 +704,24 @@ gdjs.dialogueTree.saveState = function(outputVariable) {
* Load the current State of the Dialogue Parser from a specified variable.
* Can be used to implement persistence in dialogue through your game's Load/Save function.
* That way you can later load all the dialogue choices the player has made.
* @param {gdjs.Variable} inputVariable The variable where to load the State from.
* @param {gdjs.Variable} inputVariable The structured variable where to load the State from.
*/
gdjs.dialogueTree.loadState = function(inputVariable) {
const jsonData = gdjs.evtTools.network.variableStructureToJSON(inputVariable);
var loadedState = JSON.parse(
gdjs.evtTools.network.variableStructureToJSON(inputVariable)
);
if (!loadedState) {
console.error('Load state variable is empty:', inputVariable);
return
}
try {
const loadedState = JSON.parse(
gdjs.evtTools.network.variableStructureToJSON(inputVariable)
);
gdjs.dialogueTree.runner.visited = loadedState.visited;
gdjs.dialogueTree.runner.variables.data = loadedState.variables;
gdjs.dialogueTree.runner.variables.data = {};
Object.keys(loadedState.variables).forEach(function(key) {
var value = loadedState.variables[key];
gdjs.dialogueTree.runner.variables.set(key, value);
});
} catch (e) {
console.error(e);
console.error('Failed to load state from variable:', inputVariable, e);
}
};

View File

@@ -8,6 +8,7 @@
},
"properties": {
"adMobAppId": "",
"adaptGameResolutionAtRuntime": false,
"folderProject": false,
"linuxExecutableFilename": "",
"macExecutableFilename": "",
@@ -805,6 +806,15 @@
"smoothed": true,
"userAdded": false
},
{
"alwaysLoaded": false,
"file": "other/grasshopper-idle-4.png",
"kind": "image",
"metadata": "",
"name": "other/grasshopper-idle-4.png",
"smoothed": true,
"userAdded": true
},
{
"disablePreload": false,
"file": "dialogueData/npcs.json",
@@ -826,6 +836,10 @@
{
"name": "optionIndex",
"value": "0"
},
{
"name": "yarnState",
"value": ""
}
],
"layouts": [
@@ -934,6 +948,10 @@
{
"name": "Score",
"value": "0"
},
{
"name": "debugYarn",
"value": "true"
}
],
"instances": [
@@ -945,8 +963,8 @@
"locked": false,
"name": "Player",
"width": 0,
"x": 21,
"y": 221,
"x": 159,
"y": 519,
"zOrder": 1,
"numberProperties": [],
"stringProperties": [],
@@ -1035,8 +1053,8 @@
"locked": false,
"name": "PlayerHitBox",
"width": 45,
"x": 155,
"y": 390,
"x": 183,
"y": 523,
"zOrder": 1,
"numberProperties": [],
"stringProperties": [],
@@ -1976,6 +1994,51 @@
"numberProperties": [],
"stringProperties": [],
"initialVariables": []
},
{
"angle": 0,
"customSize": false,
"height": 0,
"layer": "GUI",
"locked": false,
"name": "commandsDebug",
"width": 0,
"x": 5,
"y": 10,
"zOrder": 48,
"numberProperties": [],
"stringProperties": [],
"initialVariables": []
},
{
"angle": 0,
"customSize": false,
"height": 0,
"layer": "GUI",
"locked": false,
"name": "fullTextDebug",
"width": 0,
"x": 353,
"y": 10,
"zOrder": 49,
"numberProperties": [],
"stringProperties": [],
"initialVariables": []
},
{
"angle": 0,
"customSize": false,
"height": 0,
"layer": "",
"locked": false,
"name": "enemy2",
"width": 0,
"x": -268,
"y": 390,
"zOrder": 50,
"numberProperties": [],
"stringProperties": [],
"initialVariables": []
}
],
"objects": [
@@ -3257,6 +3320,10 @@
{
"name": "GoingLeft",
"value": "0"
},
{
"name": "dialogueBranch",
"value": "cricket"
}
],
"behaviors": [],
@@ -5311,6 +5378,35 @@
]
}
]
},
{
"name": "cricket",
"useMultipleDirections": false,
"directions": [
{
"looping": false,
"timeBetweenFrames": 0.08,
"sprites": [
{
"hasCustomCollisionMask": false,
"image": "other/grasshopper-idle-4.png",
"points": [],
"originPoint": {
"name": "origine",
"x": 0,
"y": 0
},
"centerPoint": {
"automatic": true,
"name": "centre",
"x": 0,
"y": 0
},
"customCollisionMask": []
}
]
}
]
}
]
},
@@ -5374,6 +5470,42 @@
"align": "left",
"wordWrap": true
}
},
{
"bold": false,
"italic": false,
"name": "commandsDebug",
"smoothed": true,
"tags": "",
"type": "TextObject::Text",
"underlined": false,
"variables": [],
"behaviors": [],
"string": "",
"font": "",
"characterSize": 20,
"color": {
"b": 219,
"g": 0,
"r": 160
}
},
{
"name": "fullTextDebug",
"tags": "",
"type": "BBText::BBText",
"variables": [],
"behaviors": [],
"content": {
"text": "[b]bold[/b] [i]italic[/i] [size=15]smaller[/size] [font=times]times[/font] font\n[spacing=12]spaced out[/spacing]\n[outline=yellow]outlined[/outline] [shadow=red]DropShadow[/shadow] ",
"opacity": 255,
"fontSize": "20",
"visible": false,
"color": "#000000",
"fontFamily": "Arial",
"align": "left",
"wordWrap": true
}
}
],
"events": [
@@ -5409,137 +5541,13 @@
}
]
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Comment",
"color": {
"b": 109,
"g": 230,
"r": 255,
"textB": 0,
"textG": 0,
"textR": 0
},
"comment": "Trigger sign text on collision",
"comment2": ""
},
{
"disabled": false,
"folded": true,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
"type": {
"inverted": false,
"value": "VarObjetTxt"
},
"parameters": [
"NPC",
"state",
"=",
"\"sign\""
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "CollisionNP"
},
"parameters": [
"Player",
"NPC",
"",
"",
"yes"
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "PlatformBehavior::IsOnFloor"
},
"parameters": [
"PlayerHitBox",
"PlatformerObject"
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "BuiltinCommonInstructions::Once"
},
"parameters": [],
"subInstructions": []
}
],
"actions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::StartDialogueFromBranch"
},
"parameters": [
"NPC.VariableString(dialogueBranch)"
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "DialogueTree::CompleteClippedTextScrolling"
},
"parameters": [],
"subInstructions": []
}
],
"events": [
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [],
"actions": [
{
"type": {
"inverted": false,
"value": "ModVarObjetTxt"
},
"parameters": [
"NPC",
"state",
"=",
"\"talking\""
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "ChangeAnimation"
},
"parameters": [
"Player",
"=",
"0"
],
"subInstructions": []
}
],
"events": []
}
]
},
{
"colorB": 228,
"colorG": 176,
"colorR": 74,
"creationTime": 0,
"disabled": false,
"folded": false,
"folded": true,
"name": "Other gameplay mechanics",
"source": "",
"type": "BuiltinCommonInstructions::Group",
@@ -5584,20 +5592,6 @@
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "PlayMusic"
},
"parameters": [
"",
"other\\sounds\\the_valley.ogg",
"yes",
"100",
"1"
],
"subInstructions": []
},
{
"type": {
"inverted": false,
@@ -5731,7 +5725,7 @@
},
{
"disabled": false,
"folded": false,
"folded": true,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
@@ -6523,6 +6517,21 @@
"events": [
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Comment",
"color": {
"b": 109,
"g": 230,
"r": 255,
"textB": 0,
"textG": 0,
"textR": 0
},
"comment": "Enable this to stresstest the DialogueTree extension for regressions",
"comment2": ""
},
{
"disabled": true,
"folded": true,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
@@ -6537,6 +6546,73 @@
"subInstructions": []
}
],
"actions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::SetBooleanVariable"
},
"parameters": [
"\"debug\"",
"True"
],
"subInstructions": []
}
],
"events": [
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [],
"actions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::SetBooleanVariable"
},
"parameters": [
"\"debugLinks\"",
"True"
],
"subInstructions": []
}
],
"events": []
}
]
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Comment",
"color": {
"b": 109,
"g": 230,
"r": 255,
"textB": 0,
"textG": 0,
"textR": 0
},
"comment": "Innitiate your dialogue data by loading it from a yarn json file",
"comment2": ""
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
"type": {
"inverted": false,
"value": "DepartScene"
},
"parameters": [
""
],
"subInstructions": []
}
],
"actions": [
{
"type": {
@@ -6558,6 +6634,185 @@
"textHud"
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "ResetTimer"
},
"parameters": [
"",
"\"endedChat\""
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "Cache"
},
"parameters": [
"commandsDebug"
],
"subInstructions": []
}
],
"events": []
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::WasBranchVisited"
},
"parameters": [
"\"ant\""
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "BuiltinCommonInstructions::Once"
},
"parameters": [],
"subInstructions": []
}
],
"actions": [
{
"type": {
"inverted": false,
"value": "Montre"
},
"parameters": [
"crumb",
""
],
"subInstructions": []
}
],
"events": []
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
"type": {
"inverted": true,
"value": "DialogueTree::WasBranchVisited"
},
"parameters": [
"\"ant\""
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "BuiltinCommonInstructions::Once"
},
"parameters": [],
"subInstructions": []
}
],
"actions": [
{
"type": {
"inverted": false,
"value": "Cache"
},
"parameters": [
"crumb"
],
"subInstructions": []
}
],
"events": []
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Comment",
"color": {
"b": 109,
"g": 230,
"r": 255,
"textB": 0,
"textG": 0,
"textR": 0
},
"comment": "Trigger sign text on collision",
"comment2": ""
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
"type": {
"inverted": false,
"value": "VarObjetTxt"
},
"parameters": [
"NPC",
"state",
"=",
"\"sign\""
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "CollisionNP"
},
"parameters": [
"Player",
"NPC",
"",
"",
"yes"
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "PlatformBehavior::IsOnFloor"
},
"parameters": [
"PlayerHitBox",
"PlatformerObject"
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "BuiltinCommonInstructions::Once"
},
"parameters": [],
"subInstructions": []
}
],
"actions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::StartDialogueFromBranch"
},
"parameters": [
"NPC.VariableString(dialogueBranch)"
],
"subInstructions": []
}
],
"events": [
@@ -6570,13 +6825,99 @@
{
"type": {
"inverted": false,
"value": "ResetTimer"
"value": "ModVarObjetTxt"
},
"parameters": [
"",
"\"endedChat\""
"NPC",
"state",
"=",
"\"talking\""
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "ChangeAnimation"
},
"parameters": [
"Player",
"=",
"0"
],
"subInstructions": []
}
],
"events": []
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::CompareDialogueStateBooleanVariable"
},
"parameters": [
"\"debug\"",
"True"
],
"subInstructions": []
}
],
"actions": [
{
"type": {
"inverted": false,
"value": "TextObject::String"
},
"parameters": [
"commandsDebug",
"=",
"\"Yarn is in debug mode\""
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "Montre"
},
"parameters": [
"fullTextDebug",
""
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "Montre"
},
"parameters": [
"commandsDebug",
""
],
"subInstructions": []
}
],
"events": []
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [],
"actions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::CompleteClippedTextScrolling"
},
"parameters": [],
"subInstructions": []
}
],
"events": []
@@ -7091,6 +7432,39 @@
}
],
"events": []
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::CompareDialogueStateBooleanVariable"
},
"parameters": [
"\"debug\"",
"True"
],
"subInstructions": []
}
],
"actions": [
{
"type": {
"inverted": false,
"value": "BBText::SetBBText"
},
"parameters": [
"fullTextDebug",
"=",
"\"+\"+DialogueTree::LineText()"
],
"subInstructions": []
}
],
"events": []
}
]
},
@@ -7300,9 +7674,59 @@
"textG": 0,
"textR": 0
},
"comment": "The <<COMMAND>> type can be used to trigger game events - such as changing an avatar picture to happen",
"comment": "The <<COMMAND>> type can be used to trigger game events - such as changing an avatar picture to happen,parameter -1 is the name of the command where it came from, from there on it starts from 0",
"comment2": ""
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::IsDialogueLineType"
},
"parameters": [
"\"command\""
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "Visible"
},
"parameters": [
"commandsDebug"
],
"subInstructions": []
},
{
"type": {
"inverted": false,
"value": "BuiltinCommonInstructions::Once"
},
"parameters": [],
"subInstructions": []
}
],
"actions": [
{
"type": {
"inverted": false,
"value": "TextObject::String"
},
"parameters": [
"commandsDebug",
"+",
"\"<<\"+DialogueTree::CommandParameter(-1)+\">>\""
],
"subInstructions": []
}
],
"events": []
},
{
"disabled": false,
"folded": false,
@@ -7333,6 +7757,81 @@
}
],
"events": []
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Comment",
"color": {
"b": 109,
"g": 230,
"r": 255,
"textB": 0,
"textG": 0,
"textR": 0
},
"comment": "Example of loading/saving yarn's dialogue state from/to a gdevelop variable (use for load/save in your games)",
"comment2": ""
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::IsCommandCalled"
},
"parameters": [
"\"loadGame\""
],
"subInstructions": []
}
],
"actions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::LoadState"
},
"parameters": [
"yarnState"
],
"subInstructions": []
}
],
"events": []
},
{
"disabled": false,
"folded": false,
"type": "BuiltinCommonInstructions::Standard",
"conditions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::IsCommandCalled"
},
"parameters": [
"\"saveGame\""
],
"subInstructions": []
}
],
"actions": [
{
"type": {
"inverted": false,
"value": "DialogueTree::SaveState"
},
"parameters": [
"yarnState"
],
"subInstructions": []
}
],
"events": []
}
],
"parameters": []
@@ -7399,7 +7898,7 @@
"externalEvents": [
{
"associatedLayout": "New scene",
"lastChangeTimeStamp": 1383154438,
"lastChangeTimeStamp": 1383154432,
"name": "EnemiesManagement",
"events": [
{
@@ -7939,7 +8438,7 @@
},
{
"associatedLayout": "New scene",
"lastChangeTimeStamp": 1383151997,
"lastChangeTimeStamp": 1383152000,
"name": "ObjectsManagement",
"events": [
{
@@ -8098,7 +8597,7 @@
},
{
"associatedLayout": "New scene",
"lastChangeTimeStamp": 1383151997,
"lastChangeTimeStamp": 1383152000,
"name": "GUIManagement",
"events": [
{

View File

@@ -1,21 +1,21 @@
[
{
"title": "Start",
"tags": "",
"body": "<<avatar sign>> [color=#e90b0b]Press Z[/color] to interact with the tree critters 🐜🐛🐞 [color=#07a9b0]Spacebar[/color] to jump.\nAnd welcome to yarn's example GD project!",
"position": {
"x": -2144,
"y": 468
},
"colorID": 0
},
{
"title": "ant",
"tags": "",
"body": "<<avatar ant>>[b]Please don't bug me now[/b]... <<wait 1000>> I am [i]quite[/i] busy at the moment.\nHave you seen my crumb?\n[[ yes |antcrumbyes ]] [[ no |antcrumbno ]] ",
"position": {
"x": -1878,
"y": 470
"x": 7566,
"y": 10185
},
"colorID": 0
},
{
"title": "antcrumbno",
"tags": "",
"body": "Then [b]scram[/b]!\nI don't have time for you...",
"position": {
"x": 7370,
"y": 10460
},
"colorID": 0
},
@@ -24,48 +24,128 @@
"tags": "",
"body": "<<if $seenCrumb == true>>\nOh yeah? You saw it on a branch?\nDid you taste it?...\n<<else>>\nOh ha-ha! I can see that you are lying.\n<<endif>>",
"position": {
"x": -2086,
"y": 752
"x": 7671,
"y": 10487
},
"colorID": 3
},
{
"title": "antcrumbno",
"tags": "",
"body": "Then [b]scram[/b]!\nI don't have time for you...",
"position": {
"x": -1694,
"y": 744
},
"colorID": 0
},
{
"title": "crumb",
"tags": "",
"body": "<<avatar crumb>> <<set $seenCrumb to true >> You stumbled on a giant crumb.\nWhat would you like to do with it?\n[[ taste it | eatCrumb]] [[ take it| takeCrumb]] [[ nothing |null ]] ",
"position": {
"x": -1891,
"y": 974
"x": 7400,
"y": 10721
},
"colorID": 6
},
{
"title": "debug",
"tags": "",
"body": "0I am another weird node problem to test||<\n<<df>>\n [[Answer:debug|debug0]]",
"position": {
"x": 8208,
"y": 10166
},
"colorID": 0
},
{
"title": "debug0",
"tags": "",
"body": "]<<avatar sign>> >1[color=#e90b0b]Press Z[/color] to interact with the tree critters 🐜🐛🐞 [color=#07a9b0]Spacebar[/color] to jump.wait test .<<wait 1000>>.<<wait 1000>>.<<wait 1000>>||<<wait 2000>> \n2And welcome to yarn's example GD project!>||\n [[Answer:debug|debug1]]",
"position": {
"x": 8473,
"y": 10165
},
"colorID": 0
},
{
"title": "debug1",
"tags": "",
"body": "<<avatar ant>>\n>3Now scram!||<\n<<test>>\n\n[[ answer: |debug2 ]] ",
"position": {
"x": 8713,
"y": 10169
},
"colorID": 0
},
{
"title": "debug2",
"tags": "",
"body": "<<err>> >4 text with < <<avatar crumb>> >command in the middle ||\n5This is my tree|| <\n\n6||< <<avatar ant>>\n\n>7and my crumb||\n[[ answer: |debug3 ]] ",
"position": {
"x": 8967,
"y": 10172
},
"colorID": 0
},
{
"title": "debug3",
"tags": "",
"body": "<<only command>>\n[[ answer: |debug4 ]] ",
"position": {
"x": 9224,
"y": 10176
},
"colorID": 0
},
{
"title": "debug4",
"tags": "",
"body": "one last text",
"position": {
"x": 9466,
"y": 10180
},
"colorID": 0
},
{
"title": "eatCrumb",
"tags": "",
"body": "Let see <<wait 1000>>.<<wait 200>>.<<wait 200>> .<<wait 200>>these 🥨 are making you thirsty...",
"position": {
"x": -2105,
"y": 1225
"x": 7337,
"y": 11180
},
"colorID": 0
},
{
"title": "takeCrumb",
"title": "Node1",
"tags": "",
"body": "The thing is way too heavy 😬 ....",
"body": "node1= Once upon a time you<<command>> pressed SPACE to progress to the next node. [[Answer:Node2|Node2]]",
"position": {
"x": -1670,
"y": 1212
"x": 8210,
"y": 10419
},
"colorID": 0
},
{
"title": "Node2",
"tags": "",
"body": "node2= <<big_boi>>2 But suddenly the small boi black box started to move! [[Answer:Node3|Node3]]",
"position": {
"x": 8459,
"y": 10411
},
"colorID": 0
},
{
"title": "Node3",
"tags": "",
"body": "<<not_a_registered_command>> node3= But something horrible happened! All the text merged to the single text box, this is Node3. Press Space... [[Answer:Node4|Node4]]",
"position": {
"x": 8693,
"y": 10407
},
"colorID": 0
},
{
"title": "Node4",
"tags": "",
"body": "node4 I am Node4 and I didn't get merged as I don't have a command!",
"position": {
"x": 8917,
"y": 10402
},
"colorID": 0
},
@@ -74,8 +154,68 @@
"tags": "",
"body": "<<wait 100>> ",
"position": {
"x": -1590,
"y": 975
"x": 7149,
"y": 10728
},
"colorID": 0
},
{
"title": "Start",
"tags": "",
"body": "<<if $debug == true>>\n\n<<if $debugLinks == true>> \n[[ answer: |Node1 ]] \n<<else>> \n[[ debug|debug ]] \n<<endif>>\n\n<<else>>\n[[ start|Start1 ]] \n<<endif>>",
"position": {
"x": 7937,
"y": 10183
},
"colorID": 0
},
{
"title": "Start1",
"tags": "",
"body": "<<avatar sign>>[color=#e90b0b]Press Z[/color] to interact with the tree critters 🐜🐛🐞 [color=#07a9b0]Spacebar[/color] to jump.\nAnd welcome to yarn's example GD project!\n",
"position": {
"x": 7928,
"y": 10489
},
"colorID": 0
},
{
"title": "takeCrumb",
"tags": "",
"body": "The thing is way too heavy 😬 ....",
"position": {
"x": 7662,
"y": 10962
},
"colorID": 0
},
{
"title": "cricket",
"tags": "",
"body": "<<avatar cricket>> \nI am a cricket.\nWould you like to me to load/save the state\n\n[[ save it |saveState ]] \n[[ load it |loadState ]] \n[[ cancel |null ]] ",
"position": {
"x": 7017,
"y": 10159
},
"colorID": 0
},
{
"title": "saveState",
"tags": "",
"body": "<<saveGame>>\nGame stored to a GD variable",
"position": {
"x": 6678,
"y": 10466
},
"colorID": 0
},
{
"title": "loadState",
"tags": "",
"body": "<<loadGame>> \ngame loaded from GD variable",
"position": {
"x": 6930,
"y": 10468
},
"colorID": 0
}