Merge branch 'main' into flourishes

This commit is contained in:
Eric Wagoner
2026-08-17 09:18:40 -04:00
+34 -2
View File
@@ -383,6 +383,9 @@ function bestAttack(view: GameView, targetId: PlayerId, tier: TierTraits): Comma
for (const c of view.yourHand) {
const atk = ATTACKS[c.cardId];
if (!atk) continue;
// Heave-Ho throws the treasure we are carrying: priced for defense,
// never worth casting.
if (c.cardId === "heave-ho") continue;
if (atk.sameSquare && !together) continue;
// A wand needs its charges set by a number on first use.
const isWand = c.cardId === "blaster-wand";
@@ -401,12 +404,31 @@ function bestAttack(view: GameView, targetId: PlayerId, tier: TierTraits): Comma
cmd: {
type: "cast", instanceId: c.instanceId,
target: { kind: "player", playerId: targetId },
// An illusion needs a spell to imitate; a fireball sells best.
...(c.cardId === "illusionary-attack" ? { params: { cardId: "fireball" } } : {}),
...(withNumber ? { numberInstanceIds: [biggest.instanceId] } : {}),
...(amplified ? { amplifyInstanceIds: [amplify.instanceId] } : {}),
},
};
}
}
// STONE DEAD: number times the stones the victim carries — the displayed
// ones are the visible floor of that count.
const sd = view.yourHand.find((c) => c.cardId === "stone-dead");
if (sd && biggest) {
const shown = target.displayed.filter((c) => STONES.has(c.cardId)).length;
const dmg = biggestValue * shown;
if (dmg >= 4 && dmg > (best?.damage ?? 0)) {
best = {
damage: dmg,
cmd: {
type: "cast", instanceId: sd.instanceId,
target: { kind: "player", playerId: targetId },
numberInstanceIds: [biggest.instanceId],
},
};
}
}
return best?.cmd ?? null;
}
@@ -690,9 +712,19 @@ export function automatonCommand(
const movesLeft = view.turn.movementAllowance - view.turn.movementUsed;
if (!view.turn.numberPlayedForMovement && path.distance > movesLeft) {
const numbers = numbersInHand(view);
const helper = numbers.find(
// The war chest: when an attack in hand wants a number, the
// biggest one is reserved — a waterbolt unfired outbids a longer
// march, and walking is free next turn.
const wantsNumber = view.yourHand.some((c) => {
const atk = ATTACKS[c.cardId];
if (!atk) return false;
return atk.perNumber || atk.needsNumber === true ||
(c.cardId === "blaster-wand" && view.wandCharges[c.instanceId] == null);
});
const spendable = wantsNumber ? numbers.slice(0, -1) : numbers;
const helper = spendable.find(
(n) => movesLeft + (cardDef(n.cardId).value ?? 0) >= path.distance,
) ?? (path.distance > movesLeft + 2 ? numbers[numbers.length - 1] : undefined);
) ?? (path.distance > movesLeft + 2 ? spendable[spendable.length - 1] : undefined);
if (helper) {
return { type: "playNumberForMovement", instanceId: helper.instanceId };
}