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-16 14:00:49 +08:00
|
|
|
|
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-16 14:00:49 +08:00
|
|
|
}
|
|
|
|
|
|
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-16 14:00:49 +08:00
|
|
|
}
|
|
|
|
|
}
|
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-16 21:52:28 +08:00
|
|
|
|
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
|
|
|
}
|