The MASTER KEY earns its display
"Display Immediately," says the card — now the key lives up to it. Cast bare (a new Display button beside the hold-the-door checkbox), it goes straight on display; once displayed, it turns in every lock its bearer walks through — no more casting at each door — with the door relocking behind them at turn's end like any picked lock, and the doorUnlocked event still swinging the door in the reels. Cast at an adjacent door it still works one lock like PICK LOCK, including holding the door open for others. A JAMmed LOCK refuses it as ever, and the adjacent peek through workable locks already rode the rev-2 sight rules. Replay-safe ungated: bare casts were never recorded (they were refused), displayed cards still count against the hand limit, and walking through a locked door only widens what is accepted. 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
805fb09782
commit
64e4e243dc
@@ -1233,8 +1233,14 @@ const CARD_EFFECTS: Record<string, AttackEffect | NeutralEffect | CounterEffect>
|
||||
keepInHand: true,
|
||||
// "Unlocks any door (door relocks behind you). Do not discard when used.
|
||||
// Display Immediately. Must be adjacent. Does not work on a JAMmed LOCK."
|
||||
// Cast bare, it simply goes on display, and a DISPLAYED key turns in
|
||||
// every lock its bearer walks through (see doMove) — no further casts.
|
||||
// Cast at a door, it works that one lock like PICK LOCK and may hold
|
||||
// the door open for others.
|
||||
resolve: (state, events, caster, cmd) =>
|
||||
unlockDoor(state, events, caster, cmd, "master-key", { requireAdjacent: true }),
|
||||
cmd.target
|
||||
? unlockDoor(state, events, caster, cmd, "master-key", { requireAdjacent: true })
|
||||
: null,
|
||||
},
|
||||
"remove-lock": {
|
||||
kind: "neutral",
|
||||
@@ -3941,7 +3947,15 @@ function doMove(prev: GameState, direction: Side, over = false): CommandResult {
|
||||
p.position = { ...warp.to.cell };
|
||||
via = "warp";
|
||||
crossedFirewall = true;
|
||||
} else if (edge === "door" && doorIsOpen(state, key)) {
|
||||
} else if (edge === "door" &&
|
||||
(doorIsOpen(state, key) || (displays(p, "master-key") && state.doorStates[key] !== "jammed"))) {
|
||||
// The displayed MASTER KEY turns in every lock it meets: the walker
|
||||
// passes without another cast, and the door relocks behind them at
|
||||
// turn's end like any picked lock. A JAMmed LOCK still refuses it.
|
||||
if (!doorIsOpen(state, key)) {
|
||||
state.openDoorEdges.push(key);
|
||||
events.push({ type: "doorUnlocked", player: p.id, edge: parseEdgeKey(key), withCardId: "master-key" });
|
||||
}
|
||||
p.position = dest;
|
||||
via = "step";
|
||||
} else if (edge === "firewall") {
|
||||
@@ -4737,6 +4751,9 @@ function doCast(prev: GameState, cmd: Extract<Command, { type: "cast" }>): Comma
|
||||
if (effect.kind === "neutral" && effect.displayOnce && caster.displayed.includes(inHand.instanceId)) {
|
||||
return err(`${def.name} is already displayed`);
|
||||
}
|
||||
if (inHand.cardId === "master-key" && !cmd.target && caster.displayed.includes(inHand.instanceId)) {
|
||||
return err("the key is already on display");
|
||||
}
|
||||
|
||||
// Magic wands: charged on first use by the number card(s) played; one
|
||||
// charge per use, one use per turn; discarded when the last charge goes.
|
||||
|
||||
Reference in New Issue
Block a user