Rematches, seats that travel by phrase, the keeper's bell with the hour where they live, the host's leave for the gallery to talk, and seats doubted before they are dropped
Ported from Wiz-War, where each earned its keep. All on the ledger: galleryTalk, challenge and rematch lines, gallery chat signed with a name, held seats on a rematch table's room line. Twenty-two protocol checks against a scratch server and a replay after restart. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
65d62f2ab3
commit
6dce3b82f0
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { page } from '$app/state';
|
||||
import Board from '$lib/components/Board.svelte';
|
||||
import Lobby from '$lib/components/Lobby.svelte';
|
||||
@@ -15,6 +16,9 @@
|
||||
let error = $state('');
|
||||
let copied = $state(false);
|
||||
let reporting = $state(false);
|
||||
/** A phrase minted to carry this seat to another device, while it lasts. */
|
||||
let phrase = $state<{ phrase: string; expiresAt: number } | null>(null);
|
||||
let rematching = $state(false);
|
||||
|
||||
const link = $derived(typeof location === 'undefined' ? '' : `${location.origin}/join/${roomId}`);
|
||||
const watching = $derived(room?.spectating ?? false);
|
||||
@@ -64,6 +68,29 @@
|
||||
// The link is on screen to copy by hand.
|
||||
}
|
||||
}
|
||||
|
||||
async function transfer() {
|
||||
if (!room) return;
|
||||
try {
|
||||
phrase = await room.transfer();
|
||||
setTimeout(() => (phrase = null), Math.max(0, phrase.expiresAt - Date.now()));
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'The seat could not be offered.';
|
||||
}
|
||||
}
|
||||
|
||||
/** Call for a rematch, or take the seat held at one already called. */
|
||||
async function rematch() {
|
||||
if (!room) return;
|
||||
rematching = true;
|
||||
try {
|
||||
await goto(`/join/${await room.rematch()}`);
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : 'The rematch could not be called.';
|
||||
} finally {
|
||||
rematching = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -87,7 +114,10 @@
|
||||
<span class="muted">{watching ? 'watching · room' : 'invite friends · room'}</span> <b>{roomId}</b>{copied ? ' · link copied' : ''}
|
||||
</button>
|
||||
{#if room.view.audience > 0}
|
||||
<span class="audience" title="the Peanut Gallery">{room.view.audience} in the gallery</span>
|
||||
<span class="audience" title="the Peanut Gallery">{room.view.audience} in the gallery{room.view.galleryTalk ? ', talking' : ''}</span>
|
||||
{/if}
|
||||
{#if !watching}
|
||||
<button type="button" class="quiet" title="A phrase that brings this seat to another device" onclick={transfer}>Transfer seat</button>
|
||||
{/if}
|
||||
{/if}
|
||||
<a class="quiet" href="/guide">How to play</a>
|
||||
@@ -107,6 +137,22 @@
|
||||
<p class="notice">{error}</p>
|
||||
{/if}
|
||||
|
||||
{#if phrase}
|
||||
<p class="notice muted">On the other device, open the hall and claim this phrase within ten minutes: <b class="phrase">{phrase.phrase}</b></p>
|
||||
{/if}
|
||||
|
||||
{#if room?.view.over && !watching}
|
||||
<p class="notice muted">
|
||||
{#if room.view.rematch}
|
||||
{room.nameOf(room.view.rematch.by)} called for a rematch at table {room.view.rematch.to}.
|
||||
<a href={`/join/${room.view.rematch.to}`}>Take your seat</a>
|
||||
{:else}
|
||||
<button type="button" class="quiet" disabled={rematching} onclick={rematch}>Rematch with this table</button>
|
||||
<span>the same company, at a new table; seats are held for everyone here.</span>
|
||||
{/if}
|
||||
</p>
|
||||
{/if}
|
||||
|
||||
{#if joining && seatFree}
|
||||
<section class="seat">
|
||||
<p class="eyebrow">room {roomId}</p>
|
||||
@@ -193,6 +239,11 @@
|
||||
color: var(--bone-dim);
|
||||
}
|
||||
|
||||
.phrase {
|
||||
letter-spacing: 0.06em;
|
||||
user-select: all;
|
||||
}
|
||||
|
||||
.seat {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
|
||||
Reference in New Issue
Block a user