/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { InkProcessorEngine } from '@a-morphous/frontispiece-ink-processor' import { VisualInkChoice, VisualInkLineOrCommand, } from '@a-morphous/frontispiece-ink-processor/src/types' import { Story } from 'inkjs/engine/Story' import inquirer, { DistinctChoice } from 'inquirer' type LineParser = (inkLine: VisualInkLineOrCommand) => string type ChoiceParser = (inkChoice: VisualInkChoice) => string type ChoiceEngine = (choices: VisualInkChoice[], engine: InkProcessorEngine) => Promise<number> type ScriptOptions = { customEngine?: InkProcessorEngine // can override the story lineParser: LineParser choiceParser: ChoiceParser choiceEngine: ChoiceEngine // set this to do something different than the default `engine.makeChoice`. Useful mostly for storylets. overrideMakeChoice?: ( engine: InkProcessorEngine, choices: VisualInkChoice[], choiceResult: number ) => void verbose: boolean } export const defaultLineParser: LineParser = (inkLine: VisualInkLineOrCommand): string => { if (inkLine.type === 'command') { return '' } return inkLine.text + '\n' } export const defaultChoiceParser: ChoiceParser = (inkChoice: VisualInkChoice): string => { return '> ' + inkChoice.text + '\n\n' } export const defaultChoiceEngine: ChoiceEngine = async (choices: VisualInkChoice[], engine) => { const choiceResult = await inquirer.prompt([ { name: 'choice', type: 'list', message: engine.activeLine.type === 'line' ? engine.activeLine.text : '', choices: () => { const cArray: DistinctChoice[] = [] for (let choice of choices) { cArray.push({ key: (choice.index + 1).toString(), name: choice.text, value: choice.index, }) } return cArray }, }, ]) return choiceResult.choice } const defaultOptions: ScriptOptions = { lineParser: defaultLineParser, choiceParser: defaultChoiceParser, choiceEngine: defaultChoiceEngine, verbose: false, } export const createScript = async ( story: Story, options: Partial<ScriptOptions> = {} ): Promise<string> => { let finalString = '' let mergedOptions = { ...defaultOptions, ...options } const engine = mergedOptions.customEngine ?? new InkProcessorEngine(story) while (engine.canAdvance || engine.choices.length > 0) { if (engine.canAdvance) { engine.advance() if (mergedOptions.verbose) { console.log(mergedOptions.lineParser(engine.getActiveLine())) } finalString += mergedOptions.lineParser(engine.getActiveLine()) } else { const choiceResult = await mergedOptions.choiceEngine(engine.choices, engine) finalString += mergedOptions.choiceParser(engine.choices[choiceResult]) if (mergedOptions.overrideMakeChoice) { mergedOptions.overrideMakeChoice(engine, engine.choices, choiceResult) } else { engine.makeChoice(choiceResult) engine.advance() } } } return finalString }