feat: Add audio assets, UI escape room polish, requirements, and INSTALL.md

This commit is contained in:
Maxi
2026-10-29 08:51:59 +01:00
parent c07c0e10b9
commit 3d30d0812a
17 changed files with 1367 additions and 180 deletions
+47 -20
View File
@@ -1,8 +1,8 @@
// Wichtel-Panik / Cornish Pixies Arcade Engine (Mobile First)
// Wichtel-Panik / Cornish Pixies Arcade Engine (Mobile First - Frenzy & Challenge Overhaul)
(function() {
let score = 0;
const targetScore = 10;
let timeLeft = 35;
const targetScore = 12;
let timeLeft = 30;
let gameRunning = false;
let timerInterval = null;
let spawnTimeout = null;
@@ -21,10 +21,10 @@
if (gameRunning) return;
gameRunning = true;
score = 0;
timeLeft = 35;
timeLeft = 30;
scoreEl.innerText = score;
timerEl.innerText = timeLeft;
if (scoreEl) scoreEl.innerText = score;
if (timerEl) timerEl.innerText = timeLeft;
if (startOverlay) startOverlay.style.display = 'none';
if (successPanel) successPanel.style.display = 'none';
@@ -34,7 +34,7 @@
// Start countdown
timerInterval = setInterval(() => {
timeLeft--;
timerEl.innerText = timeLeft;
if (timerEl) timerEl.innerText = timeLeft;
if (timeLeft <= 0) {
endGame(false);
@@ -46,9 +46,24 @@
function scheduleNextSpawn() {
if (!gameRunning) return;
const delay = Math.random() * 350 + 400; // 400ms - 750ms
// 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);
}
@@ -67,13 +82,23 @@
const targetEl = document.getElementById(`target${holeIdx}`);
if (!targetEl) return;
// 12% chance Neville, 88% chance Pixie
const isNeville = Math.random() < 0.12;
// 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');
const stayTime = Math.random() * 450 + 900; // 900ms - 1350ms (forgiving for mobile)
// 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);
@@ -113,16 +138,18 @@
const targetEl = document.getElementById(`target${idx}`);
if (targetData.isNeville) {
// Clicked Neville -> Penalty!
// Clicked Neville -> Penalty (-2 Pkt and -1s)!
if (window.soundFX) window.soundFX.playWhoosh();
if (window.navigator && window.navigator.vibrate) window.navigator.vibrate([40, 40]);
if (window.navigator && window.navigator.vibrate) window.navigator.vibrate([60, 60]);
score = Math.max(0, score - 2);
scoreEl.innerText = score;
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("🤕 <strong>Neville:</strong> »Aua! Ich bin doch kein Wichtel!« (-2 Pkt)");
window.showFloatingToast("🤕 <strong>Neville:</strong> »Aua! Ich bin doch kein Wichtel!« (-2 Pkt, -1s)");
}
setTimeout(() => hideTarget(idx), 350);
@@ -141,12 +168,12 @@
}
score++;
scoreEl.innerText = score;
if (scoreEl) scoreEl.innerText = score;
if (score >= targetScore) {
endGame(true);
} else {
setTimeout(() => hideTarget(idx), 380);
setTimeout(() => hideTarget(idx), 280);
}
}
}
@@ -193,9 +220,9 @@
window.showChamberVictory({
chamberBadge: "Kammer V: Wichtel-Panik",
title: "🧚 Wichtel Gebannt!",
statsHtml: `<span>❄️ Gebannt: <strong>${score} Wichtel</strong></span><span>👦 Neville: <strong>Gerettet</strong></span>`,
statsHtml: `<span>❄️ Gebannt: <strong>${score}/${targetScore} Wichtel</strong></span><span>👦 Neville: <strong>Gerettet</strong></span><span>⏱️ Restzeit: <strong>${timeLeft}s</strong></span>`,
item: newItem,
storyText: "Mit blitzschnellen <em>Immobilus!</em>-Zaubern hast du alle 10 Wichtel eingefroren! Ein zappelnder Wichtel landet sicher im <strong>Wichtelglas</strong>. Neville bedankt sich erleichtert. Der Weg zur berüchtigten <strong>Flammenkammer von Severus Snape</strong> liegt nun offen!",
storyText: "Mit blitzschnellen <em>Immobilus!</em>-Zaubern hast du alle 12 frechen Wichtel eingefroren! Ein zappelnder Wichtel landet sicher im <strong>Wichtelglas</strong>. Neville bedankt sich erleichtert. Der Weg zur berüchtigten <strong>Flammenkammer von Severus Snape</strong> liegt nun offen!",
nextUrl: "/bottles",
nextBtnText: "➔ Weiter zu Kammer VI: Snapes Flaschen 🧪"
});
@@ -208,7 +235,7 @@
if (startBtn) startBtn.innerText = "Erneut versuchen 🔄";
}
if (window.showFloatingToast) {
window.showFloatingToast("⏰ Die Zeit ist abgelaufen! Versuch es noch einmal.");
window.showFloatingToast("⏰ Die Zeit ist abgelaufen! Die Wichtel entwischten. Versuch es noch einmal!");
}
}
}