diff --git a/packages/web/src/App.svelte b/packages/web/src/App.svelte index b2b0465..29d88e8 100644 --- a/packages/web/src/App.svelte +++ b/packages/web/src/App.svelte @@ -38,6 +38,8 @@ let rotateCW = $state(true); /** Cards marked for discard. */ let discardSelection = $state>(new Set()); + /** Voluntary discard mode: hand clicks mark cards instead of playing them. */ + let discardMode = $state(false); const view = $derived(net.view); const isYourTurn = $derived(view !== null && view.activePlayerId === view.you && !view.stack); @@ -61,9 +63,7 @@ const TWO_CELL_CARDS = new Set(["trader", "dimensional-warp", "redirection"]); const CREATURE_TARGET_CARDS = new Set(["mega-monster"]); const MODIFIER_CARDS = new Set(["amplify", "add", "extend", "around-the-corner"]); - const SELF_CARDS = new Set([ - "invisible", "shrink", "mist-body", "strength", "empathy", "big-man", "fear", "adrenaline", - ]); + const NAMED_CARDS = new Set(["card-erasure", "drop-object", "deja-vu", "thief", "swap-meet", "remove-curse", "swarthmores-enchantment", "illusionary-attack"]); const edgeSelectMode = $derived(selectedCard != null && EDGE_CARDS.has(selectedCard.cardId)); const cellSelectMode = $derived( @@ -111,7 +111,7 @@ net.command({ type: "counteract", instanceId: card.instanceId }); return; } - if (youMustDiscard || discardSelection.size > 0) { + if (youMustDiscard || discardMode || discardSelection.size > 0) { const next = new Set(discardSelection); next.has(card.instanceId) ? next.delete(card.instanceId) : next.add(card.instanceId); discardSelection = next; @@ -135,24 +135,32 @@ } selectedCard = card; attachedNumber = null; - if (isNumberCard(card.cardId)) { - // A bare number card: play it for movement. - net.command({ type: "playNumberForMovement", instanceId: card.instanceId }); - clearSelection(); - return; - } - // Instant untargeted spells (and stone displays) cast immediately; - // duration self-spells wait so a number card can be attached. - const INSTANT = new Set([ - "speed", "pass-through-wall", "reuse-spell", "ugly", "alter-ego", "lifesaver", "mad-dash", - "gift-from-above", "chaos", "interrupt", "opportunity-fire", - "bloodstone", "brainstone", "powerstone", "shadowstone", - "shieldstone", "soulstone", "speedstone", "visionstone", - ]); - if (INSTANT.has(card.cardId)) { - net.command({ type: "cast", instanceId: card.instanceId }); - clearSelection(); - } + // Nothing casts on first click: every play is confirmed from the hint + // bar or by choosing a target. Misclicks cost nothing. + } + + /** Untargeted spells confirmed from the hint bar (with optional number). */ + const CONFIRM_CAST = new Set([ + "speed", "pass-through-wall", "reuse-spell", "ugly", "alter-ego", "lifesaver", "mad-dash", + "gift-from-above", "chaos", "interrupt", "opportunity-fire", + "bloodstone", "brainstone", "powerstone", "shadowstone", + "shieldstone", "soulstone", "speedstone", "visionstone", + "invisible", "shrink", "mist-body", "strength", "empathy", "big-man", "fear", "adrenaline", + ]); + + function playNumberForMovement() { + if (!selectedCard) return; + net.command({ type: "playNumberForMovement", instanceId: selectedCard.instanceId }); + clearSelection(); + } + + function startDiscardMode() { + clearSelection(); + discardMode = true; + } + function cancelDiscardMode() { + discardMode = false; + discardSelection = new Set(); } function castSelfWithNumber() { @@ -351,6 +359,7 @@ function doDiscard() { net.command({ type: "discard", instanceIds: [...discardSelection] }); discardSelection = new Set(); + discardMode = false; } function endTurn() { @@ -519,14 +528,19 @@
- {#if selectedDef || youMustDiscard || discardSelection.size > 0} + {#if selectedDef || youMustDiscard || discardMode || discardSelection.size > 0}
{#if youMustDiscard} Hand over the limit — mark cards and discard. + {:else if discardMode && discardSelection.size === 0} + Mark the cards to throw away, then confirm. {/if} {#if discardSelection.size > 0} {/if} + {#if discardMode || (discardSelection.size > 0 && !youMustDiscard)} + + {/if} {#if selectedDef} {selectedDef.name} {#if edgeSelectMode}— click a wall line{/if} @@ -571,9 +585,14 @@ {/if} - {#if selectedCard && SELF_CARDS.has(selectedCard.cardId)} + {#if selectedCard && CONFIRM_CAST.has(selectedCard.cardId)} + {/if} + {#if selectedCard && isNumberCard(selectedCard.cardId)} + {/if} @@ -589,6 +608,7 @@ +