/* ================================ Kristall-Mapping (aus carddeck.js) ================================ */ const RARITY_CRYSTALS = { 1: "roter-cristal.png", 2: "blauer-cristal.png", 3: "gelber-cristal.png", 4: "gruener-cristal.png", 5: "oranger-cristal.png", 6: "violet-cristal.png", 7: "pinker-cristal.png", }; function rarityImgs(rarity, size = 13) { const file = RARITY_CRYSTALS[String(rarity)]; if (!file) return ""; const count = parseInt(rarity) || 0; const img = `Stufe ${rarity}`; return img.repeat(count); } function cardHTML(card, isFront = true) { if (!isFront) return `?`; // image zuerst, dann icon als Fallback const imgFile = card?.image || card?.icon || null; const img = imgFile ? `/images/cards/${imgFile}` : "/images/items/rueckseite.png"; return ` ${card?.name || ''} ${card?.attack != null ? `${card.attack}` : ""} ${card?.defends != null ? `${card.defends}` : ""} ${card?.cooldown!= null ? `${card.cooldown}` : ""} ${card?.rarity ? `
${rarityImgs(card.rarity, 11)}
` : ""}
${card?.name || ''}
`; } /* ================================ Haupt-Export ================================ */ export async function loadEvents() { const body = document.getElementById("qm-body-events"); if (!body) return; if (!document.querySelector('link[href="/css/events.css"]')) { const link = document.createElement("link"); link.rel = "stylesheet"; link.href = "/css/events.css"; document.head.appendChild(link); } const events = [ { id: 1, img: "/images/items/runenhaufen.png", label: "Booster Öffnen", type: "booster" }, { id: 2, img: "/images/items/runenhaufen.png", label: "Textzeile 2" }, { id: 3, img: "/images/items/runenhaufen.png", label: "Textzeile 3" }, { id: 4, img: "/images/items/runenhaufen.png", label: "Textzeile 4" }, { id: 5, img: "/images/items/runenhaufen.png", label: "Textzeile 5" }, ]; body.innerHTML = `
${events.map(ev => `
${ev.label}
${ev.label}
`).join("")}
Inhalt folgt...
`; const overlay = body.querySelector("#event-detail-overlay"); const edpImg = body.querySelector("#edp-img"); const edpTitle = body.querySelector("#edp-title"); const edpBody = body.querySelector("#edp-body"); const boosterUi = body.querySelector("#booster-ui"); const eventsGrid = body.querySelector("#events-grid"); /* ── Event-Karten ── */ body.querySelectorAll(".event-card").forEach(card => { card.addEventListener("click", () => { if (card.dataset.type === "booster") { eventsGrid.style.display = "none"; boosterUi.style.display = "flex"; resetBooster(); return; } const id = Number(card.dataset.eventId); const ev = events.find(e => e.id === id); if (!ev) return; edpImg.src = ev.img; edpImg.alt = ev.label; edpTitle.textContent = ev.label; edpBody.textContent = "Inhalt folgt..."; overlay.classList.add("active"); }); }); body.querySelector("#edp-close-btn").addEventListener("click", () => overlay.classList.remove("active")); overlay.addEventListener("click", e => { if (e.target === overlay) overlay.classList.remove("active"); }); body.querySelector("#booster-back-btn").addEventListener("click", () => { eventsGrid.style.display = ""; boosterUi.style.display = "none"; clearAllIntervals(); isSpinning = false; }); document.addEventListener("keydown", e => { if (e.key === "Escape") { overlay.classList.remove("active"); eventsGrid.style.display = ""; boosterUi.style.display = "none"; clearAllIntervals(); } }); /* ── Booster Zustand ── */ let allCards = []; let isSpinning = false; let spinIntervals = {}; // { index: intervalId } let slotLocked = {}; // { index: true } → verhindert Überschreiben nach reveal function clearAllIntervals() { Object.values(spinIntervals).forEach(id => clearInterval(id)); spinIntervals = {}; slotLocked = {}; } async function preloadCards() { if (allCards.length) return; try { const res = await fetch("/api/booster/cards"); if (!res.ok) throw new Error(res.status); allCards = await res.json(); } catch (e) { console.error("Karten laden fehlgeschlagen", e); } } function resetBooster() { clearAllIntervals(); isSpinning = false; for (let i = 0; i < 5; i++) { const inner = body.querySelector(`#booster-slot-${i} .booster-slot-inner`); inner.innerHTML = `?`; body.querySelector(`#booster-slot-${i}`).classList.remove("revealed", "spinning"); } const stapel = body.querySelector("#booster-stapel"); stapel.classList.remove("used"); stapel.style.opacity = "1"; stapel.style.cursor = "pointer"; body.querySelector("#booster-hint").textContent = "Klicken zum Öffnen"; preloadCards(); } /* ── Slot drehen – 350ms, damit man die Karten erkennt ── */ function startSpinSlot(index) { slotLocked[index] = false; const slot = body.querySelector(`#booster-slot-${index}`); const inner = slot.querySelector(".booster-slot-inner"); slot.classList.add("spinning"); const iv = setInterval(() => { if (!allCards.length || slotLocked[index]) return; const rnd = allCards[Math.floor(Math.random() * allCards.length)]; inner.innerHTML = cardHTML(rnd, true); }, 150); spinIntervals[index] = iv; } /* ── Slot enthüllen – Sperre setzen BEVOR clearInterval ── */ function revealSlot(index, card) { slotLocked[index] = true; // zuerst sperren clearInterval(spinIntervals[index]); // dann stoppen delete spinIntervals[index]; console.log(`[Booster] Slot ${index} enthüllt:`, card); const slot = body.querySelector(`#booster-slot-${index}`); const inner = slot.querySelector(".booster-slot-inner"); slot.classList.remove("spinning"); slot.classList.add("revealed"); // innerHTML setzen und danach nochmal sicherstellen (doppelte Absicherung) inner.innerHTML = cardHTML(card, true); setTimeout(() => { if (slot.classList.contains("revealed")) { inner.innerHTML = cardHTML(card, true); } }, 100); } /* ── Stapel klicken ── */ body.querySelector("#booster-stapel").addEventListener("click", async () => { if (isSpinning) return; if (!allCards.length) await preloadCards(); if (!allCards.length) return; isSpinning = true; const stapel = body.querySelector("#booster-stapel"); stapel.classList.add("used"); stapel.style.opacity = "0.35"; stapel.style.cursor = "default"; body.querySelector("#booster-hint").textContent = "Wird gezogen..."; let drawnCards = []; try { const res = await fetch("/api/booster/open", { method: "POST" }); const text = await res.text(); console.log("[Booster] API Antwort raw:", text); const data = JSON.parse(text); console.log("[Booster] API Antwort parsed:", data); drawnCards = data.cards || []; console.log("[Booster] drawnCards:", drawnCards); } catch (e) { console.error("Booster öffnen fehlgeschlagen", e); resetBooster(); return; } for (let i = 0; i < 5; i++) startSpinSlot(i); for (let i = 0; i < 5; i++) { setTimeout(() => revealSlot(i, drawnCards[i]), (i + 1) * 5000); } setTimeout(() => { body.querySelector("#booster-hint").textContent = "Alle Karten enthüllt!"; isSpinning = false; }, 5 * 5000 + 500); }); preloadCards(); }