-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathinput_router.js
162 lines (144 loc) · 5.63 KB
/
input_router.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
var files = require('./files.js');
var strings = require('./strings.js');
var dialogue_tree = require('./dialogue_tree.js');
var zork = require('./zork.js');
var reading = require('./reading.js');
var fs = require('fs');
var list_keys = require('./utils.js').list_keys;
const RETURN_TO_GAME_KEY = 'return_to_game';
const BACK_KEY = 'back';
const PATH_KEY = 'path';
const CURRENT_PAGE_KEY = reading.CURRENT_PAGE_KEY;
const PAGES_KEY = reading.PAGES_KEY;
// Accepts an incoming main intent.
exports.acceptMain = function (app) {
fs.access(files.getUserSaveFile(app), fs.constants.R_OK, (err) => {
if (err) {
app.askSSML(strings.main_intent);
} else {
zork.doReturningUserLook(app);
}
});
}
// Accepts a text input intent.
exports.acceptInput = function(app) {
var input = app.getRawInput();
var dialogue_state = app.getDialogState();
// If we have state, that means we asked them to select an option but they
// didn't say anything we understood
if (PATH_KEY in dialogue_state && dialogue_state[PATH_KEY].length > 0) {
var prompt = `Sorry, I didn't understand that. I thought you said "${input}".`;
if (CURRENT_PAGE_KEY in dialogue_state) {
prompt = `${prompt} Would you like to keep reading?`;
app.askWithListSSML(prompt, reading.makePagesOptions(app), dialogue_state);
} else {
var current_node = followPath(dialogue_state[PATH_KEY]);
prompt = `${prompt} The options are ${list_keys(current_node.children)}. You can also return to the game.`;
app.askWithListSSML(prompt, buildList(app, current_node), dialogue_state);
}
}
var next_node = dialogue_tree.getChildWithKeyOrAlias(input);
if (next_node) {
doNode(app, next_node, [next_node.key]);
} else {
zork.handleInput(app);
}
}
// Accepts an incoming option selection intent.
// If we're here, we're assuming that we're somewhere within the dialogue
// tree that is not the root.
exports.acceptOption = function(app) {
var dialogue_state = app.getDialogState();
var selected_option = app.getSelectedOption();
var current_node = followPath(dialogue_state[PATH_KEY]);
// Reading pages always takes priority
if (CURRENT_PAGE_KEY in dialogue_state && selected_option != reading.QUIT_READING_KEY) {
var next_page_index = dialogue_state[CURRENT_PAGE_KEY] + 1;
var pages = dialogue_state[PAGES_KEY];
if(pages.length - 1 === next_page_index) {
var [parent, parent_path] = backtrack(dialogue_state[PATH_KEY]);
var next_page = pages[next_page_index];
doNode(app, parent, parent_path, next_page);
return;
} else {
dialogue_state[CURRENT_PAGE_KEY] = next_page_index;
app.askWithListSSML(pages[next_page_index], reading.makePagesOptions(app), dialogue_state);
return;
}
} else if (CURRENT_PAGE_KEY in dialogue_state){
// We're quitting reading
var [parent, parent_path] = backtrack(dialogue_state[PATH_KEY]);
doNode(app, parent, parent_path, 'Ok.');
return;
}
if (selected_option == RETURN_TO_GAME_KEY) {
app.askSSML('Ok, returning to game. What do you do next?');
return;
}
next_node = current_node.getChildByKey(selected_option);
if (next_node) {
doNode(app, next_node, dialogue_state[PATH_KEY].concat(selected_option));
return;
}
var prompt = `Sorry, something went wrong. Returning to game.`;
app.askSSML(prompt);
}
// param path: the path of the node we're doing
function doNode(app, node, path=[], say_first) {
if (node === dialogue_tree) {
if (say_first) {
app.askSSML(`${say_first} What do you do next?`);
}
return;
}
var dialogue_state = {[PATH_KEY]: path};
if (node.terminatingAction) {
node.terminatingAction(app);
} else if (node.hasChildren()) {
if (say_first) {
var text = `${say_first} Would you like to hear about something else? The options are ${list_keys(node.children)}`;
app.askWithListSSML(text, buildList(app, node), dialogue_state);
} else{
app.askWithListSSML(node.text, buildList(app, node), dialogue_state);
}
} else {
var pages = reading.makePages(node.text);
if (pages.length === 1) {
// If this is a leaf node, we're going to say it's text and then return to the parent
var [parent, parent_path] = backtrack(dialogue_state[PATH_KEY]);
doNode(app, parent, parent_path, pages[0]);
} else {
dialogue_state[CURRENT_PAGE_KEY] = 0;
dialogue_state[PAGES_KEY] = pages;
app.askWithListSSML(pages[0], reading.makePagesOptions(app), dialogue_state);
}
}
}
// Given a node, build a list to select one of its children
function buildList(app, node) {
var list = app.buildList();
for (var key in node.children) {
list.addItems(
app.buildOptionItem(key, node.children[key].aliases.concat(key)).setTitle(key)
);
}
list.addItems(app.buildOptionItem(RETURN_TO_GAME_KEY, ['return to game', 'return', 'game', 'no', 'quit', 'leave', 'none', 'stop']).setTitle('Return to Game'));
return list;
}
function backtrack(path) {
if (path) {
new_path = path.slice(0, -1);
return [followPath(new_path), new_path];
} else {
return [dialogue_tree, []];
}
}
function followPath(path) {
var node = dialogue_tree;
if (path) {
for (var key of path) {
node = node.getChildByKey(key);
}
}
return node;
}