Rev 23: POWER DRAIN drains the number played; the troll punches walls; the first-person stack fits
POWER DRAIN's gain is the number played, BLUNTed or ABSORBed or not (FAQ: the counter blunts the damage done, not the drain), and a wall drained for its points gives them up too. Older games gave only what the opponent lost and nothing from a wall, and replay so. "This rock-hard beast can punch a player (or a wall, etc.)": a commanded troll now punches a wall line beside it for a D4, once a turn — a new command, so no old game changes. Under the first-person pane the board strip could run into the dock on a short or tall window; the pane now takes no more height than the row can spare and the strip shrinks beneath it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
803c51415e
commit
80dd7a7865
@@ -998,3 +998,27 @@ describe("the alter ego casts from its own square", () => {
|
||||
expect(done.players.find((p) => p.id === defender)!.life).toBe(10);
|
||||
});
|
||||
});
|
||||
|
||||
describe("the troll's fist on a wall", () => {
|
||||
it("punches a wall line beside it for a D4, once a turn", () => {
|
||||
let { state } = newGame();
|
||||
state = toRound2(state);
|
||||
const me = activePlayer(state).id;
|
||||
const r = summon(state, me, "troll");
|
||||
state = r.state;
|
||||
const other = state.players.find((p) => p.id !== me)!.id;
|
||||
state = must(state, me, { type: "endTurn", draw: 0 });
|
||||
state = must(state, other, { type: "endTurn", draw: 0 });
|
||||
const troll = state.creatures[0]!;
|
||||
const board = boardView(state);
|
||||
const side = SIDES.find((s) => board.edges[edgeKey(troll.position, s)] === "wall")!;
|
||||
const res = applyCommand(state, me, { type: "creatureAttackWall", creatureId: troll.id, cell: troll.position, side });
|
||||
expect(res.ok).toBe(true);
|
||||
if (!res.ok) return;
|
||||
const hit = res.events.find((e) => e.type === "wallDamaged");
|
||||
expect(hit && hit.type === "wallDamaged" ? hit.amount : 0).toBeGreaterThanOrEqual(1);
|
||||
expect(res.state.creatures[0]!.attackUsed).toBe(true);
|
||||
const again = applyCommand(res.state, me, { type: "creatureAttackWall", creatureId: troll.id, cell: troll.position, side });
|
||||
expect(again.ok).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { applyCommand, activePlayer, boardView, createGame, sustainedOn, type GameState } from "../src/game";
|
||||
import { cellKey, edgeKey, neighbor, opposite, type Side } from "../src/board";
|
||||
import { cellKey, edgeKey, neighbor, opposite, SIDES, type Side } from "../src/board";
|
||||
import type { CardInstance } from "../src/cards";
|
||||
import { newGame, must, giveCard, toRound2, faceOff, castAt } from "./helpers";
|
||||
import { newGame, must, giveCard, toRound2, faceOff, castAt, drain } from "./helpers";
|
||||
|
||||
describe("duration spells", () => {
|
||||
it("slow reduces movement to 1, blocks number cards, and halves attacks", () => {
|
||||
@@ -567,3 +567,44 @@ describe("the displayed MASTER KEY", () => {
|
||||
expect(r.ok).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("POWER DRAIN drains the number played (rev 23)", () => {
|
||||
it("gains the number even when the blow is blunted", () => {
|
||||
let { state } = newGame();
|
||||
state = toRound2(state);
|
||||
const { attacker, defender } = faceOff(state);
|
||||
const pd = giveCard(state, attacker, "power-drain");
|
||||
giveCard(state, attacker, "number-4", "N", 1);
|
||||
const d = state.players.find((p) => p.id === defender)!;
|
||||
d.hand[0] = { instanceId: "blunt#T", cardId: "blunt" };
|
||||
state = must(state, attacker, { type: "cast", instanceId: pd.instanceId, target: { kind: "player", playerId: defender }, numberInstanceIds: ["number-4#N"] });
|
||||
state = must(state, defender, { type: "counteract", instanceId: "blunt#T" });
|
||||
state = drain(state);
|
||||
expect(state.players.find((p) => p.id === defender)!.life).toBe(13);
|
||||
expect(state.players.find((p) => p.id === attacker)!.life).toBe(19);
|
||||
});
|
||||
|
||||
it("drains a wall for its points", () => {
|
||||
let { state } = newGame();
|
||||
state = toRound2(state);
|
||||
const me = activePlayer(state);
|
||||
const board = boardView(state);
|
||||
const side = SIDES.find((s) => board.edges[edgeKey(me.position, s)] === "wall")!;
|
||||
const pd = giveCard(state, me.id, "power-drain");
|
||||
giveCard(state, me.id, "number-3", "N", 1);
|
||||
state = must(state, me.id, { type: "cast", instanceId: pd.instanceId, target: { kind: "edge", cell: me.position, side }, numberInstanceIds: ["number-3#N"] });
|
||||
expect(state.wallDamage[edgeKey(me.position, side)]).toBe(3);
|
||||
expect(state.players.find((p) => p.id === me.id)!.life).toBe(18);
|
||||
});
|
||||
|
||||
it("older games gave only what the opponent lost, and nothing from a wall", () => {
|
||||
let state = toRound2(createGame({ playerIds: ["alice", "bob"], seed: 42, sets: ["basic"], deckRev: 22 }).state);
|
||||
const me = activePlayer(state);
|
||||
const board = boardView(state);
|
||||
const side = SIDES.find((s) => board.edges[edgeKey(me.position, s)] === "wall")!;
|
||||
const pd = giveCard(state, me.id, "power-drain");
|
||||
giveCard(state, me.id, "number-3", "N", 1);
|
||||
state = must(state, me.id, { type: "cast", instanceId: pd.instanceId, target: { kind: "edge", cell: me.position, side }, numberInstanceIds: ["number-3#N"] });
|
||||
expect(state.players.find((p) => p.id === me.id)!.life).toBe(15);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user