import { useMemo, useState } from "react"; import { eventIcon, severityClass } from "../eventDecor"; import type { GameLogEventSnapshot, WorldSnapshot } from "../types"; type GameOverOverlayProps = { snapshot: WorldSnapshot; events: GameLogEventSnapshot[]; }; const RESULT_COPY: Record = { win_population: { title: "THE WORLD PREVAILS", subtitle: "The countries reached the population goal.", tone: "win", }, win_survival: { title: "THE WORLD ENDURES", subtitle: "The countries survived the pressure of the world.", tone: "win", }, lose: { title: "THE WORLD HAS FALLEN", subtitle: "No citizen drew breath at the end.", tone: "lose", }, }; export function GameOverOverlay({ snapshot, events }: GameOverOverlayProps) { const [isDismissed, setIsDismissed] = useState(false); const status = snapshot.simulation.game_status ?? "running"; const copy = RESULT_COPY[status]; const stats = snapshot.simulation.stats; const totalDeaths = Object.values(stats?.deaths_by_cause ?? {}).reduce( (sum, count) => sum + count, 0, ); const betrayals = useMemo( () => events.filter((event) => event.type === "steal" || event.type === "treasury_stolen").length, [events], ); const storyEvents = useMemo( () => events .filter((event) => [ "npc_born", "npc_died", "build_completed", "house_destroyed", "beast_killed", "election_completed", "policy_updated", "cannon_crafted", "cannon_fired", "game_over", ].includes(event.type), ) .slice(-14), [events], ); if (!copy || isDismissed) { return null; } return (

{copy.title}

{copy.subtitle}

{Object.keys(stats?.deaths_by_cause ?? {}).length > 0 ? (

Causes of death:{" "} {Object.entries(stats?.deaths_by_cause ?? {}) .map(([cause, count]) => `${cause.replaceAll("_", " ")} x${count}`) .join(", ")}

) : null} {storyEvents.length > 0 ? (

The world's story

{storyEvents.map((event, index) => (
{event.tick} {eventIcon(event.type)} {event.summary}
))}
) : null}
); } function Stat({ label, value }: { label: string; value: number }) { return (
{value} {label}
); }