Reversed, Walking Dead heals half a point per step (rules rev 11)

The same FAQ turn as Slow Death's: a REVERSE riding the cast attaches
the curse backward, and every second space walked gains the point the
bite would have taken. Older ledgers attached it biting and replay so.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
Eric Wagoner
2026-08-29 23:01:01 -04:00
co-authored by Claude Fable 5
parent 4430a0def1
commit b538a0a2ae
2 changed files with 45 additions and 8 deletions
+17 -6
View File
@@ -270,10 +270,11 @@ export interface GameConfig {
* Rev 10: BUTT-HEAD's ram is MOVEMENT the charge walks real * Rev 10: BUTT-HEAD's ram is MOVEMENT the charge walks real
* corridors on the turn's legal legs (three plus numbers) and spends * corridors on the turn's legal legs (three plus numbers) and spends
* them. * them.
* Rev 11: a REVERSE against SLOW DEATH turns the whole curse (FAQ) * Rev 11: a REVERSE against SLOW DEATH or WALKING DEAD turns the whole
* the victim gains a point for every card drawn, permanently and a * curse (FAQ) a point gained per card drawn, half a point per space
* FULL REFLECTION returns a permanent curse (SLOW DEATH, WALKING DEAD, * walked, permanently and a FULL REFLECTION returns a permanent
* IDIOT) onto its caster instead of letting it evaporate. * curse (SLOW DEATH, WALKING DEAD, IDIOT) onto its caster instead of
* letting it evaporate.
*/ */
deckRev?: number; deckRev?: number;
} }
@@ -2219,9 +2220,13 @@ const CARD_EFFECTS: Record<string, AttackEffect | NeutralEffect | CounterEffect>
baseDamage: () => 0, baseDamage: () => 0,
permanentCurse: true, permanentCurse: true,
// "1/2 point of damage for every space moved. This spell is permanent." // "1/2 point of damage for every space moved. This spell is permanent."
// Rev 11: REVERSED at cast, the walk heals instead — half a point
// gained per space, as permanently. Older games attached it biting.
onResolved: (ctx) => { onResolved: (ctx) => {
if (ctx.fullyStopped || !ctx.defender.alive) return; if (ctx.fullyStopped || !ctx.defender.alive) return;
attachSustained(ctx.state, ctx.events, "walking-dead", ctx.attacker.id, ctx.defender.id, PERMANENT_TURNS); const reversed = ctx.reversed && (ctx.state.config.deckRev ?? 1) >= 11;
attachSustained(ctx.state, ctx.events, "walking-dead", ctx.attacker.id, ctx.defender.id,
PERMANENT_TURNS, reversed ? { reversed: 1 } : {});
}, },
}, },
disease: { disease: {
@@ -4312,14 +4317,20 @@ function doMove(prev: GameState, direction: Side, over = false): CommandResult {
state.turn.movementUsed++; state.turn.movementUsed++;
events.push({ type: "moved", player: p.id, from, to: p.position, direction, via }); events.push({ type: "moved", player: p.id, from, to: p.position, direction, via });
// WALKING DEAD: 1/2 point per space moved (a full point every two steps). // WALKING DEAD: 1/2 point per space moved (a full point every two
// steps) — gained instead of bled for a curse REVERSED at its casting.
for (const fx of sustainedOn(state, p.id, "walking-dead")) { for (const fx of sustainedOn(state, p.id, "walking-dead")) {
fx.data.halfSteps = (fx.data.halfSteps ?? 0) + 1; fx.data.halfSteps = (fx.data.halfSteps ?? 0) + 1;
if (fx.data.halfSteps % 2 === 0) { if (fx.data.halfSteps % 2 === 0) {
if (fx.data.reversed) {
p.life += 1;
events.push({ type: "lifeGained", player: p.id, amount: 1, source: "walking dead (reversed)", lifeAfter: p.life });
} else {
applyDamage(state, events, p, 1, "walking dead", null); applyDamage(state, events, p, 1, "walking dead", null);
checkVictory(state, events); checkVictory(state, events);
} }
} }
}
// DISEASE: the carrier infects every other player in a square they enter. // DISEASE: the carrier infects every other player in a square they enter.
if (p.alive && sustainedOn(state, p.id, "disease").length > 0) { if (p.alive && sustainedOn(state, p.id, "disease").length > 0) {
for (const other of state.players) { for (const other of state.players) {
+26
View File
@@ -170,6 +170,32 @@ describe("slow death", () => {
expect(state.players.find((p) => p.id === defender)!.life).toBe(17); expect(state.players.find((p) => p.id === defender)!.life).toBe(17);
}); });
it("a reversed walking dead heals half a point per space walked (rev 11)", () => {
let { state } = newGame();
state = toRound2(state);
const { attacker, defender } = faceOff(state);
const wd = giveCard(state, attacker, "walking-dead");
giveCard(state, defender, "reverse", "RV", 0);
const r = applyCommand(state, attacker, {
type: "cast", instanceId: wd.instanceId, target: { kind: "player", playerId: defender },
});
if (!r.ok) throw new Error(r.error);
state = must(r.state, defender, { type: "counteract", instanceId: "reverse#RV" });
state = drain(state);
expect(sustainedOn(state, defender, "walking-dead").length).toBe(1);
state = must(state, attacker, { type: "endTurn", draw: 0 });
// Two spaces walked: one point gained, not bled.
let steps = 0;
for (const dir of ["N", "S", "E", "W", "N", "S", "E", "W"] as const) {
if (steps >= 2) break;
const mv = applyCommand(state, defender, { type: "move", direction: dir });
if (mv.ok) { state = mv.state; steps++; }
}
expect(steps).toBe(2);
expect(state.players.find((p) => p.id === defender)!.life).toBe(16);
});
it("a full reflection returns the curse onto its caster (rev 11)", () => { it("a full reflection returns the curse onto its caster (rev 11)", () => {
let { state } = newGame(); let { state } = newGame();
state = toRound2(state); state = toRound2(state);