Compare commits

..

No commits in common. "23ac09ff21f296ccb6ec7d903256ea3155ff70ee" and "bbab3cc43b0b3ab73f23843c82b68c5e560700b9" have entirely different histories.

5 changed files with 45 additions and 60 deletions

View File

@ -12,7 +12,6 @@ export type GameHostStatus = "created" | "running" | "disposed";
export class GameHost< export class GameHost<
TState extends Record<string, unknown>, TState extends Record<string, unknown>,
TResult = unknown, TResult = unknown,
TModule extends GameModule<TState, TResult> = GameModule<TState, TResult>,
> { > {
readonly state: ReadonlySignal<TState>; readonly state: ReadonlySignal<TState>;
readonly status: ReadonlySignal<GameHostStatus>; readonly status: ReadonlySignal<GameHostStatus>;
@ -30,16 +29,16 @@ export class GameHost<
private _eventListeners: Map<"start" | "dispose", Set<() => void>>; private _eventListeners: Map<"start" | "dispose", Set<() => void>>;
private _isDisposed = false; private _isDisposed = false;
constructor(public readonly gameModule: TModule) { constructor(
const { createInitialState, registry, start } = gameModule; registry: CommandRegistry<IGameContext<TState>>,
createInitialState: () => TState,
start: (ctx: IGameContext<TState>) => Promise<TResult>,
) {
this._createInitialState = createInitialState; this._createInitialState = createInitialState;
this._eventListeners = new Map(); this._eventListeners = new Map();
const initialState = createInitialState(); const initialState = createInitialState();
this._context = createGameContext( this._context = createGameContext(registry, initialState);
registry ?? createGameCommandRegistry(),
initialState,
);
this._start = start; this._start = start;
this.state = this._context._state; this.state = this._context._state;
@ -180,7 +179,10 @@ export type GameModule<
export function createGameHost< export function createGameHost<
TState extends Record<string, unknown>, TState extends Record<string, unknown>,
TResult = unknown, TResult = unknown,
TModule extends GameModule<TState, TResult> = GameModule<TState, TResult>, >(gameModule: GameModule<TState, TResult>): GameHost<TState, TResult> {
>(gameModule: TModule): GameHost<TState, TResult> { return new GameHost(
return new GameHost(gameModule); gameModule.registry || createGameCommandRegistry(),
gameModule.createInitialState,
gameModule.start,
);
} }

View File

@ -71,6 +71,4 @@ export { createRNG, Mulberry32RNG } from "./utils/rng";
export type { MiddlewareChain } from "./utils/middleware"; export type { MiddlewareChain } from "./utils/middleware";
export { createMiddlewareChain } from "./utils/middleware"; export { createMiddlewareChain } from "./utils/middleware";
export * from "./utils/spawner";
export * from "@preact/signals-core"; export * from "@preact/signals-core";

View File

@ -5,14 +5,14 @@ import type * as desert from "./desert";
import { IRunContext } from "../system/combat"; import { IRunContext } from "../system/combat";
export type ContentModule = { export type ContentModule = {
readonly getCards: () => readonly desert.Card[]; getCards: () => desert.Card[];
readonly getEffects: () => readonly desert.Effect[]; getEffects: () => desert.Effect[];
readonly getEncounters: () => readonly desert.Encounter[]; getEncounters: () => desert.Encounter[];
readonly getEnemies: () => readonly desert.Enemy[]; getEnemies: () => desert.Enemy[];
readonly getIntents: () => readonly desert.Intent[]; getIntents: () => desert.Intent[];
readonly getItems: () => readonly desert.Item[]; getItems: () => desert.Item[];
readonly getStartingItems: () => readonly desert.Item[]; getStartingItems: () => desert.Item[];
readonly dialogues: YarnDialogues; dialogues: YarnDialogues;
readonly addTriggers: (triggers: Triggers, run: IRunContext) => void; addTriggers: (triggers: Triggers, run: IRunContext) => void;
}; };

View File

@ -3,3 +3,27 @@ export * from "./factory";
export * from "./prompts"; export * from "./prompts";
export * from "./triggers"; export * from "./triggers";
export * from "./types"; export * from "./types";
import { GameHost } from "@/core/game-host";
import { ContentModule } from "../types";
import { createCommandRegistry } from "@/utils/command";
import { createStart, createTriggers, Triggers } from "./triggers";
import { CombatState, IRunContext } from "./types";
export class CombatGameHost extends GameHost<CombatState> {
public readonly triggers: Triggers;
constructor(
private module: ContentModule,
private runContext: IRunContext,
private initialState: CombatState,
) {
let triggers: Triggers;
super(
createCommandRegistry(),
() => initialState,
createStart((triggers = createTriggers(runContext)), runContext),
);
module.addTriggers(triggers, runContext);
this.triggers = triggers;
}
}

View File

@ -1,39 +0,0 @@
import { effect } from "@preact/signals-core";
export type SpawnerFunction = (id: string) => () => void;
export function createSpawner(spawner: SpawnerFunction) {
const entries = new Map<string, () => void>();
function update(set: Set<string>) {
for (const key of set) {
if (!entries.has(key)) {
entries.set(key, spawner(key));
}
}
for (const [key, entry] of entries) {
if (!set.has(key)) {
entry();
entries.delete(key);
}
}
}
return update;
}
export function spawnerEffect(
iterable: () => Iterable<string>,
spawner: SpawnerFunction,
) {
const update = createSpawner(spawner);
return effect(() => {
const set = new Set<string>();
for (const each of iterable()) {
set.add(each);
}
update(set);
});
}