Heli: Onboarding-Zurueck-Button + Routen-Card-Sicherheitsnetz (ohne Ton)

- Onboarding: "Zurueck"-Button (ab Schritt 2, prevHeliOnboarding)
- Routenplanung: planInstruction-Card erscheint garantiert auch ohne Ton / bei
  Audio-Ladefehler (Fallback + Timeout-Netz); bleibt bis zum Wegpunkt-Fund stehen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-23 12:25:08 +02:00
parent 5d79fa3c3a
commit 0532327e6a
+22
View File
@@ -182,6 +182,7 @@
<div class="heli-onb-visual" id="heliOnbVisual"></div>
<div class="heli-onb-text" id="heliOnbText"></div>
<div class="heli-onb-actions">
<button class="heli-onb-btn heli-onb-btn-secondary" type="button" id="heliOnbBack" onclick="prevHeliOnboarding()" style="display:none">← Zurück</button>
<button class="heli-onb-btn heli-onb-btn-secondary" type="button" id="heliOnbSkip" onclick="skipHeliOnboarding()">Überspringen</button>
<button class="heli-onb-btn heli-onb-btn-primary" type="button" id="heliOnbNext" onclick="nextHeliOnboarding()">Weiter →</button>
</div>
@@ -2043,7 +2044,21 @@ function startHeliAudioEngineForPlan() {
});
window.heliAudioEngine.loadAndStart('plan').catch(function(err){
console.warn('[heli-engine] startPhase failed', err);
// Audio konnte nicht starten (Ton aus, Ladefehler, Autoplay blockiert) →
// die Wegpunkt-Anweisung trotzdem sofort als Card zeigen, sonst steht
// ein tonloser Spieler ohne Hinweis da. Bleibt bis zum Fund stehen.
if (game.phase === 'plan' && game.planIndex < game.route.length) showPlanInstruction();
});
// Sicherheitsnetz unabhängig vom Audio: falls das wp-sichtbar-Event nach kurzer
// Zeit nicht gekommen ist (z. B. stummes Abspielen ohne Events), zeigen wir die
// Anweisung selbst an — jede Audio-Meldung hat so ihren sichtbaren „Untertitel".
clearTimeout(window._heliPlanCardFallback);
window._heliPlanCardFallback = setTimeout(function(){
var pi = document.getElementById('planInstruction');
if (game.phase === 'plan' && game.planIndex < game.route.length && pi && !pi.innerHTML.trim()) {
showPlanInstruction();
}
}, 5000);
}
// =========================================================
@@ -2543,6 +2558,9 @@ function renderHeliOnboardingStep() {
document.getElementById('heliOnbDots').innerHTML = dots;
var isLast = (heliOnbStep === HELI_ONBOARDING_STEPS.length - 1);
document.getElementById('heliOnbNext').textContent = isLast ? 'Los geht\'s 🚁' : 'Weiter →';
// Zurück-Button erst ab Schritt 2 zeigen.
var back = document.getElementById('heliOnbBack');
if (back) back.style.display = heliOnbStep > 0 ? '' : 'none';
}
function nextHeliOnboarding() {
if (heliOnbStep < HELI_ONBOARDING_STEPS.length - 1) {
@@ -2552,12 +2570,16 @@ function nextHeliOnboarding() {
skipHeliOnboarding();
}
}
function prevHeliOnboarding() {
if (heliOnbStep > 0) { heliOnbStep--; renderHeliOnboardingStep(); }
}
function skipHeliOnboarding() {
document.getElementById('heliOnbOverlay').hidden = true;
try { localStorage.setItem('heli.onboardingDone', '1'); } catch (_) {}
}
window.startHeliOnboarding = startHeliOnboarding;
window.nextHeliOnboarding = nextHeliOnboarding;
window.prevHeliOnboarding = prevHeliOnboarding;
window.skipHeliOnboarding = skipHeliOnboarding;
// Plattform-Convention: GGS_TUTORIAL (siehe live-client.js).
window.GGS_TUTORIAL = { simId: 'heli', title: 'Helikopter-Navigation', replay: function() { startHeliOnboarding(true); } };