dok/public/js/quickmenu/events.js
2026-04-06 13:52:15 +01:00

266 lines
9.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* ================================
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 = `<img src="/images/items/${file}" alt="Stufe ${rarity}" style="width:${size}px;height:${size}px;object-fit:contain;filter:drop-shadow(0 1px 2px rgba(0,0,0,0.8));">`;
return img.repeat(count);
}
function cardHTML(card, isFront = true) {
if (!isFront) return `<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">`;
// image zuerst, dann icon als Fallback
const imgFile = card?.image || card?.icon || null;
const img = imgFile ? `/images/cards/${imgFile}` : "/images/items/rueckseite.png";
return `
<img class="booster-slot-img" src="${img}" alt="${card?.name || ''}" draggable="false"
onerror="this.src='/images/items/rueckseite.png'">
${card?.attack != null ? `<span class="bs-stat-atk">${card.attack}</span>` : ""}
${card?.defends != null ? `<span class="bs-stat-def">${card.defends}</span>` : ""}
${card?.cooldown!= null ? `<span class="bs-stat-cd">${card.cooldown}</span>` : ""}
${card?.rarity ? `<div class="bs-rarity">${rarityImgs(card.rarity, 11)}</div>` : ""}
<div class="bs-card-name">${card?.name || ''}</div>
`;
}
/* ================================
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 = `
<div class="events-grid" id="events-grid">
${events.map(ev => `
<div class="event-card" data-event-id="${ev.id}" data-type="${ev.type || ''}">
<div class="event-card-img-wrap">
<img src="${ev.img}" alt="${ev.label}" draggable="false">
</div>
<span class="event-card-label">${ev.label}</span>
</div>`).join("")}
</div>
<!-- Booster UI -->
<div id="booster-ui" class="booster-ui" style="display:none;">
<button class="booster-back-btn" id="booster-back-btn">← Zurück</button>
<div class="booster-stage">
<div class="booster-left">
<img id="booster-stapel" src="/images/items/boosterstapel.png" alt="Booster" draggable="false" class="booster-stapel-img">
<span class="booster-stapel-hint" id="booster-hint">Klicken zum Öffnen</span>
</div>
<div class="booster-slots" id="booster-slots">
${Array.from({length: 5}, (_, i) => `
<div class="booster-slot" id="booster-slot-${i}">
<div class="booster-slot-inner">
<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">
</div>
</div>`).join("")}
</div>
</div>
</div>
<!-- Standard Detail-Popup -->
<div id="event-detail-overlay">
<div id="event-detail-popup">
<button class="edp-close" id="edp-close-btn"></button>
<img class="edp-img" id="edp-img" src="" alt="">
<div class="edp-title" id="edp-title"></div>
<div class="edp-body" id="edp-body">Inhalt folgt...</div>
</div>
</div>
`;
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 = `<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">`;
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);
}, 350);
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 data = await res.json();
drawnCards = data.cards || [];
} 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();
}