diff --git a/src/core/game.ts b/src/core/game.ts index 677d211..50c396e 100644 --- a/src/core/game.ts +++ b/src/core/game.ts @@ -1,80 +1,104 @@ -import {MutableSignal, mutableSignal} from "@/utils/mutable-signal"; +import { MutableSignal, mutableSignal } from "@/utils/mutable-signal"; import { - Command, - CommandRegistry, CommandResult, - CommandRunnerContextExport, - CommandSchema, - createCommandRegistry, - createCommandRunnerContext, parseCommandSchema, + Command, + CommandRegistry, + CommandResult, + CommandRunnerContextExport, + CommandSchema, + createCommandRegistry, + createCommandRunnerContext, + parseCommandSchema, } from "@/utils/command"; -import {PromptValidator} from "@/utils/command/command-runner"; -import {Mulberry32RNG, ReadonlyRNG, RNG} from "@/utils/rng"; +import { PromptValidator } from "@/utils/command/command-runner"; +import { Mulberry32RNG, ReadonlyRNG, RNG } from "@/utils/rng"; -export interface IGameContext = {} > { - get value(): TState; - get rng(): ReadonlyRNG; - produce(fn: (draft: TState) => void): void; - produceAsync(fn: (draft: TState) => void): Promise; - run(input: string): Promise>; - runParsed(command: Command): Promise>; - prompt: (def: PromptDef, validator: PromptValidator, currentPlayer?: string | null) => Promise; - - // test only - _state: MutableSignal; - _commands: CommandRunnerContextExport>; - _rng: RNG; +export interface IGameContext = {}> { + get value(): TState; + get rng(): ReadonlyRNG; + produce(fn: (draft: TState) => void): void; + produceAsync(fn: (draft: TState) => void): Promise; + run(input: string): Promise>; + runParsed(command: Command): Promise>; + prompt: ( + def: PromptDef, + validator: PromptValidator, + currentPlayer?: string | null, + ) => Promise; + + // test only + _state: MutableSignal; + _commands: CommandRunnerContextExport>; + _rng: RNG; } +export type IGameContextExport = {}> = + Omit, "_state" | "_commands" | "_rng">; -export function createGameContext = {} >( - commandRegistry: CommandRegistry>, - initialState?: TState | (() => TState) +export function createGameContext = {}>( + commandRegistry: CommandRegistry>, + initialState?: TState | (() => TState), ): IGameContext { - const stateValue = typeof initialState === 'function' ? initialState() : initialState ?? {} as TState; - const state = mutableSignal(stateValue); - let commands: CommandRunnerContextExport> = null as any; + const stateValue = + typeof initialState === "function" + ? initialState() + : (initialState ?? ({} as TState)); + const state = mutableSignal(stateValue); + let commands: CommandRunnerContextExport> = null as any; - const context: IGameContext = { - get value(): TState { - return state.value; - }, - get rng() { - return this._rng; - }, - produce(fn) { - return state.produce(fn); - }, - produceAsync(fn) { - return state.produceAsync(fn); - }, - run(input: string) { - return commands.run(input); - }, - runParsed(command: Command) { - return commands.runParsed(command); - }, - prompt(def, validator, currentPlayer) { - return commands.prompt(def.schema, validator, def.hintText, currentPlayer); - }, - - _state: state, - _commands: commands, - _rng: new Mulberry32RNG(), - }; + const context: IGameContext = { + get value(): TState { + return state.value; + }, + get rng() { + return this._rng; + }, + produce(fn) { + return state.produce(fn); + }, + produceAsync(fn) { + return state.produceAsync(fn); + }, + run(input: string) { + return commands.run(input); + }, + runParsed(command: Command) { + return commands.runParsed(command); + }, + prompt(def, validator, currentPlayer) { + return commands.prompt( + def.schema, + validator, + def.hintText, + currentPlayer, + ); + }, - context._commands = commands = createCommandRunnerContext(commandRegistry, context); - - return context; + _state: state, + _commands: commands, + _rng: new Mulberry32RNG(), + }; + + context._commands = commands = createCommandRunnerContext( + commandRegistry, + context, + ); + + return context; } -export type PromptDef = { - schema: CommandSchema, - hintText?: string, -} -export function createPromptDef(schema: CommandSchema | string, hintText?: string): PromptDef { - schema = typeof schema === 'string' ? parseCommandSchema(schema) : schema; - return { schema, hintText }; +export type PromptDef = { + schema: CommandSchema; + hintText?: string; +}; +export function createPromptDef( + schema: CommandSchema | string, + hintText?: string, +): PromptDef { + schema = typeof schema === "string" ? parseCommandSchema(schema) : schema; + return { schema, hintText }; } -export function createGameCommandRegistry = {} >() { - return createCommandRegistry>(); -} \ No newline at end of file +export function createGameCommandRegistry< + TState extends Record = {}, +>() { + return createCommandRegistry>(); +} diff --git a/src/samples/slay-the-spire-like/system/combat/types.ts b/src/samples/slay-the-spire-like/system/combat/types.ts index 25f1ef8..66a273f 100644 --- a/src/samples/slay-the-spire-like/system/combat/types.ts +++ b/src/samples/slay-the-spire-like/system/combat/types.ts @@ -1,53 +1,59 @@ import type { PlayerDeck } from "../deck/types"; -import {EnemyData, IntentData} from "@/samples/slay-the-spire-like/system/types"; -import {EffectData} from "@/samples/slay-the-spire-like/system/types"; -import {GridInventory} from "@/samples/slay-the-spire-like/system/grid-inventory"; -import {GameItemMeta} from "@/samples/slay-the-spire-like/system/progress"; +import { + EnemyData, + IntentData, +} from "@/samples/slay-the-spire-like/system/types"; +import { EffectData } from "@/samples/slay-the-spire-like/system/types"; +import { GridInventory } from "@/samples/slay-the-spire-like/system/grid-inventory"; +import { GameItemMeta } from "@/samples/slay-the-spire-like/system/progress"; -export type EffectTable = Record; +export type EffectTable = Record; export type CombatEntity = { - id: string; // player is just "player" - effects: EffectTable; - hp: number; - maxHp: number; - isAlive: boolean; + id: string; // player is just "player" + effects: EffectTable; + hp: number; + maxHp: number; + isAlive: boolean; }; export type PlayerEntity = CombatEntity & { - energy: number; - maxEnergy: number; - deck: PlayerDeck; - itemEffects: Record; -} + energy: number; + maxEnergy: number; + deck: PlayerDeck; + itemEffects: Record; +}; export type EnemyEntity = CombatEntity & { - enemy: EnemyData; - intents: Record; - currentIntent: IntentData; + enemy: EnemyData; + intents: Record; + currentIntent: IntentData; }; export type CombatPhase = "playerTurn" | "enemyTurn" | "combatEnd"; export type CombatResult = "victory" | "defeat"; -export type LootEntry = { - type: "gold"; - amount: number; -} | { - type: "item", - itemId: string; -}; +export type LootEntry = + | { + type: "gold"; + amount: number; + } + | { + type: "item"; + itemId: string; + }; export type CombatState = { - enemies: EnemyEntity[]; - player: PlayerEntity; - inventory: GridInventory; + enemies: EnemyEntity[]; + player: PlayerEntity; + inventory: GridInventory; - phase: CombatPhase; - turnNumber: number; - result: CombatResult | null; + phase: CombatPhase; + turnNumber: number; + result: CombatResult | null; - loot: LootEntry[]; + loot: LootEntry[]; }; -export type CombatGameContext = import("@/core/game").IGameContext; +export type CombatGameContext = + import("@/core/game").IGameContextExport;