IDIOT trusts the feet and yields to a jailbreak drop (rules rev 37)
The per-step steering recalculated greedily, ping-ponging between routes that tie at a corner and able to wall the victim off from the cure; rev 37 retires it — the march is the player's to honor, and the automatons steer themselves. DROP OBJECT that shakes the victim's OWN treasure out of a thief's arms is now an aid, not an attack: while carried, that treasure cannot even be stood upon, so the curse could be unsatisfiable. Older ledgers replay steered and strict. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
6adcbe23b5
commit
118bfd236b
@@ -3790,7 +3790,11 @@ function doMove(prev: GameState, direction: Side, over = false): CommandResult {
|
||||
const events: GameEvent[] = [];
|
||||
|
||||
// IDIOT: every move heads for the nearest of their own treasures.
|
||||
if (sustainedOn(state, p.id, "idiot").length > 0) {
|
||||
// Rev 37 retires the steering: a greedy per-step recalculation ping-pongs
|
||||
// between routes that tie at a corner and can wall the victim off from
|
||||
// the cure entirely. The march is the player's to honor (like FEAR's
|
||||
// duty); the automatons steer themselves. Older ledgers replay steered.
|
||||
if ((state.config.deckRev ?? 1) < 37 && sustainedOn(state, p.id, "idiot").length > 0) {
|
||||
const steered = idiotSteer(state, p);
|
||||
if (steered) direction = steered;
|
||||
}
|
||||
@@ -4169,7 +4173,7 @@ const IDIOT_AIDS = new Set([
|
||||
|
||||
function castingBlocked(
|
||||
state: GameState, playerId: PlayerId,
|
||||
opts?: { counteraction?: boolean; cardId?: string },
|
||||
opts?: { counteraction?: boolean; cardId?: string; targetPlayerId?: PlayerId; pickedCardId?: string },
|
||||
): string | null {
|
||||
if (sustainedOn(state, playerId, "medusa").length > 0) return "you are paralyzed by Medusa";
|
||||
if (sustainedOn(state, playerId, "no-spell").length > 0) return "No Spell — you cannot cast";
|
||||
@@ -4177,7 +4181,16 @@ function castingBlocked(
|
||||
// needed)" — and per the FAQ, spells that aid the march to the treasure.
|
||||
if (sustainedOn(state, playerId, "idiot").length > 0 &&
|
||||
!opts?.counteraction && !(opts?.cardId && IDIOT_AIDS.has(opts.cardId))) {
|
||||
return "What am I doing here...? (you can do nothing but head for your treasure)";
|
||||
// Rev 37: DROP OBJECT that shakes YOUR OWN treasure out of a thief's
|
||||
// arms serves the march — while carried, that treasure cannot even be
|
||||
// stood upon, so without this the curse can be unsatisfiable.
|
||||
const freesOwnGold = (state.config.deckRev ?? 1) >= 37 &&
|
||||
opts?.cardId === "drop-object" && opts.pickedCardId === "treasure" &&
|
||||
opts.targetPlayerId != null &&
|
||||
state.treasures.some((t) => t.owner === playerId && t.carriedBy === opts.targetPlayerId);
|
||||
if (!freesOwnGold) {
|
||||
return "What am I doing here...? (you can do nothing but head for your treasure)";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -4605,7 +4618,11 @@ function doCast(prev: GameState, cmd: Extract<Command, { type: "cast" }>): Comma
|
||||
// NO SPELL cast on you."
|
||||
const isSpell = def.cardType !== "object" && !NOT_SPELLS.has(inHand.cardId) && !isWand;
|
||||
if (isSpell) {
|
||||
const castBlock = castingBlocked(state, caster.id, { cardId: inHand.cardId });
|
||||
const castBlock = castingBlocked(state, caster.id, {
|
||||
cardId: inHand.cardId,
|
||||
targetPlayerId: cmd.target?.kind === "player" ? cmd.target.playerId : undefined,
|
||||
pickedCardId: cmd.params?.cardId,
|
||||
});
|
||||
if (castBlock) return err(castBlock);
|
||||
} else if (sustainedOn(state, caster.id, "medusa").length > 0) {
|
||||
return err("you are paralyzed by Medusa");
|
||||
|
||||
Reference in New Issue
Block a user