The great simplification: every vintage gate collapses, the count restarts at 1
All 50 rooms were retired (backed up on the droplet and in Spaces), so no ledger needs an old branch to replay: forty revisions of deckRev gates fold into one canonical ruleset — the newest behavior everywhere. The ward's arming, the idiot's steering, the lazy illusion roll, the legacy redirection swap, and the flat wave all leave with their gates; RULES_REV restarts at 1 for whenever the rules fork again. Old-vintage test pins go with them. The opening screen now quietly drops seats whose rooms the server no longer knows, instead of listing them "unreachable" forever. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
e8df6efcde
commit
8a50ff7f36
@@ -784,7 +784,7 @@ function respond(view: GameView, style: AutomatonStyle, tier: TierTraits): Comma
|
||||
}
|
||||
// Or vanish: INVISIBLE gives the attacker a 1-in-4 hit and lingers after.
|
||||
const vanish = find("invisible");
|
||||
if (vanish && (!stack.creatureId || view.deckRev >= 13) && incoming >= 3 - flinch) {
|
||||
if (vanish && incoming >= 3 - flinch) {
|
||||
const num = numbersInHand(view)[0];
|
||||
return {
|
||||
type: "counteract", instanceId: vanish.instanceId,
|
||||
@@ -957,11 +957,6 @@ function selfCare(view: GameView, style: AutomatonStyle, tier: TierTraits): Comm
|
||||
// Three or more wizards: LIFESAVER takes elimination off the table.
|
||||
const lifesaver = inHand(view, "lifesaver");
|
||||
if (lifesaver && view.players.length > 2) return { type: "cast", instanceId: lifesaver.instanceId };
|
||||
// The ward guards the gold while its owner is away robbing yours
|
||||
// (arming retired at rev 31: the window asks in the moment instead).
|
||||
if (view.deckRev < 31 && inHand(view, "ward") && !view.yourWardArmed) {
|
||||
return { type: "armWard", armed: true };
|
||||
}
|
||||
const enemyNear = livingEnemies(view).some(
|
||||
(p) => Math.abs(p.position.x - self.position.x) + Math.abs(p.position.y - self.position.y) <= 3,
|
||||
);
|
||||
@@ -1323,12 +1318,12 @@ export function automatonCommand(
|
||||
}
|
||||
}
|
||||
|
||||
// IDIOT's curse: the maze no longer forces the feet (rev 37), so the
|
||||
// IDIOT's curse: the maze no longer forces the feet, so the
|
||||
// clockwork honors the march to its own gold itself — and when a thief
|
||||
// carries that gold, DROP OBJECT (the rev-37 carve-out) shakes it onto
|
||||
// the floor where it can finally be stood upon.
|
||||
// carries that gold, DROP OBJECT (an IDIOT aid) shakes it onto the
|
||||
// floor where it can finally be stood upon.
|
||||
const cursedIdiot = view.sustained.some((e) => e.cardId === "idiot" && e.targetId === view.you);
|
||||
if (cursedIdiot && view.deckRev >= 37 && view.turn.round > 1 && !view.turn.attackUsed) {
|
||||
if (cursedIdiot && view.turn.round > 1 && !view.turn.attackUsed) {
|
||||
const dropper = inHand(view, "drop-object");
|
||||
if (dropper) {
|
||||
const sighted = sightedCellsFor(view);
|
||||
@@ -1365,8 +1360,8 @@ export function automatonCommand(
|
||||
pathToward(view, self.position, objectives, { canUnlock }) ??
|
||||
pathToward(view, self.position, enemyCells, { canUnlock });
|
||||
// A shimmering illusion on the best crossing costs nothing to doubt:
|
||||
// roll the free test before spending any card on that wall (rev 29).
|
||||
if (view.deckRev >= 29) {
|
||||
// roll the free test before spending any card on that wall.
|
||||
{
|
||||
const crossing = bestWallCrossing(view, self, objectives, canUnlock);
|
||||
if (crossing && crossing.total < (path?.distance ?? Infinity)) {
|
||||
const k = edgeKey(crossing.cell, crossing.side);
|
||||
|
||||
Reference in New Issue
Block a user