A bare wand lights a single charge
'ANY CARD MAY BE PLAYED WITHOUT A NUMBER CARD, but its power is only 1.' The wand first-use gate was the engine's one remaining missing-number refusal — everything else already defaults its power to 1. A wand cast bare now charges to one, fires once, and crumbles; the client hint says so. Ungated: the refused casts never reached a ledger. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
co-authored by
Claude Fable 5
parent
1e5b7ee985
commit
4720ec25ff
@@ -4523,8 +4523,9 @@ function doCast(prev: GameState, cmd: Extract<Command, { type: "cast" }>): Comma
|
|||||||
if (!isWand) return null;
|
if (!isWand) return null;
|
||||||
let charges = st.wandCharges[inHand.instanceId];
|
let charges = st.wandCharges[inHand.instanceId];
|
||||||
if (charges === undefined) {
|
if (charges === undefined) {
|
||||||
if (mods.numbers.length === 0) return "a wand's first use needs a number card to set its charges";
|
// "ANY CARD MAY BE PLAYED WITHOUT A NUMBER CARD, but its power is
|
||||||
charges = mods.magnitude.power; // AMPLIFY and ADD both work here
|
// only 1" — a bare first use lights a single charge.
|
||||||
|
charges = mods.magnitude.power; // 1 without a number; AMPLIFY and ADD work here
|
||||||
st.wandCharges[inHand.instanceId] = charges;
|
st.wandCharges[inHand.instanceId] = charges;
|
||||||
if (!wielder.displayed.includes(inHand.instanceId)) wielder.displayed.push(inHand.instanceId);
|
if (!wielder.displayed.includes(inHand.instanceId)) wielder.displayed.push(inHand.instanceId);
|
||||||
events.push({ type: "wandCharged", player: wielder.id, card: inHand, charges });
|
events.push({ type: "wandCharged", player: wielder.id, card: inHand, charges });
|
||||||
|
|||||||
@@ -12,11 +12,6 @@ describe("magic wands", () => {
|
|||||||
const wand = giveCard(state, attacker, "blaster-wand");
|
const wand = giveCard(state, attacker, "blaster-wand");
|
||||||
giveCard(state, attacker, "number-2", "N", 1);
|
giveCard(state, attacker, "number-2", "N", 1);
|
||||||
|
|
||||||
// First use without a number card is refused.
|
|
||||||
expect(applyCommand(state, attacker, {
|
|
||||||
type: "cast", instanceId: wand.instanceId, target: { kind: "player", playerId: defender },
|
|
||||||
}).ok).toBe(false);
|
|
||||||
|
|
||||||
// Charged with a 2: fires (3 damage), one charge left, wand displayed.
|
// Charged with a 2: fires (3 damage), one charge left, wand displayed.
|
||||||
state = must(state, attacker, {
|
state = must(state, attacker, {
|
||||||
type: "cast", instanceId: wand.instanceId, numberInstanceIds: ["number-2#N"],
|
type: "cast", instanceId: wand.instanceId, numberInstanceIds: ["number-2#N"],
|
||||||
@@ -210,3 +205,20 @@ describe("dropping objects", () => {
|
|||||||
expect(refused.ok).toBe(false);
|
expect(refused.ok).toBe(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("a bare wand lights a single charge", () => {
|
||||||
|
it("'played without a number card, its power is only 1': one shot, then dust", () => {
|
||||||
|
let { state } = newGame();
|
||||||
|
state = toRound2(state);
|
||||||
|
const { attacker, defender } = faceOff(state);
|
||||||
|
const bw = giveCard(state, attacker, "blaster-wand");
|
||||||
|
state = must(state, attacker, {
|
||||||
|
type: "cast", instanceId: bw.instanceId, target: { kind: "player", playerId: defender },
|
||||||
|
});
|
||||||
|
state = must(state, defender, { type: "pass" });
|
||||||
|
// The single charge fired (3 flat damage) and the wand crumbled.
|
||||||
|
expect(state.players.find((p) => p.id === defender)!.life).toBe(12);
|
||||||
|
expect(state.players.find((p) => p.id === attacker)!.hand.some((c) => c.cardId === "blaster-wand")).toBe(false);
|
||||||
|
expect(state.wandCharges[bw.instanceId]).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1818,7 +1818,7 @@
|
|||||||
<span>— {EDGE_HINTS[selectedCard.cardId] ?? "click a wall line"}</span>
|
<span>— {EDGE_HINTS[selectedCard.cardId] ?? "click a wall line"}</span>
|
||||||
{/if}
|
{/if}
|
||||||
{#if selectedCard && WAND_IDS.has(selectedCard.cardId) && view.wandCharges[selectedCard.instanceId] == null && !attachedNumber}
|
{#if selectedCard && WAND_IDS.has(selectedCard.cardId) && view.wandCharges[selectedCard.instanceId] == null && !attachedNumber}
|
||||||
<span>— first use: tap a NUMBER card to set the wand's charges, then click a target</span>
|
<span>— first use sets the charges: tap a NUMBER card first, or cast bare for a single charge</span>
|
||||||
{:else if selectedDef.cardType === "attack" && !cellSelectMode && !EDGE_CARDS.has(selectedCard?.cardId ?? "")}
|
{:else if selectedDef.cardType === "attack" && !cellSelectMode && !EDGE_CARDS.has(selectedCard?.cardId ?? "")}
|
||||||
<span>— click a target, or a wall line to batter it{attachedNumber ? ` (powered by a ${numberTotal})` : ""}</span>
|
<span>— click a target, or a wall line to batter it{attachedNumber ? ` (powered by a ${numberTotal})` : ""}</span>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user