Pick your standee: hotseat wizards choose their color while naming
The naming round now shows the six real wizard standees; each player taps theirs before typing their name, claimed standees gray out, and the next player defaults to the first free one. The choice travels as an optional colors array in the engine config, the view exposes each player's colorIndex, and the board, score sheet, treasure chests, and wizard art all follow the chosen color instead of seat order — persisting through hotseat saves. Verified: Alice claimed the yellow standee and marched onto the board as the yellow wizard with yellow treasure chests. (Online rooms still assign by seat order; a lobby color picker can reuse the same config field later.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
98d7dee5c7
commit
77ae65b263
@@ -16,6 +16,13 @@
|
||||
let showHelp = $state(false);
|
||||
let hotseatCount = $state(2);
|
||||
let setupName = $state("");
|
||||
let setupColor = $state(0);
|
||||
// Default each new wizard to the first unclaimed standee.
|
||||
$effect(() => {
|
||||
if (local.setup && local.setup.colors.includes(setupColor)) {
|
||||
setupColor = [0, 1, 2, 3, 4, 5].find((c) => !local.setup!.colors.includes(c)) ?? 0;
|
||||
}
|
||||
});
|
||||
/** Tap-to-inspect: hide the enlarged card for the current selection. */
|
||||
let inspectorHidden = $state(false);
|
||||
$effect(() => {
|
||||
@@ -456,7 +463,8 @@
|
||||
|
||||
const PLAYER_COLORS = ["#1a9c46", "#d3352b", "#c9308f", "#3a3ac0", "#2ab0c9", "#c9a72a"];
|
||||
function playerColor(id: string): string {
|
||||
const idx = view?.players.findIndex((p) => p.id === id) ?? 0;
|
||||
const p = view?.players.find((p) => p.id === id);
|
||||
const idx = p?.colorIndex ?? (view?.players.findIndex((q) => q.id === id) ?? 0);
|
||||
return PLAYER_COLORS[idx % PLAYER_COLORS.length]!;
|
||||
}
|
||||
</script>
|
||||
@@ -503,9 +511,23 @@
|
||||
<div class="handoff-card">
|
||||
<div class="handoff-eyebrow">wizard {local.setup.names.length + 1} of {local.setup.count}</div>
|
||||
<div class="handoff-name setup-title">What is your name?</div>
|
||||
<div class="standee-row" role="group" aria-label="choose your wizard">
|
||||
{#each [0, 1, 2, 3, 4, 5] as c (c)}
|
||||
{@const taken = local.setup.colors.includes(c)}
|
||||
<button
|
||||
class="standee" class:current={setupColor === c} class:taken
|
||||
disabled={taken}
|
||||
style:--ring={PLAYER_COLORS[c]}
|
||||
onclick={() => (setupColor = c)}
|
||||
aria-label={`wizard color ${c + 1}${taken ? " (taken)" : ""}`}
|
||||
>
|
||||
<img src={`/tokens/wizard-${c}.png`} alt="" />
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
<form class="setup-form" onsubmit={(e) => {
|
||||
e.preventDefault();
|
||||
const err = local.submitName(setupName);
|
||||
const err = local.submitName(setupName, setupColor);
|
||||
if (err) net.error = err;
|
||||
else setupName = "";
|
||||
}}>
|
||||
@@ -925,6 +947,26 @@
|
||||
}
|
||||
.handoff-hint { font-size: 0.85rem; color: #6b5a41; margin-top: 0.4rem; }
|
||||
.setup-title { font-size: 2.2rem; }
|
||||
.standee-row {
|
||||
display: flex;
|
||||
gap: 0.45rem;
|
||||
justify-content: center;
|
||||
margin-top: 0.9rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.standee {
|
||||
width: 3.1rem;
|
||||
height: 3.1rem;
|
||||
padding: 0;
|
||||
border: 2.5px solid transparent;
|
||||
border-radius: 6px;
|
||||
background: #f4eede;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
}
|
||||
.standee img { width: 100%; height: 100%; object-fit: cover; display: block; }
|
||||
.standee.current { border-color: var(--ring); box-shadow: 0 0 0 2px rgba(0,0,0,0.15); }
|
||||
.standee.taken { opacity: 0.28; cursor: default; filter: grayscale(0.8); }
|
||||
.setup-form { display: flex; flex-direction: column; gap: 0.7rem; margin-top: 0.8rem; }
|
||||
.setup-input {
|
||||
background: #f4eede;
|
||||
|
||||
Reference in New Issue
Block a user