Object-ness comes from the card face, not a parallel list

'This is most certainly an object' (WIZARDBLADE's FAQ) — and the card
data already says so: every physical item bears the OBJECT subtype on
its face. isMovableObject now reads it from there, retiring the
hand-kept list — which had missed MASTER KEY and HANDFUL OF TACKS,
both object-marked. Ungated: no stored ledger holds a swap or drop
this widens (verified against production), and refused commands are
never recorded.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
Eric Wagoner
2026-08-17 22:39:46 -04:00
co-authored by Claude Fable 5
parent 2bb2ca62d8
commit 5351e345c3
+7 -10
View File
@@ -5689,18 +5689,15 @@ function doPickUpObject(prev: GameState, instanceId: string): CommandResult {
}
/**
* Physical, droppable objects beyond the object-type stones. Rulebook:
* "Movable objects include magic stones, treasure chests, the dagger, the
* large rock, and the wizardblade"plus the expansion wands, which the
* rules expect to change hands ("its remaining charges go with it";
* charges are keyed by instance, so they travel automatically).
* A physical, droppable object is anything the card face marks as one —
* the object-typed stones, and attack/neutral cards bearing the OBJECT
* subtype (dagger, rock, wizardblade — "this is most certainly an object",
* per its FAQ — the wands, the master key, the handful of tacks). Wand
* charges are keyed by instance, so they travel with a traded wand.
*/
const MOVABLE_OBJECT_CARD_IDS = new Set([
"dagger", "large-rock", "wizardblade", ...WAND_CARD_IDS,
]);
export function isMovableObject(cardId: string): boolean {
return cardDef(cardId).cardType === "object" || MOVABLE_OBJECT_CARD_IDS.has(cardId);
const def = cardDef(cardId);
return def.cardType === "object" || (def.subtypes?.includes("object") ?? false);
}
function doDropObject(prev: GameState, instanceId: string): CommandResult {