The dread wraps: fear's diamond continues from the opposite rim
The maze is a torus — a wizard walking through walls off one edge arrives at the other, so the crow flies around the wrap too. dreadDistance measures toroidal manhattan; the aura's wash wraps with it. No rev-32 game has cast fear yet, so the measure corrects in place; older vintages replay flat as they were played. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
co-authored by
Claude Fable 5
parent
bcd2155fe0
commit
0a0108c48c
@@ -3722,15 +3722,24 @@ function takeFromHand(p: PlayerState, instanceId: string): CardInstance | null {
|
||||
* monsters (rules rev 32 widened it beyond walking wizards; forced movement
|
||||
* such as knockback or a wave is not willing and passes).
|
||||
*/
|
||||
/**
|
||||
* FEAR's measure — FAQ: "as a Wizard walks (if he could walk through
|
||||
* walls), not diagonally." Orthogonal steps, walls ignored — and the maze
|
||||
* wraps, so stepping off one rim continues from the opposite one.
|
||||
*/
|
||||
function dreadDistance(board: AssembledBoard, a: Cell, b: Cell): number {
|
||||
const dx = Math.abs(a.x - b.x);
|
||||
const dy = Math.abs(a.y - b.y);
|
||||
return Math.min(dx, board.width - dx) + Math.min(dy, board.height - dy);
|
||||
}
|
||||
|
||||
function fearRepels(state: GameState, moverId: PlayerId | null, from: Cell, to: Cell): boolean {
|
||||
const board = boardView(state);
|
||||
for (const other of state.players) {
|
||||
if (!other.alive || other.id === moverId) continue;
|
||||
if (sustainedOn(state, other.id, "fear").length === 0) continue;
|
||||
// FAQ: "The 3 spaces away is measured as a Wizard walks (if he could
|
||||
// walk through walls), not diagonally" — orthogonal steps, walls
|
||||
// ignored. Warps do not carry the dread; walls do not shield from it.
|
||||
const d = Math.abs(other.position.x - to.x) + Math.abs(other.position.y - to.y);
|
||||
const dBefore = Math.abs(other.position.x - from.x) + Math.abs(other.position.y - from.y);
|
||||
const d = dreadDistance(board, other.position, to);
|
||||
const dBefore = dreadDistance(board, other.position, from);
|
||||
if (d <= 3 && d < dBefore) return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -181,16 +181,21 @@
|
||||
});
|
||||
|
||||
// FEAR's dread: three spaces in every direction, straight through walls
|
||||
// ("even if walls separate you"), never diagonally — a manhattan diamond,
|
||||
// the same measure the engine's refusal takes.
|
||||
// ("even if walls separate you"), never diagonally — and the maze wraps,
|
||||
// so the diamond continues from the opposite rim. Same measure the
|
||||
// engine's refusal takes.
|
||||
const fearCells = $derived.by(() => {
|
||||
const out = new Set<string>();
|
||||
const W = view.board.width;
|
||||
const H = view.board.height;
|
||||
for (const fp of view.players) {
|
||||
if (!fp.alive) continue;
|
||||
if (!view.sustained.some((e) => e.cardId === "fear" && e.targetId === fp.id)) continue;
|
||||
for (let dx = -3; dx <= 3; dx++) {
|
||||
for (let dy = -3 + Math.abs(dx); dy <= 3 - Math.abs(dx); dy++) {
|
||||
const k = `${fp.position.x + dx},${fp.position.y + dy}`;
|
||||
const wx = ((fp.position.x + dx) % W + W) % W;
|
||||
const wy = ((fp.position.y + dy) % H + H) % H;
|
||||
const k = `${wx},${wy}`;
|
||||
if (view.board.cells[k]) out.add(k);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user