Back to City Breaker
SOURCE / PINNED RELEASE

Made of little things.

City Breaker

Release
94d2b8664b10…
Author-recorded commit
df23103cbcc1…
License
LICENSE
Author’s source reference
nostr://npub1sj2vketepqw9v6fmge5fdzuj7atj9sv6qv2jss05n2z6rl64lcfqumdsnt/wss%3A%2F%2Fgit.napplet.soy%2F/n-cf8b858653e

Archive hash verified: eeeed725668c1ece…. The source-to-build association is the author’s claim; it has not been independently rebuilt.

src/ui/end.ts
// End of campaign: the numbers, then the honest after-action summary.
import { afterAction } from '../game/campaign';
import { fmtTime, type GameState } from '../game/state';
import { bind, esc } from './dom';

export class EndView {
  constructor(private root: HTMLElement, s: GameState, onNew: () => void) {
    this.root.replaceChildren();
    this.root.className = 'screen end';
    const e = s.ended!;
    const aa = afterAction(s);
    const title = e.outcome === 'win' ? 'The city is broken' : e.outcome === 'partial' ? 'The offensive goes in anyway' : 'Hafenstadt endures';
    this.root.innerHTML = `<div class="end-in">
      <div class="end-k">${esc(fmtTime(e.hour))} · ${e.outcome.toUpperCase()}</div>
      <div class="end-t">${esc(title)}</div>
      <p class="end-reason">${esc(e.reason)}</p>
      <div class="end-cols">
        <table class="stats">${aa.stats.map(([k, v]) => `<tr><th>${esc(k)}</th><td>${esc(v)}</td></tr>`).join('')}</table>
        <div class="ussbs">
          <div class="ussbs-k">Strategic bombing survey — summary report</div>
          ${aa.paragraphs.map((p) => `<p>${esc(p)}</p>`).join('')}
        </div>
      </div>
      <button type="button" class="primary big" data-act="new" data-tip="Start over with a new 60-day campaign. The city will be different this time.">New campaign</button>
    </div>`;
    bind(this.root, { new: () => onNew() });
  }

  destroy(): void {
    /* static */
  }
}