79ac9dad84
- Logistik: Musik-Player Playlist-Modus (5 Gruppen, 20 Tracks) - Heli: End-Screen auf .ggs-endscreen, Mission-Bilder, Voice-Lines, Briefing-Audio - Logistik: Layout-Tausch Auftraege+Fahrzeuge links, Karte rechts - Logistik: Tier-1-Staedte ausgebaut, Auto-Timescale-Badge - Logistik: Roadnet/Railnet Dijkstra-Routing, Balance-Updates - Atlas: 5 Atlas-Inbox-Nachrichten (Cards-Pattern, DALL-E-Key, Musik-Playlists) - Status-Updates Heli + Logistik Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
231 lines
12 KiB
HTML
231 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>GeoGraSim — Stadtplaner*in in Erdbebenregion</title>
|
|
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="favicon.svg">
|
|
<link rel="stylesheet" href="assets/fonts/inter.css">
|
|
<style>
|
|
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
|
|
:root {
|
|
--bg: #f7f6f3; --bg2: #efeee9; --white: #fff;
|
|
--text: #1a1a1a; --text2: #4a4a4a; --text3: #8a8a8a;
|
|
--fjord: #4a7c8a; --fjord-l: #dae8ec; --fjord-d: #3a6470;
|
|
--moss: #5a8a5e; --moss-l: #dceadd;
|
|
--sand: #c4a35a; --sand-l: #f2eacc;
|
|
--coral: #c07a6b; --coral-l: #f2ddd8;
|
|
--danger: #b04a3a;
|
|
}
|
|
body { font-family:'Inter',system-ui,sans-serif; background:var(--bg); color:var(--text); line-height:1.5; }
|
|
|
|
.nav { padding:.6rem 1.2rem; display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid rgba(0,0,0,.05); background:var(--white); }
|
|
.nav-brand { display:flex; align-items:center; gap:.5rem; font-weight:800; font-size:1rem; color:var(--fjord); text-decoration:none; }
|
|
.nav-brand img { width:28px; height:28px; border-radius:6px; }
|
|
.nav-actions { display:flex; gap:.4rem; }
|
|
.nav-btn { padding:.4rem .8rem; border:1px solid rgba(0,0,0,.08); border-radius:8px; background:var(--white); color:var(--text2); font-size:.78rem; font-weight:600; cursor:pointer; text-decoration:none; }
|
|
.nav-btn:hover { background:var(--fjord-l); border-color:var(--fjord); color:var(--fjord); }
|
|
|
|
.game-layout { display:grid; grid-template-columns:280px 1fr 280px; gap:.8rem; padding:.8rem; max-width:1400px; margin:0 auto; align-items:start; }
|
|
|
|
.panel { background:var(--white); border-radius:12px; border:1px solid rgba(0,0,0,.05); padding:.9rem; box-shadow:0 2px 8px rgba(0,0,0,.03); }
|
|
.panel-h { font-size:.66rem; font-weight:700; color:var(--fjord); text-transform:uppercase; letter-spacing:.06em; margin-bottom:.5rem; }
|
|
|
|
.left { display:flex; flex-direction:column; gap:.8rem; }
|
|
.resource { display:flex; align-items:center; gap:.6rem; padding:.4rem .2rem; border-bottom:1px solid rgba(0,0,0,.04); }
|
|
.resource:last-child { border-bottom:none; }
|
|
.resource-icon { font-size:1.4rem; width:28px; text-align:center; }
|
|
.resource-info { flex:1; min-width:0; }
|
|
.resource-name { font-size:.7rem; color:var(--text3); font-weight:500; }
|
|
.resource-val { font-size:.95rem; font-weight:700; color:var(--text); }
|
|
|
|
.goals .goal { padding:.4rem 0; border-bottom:1px solid rgba(0,0,0,.04); }
|
|
.goals .goal:last-child { border:0; }
|
|
.goal-row { display:flex; align-items:center; gap:.4rem; font-size:.78rem; }
|
|
.goal-check { width:14px; height:14px; border:1.5px solid var(--text3); border-radius:3px; display:flex; align-items:center; justify-content:center; font-size:.6rem; flex-shrink:0; }
|
|
.goal-check.done { background:var(--moss); border-color:var(--moss); color:#fff; }
|
|
.goal-bar { height:3px; background:#e8e5dc; border-radius:2px; margin-top:.3rem; overflow:hidden; }
|
|
.goal-bar-fill { height:100%; background:var(--moss); transition:width .3s; }
|
|
|
|
.center { display:flex; flex-direction:column; gap:.6rem; }
|
|
.canvas-wrap { background:var(--white); border-radius:14px; border:1px solid rgba(0,0,0,.05); overflow:hidden; box-shadow:0 4px 16px rgba(0,0,0,.05); position:relative; min-height:440px; }
|
|
|
|
.tutorial-overlay { position:absolute; inset:0; background:rgba(15,30,40,.85); backdrop-filter:blur(8px); display:flex; align-items:center; justify-content:center; z-index:10; padding:1.5rem; }
|
|
.tutorial-card { background:var(--white); border-radius:16px; padding:1.5rem 1.8rem; max-width:480px; box-shadow:0 20px 60px rgba(0,0,0,.3); }
|
|
.tutorial-card h3 { font-size:1.2rem; font-weight:800; margin-bottom:.6rem; color:var(--fjord); }
|
|
.tutorial-card p { font-size:.88rem; color:var(--text2); white-space:pre-line; margin-bottom:1rem; }
|
|
.tutorial-card .progress-dots { display:flex; gap:.3rem; justify-content:center; margin:.8rem 0; }
|
|
.dot { width:8px; height:8px; border-radius:50%; background:#dadad0; }
|
|
.dot.active { background:var(--fjord); }
|
|
.tut-btn { width:100%; padding:.7rem; background:var(--fjord); color:#fff; border:none; border-radius:10px; font-weight:700; font-size:.9rem; cursor:pointer; }
|
|
.tut-btn:hover { background:var(--fjord-d); }
|
|
|
|
.speed-bar { display:flex; gap:.3rem; padding:.5rem; background:var(--white); border-radius:10px; border:1px solid rgba(0,0,0,.05); }
|
|
.speed-btn { flex:1; padding:.5rem; border:none; background:transparent; color:var(--text2); font-size:.8rem; font-weight:600; cursor:pointer; border-radius:6px; }
|
|
.speed-btn:hover { background:#f0eeea; }
|
|
.speed-btn.active { background:var(--fjord); color:#fff; }
|
|
|
|
.graphs { display:grid; grid-template-columns:1fr 1fr; gap:.6rem; }
|
|
.graph-card { background:var(--white); border-radius:10px; border:1px solid rgba(0,0,0,.05); padding:.6rem; }
|
|
.graph-title { font-size:.65rem; color:var(--text3); font-weight:600; text-transform:uppercase; letter-spacing:.06em; margin-bottom:.2rem; }
|
|
.graph-svg { width:100%; height:50px; }
|
|
|
|
.right { display:flex; flex-direction:column; gap:.8rem; }
|
|
.measure-card { display:flex; gap:.6rem; padding:.6rem; border-radius:10px; border:1px solid rgba(0,0,0,.06); margin-bottom:.4rem; cursor:pointer; transition:all .2s; background:var(--white); }
|
|
.measure-card:hover { border-color:var(--fjord); background:var(--fjord-l); }
|
|
.measure-card.disabled { opacity:.5; cursor:not-allowed; }
|
|
.measure-card.disabled:hover { border-color:rgba(0,0,0,.06); background:var(--white); }
|
|
.measure-icon { font-size:1.5rem; width:32px; text-align:center; }
|
|
.measure-info { flex:1; min-width:0; }
|
|
.measure-name { font-size:.8rem; font-weight:700; }
|
|
.measure-desc { font-size:.66rem; color:var(--text3); line-height:1.3; }
|
|
.measure-stats { display:flex; gap:.3rem; flex-wrap:wrap; margin-top:.2rem; }
|
|
.measure-stat { font-size:.6rem; padding:1px 5px; border-radius:4px; background:#f0eeea; color:var(--text3); font-weight:600; }
|
|
.measure-cost { background:var(--sand-l); color:var(--sand); }
|
|
.measure-reduction { background:var(--moss-l); color:var(--moss); }
|
|
.measure-protection { background:var(--fjord-l); color:var(--fjord); }
|
|
.measure-capacity { background:#e8e3f2; color:#7a5ea8; }
|
|
.measure-quality { background:var(--coral-l); color:var(--danger); }
|
|
.measure-neutral { background:#f0eeea; color:var(--text3); }
|
|
|
|
.events-list { max-height:180px; overflow-y:auto; }
|
|
.event { padding:.4rem .5rem; border-radius:8px; margin-bottom:.3rem; font-size:.74rem; line-height:1.3; }
|
|
.event-info { background:#f0eeea; color:var(--text2); }
|
|
.event-success { background:var(--moss-l); color:var(--moss); }
|
|
.event-warning { background:var(--sand-l); color:var(--sand); }
|
|
.event-danger { background:var(--coral-l); color:var(--danger); }
|
|
|
|
.end-screen { position:fixed; inset:0; background:rgba(15,30,40,.9); backdrop-filter:blur(10px); display:flex; align-items:center; justify-content:center; z-index:100; padding:2rem; }
|
|
.end-card { background:var(--white); border-radius:20px; padding:2rem 2.5rem; max-width:500px; text-align:center; box-shadow:0 30px 80px rgba(0,0,0,.4); }
|
|
.end-icon { font-size:4rem; margin-bottom:.5rem; }
|
|
.end-card h2 { font-size:1.8rem; font-weight:900; letter-spacing:-.02em; margin-bottom:.3rem; }
|
|
.end-card .end-summary { color:var(--text2); margin-bottom:1rem; }
|
|
.end-stats { display:grid; grid-template-columns:1fr 1fr; gap:.8rem; margin:1rem 0; }
|
|
.end-stat { background:#f7f6f3; border-radius:10px; padding:.8rem; }
|
|
.end-stat-val { font-size:1.4rem; font-weight:800; color:var(--fjord); }
|
|
.end-stat-lbl { font-size:.7rem; color:var(--text3); text-transform:uppercase; }
|
|
|
|
@media (max-width: 1100px) {
|
|
.game-layout { grid-template-columns:1fr; }
|
|
.left, .right { order:2; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<nav class="nav">
|
|
<a href="index.html" class="nav-brand"><img src="assets/img/logo.png" alt="">GeoGraSim · Erdbebenregion</a>
|
|
<div class="nav-actions">
|
|
<button class="nav-btn" id="btn-save">💾 Speichern</button>
|
|
<button class="nav-btn" id="btn-load">📂 Laden</button>
|
|
<button class="nav-btn" id="btn-finish">⏹ Beenden</button>
|
|
<button class="nav-btn" id="btn-reset" title="Stand löschen und neu starten">🔄 Reset</button>
|
|
<a href="index.html" class="nav-btn">← Zurück</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="game-layout">
|
|
|
|
<aside class="left">
|
|
<div class="panel">
|
|
<div class="panel-h">📊 Status</div>
|
|
<div id="resources"></div>
|
|
</div>
|
|
<div class="panel goals">
|
|
<div class="panel-h">🎯 Ziele</div>
|
|
<div id="goals"></div>
|
|
</div>
|
|
</aside>
|
|
|
|
<main class="center">
|
|
<div class="canvas-wrap" id="canvas-wrap">
|
|
<div class="tutorial-overlay" id="tutorial">
|
|
<div class="tutorial-card">
|
|
<h3 id="tut-title">…</h3>
|
|
<p id="tut-text">…</p>
|
|
<div class="progress-dots" id="tut-dots"></div>
|
|
<button class="tut-btn" id="tut-next">Weiter →</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="speed-bar">
|
|
<button class="speed-btn" data-speed="0">⏸</button>
|
|
<button class="speed-btn active" data-speed="1">▶ Normal</button>
|
|
<button class="speed-btn" data-speed="2">⏩ Schnell</button>
|
|
<button class="speed-btn" data-speed="4">⏭ Sehr schnell</button>
|
|
</div>
|
|
|
|
<div class="graphs">
|
|
<div class="graph-card">
|
|
<div class="graph-title">👥 Bevölkerung</div>
|
|
<svg class="graph-svg" id="graph-pop"></svg>
|
|
</div>
|
|
<div class="graph-card">
|
|
<div class="graph-title">🏠 Wohnraum</div>
|
|
<svg class="graph-svg" id="graph-housed"></svg>
|
|
</div>
|
|
<div class="graph-card">
|
|
<div class="graph-title">💰 Budget</div>
|
|
<svg class="graph-svg" id="graph-budget"></svg>
|
|
</div>
|
|
<div class="graph-card">
|
|
<div class="graph-title">🕯️ Opfer (kumulativ)</div>
|
|
<svg class="graph-svg" id="graph-deaths"></svg>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<aside class="right">
|
|
<div class="panel">
|
|
<div class="panel-h">🏗 Häuser bauen</div>
|
|
<div id="measures"></div>
|
|
</div>
|
|
<div class="panel">
|
|
<div class="panel-h">📰 Ereignisse</div>
|
|
<div class="events-list" id="events"></div>
|
|
</div>
|
|
</aside>
|
|
|
|
</div>
|
|
|
|
<div id="end-screen-host"></div>
|
|
|
|
<script type="module">
|
|
import { ErdbebenGame, BUILDING_TYPES } from './src/sims/sim-07-erdbeben/game.ts'
|
|
import { ErdbebenRenderer } from './src/sims/sim-07-erdbeben/game-renderer.ts'
|
|
import { GameUI } from './src/ui/game-ui.ts'
|
|
|
|
const game = new ErdbebenGame()
|
|
|
|
const shopItems = BUILDING_TYPES.map(b => ({
|
|
id: b.id,
|
|
name: b.name,
|
|
emoji: b.emoji,
|
|
description: b.description,
|
|
cost: b.cost,
|
|
upkeep: b.upkeep,
|
|
badges: [
|
|
b.capacity > 0 ? { label: `👥 ${b.capacity} Plätze`, type: 'capacity' } : null,
|
|
{ label: `🛡 Q ${(b.quality * 100).toFixed(0)}%`, type: b.quality >= 0.6 ? 'protection' : 'quality' },
|
|
].filter(Boolean),
|
|
}))
|
|
|
|
new GameUI({
|
|
game,
|
|
Renderer: ErdbebenRenderer,
|
|
shopItems,
|
|
onBuy: (id) => game.buyBuilding(id),
|
|
graphs: [
|
|
{ id: 'graph-pop', title: 'Bevölkerung', field: 'population', yMin: 0, yMax: 6000, color: '#4a7c8a' },
|
|
{ id: 'graph-housed', title: 'Wohnraum', field: 'housed', yMin: 0, yMax: 6000, color: '#5a8a5e' },
|
|
{ id: 'graph-budget', title: 'Budget', field: 'budget', yMin: -300, yMax: 1500, color: '#c4a35a' },
|
|
{ id: 'graph-deaths', title: 'Opfer', field: 'deaths', yMin: 0, yMax: 500, color: '#b04a3a' },
|
|
],
|
|
saveKey: 'erdbeben-save',
|
|
yearOffset: 1975,
|
|
})
|
|
</script>
|
|
</body>
|
|
</html>
|