Polish: Fix pixie visibility bug, add flight ready countdown, SVG cauldron redesign, and upgrade riddles
This commit is contained in:
+86
-52
@@ -1,4 +1,4 @@
|
||||
// Zaubertrank-Brauküche (Felix Felicis Potion Brewing Engine - Mobile First)
|
||||
// Zaubertrank-Brauküche (Felix Felicis Potion Brewing Engine - SVG Overhaul)
|
||||
(function() {
|
||||
let currentStep = 1; // 1: Ingredients, 2: Stirring, 3: Heat, 4: Done
|
||||
const ingredients = {
|
||||
@@ -16,9 +16,18 @@
|
||||
const stepBadge = document.getElementById('stepBadge');
|
||||
const stepInstruction = document.getElementById('stepInstruction');
|
||||
const stepSubtext = document.getElementById('stepSubtext');
|
||||
const ingredientsShelf = document.getElementById('ingredientsShelf');
|
||||
const potionSurface = document.getElementById('potionSurface');
|
||||
const stirCircle = document.getElementById('stirCircle');
|
||||
const step1Wrapper = document.getElementById('step1Wrapper');
|
||||
const totalIngredientsCount = document.getElementById('totalIngredientsCount');
|
||||
|
||||
// SVG Elements
|
||||
const gradStop1 = document.getElementById('gradStop1');
|
||||
const gradStop2 = document.getElementById('gradStop2');
|
||||
const gradStop3 = document.getElementById('gradStop3');
|
||||
const liquidSurface = document.getElementById('liquidSurface');
|
||||
const stirSpoon = document.getElementById('stirSpoon');
|
||||
const dropItemAnim = document.getElementById('dropItemAnim');
|
||||
|
||||
// Controls
|
||||
const stirPanel = document.getElementById('stirPanel');
|
||||
const stirCountSpan = document.getElementById('stirCount');
|
||||
const stirBtn = document.getElementById('stirBtn');
|
||||
@@ -26,7 +35,6 @@
|
||||
const tempIndicator = document.getElementById('tempIndicator');
|
||||
const heatTimerSpan = document.getElementById('heatTimer');
|
||||
const successPanel = document.getElementById('successPanel');
|
||||
const cauldronZone = document.getElementById('cauldronZone');
|
||||
|
||||
// Step 1: Add Ingredient
|
||||
window.addIngredient = function(type) {
|
||||
@@ -35,7 +43,7 @@
|
||||
|
||||
ingredients[type]++;
|
||||
if (window.soundFX) window.soundFX.playBottleClink();
|
||||
if (window.navigator && window.navigator.vibrate) window.navigator.vibrate(25);
|
||||
if (window.navigator && window.navigator.vibrate) window.navigator.vibrate(30);
|
||||
|
||||
// Update UI Badge
|
||||
if (type === 'dragon') {
|
||||
@@ -49,14 +57,29 @@
|
||||
if (ingredients.star >= targetIngredients.star) document.getElementById('ingStar').classList.add('done');
|
||||
}
|
||||
|
||||
// Ripple effect on surface
|
||||
potionSurface.style.transform = 'scale(1.12)';
|
||||
setTimeout(() => potionSurface.style.transform = 'scale(1)', 200);
|
||||
const total = ingredients.dragon + ingredients.mandrake + ingredients.star;
|
||||
if (totalIngredientsCount) totalIngredientsCount.innerText = total;
|
||||
|
||||
// Visual drop animation in SVG
|
||||
if (dropItemAnim) {
|
||||
const icons = { dragon: '🐉', mandrake: '🌿', star: '✨' };
|
||||
dropItemAnim.textContent = icons[type];
|
||||
dropItemAnim.style.display = 'block';
|
||||
dropItemAnim.style.animation = 'ingredientDropAnim 0.5s ease-out forwards';
|
||||
setTimeout(() => {
|
||||
dropItemAnim.style.display = 'none';
|
||||
}, 550);
|
||||
}
|
||||
|
||||
// Ripple pulse on liquid
|
||||
if (liquidSurface) {
|
||||
liquidSurface.style.transform = 'scale(1.06)';
|
||||
setTimeout(() => liquidSurface.style.transform = 'scale(1)', 200);
|
||||
}
|
||||
|
||||
// Check if all ingredients added
|
||||
const total = ingredients.dragon + ingredients.mandrake + ingredients.star;
|
||||
if (total === 4) {
|
||||
setTimeout(startStep2, 500);
|
||||
setTimeout(startStep2, 600);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -67,11 +90,19 @@
|
||||
currentStep = 2;
|
||||
stepBadge.innerText = "Schritt 2: Gleichmäßig rühren";
|
||||
stepInstruction.innerText = "Rühre den Kessel 3-mal um!";
|
||||
stepSubtext.innerText = "Tippe auf den großen Rühr-Button oder wische über den Kessel.";
|
||||
ingredientsShelf.style.display = 'none';
|
||||
stirPanel.style.display = 'flex';
|
||||
stirCircle.classList.add('active');
|
||||
potionSurface.className = 'potion-surface state-stir';
|
||||
stepSubtext.innerText = "Tippe auf den großen Rühr-Button, um die Essenzen zu vermengen.";
|
||||
if (step1Wrapper) step1Wrapper.style.display = 'none';
|
||||
if (stirPanel) stirPanel.style.display = 'flex';
|
||||
|
||||
// Show wooden spoon in cauldron
|
||||
if (stirSpoon) stirSpoon.style.display = 'block';
|
||||
|
||||
// Shift liquid color to mystical purple
|
||||
if (gradStop1 && gradStop2 && gradStop3) {
|
||||
gradStop1.setAttribute('stop-color', '#9b59b6');
|
||||
gradStop2.setAttribute('stop-color', '#8e44ad');
|
||||
gradStop3.setAttribute('stop-color', '#341f47');
|
||||
}
|
||||
|
||||
if (window.soundFX) window.soundFX.playStoneSlide();
|
||||
}
|
||||
@@ -79,37 +110,28 @@
|
||||
window.doStir = function() {
|
||||
if (currentStep !== 2) return;
|
||||
completedStirs++;
|
||||
stirCountSpan.innerText = completedStirs;
|
||||
if (stirCountSpan) stirCountSpan.innerText = completedStirs;
|
||||
if (stirBtn) stirBtn.innerHTML = `🥄 Kessel umrühren! (<span>${completedStirs}</span> / 3)`;
|
||||
|
||||
if (window.soundFX) window.soundFX.playBottleClink();
|
||||
if (window.navigator && window.navigator.vibrate) window.navigator.vibrate(35);
|
||||
|
||||
// Spin animation on surface
|
||||
potionSurface.style.transform = 'rotate(' + (completedStirs * 180) + 'deg) scale(1.1)';
|
||||
setTimeout(() => potionSurface.style.transform = 'rotate(' + (completedStirs * 180) + 'deg) scale(1)', 250);
|
||||
// Animate stirring spoon
|
||||
if (stirSpoon) {
|
||||
stirSpoon.classList.remove('stirring-active');
|
||||
void stirSpoon.offsetWidth; // re-flow
|
||||
stirSpoon.classList.add('stirring-active');
|
||||
}
|
||||
|
||||
if (completedStirs >= 3) {
|
||||
stirCircle.classList.remove('active');
|
||||
stirPanel.style.display = 'none';
|
||||
setTimeout(startStep3, 500);
|
||||
setTimeout(() => {
|
||||
if (stirSpoon) stirSpoon.style.display = 'none';
|
||||
if (stirPanel) stirPanel.style.display = 'none';
|
||||
startStep3();
|
||||
}, 600);
|
||||
}
|
||||
};
|
||||
|
||||
// Cauldron tap / swipe to stir as well
|
||||
let touchStartX = 0;
|
||||
cauldronZone.addEventListener('pointerdown', (e) => {
|
||||
if (currentStep === 2) {
|
||||
touchStartX = e.clientX;
|
||||
}
|
||||
});
|
||||
|
||||
cauldronZone.addEventListener('pointerup', (e) => {
|
||||
if (currentStep === 2) {
|
||||
window.doStir();
|
||||
}
|
||||
});
|
||||
|
||||
// Step 3: Heat Control
|
||||
let currentTemp = 35; // percent (0-100)
|
||||
let heatTimer = 0.0;
|
||||
@@ -118,10 +140,16 @@
|
||||
function startStep3() {
|
||||
currentStep = 3;
|
||||
stepBadge.innerText = "Schritt 3: Hitze balancieren";
|
||||
stepInstruction.innerText = "Pumpe mit dem Blasebalg, um die Hitze im grünen Bereich zu halten!";
|
||||
stepSubtext.innerText = "Halte die Anzeige für 3 Sekunden im grünen Idealbereich (50% - 85%).";
|
||||
potionSurface.className = 'potion-surface state-heat';
|
||||
heatPanel.classList.add('active');
|
||||
stepInstruction.innerText = "Pumpe mit dem Blasebalg, um die Flammen zu nähren!";
|
||||
stepSubtext.innerText = "Halte die Anzeige für 3 Sekunden im grünen Idealbereich (45% - 85%).";
|
||||
if (heatPanel) heatPanel.classList.add('active');
|
||||
|
||||
// Shift liquid color to fiery orange
|
||||
if (gradStop1 && gradStop2 && gradStop3) {
|
||||
gradStop1.setAttribute('stop-color', '#e67e22');
|
||||
gradStop2.setAttribute('stop-color', '#d35400');
|
||||
gradStop3.setAttribute('stop-color', '#561d00');
|
||||
}
|
||||
|
||||
if (window.soundFX) window.soundFX.playWhoosh();
|
||||
|
||||
@@ -144,17 +172,17 @@
|
||||
function updateHeatLoop() {
|
||||
if (currentStep !== 3) return;
|
||||
|
||||
// Slow cooling down
|
||||
// Gentle cooling down
|
||||
currentTemp = Math.max(0, currentTemp - 0.45);
|
||||
tempIndicator.style.width = currentTemp + '%';
|
||||
if (tempIndicator) tempIndicator.style.width = currentTemp + '%';
|
||||
|
||||
// Check ideal zone (50% to 85%) - forgiving on mobile!
|
||||
if (currentTemp >= 50 && currentTemp <= 85) {
|
||||
// Check ideal zone (45% to 85%) - forgiving on mobile!
|
||||
if (currentTemp >= 45 && currentTemp <= 85) {
|
||||
heatTimer += 0.05;
|
||||
heatTimerSpan.innerText = heatTimer.toFixed(1);
|
||||
tempIndicator.style.background = '#2ecc71';
|
||||
if (heatTimerSpan) heatTimerSpan.innerText = heatTimer.toFixed(1);
|
||||
if (tempIndicator) tempIndicator.style.background = '#2ecc71';
|
||||
} else {
|
||||
tempIndicator.style.background = 'linear-gradient(90deg, #3498db, #f39c12, #e74c3c)';
|
||||
if (tempIndicator) tempIndicator.style.background = 'linear-gradient(90deg, #3498db, #f39c12, #e74c3c)';
|
||||
}
|
||||
|
||||
if (heatTimer >= 3.0) {
|
||||
@@ -172,10 +200,16 @@
|
||||
stepBadge.style.color = "#2ecc71";
|
||||
|
||||
stepInstruction.innerText = "Felix Felicis strahlt in reinem Gold!";
|
||||
stepSubtext.innerText = "Dein Zaubertrank ist perfekt gelungen.";
|
||||
stepSubtext.innerText = "Dein Zaubertrank ist meisterhaft gelungen.";
|
||||
|
||||
heatPanel.classList.remove('active');
|
||||
potionSurface.className = 'potion-surface state-gold';
|
||||
if (heatPanel) heatPanel.classList.remove('active');
|
||||
|
||||
// Turn liquid into sparkling golden elixir
|
||||
if (gradStop1 && gradStop2 && gradStop3) {
|
||||
gradStop1.setAttribute('stop-color', '#fff6a5');
|
||||
gradStop2.setAttribute('stop-color', '#ffd700');
|
||||
gradStop3.setAttribute('stop-color', '#b7950b');
|
||||
}
|
||||
|
||||
if (window.soundFX) window.soundFX.playMagicSuccess();
|
||||
if (window.navigator && window.navigator.vibrate) window.navigator.vibrate([50, 100, 150]);
|
||||
@@ -191,6 +225,6 @@
|
||||
console.error("Brew complete error:", e);
|
||||
}
|
||||
|
||||
successPanel.style.display = 'block';
|
||||
if (successPanel) successPanel.style.display = 'block';
|
||||
}
|
||||
})();
|
||||
|
||||
+31
-7
@@ -27,12 +27,36 @@
|
||||
|
||||
// Game Configuration
|
||||
const TOTAL_RINGS_NEEDED = 12;
|
||||
let gameRunning = true;
|
||||
let gameRunning = false; // Does not start automatically!
|
||||
let startTime = Date.now();
|
||||
let score = 0;
|
||||
let ringsCollected = 0;
|
||||
let combo = 0;
|
||||
|
||||
window.startFlight = function() {
|
||||
const overlay = document.getElementById('broomStartOverlay');
|
||||
if (overlay) overlay.style.display = 'none';
|
||||
|
||||
rings.length = 0;
|
||||
rings.push({ x: width + 60, y: height * 0.4, radius: 25, speed: 3.5, golden: false, collected: false, scale: 1, alpha: 1, pulse: 0 });
|
||||
rings.push({ x: width + 290, y: height * 0.65, radius: 25, speed: 3.6, golden: true, collected: false, scale: 1, alpha: 1, pulse: 0 });
|
||||
rings.push({ x: width + 530, y: height * 0.3, radius: 25, speed: 3.7, golden: false, collected: false, scale: 1, alpha: 1, pulse: 0 });
|
||||
|
||||
score = 0;
|
||||
ringsCollected = 0;
|
||||
combo = 0;
|
||||
if (scoreVal) scoreVal.innerText = score;
|
||||
if (ringsVal) ringsVal.innerText = `0/${TOTAL_RINGS_NEEDED}`;
|
||||
if (comboVal) comboVal.innerText = '';
|
||||
|
||||
startTime = Date.now();
|
||||
lastRingSpawn = Date.now();
|
||||
gameRunning = true;
|
||||
|
||||
if (window.soundFX) window.soundFX.playWhoosh();
|
||||
if (window.navigator && window.navigator.vibrate) window.navigator.vibrate(40);
|
||||
};
|
||||
|
||||
// Player (Broomstick)
|
||||
const player = {
|
||||
x: 90,
|
||||
@@ -206,13 +230,13 @@
|
||||
btnBoost.addEventListener('pointerleave', endBoost);
|
||||
}
|
||||
|
||||
// Pre-spawn 3 rings
|
||||
rings.push({ x: width + 50, y: height * 0.4, radius: 25, speed: 3.5, golden: false, collected: false, scale: 1, alpha: 1, pulse: 0 });
|
||||
rings.push({ x: width + 280, y: height * 0.65, radius: 25, speed: 3.6, golden: true, collected: false, scale: 1, alpha: 1, pulse: 0 });
|
||||
rings.push({ x: width + 520, y: height * 0.3, radius: 25, speed: 3.7, golden: false, collected: false, scale: 1, alpha: 1, pulse: 0 });
|
||||
|
||||
function update() {
|
||||
if (!gameRunning) return;
|
||||
if (!gameRunning) {
|
||||
// Idle gentle float before start
|
||||
player.y = (height * 0.5) + Math.sin(Date.now() * 0.003) * 8;
|
||||
player.angle = Math.sin(Date.now() * 0.003) * 0.04;
|
||||
return;
|
||||
}
|
||||
|
||||
const elapsedSec = Math.floor((Date.now() - startTime) / 1000);
|
||||
if (timerVal) timerVal.innerText = elapsedSec + 's';
|
||||
|
||||
@@ -69,6 +69,21 @@
|
||||
{ x: 0.34, y: 0.52 },
|
||||
{ x: 0.34, y: 0.80 }
|
||||
]
|
||||
},
|
||||
{
|
||||
id: 'expecto_patronum',
|
||||
name: 'Expecto Patronum 🦌',
|
||||
incantation: '"Expecto Patronum!" (Meister-Schutzzauber)',
|
||||
desc: 'Verbinde die 5 Sterne des Lichts im Pentagramm (1 ➔ 2 ➔ 3 ➔ 4 ➔ 5), um die Rüstung endgültig zu bannen!',
|
||||
color: '#ffffff',
|
||||
beamColor: '#bbf2f6',
|
||||
points: [
|
||||
{ x: 0.35, y: 0.18 },
|
||||
{ x: 0.50, y: 0.65 },
|
||||
{ x: 0.18, y: 0.35 },
|
||||
{ x: 0.52, y: 0.35 },
|
||||
{ x: 0.20, y: 0.65 }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@
|
||||
targetEl.classList.remove('active');
|
||||
targetEl.classList.remove('frozen');
|
||||
targetEl.classList.remove('neville');
|
||||
targetEl.innerText = '';
|
||||
}
|
||||
activeTargets.delete(holeIdx);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user