From b4adb975369ff1a2849c086d859a2c1d2f94af55 Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Mon, 17 Aug 2026 16:53:28 -0400 Subject: [PATCH] The mid-round democratic monster claws when its turn comes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every creature is born with attackUsed spent — the right way to say "cannot attack the turn created" for monsters whose flag refreshes next turn. But the democratic monster's flag budgets its ROUND, so a mid-round summon arrived pre-spent and bumped harmlessly until the round rolled over. Creation-turn pacifism now rides justCreated alone for the monster (checked at the touch), and its round-claw starts live — folded into rev 18 with the boundary refresh. Co-Authored-By: Claude Fable 5 --- packages/engine/src/game.ts | 8 ++++++-- packages/engine/test/creatures.test.ts | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/engine/src/game.ts b/packages/engine/src/game.ts index 4f47893..c4670fa 100644 --- a/packages/engine/src/game.ts +++ b/packages/engine/src/game.ts @@ -2543,7 +2543,11 @@ function spawnCreature( maxDamage: stats.maxDamage, movesPerTurn: stats.moves, movementUsed: 0, // "It may move on that turn." (Exp1 sheet) - attackUsed: true, // "cannot attack the turn they are created" + // "Cannot attack the turn they are created" is justCreated's job; the + // democratic monster's attackUsed budgets its ROUND, so spending it at + // birth would mute a mid-round summon until the round rolled over + // (rules rev 18). + attackUsed: !(kind === "democratic-monster" && (state.config.deckRev ?? 1) >= 18), justCreated: true, wallPassesPerTurn: stats.wallPasses, wallPassUsed: 0, @@ -2666,7 +2670,7 @@ function doMoveCreature(prev: GameState, creatureId: string, direction: Side): C events.push({ type: "cardsDiscarded", player: p.id, cards: [card!] }); } } - if (creature.kind === "democratic-monster" && !creature.attackUsed) { + if (creature.kind === "democratic-monster" && !creature.attackUsed && !creature.justCreated) { creature.attackUsed = true; // "may attack only one player per round of turns" events.push({ type: "creatureTouched", creatureId: creature.id, kind: creature.kind, player: p.id }); if (rev4) { diff --git a/packages/engine/test/creatures.test.ts b/packages/engine/test/creatures.test.ts index 8c85046..0d25822 100644 --- a/packages/engine/test/creatures.test.ts +++ b/packages/engine/test/creatures.test.ts @@ -616,3 +616,27 @@ describe("the democratic monster's claw survives the first wizard's death (rules expect(state.creatures[0]!.attackUsed).toBe(false); }); }); + +describe("a mid-round democratic monster claws on the next turn (rules rev 18)", () => { + it("creation spends the turn, not the round", () => { + let { state } = createGame({ playerIds: ["a", "b"], seed: 42, sets: ["basic", "expansion1"], deckRev: 18 }); + state = toRound2(state); + const creator = activePlayer(state); + const r0 = summon(state, creator.id, "democratic-monster"); + state = r0.state; + const dm = state.creatures.find((c) => c.kind === "democratic-monster")!; + expect(dm.attackUsed).toBe(false); + expect(dm.justCreated).toBe(true); + // Next player's turn: justCreated clears; the claw is live. + state = must(state, creator.id, { type: "endTurn", draw: 0 }); + const mover = activePlayer(state); + const victim = state.players.find((p) => p.id !== mover.id)!; + const fresh = state.creatures.find((c) => c.kind === "democratic-monster")!; + expect(fresh.justCreated).toBe(false); + // March it onto the victim: the touch must open. + fresh.position = { x: victim.position.x - 1, y: victim.position.y }; + const r = applyCommand(state, mover.id, { type: "moveCreature", creatureId: fresh.id, direction: "E" }); + if (!r.ok) throw new Error(r.error); + expect(r.state.stack?.creatureId ?? null).toBe(fresh.id); + }); +});