let currentSessionId = null; let currentQuestionNumber = 1; let totalQuestions = 15; let currentScore = 0; let attemptsUsed = 0; const maxAttempts = 3; // Web Audio API Sound Generator for magic chimes and buzzers const audioCtx = new (window.AudioContext || window.webkitAudioContext)(); function playSound(type) { if (audioCtx.state === 'suspended') { audioCtx.resume(); } if (type === 'magic') { // Magical bright arpeggio chime const notes = [523.25, 659.25, 783.99, 1046.50]; // C5, E5, G5, C6 notes.forEach((freq, index) => { const osc = audioCtx.createOscillator(); const gain = audioCtx.createGain(); osc.type = 'sine'; osc.frequency.value = freq; gain.gain.setValueAtTime(0.15, audioCtx.currentTime + index * 0.08); gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + index * 0.08 + 0.35); osc.connect(gain); gain.connect(audioCtx.destination); osc.start(audioCtx.currentTime + index * 0.08); osc.stop(audioCtx.currentTime + index * 0.08 + 0.35); }); } else if (type === 'wrong') { // Soft error buzz const osc = audioCtx.createOscillator(); const gain = audioCtx.createGain(); osc.type = 'sawtooth'; osc.frequency.setValueAtTime(150, audioCtx.currentTime); osc.frequency.exponentialRampToValueAtTime(80, audioCtx.currentTime + 0.25); gain.gain.setValueAtTime(0.1, audioCtx.currentTime); gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.25); osc.connect(gain); gain.connect(audioCtx.destination); osc.start(); osc.stop(audioCtx.currentTime + 0.25); } } async function startGame() { const envelope = document.getElementById("envelope"); const startBtn = document.getElementById("startBtn"); startBtn.disabled = true; startBtn.innerText = "✨ Zauber wird gewirkt..."; envelope.classList.add("envelope-opened"); // Start background music if enabled or first click const bgm = document.getElementById("bgm"); if (bgm && bgm.paused) { bgm.play().then(() => { const icon = document.getElementById("audioIcon"); const text = document.getElementById("audioText"); if (icon && text) { icon.innerText = "🔊"; text.innerText = "Musik: An"; } localStorage.setItem("bgm_enabled", "true"); }).catch(() => {}); } try { const res = await fetch("/api/game/start", { method: "POST", headers: { "Content-Type": "application/json" } }); if (!res.ok) { throw new Error("Konnte Spiel nicht starten."); } const data = await res.json(); currentSessionId = data.session_id; currentQuestionNumber = data.question_number; totalQuestions = data.total_questions; currentScore = data.score; attemptsUsed = data.attempts_used; setTimeout(() => { document.getElementById("introCard").classList.add("hidden"); document.getElementById("gameCard").classList.remove("hidden"); renderQuestion(data); }, 1100); } catch (err) { alert("Fehler beim Starten des Quiz: " + err.message); startBtn.disabled = false; startBtn.innerText = "📜 Siegel brechen & Brief öffnen"; envelope.classList.remove("envelope-opened"); } } function renderQuestion(qData) { document.getElementById("questionCounter").innerText = `Frage ${qData.question_number} von ${totalQuestions}`; document.getElementById("pointsCounter").innerText = `🏆 Hauspunkte: ${currentScore}`; document.getElementById("badgeCategory").innerText = `⚡ ${qData.category.replace("_", " ").toUpperCase()}`; document.getElementById("attemptBadge").innerText = `Versuch ${attemptsUsed + 1} von ${maxAttempts}`; document.getElementById("frageText").innerText = qData.question; const textGroup = document.getElementById("textAnswerGroup"); const choiceGroup = document.getElementById("choiceAnswerGroup"); const choiceContainer = document.getElementById("choiceOptionsContainer"); const input = document.getElementById("answerInput"); document.getElementById("hintBox").classList.add("hidden"); document.getElementById("feedbackBox").innerHTML = ""; if (qData.question_type === "multiple_choice" && qData.options && qData.options.length > 0) { textGroup.classList.add("hidden"); choiceGroup.classList.remove("hidden"); choiceContainer.innerHTML = ""; const letters = ["A", "B", "C", "D", "E", "F"]; qData.options.forEach((opt, idx) => { const btn = document.createElement("button"); btn.className = "choice-btn"; btn.type = "button"; btn.innerHTML = `${letters[idx] || "•"} ${opt}`; btn.onclick = () => submitAnswer(opt, btn); choiceContainer.appendChild(btn); }); } else { choiceGroup.classList.add("hidden"); textGroup.classList.remove("hidden"); input.value = ""; input.disabled = false; document.getElementById("checkBtn").disabled = false; input.focus(); } const hintBtn = document.getElementById("hintBtn"); if (hintBtn) hintBtn.disabled = false; const hintBtnMC = document.getElementById("hintBtnMC"); if (hintBtnMC) hintBtnMC.disabled = false; updateProgress(); } function updateProgress() { const percent = ((currentQuestionNumber - 1) / totalQuestions) * 100; document.getElementById("progressBar").style.width = percent + "%"; } function checkAnswer() { const input = document.getElementById("answerInput"); const answer = input.value.trim(); if (!answer) { input.focus(); return; } submitAnswer(answer); } async function submitAnswer(answer, clickedBtn = null) { const checkBtn = document.getElementById("checkBtn"); const input = document.getElementById("answerInput"); if (checkBtn) checkBtn.disabled = true; if (input) input.disabled = true; // Disable all choice buttons const choiceBtns = document.querySelectorAll(".choice-btn"); choiceBtns.forEach(b => b.disabled = true); if (clickedBtn) { clickedBtn.classList.add("choice-selected"); } try { const res = await fetch("/api/game/check", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ session_id: currentSessionId, answer: answer }) }); if (!res.ok) { throw new Error("Fehler bei der Antwortprüfung."); } const result = await res.json(); currentScore = result.score; document.getElementById("pointsCounter").innerText = `🏆 Hauspunkte: ${currentScore}`; const frageBox = document.getElementById("frageBox"); const feedbackBox = document.getElementById("feedbackBox"); if (result.correct) { // Success! playSound('magic'); if (clickedBtn) { clickedBtn.classList.remove("choice-selected"); clickedBtn.classList.add("choice-correct"); } frageBox.classList.add("sparkle-effect"); feedbackBox.innerHTML = `✨ Richtig! 1 Hauspunkt für dein Haus! ✨`; setTimeout(() => { frageBox.classList.remove("sparkle-effect"); if (result.is_finished) { finishGame(); } else if (result.next_question) { currentQuestionNumber = result.next_question.question_number; attemptsUsed = 0; renderQuestion(result.next_question); } }, 1200); } else { // Incorrect playSound('wrong'); if (clickedBtn) { clickedBtn.classList.remove("choice-selected"); clickedBtn.classList.add("choice-wrong"); } frageBox.classList.add("shake-effect"); setTimeout(() => frageBox.classList.remove("shake-effect"), 500); attemptsUsed = result.attempts_used; document.getElementById("attemptBadge").innerText = `Versuch ${Math.min(attemptsUsed + 1, maxAttempts)} von ${maxAttempts}`; if (result.attempts_left === 0) { // Exhausted all attempts feedbackBox.innerHTML = `