/* * 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 { CommandParams, InkEngine, VisualInkCommand, VisualInkState } from '../types' /** * Commands are run when called in the story. Returns true if the command * should interrupt story flow, false otherwise. */ export type Command = (engine: InkEngine, params: CommandParams) => CommandReturn | undefined export type CommandReturn = { interruptStoryFlow?: boolean } export type ExtendedCommandReturn = CommandReturn & { mutatedVisualState?: VisualInkState } export class CommandHandler { protected commandMap: Record<string, Command> constructor() { this.commandMap = {} } public addCommand(commandName: string, command: Command) { this.commandMap[commandName] = command } /** * Accepts a command, and acts upon it for the current story. * @param command The command to run * @returns {boolean} Returns true if the command should interrupt story flow, false otherwise. */ public processCommand( command: VisualInkCommand, currentState?: VisualInkState, engine?: InkEngine, ): ExtendedCommandReturn | undefined { const commandName = command.command.trim() if (!this.commandMap[commandName]) { return } // TODO: Ugh...this breaks so many conventions with immutable stuff, but it works // because we will be setting visualState to currentState regardless if we didn't mutate the visual state... // and this allows delays to still affect the engine. engine.visualState = currentState const returns: ExtendedCommandReturn = this.commandMap[commandName](engine, command.params) ?? {} if (engine.visualState !== currentState) { returns.mutatedVisualState = engine.visualState } return returns } }