Daggers, rocks, blades, and wands can be set down too
The rulebook's movable-object list is wider than the stones: "magic stones, treasure chests, the dagger, the large rock, and the wizardblade" — and the expansion expects wands to change hands, since "its remaining charges go with it." A new isMovableObject helper in the engine names that full set, doDropObject honors it, and the hint bar's "Drop it here" button follows suit. Charges are keyed by card instance, so a dropped wand carries them to whoever picks it up — covered by new tests, along with the refusal to drop spell cards. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c04ed1e0ee
commit
789d927122
@@ -198,3 +198,52 @@ describe("magic wands", () => {
|
||||
expect(state.players.find((p) => p.id === me.id)!.hand.some((c) => c.cardId === "fireball")).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("dropping objects", () => {
|
||||
it("a charged wand can be dropped and picked up, charges intact", () => {
|
||||
let { state } = newGame();
|
||||
state = toRound2(state);
|
||||
const { attacker, defender } = faceOff(state);
|
||||
const wand = giveCard(state, attacker, "blaster-wand");
|
||||
giveCard(state, attacker, "number-3", "N", 1);
|
||||
|
||||
// Charge it with a 3 (one charge spent on the shot, two remain).
|
||||
state = must(state, attacker, {
|
||||
type: "cast", instanceId: wand.instanceId, numberInstanceIds: ["number-3#N"],
|
||||
target: { kind: "player", playerId: defender },
|
||||
});
|
||||
state = must(state, defender, { type: "pass" });
|
||||
expect(state.wandCharges[wand.instanceId]).toBe(2);
|
||||
|
||||
// Set it down: leaves the hand and the displayed list, lands on the floor.
|
||||
state = must(state, attacker, { type: "dropObject", instanceId: wand.instanceId });
|
||||
const owner = state.players.find((p) => p.id === attacker)!;
|
||||
expect(owner.hand.some((c) => c.instanceId === wand.instanceId)).toBe(false);
|
||||
expect(owner.displayed.includes(wand.instanceId)).toBe(false);
|
||||
const key = cellKey(owner.position);
|
||||
expect((state.groundObjects[key] ?? []).some((c) => c.instanceId === wand.instanceId)).toBe(true);
|
||||
|
||||
// The wizard standing there picks it up on their turn — charges travel.
|
||||
state = must(state, attacker, { type: "endTurn", draw: 0 });
|
||||
state = must(state, defender, { type: "pickUpObject", instanceId: wand.instanceId });
|
||||
const thief = state.players.find((p) => p.id === defender)!;
|
||||
expect(thief.hand.some((c) => c.instanceId === wand.instanceId)).toBe(true);
|
||||
expect(state.wandCharges[wand.instanceId]).toBe(2);
|
||||
expect(state.players.find((p) => p.id === defender)!.id).toBe(activePlayer(state).id);
|
||||
});
|
||||
|
||||
it("the dagger and wizardblade can be set down; spell cards cannot", () => {
|
||||
let { state } = newGame();
|
||||
state = toRound2(state);
|
||||
const who = activePlayer(state).id;
|
||||
const dagger = giveCard(state, who, "dagger");
|
||||
const fireball = giveCard(state, who, "fireball", "F", 1);
|
||||
|
||||
state = must(state, who, { type: "dropObject", instanceId: dagger.instanceId });
|
||||
expect((state.groundObjects[cellKey(activePlayer(state).position)] ?? [])
|
||||
.some((c) => c.cardId === "dagger")).toBe(true);
|
||||
|
||||
const refused = applyCommand(state, who, { type: "dropObject", instanceId: fireball.instanceId });
|
||||
expect(refused.ok).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user