Checkpoint current UI and ink integration state
This commit is contained in:
Vendored
+6
@@ -9,6 +9,8 @@ export declare class InkEngine {
|
||||
private readonly storyPath;
|
||||
private story;
|
||||
private nextTurnId;
|
||||
private storyJson;
|
||||
private readonly choicePreviewTagKeys;
|
||||
constructor(storyPath: string);
|
||||
isRunning(): boolean;
|
||||
newGame(): TurnResult;
|
||||
@@ -17,4 +19,8 @@ export declare class InkEngine {
|
||||
loadGame(savedState: string): TurnResult;
|
||||
private loadStory;
|
||||
private continueStory;
|
||||
private getChoiceTags;
|
||||
private extractChoicePreviewTags;
|
||||
private resolveInkPath;
|
||||
private isNamedContainerMap;
|
||||
}
|
||||
|
||||
Vendored
+70
-3
@@ -57,6 +57,8 @@ class InkEngine {
|
||||
this.storyPath = storyPath;
|
||||
this.story = null;
|
||||
this.nextTurnId = 1;
|
||||
this.storyJson = null;
|
||||
this.choicePreviewTagKeys = new Set(['action', 'key', 'letter', 'optional', 'gated', 'sort']);
|
||||
}
|
||||
isRunning() {
|
||||
if (!this.story)
|
||||
@@ -111,8 +113,8 @@ class InkEngine {
|
||||
if (!(0, fs_1.existsSync)(resolvedPath)) {
|
||||
throw new Error(`Ink story file not found: ${resolvedPath}`);
|
||||
}
|
||||
const storyJson = JSON.parse((0, fs_1.readFileSync)(resolvedPath, 'utf8'));
|
||||
return new inkjs_1.Story(storyJson);
|
||||
this.storyJson = JSON.parse((0, fs_1.readFileSync)(resolvedPath, 'utf8'));
|
||||
return new inkjs_1.Story(this.storyJson);
|
||||
}
|
||||
continueStory() {
|
||||
if (!this.story) {
|
||||
@@ -137,7 +139,7 @@ class InkEngine {
|
||||
}
|
||||
}
|
||||
const choices = this.story.currentChoices.map((choice) => {
|
||||
const tags = (0, tag_parser_1.parseTags)(choice.tags || []);
|
||||
const tags = this.getChoiceTags(choice);
|
||||
const category = (0, tag_parser_1.getTagValue)(tags, 'action');
|
||||
const letter = (0, tag_parser_1.getTagValue)(tags, 'letter') || (0, tag_parser_1.getTagValue)(tags, 'key');
|
||||
return {
|
||||
@@ -187,6 +189,71 @@ class InkEngine {
|
||||
gameState: Object.keys(gameState).length > 0 ? gameState : undefined,
|
||||
};
|
||||
}
|
||||
getChoiceTags(choice) {
|
||||
const directTags = (0, tag_parser_1.parseTags)(choice?.tags || []);
|
||||
const previewTags = this.extractChoicePreviewTags(choice);
|
||||
const merged = new Map();
|
||||
[...previewTags, ...directTags].forEach((tag) => {
|
||||
merged.set(`${tag.key}:${tag.value || ''}:${tag.param || ''}`, tag);
|
||||
});
|
||||
return Array.from(merged.values());
|
||||
}
|
||||
extractChoicePreviewTags(choice) {
|
||||
const pathString = String(choice?.pathStringOnChoice || choice?.targetPath?.toString?.() || '').trim();
|
||||
if (!pathString || !this.storyJson)
|
||||
return [];
|
||||
const container = this.resolveInkPath(pathString);
|
||||
if (!Array.isArray(container))
|
||||
return [];
|
||||
const tags = [];
|
||||
for (let index = 0; index < container.length; index += 1) {
|
||||
const token = container[index];
|
||||
if (typeof token === 'string' && token.replace(/^\^/, '').trim() === '')
|
||||
continue;
|
||||
if (token === '\n')
|
||||
continue;
|
||||
if (token !== '#')
|
||||
break;
|
||||
const rawParts = [];
|
||||
index += 1;
|
||||
while (index < container.length && container[index] !== '/#') {
|
||||
const part = container[index];
|
||||
if (typeof part === 'string') {
|
||||
rawParts.push(part.replace(/^\^/, ''));
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
const tag = (0, tag_parser_1.parseTags)([rawParts.join('').trim()])[0];
|
||||
if (tag && this.choicePreviewTagKeys.has(tag.key)) {
|
||||
tags.push(tag);
|
||||
}
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
resolveInkPath(pathString) {
|
||||
const parts = pathString.split('.').filter(Boolean);
|
||||
let node = this.storyJson?.root;
|
||||
for (const part of parts) {
|
||||
if (!node)
|
||||
return null;
|
||||
if (Array.isArray(node) && node.length > 0 && this.isNamedContainerMap(node[node.length - 1]) && part in node[node.length - 1]) {
|
||||
node = node[node.length - 1][part];
|
||||
}
|
||||
else if (Array.isArray(node) && /^\d+$/.test(part)) {
|
||||
node = node[Number(part)];
|
||||
}
|
||||
else if (this.isNamedContainerMap(node) && part in node) {
|
||||
node = node[part];
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
isNamedContainerMap(value) {
|
||||
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
}
|
||||
exports.InkEngine = InkEngine;
|
||||
//# sourceMappingURL=ink-engine.js.map
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user