Checkpoint current UI and ink integration state

This commit is contained in:
2026-05-18 02:46:02 +02:00
parent 2c54498ee2
commit d7bb175167
384 changed files with 922883 additions and 764 deletions
+6
View File
@@ -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;
}
+70 -3
View File
@@ -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
+1 -1
View File
File diff suppressed because one or more lines are too long