Attacks aimed at a bush or the ooze: five points clear the square
A THORNBUSH or ROSEBUSH "will be destroyed" by five points of damage, and the FAQ lets only fire hurt a KILLER OOZE; the table refused every attack aimed at one. An attack tapped onto a bush or ooze now lands on it, the damage accumulating across attackers and turns, and the fifth point clears the square. A WIZARDBLADE is swung from the square beside it, as its text asks of a target that fills a square. 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
23b4a7675e
commit
bc99ee3eb7
@@ -610,6 +610,9 @@ function castSightEdge(
|
||||
return false;
|
||||
}
|
||||
|
||||
/** The attacks that burn: what the FAQ lets hurt a KILLER OOZE. */
|
||||
const FIRE_ATTACKS = new Set(["fireball"]);
|
||||
|
||||
function inThornbush(state: GameState, p: PlayerState): boolean {
|
||||
return state.squareContents[cellKey(p.position)]?.kind === "thornbush";
|
||||
}
|
||||
@@ -786,6 +789,8 @@ export type GameEvent =
|
||||
| { type: "slowDeathCountered"; player: PlayerId; cardId: string; remaining: number }
|
||||
| { type: "safeDamaged"; attacker: PlayerId; cell: Cell; amount: number; total: number }
|
||||
| { type: "safeSmashed"; attacker: PlayerId; cell: Cell }
|
||||
| { type: "squareContentDamaged"; attacker: PlayerId; cell: Cell; kind: "thornbush" | "rosebush" | "ooze"; amount: number; total: number; needed: number }
|
||||
| { type: "squareContentDestroyed"; attacker: PlayerId; cell: Cell; kind: "thornbush" | "rosebush" | "ooze" }
|
||||
| { type: "trapSprung"; player: PlayerId; cardId?: string }
|
||||
| { type: "died"; player: PlayerId; killedBy: PlayerId | null }
|
||||
| { type: "handTaken"; from: PlayerId; to: PlayerId; count: number }
|
||||
@@ -5450,6 +5455,53 @@ function doCast(prev: GameState, cmd: Extract<Command, { type: "cast" }>): Comma
|
||||
}
|
||||
return { ok: true, state, events };
|
||||
}
|
||||
// A THORNBUSH or ROSEBUSH: "Five points of damage will destroy it." A
|
||||
// KILLER OOZE: "Only fire ... will hurt the ooze" (FAQ), and five points
|
||||
// burn it away. Damage accumulates across attackers and turns. A
|
||||
// same-square attack (WIZARDBLADE) is swung from a square beside it:
|
||||
// "If target fills an entire square, you must be in an adjacent square."
|
||||
if (cmd.target?.kind === "cell") {
|
||||
const cell = cmd.target.cell;
|
||||
const content = state.squareContents[cellKey(cell)];
|
||||
if (content && (content.kind === "thornbush" || content.kind === "rosebush" || content.kind === "ooze")) {
|
||||
const what = content.kind === "ooze" ? "ooze" : content.kind;
|
||||
if (effect.sameSquare) {
|
||||
const dx = cell.x - origin.x, dy = cell.y - origin.y;
|
||||
const side: Side | null = dx === 1 && dy === 0 ? "E" : dx === -1 && dy === 0 ? "W" : dy === 1 && dx === 0 ? "S" : dy === -1 && dx === 0 ? "N" : null;
|
||||
if (!side || boardView(state).edges[edgeKey(origin, side)] === "wall") {
|
||||
return err(`you must stand beside the ${what} to use that`);
|
||||
}
|
||||
} else if (effect.requiresLos && !castSight(state, caster, cmd, cell)) {
|
||||
return err(`no line of sight to the ${what}`);
|
||||
}
|
||||
if (content.kind === "ooze" && !FIRE_ATTACKS.has(inHand.cardId)) {
|
||||
return err("only fire hurts the ooze");
|
||||
}
|
||||
const wandEvents: GameEvent[] = [];
|
||||
{
|
||||
const werr = spendWandCharge(state, caster, wandEvents);
|
||||
if (werr) return err(werr);
|
||||
}
|
||||
const dmg = effect.baseDamage(mods.magnitude.numberValue, cmd.params ?? null) * (2 ** mods.amplifies.length);
|
||||
if (dmg <= 0) return err(`that spell would not singe the ${what}`);
|
||||
consumeCast(state, caster, inHand, mods, effect.keepInHand ?? false);
|
||||
if (state.turn.attackUsed) state.turn.secondAttackUsed = true;
|
||||
state.turn.attackUsed = true;
|
||||
state.lastSpellUsed[caster.id] = inHand.cardId;
|
||||
const events: GameEvent[] = [...wandEvents, {
|
||||
type: "spellCast", caster: caster.id, card: inHand, cardId: inHand.cardId,
|
||||
numberCards: mods.numbers, numberValue: mods.magnitude.numberValue,
|
||||
from: origin, target: null, targetCell: { ...cell },
|
||||
}];
|
||||
content.damage += dmg;
|
||||
events.push({ type: "squareContentDamaged", attacker: caster.id, cell: { ...cell }, kind: content.kind, amount: dmg, total: content.damage, needed: 5 });
|
||||
if (content.damage >= 5) {
|
||||
delete state.squareContents[cellKey(cell)];
|
||||
events.push({ type: "squareContentDestroyed", attacker: caster.id, cell: { ...cell }, kind: content.kind });
|
||||
}
|
||||
return { ok: true, state, events };
|
||||
}
|
||||
}
|
||||
// FILL SQUARE WITH SLIME: "Spells cast at the slime get stuck there, and
|
||||
// affect anyone in the slime or entering it later on." A 5-point WATERBOLT
|
||||
// washes the slime away instead.
|
||||
|
||||
Reference in New Issue
Block a user