Atlas: Deploy-Buendel vor Staustufen-Sprint

- 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>
This commit is contained in:
2026-04-26 01:05:13 +02:00
parent f811437a35
commit 79ac9dad84
773 changed files with 17482 additions and 541 deletions
+553
View File
@@ -987,3 +987,556 @@ Thomas-Frage „nächstes Modul" → Atlas sagt: erst nach Phase 7b.
### Deploy-bereit (auf Thomas-Kommando)
Alle Aenderungen lokal fertig. Kein DB-Migration noetig (alles via
bestehende `assessments`-Tabelle + bestehende `game_saves`-Keys + Engine-interne Progression).
---
## 2026-04-24 ~11:00 — Deploy von Atlas durch (Option B)
Atlas hat den Deploy selbst koordiniert — antwortete auf meine
Anfrage vom Morgen (`zentrale/2026-04-24-0900-logistik-deploy-anfrage.md`).
**Auf Prod live (https://geograsim.at/):**
- ✅ `pages/logistik.php` — mode-check + forcedLevel + easy + Sperrseite
- ✅ `php/api/logistik-sessions.php`, `logistik-saves.php`, `logistik-analytics.php`
- ✅ `sims/logistik/game.html` (~149 KB, aktueller Stand)
- ✅ DB: `lg_contracts_log` existiert und leer, bereit
- ✅ DB: `students.easy_language` additiv ergänzt (Default 0)
- ✅ Module-IDs-Migration sim-XX → klima/heli/fluss/logistik
- ✅ HTTP-200 auf `/logistik` und `/modul-logistik`
**Reviews geschlossen:**
- Phase 7b Fertig — gelesen, kein Review noetig
- Warnton + Trip-Integration — kommt als Phase 8e separat
- L3-Balance + R-1 — **Atlas delegiert an mich**: `game_levels.params`-
Update mache ich selbst in einem Sweep, kein Atlas-Eingriff noetig
**Noch bei mir offen (nicht blockierend):**
- L3 startBudget 2.500 → 5.000 in `game_levels.params` via UPDATE-SQL
(Empfehlung A aus meiner 23.04 17:30 Mail) — wartet auf Thomas-OK
- Sounds — Thomas kuemmert sich um ElevenLabs
- End-Screen-Umstellung auf `.ggs-endscreen` — wartet auf Atlas-Komponenten-Meldung
---
## 2026-04-24 ~13:00 — Alle delegierten Schritte umgesetzt
### L3-Balance-Fix
- **SQL-Migration**: `App/Don_t_Deploy/2026-04-24-logistik-l3-balance-fix.sql`
setzt L3 `params.startBudget` auf 5.000 (war 2.500).
- **Lokal ausgerollt** auf XAMPP-MariaDB. Verifikation OK.
- Wartet auf naechsten Deploy → Atlas (siehe Mail
`zentrale/2026-04-24-1300-logistik-l3-migration-und-balance-korridor.md`).
### Balance-Korridor-Doku + Mechanik
- Neue Doku: `App/sims/logistik/balance-corridor.md`
- Drei Regeln formal:
- **R-1 Runway**: `startBudget ≥ 1.5 × Tagesfixkosten` — Engine-Warn.
- **R-2 Winnable**: per Level min. 1 Strategie schafft Median-success
ueber 5 Seeds.
- **R-3 Loseable**: noop schlaegt 100% fehl, zusaetzlich strategie-
spezifische Anforderungen pro Level.
- Neuer Button `Balance-Korridor-Check (R-1/R-2/R-3)` in
`headless-runner.html`: faehrt 45 Durchlaeufe (3 Lvl × 3 Strategien
× 5 Seeds) und liefert PASS/FAIL pro Regel + Level. Auch greedy als
Proxy fuer optimal verwendet (Stub fehlt noch).
- Aktuelle Verifikation R-1 mathematisch: L1/L2/L3 alle PASS nach Fix.
### Bekannte Luecke (nicht-blockierend)
- `optimal`-Strategie in `headless-runner.js` ist noch Stub (wirft).
Damit ist L3-Winnability nicht hart-verifiziert. Folgearbeit, sobald
nichts dringender ist.
### Atlas-Mail raus
`zentrale/2026-04-24-1300-logistik-l3-migration-und-balance-korridor.md`
mit SQL-Migration zum naechsten Deploy + Korridor-Doku zur Kenntnis.
---
## 2026-04-24 ~14:00 — optimal-Strategie implementiert
Die letzte offene Luecke im Balance-Korridor geschlossen.
### Was gebaut
`headless-runner.js` — `optimal` ist nicht mehr ein Stub, sondern eine
**Best-Net-Heuristik**:
- Pro Tick alle (contract, vehicle)-Paarungen bewerten:
`net = reward × 1.15 fare erwartete Verspaetungsstrafe`
mit `fare = pickup-km × €/km + pickup-h × €/h + delivery-km × €/km + delivery-h × €/h`
und `expectedPenalty = rewardBase × latePenaltyRate × max(0, totalH slackH)`
- Kapazitaets-Constraint hart (Skip wenn veh.capacity < c.containers)
- Paarungen nach Netto sortiert, oben-nach-unten feuern, pro Iteration
jedes Vehicle/Contract max. 1×
- Unprofitable Paarungen (net ≤ 0) werden ausgelassen
~120 Zeilen, UMD-konform (laeuft in Browser + Node). Intermodal noch
ausgeklammert (wie greedy).
### Korridor-Check jetzt vollstaendig
- `headless-runner.html` → „Balance-Korridor-Check" faehrt jetzt **60
Durchlaeufe** (3 Lvl × 4 Strategien × 5 Seeds)
- R-2 ueber `optimal` hart verifizierbar (nicht mehr nur greedy-Proxy)
- R-3 strenger: zusaetzlich zur noop-Regel wird fuer L2 naive und L3
greedy auf Median-Fail geprueft (Level muss schwerer werden, nicht
nur durch Untaetigkeit verlierbar)
### Docs aktualisiert
- `balance-corridor.md` §5 + §7: Status auf vollstaendig, Luecke
geschlossen
- `headless-runner.js` Header-Kommentar: Strategie-Beschreibungen
korrekt
### Test-URL
`http://localhost/geograsim/App/sims/logistik/headless-runner.html`
→ 3. Button „Balance-Korridor-Check (R-1/R-2/R-3)" druecken → 60 Runs,
Ergebnis-Tabelle mit PASS/FAIL pro Regel + Level + Detail-Zahlen.
### Was jetzt noch offen bleibt
- L3-SQL-Migration wartet auf naechsten Deploy (an Atlas via Mail 13:00)
- ElevenLabs-Sounds (Thomas morgen)
- End-Screen-Umstellung auf `.ggs-endscreen` (wartet auf Atlas)
- Phase 8e Warnton + Trip-Integration (wartet auf Atlas-Meldung)
---
## 2026-04-24 ~16:00 — Phase 8e: L1-Stufen-Progression mit Accept/Decline
Auf Thomas-Wunsch: L1 in 6 Stufen geteilt mit jeweils einer neuen
Entscheidungsdimension pro Stufe. Konzept in diesem Status-Update
knapp, ausfuehrlich in `level-progression.md` nachtragbar.
### Die 6 Stufen (L1-intern, reine Engine+UI-Mechanik, kein DB-Change)
| Stufe | ab Runde | Neu | Mechanik |
|-------|---------|-----|----------|
| 1 Fahren lernen | 1 | START druecken | 1 Auftrag direkt OPEN, kein Accept noetig |
| 2 Rueckweg waehlen | 2 | Annehmen/Ablehnen | offers-buffer=1, Standard-Varianten im Pool |
| 3 Zeitdruck | 4 | Express-Varianten | 30 % Chance auf Eilauftrag (halbe Frist, +50 % Reward) |
| 4 Container-Grenze | 6 | Multi-Container + TRUCK_LARGE-Unlock | 25 % Chance auf 2-Container, Kauf-Dialog zeigt TRUCK_LARGE |
| 5 Parallel disponieren | 8 | 2 OPEN gleichzeitig + offers-buffer=2 | volle Pool-Breite, Distanzen bis 1.5× Mult |
| 6 Soft-Ramp L2 | 11 | Events 0 → 0.3, Fernstrecken | eventProbabilityMultiplier=0.3, poolMaxMult=1.7 |
### Neue Engine-Funktionen
- `CONTRACT_STATE.OFFERED` + `EXPIRED`
- `LogistikEngine.acceptOffer(game, contractId)` — setzt OFFERED→OPEN, prueft max-OPEN-Slots
- `LogistikEngine.declineOffer(game, contractId)` — entfernt OFFERED
- `_l1Stufe(game)` / `_l1StufeCfg(game)` — Stufen-Aufloesung via round
- `_totalContractSlots(game)` — max-OPEN + offers-buffer
- `_maybeRefillOffers(game)` — fuellt total-slots mit OFFERED-Angeboten
- `_expireOffers(game)` — entfernt abgelaufene OFFERED nach Sim-Zeit
- `_maybeGenerateEvents` + `buyVehicle` beachten L1-Stufen-Overrides
- Offers expirieren nach **30 Sim-Minuten** stumm
- Tick ruft `_expireOffers` + `_maybeRefillOffers` jeden Tick
### UI-Neu
- OFFERED-Karten: eigenes Beige-Farbthema, Countdown `⏳ Verfällt in MM:SS`
- Buttons `✓ Annehmen` / `✕ Ablehnen` pro Angebot
- Express-Badge `⚡ Eilauftrag` + Multi-Container-Badge `×2`
- Header-Badge: `Level 1 · Stufe 3 Zeitdruck · R 5`
- Kauf-Button erscheint auf L1 ab Stufe 4 (Container-Grenze)
- Kauf-Dialog zeigt TRUCK_LARGE auf L1 Stufe 4+
- RAF-Loop: Sekunden-Trigger fuer Countdown-Update wenn Offers aktiv
### Headless-Runner angepasst
- `naive`/`greedy`/`optimal` akzeptieren OFFERED automatisch (Stufe 1 hatte keine, jetzt ab Stufe 2)
- `noop` laesst Offers verfallen → L1 fail wie erwartet
### Testbar
- [http://localhost/geograsim/App/logistik?level=1](http://localhost/geograsim/App/logistik?level=1) — Runde 1: ein Auftrag. Nach Lieferung: 2 Angebote, echte Wahl
- Balance-Korridor-Check (`headless-runner.html`): laeuft jetzt ueber die neue L1-Mechanik
### Deploy-Relevant
- Keine DB-Aenderung → keine Migration noetig
- Reiner Code-Deploy (engine.js + game.html)
---
## 2026-04-24 ~17:00 — Phase 8e Rückbau (L1 zu komplex, zurück zu simpel)
Thomas-Feedback: „das mit dem Stress, Eilauftrag, geht viel zu schnell,
keine Reaktionszeit. In Level 1 gibt es keinen Eilauftrag. Aufträge
kommen und gehen, sind vielleicht irgendwann auch weg ... aber sonst
zu kompliziert." → simpler machen.
### Was rausgenommen
- **CONTRACT_STATE.OFFERED** aus dem L1-Flow (Enum bleibt im Code, aber
Generator setzt es nicht mehr). Aufträge erscheinen direkt als OPEN.
- **Accept/Decline-Buttons** auf den Auftragskarten
- **Countdown** „⏳ Verfällt in MM:SS"
- **Express-Badge** `⚡ Eilauftrag` und **Multi-Container-Badge** `×2`
- **RAF-Sekunden-Trigger** (war nur für Countdown)
- **TRUCK_LARGE-Unlock ab L1 Stufe 4** in `buyVehicle` + UI-Kauf-Dialog
- **Kauf-Button auf L1** generell (Auto-Buy reicht)
### Was bleibt (einfaches Modell)
- **5 Stufen** (statt 6), jeweils `maxOpen` + `poolMaxMult` + `eventMult`:
- Stufe 1 Erster Auftrag (R1): 1 OPEN
- Stufe 2 Mehrere zur Wahl (R2): 2 OPEN, gleicher Pool
- Stufe 3 Weitere Strecken (R4): 2 OPEN, Pool bis Mult 1.3 (München)
- Stufe 4 Mehr Fahrzeuge (R7): 3 OPEN, Pool bis Mult 1.5
- Stufe 5 Soft-Ramp → L2 (R11): 3 OPEN, Pool 1.7 + Events 0→0.3
- **„Kommen und gehen"**: `_expireOffers` (nur auf L1 aktiv) entfernt
OPEN-Auftraege die ihre eigene `dueTime` ueberschritten haben ohne
Fahrzeug-Zuweisung. Silent-Remove + kurze Notification. Keine
eigene Ablaufzeit, keine gelben Ringe, kein UI-Alarm — die Frist ist
die natuerliche Grenze.
- **Auto-Buy** TRUCK_SMALL bei Balance ≥ 15.000 €: unverändert
- **Pool-Staffelung** nach Distanz (Stufen-poolMaxMult): unverändert
- **Away-Bonus-Badge** auf Auftragskarten: bleibt (ist subtil, nicht stressig)
- **Runden-/Stufen-Anzeige** im Header: aktualisiert auf neue Stufen-Namen
### Engine-Seite
- `L1_STUFEN[]` hat jetzt nur `{n, name, minRound, maxOpen, poolMaxMult, eventMult}`
- `_effectiveMaxContracts(game)` nimmt `stufe.maxOpen` direkt
- `_totalContractSlots = _effectiveMaxContracts` (kein Buffer-Konzept mehr)
- `_generateL1ContractFromPool`: immer OPEN, 1 Container, nicht Express
- `_expireOffers` → silent-removes OPEN mit abgelaufener dueTime (nur L1)
### Headless-Runner
- `acceptOffer`-Aufrufe in naive/greedy/optimal bleiben stehen
(try/catch — no-op wenn keine OFFERED-Angebote da sind)
- L1 sollte jetzt wieder mit noop=fail, naive=success laufen
### Testbar
[http://localhost/geograsim/App/logistik?level=1](http://localhost/geograsim/App/logistik?level=1)
— Runde 1: ein Auftrag (wie altbewährt). Nach Lieferung: zwei
Aufträge parallel, ohne Accept-Klick, jeder mit eigener dueTime. Wer
ignoriert wird, verschwindet irgendwann still. Kein Stress, keine
Eilaufträge, keine Countdown-Alarme.
### Nicht-Deploy-blockierend
Keine DB-Änderung, reiner Code-Deploy.
---
## 2026-04-24 ~18:00 — Phase 8e Ausbau: Variety, History, Verfahren-Event
Thomas-Feedback: „Ab der zweiten Fahrt sollte es 3-4 Optionen geben.
Manchmal attraktiver mit längerer Anfahrt, manchmal finanziell gut
aber zeitlich knapp — muss an den Zahlen erkennbar sein. Fahrt-Protokoll
als Pill." Plus Zusatzaufgabe: „Fahrer:in hat sich verfahren"-Event.
### Mehr Optionen ab Runde 2
`L1_STUFEN.maxOpen` erhoeht:
- Stufe 1 (R1): 1 Auftrag
- Stufe 2 (R2+): **3** Auftraege parallel (war 2)
- Stufe 3+ (R4+): **4** Auftraege parallel
- `poolMaxMult` auch schneller erweitert: Stufe 2 schon auf 1.3 (München)
### Profile-Variance im Generator
Jedes Angebot bekommt ein Profil gewuerfelt (Stufe 1 immer `standard`):
| Profil | Gewicht | Reward-Mult | Frist-Mult | Pool-Filter |
|--------|---------|-------------|------------|-------------|
| standard | 50 % | 1.0 | 1.0 | — |
| **tight** (Frist knapp) | 20 % | 1.3 | 0.6 | — |
| **far** (Weite Fahrt) | 15 % | 1.0 | 1.0 | mult ≥ 1.5 |
| **easy** (Kurz) | 15 % | 0.85 | 1.3 | mult ≤ 1.0 |
Profil-Name wird auf `contract.profile` gespeichert, UI-Badge rendert:
- ⚡ knappe Frist (orange)
- 🌍 weite Fahrt (blau)
- 🌿 kurz (grün)
### Zeit-Reserve-Berechnung sichtbar
Beim Klick auf Fahrzeug (Lademodus) rechnet jede Auftragskarte jetzt:
- `Fahrkosten ≈ X €` + `Marge ± Y €` (wie bisher)
- **NEU:** `⏰ Z.Z h Reserve` in Grün/Orange/Rot:
- ≥ 3 h grün (entspannt)
- 13 h orange (knapp)
- 01 h rot (kritisch)
- < 0 h rot „Frist NICHT zu schaffen"
Dadurch erkennt der Spieler an den Zahlen: `⚡ knappe Frist`-Auftraege
mit hohem Reward sind nur machbar wenn die Zeit-Reserve es zulaesst.
### Fahrt-Historie als Pills
Neuer UI-Strip zwischen Status-Leiste und Didaktikfenster:
- `📜 Historie: Fahrt 1 +523 € | Fahrt 2 120 € | Fahrt 3 +890 €`
- Grüne/rote Pills je nach Netto-Vorzeichen
- Klick auf Pill → Detail-Modal mit Strecke, Container, Dauer, Verspätung, Netto
Strip erscheint nur wenn ≥ 1 Lieferung abgeschlossen. Horizontal scrollbar
bei vielen Pills.
### Zusatzaufgabe: Verfahren-Ereignis
- **Engine-Trigger**: Mit 6 % / Sim-Stunde pro Fahrzeug im `*_drive` ab
L1 Stufe 2 wuerfelt ein Verfahren-Event. Bei Treffer:
- `vehicle.verfahrenPending = true`
- `vehicle.verfahrenTargetLocationId` = aktueller Trip-Zielort
- `vehicle.verfahrenDriverLabel` = „Fahrerin Anna" oder „Fahrer Tom"
(alternierend ueber `game.progression.verfahrenCount`)
- Fahrzeug pausiert in `_updateVehicles` (keine Bewegung, keine Zeit-Verbrauch)
- Notification `DRIVER_LOST` wird gefeuert
- **UI-Banner** am oberen Map-Rand:
`🤷 Fahrerin Anna hat sich verfahren! Bring sie nach Salzburg — klick den Ort auf der Karte.`
- **Map-Klick-Handler** pro Stadt-Marker:
- Wenn ein Fahrzeug `verfahrenPending` hat und der geklickte Ort das Ziel ist →
`LogistikEngine.resolveDriverLost(game, vehicleId, locationId)` → Fahrt geht weiter
- Falscher Ort → Toast-Hinweis, Event bleibt aktiv
- Didaktik: uebt Kartenorientierung; Zielstadt muss identifiziert werden
### Minigame-Buttons korrigiert
- 🎮 Einparken: jetzt auf **allen Levels** sichtbar (war fälschlich an
`minigamesEnabled` gebunden, dadurch L1 leer)
- 🚆 Rangieren: nur sichtbar wenn TRAIN im Fuhrpark (L1 hat keinen → Button aus)
### Testbar
[http://localhost/geograsim/App/logistik?level=1](http://localhost/geograsim/App/logistik?level=1):
- Runde 1: 1 Auftrag (Tutorial)
- Runde 2+: 3-4 Optionen mit unterschiedlichen Profilen, durchgemischt
- Zeit-Reserve erscheint beim Klick auf Fahrzeug
- Trip-Pills unten nach jeder Lieferung
- Gelegentlich Verfahren-Event → Stadt auf Karte zeigen
- 🎮 LKW-Einparken-Button sichtbar
### Reiner Code-Deploy, keine DB-Aenderung
---
## 2026-04-24 ~19:00 — End-Screen transparent + L1 längere Spielzeit + Favicon
### End-Screen-Zahlen klarer
Alter End-Screen zeigte nur „Ø Netto/Auftrag" und „Endbilanz". Das war
irreführend, weil in Multi-Contract-Touren Fahrkosten im Tick
abgezogen werden, aber NICHT in `contract.finalBalance` — Summe der
avgNet × Anzahl stimmte nicht mit Endbilanz überein. Thomas sah:
3 × 1247 = 3741 vs. Endbilanz +2547, konnte es nicht nachvollziehen.
Neu im End-Screen — komplette Konto-Rechnung sichtbar:
- Startbudget
- Erlöse (Basis + Bonus) +X €
- Strafen X €
- Fahrkosten X €
- Laufende Kosten X €
- **Zuwachs (Konto)** ±X €
- Min-Ziel
Jetzt kann der Spieler selbst ausrechnen, wo das Geld hin ist. Die
Zahlen-Quellen sind dieselben wie vorher (`game.analytics`), nur die
Zeilen transparenter gruppiert.
### L1 timeLimitHours 24 → 72
Thomas-Feedback: „das Spiel sollte deutlich länger gehen". L1-Tutorial
war bei 4×/8× nur 3-6 Echt-Minuten lang, fühlte sich gehetzt an.
SQL-Migration: [App/Don_t_Deploy/2026-04-24-logistik-l1-timelimit-72h.sql](../../Don_t_Deploy/2026-04-24-logistik-l1-timelimit-72h.sql)
setzt `game_levels.params.timeLimitHours` von 24 auf 72 (= 9 Echt-Min
bei 8×, 18 Echt-Min bei 4×). Andere Parameter unverändert: Min-Ziel
3.000 €, Events aus, BLINK_EXACT-Hilfe.
**Lokal ausgerollt** auf XAMPP. Aktueller DB-Stand:
```
L1: timeLimitHours=72 (war 24)
L2: timeLimitHours=48 (unverändert)
L3: timeLimitHours=72 (unverändert, startBudget=5000 seit letztem Fix)
```
### Favicon verdrahtet
`game.html` hatte keine `<link rel="icon">`-Tags → Browser-Tab zeigte
Generic-Icon. Jetzt analog zu heli/lehrplan/glossar:
- `game.html` referenziert `../../favicon.svg` + `../../favicon-96x96.png`
- `logistik.php`-Wrapper biegt beide Pfade auf absolute `BASE_PATH`-URLs
um (im bestehenden `strtr`-Block)
### Offene Deploy-Items für Atlas
Sammel-Liste der lokalen DB-Änderungen, die noch auf Prod müssen:
1. `2026-04-24-logistik-l3-balance-fix.sql` — startBudget 2500 → 5000
2. `2026-04-24-logistik-l1-timelimit-72h.sql` — L1 timeLimit 24 → 72
3. Seed-Einträge `class_modules` für logistik='free' pro Klasse (lokal nur)
Diese drei Migrations sind reine `game_levels.params` / `class_modules`
Updates, keine Schema-Änderungen.
---
## 2026-04-24 ~19:30 — Auto-Boost Fahrtzeit
Thomas-Wunsch: „In Phasen, in denen nur Fahrtzeit erwartet wird, die
Timescale automatisch auf 8× springen und dann automatisch zurück."
### Mechanik
- **Gespeicherte Player-Wahl** (`playerSpeed`) vs. **aktuelle sim-Geschwindigkeit**
- Jeden Frame `updateAutoBoost()`:
- Condition: `allBusy = alle Fahrzeuge haben tripPhase && keinen verfahrenPending`
- `shouldBoost = allBusy && kein Verfahren-Event offen`
- Wenn true + `!autoBoostActive` → setTimeScale(8), Flag setzen
- Wenn false + `autoBoostActive` → setTimeScale(playerSpeed), Flag loeschen
- Klick auf einen Speed-Button: `playerSpeed` updaten, AutoBoost deaktivieren
(manueller Override hat Vorrang)
- Pause (0×): Auto-Boost greift nicht
### UI
- Spieler-Button bleibt aktiv (visueller Anker)
- Neuer Badge `⚡ Auto 8×` rechts neben den Speed-Buttons pulsiert sanft
gelb, wenn Auto-Boost aktiv
- Tooltip: „Alle Fahrzeuge unterwegs — Sim läuft automatisch auf 8×.
Pressen einer Taste übernimmt wieder die Kontrolle."
### Auto-Release in diesen Fällen
- Ein Fahrzeug wird IDLE (Lieferung fertig) → Spieler könnte neuen Trip starten
- Verfahren-Event triggert → Spieler muss Karte klicken
- Spieler klickt selbst eine Speed-Taste
### Testbar
[http://localhost/geograsim/App/logistik?level=1](http://localhost/geograsim/App/logistik?level=1):
- Assign Auftrag zu Lok → Fahrt startet → sobald sie rollt: ⚡ Auto 8×
Badge pulsiert gelb, Sim-Zeit rennt
- Lieferung fertig → Fahrzeug IDLE → Badge verschwindet, Zurück auf
Spieler-Speed (normalerweise 1×)
---
## 2026-04-24 ~20:00 — Road-Dijkstra + Verfahren-Penalty + Auto-Boost-Override
### Straßennetz-Routing für LKWs
Thomas: „LKW fährt Luftlinie Salzburg→Berlin, unrealistisch."
- Neuer Seed `App/assets/data/lg-roadnet.json`: 11 Knoten (Stadt-Hubs) + 13 Edges mit echten Autobahn-Distanzen (A1/A7/A8/A9 etc)
- `logistik.php` injiziert Roadnet in `LOGISTIK_SEEDS.roadnet`
- `engine.js` `loadContent`: nimmt Roadnet in `worldState.roadnet` auf
- `calculateRoute` für TRUCK_SMALL/TRUCK_LARGE: erst Dijkstra auf Roadnet,
Geometry = Polyline durch die Dijkstra-Knoten, Segments pro Kante mit
`routeCode` (A8, A9 etc). Fallback routesOsm/Luftlinie für Locations
ausserhalb des Roadnet-Graphs.
- Salzburg→Berlin fährt jetzt salzburg→muenchen→berlin (150+580=730km)
statt Luftlinie (590km).
### Vertagte Follow-Up: Höhere „Auflösung" der Polylines
Thomas: aktuell sind Polyline-Segmente zwischen Stadt-Knoten gerade
Linien. Echte Autobahnen haben Kurven. Option C aus meinem Feedback:
hand-gepflegte Polylines pro Road-Kante in `lg-routes-osm.json`
(13 Paare × 5-10 Stützpunkte ≈ 1.5 h Arbeit). In die To-Do-Liste
aufgenommen, niedrige Prio.
### Verfahren-Ereignis: Zeit-Strafe + Capital-Only
Thomas-Wunsch: Stufe A (Zeit-Strafe statt sichtbarem Detour), nur
Hauptstädte zaehlen (sonst iPad-Fat-Finger-Problem).
- Engine `resolveDriverLost(game, vehicleId, clickedLocationId, locationType)`
unterscheidet jetzt 3 Fälle:
- `locationType !== 'CAPITAL'` → `ignored:true`, kein Strafe, UI zeigt
„Nur Hauptstädte zählen"
- Falsche Hauptstadt → `wrong:true, wastedHours:1.5`, akkumuliert in
`vehicle.verfahrenPenaltyHours`, Event bleibt offen
- Richtige Hauptstadt → löst Event auf, rechnet akkumulierte Strafe
in Reduktion von `segmentProgress` um (max 90 % zurück) → Restfahrt
dauert entsprechend laenger, late-fee-Risiko steigt
- UI-Marker-Klick reicht `loc.type` mit, Toasts differenziert nach Fall
- Konstante `VERFAHREN_PENALTY_H = 1.5` in engine.js
### TimeScale-Override bei Verfahren
Thomas: „Beim Verfahren TimeScale 1."
- `effectiveTimeScale()` mit Prioritaet: Pause → Verfahren 1× → AutoBoost 8× → playerSpeed
- Wenn Verfahren-Event triggert: egal ob vorher Player auf 4× oder AutoBoost 8× war, Sim springt sofort auf 1×
- Nach Resolution: zurueck zur richtigen Stufe
- AutoBoost-Badge wird waehrend Verfahren ausgeblendet
---
## 2026-04-24 ~20:30 — QoL: Auto-Select + Auto-Swap + Layer-Control raus
### Auto-Select beim Lademodus
Thomas: „Das oberste freie Fahrzeug ist automatisch schon markiert und
offen. Sobald es steht."
- In `renderVehicles()`: wenn kein `loadingVehicleId` → setze auf
erstes IDLE-Fahrzeug ohne tripPhase. Auch beim Game-Start.
- Wenn das aktuell gewählte IDLE-Fahrzeug losfährt (tripPhase wird
gesetzt) → automatisch auf nächstes IDLE umschalten
- Resultat: Spieler klickt nur noch Aufträge, das Fahrzeug ist
vorausgewählt
### Auto-Swap im Laderaum
Thomas: „Wenn ein Auftrag bereits zugewiesen ist und ein anderer
angeklickt wird, der nicht mehr Platz hat, fliegt der Auftrag, der
bereits im LKW drin ist, wieder raus."
- In Auftragskarten-Klick-Handler:
- Wenn Auftrag bereits im Fahrzeug geladen: **Toggle** → entladen
- Wenn `loadContract` wegen vollem Laderaum failt: ältesten
geladenen Auftrag `unloadContract`, dann neu versuchen
- Toast-Message: „🔄 X geladen (Y ausgetauscht)" statt Fehler
- Spieler kann durch Aufträge schnell durchblättern
### Layer-Control-Widget entfernt
Thomas: „Die Auswahl zur Ansicht rechts oben (Hauptstädte, Städte,
Häfen, Terminals und Bahnnetz) kannst du entfernen. Wir zeigen einfach
immer alles an."
- `L.control.layers(...)` entfernt aus der Karten-Initialisierung
- Alle Layer werden unbedingt dem Map hinzugefügt (capitals, cities,
ports, terminals); Bahnnetz nur wenn `railEnabled` im Level-Config
- Die Karte hat jetzt keine Widget rechts oben mehr
## 2026-04-24 21:30 — Bonus-Pills + Gratulations-Modal + Städte Tier 1 + Atlas-Mail
### Atlas-Mail raus: Info-Cards mit Bildern (Heli-Pattern)
- `_inbox/zentrale/2026-04-24-2100-logistik-infocards-heli-pattern.md`
- 5 konkrete Fragen: Heli-Card-Komponente, Bild-Pfad/Lizenz,
Granularität (pro Auftrag vs. pro Zielort), AI-Pipeline,
Design-System-Wiederverwendbarkeit
- Thomas-Wunsch: pro Start eine Info-Card mit Bild der Zielstadt
- Warte auf Atlas-Antwort; baue derweil andere Tasks
### Gratulations-Meldungsfenster
Thomas: „einen zweiten LKW bekommen. Dies wurde aber nicht angekündigt.
In einem solchen Fall bitte kurzes Meldungsfenster. Gratulation..."
- Neue Komponente `.lg-announce-overlay` + `.lg-announce-modal` in
game.html (CSS + DOM)
- `announce(icon, title, text, sub)` — Scale-in-Animation, 4 Sek
auto-close, Click schließt sofort
- VEHICLE_PURCHASED-Notification wird via `drainNotifications()` auf das
Modal umgeleitet (statt Toast)
- `checkStufeChange()` vergleicht `_l1Stufe` mit `lastAnnouncedStufe`,
feuert Modal bei Stufen-Wechsel mit Stufen-Parametern
(maxOpen/poolMaxMult/eventMult)
### Bonus-Pills UI komplett
Thomas: „rechts oben Pills setzen, klickbar für Info, automatisch
benutzt. Stack-Limit gute Idee. Bonusskala passt."
- Container `#bonusPills` oben rechts über der Karte (absolute
positioniert, `pointer-events: auto`)
- `renderBonusPills()` zeichnet die FIFO-Queue aus `game.pendingBonuses`
(cap 5); jede Pill mit ⏱ Icon + Minutenwert + Quellen-Tooltip
- `showBonusPopover(idx)` — Click zeigt kurzes Erklär-Popover
(„Bonus aus Rangier-Minispiel — wird beim nächsten Laden angewendet")
- `flyBonusToVehicle(vehicle)` — Consumption-Animation: Pill fliegt
zum Fahrzeug-Marker, skaliert auf 0, dann `pendingBonuses.shift()`
- Minispiel-Hook in `mgApplyResult`: bei Success `LogistikEngine.pushLoadBonus`
mit 45/20/5 min je nach Zeit (<15s/<30s/<60s)
- Engine hat `_consumeNextLoadBonus(game, vehicle)` an 4
Phase-Transitions (pickup/loading/unloading/dropoff)
### Layer-Fix: Ports + Terminals wirklich sichtbar
Fehler nach Layer-Control-Removal: `visibleLevel`-Filter im marker
forEach blockte Ports/Terminals (nur ab L3 sichtbar).
- Filter entfernt — alle Locations immer gerendert
- `bindPopup` zeigt jetzt Name + Typ-Label (Hauptstadt/Stadt/Hafen/
Terminal) + `didacticInfo` als kleinen Absatz
- Popup-CSS `.lg-loc-popup` mit typeLabel-Subtitle
### Städte-Erweiterung Tier 1 (Hauptstädte)
Thomas: „Mache einen Entwurf und gib vor, wie viele Städte in Europa
relevant wären."
- `App/assets/data/lg-locations.json` von 13 auf **27 Einträge**
erweitert (alle bestehenden Einträge behalten IDs/Koordinaten)
- **+14 Hauptstädte**: Rom, London, Brüssel, Amsterdam, Prag, Budapest,
Athen, Stockholm, Oslo, Helsinki, Dublin, Lissabon, Bern
- Jeder Eintrag hat `didacticInfo` — 1 Satz mit logistik-relevantem
Geo-Fakt (Verkehrsknoten, Hafen-Kapazität, EU-Status etc.)
- `regionId` konsistent gesetzt (benelux, scandinavia, iberia,
western_europe, southern_europe, central_europe)
- **Offen**: Tier 2 (~50 Großstädte) + Tier 3 (~25 Häfen/Terminals)
— Konzept steht, Umsetzung vertagt
### Auto-Timescale-Badge dynamisch
Thomas: „bei der Auto Timescale steht immer Auto 8× .. die Zahl sollte
sich aber ändern, wenn nicht reine Fahrt aktiv ist."
- Badge-Text wird jetzt pro Frame aus `effectiveTimeScale()` gesetzt
- `⚡ Auto 8×` bei reiner Fahrt, `⚡ Auto 1×` bei Verfahren-Event
(wenn playerSpeed != 1)
- Badge hidden wenn Auto-Logik nicht override-t (playerSpeed==target)
- `updateAutoBoost()` resettet Badge auch bei non-RUNNING States
(MINIGAME/PAUSED/LEVEL_SUCCESS), bisher blieb es stale sichtbar
### Offene Punkte
- Atlas-Antwort zu Info-Cards (5 Fragen vom 21:00)
- Städte Tier 2/3 (Konzept steht, ausbauen)
- Uhr mit Stunden/Minutenzeiger + Tag/Nacht in Karten-Ecke
- Pausepflicht LKW bei Langstrecken in höheren Levels
- Sounds via ElevenLabs (Thomas macht morgen)
- Polyline-Auflösung Option C (hand-gepflegt pro road-edge)