diff --git a/package.json b/package.json index a2be633..77404f3 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "index.js", "scripts": { "postinstall": "node node_modules/jspm/jspm.js install", - "start": "node node_modules/gulp/bin/gulp.js" + "start": "node node_modules/gulp/bin/gulp.js", + "test": "./node_modules/.bin/mocha --reporter spec --recursive" }, "author": "Thomas Yuill", "license": "ISC", @@ -16,6 +17,7 @@ "babel-core": "^5.8.24", "babel-eslint": "^4.1.3", "browser-sync": "^2.4.0", + "chai": "^3.5.0", "chalk": "^1.1.1", "concurrent-transform": "^1.0.0", "del": "^1.1.1", @@ -34,6 +36,7 @@ "gulp-util": "^3.0.5", "gulp-zip": "^3.1.0", "jspm": "^0.16.20", + "mocha": "^3.0.2", "node-lambda": "^0.7.1", "require-dir": "^0.2.0", "run-sequence": "^1.1.0", diff --git a/src/skill/AlexaSkill.js b/src/skill/AlexaSkill.js index 8f81db4..334e047 100644 --- a/src/skill/AlexaSkill.js +++ b/src/skill/AlexaSkill.js @@ -67,8 +67,11 @@ AlexaSkill.prototype.execute = function ( event, context ) { + this._appId) throw "Invalid applicationId" } + if (!event.session.attributes) { - event.session.attributes = {} + event.session.attributes = { + flags: {} + } } if (event.session.new) { this.eventHandlers.onSessionStarted(event.request, event.session) diff --git a/src/skill/handlers/dynamoDB.js b/src/skill/handlers/dynamoDB.js index 449082a..b7048d1 100644 --- a/src/skill/handlers/dynamoDB.js +++ b/src/skill/handlers/dynamoDB.js @@ -28,7 +28,8 @@ function putUserState ( session, cb ) { "Item": { "userId": session.user.userId, "breadcrumbs": session.attributes.breadcrumbs, - "currentSceneId": session.attributes.currentSceneId + "currentSceneId": session.attributes.currentSceneId, + "flags": session.attributes.flags } } @@ -46,7 +47,8 @@ function getUserState ( session, cb ) { }, "AttributesToGet": [ "currentSceneId", - "breadcrumbs" + "breadcrumbs", + "flags" ], } diff --git a/src/skill/handlers/intentHandlers_default.js b/src/skill/handlers/intentHandlers_default.js index 9c616ee..a0a877f 100644 --- a/src/skill/handlers/intentHandlers_default.js +++ b/src/skill/handlers/intentHandlers_default.js @@ -7,9 +7,37 @@ var defaultIntentHandlers = { "LaunchIntent": function ( intent, session, request, response ) { session.attributes.breadcrumbs = [] + session.attributes.flags = {} session.attributes.currentSceneId = utils.findFirstScene().id var scene = utils.findResponseBySceneId( session.attributes.currentSceneId ) - respond.readSceneWithCard( scene, session, response ) + + var alreadyResponded = false; + + //check alternate conditions for next scene to see if alternate card and voice needs to be used instead + if(scene.alternateConditions && scene.alternateConditions !== ''){ + + if(utils.checkConditionString(scene.alternateConditions,session)){ + respond.readSceneWithCard( utils.getModifiedScene(scene,'alternate'), session, response ); + alreadyResponded = true; + } + } + + //set session flags on enter if the next scene specifies their values + if(scene.setSessionFlagsOnEnter && scene.setSessionFlagsOnEnter !== ''){ + var flags = scene.setSessionFlagsOnEnter.split("\n"); + flags.forEach(function(flag){ + var flagArray = flag.split('='); + var flagKey = flagArray[0]; + var flagValue = flagArray[1]; + + session.attributes.flags[flagKey] = flagValue; + }); + } + + if(!alreadyResponded){ + respond.readSceneWithCard( scene, session, response ) + } + }, "GoBackIntent": function ( intent, session, request, response ) { @@ -20,6 +48,25 @@ var defaultIntentHandlers = { session.attributes.currentSceneId = session.attributes.breadcrumbs.pop() } var scene = utils.findResponseBySceneId( session.attributes.currentSceneId ) + + //check entry conditions for next scene to make sure user can actually enter + if(scene.entryConditions && scene.entryConditions !== ''){ + + if(!utils.checkConditionString(scene.entryConditions,session)){ + respond.readSceneWithCard( utils.getModifiedScene(scene,'reject'), session, response ); + return; + } + } + + //check alternate conditions for next scene to see if alternate card and voice needs to be used instead + if(scene.alternateConditions && scene.alternateConditions !== ''){ + + if(utils.checkConditionString(scene.alternateConditions,session)){ + respond.readSceneWithCard( utils.getModifiedScene(scene,'alternate'), session, response ); + return; + } + } + respond.readSceneWithCard( scene, session, response ) }, @@ -38,6 +85,24 @@ var defaultIntentHandlers = { previousScene.options.splice( index , 1 ) // remove current option scene.options = previousScene.options } + + //check entry conditions for next scene to make sure user can actually enter + if(scene.entryConditions && scene.entryConditions !== ''){ + + if(!utils.checkConditionString(scene.entryConditions,session)){ + respond.readSceneWithCard( utils.getModifiedScene(scene,'reject'), session, response ); + return; + } + } + + //check alternate conditions for next scene to see if alternate card and voice needs to be used instead + if(scene.alternateConditions && scene.alternateConditions !== ''){ + + if(utils.checkConditionString(scene.alternateConditions,session)){ + respond.readSceneWithCard( utils.getModifiedScene(scene,'alternate'), session, response ); + return; + } + } } respond.readSceneWithCard( scene, session, response ) }, @@ -73,9 +138,29 @@ var defaultIntentHandlers = { "ResetStateIntent": function ( intent, session, request, response ) { session.attributes.breadcrumbs = [] + session.attributes.flags = {} delete session.attributes.isAskingToRestoreState session.attributes.currentSceneId = utils.findFirstScene().id var scene = utils.findResponseBySceneId( session.attributes.currentSceneId ) + + //check entry conditions for next scene to make sure user can actually enter + if(scene.entryConditions && scene.entryConditions !== ''){ + + if(!utils.checkConditionString(scene.entryConditions,session)){ + respond.readSceneWithCard( utils.getModifiedScene(scene,'reject'), session, response ); + return; + } + } + + //check alternate conditions for next scene to see if alternate card and voice needs to be used instead + if(scene.alternateConditions && scene.alternateConditions !== ''){ + + if(utils.checkConditionString(scene.alternateConditions,session)){ + respond.readSceneWithCard( utils.getModifiedScene(scene,'alternate'), session, response ); + return; + } + } + respond.readSceneWithCard( scene, session, response ) }, diff --git a/src/skill/handlers/intentHandlers_generated.js b/src/skill/handlers/intentHandlers_generated.js index fa6fbb4..7b02685 100644 --- a/src/skill/handlers/intentHandlers_generated.js +++ b/src/skill/handlers/intentHandlers_generated.js @@ -40,7 +40,13 @@ module.exports = { "OpenDoorFourIntent": function ( intent, session, request, response ) { processUtterance( intent, session, request, response, "open door 4" ) }, + "OpenDoorSixIntent": function ( intent, session, request, response ) { + processUtterance( intent, session, request, response, "open door 6" ) + }, "OpenDoorFiveIntent": function ( intent, session, request, response ) { processUtterance( intent, session, request, response, "open door 5" ) }, + "TakeRedKeyIntent": function ( intent, session, request, response ) { + processUtterance( intent, session, request, response, "take red key" ) + }, } \ No newline at end of file diff --git a/src/skill/handlers/processUtterance.js b/src/skill/handlers/processUtterance.js index 079f281..08c5eb7 100644 --- a/src/skill/handlers/processUtterance.js +++ b/src/skill/handlers/processUtterance.js @@ -19,6 +19,7 @@ function processUtterance ( intent, session, request, response, utterance ) { }) var currentScene = utils.findResponseBySceneId( session.attributes.currentSceneId ) + var actualCurrentScene = utils.findResponseBySceneId( session.attributes.currentSceneId ) if (!currentScene || !currentScene.options) { intentHandlers["LaunchIntent"](intent, session, request, response) @@ -38,9 +39,61 @@ function processUtterance ( intent, session, request, response, utterance ) { // option found if ( option ) { var nextScene = utils.findNextScene( currentScene, option ); + var actualNextScene = utils.findNextScene( actualCurrentScene, option ); + + var alreadyResponded = false; + + //set session flags on exit if the current scene specifies their values + if(actualCurrentScene.setSessionFlagsOnExit && actualCurrentScene.setSessionFlagsOnExit !== ''){ + var flags = actualCurrentScene.setSessionFlagsOnExit.split("\n"); + flags.forEach(function(flag){ + var flagArray = flag.split('='); + var flagKey = flagArray[0]; + var flagValue = flagArray[1]; + + session.attributes.flags[flagKey] = flagValue; + }); + } + + //check entry conditions for next scene to make sure user can actually enter + if(actualNextScene.entryConditions && actualNextScene.entryConditions !== ''){ + + if(!utils.checkConditionString(actualNextScene.entryConditions,session)){ + alreadyResponded = true; + respond.readSceneWithCard( utils.getModifiedScene(actualNextScene,'reject'), session, response ); + } + } + + //check alternate conditions for next scene to see if alternate card and voice needs to be used instead + if(actualNextScene.alternateConditions && actualNextScene.alternateConditions !== ''){ + + if(utils.checkConditionString(actualNextScene.alternateConditions,session)){ + alreadyResponded = true; + respond.readSceneWithCard( utils.getModifiedScene(actualNextScene,'alternate'), session, response ); + } + } + + console.log('Currentscene: ',currentScene); + console.log('Nextscene: ',nextScene); + + //set session flags on enter if the next scene specifies their values + if(actualNextScene.setSessionFlagsOnEnter && actualNextScene.setSessionFlagsOnEnter !== ''){ + var flags = actualNextScene.setSessionFlagsOnEnter.split("\n"); + flags.forEach(function(flag){ + var flagArray = flag.split('='); + var flagKey = flagArray[0]; + var flagValue = flagArray[1]; + + session.attributes.flags[flagKey] = flagValue; + }); + } + session.attributes.breadcrumbs.push( currentScene.id ) session.attributes.currentSceneId = nextScene.id - respond.readSceneWithCard( nextScene, session, response ) + + if(!alreadyResponded){ + respond.readSceneWithCard( nextScene, session, response ) + } } // no match diff --git a/src/skill/handlers/respond.js b/src/skill/handlers/respond.js index 9b49cdb..f49f24f 100644 --- a/src/skill/handlers/respond.js +++ b/src/skill/handlers/respond.js @@ -2,11 +2,12 @@ var AlexaSkill = require('../AlexaSkill') var dynamo = require('./dynamoDB') +var utils = require('./utils') module.exports = { readSceneWithCard: function ( scene, session, response ) { - var json = buildResponse( scene ) + var json = buildResponse( scene, session ) dynamo.putUserState( session, function ( data ) { console.log( data.message ) response.askWithCard( @@ -20,7 +21,7 @@ module.exports = { }, exitWithCard: function ( scene, session, response ) { - var json = buildResponse( scene ) + var json = buildResponse( scene, session ) dynamo.putUserState( session, function ( data ) { console.log( data.message ) response.tellWithCard( @@ -34,10 +35,10 @@ module.exports = { } -function buildResponse ( scene ){ +function buildResponse ( scene, session ){ - var voicePrompt = scene.voice.prompt.trim() || buildPrompt( scene, true ) - var cardPrompt = scene.card.prompt.trim() || buildPrompt( scene, false ) + var voicePrompt = scene.voice.prompt.trim() || buildPrompt( scene, true, session ) + var cardPrompt = scene.card.prompt.trim() || buildPrompt( scene, false, session ) return { @@ -71,14 +72,18 @@ function buildResponse ( scene ){ } -function buildPrompt ( scene, isForSpeech ) { +function buildPrompt ( scene, isForSpeech, session ) { var utils = require('./utils') var options = [] if ( scene.voice.prompt ) return scene.voice.prompt.trim() var options = scene.options.filter( function ( option ) { - return ! utils.findResponseBySceneId( option.sceneId ).isHidden + + var filteredScene = utils.findResponseBySceneId( option.sceneId ); + + //check entry conditions for scene to filter to see if it can be shown if the entry conditions are met, regardless if its hidden or not + return (!filteredScene.isHidden || (filteredScene.isHidden && filteredScene.entryConditions && filteredScene.entryConditions !== '' && utils.checkConditionString(filteredScene.entryConditions,session))); }).map( function ( option ) { return option.utterances[0] }) diff --git a/src/skill/handlers/utils.js b/src/skill/handlers/utils.js index aa8a6a9..b0e5e31 100644 --- a/src/skill/handlers/utils.js +++ b/src/skill/handlers/utils.js @@ -5,6 +5,55 @@ var scenes = require('../models/scenes.json') var utils = { + checkConditionString: function(inputString,session) { + + var conditions = inputString.split("\n"); + var conditionString = ''; + + //skip check if flags are empty + if(session.attributes.flags.length === 0){ + return false; + } + + for(var i = 0; i < conditions.length; i++){ + var condition = conditions[i]; + var conditionArray = condition.split('='); + var conditionKey = conditionArray[0]; + + switch(conditionKey){ + case 'AND': + //is logical AND + conditionString += ' && '; + break; + case 'OR': + //is logical OR + conditionString += ' || '; + break; + case 'NOT': + //is logical NOT + conditionString += '!'; + break; + case 'GROUPSTART': + //is ( + conditionString +='('; + break; + case 'GROUPEND': + //is ( + conditionString +=')'; + break; + default: + //is regular condition + var conditionValue = conditionArray[1]; + conditionString += 'session.attributes.flags[\''+conditionKey+'\'] === \''+conditionValue+'\''; + break; + } + } + + + + return eval(conditionString); + }, + getSkillName: function () { return config.skillName }, @@ -41,6 +90,39 @@ var utils = { findPreviousScene: function ( session ) { var sceneId = session.attributes.breadcrumbs[ session.attributes.breadcrumbs.length -1 ] return utils.findResponseBySceneId( sceneId ) + }, + + cloneScene: function( scene ) { + return cloneScene(scene); + }, + + getModifiedScene: function( scene , type ) { + + var newScene = this.cloneScene(scene); + + switch(type){ + default: + case 'reject': + newScene.card = newScene.rejectCard; + newScene.voice = newScene.rejectVoice; + break; + case 'alternate': + newScene.card = newScene.alternateCard; + newScene.voice = newScene.alternateVoice; + break; + } + + /*if(newScene.card.prompt === '' && scene.card.prompt !== ''){ + newScene.card.prompt = scene.card.prompt; + } + + if(newScene.voice.prompt === '' && scene.voice.prompt !== ''){ + newScene.voice.prompt = scene.voice.prompt; + }*/ + + console.log('Modified scene: ',newScene); + + return newScene; } } @@ -50,7 +132,9 @@ module.exports = utils function cloneScene ( scene ) { var scene = Object.assign( {}, scene ) scene.card = Object.assign( {}, scene.card ) + scene.rejectCard = Object.assign( {}, scene.rejectCard ) scene.voice = Object.assign( {}, scene.voice ) + scene.rejectVoice = Object.assign( {}, scene.rejectVoice ) if ( 'options' in scene ) scene.options = scene.options.slice() return scene } diff --git a/src/skill/models/config.json b/src/skill/models/config.json index d1884b9..6e99dfb 100644 --- a/src/skill/models/config.json +++ b/src/skill/models/config.json @@ -1,6 +1,6 @@ { "applicationId": null, - "awsProfileName": "", + "awsProfileName": "adventure-game", "skillName": "My Alexa Skill", "lambdaName": "MyAlexaSkillLambdaFunction", "dynamoTableName": "MyAlexaSkillTable", @@ -8,6 +8,7 @@ "commands": { "ResetStateIntent": [ "reset skill", + "restart", "start again", "reset" ], diff --git a/src/skill/models/intentSchema.json b/src/skill/models/intentSchema.json index eea9be2..1ea9025 100644 --- a/src/skill/models/intentSchema.json +++ b/src/skill/models/intentSchema.json @@ -42,8 +42,14 @@ { "intent": "OpenDoorFourIntent" }, + { + "intent": "OpenDoorSixIntent" + }, { "intent": "OpenDoorFiveIntent" + }, + { + "intent": "TakeRedKeyIntent" } ] } \ No newline at end of file diff --git a/src/skill/models/scenes.json b/src/skill/models/scenes.json index c97f492..84f9ea5 100644 --- a/src/skill/models/scenes.json +++ b/src/skill/models/scenes.json @@ -4,6 +4,9 @@ "color": "default", "isHidden": false, "readPreviousOptions": false, + "setSessionFlagsOnEnter": "", + "setSessionFlagsOnExit": "", + "entryConditions": "", "card": { "title": "Welcome", "text": "Welcome to my Alexa Skill. To learn how to use this skill, say \"Help\".", @@ -13,10 +16,23 @@ "smallImageUrl": null } }, + "rejectCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, "voice": { "intro": "Welcome to my Alexa Skill. To learn how to use this skill, say \"Help\".", "prompt": "When you are ready, say \"Begin\"." }, + "rejectVoice": { + "intro": "", + "prompt": "" + }, "options": [ { "utterances": [ @@ -24,16 +40,42 @@ ], "sceneId": 1 } - ] + ], + "alternateConditions": "", + "alternateCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "alternateVoice": { + "intro": "", + "prompt": "" + } }, { "id": 1, "color": "default", "isHidden": false, "readPreviousOptions": false, + "setSessionFlagsOnEnter": "", + "setSessionFlagsOnExit": "", + "entryConditions": "", "card": { "title": "Welcome", - "text": "You enter a room with three doors each with a distinct number on it. Which door would you like to open?", + "text": "You enter a room with three doors, each with a distinct number on it. Which door would you like to open?", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "rejectCard": { + "title": "", + "text": "", "prompt": "", "image": { "largeImageUrl": null, @@ -44,6 +86,10 @@ "intro": "You enter a room with three doors, each with a distinct number on it. Which door would you like to open?", "prompt": "" }, + "rejectVoice": { + "intro": "", + "prompt": "" + }, "options": [ { "utterances": [ @@ -69,13 +115,30 @@ ], "sceneId": 5 } - ] + ], + "alternateConditions": "inventory.redKey=1", + "alternateCard": { + "title": "Welcome", + "text": "You are in a room with three doors, each with a distinct number on it. Your red key glows as you turn to face door number two. Which door would you like to open?", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "alternateVoice": { + "intro": "You are in a room with three doors, each with a distinct number on it. Your red key glows as you turn to face door number two. Which door would you like to open?", + "prompt": "" + } }, { "id": 2, "color": "red", "isHidden": false, "readPreviousOptions": false, + "setSessionFlagsOnEnter": "", + "setSessionFlagsOnExit": "", + "entryConditions": "", "card": { "title": "You lose", "text": "Better luck next time.", @@ -85,37 +148,104 @@ "smallImageUrl": null } }, + "rejectCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, "voice": { "intro": "You lose. Better luck next time.", "prompt": "If you would like to play again say, \"start again.\" Otherwise you can say \"exit skill.\"" }, - "options": [] + "rejectVoice": { + "intro": "", + "prompt": "" + }, + "options": [], + "alternateConditions": "", + "alternateCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "alternateVoice": { + "intro": "", + "prompt": "" + } }, { "id": 3, "color": "yellow", "isHidden": false, - "readPreviousOptions": true, + "readPreviousOptions": false, + "setSessionFlagsOnEnter": "", + "setSessionFlagsOnExit": "", + "entryConditions": "inventory.redKey=1\nOR\ninventory.skeletonKey=1", "card": { "title": "Locked Door", - "text": "This door is locked.", + "text": "You unlock the door with the key.", "prompt": "", "image": { "largeImageUrl": null, "smallImageUrl": null } }, + "rejectCard": { + "title": "Locked Door", + "text": "The door is locked. You need a Red Key.", + "prompt": "You can say \"Open Door One\", \"Open Door Two\" or \"Open Door Three\".", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, "voice": { - "intro": "This door is locked. Maybe you should try one of the other doors.", + "intro": "You unlock the door with the key.", "prompt": "" }, - "options": [] + "rejectVoice": { + "intro": "The door is locked. You need a Red Key.", + "prompt": "You can say \"Open Door One\", \"Open Door Two\" or \"Open Door Three\"." + }, + "options": [ + { + "sceneId": 8, + "utterances": [ + "open door 6" + ] + } + ], + "alternateConditions": "", + "alternateCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "alternateVoice": { + "intro": "", + "prompt": "" + } }, { "id": 4, "color": "green", "isHidden": false, "readPreviousOptions": false, + "setSessionFlagsOnEnter": "", + "setSessionFlagsOnExit": "", + "entryConditions": "", "card": { "title": "You win", "text": "Congratulations, you've beat my skill!", @@ -125,20 +255,60 @@ "smallImageUrl": null } }, + "rejectCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, "voice": { "intro": "Congratulations, you've beat my skill!", "prompt": "If you would like to play again say, \"Start again.\" Otherwise you can say \"Exit skill.\"" }, - "options": [] + "rejectVoice": { + "intro": "", + "prompt": "" + }, + "options": [], + "alternateConditions": "", + "alternateCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "alternateVoice": { + "intro": "", + "prompt": "" + } }, { "id": 5, "color": "default", "isHidden": true, "readPreviousOptions": false, + "setSessionFlagsOnEnter": "", + "setSessionFlagsOnExit": "", + "entryConditions": "", + "alternateConditions": "inventory.redKey=1", "card": { "title": "Secret Room", - "text": "Congratulations, you've found a secret room. You look around and see a single door with a star on it.", + "text": "Congratulations, you've found a secret room. You look around and see a single door with a star on it and a red key lying in the centre.", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "rejectCard": { + "title": "", + "text": "", "prompt": "", "image": { "largeImageUrl": null, @@ -146,7 +316,15 @@ } }, "voice": { + "intro": "Congratulations, you've found a secret room. You look around and see a single door with a star on it and a red key lying in the centre.", + "prompt": "" + }, + "alternateVoice": { "intro": "Congratulations, you've found a secret room. You look around and see a single door with a star on it.", + "prompt": "You can say \"Open door five\" or \"go back\"." + }, + "rejectVoice": { + "intro": "", "prompt": "" }, "options": [ @@ -155,8 +333,23 @@ "utterances": [ "open door 5" ] + }, + { + "sceneId": 7, + "utterances": [ + "take red key" + ] + } + ], + "alternateCard": { + "title": "Secret Room", + "text": "Congratulations, you've found a secret room. You look around and see a single door with a star on it.", + "prompt": "You can say \"Open door five\" or \"go back\".", + "image": { + "largeImageUrl": null, + "smallImageUrl": null } - ] + } }, { "id": 6, @@ -164,6 +357,9 @@ "isHidden": false, "generateOptions": true, "readPreviousOptions": false, + "setSessionFlagsOnEnter": "", + "setSessionFlagsOnExit": "", + "entryConditions": "", "card": { "title": "Room", "text": "You win!", @@ -173,10 +369,139 @@ "smallImageUrl": null } }, + "rejectCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, "voice": { "intro": "You win!", "prompt": "If you would like to play again say, \"Start again.\" Otherwise you can say \"Exit skill.\"" }, - "options": [] + "rejectVoice": { + "intro": "", + "prompt": "" + }, + "options": [], + "alternateConditions": "", + "alternateCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "alternateVoice": { + "intro": "", + "prompt": "" + } + }, + { + "id": 7, + "color": "red", + "isHidden": false, + "generateOptions": true, + "readPreviousOptions": false, + "setSessionFlagsOnEnter": "inventory.redKey=1", + "setSessionFlagsOnExit": "", + "entryConditions": "", + "card": { + "title": "Red key", + "text": "You take the red key. It shines like a ruby.", + "prompt": "Say \"go back\" to proceed.", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "rejectCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "voice": { + "intro": "You take the red key. It shines like a ruby.", + "prompt": "Say \"go back\" to proceed." + }, + "rejectVoice": { + "intro": "", + "prompt": "" + }, + "options": [], + "alternateConditions": "inventory.redKey=1", + "alternateCard": { + "title": "Red key", + "text": "There is nothing there. You have already taken the red key.", + "prompt": "Say \"go back\" to proceed.", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "alternateVoice": { + "intro": "There is nothing there. You have already taken the red key.", + "prompt": "Say \"go back\" to proceed." + } + }, + { + "id": 8, + "color": "default", + "isHidden": false, + "generateOptions": true, + "readPreviousOptions": false, + "setSessionFlagsOnEnter": "", + "setSessionFlagsOnExit": "", + "entryConditions": "", + "card": { + "title": "Room", + "text": "You enter a room filled with gold bars.", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "rejectCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "voice": { + "intro": "You enter a room filled with gold bars. What would you like to do?", + "prompt": "" + }, + "rejectVoice": { + "intro": "", + "prompt": "" + }, + "options": [], + "alternateConditions": "", + "alternateCard": { + "title": "", + "text": "", + "prompt": "", + "image": { + "largeImageUrl": null, + "smallImageUrl": null + } + }, + "alternateVoice": { + "intro": "", + "prompt": "" + } } ] \ No newline at end of file diff --git a/src/skill/models/utterances.txt b/src/skill/models/utterances.txt index 31f02d4..49223c6 100644 --- a/src/skill/models/utterances.txt +++ b/src/skill/models/utterances.txt @@ -4,6 +4,7 @@ UnrecognizedIntent ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyN UnrecognizedIntent ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense UnrecognizedIntent ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense ThisIsPurposlyNonSense ResetStateIntent reset skill +ResetStateIntent restart ResetStateIntent start again ResetStateIntent reset RestoreStateIntent resume skill @@ -20,4 +21,6 @@ OpenDoorOneIntent open door one OpenDoorTwoIntent open door two OpenDoorThreeIntent open door three OpenDoorFourIntent open door four -OpenDoorFiveIntent open door five \ No newline at end of file +OpenDoorSixIntent open door six +OpenDoorFiveIntent open door five +TakeRedKeyIntent take red key \ No newline at end of file diff --git a/src/tags/js/panel-edit-scene.js b/src/tags/js/panel-edit-scene.js index 243bc2e..8941f99 100644 --- a/src/tags/js/panel-edit-scene.js +++ b/src/tags/js/panel-edit-scene.js @@ -7,7 +7,7 @@ tagger(window.riot); } })(function(riot) { -riot.tag2('panel-edit-scene', '
Note: All image URLs must be secure (HTTPS)
Override Default Prompt:
By default, the Alexa will provide a visual "card" to prompt the user to respond by reading out the all current available options.
If you would prefer to override this default behavior, enter your user prompt here.
Note: Options that lead to "hidden" scenes will be ignored.
Override Default Prompt:
By default, Alexa will prompt the user to respond by reading out the all current available options.
If you would prefer to override this default behavior, enter your user prompt here.
Note: Options that lead to "hidden" scenes will be ignored.
Supported SSML Tags
- <audio>
- <break>
- <speak>
- <say-as>
- <phoneme>
- <s>
- <p>
- <w>
See Alexa SSML documentation
Note: All URLs must be secure (HTTPS)
Use the format FLAG_NAME=FLAG_VALUE with a new flag on each line. E.g.
inventory.redKey=1 player.poisoned=1
These flags will be set when the user enters the scene.
Use the format FLAG_NAME=FLAG_VALUE with a new flag on each line. E.g.
player.poisoned=0
These flags will be set when the user exits the scene.
Use the format FLAG_NAME=FLAG_VALUE with a new condition on each line. You may also use the following key words to indicate conditions: AND, OR, NOT, GROUPSTART, GROUPEND E.g.
player.poisoned=0
AND
GROUPSTART
inventory.redKey=1
OR
inventory.skeletonKey=1
GROUPEND
This will translate into the following logic code:
if(session.attributes.flags[\'player.poisoned\'] === "0" && (session.attributes.flags.[\'inventory.redKey\'] === "1" || session.attributes.flags.[\'inventory.skeletonKey\'])
This logic is applied before the user enters the scene. If the conditions are not met the reject Voice and Card will be played to the user.
Use the format FLAG_NAME=FLAG_VALUE with a new condition on each line. You may also use the following key words to indicate conditions: AND, OR, NOT, GROUPSTART, GROUPEND E.g.
player.poisoned=0
AND
GROUPSTART
inventory.redKey=1
OR
inventory.skeletonKey=1
GROUPEND
This will translate into the following logic code:
if(session.attributes.flags[\'player.poisoned\'] === "0" && (session.attributes.flags.[\'inventory.redKey\'] === "1" || session.attributes.flags.[\'inventory.skeletonKey\'])
This logic is applied before the user enters the scene. If the conditions are not met the reject Voice and Card will be played to the user.
Override Default Prompt:
By default, the Alexa will provide a visual "card" to prompt the user to respond by reading out the all current available options.
If you would prefer to override this default behavior, enter your user prompt here.
Note: Options that lead to "hidden" scenes will be ignored.
Note: All image URLs must be secure (HTTPS)
Note: All image URLs must be secure (HTTPS)
Note: All image URLs must be secure (HTTPS)
Override Default Prompt:
By default, Alexa will prompt the user to respond by reading out the all current available options.
If you would prefer to override this default behavior, enter your user prompt here.
Note: Options that lead to "hidden" scenes will be ignored.
Supported SSML Tags
- <audio>
- <break>
- <speak>
- <say-as>
- <phoneme>
- <s>
- <p>
- <w>
See Alexa SSML documentation
Note: All URLs must be secure (HTTPS)
Command Utterances:
diff --git a/src/tags/panel-edit-scene.tag b/src/tags/panel-edit-scene.tag
index db3ec8f..351c2b7 100644
--- a/src/tags/panel-edit-scene.tag
+++ b/src/tags/panel-edit-scene.tag
@@ -9,6 +9,8 @@
+
+ Use the format FLAG_NAME=FLAG_VALUE with a new flag on each line. E.g.
+ inventory.redKey=1
+ player.poisoned=1
+
+
+ These flags will be set when the user enters the scene.
+
+
+
+ Use the format FLAG_NAME=FLAG_VALUE with a new flag on each line. E.g.
+ player.poisoned=0
+
+
+ These flags will be set when the user exits the scene.
+
+
+
+ Use the format FLAG_NAME=FLAG_VALUE with a new condition on each line. You may also use the
+ following key words to indicate conditions: AND, OR, NOT, GROUPSTART, GROUPEND E.g.
+
+
+ player.poisoned=0
+ AND
+ GROUPSTART
+ inventory.redKey=1
+ OR
+ inventory.skeletonKey=1
+ GROUPEND
+
+
+ This will translate into the following logic code:
+ if(session.attributes.flags['player.poisoned'] === "0" && (session.attributes.flags.['inventory.redKey'] === "1" || session.attributes.flags.['inventory.skeletonKey'])
+
+
+ This logic is applied before the user enters the scene. If the conditions are not met the reject Voice and Card will
+ be played to the user.
+
+
+
+ Use the format FLAG_NAME=FLAG_VALUE with a new condition on each line. You may also use the
+ following key words to indicate conditions: AND, OR, NOT, GROUPSTART, GROUPEND E.g.
+
+
+ player.poisoned=0
+ AND
+ GROUPSTART
+ inventory.redKey=1
+ OR
+ inventory.skeletonKey=1
+ GROUPEND
+
+
+ This will translate into the following logic code:
+ if(session.attributes.flags['player.poisoned'] === "0" && (session.attributes.flags.['inventory.redKey'] === "1" || session.attributes.flags.['inventory.skeletonKey'])
+
+
+ This logic is applied before the user enters the scene. If the conditions are not met the reject Voice and Card will
+ be played to the user.
+
+
+ Override Default Prompt:
+ By default, the Alexa will provide a visual "card" to
+ prompt the user to respond by reading out the all
+ current available options.
+
+ If you would prefer to override this default behavior, + enter your user prompt here. +
++ + Note: Options that lead to "hidden" + scenes will be ignored. + +
+
- Override Default Prompt:
- By default, the Alexa will provide a visual "card" to
- prompt the user to respond by reading out the all
- current available options.
-
- If you would prefer to override this default behavior, - enter your user prompt here. -
-- - Note: Options that lead to "hidden" - scenes will be ignored. - -
++ + Note: All image URLs must be secure (HTTPS) + +
++ + Note: All image URLs must be secure (HTTPS) + +
+