// Magisches Runen-Drehschloss (Cryptex Engine - Mobile First) (function() { const DIALS = [ // Dial 0: Houses [ { icon: '🦁', name: 'Löwe' }, { icon: '🐍', name: 'Schlange' }, { icon: '🦅', name: 'Rabe' }, { icon: '🦡', name: 'Dachs' } ], // Dial 1: Astral [ { icon: '☀️', name: 'Sonne' }, { icon: '🌙', name: 'Mond' }, { icon: '⭐', name: 'Stern' }, { icon: '⚡', name: 'Blitz' } ], // Dial 2: Elements [ { icon: '🔥', name: 'Feuer' }, { icon: '💧', name: 'Wasser' }, { icon: '🌿', name: 'Kräuter' }, { icon: '💨', name: 'Wind' } ], // Dial 3: Artifacts [ { icon: '🗝️', name: 'Schlüssel' }, { icon: '🪄', name: 'Zauberstab' }, { icon: '📜', name: 'Rolle' }, { icon: '⚗️', name: 'Phiole' } ] ]; // Initial indices (unsolved) const state = [0, 0, 1, 0]; let isUnlocked = false; // Elements const feedbackBox = document.getElementById('cryptexFeedback'); const successPanel = document.getElementById('cryptexSuccess'); const unlockBtn = document.getElementById('unlockCryptexBtn'); window.stepDial = function(dialIdx, dir) { if (isUnlocked) return; const dial = DIALS[dialIdx]; state[dialIdx] = (state[dialIdx] + dir + dial.length) % dial.length; const symEl = document.getElementById(`sym${dialIdx}`); const lblEl = document.getElementById(`lbl${dialIdx}`); if (window.navigator && window.navigator.vibrate) window.navigator.vibrate(20); if (window.soundFX) window.soundFX.playStoneSlide(); // Quick flip animation symEl.style.transform = dir > 0 ? 'translateY(12px) scale(0.85)' : 'translateY(-12px) scale(0.85)'; symEl.style.opacity = '0.4'; setTimeout(() => { const currentItem = dial[state[dialIdx]]; symEl.innerText = currentItem.icon; lblEl.innerText = currentItem.name; symEl.style.transform = 'translateY(0) scale(1)'; symEl.style.opacity = '1'; }, 80); }; // Mobile Swipe Handler for each cylinder for (let i = 0; i < 4; i++) { const cyl = document.getElementById(`cylinder${i}`); if (!cyl) continue; let startY = 0; let isTouching = false; cyl.addEventListener('touchstart', (e) => { if (e.touches.length > 0) { startY = e.touches[0].clientY; isTouching = true; } }, { passive: true }); cyl.addEventListener('touchend', (e) => { if (!isTouching) return; isTouching = false; const endY = e.changedTouches[0].clientY; const diff = endY - startY; // If swiped more than 20px if (Math.abs(diff) > 20) { e.preventDefault(); if (diff < 0) { window.stepDial(i, 1); // Swipe Up -> Next } else { window.stepDial(i, -1); // Swipe Down -> Prev } } }); } window.checkCryptex = async function() { if (isUnlocked) return; const currentCombination = [ DIALS[0][state[0]].icon, DIALS[1][state[1]].icon, DIALS[2][state[2]].icon, DIALS[3][state[3]].icon ]; try { const res = await fetch('/api/cryptex/unlock', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ combination: currentCombination }) }); const data = await res.json(); if (data.success) { isUnlocked = true; if (unlockBtn) unlockBtn.style.display = 'none'; if (window.soundFX) { window.soundFX.playKeyChime(); window.soundFX.playMagicSuccess(); } if (window.navigator && window.navigator.vibrate) { window.navigator.vibrate([60, 100, 150]); } // Show golden shine on cylinders document.querySelectorAll('.dial-cylinder').forEach(c => { c.style.borderColor = 'var(--gold)'; c.style.boxShadow = '0 0 20px var(--gold)'; }); if (feedbackBox) { feedbackBox.style.display = 'block'; feedbackBox.style.background = 'rgba(46, 204, 113, 0.25)'; feedbackBox.style.border = '1px solid #2ecc71'; feedbackBox.style.color = '#2ecc71'; feedbackBox.innerText = data.message; } if (data.new_item && window.notifyNewItem) { window.notifyNewItem(data.new_item); } setTimeout(() => { if (successPanel) successPanel.style.display = 'block'; }, 600); } else { if (window.soundFX) window.soundFX.playWhoosh(); if (window.navigator && window.navigator.vibrate) { window.navigator.vibrate([40, 40]); } const box = document.querySelector('.cryptex-box'); box.style.transform = 'translateX(-8px)'; setTimeout(() => box.style.transform = 'translateX(8px)', 80); setTimeout(() => box.style.transform = 'translateX(-4px)', 160); setTimeout(() => box.style.transform = 'translateX(0)', 240); if (feedbackBox) { feedbackBox.style.display = 'block'; feedbackBox.style.background = 'rgba(231, 76, 60, 0.25)'; feedbackBox.style.border = '1px solid #e74c3c'; feedbackBox.style.color = '#e74c3c'; feedbackBox.innerText = data.message; } } } catch (e) { console.error("Cryptex check error:", e); } }; })();