From 16fac5e6caf74cdba1e9f163acd8749fbc5e9042 Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Mon, 7 Sep 2026 15:55:00 -0500 Subject: [PATCH] A test walks a wizard into a slime with a spell waiting in it Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG --- .../engine/test/expansion-terrain.test.ts | 33 ++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/engine/test/expansion-terrain.test.ts b/packages/engine/test/expansion-terrain.test.ts index 9c0ef9d..e991606 100644 --- a/packages/engine/test/expansion-terrain.test.ts +++ b/packages/engine/test/expansion-terrain.test.ts @@ -3,7 +3,7 @@ import { applyCommand, activePlayer, boardView, createGame, gameLos, type GameSt import { cellKey, edgeKey, neighbor, opposite, SIDES, stepTarget, type Cell, type Side } from "../src/board"; import type { CardInstance } from "../src/cards"; import { eligibleCellsFor, sightedCellsFor, viewFor } from "../src/view"; -import { newExpansionGame as newGame, must, giveCard, emptyNeighborCell, plainRimWall } from "./helpers"; +import { newExpansionGame as newGame, must, giveCard, emptyNeighborCell, plainRimWall, toRound2 } from "./helpers"; /** The sides a walker may leave a pit by, having entered it heading `entry`. */ function rimExits(state: GameState, pit: Cell, entry: Side): Side[] { @@ -675,3 +675,34 @@ describe("a wave names its victims before it pushes (LK97)", () => { }); } }); + +describe("spells cast at a slime wait in the gel", () => { + it("a lightning blast lodges in the slime and goes off on the next wizard in, once", () => { + let { state } = newGame(42); + state = toRound2(state); + const caster = activePlayer(state); + const victim = state.players.find((p) => p.id !== caster.id)!; + const spot = emptyNeighborCell(state, caster.position); + state.squareContents[cellKey(spot.cell)] = { kind: "slime", damage: 0, createdBy: caster.id }; + const bolt = giveCard(state, caster.id, "lightning-blast"); + const cast = applyCommand(state, caster.id, { type: "cast", instanceId: bolt.instanceId, target: { kind: "cell", cell: spot.cell } }); + expect(cast.ok).toBe(true); + if (!cast.ok) return; + expect(cast.events.some((e) => e.type === "spellTrapped")).toBe(true); + expect(cast.state.slimeTraps[cellKey(spot.cell)]?.length).toBe(1); + // Nobody is hurt yet; the victim walks in on their own turn. + state = must(cast.state, caster.id, { type: "endTurn", draw: 2 }); + victim.position = { ...caster.position }; + const v = state.players.find((p) => p.id === victim.id)!; + v.position = { ...caster.position }; + const walk = applyCommand(state, victim.id, { type: "move", direction: spot.side }); + expect(walk.ok).toBe(true); + if (!walk.ok) return; + expect(walk.events.some((e) => e.type === "slimeTrapSprung")).toBe(true); + expect(walk.state.stack?.defenderId).toBe(victim.id); + expect(walk.state.stack?.trapped).toBe(true); + const hit = must(walk.state, victim.id, { type: "pass" }); + expect(hit.players.find((p) => p.id === victim.id)!.life).toBeLessThan(15); + expect(hit.slimeTraps[cellKey(spot.cell)]).toBeUndefined(); + }); +});