Creatures walk open doorways, and the interruption gets its fanfare
Player movement asked the full question of a door — removed, keyed this turn, or held — while creature movement only saw "door" and refused, so a skeleton balked at a doorway its master had unlocked for good. One doorIsOpen() now answers for both, and an open doorway costs a wraith none of its wall passes. And the interruption window earns the modal it deserved: "The maze holds its breath" — the card shown, the instruction plain, dismissed with "Seize it". No more hunting the rail for a slip while time stands parted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
44c14f5ce1
commit
e7c8ddc0b3
@@ -2578,9 +2578,15 @@ function doMoveCreature(prev: GameState, creatureId: string, direction: Side): C
|
||||
const from = creature.position;
|
||||
const target = stepTarget(view, creature.position, direction);
|
||||
if (target.kind === "blocked") {
|
||||
// WRAITH: "can move ... through 1 wall or object per turn."
|
||||
const dest = neighbor(creature.position, direction);
|
||||
if (
|
||||
// An open doorway (lock removed, keyed, or held) is no obstacle —
|
||||
// and costs a wraith nothing.
|
||||
if (target.by === "door" && doorIsOpen(state, edgeKey(creature.position, direction)) &&
|
||||
view.cells[cellKey(dest)] &&
|
||||
state.squareContents[cellKey(dest)]?.kind !== "stone") {
|
||||
creature.position = dest;
|
||||
} else if (
|
||||
// WRAITH: "can move ... through 1 wall or object per turn."
|
||||
creature.wallPassesPerTurn > creature.wallPassUsed &&
|
||||
view.cells[cellKey(dest)] &&
|
||||
state.squareContents[cellKey(dest)]?.kind !== "stone"
|
||||
@@ -2998,6 +3004,14 @@ function unlockDoor(
|
||||
return null;
|
||||
}
|
||||
|
||||
/** An open doorway: lock removed for good, keyed or picked this turn, or
|
||||
* held by a standing wizard. */
|
||||
function doorIsOpen(state: GameState, key: string): boolean {
|
||||
return state.doorStates[key] === "removed" ||
|
||||
state.openDoorEdges.includes(key) ||
|
||||
state.heldDoors.some((h) => h.key === key);
|
||||
}
|
||||
|
||||
/** A held door needs its holder: standing adjacent and alive. Anything that
|
||||
* moves or fells them — a step, a shove, a teleport, a killing blow — lets
|
||||
* the door swing shut. */
|
||||
@@ -3486,8 +3500,7 @@ function doMove(prev: GameState, direction: Side, over = false): CommandResult {
|
||||
if (isBlinded(state, p)) return blindBump(state, events, p, direction);
|
||||
return err("blocked");
|
||||
}
|
||||
if (edge === "door" && (state.doorStates[key] === "removed" || state.openDoorEdges.includes(key) ||
|
||||
state.heldDoors.some((h) => h.key === key))) {
|
||||
if (edge === "door" && doorIsOpen(state, key)) {
|
||||
p.position = dest;
|
||||
via = "step";
|
||||
} else if (edge === "firewall") {
|
||||
|
||||
Reference in New Issue
Block a user