From f4c96a4a7292190ce24a086fef6873f3cc8a71e1 Mon Sep 17 00:00:00 2001 From: hypercross Date: Wed, 22 Apr 2026 20:13:31 +0800 Subject: [PATCH] refactor: update turn start triggers in desert sample Fixes logic in `defendNext` to ensure effects are applied after buff updates by calling `next()` before mutation. Also updates indentation and formatting to match project style guidelines. --- .../data/desert/triggers/turn-start.ts | 142 +++++++++--------- .../combat/triggers.test.ts | 8 +- 2 files changed, 74 insertions(+), 76 deletions(-) diff --git a/src/samples/slay-the-spire-like/data/desert/triggers/turn-start.ts b/src/samples/slay-the-spire-like/data/desert/triggers/turn-start.ts index 02db139..7c4cea5 100644 --- a/src/samples/slay-the-spire-like/data/desert/triggers/turn-start.ts +++ b/src/samples/slay-the-spire-like/data/desert/triggers/turn-start.ts @@ -4,85 +4,89 @@ import { EffectData } from "@/samples/slay-the-spire-like/system/types"; import getEffects from "../effect.csv"; export function addTurnStartTriggers(triggers: Triggers) { - const effects = getEffects(); + const effects = getEffects(); - function findEffect(id: string): EffectData { - const found = effects.find(e => e.id === id); - if (found) return found; - return { id, name: id, description: "", lifecycle: "instant" } as EffectData; + function findEffect(id: string): EffectData { + const found = effects.find((e) => e.id === id); + if (found) return found; + return { + id, + name: id, + description: "", + lifecycle: "instant", + } as EffectData; + } + + // discard: random discard at turn start + triggers.onTurnStart.use(async (ctx, next) => { + if (ctx.entityKey !== "player") { + await next(); + return; } - // discard: random discard at turn start - triggers.onTurnStart.use(async (ctx, next) => { - if (ctx.entityKey !== "player") { - await next(); - return; - } + const discard = ctx.game.value.player.effects.discard; + if (discard && discard.stacks > 0) { + const handIds = [...ctx.game.value.player.deck.regions.hand.childIds]; + if (handIds.length > 0) { + const randomIndex = ctx.game.rng.nextInt(handIds.length); + const randomCardId = handIds[randomIndex]; + await triggers.onCardDiscarded.execute(ctx.game, { + cardId: randomCardId, + }); + } + } - const discard = ctx.game.value.player.effects.discard; - if (discard && discard.stacks > 0) { - const handIds = [...ctx.game.value.player.deck.regions.hand.childIds]; - if (handIds.length > 0) { - const randomIndex = ctx.game.rng.nextInt(handIds.length); - const randomCardId = handIds[randomIndex]; - await triggers.onCardDiscarded.execute(ctx.game, { cardId: randomCardId }); - } - } + await next(); + }); - await next(); + // defendNext: gain block next turn + // record how many defendNext there is, before buff update + // then apply after buff update + triggers.onTurnStart.use(async (ctx, next) => { + const defendNext = ctx.game.value.player.effects.defendNext; + if (!defendNext || defendNext.stacks <= 0) { + await next(); + return; + } + await next(); + await ctx.game.produceAsync((draft) => { + addEntityEffect(draft.player, findEffect("defend"), defendNext.stacks); }); + }); - // defendNext: gain block next turn - triggers.onTurnStart.use(async (ctx, next) => { - if (ctx.entityKey !== "player") { - await next(); - return; - } + // energyNext: gain energy next turn + triggers.onTurnStart.use(async (ctx, next) => { + if (ctx.entityKey !== "player") { + await next(); + return; + } - const defendNext = ctx.game.value.player.effects.defendNext; - if (defendNext && defendNext.stacks > 0) { - await ctx.game.produceAsync(draft => { - addEntityEffect(draft.player, findEffect("defend"), defendNext.stacks); - addEntityEffect(draft.player, defendNext.data, -defendNext.stacks); - }); - } + const energyNext = ctx.game.value.player.effects.energyNext; + if (energyNext && energyNext.stacks > 0) { + await ctx.game.produceAsync((draft) => { + draft.player.energy += energyNext.stacks; + addEntityEffect(draft.player, energyNext.data, -energyNext.stacks); + }); + } - await next(); - }); + await next(); + }); - // energyNext: gain energy next turn - triggers.onTurnStart.use(async (ctx, next) => { - if (ctx.entityKey !== "player") { - await next(); - return; - } + // drawNext: draw extra cards next turn + triggers.onTurnStart.use(async (ctx, next) => { + if (ctx.entityKey !== "player") { + await next(); + return; + } - const energyNext = ctx.game.value.player.effects.energyNext; - if (energyNext && energyNext.stacks > 0) { - await ctx.game.produceAsync(draft => { - draft.player.energy += energyNext.stacks; - addEntityEffect(draft.player, energyNext.data, -energyNext.stacks); - }); - } + const drawNext = ctx.game.value.player.effects.drawNext; + if (drawNext && drawNext.stacks > 0) { + await ctx.game.produceAsync((draft) => { + addEntityEffect(draft.player, drawNext.data, -drawNext.stacks); + }); + await triggers.onDraw.execute(ctx.game, { count: drawNext.stacks }); + } - await next(); - }); - - // drawNext: draw extra cards next turn - triggers.onTurnStart.use(async (ctx, next) => { - if (ctx.entityKey !== "player") { - await next(); - return; - } - - const drawNext = ctx.game.value.player.effects.drawNext; - if (drawNext && drawNext.stacks > 0) { - await ctx.game.produceAsync(draft => { - addEntityEffect(draft.player, drawNext.data, -drawNext.stacks); - }); - await triggers.onDraw.execute(ctx.game, { count: drawNext.stacks }); - } - - await next(); - }); + await next(); + }); } diff --git a/tests/samples/slay-the-spire-like/combat/triggers.test.ts b/tests/samples/slay-the-spire-like/combat/triggers.test.ts index c3375f2..124038c 100644 --- a/tests/samples/slay-the-spire-like/combat/triggers.test.ts +++ b/tests/samples/slay-the-spire-like/combat/triggers.test.ts @@ -26,20 +26,14 @@ import { InventoryItem, } from "@/samples/slay-the-spire-like/system/grid-inventory/types"; import { GameItemMeta } from "@/samples/slay-the-spire-like/system/grid-inventory/types"; -import { ParsedShape } from "@/samples/slay-the-spire-like/system/utils/parse-shape"; -import { Transform2D } from "@/samples/slay-the-spire-like/system/utils/shape-collision"; import { CardEffect, getCards, getEffects, - getEncounters, getEnemies, - getItems, } from "@/samples/slay-the-spire-like/data/desert"; const cards = getCards(); const effects = getEffects(); -const encounters = getEncounters(); -const items = getItems(); const enemies = getEnemies(); function createEffect( @@ -298,7 +292,7 @@ describe("desert triggers", () => { }); expect(ctx.value.player.hp).toBe(27); - expect(ctx.value.player.effects.defend?.stacks).toBe(2); + expect(ctx.value.player.effects.defend?.stacks).toBe(undefined); }); it("should reduce damage with damageReduce", async () => {