A treasure carried home says so, and a turn out of steps points at End turn
A first-time player banked a stolen chest, stepped off with no moves left, and left (NQ6S): the score changed only in the turn bar's quiet tally, and a still board with no word read as a game that had stopped. Now a slip announces the score for the rest of the turn, and once the steps are spent the turn bar says to cast or end the turn while End turn beckons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
ceb22a9898
commit
aeb58bdf4a
@@ -1756,6 +1756,20 @@
|
|||||||
view && me ? view.treasures.filter((t) => t.owner !== me!.id && t.position &&
|
view && me ? view.treasures.filter((t) => t.owner !== me!.id && t.position &&
|
||||||
t.position.x === me!.home.x && t.position.y === me!.home.y).length : 0,
|
t.position.x === me!.home.x && t.position.y === me!.home.y).length : 0,
|
||||||
);
|
);
|
||||||
|
/** Chests you carried home THIS turn: the drop is the game's biggest
|
||||||
|
* moment, and the turn bar's quiet tally alone let it pass unremarked. */
|
||||||
|
let scoredThisTurn = $state(0);
|
||||||
|
let scoreTurnKey = "";
|
||||||
|
let homeAtTurnStart = 0;
|
||||||
|
$effect(() => {
|
||||||
|
const key = view && view.activePlayerId === view.you ? `${view.turn.round}:${view.activePlayerId}` : "";
|
||||||
|
if (key !== scoreTurnKey) { scoreTurnKey = key; homeAtTurnStart = treasuresHome; }
|
||||||
|
scoredThisTurn = key ? Math.max(0, treasuresHome - homeAtTurnStart) : 0;
|
||||||
|
});
|
||||||
|
/** Steps spent, actions not: the turn waits on a spell or End turn,
|
||||||
|
* and a still board with no word reads as a game that froze. */
|
||||||
|
const movesSpent = $derived(!!view && view.activePlayerId === view.you && !view.turn.actionsEnded &&
|
||||||
|
view.turn.movementAllowance - view.turn.movementUsed <= 0);
|
||||||
const paBurnable = $derived(me ? Array.from({ length: Math.max(0, me.life - 1) }, (_, i) => i + 1) : []);
|
const paBurnable = $derived(me ? Array.from({ length: Math.max(0, me.life - 1) }, (_, i) => i + 1) : []);
|
||||||
/** Two treasures can share a square: one dispatches, more ask whose. */
|
/** Two treasures can share a square: one dispatches, more ask whose. */
|
||||||
const treasuresHere = $derived(
|
const treasuresHere = $derived(
|
||||||
@@ -3291,8 +3305,16 @@
|
|||||||
{/if}
|
{/if}
|
||||||
{:else}
|
{:else}
|
||||||
{view.turn.movementAllowance - view.turn.movementUsed} moves left{view.turn.attackUsed ? " · attack spent" : ""} · treasures home {treasuresHome} of 2
|
{view.turn.movementAllowance - view.turn.movementUsed} moves left{view.turn.attackUsed ? " · attack spent" : ""} · treasures home {treasuresHome} of 2
|
||||||
|
{#if movesSpent}
|
||||||
|
<div class="goal">Out of steps — cast a spell, or <strong>End turn</strong>.</div>
|
||||||
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{#if scoredThisTurn > 0 && treasuresHome < 2}
|
||||||
|
<div class="slip scored">
|
||||||
|
🏆 <strong>Scored — {treasuresHome} of 2.</strong> One more stolen treasure carried home wins the game.
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if !prefs.coached && !view.turn.actionsEnded}
|
{#if !prefs.coached && !view.turn.actionsEnded}
|
||||||
<!-- A stranger's first turn: what a turn is, before they stare at
|
<!-- A stranger's first turn: what a turn is, before they stare at
|
||||||
seven cards and a maze. Dismissed once, remembered forever. -->
|
seven cards and a maze. Dismissed once, remembered forever. -->
|
||||||
@@ -3658,7 +3680,7 @@
|
|||||||
{:else if net.confirmed}
|
{:else if net.confirmed}
|
||||||
<span class="sending ok" aria-live="polite">✓ {net.confirmed} confirmed</span>
|
<span class="sending ok" aria-live="polite">✓ {net.confirmed} confirmed</span>
|
||||||
{/if}
|
{/if}
|
||||||
<button class="stamp primary" onclick={endTurn} disabled={offline}>End turn</button>
|
<button class="stamp primary" class:beckon={movesSpent} onclick={endTurn} disabled={offline}>End turn</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -4401,6 +4423,14 @@
|
|||||||
.stamp:disabled { opacity: 0.45; cursor: default; }
|
.stamp:disabled { opacity: 0.45; cursor: default; }
|
||||||
.stamp.primary { background: #43331f; color: #e9e1cb; }
|
.stamp.primary { background: #43331f; color: #e9e1cb; }
|
||||||
.stamp.primary:hover:not(:disabled) { background: #5a4429; }
|
.stamp.primary:hover:not(:disabled) { background: #5a4429; }
|
||||||
|
.stamp.beckon:not(:disabled) { animation: beckon 1.6s ease-in-out infinite; }
|
||||||
|
@keyframes beckon {
|
||||||
|
0%, 100% { box-shadow: 2px 2px 0 rgba(0,0,0,0.35), 0 0 0 0 rgba(201, 167, 42, 0); }
|
||||||
|
50% { box-shadow: 2px 2px 0 rgba(0,0,0,0.35), 0 0 0 4px rgba(201, 167, 42, 0.55); }
|
||||||
|
}
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.stamp.beckon:not(:disabled) { animation: none; box-shadow: 0 0 0 3px rgba(201, 167, 42, 0.7); }
|
||||||
|
}
|
||||||
.stamp.big { font-size: 0.95rem; padding: 0.6rem 1.3rem; }
|
.stamp.big { font-size: 0.95rem; padding: 0.6rem 1.3rem; }
|
||||||
.stamp.tiny { font-size: 0.62rem; padding: 0.22rem 0.5rem; box-shadow: 1px 1px 0 rgba(0,0,0,0.3); }
|
.stamp.tiny { font-size: 0.62rem; padding: 0.22rem 0.5rem; box-shadow: 1px 1px 0 rgba(0,0,0,0.3); }
|
||||||
.prefs-slip { text-align: left; }
|
.prefs-slip { text-align: left; }
|
||||||
@@ -4598,6 +4628,7 @@
|
|||||||
.slip.urgent { border-left: 4px solid #b3372b; transform: rotate(0.4deg); }
|
.slip.urgent { border-left: 4px solid #b3372b; transform: rotate(0.4deg); }
|
||||||
.slip.ambush-note { border-left: 4px solid #43331f; font-size: 0.85rem; }
|
.slip.ambush-note { border-left: 4px solid #43331f; font-size: 0.85rem; }
|
||||||
.slip.catchup { border-left: 4px solid #5b3f9e; }
|
.slip.catchup { border-left: 4px solid #5b3f9e; }
|
||||||
|
.slip.scored { border-left: 4px solid #c9a72a; background: #f3e7b8; }
|
||||||
.catchup-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
|
.catchup-head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
|
||||||
.catchup-facts { list-style: none; margin: 0.45rem 0 0; padding: 0; font-size: 0.9rem; }
|
.catchup-facts { list-style: none; margin: 0.45rem 0 0; padding: 0; font-size: 0.9rem; }
|
||||||
.catchup-facts li { margin: 0.15rem 0; }
|
.catchup-facts li { margin: 0.15rem 0; }
|
||||||
|
|||||||
Reference in New Issue
Block a user