Reversed, Slow Death heals a point per draw (rules rev 11)
Per the FAQ: a REVERSE riding the cast turns the whole curse — the victim gains a point for every card drawn, as permanently as the bite. The stack's reversed verdict now reaches onResolved, and the sustained effect carries it in its data scratch. Older ledgers attached the biting curse regardless and replay unchanged (pinned at deckRev 10). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
co-authored by
Claude Fable 5
parent
e930d013f8
commit
e885325098
@@ -233,7 +233,7 @@ export interface CastParams {
|
||||
}
|
||||
|
||||
/** The revision new games are dealt under; GameConfig.deckRev pins it per game. */
|
||||
export const CURRENT_RULES_REV = 10;
|
||||
export const CURRENT_RULES_REV = 11;
|
||||
|
||||
export interface GameConfig {
|
||||
playerIds: PlayerId[];
|
||||
@@ -270,6 +270,8 @@ export interface GameConfig {
|
||||
* Rev 10: BUTT-HEAD's ram is MOVEMENT — the charge walks real
|
||||
* corridors on the turn's legal legs (three plus numbers) and spends
|
||||
* them.
|
||||
* Rev 11: a REVERSE against SLOW DEATH turns the whole curse (FAQ) —
|
||||
* the victim gains a point for every card drawn, permanently.
|
||||
*/
|
||||
deckRev?: number;
|
||||
}
|
||||
@@ -864,6 +866,8 @@ interface ResolutionContext {
|
||||
defender: PlayerState;
|
||||
damageDealt: number;
|
||||
fullyStopped: boolean;
|
||||
/** A surviving REVERSE rode the stack: the spell's effect runs backward. */
|
||||
reversed: boolean;
|
||||
duration: number;
|
||||
stack: CastStack;
|
||||
}
|
||||
@@ -1717,9 +1721,14 @@ const CARD_EFFECTS: Record<string, AttackEffect | NeutralEffect | CounterEffect>
|
||||
requiresLos: true,
|
||||
baseDamage: () => 0,
|
||||
// "This is permanent. Once SLOW DEATH is on, it can't be turned off."
|
||||
// Rev 11, per the FAQ: "If SLOW DEATH is REVERSED, the player receives
|
||||
// a point for every card drawn" — the whole curse attaches backward,
|
||||
// just as permanently. Older games attached it biting; they replay so.
|
||||
onResolved: (ctx) => {
|
||||
if (ctx.fullyStopped || !ctx.defender.alive) return;
|
||||
attachSustained(ctx.state, ctx.events, "slow-death", ctx.attacker.id, ctx.defender.id, PERMANENT_TURNS);
|
||||
const reversed = ctx.reversed && (ctx.state.config.deckRev ?? 1) >= 11;
|
||||
attachSustained(ctx.state, ctx.events, "slow-death", ctx.attacker.id, ctx.defender.id,
|
||||
PERMANENT_TURNS, reversed ? { reversed: 1 } : {});
|
||||
},
|
||||
},
|
||||
blind: { kind: "attack", requiresLos: true, baseDamage: () => 0, sustains: true },
|
||||
@@ -3584,6 +3593,7 @@ function attachSustained(
|
||||
casterId: PlayerId,
|
||||
targetId: PlayerId,
|
||||
turns: number,
|
||||
data: Record<string, number> = {},
|
||||
): void {
|
||||
const effect: SustainedEffect = {
|
||||
id: `fx-${state.nextEffectId++}`,
|
||||
@@ -3591,7 +3601,7 @@ function attachSustained(
|
||||
casterId,
|
||||
targetId,
|
||||
remainingTurns: Math.max(1, turns),
|
||||
data: {},
|
||||
data,
|
||||
};
|
||||
state.sustained.push(effect);
|
||||
events.push({
|
||||
@@ -6016,7 +6026,7 @@ function resolveStack(state: GameState, events: GameEvent[]): void {
|
||||
effect.onResolved({
|
||||
state, events,
|
||||
attacker: defender, defender: attacker,
|
||||
damageDealt: 0, fullyStopped: false, duration: 0,
|
||||
damageDealt: 0, fullyStopped: false, reversed: false, duration: 0,
|
||||
stack: { ...stack, params: { ...stack.params, cardId: chosen } },
|
||||
});
|
||||
}
|
||||
@@ -6150,6 +6160,7 @@ function resolveStack(state: GameState, events: GameEvent[]): void {
|
||||
defender,
|
||||
damageDealt,
|
||||
fullyStopped: pipe.fullyStopped,
|
||||
reversed: pipe.reversed,
|
||||
duration: pipe.duration,
|
||||
stack,
|
||||
});
|
||||
@@ -6550,11 +6561,18 @@ function doDiscard(prev: GameState, playerId: PlayerId, instanceIds: string[]):
|
||||
return { ok: true, state, events: [{ type: "cardsDiscarded", player: p.id, cards }] };
|
||||
}
|
||||
|
||||
/** SLOW DEATH: "Opponent takes 1 point of magical damage whenever he draws." */
|
||||
/** SLOW DEATH: "Opponent takes 1 point of magical damage whenever he draws" —
|
||||
* or gains one, for a curse that was REVERSED at its casting. */
|
||||
function applySlowDeathOnDraw(state: GameState, events: GameEvent[], p: PlayerState, cardsDrawn: number): void {
|
||||
const stacks = sustainedOn(state, p.id, "slow-death").length;
|
||||
if (stacks === 0 || cardsDrawn === 0 || !p.alive) return;
|
||||
for (let i = 0; i < cardsDrawn * stacks; i++) {
|
||||
const curses = sustainedOn(state, p.id, "slow-death");
|
||||
if (curses.length === 0 || cardsDrawn === 0 || !p.alive) return;
|
||||
const blessed = curses.filter((e) => e.data.reversed).length;
|
||||
if (blessed > 0) {
|
||||
const amount = cardsDrawn * blessed;
|
||||
p.life += amount;
|
||||
events.push({ type: "lifeGained", player: p.id, amount, source: "slow death (reversed)", lifeAfter: p.life });
|
||||
}
|
||||
for (let i = 0; i < cardsDrawn * (curses.length - blessed); i++) {
|
||||
if (!p.alive) break;
|
||||
applyDamage(state, events, p, 1, "slow death", null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user