- Adds a full-screen intro/title screen (new 'intro' game phase) with a moody Malmö/Turning Torso background and a "Börja ritualen" button; the game no longer starts ticking until the player begins. - Win and loss overlays now show matching generated artwork behind the existing text, instead of a flat scrim. - New "Avbryt" header button lets the player abandon a run mid-game (with a confirm prompt) via a new 'abandoned' phase, reusing the existing overlay/restart flow. - Source images converted from PNG (~2.1MB each) to WebP (~120KB each) and placed under public/img/ so Vite serves them as-is. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
59 lines
1.7 KiB
TypeScript
59 lines
1.7 KiB
TypeScript
import './style.css';
|
|
import { createState, tick, buyUpgrade, visitLocation, resolveEventChoice, startGame, abandonGame, saveState, loadState, clearSave } from './engine.ts';
|
|
import { initUI, renderState } from './ui.ts';
|
|
import { initMap, updateMap } from './map.ts';
|
|
|
|
let state = loadState() ?? createState();
|
|
let visitCooldowns = new Map<string, number>();
|
|
let lastTime = 0;
|
|
const TARGET_FPS = 30;
|
|
const FRAME_MS = 1000 / TARGET_FPS;
|
|
const SAVE_INTERVAL_MS = 10_000;
|
|
let lastSaveTime = 0;
|
|
|
|
function start(): void {
|
|
const app = document.getElementById('app')!;
|
|
|
|
initUI(app,
|
|
(id) => { state = buyUpgrade(state, id); renderState(state); saveState(state); },
|
|
() => {
|
|
clearSave();
|
|
state = createState();
|
|
visitCooldowns = new Map();
|
|
document.getElementById('overlay')!.classList.remove('visible');
|
|
renderState(state);
|
|
},
|
|
(index) => { state = resolveEventChoice(state, index); renderState(state); saveState(state); },
|
|
() => { state = startGame(state); renderState(state); saveState(state); },
|
|
() => { state = abandonGame(state); renderState(state); saveState(state); }
|
|
);
|
|
|
|
initMap('map', (locationId) => {
|
|
const result = visitLocation(state, locationId, visitCooldowns);
|
|
state = result.state;
|
|
visitCooldowns = result.cooldowns;
|
|
renderState(state);
|
|
});
|
|
renderState(state);
|
|
|
|
requestAnimationFrame(loop);
|
|
}
|
|
|
|
function loop(now: number): void {
|
|
if (now - lastTime >= FRAME_MS) {
|
|
lastTime = now;
|
|
if (state.phase === 'playing') {
|
|
state = tick(state);
|
|
renderState(state);
|
|
updateMap(state.dread, state.areas);
|
|
}
|
|
if (now - lastSaveTime >= SAVE_INTERVAL_MS) {
|
|
lastSaveTime = now;
|
|
saveState(state);
|
|
}
|
|
}
|
|
requestAnimationFrame(loop);
|
|
}
|
|
|
|
start();
|