Compare commits
No commits in common. "23ac09ff21f296ccb6ec7d903256ea3155ff70ee" and "bbab3cc43b0b3ab73f23843c82b68c5e560700b9" have entirely different histories.
23ac09ff21
...
bbab3cc43b
|
|
@ -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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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";
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue