--- instanz: logistik rolle: Simulation „Logistik Europa" (Modul 11) stand_seit: 2026-04-19 phase: Phase 8c+ — Rangier-Minigame mit Sammelgleis + L1-Innen-Progression + Balance-Regel R-1. Wartet auf Atlas-Reviews (3 offene Mails in zentrale) --- # Status — Logistik-Instanz ## Rolle und Scope - Eigner: `App/sims/logistik/` (Gerüst kommt von Atlas) - Eigner: `App/pages/logistik.php`, `App/pages/modul-logistik.php` - Eigner: `App/php/api/logistik-*.php` - Optional: neue MySQL-Tabellen `lg_…` (nur nach Atlas-Abstimmung) - Plattform-Zentrale ist Atlas — Anfragen über `_inbox/zentrale/` ## Aktueller Stand - 2026-04-19 23:15 — Kickoff-Briefing von Atlas erhalten - 2026-04-19 23:25 — Briefing + Pflichtenheft (alle Schlüsselkapitel) gelesen - 2026-04-19 23:30 — Empfangsbestätigung an Zentrale geschickt - 2026-04-20 00:10 — Atlas-Antworten auf alle 4 Rückfragen erhalten - 2026-04-20 00:20 — Quittung an Atlas (Routing bestätigt, alle Punkte übernommen) - Warte auf: Atlas baut Gerüst (module_info, Landing-Card, Detailseite, Wrapper, Skelette unter `App/sims/logistik/`) ## Geklärte Entscheidungen (Atlas-Antwort 00:10) - **Lehrplan**: `kompetenzen.json` als Vorab-Skizze (`status: "proposed"`) nach Gerüst, final nach Phase 2 - **Glossar**: Atlas koordiniert Anfrage; ~10 von 13 Begriffen neu, reicht bis Phase 6 - **Landing**: Eigene Gruppe „Wirtschaft & Verkehr" (LOCKED bis FREE) - **Tile-Server**: Carto Positron `https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png`, Leaflet 1.9.4, `minZoom: 4, maxZoom: 10` - **Routing**: bestätigt — L1 Luftlinie×1.3, L2/L3 hand-gepflegte Polylines in `lg-routes-osm.json`, OSRM erst auf Thomas-Wunsch - **State-Machine**: Atlas legt Enum exakt nach Pflichtenheft Kap 44.2 ins `engine.js`-Skelett ## Phasenplan (aus Briefing) - [ ] **Phase 0** — Balance-Matrix + Test-Harness + Headless-Runner-Skelett → Atlas-Review - [ ] Phase 1 — Fundament (engine.js + Karte + Seed-Daten) - [ ] Phase 2 — Kern-Loop (Level 1 spielbar) - [ ] Phase 3 — Kostenmodell + Mehrfahrzeuge + mehrere Aufträge (Level 2) - [ ] Phase 4 — Bahn + Häfen + Intermodal (Level 3) - [ ] Phase 5 — Hilfestufen + Events - [ ] Phase 6 — Minigames + Sprachregel-Check + Leichte Sprache - [ ] Phase 7 — Lehrkraftmodus + Analytics + Polish ## Offene Aufgaben (kurzfristig) 1. `App/docs/module-interface.md` Abschnitte 4a/4b/4c/7b lesen 2. Sobald Gerüst von Atlas steht: `balance-matrix.md` schreiben (Werte aus Kap 65 + Schätzwerte) 3. `test.html` mit 7 Pflichttests anlegen 4. Headless-Runner-Skelett `runLevel(levelId, seed, strategy)` definieren 5. Atlas-Review von Phase 0 anfordern, bevor Phase 1 startet ## Blocker - Keine. Wartepunkt: Atlas-Gerüst (≈ 2 Sessions geschätzt) ## Konventions-Anker (Erinnerung) - Sprachregel 4a: keine „spielen / Spiel / Spieler" - Leichte Sprache 4b: `pickText()`-Pattern für alle UI-Texte - iPad 4c: 1180×820 Landscape, 36 px Touch-Ziele, kein Hover-Kleber - Autosave 7b: Pflicht bei state-relevanten Übergängen - Keine KI im Produkt: Auftragstexte/Events/Hilfe vorab generieren, statisch ausliefern - Inbox-Check vor jeder „Fertig"-Meldung - Commits: `Logistik: ` ## Komplexitätshinweis Atlas schätzt 30–50 Sessions für das Gesamtmodul. Phasenschnitte sauber halten, nicht den ganzen Brocken auf einmal angehen. --- ## Tagesabschluss 2026-04-20 (00:20) - Kickoff + Pflichtenheft gelesen - Empfangsbestätigung + 4 Rückfragen an Atlas verschickt - Atlas-Antworten gelesen, alle Entscheidungen quittiert - Routing-Strategie (L1 Luftlinie×1.3 / L2-L3 Hand-Polylines / kein OSRM) bestätigt - **Nächstes (sobald Gerüst steht):** `balance-matrix.md` → 7 Pflichttests in `test.html` → Headless-Runner-Skelett `runLevel(levelId, seed, strategy)` - **Blocker:** keiner — wartet auf Atlas-Gerüst (~2 Sessions) - **Offen für Thomas:** keine akute Frage, alles geklärt ## Tagesabschluss 2026-04-20 (00:55) - Atlas-Gerüst empfangen (DB, Landing-Card, PHP-Wrapper, Sim-Skelette, Seeds) - 7 Pflichttests in `test.html` statisch geprüft + via Python-Mathematik verifiziert → 22 von 22 Test-Cases bestehen rechnerisch, Browser-Bestätigung steht aus - **Phase 0 v0.1 geliefert:** - `App/sims/logistik/balance-matrix.md` v0.1 - `App/sims/logistik/headless-runner.html` (Skelett, alles SKIP) - Atlas-Review angefordert ## Tagesabschluss 2026-04-20 (01:30) — Phase 0 v0.2 nach Atlas-Klarstellung Atlas hat klargestellt: Phase 0 ist **meine** Arbeit, das Gerüst war nur Vorarbeit. Konkrete Atlas-Forderungen alle abgehakt: - **balance-matrix.md v0.2** — Rationale-Spalte je Parameter, INSERT-SQLs für `game_levels`, Konsistenz-Checks an Atlas, Event-Wahrsch. als Multiplikator umstrukturiert, `noop` zur Strategieliste - **headless-runner.js** (NEU, vorher .html) — Vanilla-JS-Modul, Browser+Node-kompatibel via UMD, Mulberry32-RNG, runLevel-Vertrag, 4 Strategien (`noop` lauffähig + `naive/greedy/optimal` als Stubs) - **headless-runner.html** umgebaut zu dünner UI-Hülle (Logik in .js) - **test.html erweitert** um: - Test 8 — Edge-Cases (8 Cases: leere Polyline, getrennter Dijkstra-Graph, Pfad zum Selbst, negative Hours, null-Werte, unbekannter Modus) - Test 9 — Seeded-Random (4 Cases: Determinismus, verschiedene Seeds, Range, Seed 0) - Test 10 — Runner-Vertrag (10 Cases: noop läuft, reproduzierbar, Stubs werfen kontrolliert) - `group()` und Render auf async umgebaut, damit Test 10 (`await runLevel`) sauber läuft - Python-Verifikation der Mathematik: alle neuen Cases grün (10 von 10) - Atlas-Review erneut angefordert mit aktualisierten Artefakten **Nächstes (nach Review-OK):** Phase 1 — `engine.js` `tick()` Loop + Leaflet-Karte mit 13 Seed-Locations **Blocker:** Atlas-Review + Thomas-Browser-Test (test.html + headless-runner.html) **Offen für Thomas:** einmal beide HTML-Seiten öffnen, Status melden ## Tagesabschluss 2026-04-20 (02:30) — Phase 1 ausgeliefert Phase 0 von Atlas mit BESTANDEN reviewt (01:45). Doku-Korrekturen aus Review umgesetzt (Bahnnetz-Distanzen Paris↔Rotterdam=520, Paris↔München=820; INSERT-Schema mit `scenario`+`levelNameEasy` in params); 3 Logistik-Level sind in DB. Phase 1 komplett implementiert: - **engine.js erweitert:** - `loadContent(game, seeds)` — INIT → LOADING_CONTENT → READY - `startPlanning(game)` — READY → PLANNING - `startSimulation(game)` — PLANNING → RUNNING (paused=false) - `pause(game)` / `resume(game)` — User-Pause via paused-Flag - `setTimeScale(game, scale)` — 1×/2×/4×/8× - `onStateChange(game, callback)` → unregister-Funktion (für Autosave 7b) - `tick(game, deltaMs)` — Phase 1: Sim-Zeit + Zeitlimit-Check, alle anderen Pipeline-Schritte (Vehicles, Contracts, Economy, Events) sind Phase 2/3/5 Stubs - `convertRealTimeToGameMinutes(deltaMs, timeScale)` — utility - `getSimHoursElapsed(game)` — utility - `serialize(game)` / `deserialize(json)` — ohne Listener (Autosave 7b) - `createGame(levelNum, {deterministic, seed})` — neue Option für Tests - Internes `_setState()` löst onStateChange-Callbacks aus - **game.html komplett umgebaut:** - Leaflet-Karte mit Carto Positron (Atlas-Vorgabe), tap:true für iPad - 13 Locations gerendert als CircleMarker pro Typ (CAPITAL grün/CITY grau/PORT blau/TERMINAL braun) - Layer-Gruppen: Hauptstädte, Städte, Häfen, Terminals, Bahnnetz - Layer-Control oben rechts (collapsed:false), Marker-Filter nach `visibleFromLevel <= visibleLocationLevel` aus Level-Config - Bahnnetz als gestrichelte Polylines (5 Kanten Wien-München-Hamburg- Rotterdam-Paris-München) - RAF-Loop ruft `tick(deltaMs)` und `updateStatusUI()` - Speed-Buttons (1×/2×/4×/8×) mit `aria-pressed`-Toggle, ≥36px - Pause-Button mit kontextsensitiven Übergängen (READY→PLANNING→RUNNING ↔ pause/resume) - Status-Leiste live: Sim-Zeit, Konto, Bilanz, Aufträge x/y, State - Save/Load via localStorage (Phase 1 Skelett, Server-API in Phase 7) - Autosave-Hook via onStateChange (localStorage) - Sprachregel 4a durchgehend („Bearbeiter:in", „Simulation", „Durchgang", „Sim-Zeit") — nirgends „Spieler"/„Spiel" - **test.html erweitert um Test 11 (10 Cases) Phase 1:** - 11.1 deterministic createGame → reproduzierbare sessionId+startTime - 11.2 State-Übergänge INIT→LOADING_CONTENT→READY - 11.3 startPlanning + startSimulation - 11.4 tick(1000ms, 1×) → +1 Sim-Min - 11.5 tick(1000ms, 4×) → +4 Sim-Min - 11.6 paused tick → keine Zeit-Änderung - 11.7 50× tick auf zwei Instanzen mit Seed 99 → identische simulationTime - 11.8 onStateChange protokolliert alle 4 Übergänge - 11.9 Zeitlimit überschritten → state=LEVEL_FAILED - 11.10 serialize/deserialize Roundtrip + Listener-Reaktivierung - Test 7 (Bahn-Dijkstra) erweitert um Wien→Paris (1220 km) und Wien→Rotterdam (1700 km via Hamburg, nicht via Paris) - **noop-Strategie weiterhin lauffähig:** noop nutzt eigenen Mini-Loop (`simHours += 1`), keine engine.tick-Abhängigkeit → läuft ohne Phase-2-Implementierung weiter. Test 10 grün-erwartet. - **Mathematische Verifikation (Python 1:1):** Tick-Konversion, Dijkstra-Pfade, Mulberry32 — alle neuen Cases verifiziert. **Verbliebene Stubs (Phase 2+):** `assignContract`, `calculateRoute`, `useHint`, `applyMinigameResult`, sowie die Strategien `naive/greedy/optimal`. **Nächstes (Phase 2):** Auftrags-Generierung + Fahrzeug-Bewegung + Routen-Visualisierung → Level 1 spielbar **Blocker:** keiner — Atlas hat „keine weiteren Reviews bis Phase 1 fertig" gesagt, ich starte Phase 2 nach Thomas-Test **Offen für Thomas:** - Browser-Test `http://localhost/geograsim/App/sims/logistik/test.html` (Test 1–11, ~36 Cases) - Browser-Test `http://localhost/geograsim/App/logistik?level=1` (Karte sichtbar, Pause-Button startet Sim-Zeit, Speed-Buttons schalten) ## Tagesabschluss 2026-04-20 (03:30) — Phase 2 ausgeliefert + Header-Fix Atlas-Phase-1-OK + grünes Licht für Phase 2 (03:00). Atlas hat mein Phase-1-Plan-§6 1:1 übernommen und „keine weiteren Reviews bis Phase 2 fertig" gesagt. Header-Klassen-Anfrage von 02:45 wurde nicht direkt beantwortet (Überschneidung), aber das Template ist die Wahrheitsquelle — Header habe ich selbst aufs Template-Pattern umgestellt (kein Klassen- Erfinden, nur 1:1-Übernahme). ### Header-Fix (vor Phase 2) - Klassen auf Template-Muster: `ggs-header-logo` + `ggs-header-logo-icon` + `ggs-header-logo-text` + `ggs-header-separator` + `ggs-header-module` + `ggs-header-badge` + `ggs-header-spacer` + `ggs-header-actions` + `ggs-speed`/`ggs-speed-btn` + `ggs-btn-ghost` - Pause-Button als `data-speed="0"` integriert (Template-Vorschlag) - Lehrplan-Link `📚` ergänzt (verweist auf modul-logistik.php#lehrplan-bezug) - Eigene CSS-Override-Regeln entfernt (DS macht das jetzt sauber) - Speed-Button-Wahl steuert auch start (von PLANNING → RUNNING bei `>0`) ### Phase 2 — Engine - `calculateRoute(game, originId, targetId, mode)` — Phase-2-Strategie Luftlinie × 1.3, liefert Route mit Geometrie + Distanz + Dauer + Segments. Provider markiert als `airline_x1.3` (Phase 3 ersetzt mit Hand-Polylines). - `assignContract(game, contractId, vehicleId)` — Validierung, Routenberechnung, Vehicle springt zur Origin (kein Pickup-Drive in Phase 2), States werden gesetzt. - `_updateVehicles(game, simMinutes)` im tick — Routen-Interpolation, bei Ankunft Vehicle→IDLE, Contract→DELIVERED - `_completeContract` — Verspätung berechnen, Erlös + Bonus−Fahrkosten−Strafe buchen, Contract in completedContracts, Notification, Auto-Folgeauftrag generieren (Phase-3-Vorgriff für L1-Spielbarkeit) - `seedInitialVehicles(game)` — Level-Config-driven Vehicle-Erstellung (L1: 1× TRUCK_SMALL in Wien) - `seedInitialContracts(game)` — Level-1: 1× Wien→Salzburg fest - `tick` erweitert um Erfolgsprüfung (Time-Limit-Erreichung mit minTarget → LEVEL_SUCCESS, sonst LEVEL_FAILED) ### Phase 2 — Headless-Runner - `naive`-Strategie aktiviert: nimmt erstes OPEN ↔ erstes IDLE, tickt 5 Sim-Min/Iter bis state≠RUNNING. Nutzt opts.seeds wenn übergeben (für Tests ohne window.LOGISTIK_SEEDS). - runLevel ruft createGame mit deterministic+seed - noop bleibt unverändert lauffähig (eigener Loop, keine engine.tick-Abhängigkeit) ### Phase 2 — UI (game.html) - **Contracts-Panel** zeigt Cards pro Auftrag mit Code, Strecke, km, Erlös, Frist, State-Badge. Klick selektiert (toggleable). - **Vehicles-Panel** zeigt Cards pro Fahrzeug mit Name, Speed, Kapazität, Standort. Klick bei selected contract → assignContract. - **Routen-Polylines** (durchgezogen, dunkelgrün) für jede activeRoute - **Fahrzeug-Marker** als 🚚/🚆 (DivIcon), Position aus RAF-Loop - **Hilfestufe BLINK_EXACT** (Phase 5 vorgegriffen): blinkende Ringe um Origin (gelb) und Target (rot) bei selected contract - **Toast-Notifications** bei Delivery (mit Net-Betrag) - **Sprachregel 4a** durchgehend (Aufträge, Bearbeiter:in, etc.) ### Phase 2 — Tests (test.html) - Test 12 (5 Cases) — calculateRoute Wien→Salzburg ≈ 326 km × 1.3 - Test 13 (8 Cases) — assignContract State-Übergänge + doppelte Zuweisung wirft - Test 14 (3 Cases) — tick bewegt Vehicle (segmentProgress strikt zwischen 0/1) - Test 15 (6 Cases) — Delivery + Erlös + Folge-Auftrag automatisch - Test 16 (3 Cases) — latePenaltyOverride wird respektiert + analytics++ - Test 17 (5 Cases) — naive auf L1 schafft Akzeptanzkorridor (≥4 Aufträge, Profit ≥ +1000€, success=true) - Test 10.3 angepasst: greedy wirft jetzt „Phase 2", naive ist aktiv ### Mathematische Verifikation (Python 1:1) - Wien-Salzburg airline = 250.82 km, × 1.3 = 326.06 km, 4.66 h @ 70 km/h - Pro Auftrag: Net 792.27€ (1300€ Erlös − 507.73€ Fahrkosten) - 24h / 4.66h = 5 Aufträge schaffbar - Gesamtprofit: 3961€ > 3000€ Min-Ziel → success ✓ **L1 ist spielbar.** Im Browser: Klick auf Auftrag (blinkende Ringe) → Klick auf LKW → Fahrt beginnt → 1× oder 4×/8× Speed → LKW fährt nach Salzburg → Toast „Auftrag abgeschlossen +792€" → Folge-Auftrag erscheint. **Nächstes (Phase 3):** Mehrfahrzeuge, Mehraufträge mit Variation, Kostenmodell für Miete/Standkosten, Hand-Polylines für 12 Hauptstrecken, Level 2 spielbar. Ziel: ~50% schaffen L2 mit greedy, ~70% mit optimal. **Blocker:** keiner — Atlas hat „direkt Level 1 spielbar → Thomas- Browsertest → Phase 3" gesagt. Header-Klassen-Frage 02:45 ist faktisch durch Selbstkorrektur auf Template gelöst, aber Atlas könnte noch beanstanden falls anders gemeint. **Offen für Thomas:** - Browser-Test `App/logistik?level=1`: 1 Auftrag links, 1 LKW rechts, klicken → blinkende Ringe → LKW klicken → Fahrt → Toast bei Ankunft → Folge-Auftrag → Bilanz wächst - Test-Harness `App/sims/logistik/test.html`: 17 Gruppen, ~60 Cases, alle grün erwartet ## Tagesabschluss 2026-04-20 (05:00) — Phase 3 ausgeliefert Atlas-Wrapper-Patch war 04:00 fertig, Thomas hat Phase 2 live gesehen und sofort gefragt, ob die LKW Hauptstraßen statt Luftlinie fahren können — exakt Phase 3 nach Plan. Grünes Licht erteilt, gestartet. ### Phase 3 — Hand-Polylines + Engine - **`App/assets/data/lg-routes-osm.json`** — 17 Hauptstrecken zwischen den 13 Locations mit handgepflegten Polyline-Stützpunkten an bekannten Knoten (St. Pölten, Linz, Brennerpass, Lille, Reims, etc.). Bidirektional. Polyline-Längen via Python verifiziert. - **`engine.calculateRoute` Phase 3** — Polyline-Lookup (Forward + Reversed), Fallback auf Luftlinie × 1.3. Provider-Markierung (`osm_polyline` / `osm_polyline_reversed` / `airline_x1.3`). - **Pickup-Drive** in `assignContract`: wenn Vehicle nicht am Origin, zweistufige Route (Pickup + Delivery) - **4-Phasen-Trip** in `_updateVehicles`: pickup_drive → loading → delivery_drive → unloading. Mit Phase-Übertrag-Loop (kein Drift bei großen Ticks) - **`_completeContract`** mit `vehicle`-Param: noEmpty-Bonus korrekt, Pickup-Fahrkosten zusätzlich, `contract.pickupKm` für Tracking - **Kostenmodell** im tick (`_applyRunningCosts`): Standkosten/h für IDLE-Vehicles, Miete/Tag für alle Vehicles - **Auftrags-Variation** deterministisch (Mulberry32 + Counter): 12 `CONTRACT_TEMPLATES`, L2/L3 ziehen daraus, L1 hardcoded auf **Wien↔Salzburg-Pendel** (vermeidet Leerfahrten, hält naive im Akzeptanzkorridor) - **`seedInitialVehicles`** verteilt auf Hubs (L1: Wien; L2: Wien/ München/Hamburg; L3: 5 Hubs) ### Phase 3 — Headless-Runner - **`greedy`-Strategie aktiviert**: höchster rewardBase ↔ größtes Vehicle das passt ### Phase 3 — Tests 5 neue Gruppen, 19 neue Cases (Test 18-22). Total **22 Gruppen / ~80 Cases**. ### Mathematische Sanity-Checks (Python) - L1 Pendel mit airline-Fallback: 4 Trips × 792€ = 3169€ > 3000€ Min ✓ - L1 mit Polyline (kürzer): noch profitabler - L2/L3 Akzeptanzkorridor: nicht erfüllt (siehe Balance-Hinweis unten) ### Atlas-Wartepunkt Wrapper-Erweiterung in `logistik.php` für `lg-routes-osm.json` (siehe Atlas-Mail 2026-04-20-0500). Bis dahin fahren LKWs im Browser noch auf Luftlinie × 1.3. Test-Harness unbetroffen (Inline-Seeds). ### Balance-Hinweis (für künftige Tuning-Iteration) L2/L3-Akzeptanzkorridor mathematisch noch nicht erfüllt. Pflichtenheft gibt `rewardBase=1000` fix (unabhängig von Container/Distanz). Mit Pickup-Drive werden lange Strecken (>500km) verlustig. Tuning für Phase 4+ (z.B. Reward proportional zur Distanz). Test 22 prüft nur strukturelle Lauffähigkeit. ### Offen für Thomas - Atlas-Wrapper-Update abwarten, dann Browser-Test L1 (Pendel-Modus, Polyline-Routen sichtbar — LKW fährt entlang St. Pölten-Linz-Wels statt diagonal durch die Donau) - Test-Harness `test.html`: 22 Gruppen / ~80 Cases sollten alle grün ## Tagesabschluss 2026-04-20 (06:00) — Phase 4a + Music ### Music-Player aktiv - 4 Tracks aus `.humanInput/Background Music/_claimed/` kopiert nach `App/sims/logistik/sounds/music/`: - `saddlewood-metronome.mp3` (3 MB, mechanisch-rhythmisch) - `gears-and-marbles.mp3` (3.2 MB, Steve-Reich-Stil) - `barbed-lullaby.mp3` (3.2 MB) - `untitled-instrumental.mp3` (2.9 MB) - `.ggs-music`-Markup im Header eingebaut (Pattern aus template.html) - `ggsMusicSetup`-Funktion inline (gleicher Code-Pfad wie Klima/Fluss) - Default-Volume 22 %, localStorage `ggs-music-logistik` ### Phase 4a — Engine - **TRAIN-Routing**: `calculateRoute` nutzt für mode=TRAIN den `railShortestPath`-Dijkstra über `worldState.railnet`. Wenn beide Locations Bahnknoten sind, kommt eine echte Mehr-Segment-Route raus (provider: `rail_dijkstra`), sonst Fallback auf Polyline/airline. Geometrie führt durch alle Bahnknoten. - **Hafen-Schiffsankünfte**: `_maybeGenerateShipArrival(game)` läuft im tick, alle 6 Sim-Stunden ein Schiff (deterministisch via Counter). Generiert OPEN-Auftrag mit Origin=Hafen, Target=Hauptstadt-Pool rotierend. Code-Präfix `SHIP-`, `narrativeText` erwähnt Hafen, Notification `SHIP_ARRIVED`. Nur aktiv bei `cfg.portsEnabled=true`. - **Container-Standkosten**: `_applyRunningCosts` rechnet zusätzlich zu Vehicle-Standkosten/Miete auch `containerStandCostPerHour × quantityContainers × simHours` für jeden OPEN-Auftrag mit Origin am Hafen. ### Phase 4a — Tests (3 neue Gruppen, ~10 Cases) - Test 23 (5): TRAIN-Routing über railnet-Dijkstra (Wien→Hamburg via München = 1200 km, 2 RAIL-Segmente), Fallback wenn kein Bahnknoten - Test 24 (4): Schiffsankunft-Generator (nach 7h Sim mit portsEnabled → SHIP-Auftrag + Notification) - Test 25 (1): Container-Standkosten an Häfen (3 Container × 10€/h × 1h = 30€ pro Sim-Stunde abgezogen) Total jetzt: **25 Test-Gruppen, ~90 Cases**. ### Phase 4b verschoben (Intermodal) Vollständige intermodale Aufträge mit `legs[]`-Struktur und Multi- Vehicle-Übergabe (LKW→Zug→LKW) sind komplexer als die anderen 3 Phase-4-Punkte zusammen. Phase 4a deckt die Basis-Strukturen ab (Bahn-Routing + Hafen-Aufträge), 4b kommt als nächste Iteration: - Contract-Schema um `legs: [{mode, originId, targetId}]` erweitern - Engine-Logik für Übergabe zwischen Vehicles am Terminal/Hafen - Container am Hafen warten auf Folge-Vehicle (Inland-Strecke) - LOADING-Phase am Übergabepunkt mit echten Cargo-Transfer-Zeiten - Lehrziel #13 (kombinierte Verkehre) wirklich erlebbar ### Offen für Thomas - Browser-Test [App/logistik?level=1](http://localhost/geograsim/App/logistik?level=1): Music-Player rechts oben sollte sichtbar sein (Tracks wählbar, ▶ startet) - Browser-Test [test.html](http://localhost/geograsim/App/sims/logistik/test.html): 25 Gruppen / ~90 Cases sollten alle grün - Phase-4b-Entscheidung: jetzt oder erst nach L3-Tuning? ### Atlas-Wartepunkte - Wrapper-Erweiterung `lg-routes-osm.json` (von Mail 0500, noch offen) - Music-Tracks-Bestätigung (von Mail 0540, „letzten paar" akzeptiert?) ## Tagesabschluss 2026-04-20 (06:30) — Phase 4b + 5a ausgeliefert Thomas: „Arbeite weiter, soweit du kannst." → Phase 4b (Intermodal-Engine) und Phase 5a (Event-Engine) komplett implementiert. Phase 5b (Hilfestufen-UI) auf Phase 6 verschoben — passt natürlich zu Sprachregel-Check + Leichte Sprache (alles UI-Polish). ### Phase 4b — Intermodale Aufträge - **Schema**: Contract bekommt optional `intermodal: true` und `legs: [{legNum, mode, originLocationId, targetLocationId, state, assignedVehicleId, routeId, departTime, arrivalTime}]`. Plus `currentLegNum` und `currentLocationId` (wo der Container gerade ist). - **`_makeIntermodalContract(game, code, legs, containers, isExpress)`**: Factory mit Aggregations-Daten (Gesamt-Distanz approx, Gesamt-Frist, rewardBase × 1.5 als Intermodal-Bonus). - **`assignContract(game, contractId, vehicleId, legNum?)`**: - bei intermodal: `legNum` Pflicht (sonst nimmt currentLegNum) - prüft Vehicle-Mode-Match zum Leg-Mode (TRAIN-Leg → TRAIN-Vehicle) - setzt leg.state statt c.state - **`_completeLeg(game, contract, legNum, route, vehicle)`**: - markiert Leg als DELIVERED - bucht Fahrkosten dieses Legs sofort (Reward kommt am Schluss) - setzt currentLegNum/currentLocationId vor - aktiviert nächsten Leg auf OPEN (Notification `LEG_TRANSFERRED`) - bei letztem Leg: Reward + Bonus + Strafe in einem buchen, Contract als DELIVERED/LATE in completedContracts - **`_stepVehiclePhase` UNLOADING**: erkennt intermodal und ruft `_completeLeg` statt `_completeContract` **Wichtig**: Strategien (naive/greedy) sind Phase 4b NICHT angepasst — sie würden auf intermodal-Aufträgen mit Mode-Mismatch crashen. Phase 4c oder Phase 5 für Strategy-Anpassung. UI ebenfalls noch nicht intermodal-tauglich; Tests testen explizit via _makeIntermodalContract. ### Phase 5a — Event-Engine - **`_maybeGenerateEvents(game, simMinutes)`**: würfelt deterministisch via Mulberry32 (`game.seed ^ 0xE7E7` + Counter `_eventsRngCalls`). Pro Sim-Stunde-Block + EVENT_TYPE: `prob = baseProb × eventProbabilityMultiplier` - **EVENT_RULES** (aus PH 65.5): TRAFFIC_ACCIDENT 5 % Speed×0.5, SNOW 10 % Speed×0.7 (Alpen), PORT_DELAY 8 % Loadtime×1.5 - **Event-Dauer**: 30-120 min (deterministisch via 2. Würfel) - **`_expireEvents(game)`**: filtert abgelaufene Events - **`_vehicleSpeedMultiplier(game)`**: kombiniert alle aktiven Events multiplikativ → wirkt im `_stepVehiclePhase` auf `route.totalDurationMinutes` - **Notifications**: `EVENT_STARTED` mit Emoji-Message (🚧 Unfall, ❄ Schnee, ⚓ Hafenüberlastung) ### Phase 5b — Hilfestufen-UI verschoben auf Phase 6 `contract.hintMode` ist schon im Schema (Phase 0/2), `BLINK_EXACT` ist visuell umgesetzt (Phase 2). Die anderen 4 Stufen (`SHOW_COUNTRY`, `SHOW_REGION`, `DISTANCE_FEEDBACK`, `NONE`) brauchen UI-Erweiterung und passen natürlich zu Phase 6 (UI-Polish + Sprachregel + Leichte Sprache) — alle drei drehen an der Darstellungs-Schicht. ### Phase 4b + 5 — Tests 5 neue Cases: - Test 26 (4 Cases): Intermodal-Schema (legs[], States) - Test 27 (8 Cases): Multi-Leg-Trip (Rotterdam_Hafen→Hamburg→München) - Test 28 (3 Cases): Event-Generierung deterministisch + reproduzierbar - Test 29 (1 Case): Manuelles Event reduziert Vehicle-Speed - Test 30 (2 Cases): Events laufen nach Dauer ab Total jetzt: **30 Test-Gruppen, ~110 Cases**. ### Was noch offen ist (Phase 6, 7, weitere) - Phase 6: Hilfestufen-UI, 1× Minigame (An-die-Rampe-Einparken), Sprachregel-4a-Check aller UI-Texte, Leichte-Sprache via `pickText()`, Glossar-Begriffs-Anbindung - Phase 7: Lehrkraft-Konfiguration (über Admin-Tool), Analytics-Dashboard (Kennzahlen aus PH 23.2) - Strategie-Anpassung: greedy für intermodal, optimal-Strategie - Balance-Tuning für L2/L3 (rewardBase distanzproportional?) ### Browser-Tests offen - Test-Harness: 30 Gruppen / ~110 Cases sollten alle grün - Live-UI: Music-Player + LKW-Polylines (nach Atlas-Wrapper-Update) ## Tagesabschluss 2026-04-20 (07:00) — Phase 6 ausgeliefert Thomas: „Mach weiter. Direkt Phase 6 machen." → UI-Polish komplett in 3 Subphasen. ### Phase 6a — Sprachregel + pickText + Hilfestufen + Glossar + Events - **Sprachregel-4a-Audit**: alle UI-Texte sauber (nur interne Doc-Comments enthalten „Spielzustand"/„spielbar" — laut Atlas-Briefing erlaubt) - **pickText-Helper** mit Easy-Detection: `?easy=1` URL-Param oder `localStorage 'logistik:easy'='1'` schaltet auf Leichte-Sprache-Variante - **GLOSSAR-Fallback** (Pattern aus Fluss): 16 Begriffe inline definiert (Container, Intermodal, Umschlag, Luftlinie, Disposition, Frist, Leerfahrt, Standkosten, Bahnterminal, Hafen, Routing, Spedition, Logistikkette, Auftrag, Fahrzeug, Logistik). Wenn Atlas/Glossar später DB-API liefert → Fallback bleibt als Backup. - **Glossar-Click-Handler**: `.ggs-glossar-popup` Pattern aus Design-System - **Glossar-Markups** in Auftrags-Karten + Hint-Texten + Didaktik-Text - **5 Hilfestufen visuell** (PH 10.3): - BLINK_EXACT: ✓ Origin (gelb) + Target (rot) blinken (war Phase 2) - SHOW_COUNTRY: alle Locations im selben Land wie Target leuchten - SHOW_REGION: alle Locations in selber Region leuchten (sanftes Blau) - DISTANCE_FEEDBACK: Skelett (UX-Mechanik kommt mit Phase 7+) - NONE: nichts angezeigt - **Event-Panel** im Didaktik-Bereich: aktive Events als Pills („🚧 Unfall · noch 25 min", „❄ Schnee · noch 60 min") - **pickText in Toasts**: standard + easy für Auftrag-Zuweisung, Delivery-Result, Fehlermeldungen - **CSS für `[data-glossar]`**: dotted-Underline + cursor:help ### Phase 6b — Intermodal-UI - **Auftrags-Karte** erkennt `c.intermodal` und zeigt **Leg-Liste** als Pills (durchgestrichen=DELIVERED, fett-grün=OPEN, grau=WAITING) - **🔗-Symbol** im Auftrag-Titel bei Intermodal - **Mode-Filter im Vehicles-Panel**: bei selected intermodal-Auftrag werden Vehicles, deren Mode nicht zum aktuellen Leg passt, als „busy" angezeigt mit Hint „benötigt: 🚆 Zug" / „benötigt: 🚚 LKW" - **Click-Handler** übergibt `currentLegNum` an `assignContract` - **Bei Intermodal**: Auftrag bleibt selected nach Vehicle-Wahl (für Folge-Legs) - **Demo-Hook**: `?demo-intermodal=1` triggert Beispiel-Auftrag Rotterdam_Hafen → Hamburg → München bei L3 - **Strategien angepasst**: naive/greedy filtern intermodal-Aufträge raus (Phase 6c oder Tuning-Iteration für intermodal-fähige Strategien) ### Phase 6c — Minigame „An-die-Rampe-Einparken" - **Engine: `applyMinigameResult(game, result)`** implementiert (war Stub): - Speichert `loadingTimeFactor` aus `result.metadata` in `game._loadingTimeModifier` - Wirkt auf nächste LOADING-Phase (in `assignContract`), danach Reset auf 1 - Trackt `analytics.minigamesPlayed` + `minigamesSuccessful` - Generiert `MINIGAME_DONE`-Notification - **UI: Modal mit Canvas** (420×200), Top-Down-View - **Steuerung**: Touch-Buttons ⬅ ➡ + 📦 Andocken (iPad-tauglich, ≥44px) - **Bewertung**: - LKW-Vorderkante in 12 px um Rampen-Mitte → perfect → factor 0.8 (−20 %) - 12-30 px → ok → factor 1.0 - >30 px → miss → factor 1.3 (+30 %) - **PH 65.9 Werte exakt umgesetzt** - **Trigger-Button 🎮 im Header** sichtbar wenn `cfg.minigamesEnabled=true` (L2/L3) - **pickText** für alle Minigame-Texte (standard + easy) ### Phase 6 — Tests - Test 31 (4 Cases): applyMinigameResult setzt Modifier, wird in nächster LOADING-Phase angewendet (5 × 0.8 = 4 min), dann Reset - Test 32 (1 Case): Minigame-Fail erhöht Loading auf 6.5 min (5 × 1.3) Total jetzt: **32 Test-Gruppen, ~115 Cases**. ### Was Phase 6 NICHT enthält - Strategien-Anpassung für intermodal (Phase 6d / Tuning) - DB-Glossar-API (Atlas + Glossar-Instanz) - DISTANCE_FEEDBACK voll umgesetzt (braucht Klick-zum-Wählen-UX) - Keine API-Endpunkte - Kein Lehrkraft-Konfig-UI (Phase 7) ### Browser-Tests offen - [test.html](http://localhost/geograsim/App/sims/logistik/test.html): 32 Gruppen / ~115 Cases - [App/logistik?level=1](http://localhost/geograsim/App/logistik?level=1): Glossar-Begriffe (gepunktete Unterstreichung) anklickbar; Music-Player - [App/logistik?level=2](http://localhost/geograsim/App/logistik?level=2): + Minigame-Button 🎮 im Header - [App/logistik?level=3](http://localhost/geograsim/App/logistik?level=3): + Bahn-Layer + Häfen + Schiffsankünfte + Events sichtbar im Panel - [App/logistik?level=3&demo-intermodal=1](http://localhost/geograsim/App/logistik?level=3&demo-intermodal=1): + intermodaler Demo-Auftrag mit 2 Legs (LKW Rotterdam_Hafen→Hamburg, Zug Hamburg→München) - [App/logistik?level=1&easy=1](http://localhost/geograsim/App/logistik?level=1&easy=1): Leichte-Sprache-Modus aktiv ### Atlas-Wartepunkte - Wrapper-Erweiterung `lg-routes-osm.json` (Mail 0500) - Glossar-Begriffe (Anfrage 0010, Atlas koordiniert) - Music-Tracks-Bestätigung (Mail 0540) ## Tagesabschluss 2026-04-21 (Phase 8) — Multi-Contract-Tour Thomas's Konzept übernommen: **Vehicle-first-Lademodus**. 1. Klick auf IDLE-Vehicle → Lademodus aktiv (Banner + Laderaum-Slots) 2. Klick auf OPEN-Auftrag → wandert in den LKW (Cargo-Emoji im Slot) 3. „🚀 Fahrt starten" → Multi-Stop-Tour beginnt **Engine-API neu:** - `loadContract(game, vehicleId, contractId)` — Kapazität-Check, Mode-Check, Contract → RESERVED - `unloadContract` / `cancelLoading` — vor Fahrt-Start - `startTour(game, vehicleId)` — baut Stops (alle Pickups erst, dann alle Dropoffs in Klick-Reihenfolge), konsolidiert aufeinanderfolgende Stops am gleichen Ort, berechnet Routen pro Segment, startet erste Phase **Trip-Phase neu:** - `tour_driving` (zwischen Stops) und `tour_handling` (an einem Stop laden/entladen) - `_stepVehiclePhase` durchläuft Stops sequentiell, bucht Fahrkosten pro Segment sofort, Reward bei Dropoff - `_endTour` setzt Vehicle zurück auf IDLE **Cargo-Typen mit Emojis:** - `lg-cargo-types.json` um `emoji`-Feld erweitert (📱 Elektronik, 👕 Kleidung, ⚙️ Maschinen, 🥫 Lebensmittel, 🧪 Chemie, 🔩 Fahrzeugteile, 🪵 Holz/Papier, 🪨 Rohstoffe) - `CONTRACT_TEMPLATES` haben jetzt `cargoTypeIds`-Liste pro Strecke - `_nextContractTemplate` zieht deterministisch einen Cargo-Typ - Laderaum-Slots zeigen das Cargo-Emoji des belegenden Auftrags **UI-Lademodus:** - Vehicle-Card zeigt Banner + Laderaum-Grid (cap-viele Slots, gefüllt mit Cargo-Icons) - „🚀 Fahrt starten"-Button (disabled bei leer) und „↺ Abbrechen" - Klick auf RESERVED-Auftrag macht nichts (Card ist busy-styled) - Wechsel zu anderem Vehicle: altes Vehicle wird automatisch entladen (cancelLoading) **Bestehende Pfade unangetastet:** - `assignContract` bleibt für intermodale Aufträge (selectedContractId-Pfad) - Engine-Tests 13–17 nutzen weiter assignContract → laufen unverändert - Intermodal hat eigenen 4-Phasen-Trip (pickup_drive/loading/delivery_drive/unloading), nicht den neuen Tour-Pfad **Was Phase 8 NICHT enthält (Phase 9 / nice-to-have):** - Tour-Route-Vorschau auf der Karte vor „Fahrt starten" (geplante Stops als gestrichelte Linie) - Klick-Animation „Container wandert in den LKW" - Naive/greedy-Strategien wurden noch nicht angepasst (filtern intermodal+RESERVED) - Optimierungs-Button („Reihenfolge optimieren ✨") - Während-der-Fahrt-Nachladen (an Stops zusätzliche Aufträge dazunehmen) **Browser-Test:** - [http://localhost/geograsim/App/logistik?level=3](http://localhost/geograsim/App/logistik?level=3) - Zug-Card klicken → Banner „Lademodus aktiv" + 20 Slots - Aufträge nacheinander reinklicken — Container füllen sich mit Emoji - „🚀 Fahrt starten" — Zug fährt erst alle Pickup-Orte, dann alle Dropoff-Orte ab - Bei selber Origin: Stops werden konsolidiert (1 Pickup für mehrere Aufträge) ## Tagesabschluss 2026-04-20 (08:00) — Phase 7a: Analytics + Balance-Tuning Thomas: „mach weiter" → Phase 7 angepackt. Teile, die Plattform-Domain sind (Lehrkraft-Admin + API-Endpunkte + DB-Migration), an Atlas übergeben (Mail 0800). Modul-Seite von Phase 7 ist fertig: ### Balance-Tuning: rewardBase distanzabhängig - `_computeReward(distanceKm, isExpress)` in Engine - PH-Base + `max(0, (km - 300) × 1.5)` Zuschlag - Kurze Strecken bleiben PH-kompatibel (Wien-Salzburg: 1000→1039€) - Lange Strecken profitabel (Wien-Hamburg: 1000→2350€) - Intermodal-Bonus × 1.5 bleibt erhalten - Python-verifiziert: L1-Pendel-naive bleibt schaffbar (845€ × 4 = 3380€) ### Analytics-Tracking in Engine - `totalRewardEarned`, `totalPenaltyPaid`, `totalFareCostPaid` - `runningCostsTotal` (war schon da) - `contract.durationHours` pro abgeschlossenem Auftrag ### UI — Analytics-Panel - Toggle-Button 📊 oben rechts auf der Karte - 12 Kennzahlen live (Aufträge, Leerfahrtenquote, Verspätungsquote, Ø-Net/Auftrag, Erlöse, Fahrkosten, Strafen, Standkosten+Miete, Minigame-Erfolg, Bilanz/Profit) - Live-Update im RAF-Loop bei offenem Panel ### UI — End-Screen - Overlay bei State-Wechsel zu LEVEL_SUCCESS / LEVEL_FAILED - Success in grün, Fail in rot - Gekürzte Stats-Liste (5 wichtigste Werte) - pickText für standard/easy - „Neuer Durchgang"-Button reloaded Seite - Via `onStateChange`-Hook automatisch getriggert ### Was bei Atlas liegt (Phase 7b) - Lehrkraft-Admin-Tool (admin-levels.html erweitern vs. separat) - API-Endpunkte `App/php/api/logistik-*.php` — ich kann selbst, erwarte Go - DB-Migration `lg_contracts_log` — Freigabe vom Schema - Glossar-API-Anbindung falls die 13+ Begriffe angelegt sind ### Offen für Thomas - Browser-Test L1/L2/L3: Analytics-Button 📊 rechts oben, End-Screen nach Zeitlimit oder Min-Ziel-Erreichen - Die Balance-Tuning-Änderung macht L1 leichter, L2/L3 besser spielbar ## Tagesabschluss 2026-04-20 (07:30) — UX-Iteration „Fahrzeug-Auftrags-Verbindung" Thomas: „wenn der Auftrag angenommen wurde und das Fahrzeug unterwegs ist, wäre es schön, wenn irgendwo erkennbar wäre, dass diese Verbindung wirklich vorliegt." → drei Mechanismen ineinandergreifen lassen. ### Was neu ist - **Vehicle-Card zeigt Trip-Info** bei MOVING/LOADING/UNLOADING: - Phase-Label („🟡 Leerfahrt zum Abholen", „📦 Lädt", „🟢 Unterwegs", „📥 Lädt ab") - Auftrag-Code + Strecke („C-001 · Wien → Salzburg") - Progress-Bar bei Fahrten (live aus `v.segmentProgress`) - ETA („ETA 14:32") oder Restdauer („noch 3 min") je nach Phase - **Vehicle-Marker mit Hover-Tooltip** (Leaflet `bindTooltip`, sticky): Name, Phase, Auftrag, Prozent-Fortschritt - **Klickbares Pairing**: - Klick auf Vehicle-Card oder -Marker → selectedVehicleId - Zugehörige Contract-Card bekommt `linked-pair`-Highlight (blauer Ring) - Vehicle-Card bekommt `linked`-Highlight (grüner Ring) - Zugehörige Route wird auf der Karte dicker+kräftigrot, andere Routen werden gedimmt - Klick zentriert die Karte auf's Fahrzeug - Erneuter Klick deselect - **Auto-Deselect**: wenn Vehicle IDLE wird (Delivery fertig) → Selection automatisch gelöscht ### CSS-Klassen neu - `.lg-trip-info` (+ `.pickup`, `.loading`) — Trip-Box unter Vehicle-Titel - `.lg-progress-bar` + `.lg-progress-fill` (+ `.pickup` für gelb) - `.lg-card.linked` (grün) + `.lg-card.linked-pair` (blau) ### Keine neuen Tests UX-Erweiterung (visuell), kein Engine-Change. Test-Gruppen bleiben bei 32. ### Offen für Thomas - Browser-Test [App/logistik?level=1](http://localhost/geograsim/App/logistik?level=1): - Auftrag klicken → LKW klicken → Fahrt startet - Jetzt: Vehicle-Card zeigt „🟢 Unterwegs · C-001 · Wien → Salzburg · ETA ..." mit Progress-Bar die mit 1×/4×/8× Speed füllt sich live - Marker-Hover auf der Karte zeigt Tooltip - Marker-Klick zentriert Karte + beide Cards sind farblich verbunden - Bei L2/L3 analog — mit mehreren aktiven Trips siehst du die Fokus- Route hervorgehoben, andere gedimmt ## Tagesabschluss 2026-04-22 — UX-Polish-Sprint + Atlas-Phase-7b-Entscheidungen ### Neue Atlas-Nachricht (1200, gelesen + quittiert) `2026-04-22-1200-phase7-entscheidungen-und-db.md` — Atlas hat nach 2 Tagen Pause alle drei offenen Punkte entschieden: 1. **Lehrkraft-Admin**: Atlas erweitert `App/admin-levels.html` (zentrales Tool). **Mein Beitrag:** `App/sims/logistik/admin-fields.json` mit Feld-Beschreibungen aus balance-matrix.md §5. 2. **API-Endpunkte**: Ich baue selbst, Pattern aus `App/php/api/glossar.php`. Drei Endpunkte: `logistik-sessions.php`, `logistik-saves.php`, `logistik-analytics.php`. Security: Session-ID gegen `student_sessions` validieren. Kein formales Review, ich committe wenn zufrieden. 3. **DB-Migration `lg_contracts_log`** erledigt. Schema erweitert um `intermodal`, `route_distance_km`, `route_mode`. Meister pingt Atlas für Produktions-Replikation. 4. Glossar-API: Fallback bleibt, Switch wenn Glossar liefert. Pattern kommt in `App/docs/module-interface.md`. Thomas-Frage „nächstes Modul" → Atlas sagt: erst nach Phase 7b. ### Phase 8 + UX-Iterationen (heute + gestern) - **Multi-Contract-Tour**: Vehicle-first-Lademodus, Cargo-Icons (📱👕⚙️🥫🧪🔩🪵🪨), Klick-Reihenfolge-Tour (Pickups zuerst, dann Dropoffs; konsolidiert aufeinanderfolgende Stops am gleichen Ort), Laderaum-Slot-Visualisierung, „🚀 Fahrt starten" / „↺ Abbrechen" - **Container-Visualisierung**: bis 6 Container als einzelne 📦-Symbole, ab 7 als „N× 📦". Mit Glossar-Popup (TEU + metrische Maße) - **Scale-Bar** auf Leaflet-Karte (unten-links, metrisch, bis 100 km) - **Pro-Vehicle-Farben** (8 Palette-Farben): Vehicle-Card-Dot, Marker-Ring, Route-Farbe (durchgezogen Lieferfahrt, dünn gestrichelt Pickup-Leerfahrt) - **Event-Symbole** auf der Karte: 🚧 Unfall (Mittelpunkt einer aktiven Route), ❄ Schnee (Alpen-Region ±0.8°), ⚓ Hafenüberlastung (am Hafen) - **Rote Routen bei Verspätung** (dashArray, überschreibt Vehicle-Farbe) - **Analytics-Panel gedämpft** (1 Hz statt 60 Hz), Status-Leiste 4 Hz - **Farbleitsystem**: OPEN grün · PICKUP/LOADING/IN_TRANSIT orange · DELIVERED blau · LATE rot · WAITING beige. Deutsche Labels mit pickText - **State-Labels deutsch**: „offen"/„Abholung läuft"/„unterwegs"/„geliefert"/... - **Vehicle-Auftrag-Verbindung**: Klick auf Vehicle (trip-aktiv) oder Marker → Fokus-Route rot-dick, andere gedimmt, passende Contract-Card mit blauem Ring (`linked-pair`). Vehicle-Card mit Progress-Bar + ETA - **Analytics-Panel + End-Screen** (Phase 7a) - **Balance-Tuning** (Phase 7a + 8): `_computeReward` distanz-proportional + Container-Komponente (+250 €/zusätzl. Container), CONTRACT_TEMPLATES auf mehr 1-Container-Ranges (damit kleiner LKW nützlich wird) - **Drei-Kommastellen-Fix**: `fmtEuro()` + `fmtEuroSigned()` runden überall auf ganze Euro (Status, Toast, Analytics, End-Screen) ### Minigame-Komplettumbau (mehrere Iterationen heute) - **Grüne Zielzone** (LKW-Größe + 3 px Toleranz), sichtbar schraffiert mit „🎯 Hier parken"-Beschriftung - **Referenz-Miniaturen** (3× 130×70 Canvas): ✅ Rückwärts · ❌ Vorwärts · ❌ Schief - **Countdown 3:00** rückwärts, MM:SS-Format, warnt bei <60 s orange, <30 s rot - **Auto-Andocken** sobald 0,3 s stabil in grüner Zone + rückseitig + langsam - **Rückseitig-Pflicht**: Nur angle ≈ 180° (Heck zur Rampen-Rückwand) zählt als „richtig" - **Live-Dock-Status**: „✓ Zone · ✗ Heck zur Rampe (45°) · ✓ still" - **Crash-Szenarien** → Game Over, factor 1.5: - Anderes Fahrzeug rammen - Bucht-Wand mit v>55 UND tiefem Overlap - Zeitablauf (3 min) - **Active Mover** ab L2 sichtbar im Feld: fahrendes Fahrzeug mit Waypoints + sanfter Lenkung (Math.atan2 + max-turn-rate), wraps am Rand - **Zeit → Ladezeit-Faktor**: <15 s → 0.7× / 15-30 s → 1.0 / 30-60 s → 1.2 / 60-180 s → 1.3 / Crash/Timeout → 1.5 - **LKW-Optik** verbessert: Kabine + Auflieger, Frontscheibe, Scheinwerfer, 6 Räder mit gelenkten Vorderrädern, Schatten - **Web-Audio-Sounds** (synthesized, kein externer File nötig): - Engine-Brummen: Sägezahn 55-200 Hz, Volume skaliert mit v - Brems-Quietschen: Bandpass-Rauschen 0.25 s Burst bei abruptem v-Abfall - Crash: tieffrequenter Sinus-Sweep + Lowpass-Impuls - **Musik-Auto-Start**: Hauptmusik wird getriggert wenn Modal öffnet (click auf #ggs-music-toggle falls nicht playing) - **Buttons**: „↺ Neu starten" (gelb-warm, 46 px hoch) + „Fertig · Schließen" (dunkelgrün), beide groß und touch-tauglich - **Andocken-Button entfernt** (Auto-Detection ersetzt Manual-Check) ### Offene Arbeitsliste (Phase 7b — Atlas-Reihenfolge) 1. **`App/sims/logistik/admin-fields.json`** — Feld-Beschreibungen aus balance-matrix.md §5 (15 Min Arbeit) 2. **`App/php/api/logistik-sessions.php`** — POST start/end, GET status 3. **`App/php/api/logistik-saves.php`** — POST save, GET load (gegen `game_saves.save_data` JSON, Engine `serialize()` schon bereit) 4. **`App/php/api/logistik-analytics.php`** — POST in `lg_contracts_log` (Schema Atlas bereits angelegt) 5. **Analytics-Logging in `_completeContract`-Hook** — pro Delivery POST an Analytics-API ### Nicht-Blocker-Wartepunkte - Wrapper-Erweiterung `lg-routes-osm.json` (Mail 0500) — Atlas hatte bestätigt 0400 als Tile-Proxy-Patch, Routes-Seed aber weiterhin offen. Browser-LKW fahren weiterhin Luftlinie × 1.3 (Fallback). Tatsächlich: `engine.loadContent` liest `window.LOGISTIK_SEEDS.routesOsm` falls gesetzt → wenn Atlas den Wrapper erweitert, greift Polyline-Routing automatisch. - Glossar-API-Pattern (Atlas koordiniert mit Glossar-Instanz) ### Browser-Test jetzt - [http://localhost/geograsim/App/logistik?level=2](http://localhost/geograsim/App/logistik?level=2): Multi-Tour, Minigame 🎮 mit Countdown + Sounds + Mover - [http://localhost/geograsim/App/logistik?level=3](http://localhost/geograsim/App/logistik?level=3): + Bahn + Häfen + Events + Schiffsankünfte + schnellerer Mover --- ## 2026-04-22 ~14:00 — Phase 7b ausgeliefert (nach Atlas-12:00-Mail) ### Gebaut - **`App/sims/logistik/admin-fields.json`** — alle 19 `params`-Keys aus balance-matrix.md §5 mit `label`, `labelEasy`, `type`, `unit`, `min/max/step`, `options`, `default`, `help`. Gruppiert in 7 Abschnitten (Wirtschaft, Auftragslage, Fahrzeugpool, Didaktik & Hilfen, Ereignisse, Verkehrstraeger, Sonstiges). Bonus: `availableVehicleTypes` als `multienum`, `levelNameEasy` als `text` für Leichte Sprache. - **`App/php/api/logistik-sessions.php`** — POST start/end, GET status. Persistiert ohne neue Tabelle via `game_saves` mit Namespace-Keys `logistik:active-attempt` / `logistik:history` (Ring-Puffer letzte 20 Durchgänge). Security: Cookie-Session gegen `student_sessions` validiert. - **`App/php/api/logistik-saves.php`** — GET/POST/DELETE. 5 Slots (1–5) via Keys `logistik:save:`. 500 KB-Limit. Baut auf generischer `game_saves`-Tabelle auf — keine Duplikat-Tabelle zu `saves.php`. - **`App/php/api/logistik-analytics.php`** — POST in `lg_contracts_log` (Atlas-Schema mit intermodal + route_distance_km + route_mode). GET liefert 3 Scopes: `me` (eigene letzten 50), `class` (Lehrer-only, pro Session), `level` (Lehrer-only, pro Level-Aggregation). - **Engine-Hook**: `game.pendingAnalytics` als neue Queue. `_pushAnalyticsEntry()` wird in `_completeContract` (Single) und `_completeContractMulti` (Tour) aufgerufen. Engine selbst macht keinen Netz-Call — bleibt in Node/Browser gleich testbar. UI drainiert die Queue alle 2s und POSTet (best-effort). - **game.html-Integration** — `LG_API`-Helper: fire-and-forget mit `credentials: same-origin`, 401 → bis Session-Ende offline. Auf Game-Init: `startAttempt(levelNum)`. Auf LEVEL_SUCCESS/FAIL: `endAttempt(success, stats)` + Last-Drain der Analytics. Save/Load-Buttons jetzt Server-first mit localStorage-Fallback + Leichte-Sprache-Toasts. ### Security-Minimum (wie Atlas vorgegeben) - Jeder POST validiert Session-ID aus `ggs_session`-Cookie gegen `student_sessions`-Tabelle (nicht nur Cookie-Präsenz) - Keine Fremd-Session-IDs schreibbar — `session_id` kommt IMMER aus Server-Cookie, nie aus Request-Body - DELETE/GET auf Saves nur für eigene Session - `class`/`level`-Analytics-Scopes nur mit `requireTeacher()` ### Offene Punkte (an Atlas-Review) - `logistik-saves.php` legt nicht in einer eigenen Tabelle ab, sondern namespaced im vorhandenen `game_saves`. Falls du stattdessen eine `lg_saves`-Tabelle willst, Migration + Refactor-Patch. - `logistik-sessions.php` speichert Aktiv-Attempt ebenfalls in `game_saves`. Einfach, kein Schema. Falls du reportingfähige `lg_attempts`-Tabelle willst, sag Bescheid. - Ich habe **keinen Browser-Test** gemacht — es hängt daran, ob die bestehende `ggs_session`-Cookie auch unter `/App/logistik?level=1` mitkommt (sollte dank `BASE_PATH`-Konfiguration, aber ungeprüft). ### PHP lint ``` /c/xampp/php/php.exe -l App/php/api/logistik-sessions.php → OK /c/xampp/php/php.exe -l App/php/api/logistik-saves.php → OK /c/xampp/php/php.exe -l App/php/api/logistik-analytics.php → OK ``` ### Was Atlas jetzt tun kann 1. **Admin-UI** gegen `admin-fields.json` bauen — alle Feld-Metadaten stehen 2. **Review** der 3 PHP-Endpunkte, besonders: ist die `game_saves`-Kooptierung für Sessions/Saves ok oder dedizierte Tabelle? 3. **Meister** anpingen, damit das `lg_contracts_log`-Schema auf Produktion ist 4. **Glossar-API** — sobald die 13 Begriffe da sind, einbauen (Inline-Fallback in game.html funktioniert bis dahin) --- ## 2026-04-23 — Heute gebaut (lange Session) ### Neu-Mails von Atlas (beide gelesen) - **2026-04-22 12:30 ElevenLabs-Sound-Pipeline**: zentrales Script `App/scripts/generate-sounds.py`, API-Key liegt, Pattern `App/sims/logistik/scripts/sounds-list.json`. Vorgeschlagene Liste mit 22 Sounds (~3-5 €). **Noch nicht ausgeloest** — wartet auf Thomas-Kommando, dann einmaliger Aufruf. - **2026-04-23 11:00 Integrations-Auftrag**: Logistik ist Referenz. Drei Punkte: (a) mode-check im Wrapper (logistik.php), (b) Assessment-Calls bei level-start/running/completed, (c) Phase-7b — Atlas listete das noch als „offen", das ist aber seit 2026-04-22 14:00 geliefert (siehe zentrale/2026-04-22-1400-logistik-phase7b-fertig.md). Atlas hat noch nicht reviewt. ### Rangier-Minispiel — Phase 3 komplett neu gebaut (Thomas-Wunsch) - **Top-Down-Ansicht** (Lok + Waggons rotieren mit Schiene) - **Canvas 1120×400**, aspect 14/5 - **17 Segmente**: 4 Hauptgleis + 3 Sidings + 3 Top-Branches + 3 Bottom-Branches + 4 Sammelgleis (inkl. 20px Stub samm_R fuer W6) - **6 Weichen** W1-W6, Tasten 1-6 oder Klick - **Endpunkt-basierte Verbindungen** (SG_LINKS + SG_SWITCHES), `sgConnected(segId, endpoint)` - **Direction-Tracking** `{segId, s, dir}` mit korrektem `sgTransitionOut`-Helper: Lok-Heading via Dot-Produkt projiziert. Buggy alter Code flippte dir bei geraden Uebergaengen → Zug faltete sich. Fix verifiziert. - **Consist-Modell** mit Items-Array, auto-Kupplung am Wagen-Ende (nicht an Lok-Nase → Lok-Front blockiert mit Warnung) - **Entkupplung** per ✂-Klick in Luecken (nur im Stillstand, senkrecht vom Gleis gezeichnet) - **Waggon-Labels** `#1 #2 #3 #4` statt Stadt-Emojis (Thomas-Wunsch — klarer) - **Switch-Warning**: roter pulsierender Ring + Web-Audio-Warnton (2× 880Hz Square) wenn: Lok faehrt gegen Sackgasse / Lok-Front rammt geparkte Wagen / Weiche umschalten wenn Zug drauf - **Zeit-Bonus**: < 4 Minuten → `timeBonus: true` im `applyMinigameResult`-Result ### L1-Innen-Progression (Thomas-Wunsch: steigernd) - `game.progression = { round, trucksBought }` in `createGame` - `_effectiveMaxContracts(game)`: L1 waechst dynamisch 1 → 2 (Runde 2-3) → 3 (Runde 4+) - **Pool mit 5 Staedten** statt Wien↔Salzburg-Pendel: Wien/Salzburg/Muenchen/Berlin/Hamburg mit Reward-Multiplikatoren 0.8–1.7 - **Staffel-Freischaltung**: Runde 1-2 nur `mult ≤ 1.0`, Runde 3-4 ≤ 1.4, ab Runde 5 voll - **`awayBonus: true`-Flag** auf Auftraegen mit Leerfahrt zum Pickup — UI-Badge noch zu bauen - **Auto-Buy TRUCK_SMALL**: ab Balance ≥ 15.000 € spawnt automatisch neuer Kleiner LKW (Kosten 5.000 €), max 3 Fahrzeuge - Runden-Increment in BEIDEN `_completeContract*`-Pfaden ### Balance-Regel R-1 (Startbudget-Runway) - Formal: `startBudget ≥ 1.5 × (rental×vc + idle×vc×12)` - **L3 verletzt R-1** (2.500 € startBudget vs. 4.650 € benoetigt) - L1/L2 passieren - Python-verifiziert: L3-Runway 0.81–0.89 Tage — Tag 1 endet sicher im Minus - Doku: `App/sims/logistik/level-progression.md` (L1-Design §1 + L3-Analyse + R-1 §2) ### 3 neue zentrale-Mails an Atlas (alle offen) 1. **2026-04-22 14:30** ElevenLabs-Frage — von Atlas beantwortet (Pipeline-Doku, s.o.) 2. **2026-04-23 17:00** Warnton-Asset (Heli-Ton wiederverwenden?) + Konzept „Minispiel-an-Fahrt-Koppeln" (bonus auf Lade-/Entlade-Zeit) 3. **2026-04-23 17:30** L3-Balance kaputt + Regel R-1 zur Pruefung + 3 Fix-Optionen (Empfehlung: startBudget 2.500 → 5.000) ### Was auf Atlas wartet 1. Admin-UI gegen `admin-fields.json` (von Phase 7b) 2. Review der 3 PHP-Endpunkte (game_saves-Kooptierung ok?) 3. Meister-Ping fuers `lg_contracts_log`-Schema auf Produktion 4. Entscheidung L3-Balance (A/B/C aus 17:30-Mail) 5. Daumen hoch fuer R-1 als Invariante 6. Heli-Warnton-Pfad freigeben 7. Buy-in fuer Minispiel-an-Fahrt-Koppeln-Architektur ### Was auf Thomas wartet (optional, kein Blocker) - Sounds generieren: `python App/scripts/generate-sounds.py logistik` nachdem `sounds-list.json` unter `App/sims/logistik/scripts/` angelegt ist (kostet 3-5 € ElevenLabs-Kontingent) - Entscheidung ob L1-UI-Badges fuer Runde + awayBonus dazu sollen ### Offene Arbeit bei mir (wenn Atlas freigibt) - Integrations-Auftrag (mail 23.04 11:00): mode-check im logistik.php + Assessment-Calls - `sounds-list.json` anlegen + Pipeline-Run (auf Thomas-Kommando) - End-Screen auf `.ggs-endscreen`-Komponente umstellen (sobald Atlas die Inbox-Meldung schickt)