Merge branch 'm8/mafia' into codex/owner/grp_discord_joke-app

# Conflicts:
#	apps/server/src/rooms/room.ts
#	apps/web/src/games/registry.ts
#	apps/web/src/lib/catalog-ui.ts
#	e2e/games.e2e.ts
#	packages/engine/src/types.ts
#	packages/games/src/index.ts
#	packages/shared/src/catalog.ts
This commit is contained in:
EJClaw
2026-10-06 00:39:35 +09:00
16 changed files with 3238 additions and 14 deletions

View File

@@ -31,6 +31,11 @@ export interface SetupContext<O> {
gameNo?: number;
}
/** Optional server context for `validate` (time-based checks such as chat rate limits). Absent in pure tests. */
export interface ValidateContext {
now: number;
}
export interface ApplyContext {
rng: Rng;
now: number;
@@ -47,11 +52,13 @@ export interface GameDefinition<S, A, V, O> {
optionsSchema: ZodType<O>;
actionSchema: ZodType<A>;
playersFor?(options: O): { min: number; max: number };
/** The game runs its own (filtered) chat channels: the room chat and quick reactions are closed while it is played. */
ownChat?: boolean;
/** Extra player-count rule `playersFor` cannot express (e.g. even counts only); Korean reason or null. */
playerCountError?(options: O, count: number): string | null;
setup(ctx: SetupContext<O>): S;
/** `ctx.now` is passed by the server (real-time games may rate-limit with it); tests may omit it. */
validate(state: S, actor: PlayerId, action: A, ctx?: { now: number }): Validation;
validate(state: S, actor: PlayerId, action: A, ctx?: ValidateContext): Validation;
apply(state: S, actor: PlayerId, action: A, ctx: ApplyContext): { state: S; events: GameEvent[] };
view(state: S, viewer: PlayerId | null): V;
/**