Fix silently-dropped log entries past the 40-line cap, add pause, clarify locations panel
Docker / build-and-push (push) Successful in 42s

- The log view only re-rendered when state.log.length changed, but the
  log is capped at 40 entries — so once a run had logged 40+ things
  (easy in a normal session), every entry after that point, including
  choice-event outcomes, upgrade purchases, and location visits,
  stopped appearing even though the underlying state updated. Fixed
  by tracking a monotonic logSeq counter that increments on every
  push regardless of the cap, and rendering off that instead of
  array length. Consolidated the repeated unshift+cap logic into one
  pushLog() helper so future call sites can't reintroduce the bug.
- Added a pause button (and "PAUSAD" indicator) that freezes the tick
  loop without touching game state, so a hectic run can be paused to
  think without it counting as a save-scummy state mutation. Manual
  actions (buying upgrades, visiting locations) still work while
  paused, since that's usually the point of pausing.
- The "Aktiva områden" sidebar only ever listed the 3 story-gated
  core areas, while the map has 7 clickable locations — making it
  look like 4 of the map pins didn't really exist. Split the panel
  into "Ritualens kärnplatser" (the 3 gated ones, unlock status shown
  as before) and "Övriga platser" (the 4 always-open flavor
  locations), so the sidebar and map agree.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Fredrik Johansson
2026-07-13 16:49:37 +02:00
co-authored by Claude Sonnet 5
parent 4b4e5c14aa
commit b7c052a11f
5 changed files with 71 additions and 31 deletions
+24 -5
View File
@@ -9,12 +9,14 @@ export function initUI(
onEventChoice: (index: number) => void,
onStart: () => void,
onAbandon: () => void,
onTogglePause: () => void,
): void {
app.innerHTML = `
<div id="header">
<div class="brand">DJUPET</div>
<div class="brand-sub">Malmö, Sverige · <span id="phase-tag" class="phase-tag early">Tidigt skede</span></div>
<div class="brand-sub">Malmö, Sverige · <span id="phase-tag" class="phase-tag early">Tidigt skede</span><span id="pause-tag" class="pause-tag"></span></div>
<div class="header-actions">
<button id="pause-btn" class="help-btn" title="Pausa spelet">Pausa</button>
<button id="abandon-btn" class="help-btn" title="Överge kulten">Avbryt</button>
<button id="help-btn" class="help-btn" title="Hjälp &amp; Ändringslogg">? v${VERSION}</button>
</div>
@@ -126,12 +128,21 @@ export function initUI(
</div>
<div class="panel" id="panel-right">
<div class="panel-title">Aktiva områden</div>
<div class="panel-title">Ritualens kärnplatser</div>
<div id="areas" style="font-size:11px;color:var(--dim);line-height:2;">
<div id="area-rosengard">○ Rosengård</div>
<div id="area-varnhem">○ Värnhemstorget</div>
<div id="area-torso">○ Turning Torso</div>
</div>
<div style="margin-top:16px;">
<div class="panel-title">Övriga platser</div>
<div style="font-size:11px;color:var(--dim);line-height:2;">
<div>Øresundsbron</div>
<div>Ribersborgsstranden</div>
<div>Davidshallsgatan</div>
<div>Stortorget</div>
</div>
</div>
<div style="margin-top:20px;" id="investigator-section">
<div class="panel-title">Utredarna</div>
<div id="investigator-status" style="font-size:11px;color:var(--safe);">Inaktiva</div>
@@ -163,6 +174,7 @@ export function initUI(
document.getElementById('abandon-btn')!.addEventListener('click', () => {
if (window.confirm('Överge kulten? Cirkeln bryts och ni går skilda vägar.')) onAbandon();
});
document.getElementById('pause-btn')!.addEventListener('click', onTogglePause);
document.getElementById('event-modal-choices')!.addEventListener('click', e => {
const btn = (e.target as Element).closest('[data-choice]') as HTMLElement | null;
@@ -320,12 +332,12 @@ function renderUpgrades(state: State): void {
}).join('');
}
let lastLogLength = 0;
let lastLogSeq = -1;
function renderLog(state: State): void {
const log = document.getElementById('log')!;
if (state.log.length === lastLogLength) return;
lastLogLength = state.log.length;
if (state.logSeq === lastLogSeq) return;
lastLogSeq = state.logSeq;
// state.log is newest-first (unshift); render as-is, scroll to top
log.innerHTML = state.log.map(e =>
`<div class="log-entry ${e.kind}">${e.text}</div>`
@@ -363,6 +375,13 @@ function showOverlay(state: State): void {
}
}
export function setPausedUI(paused: boolean): void {
const btn = document.getElementById('pause-btn')!;
btn.textContent = paused ? 'Fortsätt' : 'Pausa';
document.getElementById('app')!.classList.toggle('paused', paused);
setText('pause-tag', paused ? '⏸ Pausad' : '');
}
function setText(id: string, val: string): void {
const el = document.getElementById(id);
if (el) el.textContent = val;