fetchOne( 'SELECT class_id, display_name FROM student_sessions WHERE id = ?', [$sessionId] ); if ($row) { $studentName = $row['display_name'] ?: 'Schüler*in'; $classId = (int)$row['class_id']; } } // Modul-Metadaten aus DB (Admin-verwaltet) — Defaults greifen, wenn // Tabelle fehlt oder kein Eintrag fuer "fluss" existiert. $mi = $db->fetchOne( 'SELECT title, icon FROM module_info WHERE module_id = ?', ['fluss'] ); if ($mi) { if (!empty($mi['title'])) $simName = $mi['title']; if (!empty($mi['icon'])) $simIcon = $mi['icon']; } } catch (Throwable $e) { // DB nicht erreichbar → Defaults } // Level-Konfiguration — 100 Jahre Spielzeit (wie V1), pro Level: // startBudget, eventFrequency und toolsAvailable progressiv angepasst. // Progressive Disclosure: L1 nur 4 Basiswerkzeuge, L2 erweitert, L3 alle. $levelConfigs = [ // Alle Werkzeuge sind in allen Stufen verfuegbar. Progressive Disclosure // (Stufenweise Freischaltung) haben wir zugunsten eines spaeteren // Tutorial/First-Buy-Hint-Flows aufgegeben — die Regel wird didaktisch // im Onboarding erklaert, nicht per hartem Ausgrauen. 1 => [ 'difficulty' => 'easy', 'label' => 'Lernen', 'timeLimit' => 100, // Jahre 'startBudget' => 60, // Mio 'startPopulation'=> 200, 'incomePerYear' => 6, 'eventFrequency' => 0.25, 'toolsAvailable' => ['inspect','deich','feld','siedlung','wald','abriss','begradigen'], ], 2 => [ 'difficulty' => 'medium', 'label' => 'Üben', 'timeLimit' => 100, 'startBudget' => 40, 'startPopulation'=> 220, 'incomePerYear' => 5, 'eventFrequency' => 0.4, 'toolsAvailable' => ['inspect','deich','feld','siedlung','wald','abriss','begradigen'], ], 3 => [ 'difficulty' => 'hard', 'label' => 'Profi', 'timeLimit' => 100, 'startBudget' => 25, 'startPopulation'=> 250, 'incomePerYear' => 4, 'eventFrequency' => 0.6, 'toolsAvailable' => ['inspect','deich','feld','siedlung','wald','abriss','begradigen'], ], ]; $ctx = [ 'sessionId' => $sessionId, 'studentName' => $studentName, 'classId' => $classId, 'simId' => 'fluss', 'simName' => $simName, 'simIcon' => $simIcon, 'level' => $level, 'levelConfig' => $levelConfigs[$level], 'baseUrl' => BASE_URL, 'basePath' => BASE_PATH, 'apiUrl' => BASE_URL . '/php/api', ]; $html = file_get_contents(__DIR__ . '/../sims/fluss/game.html'); if ($html === false) { http_response_code(500); echo 'sims/fluss/game.html nicht gefunden'; exit; } $bp = BASE_PATH; $baseTag = ''; $ctxJs = ''; // Plattform-Live-Client: Heartbeat + Pause-Overlay + Spectator-Mode für ?view=teacher $liveJs = ''; // -Tag direkt nach , damit relative Pfade aus /sims/fluss/ aufloesen $html = preg_replace('//i', '' . "\n" . $baseTag, $html, 1); // Session-Kontext NUR VOR DEM LETZTEN injizieren. Ein einfaches // str_replace wuerde auch -Vorkommen in JS-Kommentaren ersetzen // und damit das in den Quelltext-Kommentar reinschieben — // das darin wuerde den umgebenden Script-Block vorzeitig schliessen. $pos = strrpos($html, ''); if ($pos !== false) { $html = substr($html, 0, $pos) . $ctxJs . "\n" . $liveJs . "\n" . substr($html, $pos); } $html = str_replace('href="/schueler"', 'href="' . cockpit_href() . '"', $html); echo $html;