@patterkit/runtime 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/index.cjs +53 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +53 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -684,10 +684,13 @@ declare class Flow {
|
|
|
684
684
|
private activeSnippet;
|
|
685
685
|
private beatIndex;
|
|
686
686
|
private pendingChoice;
|
|
687
|
-
/** When `replayPromptOnChoose`, the chosen option's prompt
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
*
|
|
687
|
+
/** When `replayPromptOnChoose`, the chosen option's AUTHORED prompt to deliver before its content: its
|
|
688
|
+
* beat (id, gameData, tags) and the prompt exactly as the choice showed it (text and speaker fields).
|
|
689
|
+
* `shown` is missing only after loading a save written before saves carried it: the beat is then
|
|
690
|
+
* resolved when it is delivered, as it always was. */
|
|
691
|
+
private pendingPrompt;
|
|
692
|
+
/** The chosen option that owns `pendingPrompt`, so a save taken between choose() and the next
|
|
693
|
+
* advance() can find the prompt beat again on load (it isn't otherwise reachable by id). */
|
|
691
694
|
private pendingPromptOwnerId;
|
|
692
695
|
private selectors;
|
|
693
696
|
/** Per-node entry counts for this flow (node id -> times entered). */
|
|
@@ -907,6 +910,11 @@ declare class Flow {
|
|
|
907
910
|
* option's first content line. NO look-ahead. Undefined only when even that is absent.
|
|
908
911
|
*/
|
|
909
912
|
private promptFor;
|
|
913
|
+
/** An option's AUTHORED prompt beat: an Option group's own `prompt`. The only prompt a replay speaks. */
|
|
914
|
+
private authoredPromptOf;
|
|
915
|
+
/** A replayed prompt as a step: the beat's id, gameData, and tags, and the text and speaker fields the
|
|
916
|
+
* choice showed. */
|
|
917
|
+
private promptResult;
|
|
910
918
|
/** The prompt BEAT of an option: the Option group's `prompt`, else (tolerance) its first content line. */
|
|
911
919
|
private promptBeatOf;
|
|
912
920
|
/** The first snippet with a line/text beat within a child list, depth-first in authored order. */
|
package/dist/index.d.ts
CHANGED
|
@@ -684,10 +684,13 @@ declare class Flow {
|
|
|
684
684
|
private activeSnippet;
|
|
685
685
|
private beatIndex;
|
|
686
686
|
private pendingChoice;
|
|
687
|
-
/** When `replayPromptOnChoose`, the chosen option's prompt
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
*
|
|
687
|
+
/** When `replayPromptOnChoose`, the chosen option's AUTHORED prompt to deliver before its content: its
|
|
688
|
+
* beat (id, gameData, tags) and the prompt exactly as the choice showed it (text and speaker fields).
|
|
689
|
+
* `shown` is missing only after loading a save written before saves carried it: the beat is then
|
|
690
|
+
* resolved when it is delivered, as it always was. */
|
|
691
|
+
private pendingPrompt;
|
|
692
|
+
/** The chosen option that owns `pendingPrompt`, so a save taken between choose() and the next
|
|
693
|
+
* advance() can find the prompt beat again on load (it isn't otherwise reachable by id). */
|
|
691
694
|
private pendingPromptOwnerId;
|
|
692
695
|
private selectors;
|
|
693
696
|
/** Per-node entry counts for this flow (node id -> times entered). */
|
|
@@ -907,6 +910,11 @@ declare class Flow {
|
|
|
907
910
|
* option's first content line. NO look-ahead. Undefined only when even that is absent.
|
|
908
911
|
*/
|
|
909
912
|
private promptFor;
|
|
913
|
+
/** An option's AUTHORED prompt beat: an Option group's own `prompt`. The only prompt a replay speaks. */
|
|
914
|
+
private authoredPromptOf;
|
|
915
|
+
/** A replayed prompt as a step: the beat's id, gameData, and tags, and the text and speaker fields the
|
|
916
|
+
* choice showed. */
|
|
917
|
+
private promptResult;
|
|
910
918
|
/** The prompt BEAT of an option: the Option group's `prompt`, else (tolerance) its first content line. */
|
|
911
919
|
private promptBeatOf;
|
|
912
920
|
/** The first snippet with a line/text beat within a child list, depth-first in authored order. */
|
package/dist/index.js
CHANGED
|
@@ -843,10 +843,13 @@ var Flow = class {
|
|
|
843
843
|
activeSnippet = null;
|
|
844
844
|
beatIndex = 0;
|
|
845
845
|
pendingChoice = null;
|
|
846
|
-
/** When `replayPromptOnChoose`, the chosen option's prompt
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
*
|
|
846
|
+
/** When `replayPromptOnChoose`, the chosen option's AUTHORED prompt to deliver before its content: its
|
|
847
|
+
* beat (id, gameData, tags) and the prompt exactly as the choice showed it (text and speaker fields).
|
|
848
|
+
* `shown` is missing only after loading a save written before saves carried it: the beat is then
|
|
849
|
+
* resolved when it is delivered, as it always was. */
|
|
850
|
+
pendingPrompt = null;
|
|
851
|
+
/** The chosen option that owns `pendingPrompt`, so a save taken between choose() and the next
|
|
852
|
+
* advance() can find the prompt beat again on load (it isn't otherwise reachable by id). */
|
|
850
853
|
pendingPromptOwnerId = null;
|
|
851
854
|
selectors = /* @__PURE__ */ new Map();
|
|
852
855
|
/** Per-node entry counts for this flow (node id -> times entered). */
|
|
@@ -1008,7 +1011,7 @@ var Flow = class {
|
|
|
1008
1011
|
if (scene === "END") {
|
|
1009
1012
|
this.started = true;
|
|
1010
1013
|
this.pendingChoice = null;
|
|
1011
|
-
this.
|
|
1014
|
+
this.pendingPrompt = null;
|
|
1012
1015
|
this.pendingPromptOwnerId = null;
|
|
1013
1016
|
this.activeSnippet = null;
|
|
1014
1017
|
this.beatIndex = 0;
|
|
@@ -1028,7 +1031,7 @@ var Flow = class {
|
|
|
1028
1031
|
return true;
|
|
1029
1032
|
}
|
|
1030
1033
|
this.pendingChoice = null;
|
|
1031
|
-
this.
|
|
1034
|
+
this.pendingPrompt = null;
|
|
1032
1035
|
this.pendingPromptOwnerId = null;
|
|
1033
1036
|
this.activeSnippet = null;
|
|
1034
1037
|
this.beatIndex = 0;
|
|
@@ -1055,7 +1058,7 @@ var Flow = class {
|
|
|
1055
1058
|
this.activeSnippet = null;
|
|
1056
1059
|
this.beatIndex = 0;
|
|
1057
1060
|
this.pendingChoice = null;
|
|
1058
|
-
this.
|
|
1061
|
+
this.pendingPrompt = null;
|
|
1059
1062
|
this.pendingPromptOwnerId = null;
|
|
1060
1063
|
}
|
|
1061
1064
|
/** Inside a checkpoint, the first change to this flow records its cursor and PRNG, so a rollback can
|
|
@@ -1065,10 +1068,10 @@ var Flow = class {
|
|
|
1065
1068
|
const journal = this.host.journal;
|
|
1066
1069
|
if (!journal || journal.flows.has(this)) return;
|
|
1067
1070
|
journal.flows.add(this);
|
|
1068
|
-
const { rngState, started, flowEnded, currentSceneId, activeSnippet, beatIndex, pendingChoice,
|
|
1071
|
+
const { rngState, started, flowEnded, currentSceneId, activeSnippet, beatIndex, pendingChoice, pendingPrompt, pendingPromptOwnerId } = this;
|
|
1069
1072
|
const stack = this.stack.map((f) => ({ ...f }));
|
|
1070
1073
|
journal.undo.push(() => {
|
|
1071
|
-
Object.assign(this, { rngState, started, flowEnded, currentSceneId, activeSnippet, beatIndex, pendingChoice,
|
|
1074
|
+
Object.assign(this, { rngState, started, flowEnded, currentSceneId, activeSnippet, beatIndex, pendingChoice, pendingPrompt, pendingPromptOwnerId, stack });
|
|
1072
1075
|
});
|
|
1073
1076
|
}
|
|
1074
1077
|
/** True once the engine has closed this flow (closed, dropped by `reset()`, or replaced by name). */
|
|
@@ -1086,11 +1089,11 @@ var Flow = class {
|
|
|
1086
1089
|
if (this.closed) return { type: "end" };
|
|
1087
1090
|
if (!this.started) throw new Error("flow has not been started");
|
|
1088
1091
|
this.touch();
|
|
1089
|
-
if (this.
|
|
1090
|
-
const
|
|
1091
|
-
this.
|
|
1092
|
+
if (this.pendingPrompt) {
|
|
1093
|
+
const p = this.pendingPrompt;
|
|
1094
|
+
this.pendingPrompt = null;
|
|
1092
1095
|
this.pendingPromptOwnerId = null;
|
|
1093
|
-
return this.beatResult(
|
|
1096
|
+
return p.shown ? this.promptResult(p.beat, p.shown) : this.beatResult(p.beat);
|
|
1094
1097
|
}
|
|
1095
1098
|
this.settle();
|
|
1096
1099
|
if (this.flowEnded) return { type: "end" };
|
|
@@ -1209,8 +1212,9 @@ var Flow = class {
|
|
|
1209
1212
|
const node = choice.byId.get(id);
|
|
1210
1213
|
this.emit({ type: "chose", group: choice.groupId, option: id });
|
|
1211
1214
|
this.pendingChoice = null;
|
|
1212
|
-
|
|
1213
|
-
this.
|
|
1215
|
+
const authored = this.host.replayPromptOnChoose ? this.authoredPromptOf(node) : void 0;
|
|
1216
|
+
this.pendingPrompt = authored && option.prompt ? { beat: authored, shown: { ...option.prompt } } : null;
|
|
1217
|
+
this.pendingPromptOwnerId = this.pendingPrompt ? node.id : null;
|
|
1214
1218
|
this.enterChild(node);
|
|
1215
1219
|
}
|
|
1216
1220
|
isEnded() {
|
|
@@ -1276,6 +1280,8 @@ var Flow = class {
|
|
|
1276
1280
|
beatIndex: this.beatIndex,
|
|
1277
1281
|
pendingChoice: this.pendingChoice ? { groupId: this.pendingChoice.groupId, options: this.pendingChoice.options.map((o) => ({ ...o })) } : null,
|
|
1278
1282
|
pendingPromptOwnerId: this.pendingPromptOwnerId,
|
|
1283
|
+
// The prompt still to be replayed, as the choice showed it: present only in the choose -> advance window.
|
|
1284
|
+
...this.pendingPrompt?.shown ? { pendingPrompt: savedPrompt(this.pendingPrompt.shown) } : {},
|
|
1279
1285
|
selectors: serialiseSelectors(this.selectors)
|
|
1280
1286
|
}
|
|
1281
1287
|
};
|
|
@@ -1326,12 +1332,13 @@ var Flow = class {
|
|
|
1326
1332
|
}
|
|
1327
1333
|
if (options.length > 0) this.pendingChoice = { groupId: c.pendingChoice.groupId, options, byId };
|
|
1328
1334
|
}
|
|
1329
|
-
this.
|
|
1335
|
+
this.pendingPrompt = null;
|
|
1330
1336
|
this.pendingPromptOwnerId = c.pendingPromptOwnerId ?? null;
|
|
1331
1337
|
if (this.pendingPromptOwnerId) {
|
|
1332
1338
|
const owner = this.host.nodeIndex.get(this.pendingPromptOwnerId);
|
|
1333
|
-
|
|
1334
|
-
if (
|
|
1339
|
+
const beat = owner ? this.authoredPromptOf(owner) : void 0;
|
|
1340
|
+
if (beat) this.pendingPrompt = { beat, ...c.pendingPrompt ? { shown: { ...c.pendingPrompt } } : {} };
|
|
1341
|
+
else this.pendingPromptOwnerId = null;
|
|
1335
1342
|
}
|
|
1336
1343
|
}
|
|
1337
1344
|
// -- Scene / block / node entry ------------------------------------------
|
|
@@ -1726,6 +1733,27 @@ var Flow = class {
|
|
|
1726
1733
|
const text = this.interpolate(this.resolveString(beat.id));
|
|
1727
1734
|
return beat.kind === "line" ? { kind: "line", text: this.captionLine(text), character: beat.character, characterName: this.resolveCharacterName(beat.character), direction: beat.direction } : { kind: "text", text };
|
|
1728
1735
|
}
|
|
1736
|
+
/** An option's AUTHORED prompt beat: an Option group's own `prompt`. The only prompt a replay speaks. */
|
|
1737
|
+
authoredPromptOf(node) {
|
|
1738
|
+
return node.type === "group" ? node.prompt : void 0;
|
|
1739
|
+
}
|
|
1740
|
+
/** A replayed prompt as a step: the beat's id, gameData, and tags, and the text and speaker fields the
|
|
1741
|
+
* choice showed. */
|
|
1742
|
+
promptResult(beat, shown) {
|
|
1743
|
+
const tags = this.host.tagIndex.get(beat.id);
|
|
1744
|
+
const withTags = tags && tags.length ? { tags } : {};
|
|
1745
|
+
if (shown.kind === "text") return { type: "text", id: beat.id, text: shown.text, gameData: beat.gameData, ...withTags };
|
|
1746
|
+
return {
|
|
1747
|
+
type: "line",
|
|
1748
|
+
id: beat.id,
|
|
1749
|
+
text: shown.text,
|
|
1750
|
+
character: shown.character,
|
|
1751
|
+
characterName: shown.characterName,
|
|
1752
|
+
direction: shown.direction,
|
|
1753
|
+
gameData: beat.gameData,
|
|
1754
|
+
...withTags
|
|
1755
|
+
};
|
|
1756
|
+
}
|
|
1729
1757
|
/** The prompt BEAT of an option: the Option group's `prompt`, else (tolerance) its first content line. */
|
|
1730
1758
|
promptBeatOf(node) {
|
|
1731
1759
|
if (node.type === "group" && node.prompt) return node.prompt;
|
|
@@ -1849,6 +1877,13 @@ function collectCast(nodes, out) {
|
|
|
1849
1877
|
function gameDataField(gameData) {
|
|
1850
1878
|
return gameData && Object.keys(gameData).length ? { gameData } : {};
|
|
1851
1879
|
}
|
|
1880
|
+
function savedPrompt(p) {
|
|
1881
|
+
const out = { kind: p.kind, text: p.text };
|
|
1882
|
+
if (p.character !== void 0) out.character = p.character;
|
|
1883
|
+
if (p.characterName !== void 0) out.characterName = p.characterName;
|
|
1884
|
+
if (p.direction !== void 0) out.direction = p.direction;
|
|
1885
|
+
return out;
|
|
1886
|
+
}
|
|
1852
1887
|
function serialiseSelectors(map) {
|
|
1853
1888
|
const out = {};
|
|
1854
1889
|
for (const [id, st] of map) {
|