From 1d749f59a66d8fcb7f965df9c06e04002e44bb92 Mon Sep 17 00:00:00 2001 From: hypercross Date: Fri, 17 Apr 2026 11:57:07 +0800 Subject: [PATCH] feat: add posture damage & item effect update trigger --- .../system/combat/effects.ts | 28 +++++++++++++++++++ .../system/combat/triggers.ts | 24 ++++++++++------ 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/samples/slay-the-spire-like/system/combat/effects.ts b/src/samples/slay-the-spire-like/system/combat/effects.ts index 4ab3315..7d46d1d 100644 --- a/src/samples/slay-the-spire-like/system/combat/effects.ts +++ b/src/samples/slay-the-spire-like/system/combat/effects.ts @@ -34,6 +34,14 @@ export function onEntityEffectUpkeep(entity: CombatEntity){ } } +export function onEntityPostureDamage(entity: CombatEntity, damage: number){ + for(const effect of Object.values(entity.effects)){ + const lifecycle = effect.data.lifecycle; + if(lifecycle === 'posture') + addEntityEffect(entity, effect.data, -Math.min(damage, effect.stacks)); + } +} + export function onPlayerItemEffectUpkeep(entity: PlayerEntity){ for(const [itemKey, itemEffects] of Object.entries(entity.itemEffects)){ for(const effect of Object.values(itemEffects)){ @@ -44,6 +52,26 @@ export function onPlayerItemEffectUpkeep(entity: PlayerEntity){ } } +export function onItemPlay(entity: PlayerEntity, itemKey: string){ + const effects = entity.itemEffects[itemKey]; + if(!effects)return; + for(const effect of Object.values(effects)){ + if(effect.data.lifecycle === 'itemUntilPlay'){ + addItemEffect(entity, itemKey, effect.data, -effect.stacks); + } + } +} + +export function onItemDiscard(entity: PlayerEntity, itemKey: string){ + const effects = entity.itemEffects[itemKey]; + if(!effects)return; + for(const effect of Object.values(effects)){ + if(effect.data.lifecycle === 'itemUntilDiscard'){ + addItemEffect(entity, itemKey, effect.data, -effect.stacks); + } + } +} + export function* getAliveEnemies(state: CombatState) { for (let enemy of state.enemies) { if (enemy.isAlive) { diff --git a/src/samples/slay-the-spire-like/system/combat/triggers.ts b/src/samples/slay-the-spire-like/system/combat/triggers.ts index 3d21730..b24900e 100644 --- a/src/samples/slay-the-spire-like/system/combat/triggers.ts +++ b/src/samples/slay-the-spire-like/system/combat/triggers.ts @@ -2,9 +2,9 @@ import {CombatGameContext} from "./types"; import { addEntityEffect, addItemEffect, - getAliveEnemies, + getAliveEnemies, onEntityPostureDamage, onEntityEffectUpkeep, - onPlayerItemEffectUpkeep + onPlayerItemEffectUpkeep, onItemDiscard, onItemPlay } from "@/samples/slay-the-spire-like/system/combat/effects"; import {promptMainAction} from "@/samples/slay-the-spire-like/system/combat/prompts"; import {moveToRegion, shuffle} from "@/core/region"; @@ -24,6 +24,7 @@ type TriggerTypes = { onDraw: {count: number}, onEffectApplied: { effect: EffectData, entityKey: "player" | string, stacks: number, cardId?: string }, onHpChange: { entityKey: "player" | string, amount: number}, + onDamage: { entityKey: "player" | string, amount: number, dealt?: number, prevented?: number}, } function createTriggers(){ @@ -58,12 +59,14 @@ function createTriggers(){ await ctx.game.produceAsync(draft => { const {cards, regions} = draft.player.deck; moveToRegion(cards[ctx.cardId], regions.hand, regions.discardPile); + onItemPlay(draft.player, cards[ctx.cardId].itemId); }); }), onCardDiscarded: createTrigger("onCardDiscarded", async ctx => { await ctx.game.produceAsync(draft => { const {cards, regions} = draft.player.deck; moveToRegion(cards[ctx.cardId], regions.hand, regions.discardPile); + onItemDiscard(draft.player, cards[ctx.cardId].itemId); }); }), onCardDrawn: createTrigger("onCardDrawn", async ctx => { @@ -103,13 +106,6 @@ function createTriggers(){ return; } - if(ctx.effect.lifecycle.startsWith('card')){ - await ctx.game.produceAsync(draft => { - // TODO - }); - return; - } - await ctx.game.produceAsync(draft => { const entity = ctx.entityKey === "player" ? draft.player : draft.enemies.find(e => e.id === ctx.entityKey); if(entity) addEntityEffect(entity, ctx.effect, ctx.stacks); @@ -125,6 +121,16 @@ function createTriggers(){ }); if(ctx.game.value.result) throw ctx.game.value; }), + onDamage: createTrigger("onDamage", async ctx => { + const entity = ctx.entityKey === "player" ? ctx.game.value.player : ctx.game.value.enemies.find(e => e.id === ctx.entityKey); + if(!entity || !entity.isAlive) return; + const dealt = ctx.dealt = Math.min(Math.max(0,entity.hp), ctx.amount); + ctx.prevented = ctx.amount - ctx.dealt; + await ctx.game.produceAsync(draft => { + onEntityPostureDamage(entity, dealt); + }); + await triggers.onHpChange.execute(ctx.game,{entityKey: ctx.entityKey, amount: -ctx.amount}); + }), } return triggers; }