203 lines
9.6 KiB
JavaScript
Executable File
203 lines
9.6 KiB
JavaScript
Executable File
// Snape's 7 Potions Riddle & Interactive Bottle Board
|
|
(function() {
|
|
let selectedBottle = null;
|
|
const slots = document.querySelectorAll('.bottle-slot');
|
|
const selectedInfo = document.getElementById('selectedBottleInfo');
|
|
const btnDrinkAhead = document.getElementById('btnDrinkAhead');
|
|
const btnDrinkBack = document.getElementById('btnDrinkBack');
|
|
const modalBackdrop = document.getElementById('modalBackdrop');
|
|
const modalTitle = document.getElementById('modalTitle');
|
|
const modalText = document.getElementById('modalText');
|
|
const modalBtn = document.getElementById('modalBtn');
|
|
const modalIcon = document.getElementById('modalIcon');
|
|
|
|
// Bottle Descriptions based on Book Clues
|
|
const bottleDescriptions = {
|
|
1: "Eine dunkelbraune Phiole mittlerer Größe. Auf der linken Seite von Flasche 2.",
|
|
2: "Eine schlanke, grüne Glasflasche. Schmeckt laut Hinweis 4 exakt wie Flasche 6!",
|
|
3: "🔍 Die kleinste Flasche von allen (der 'Zwerg')! Sie enthält kaum mehr als einen einzigen Schluck.",
|
|
4: "Ein eigenartiger, kantiger Glaskolben mit trüber, unruhiger Flüssigkeit.",
|
|
5: "Eine bauchige Flasche aus Rauchglas. Steht direkt links von Flasche 6.",
|
|
6: "Eine elegante Flasche, die Zwillingsschwester von Flasche 2, auch wenn sie äußerlich verschieden wirken.",
|
|
7: "🏺 Die größte Flasche in der Reihe (der 'Riese')! Ein schwerer, bauchiger Dekanter."
|
|
};
|
|
|
|
slots.forEach(slot => {
|
|
slot.addEventListener('click', (e) => {
|
|
if (e.target.tagName === 'SELECT') return; // Don't trigger on tag dropdown
|
|
selectSlot(slot);
|
|
});
|
|
|
|
// Drag & Drop / Reordering support
|
|
slot.setAttribute('draggable', 'true');
|
|
slot.addEventListener('dragstart', (e) => {
|
|
e.dataTransfer.setData('text/plain', slot.dataset.index);
|
|
if (window.soundFX) window.soundFX.playStoneSlide();
|
|
});
|
|
|
|
slot.addEventListener('dragover', (e) => {
|
|
e.preventDefault();
|
|
slot.classList.add('drag-over');
|
|
});
|
|
|
|
slot.addEventListener('dragleave', () => {
|
|
slot.classList.remove('drag-over');
|
|
});
|
|
|
|
slot.addEventListener('drop', (e) => {
|
|
e.preventDefault();
|
|
slot.classList.remove('drag-over');
|
|
const sourceIndex = e.dataTransfer.getData('text/plain');
|
|
const sourceSlot = document.querySelector(`.bottle-slot[data-index="${sourceIndex}"]`);
|
|
if (sourceSlot && sourceSlot !== slot) {
|
|
swapSlots(sourceSlot, slot);
|
|
}
|
|
});
|
|
});
|
|
|
|
function swapSlots(slotA, slotB) {
|
|
if (window.soundFX) {
|
|
window.soundFX.playStoneSlide();
|
|
window.soundFX.playBottleClink();
|
|
}
|
|
// Swap inner contents except the pedestal number
|
|
const tempHTML = slotA.innerHTML;
|
|
slotA.innerHTML = slotB.innerHTML;
|
|
slotB.innerHTML = tempHTML;
|
|
|
|
// Restore event listeners on newly swapped selects
|
|
attachTagListeners();
|
|
selectSlot(slotB);
|
|
}
|
|
|
|
function selectSlot(slot) {
|
|
slots.forEach(s => s.classList.remove('selected'));
|
|
slot.classList.add('selected');
|
|
selectedBottle = parseInt(slot.dataset.index, 10);
|
|
|
|
if (window.soundFX) window.soundFX.playBottleClink();
|
|
|
|
if (btnDrinkAhead) btnDrinkAhead.disabled = false;
|
|
if (btnDrinkBack) btnDrinkBack.disabled = false;
|
|
|
|
if (selectedInfo) {
|
|
const desc = bottleDescriptions[selectedBottle] || "Eine geheimnisvolle Flasche.";
|
|
selectedInfo.innerHTML = `Gewählt: <strong>Flasche ${selectedBottle}</strong> — <em>${desc}</em>`;
|
|
}
|
|
}
|
|
|
|
function attachTagListeners() {
|
|
document.querySelectorAll('.bottle-tag-select').forEach(sel => {
|
|
sel.addEventListener('change', () => {
|
|
if (window.soundFX) window.soundFX.playStoneSlide();
|
|
});
|
|
});
|
|
}
|
|
attachTagListeners();
|
|
|
|
// Drink to pass Ahead (Black Fire)
|
|
if (btnDrinkAhead) {
|
|
btnDrinkAhead.addEventListener('click', () => {
|
|
if (!selectedBottle) return;
|
|
drinkBottle(selectedBottle, 'ahead');
|
|
});
|
|
}
|
|
|
|
// Drink to pass Back (Purple Fire)
|
|
if (btnDrinkBack) {
|
|
btnDrinkBack.addEventListener('click', () => {
|
|
if (!selectedBottle) return;
|
|
drinkBottle(selectedBottle, 'back');
|
|
});
|
|
}
|
|
|
|
async function drinkBottle(bottleIdx, gate) {
|
|
if (window.soundFX) window.soundFX.playBottleClink();
|
|
|
|
try {
|
|
const res = await fetch('/api/bottles/drink', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ bottle: bottleIdx, gate: gate, lang: 'de' })
|
|
});
|
|
const data = await res.json();
|
|
|
|
if (data.result === 'success_ahead') {
|
|
if (window.showChamberVictory) {
|
|
window.showChamberVictory({
|
|
chamberBadge: "Kammer VI: Snapes Flaschenrätsel",
|
|
title: "🔥 Schwarzes Feuer Durchquert!",
|
|
statsHtml: `<span>🧪 Flasche 3 (Zwerg): <strong>Schutztrank</strong></span><span>🔥 Schwarzes Feuer: <strong>Besiegt!</strong></span>`,
|
|
item: data.new_item || {
|
|
id: "philosophers_stone",
|
|
name: "Stein der Weisen",
|
|
icon: "💎",
|
|
desc: "Der legendäre rote Alchemistenstein!"
|
|
},
|
|
storyText: "Ein eisiger Frosthauch hüllt deinen Körper ein! Du schreitest durch das tosend schwarze Feuer, ohne auch nur ein Haar zu versengen. Dahinter enthüllt sich das größte Geheimnis von Hogwarts: <strong>Der Spiegel Nerhegeb und der Stein der Weisen</strong>!",
|
|
nextUrl: "/finale",
|
|
nextBtnText: "➔ Zum großen Finale: Der Stein der Weisen 💎"
|
|
});
|
|
} else {
|
|
if (window.soundFX) window.soundFX.playMagicSuccess();
|
|
if (window.notifyNewItem && data.new_item) {
|
|
window.notifyNewItem(data.new_item);
|
|
}
|
|
modalIcon.innerText = "❄️⚡";
|
|
modalTitle.innerText = "Hervorragend kombiniert!";
|
|
modalTitle.style.color = "#ffd700";
|
|
modalText.innerHTML = `Du hast die <strong>kleinste Flasche (Flasche 3, den 'Zwerg')</strong> getrunken!<br><br>
|
|
${data.message}<br><br>
|
|
Das schwarze Feuer teilt sich mit einem frostigen Zischen. Der Weg zum Stein der Weisen liegt frei vor dir!`;
|
|
modalBtn.innerText = "Zum Finale & Escape-Triumph 🏆";
|
|
modalBtn.onclick = () => { window.location.href = data.next_url; };
|
|
modalBackdrop.classList.add('show');
|
|
}
|
|
|
|
} else if (data.result === 'success_back') {
|
|
if (window.soundFX) window.soundFX.playMagicSuccess();
|
|
modalIcon.innerText = "🟣";
|
|
modalTitle.innerText = "Rückzug gesichert!";
|
|
modalText.innerHTML = `Du hast die <strong>größte Flasche (Flasche 7, den 'Riesen')</strong> getrunken.<br><br>
|
|
${data.message}<br><br>
|
|
Du kannst sicher durch die violetten Flammen zurückweichen, um deinen Gefährten zu helfen oder den Besenflug nochmals zu betreten.`;
|
|
modalBtn.innerText = "Zurück zum Besenflug 🧹";
|
|
modalBtn.onclick = () => { window.location.href = data.next_url; };
|
|
modalBackdrop.classList.add('show');
|
|
} else if (data.result === 'poison') {
|
|
if (window.soundFX) window.soundFX.playPoisonSizzle();
|
|
modalIcon.innerText = "💀";
|
|
modalTitle.innerText = "Tödliches Gift!";
|
|
modalTitle.style.color = "#e74c3c";
|
|
modalText.innerHTML = `${data.message}<br><br>
|
|
<strong>Snapes Rätsel-Hinweis:</strong><br>
|
|
<em>"So schlau sich das Gift auch zu tarnen mag,<br>
|
|
stets steht es zur Linken vom Wein im Gelag."</em>`;
|
|
modalBtn.innerText = "Erneut analysieren 📜";
|
|
modalBtn.onclick = () => { modalBackdrop.classList.remove('show'); };
|
|
modalBackdrop.classList.add('show');
|
|
} else if (data.result === 'wine') {
|
|
if (window.soundFX) window.soundFX.playPoisonSizzle();
|
|
modalIcon.innerText = "🍷";
|
|
modalTitle.innerText = "Harmloser Brennnesselwein";
|
|
modalTitle.style.color = "#e67e22";
|
|
modalText.innerHTML = `${data.message}<br><br>
|
|
Du spürst keinerlei Schutz vor der Hitze der Flammen. Wenn du jetzt hineintrittst, verbrennst du! Lies die Verse auf dem Pergament noch einmal gründlich.`;
|
|
modalBtn.innerText = "Verstanden 📜";
|
|
modalBtn.onclick = () => { modalBackdrop.classList.remove('show'); };
|
|
modalBackdrop.classList.add('show');
|
|
} else {
|
|
if (window.soundFX) window.soundFX.playPoisonSizzle();
|
|
modalIcon.innerText = "⚠️";
|
|
modalTitle.innerText = "Falsche Flamme!";
|
|
modalText.innerText = data.message;
|
|
modalBtn.innerText = "Zurück";
|
|
modalBtn.onclick = () => { modalBackdrop.classList.remove('show'); };
|
|
modalBackdrop.classList.add('show');
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
}
|
|
}
|
|
})();
|