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

248 lines
8.7 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">`;
const img = card?.image ? `/images/cards/${card.image}` : "/images/items/rueckseite.png";
return `
<img class="booster-slot-img" src="${img}" alt="${card?.name || ''}" draggable="false">
${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 = [];
function clearAllIntervals() {
spinIntervals.forEach(id => clearInterval(id));
spinIntervals = [];
}
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) {
const slot = body.querySelector(`#booster-slot-${index}`);
const inner = slot.querySelector(".booster-slot-inner");
slot.classList.add("spinning");
const iv = setInterval(() => {
if (!allCards.length) return;
const rnd = allCards[Math.floor(Math.random() * allCards.length)];
inner.innerHTML = cardHTML(rnd, true);
}, 350);
spinIntervals[index] = iv;
}
/* ── Slot enthüllen ── */
function revealSlot(index, card) {
clearInterval(spinIntervals[index]);
const slot = body.querySelector(`#booster-slot-${index}`);
const inner = slot.querySelector(".booster-slot-inner");
slot.classList.remove("spinning");
slot.classList.add("revealed");
inner.innerHTML = cardHTML(card, true);
}
/* ── 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();
}