| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
import { roundOutcome } from "./prompt.js"; |
| 13 |
|
| 14 |
|
| 15 |
export const watching = (snap) => Boolean(snap) && (snap.spectator === true || !snap.me); |
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
const WHY = { |
| 21 |
address: "Somebody at this address is already playing — that tab holds the seat, and this one watches.", |
| 22 |
cookie: "This browser did not send the session cookie the page sets, so there is no seat to give it.", |
| 23 |
}; |
| 24 |
const WHY_UNSAID = "This connection has no seat, so it is watching the match."; |
| 25 |
|
| 26 |
const PHASE = { buy: "buy phase", live: "live", end: "round over" }; |
| 27 |
|
| 28 |
|
| 29 |
export function watchLines(snap) { |
| 30 |
const score = snap.score ?? { red: 0, blue: 0 }; |
| 31 |
|
| 32 |
|
| 33 |
const outcome = snap.phase === "end" ? roundOutcome(snap) : null; |
| 34 |
const turned = outcome ? ` — ${outcome.winner} take it, ${outcome.why}` : ""; |
| 35 |
return { |
| 36 |
title: "watching", |
| 37 |
why: WHY[snap.why] ?? WHY_UNSAID, |
| 38 |
phase: `round ${snap.round ?? 1} · ${PHASE[snap.phase] ?? "match over"}${turned} · ${snap.attackers ?? "—"} attacking${snap.result ? " · " + snap.result : ""}`, |
| 39 |
score: `red ${score.red ?? 0} — ${score.blue ?? 0} blue`, |
| 40 |
clock: `${Math.ceil(Math.max(0, Number(snap.clock) || 0))}s`, |
| 41 |
note: "No map and no bodies: a watching connection is never told where anybody is.", |
| 42 |
}; |
| 43 |
} |
| 44 |
|
| 45 |
|
| 46 |
export function wrap(ctx, text, maxWidth) { |
| 47 |
const lines = []; |
| 48 |
let line = ""; |
| 49 |
for (const word of String(text).split(" ")) { |
| 50 |
const tried = line ? `${line} ${word}` : word; |
| 51 |
if (line && ctx.measureText(tried).width > maxWidth) { |
| 52 |
lines.push(line); |
| 53 |
line = word; |
| 54 |
} else line = tried; |
| 55 |
} |
| 56 |
if (line) lines.push(line); |
| 57 |
return lines; |
| 58 |
} |
| 59 |
|
| 60 |
|
| 61 |
|
| 62 |
|
| 63 |
|
| 64 |
|
| 65 |
export function drawWatching(ctx, snap, width, height) { |
| 66 |
const lines = watchLines(snap); |
| 67 |
const mid = width / 2; |
| 68 |
const unit = Math.min(width / 900, height / 570); |
| 69 |
ctx.fillStyle = "#0b0d11"; |
| 70 |
ctx.fillRect(0, 0, width, height); |
| 71 |
ctx.textAlign = "center"; |
| 72 |
|
| 73 |
ctx.fillStyle = "#8b93a5"; |
| 74 |
ctx.font = `${Math.round(22 * unit)}px system-ui, sans-serif`; |
| 75 |
ctx.fillText(lines.title, mid, height * 0.3); |
| 76 |
|
| 77 |
ctx.fillStyle = "#e7e9ee"; |
| 78 |
ctx.font = `${Math.round(54 * unit)}px system-ui, sans-serif`; |
| 79 |
ctx.fillText(lines.score, mid, height * 0.42); |
| 80 |
|
| 81 |
ctx.font = `${Math.round(30 * unit)}px system-ui, sans-serif`; |
| 82 |
ctx.fillText(lines.clock, mid, height * 0.52); |
| 83 |
|
| 84 |
ctx.fillStyle = "#b9c0cf"; |
| 85 |
ctx.font = `${Math.round(19 * unit)}px system-ui, sans-serif`; |
| 86 |
ctx.fillText(lines.phase, mid, height * 0.6); |
| 87 |
|
| 88 |
ctx.fillStyle = "#8b93a5"; |
| 89 |
ctx.font = `${Math.round(17 * unit)}px system-ui, sans-serif`; |
| 90 |
let y = height * 0.7; |
| 91 |
for (const line of [...wrap(ctx, lines.why, width * 0.8), ...wrap(ctx, lines.note, width * 0.8)]) { |
| 92 |
ctx.fillText(line, mid, y); |
| 93 |
y += 24 * unit; |
| 94 |
} |
| 95 |
ctx.textAlign = "left"; |
| 96 |
return lines; |
| 97 |
} |