// Wichtel-Panik / Cornish Pixies Arcade Engine (Mobile First - Frenzy & Challenge Overhaul) (function() { let score = 0; const targetScore = 12; let timeLeft = 30; let gameRunning = false; let timerInterval = null; let spawnTimeout = null; // DOM Elements const scoreEl = document.getElementById('pixieScore'); const timerEl = document.getElementById('pixieTimer'); const startOverlay = document.getElementById('startOverlay'); const startBtn = document.getElementById('startPixieBtn'); const successPanel = document.getElementById('pixieSuccess'); const holes = document.querySelectorAll('.pixie-hole'); const activeTargets = new Map(); // holeIndex -> { isNeville: bool, timer: id, clicked: bool } window.startPixieHunt = function() { if (gameRunning) return; gameRunning = true; score = 0; timeLeft = 30; if (scoreEl) scoreEl.innerText = score; if (timerEl) timerEl.innerText = timeLeft; if (startOverlay) startOverlay.style.display = 'none'; if (successPanel) successPanel.style.display = 'none'; if (window.soundFX) window.soundFX.playWhoosh(); if (window.navigator && window.navigator.vibrate) window.navigator.vibrate(30); // Start countdown timerInterval = setInterval(() => { timeLeft--; if (timerEl) timerEl.innerText = timeLeft; if (timeLeft <= 0) { endGame(false); } }, 1000); scheduleNextSpawn(); }; function scheduleNextSpawn() { if (!gameRunning) return; // Dynamic spawn delay based on progress let minDelay = 380, maxDelay = 650; if (score >= 8) { minDelay = 220; maxDelay = 420; } else if (score >= 4) { minDelay = 300; maxDelay = 520; } const delay = Math.random() * (maxDelay - minDelay) + minDelay; spawnTimeout = setTimeout(() => { spawnTarget(); // Chance of double spawn when frenzy begins (score >= 4) if (score >= 4 && Math.random() < 0.40) { setTimeout(spawnTarget, 80); } scheduleNextSpawn(); }, delay); } function spawnTarget() { if (!gameRunning) return; // Find available holes const available = []; for (let i = 0; i < 9; i++) { if (!activeTargets.has(i)) available.push(i); } if (available.length === 0) return; const holeIdx = available[Math.floor(Math.random() * available.length)]; const targetEl = document.getElementById(`target${holeIdx}`); if (!targetEl) return; // 16% chance Neville, 84% chance Pixie const isNeville = Math.random() < 0.16; targetEl.className = 'pixie-target active'; targetEl.innerText = isNeville ? '👦' : '🧚'; if (isNeville) targetEl.classList.add('neville'); // Dynamic stay duration: faster as player scores higher let stayTime = 800; if (isNeville) { stayTime = 950; // Neville stays a bit longer as a decoy } else if (score >= 8) { stayTime = Math.random() * 220 + 420; // 420ms - 640ms (Lightning fast frenzy!) } else if (score >= 4) { stayTime = Math.random() * 250 + 520; // 520ms - 770ms } else { stayTime = Math.random() * 280 + 660; // 660ms - 940ms } const hideTimer = setTimeout(() => { hideTarget(holeIdx); }, stayTime); activeTargets.set(holeIdx, { isNeville: isNeville, timer: hideTimer, clicked: false }); } function hideTarget(holeIdx) { const targetEl = document.getElementById(`target${holeIdx}`); if (targetEl) { targetEl.classList.remove('active'); targetEl.classList.remove('frozen'); targetEl.classList.remove('neville'); targetEl.innerText = ''; } activeTargets.delete(holeIdx); } // Pointerdown handler on holes (zero delay on touch devices!) holes.forEach(hole => { const idx = parseInt(hole.dataset.idx, 10); function onHoleTrigger(e) { if (!gameRunning) return; e.preventDefault(); if (!activeTargets.has(idx)) return; const targetData = activeTargets.get(idx); if (targetData.clicked) return; targetData.clicked = true; const targetEl = document.getElementById(`target${idx}`); if (targetData.isNeville) { // Clicked Neville -> Penalty (-2 Pkt and -1s)! if (window.soundFX) window.soundFX.playWhoosh(); if (window.navigator && window.navigator.vibrate) window.navigator.vibrate([60, 60]); score = Math.max(0, score - 2); timeLeft = Math.max(1, timeLeft - 1); if (scoreEl) scoreEl.innerText = score; if (timerEl) timerEl.innerText = timeLeft; targetEl.style.transform = 'scale(1.25) rotate(15deg)'; if (window.showFloatingToast) { window.showFloatingToast("🤕 Neville: »Aua! Ich bin doch kein Wichtel!« (-2 Pkt, -1s)"); } setTimeout(() => hideTarget(idx), 350); } else { // Clicked Pixie -> Immobilus! clearTimeout(targetData.timer); targetEl.classList.add('frozen'); targetEl.innerText = '❄️'; if (window.soundFX) { window.soundFX.playKeyChime(); } if (window.navigator && window.navigator.vibrate) { window.navigator.vibrate(35); } score++; if (scoreEl) scoreEl.innerText = score; if (score >= targetScore) { endGame(true); } else { setTimeout(() => hideTarget(idx), 280); } } } // Use pointerdown for instant touch & mouse response without delay hole.addEventListener('pointerdown', onHoleTrigger); }); async function endGame(won) { gameRunning = false; clearInterval(timerInterval); clearTimeout(spawnTimeout); // Hide all active activeTargets.forEach((val, idx) => hideTarget(idx)); activeTargets.clear(); if (won) { let newItem = null; try { const res = await fetch('/api/pixies/complete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ caught: score }) }); const data = await res.json(); if (data.new_item) newItem = data.new_item; } catch (e) { console.error("Pixies complete error:", e); } if (!newItem) { newItem = { id: "pixie_jar", name: "Wichtelglas", icon: "🧚", desc: "Ein dickbauchiges Glas mit einem gebannten Wichtel." }; } if (successPanel) successPanel.style.display = 'block'; if (window.showChamberVictory) { window.showChamberVictory({ chamberBadge: "Kammer V: Wichtel-Panik", title: "🧚 Wichtel Gebannt!", statsHtml: `❄️ Gebannt: ${score}/${targetScore} Wichtel👦 Neville: Gerettet⏱️ Restzeit: ${timeLeft}s`, item: newItem, storyText: "Mit blitzschnellen Immobilus!-Zaubern hast du alle 12 frechen Wichtel eingefroren! Ein zappelnder Wichtel landet sicher im Wichtelglas. Neville bedankt sich erleichtert. Der Weg zur berüchtigten Flammenkammer von Severus Snape liegt nun offen!", nextUrl: "/bottles", nextBtnText: "➔ Weiter zu Kammer VI: Snapes Flaschen 🧪" }); } } else { if (window.soundFX) window.soundFX.playWhoosh(); if (startOverlay) { startOverlay.style.display = 'flex'; if (startBtn) startBtn.innerText = "Erneut versuchen 🔄"; } if (window.showFloatingToast) { window.showFloatingToast("⏰ Die Zeit ist abgelaufen! Die Wichtel entwischten. Versuch es noch einmal!"); } } } })();