/** * The page. The first paint is the match as it stands right now — score, * round, phase, scoreboard — server-rendered HTML, so somebody arriving with * a cold cache or no JavaScript still sees a live match. The client script * then takes the same state over a socket and draws it. */ import { AGENTS } from "../abilities.ts"; import type { Result } from "../db.ts"; import type { MatchState } from "../state.ts"; import { WEAPONS, weaponIds } from "../weapons.ts"; export const escape = (s: string): string => s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[c] ?? c); const phaseWord = (state: MatchState): string => state.phase === "buy" ? "buy phase" : state.phase === "live" ? state.spike.planted ? `spike down · ${Math.ceil(state.spike.fuse)}s` : "live" : state.phase === "end" ? "round over" : "match over"; export function gamePage(opts: { state: MatchState; script: string; name: string; env: string; commit: string; ssh: string | undefined; results: Result[]; }): string { const { state } = opts; const board = [...state.players].sort((a, b) => b.kills - a.kills); const row = (side: "atk" | "def"): string => board .filter((p) => p.side === side) .map( (p) => `${escape(p.name)}${p.bot ? " bot" : ""}${escape(p.agent)}${p.kills}${p.deaths}`, ) .join(""); return ` val — attack, defend, plant the spike

val

${escape(opts.env)}${opts.commit ? " @ " + escape(opts.commit) : ""} connecting…
red ${state.score.red} ${Math.max(0, Math.ceil(state.clock))} ${state.score.blue} blue
round ${state.round} · ${escape(phaseWord(state))} · ${escape(state.attackers)} attacking${state.result ? ` · ${escape(state.result)}` : ""}
click to aim · esc releases
waiting for the next round
Click the map to aim, then press H for how to play.
100 hp Classic 12 800 cr ult 0/6
Buy phase — credits are refused server-side if you cannot afford them.
${AGENTS.map( (a) => ``, ).join("")}
${weaponIds() .map( (id) => ``, ) .join("")}
${state.events .slice(0, 3) .map((e) => `
${escape(e.text)}
`) .join("")}

attackers

${row("atk")}
playeragentkd

defenders

${row("def")}
playeragentkd
`; }