boardgame-core/src/samples/slay-the-spire-like/system/combat/triggers.ts

78 lines
3.1 KiB
TypeScript
Raw Normal View History

2026-04-17 08:33:02 +08:00
import {createMiddlewareChain} from "../utils/middleware";
import {CombatGameContext} from "./types";
2026-04-17 09:27:20 +08:00
import {getAliveEnemies} from "@/samples/slay-the-spire-like/system/combat/utils";
import {
onEntityEffectUpkeep,
onPlayerItemEffectUpkeep
} from "@/samples/slay-the-spire-like/system/combat/effects";
import {promptMainAction} from "@/samples/slay-the-spire-like/system/combat/prompts";
2026-04-17 09:27:20 +08:00
type TriggerTypes = {
onCombatStart: {},
2026-04-17 08:33:02 +08:00
onTurnStart: { entityKey: "player" | string, },
onTurnEnd: { entityKey: "player" | string, },
onShuffle: { entityKey: "player" | string, },
onCardPlayed: { cardId: string, },
onCardDiscarded: { cardId: string, },
onCardDrawn: { cardId: string, },
onEffectApplied: { effectId: string, entityKey: "player" | string, stacks: number, },
}
2026-04-17 09:27:20 +08:00
function createTriggers(){
2026-04-17 08:33:02 +08:00
return {
2026-04-17 09:27:20 +08:00
onCombatStart: createTrigger("onCombatStart"),
2026-04-17 08:33:02 +08:00
onTurnStart: createTrigger("onTurnStart"),
onTurnEnd: createTrigger("onTurnEnd"),
onShuffle: createTrigger("onShuffle"),
onCardPlayed: createTrigger("onCardPlayed"),
onCardDiscarded: createTrigger("onCardDiscarded"),
onCardDrawn: createTrigger("onCardDrawn"),
onEffectApplied: createTrigger("onEffectApplied"),
}
}
2026-04-17 09:27:20 +08:00
export type Triggers = ReturnType<typeof createTriggers>
export function createStartWith(build: (triggers: Triggers) => void){
const triggers = createTriggers();
build(triggers);
return async function(game: CombatGameContext){
await triggers.onCombatStart.execute(game,{});
while(true){
await triggers.onTurnStart.execute(game,{entityKey: "player"});
await game.produceAsync(draft => {
onEntityEffectUpkeep(draft.player);
onPlayerItemEffectUpkeep(draft.player);
});
while(true){
const action = await promptMainAction(game);
if(action.action === "end-turn") break;
//TODO resolve action here
}
// TODO discard cards here
await triggers.onTurnEnd.execute(game,{entityKey: "player"});
// TODO recover energy, draw new cards here
for(const enemy of getAliveEnemies(game.value)){
await triggers.onTurnStart.execute(game,{entityKey: enemy.id});
}
await game.produceAsync(draft => {
for(const enemy of getAliveEnemies(game.value)){
onEntityEffectUpkeep(enemy);
}
});
// TODO execute enemy intent, then update with new one here
for(const enemy of getAliveEnemies(game.value)){
await triggers.onTurnEnd.execute(game,{entityKey: enemy.id});
}
}
}
}
2026-04-17 09:27:20 +08:00
function createTrigger<TKey extends keyof TriggerTypes>(event: TKey) {
type Ctx = TriggerTypes[TKey] & { event: TKey, game: CombatGameContext };
const {use, execute} = createMiddlewareChain<Ctx>();
return {
use,
execute: (game: CombatGameContext, ctx: TriggerTypes[TKey]) => execute({...ctx, event, game}),
}
2026-04-17 08:33:02 +08:00
}