Document markup and improve choice tags
This commit is contained in:
@@ -9,6 +9,7 @@ export interface GameMetadata {
|
||||
subtitle?: string;
|
||||
version?: string;
|
||||
copyright?: string;
|
||||
language?: string;
|
||||
}
|
||||
|
||||
export interface GamePaths {
|
||||
@@ -52,6 +53,7 @@ function fallbackConfig(engine: EngineName): GameEngineConfig {
|
||||
subtitle: 'An open-world text adventure',
|
||||
version: '1.0.0',
|
||||
copyright: '',
|
||||
language: 'en_US',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -81,6 +83,7 @@ export function loadGameConfig(configPath: string, engine: EngineName): GameEngi
|
||||
metadata: {
|
||||
...fallback.metadata,
|
||||
...(parsed.metadata ?? {}),
|
||||
language: parsed.metadata?.language ?? parsed.locale ?? fallback.metadata.language,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -150,11 +150,13 @@ export class InkEngine {
|
||||
|
||||
const paragraphs: TurnResult['paragraphs'] = [];
|
||||
const globalTags: StoryTag[] = [];
|
||||
const turnTags: StoryTag[] = [];
|
||||
|
||||
while (this.story.canContinue) {
|
||||
const rawText = this.story.Continue();
|
||||
const text = String(rawText || '').trim();
|
||||
const tags = parseTags(this.story.currentTags || []);
|
||||
turnTags.push(...tags);
|
||||
|
||||
tags
|
||||
.filter((tag) => tag.key === 'title' || tag.key === 'author')
|
||||
@@ -170,7 +172,7 @@ export class InkEngine {
|
||||
const choices = this.story.currentChoices.map((choice): ChoiceResult => {
|
||||
const tags = parseTags(choice.tags || []);
|
||||
const category = getTagValue(tags, 'action');
|
||||
const letter = getTagValue(tags, 'letter');
|
||||
const letter = getTagValue(tags, 'letter') || getTagValue(tags, 'key');
|
||||
return {
|
||||
index: choice.index,
|
||||
text: String(choice.text || '').trim(),
|
||||
@@ -179,13 +181,46 @@ export class InkEngine {
|
||||
letter,
|
||||
};
|
||||
});
|
||||
const inputMode = choices.length > 0 ? 'choice' : 'end';
|
||||
const gameState: TurnResult['gameState'] = {};
|
||||
|
||||
if (inputMode === 'end') {
|
||||
const errorTag = turnTags.find((tag) => tag.key === 'error');
|
||||
const scoreTag = turnTags.find((tag) => tag.key === 'score');
|
||||
|
||||
if (!errorTag && !scoreTag) {
|
||||
const message = 'Ink story ended without an explicit #score ending tag.';
|
||||
const generatedErrorTag: StoryTag = { key: 'error', value: message };
|
||||
globalTags.push(generatedErrorTag);
|
||||
turnTags.push(generatedErrorTag);
|
||||
}
|
||||
|
||||
const finalErrorTag = turnTags.find((tag) => tag.key === 'error');
|
||||
const finalScoreTag = turnTags.find((tag) => tag.key === 'score');
|
||||
if (finalErrorTag) {
|
||||
gameState.endState = {
|
||||
type: 'error',
|
||||
message: finalErrorTag.value || finalErrorTag.param,
|
||||
};
|
||||
} else if (finalScoreTag) {
|
||||
const numericScore = Number(finalScoreTag?.value);
|
||||
if (Number.isFinite(numericScore)) {
|
||||
gameState.score = numericScore;
|
||||
}
|
||||
gameState.endState = {
|
||||
type: 'intended',
|
||||
message: finalScoreTag.value || finalScoreTag.param,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
turnId: this.nextTurnId++,
|
||||
paragraphs,
|
||||
choices,
|
||||
inputMode: choices.length > 0 ? 'choice' : 'end',
|
||||
inputMode,
|
||||
globalTags: globalTags.length > 0 ? globalTags : undefined,
|
||||
gameState: Object.keys(gameState).length > 0 ? gameState : undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ export interface TurnResult {
|
||||
score?: number;
|
||||
moves?: number;
|
||||
statusLine?: string;
|
||||
endState?: {
|
||||
type: 'intended' | 'error';
|
||||
message?: string;
|
||||
};
|
||||
};
|
||||
suggestions?: string[];
|
||||
}
|
||||
|
||||
@@ -23,6 +23,14 @@ export function parseTag(raw: string): StoryTag | null {
|
||||
return tag;
|
||||
}
|
||||
|
||||
const colonMatch = text.match(/^([A-Za-z][\w-]*)\s*:\s*(.*?)\s*(?:\(([^)]*)\))?$/);
|
||||
if (colonMatch) {
|
||||
const tag: StoryTag = { key: normalizeKey(colonMatch[1]) };
|
||||
tag.value = colonMatch[2].trim();
|
||||
if (typeof colonMatch[3] !== 'undefined') tag.param = colonMatch[3].trim();
|
||||
return tag;
|
||||
}
|
||||
|
||||
const bareMatch = text.match(/^[A-Za-z][\w-]*$/);
|
||||
if (bareMatch) {
|
||||
return { key: normalizeKey(text) };
|
||||
|
||||
Reference in New Issue
Block a user