feat: Add universal victory celebration modal, chamber item requirements, and fix broom & cauldron displays
This commit is contained in:
@@ -230,6 +230,127 @@
|
||||
window.showFloatingToast(`🎒 <strong>Neuer Gegenstand im Beutel:</strong> ${item.icon} ${item.name}!`);
|
||||
};
|
||||
|
||||
// Confetti Animation Controller
|
||||
let confettiAnimId = null;
|
||||
function runVictoryConfetti() {
|
||||
const canvas = document.getElementById('victoryConfettiCanvas');
|
||||
if (!canvas) return;
|
||||
const ctx = canvas.getContext('2d');
|
||||
canvas.width = window.innerWidth;
|
||||
canvas.height = window.innerHeight;
|
||||
|
||||
const colors = ['#ffd700', '#f39c12', '#e74c3c', '#3498db', '#2ecc71', '#9b59b6', '#ffffff'];
|
||||
const particles = [];
|
||||
for (let i = 0; i < 90; i++) {
|
||||
particles.push({
|
||||
x: Math.random() * canvas.width,
|
||||
y: Math.random() * -canvas.height * 0.5,
|
||||
w: Math.random() * 9 + 5,
|
||||
h: Math.random() * 5 + 3,
|
||||
vx: (Math.random() - 0.5) * 4,
|
||||
vy: Math.random() * 3 + 2.5,
|
||||
color: colors[Math.floor(Math.random() * colors.length)],
|
||||
angle: Math.random() * Math.PI * 2,
|
||||
vAngle: (Math.random() - 0.5) * 0.15,
|
||||
shape: Math.random() > 0.4 ? 'rect' : 'star'
|
||||
});
|
||||
}
|
||||
|
||||
let start = Date.now();
|
||||
if (confettiAnimId) cancelAnimationFrame(confettiAnimId);
|
||||
|
||||
function drawConfetti() {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
const elapsed = (Date.now() - start) / 1000;
|
||||
|
||||
particles.forEach(p => {
|
||||
p.x += p.vx;
|
||||
p.y += p.vy;
|
||||
p.angle += p.vAngle;
|
||||
|
||||
ctx.save();
|
||||
ctx.translate(p.x, p.y);
|
||||
ctx.rotate(p.angle);
|
||||
ctx.fillStyle = p.color;
|
||||
|
||||
if (p.shape === 'star') {
|
||||
ctx.beginPath();
|
||||
ctx.arc(0, 0, p.w * 0.45, 0, Math.PI * 2);
|
||||
ctx.fill();
|
||||
} else {
|
||||
ctx.fillRect(-p.w / 2, -p.h / 2, p.w, p.h);
|
||||
}
|
||||
ctx.restore();
|
||||
|
||||
if (p.y > canvas.height + 20) {
|
||||
p.y = -20;
|
||||
p.x = Math.random() * canvas.width;
|
||||
}
|
||||
});
|
||||
|
||||
if (elapsed < 8) {
|
||||
confettiAnimId = requestAnimationFrame(drawConfetti);
|
||||
} else {
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
}
|
||||
confettiAnimId = requestAnimationFrame(drawConfetti);
|
||||
}
|
||||
|
||||
// Unified Spectacular Victory Celebration Overlay
|
||||
window.showChamberVictory = function(config) {
|
||||
const modal = document.getElementById('victoryCelebrationModal');
|
||||
if (!modal) {
|
||||
// Fallback to standard modal if celebration overlay missing
|
||||
if (window.modalTitle) window.modalTitle.innerText = config.title;
|
||||
if (window.modalText) window.modalText.innerHTML = config.storyText;
|
||||
if (window.modalBackdrop) window.modalBackdrop.classList.add('show');
|
||||
return;
|
||||
}
|
||||
|
||||
const badge = document.getElementById('vicChamberBadge');
|
||||
const title = document.getElementById('vicTitle');
|
||||
const statsBox = document.getElementById('vicStatsBox');
|
||||
const itemBox = document.getElementById('vicItemRewardBox');
|
||||
const rewardIcon = document.getElementById('vicRewardIcon');
|
||||
const rewardName = document.getElementById('vicRewardName');
|
||||
const rewardDesc = document.getElementById('vicRewardDesc');
|
||||
const storyBox = document.getElementById('vicStoryBox');
|
||||
const nextBtn = document.getElementById('vicNextBtn');
|
||||
|
||||
if (badge) badge.innerText = config.chamberBadge || 'Kammer Gemeistert';
|
||||
if (title) title.innerText = config.title || 'Hervorragend!';
|
||||
if (statsBox) {
|
||||
statsBox.innerHTML = config.statsHtml || '';
|
||||
statsBox.style.display = config.statsHtml ? 'flex' : 'none';
|
||||
}
|
||||
if (storyBox) storyBox.innerHTML = config.storyText || '';
|
||||
|
||||
if (config.item && itemBox) {
|
||||
itemBox.style.display = 'flex';
|
||||
if (rewardIcon) rewardIcon.innerText = config.item.icon || '✨';
|
||||
if (rewardName) rewardName.innerText = config.item.name || '';
|
||||
if (rewardDesc) rewardDesc.innerText = config.item.desc || '';
|
||||
window.notifyNewItem(config.item);
|
||||
} else if (itemBox) {
|
||||
itemBox.style.display = 'none';
|
||||
}
|
||||
|
||||
if (nextBtn) {
|
||||
nextBtn.href = config.nextUrl || '/';
|
||||
nextBtn.innerHTML = config.nextBtnText || '➔ Weiter zur nächsten Kammer ✨';
|
||||
}
|
||||
|
||||
// Trigger Audio, Haptic & Particle Celebration
|
||||
if (window.soundFX) window.soundFX.playMagicSuccess();
|
||||
if (window.navigator && window.navigator.vibrate) {
|
||||
window.navigator.vibrate([60, 50, 80, 50, 180]);
|
||||
}
|
||||
|
||||
modal.classList.add('show');
|
||||
runVictoryConfetti();
|
||||
};
|
||||
|
||||
// Auto-select first item if available
|
||||
if (itemSlots.length > 0) {
|
||||
selectItem(itemSlots[0]);
|
||||
|
||||
Reference in New Issue
Block a user