88 lines
3.1 KiB
TypeScript
88 lines
3.1 KiB
TypeScript
import { useGame } from '../useGame'
|
|
import type { Session } from '../types'
|
|
import { Lobby } from './Lobby'
|
|
import { ShopPhase } from './ShopPhase'
|
|
import { ArrangePhase } from './ArrangePhase'
|
|
import { BattlePhase } from './BattlePhase'
|
|
import { GameOver } from './GameOver'
|
|
import { DebugPanel } from './DebugPanel'
|
|
import { EventLog } from './EventLog'
|
|
|
|
// Table connects to the game and routes to the right phase screen.
|
|
export function Table({ session, onLeave }: { session: Session; onLeave: () => void }) {
|
|
const { view, error, connected, send } = useGame(session)
|
|
|
|
if (!view) {
|
|
return (
|
|
<div className="centered muted">
|
|
{connected ? 'Loading game…' : 'Connecting…'}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
const you = view.players[view.youSeat]
|
|
const opponents = view.players.filter((p) => p.seat !== view.youSeat)
|
|
|
|
return (
|
|
<div className="table">
|
|
<header className="topbar">
|
|
<div className="topbar-brand" title="Super Auto Pets: The Board Game">
|
|
🐾 <span>SAP</span>
|
|
</div>
|
|
{view.phase !== 'gameover' && (
|
|
<div className="topbar-round">
|
|
Round <strong>{view.round}</strong> / {view.maxRounds}
|
|
</div>
|
|
)}
|
|
<div className="topbar-players">
|
|
{view.players.map((p) => (
|
|
<div
|
|
key={p.id}
|
|
className={`topbar-player ${p.seat === view.youSeat ? 'is-you' : ''}`}
|
|
>
|
|
<span className={`conn-dot ${p.connected ? 'on' : 'off'}`} />
|
|
<span className="topbar-name">{p.name}</span>
|
|
<span className="chip">🏆 {p.trophies}</span>
|
|
{(view.phase === 'shop' || view.phase === 'cleanup') && (
|
|
<span className="chip">🪙 {p.coins}</span>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
<div className="topbar-code" title="Share this code with your opponent">
|
|
{view.code}
|
|
</div>
|
|
<button className="btn btn-ghost btn-sm" onClick={onLeave}>
|
|
Leave
|
|
</button>
|
|
</header>
|
|
|
|
<div className="table-body">
|
|
<main className="table-main">
|
|
{view.phase === 'lobby' && <Lobby view={view} />}
|
|
{(view.phase === 'shop' || view.phase === 'cleanup') && (
|
|
<ShopPhase view={view} you={you} send={send} />
|
|
)}
|
|
{view.phase === 'arrange' && <ArrangePhase view={view} you={you} send={send} />}
|
|
{view.phase === 'battle' && <BattlePhase view={view} send={send} />}
|
|
{view.phase === 'gameover' && <GameOver view={view} onLeave={onLeave} />}
|
|
</main>
|
|
{view.phase !== 'lobby' && (
|
|
<EventLog entries={view.log ?? []} youSeat={view.youSeat} />
|
|
)}
|
|
</div>
|
|
|
|
{opponents.some((p) => !p.connected) && view.phase !== 'lobby' && (
|
|
<div className="banner banner-warn">An opponent is disconnected…</div>
|
|
)}
|
|
{error && <div className="toast">{error}</div>}
|
|
{view.debug && (
|
|
<DebugPanel
|
|
canGrant={view.phase === 'shop' || view.phase === 'cleanup'}
|
|
send={send}
|
|
/>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|