228 lines
8.2 KiB
JavaScript
Executable File
228 lines
8.2 KiB
JavaScript
Executable File
// Zaubertrank-Brauküche (Felix Felicis Potion Brewing Engine)
|
|
(function() {
|
|
let currentStep = 1; // 1: Ingredients, 2: Stirring, 3: Heat, 4: Done
|
|
const ingredients = {
|
|
dragon: 0,
|
|
mandrake: 0,
|
|
star: 0
|
|
};
|
|
const targetIngredients = {
|
|
dragon: 2,
|
|
mandrake: 1,
|
|
star: 1
|
|
};
|
|
|
|
// DOM Elements
|
|
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 stirTracker = document.getElementById('stirTracker');
|
|
const stirCounterText = document.getElementById('stirCounterText');
|
|
const stirCountSpan = document.getElementById('stirCount');
|
|
const heatPanel = document.getElementById('heatPanel');
|
|
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) {
|
|
if (currentStep !== 1) return;
|
|
if (ingredients[type] >= targetIngredients[type]) return;
|
|
|
|
ingredients[type]++;
|
|
if (window.soundFX) window.soundFX.playBottleClink();
|
|
|
|
// Update UI Badge
|
|
if (type === 'dragon') {
|
|
document.getElementById('countDragon').innerText = `${ingredients.dragon} / ${targetIngredients.dragon}`;
|
|
if (ingredients.dragon >= targetIngredients.dragon) document.getElementById('ingDragon').classList.add('done');
|
|
} else if (type === 'mandrake') {
|
|
document.getElementById('countMandrake').innerText = `${ingredients.mandrake} / ${targetIngredients.mandrake}`;
|
|
if (ingredients.mandrake >= targetIngredients.mandrake) document.getElementById('ingMandrake').classList.add('done');
|
|
} else if (type === 'star') {
|
|
document.getElementById('countStar').innerText = `${ingredients.star} / ${targetIngredients.star}`;
|
|
if (ingredients.star >= targetIngredients.star) document.getElementById('ingStar').classList.add('done');
|
|
}
|
|
|
|
// Ripple effect on surface
|
|
potionSurface.style.transform = 'scale(1.08)';
|
|
setTimeout(() => potionSurface.style.transform = 'scale(1)', 200);
|
|
|
|
// Check if all ingredients added
|
|
const total = ingredients.dragon + ingredients.mandrake + ingredients.star;
|
|
if (total === 4) {
|
|
setTimeout(startStep2, 600);
|
|
}
|
|
};
|
|
|
|
// Step 2: Stirring
|
|
let completedStirs = 0;
|
|
let lastAngle = null;
|
|
let accumulatedAngle = 0;
|
|
|
|
function startStep2() {
|
|
currentStep = 2;
|
|
stepBadge.innerText = "Schritt 2: Gleichmäßig rühren";
|
|
stepInstruction.innerText = "Rühre den Sud 3 Runden im Uhrzeigersinn!";
|
|
stepSubtext.innerText = "Führe deinen Finger oder die Maus im Kreis über dem Kessel oder tippe ihn an.";
|
|
ingredientsShelf.style.display = 'none';
|
|
stirCounterText.style.display = 'block';
|
|
stirCircle.classList.add('active');
|
|
potionSurface.className = 'potion-surface state-stir';
|
|
|
|
if (window.soundFX) window.soundFX.playStoneSlide();
|
|
}
|
|
|
|
// Touch / Pointer stirring logic
|
|
let isStirring = false;
|
|
|
|
function getAngle(e) {
|
|
const rect = cauldronZone.getBoundingClientRect();
|
|
const centerX = rect.left + rect.width / 2;
|
|
const centerY = rect.top + rect.height / 2;
|
|
const clientX = e.touches ? e.touches[0].clientX : e.clientX;
|
|
const clientY = e.touches ? e.touches[0].clientY : e.clientY;
|
|
return Math.atan2(clientY - centerY, clientX - centerX) * (180 / Math.PI);
|
|
}
|
|
|
|
function onStirStart(e) {
|
|
if (currentStep !== 2) return;
|
|
isStirring = true;
|
|
lastAngle = getAngle(e);
|
|
}
|
|
|
|
function onStirMove(e) {
|
|
if (currentStep !== 2 || !isStirring) return;
|
|
e.preventDefault();
|
|
const angle = getAngle(e);
|
|
if (lastAngle !== null) {
|
|
let diff = angle - lastAngle;
|
|
// Handle wrap-around
|
|
if (diff < -180) diff += 360;
|
|
if (diff > 180) diff -= 360;
|
|
|
|
// Only count clockwise
|
|
if (diff > 0) {
|
|
accumulatedAngle += diff;
|
|
if (accumulatedAngle >= 360) {
|
|
accumulatedAngle -= 360;
|
|
incrementStir();
|
|
}
|
|
}
|
|
}
|
|
lastAngle = angle;
|
|
}
|
|
|
|
function onStirEnd() {
|
|
isStirring = false;
|
|
lastAngle = null;
|
|
}
|
|
|
|
function incrementStir() {
|
|
completedStirs++;
|
|
stirCountSpan.innerText = completedStirs;
|
|
if (window.soundFX) window.soundFX.playBottleClink();
|
|
|
|
if (completedStirs >= 3) {
|
|
stirCircle.classList.remove('active');
|
|
stirCounterText.style.display = 'none';
|
|
setTimeout(startStep3, 600);
|
|
}
|
|
}
|
|
|
|
// Direct tap fallback for mobile
|
|
cauldronZone.addEventListener('click', () => {
|
|
if (currentStep === 2 && !isStirring) {
|
|
incrementStir();
|
|
}
|
|
});
|
|
|
|
cauldronZone.addEventListener('mousedown', onStirStart);
|
|
window.addEventListener('mousemove', onStirMove);
|
|
window.addEventListener('mouseup', onStirEnd);
|
|
|
|
cauldronZone.addEventListener('touchstart', onStirStart, { passive: false });
|
|
window.addEventListener('touchmove', onStirMove, { passive: false });
|
|
window.addEventListener('touchend', onStirEnd);
|
|
|
|
// Step 3: Heat Control
|
|
let currentTemp = 35; // percent (0-100)
|
|
let heatTimer = 0.0;
|
|
let heatInterval = null;
|
|
|
|
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 Nadel für 4 Sekunden im grünen Bereich (60% - 85%).";
|
|
potionSurface.className = 'potion-surface state-heat';
|
|
heatPanel.classList.add('active');
|
|
|
|
if (window.soundFX) window.soundFX.playWhoosh();
|
|
|
|
heatInterval = setInterval(updateHeatLoop, 50);
|
|
}
|
|
|
|
window.pumpHeat = function() {
|
|
if (currentStep !== 3) return;
|
|
currentTemp = Math.min(100, currentTemp + 15);
|
|
if (window.soundFX) window.soundFX.playWhoosh();
|
|
};
|
|
|
|
function updateHeatLoop() {
|
|
if (currentStep !== 3) return;
|
|
|
|
// Slow cooling down
|
|
currentTemp = Math.max(0, currentTemp - 0.55);
|
|
tempIndicator.style.width = currentTemp + '%';
|
|
|
|
// Check ideal zone (60% to 85%)
|
|
if (currentTemp >= 60 && currentTemp <= 85) {
|
|
heatTimer += 0.05;
|
|
heatTimerSpan.innerText = heatTimer.toFixed(1);
|
|
tempIndicator.style.background = '#2ecc71';
|
|
} else {
|
|
tempIndicator.style.background = 'linear-gradient(90deg, #3498db, #f39c12, #e74c3c)';
|
|
}
|
|
|
|
if (heatTimer >= 4.0) {
|
|
clearInterval(heatInterval);
|
|
finishPotionBrew();
|
|
}
|
|
}
|
|
|
|
// Step 4: Victory
|
|
async function finishPotionBrew() {
|
|
currentStep = 4;
|
|
stepBadge.innerText = "✅ Trank vollendet!";
|
|
stepBadge.style.background = "rgba(46, 204, 113, 0.3)";
|
|
stepBadge.style.borderColor = "#2ecc71";
|
|
stepBadge.style.color = "#2ecc71";
|
|
|
|
stepInstruction.innerText = "Felix Felicis strahlt in reinem Gold!";
|
|
stepSubtext.innerText = "Dein Zaubertrank ist perfekt gelungen.";
|
|
|
|
heatPanel.classList.remove('active');
|
|
potionSurface.className = 'potion-surface state-gold';
|
|
|
|
if (window.soundFX) window.soundFX.playMagicSuccess();
|
|
|
|
// API Completion Call
|
|
try {
|
|
const res = await fetch('/api/brew/complete', { method: 'POST' });
|
|
const data = await res.json();
|
|
if (data.new_item && window.notifyNewItem) {
|
|
window.notifyNewItem(data.new_item);
|
|
}
|
|
} catch (e) {
|
|
console.error("Brew complete error:", e);
|
|
}
|
|
|
|
successPanel.style.display = 'block';
|
|
}
|
|
})();
|