aehaer
This commit is contained in:
parent
82803cf272
commit
42e5c19dd9
@ -31,7 +31,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: relative; /* ← fix: damit event-done-overlay korrekt positioniert wird */
|
position: relative; /* ← fix: damit event-done-overlay korrekt positioniert wird */
|
||||||
}
|
}
|
||||||
|
|
||||||
.event-card-img-wrap img {
|
.event-card-img-wrap img {
|
||||||
@ -375,6 +375,37 @@
|
|||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.event-locked {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-locked-overlay {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(0, 0, 0, 0.55);
|
||||||
|
border-radius: inherit;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-locked-overlay span {
|
||||||
|
display: block;
|
||||||
|
padding: 4px 7px;
|
||||||
|
border: 2px solid #a05010;
|
||||||
|
border-radius: 5px;
|
||||||
|
color: #e08030;
|
||||||
|
font-family: "Cinzel", serif;
|
||||||
|
font-size: 9px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.4;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
.event-done-overlay {
|
.event-done-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
@ -395,7 +426,7 @@
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
color: #3dbb3d;
|
color: #3dbb3d;
|
||||||
font-family: "Cinzel", serif;
|
font-family: "Cinzel", serif;
|
||||||
font-size: 14px;
|
font-size: 11px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
letter-spacing: 1px;
|
letter-spacing: 1px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
|
|||||||
@ -119,7 +119,7 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #1a1008;
|
color: #ffffff;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -107,14 +107,17 @@ document.querySelectorAll(".qm-popup").forEach((popup) => {
|
|||||||
================================ */
|
================================ */
|
||||||
|
|
||||||
function isBoosterSpinning() {
|
function isBoosterSpinning() {
|
||||||
// Nur sperren wenn das Events-Popup gerade offen UND der Slot dreht
|
|
||||||
const eventsPopup = document.getElementById("qm-popup-events");
|
const eventsPopup = document.getElementById("qm-popup-events");
|
||||||
if (!eventsPopup || !eventsPopup.classList.contains("active")) return false;
|
if (!eventsPopup || !eventsPopup.classList.contains("active")) return false;
|
||||||
|
|
||||||
const ui = document.getElementById("booster-ui");
|
// Booster-UI oder Wood-UI aktiv und Slot dreht
|
||||||
if (!ui || ui.style.display === "none") return false;
|
const boosterUi = document.getElementById("booster-ui");
|
||||||
|
if (boosterUi && boosterUi.style.display !== "none" && boosterUi.querySelector(".booster-slot.spinning")) return true;
|
||||||
|
|
||||||
return !!ui.querySelector(".booster-slot.spinning");
|
const woodUi = document.getElementById("wood-ui");
|
||||||
|
if (woodUi && woodUi.style.display !== "none" && woodUi.querySelector(".booster-slot.spinning")) return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelectorAll(".qm-popup-close").forEach((btn) => {
|
document.querySelectorAll(".qm-popup-close").forEach((btn) => {
|
||||||
|
|||||||
@ -20,22 +20,19 @@ function rarityImgs(rarity, size = 13) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function cardHTML(card, isFront = true) {
|
function cardHTML(card, isFront = true) {
|
||||||
if (!isFront)
|
if (!isFront) return `<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">`;
|
||||||
return `<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">`;
|
|
||||||
|
|
||||||
// image zuerst, dann icon als Fallback
|
// image zuerst, dann icon als Fallback
|
||||||
const imgFile = card?.image || card?.icon || null;
|
const imgFile = card?.image || card?.icon || null;
|
||||||
const img = imgFile
|
const img = imgFile ? `/images/cards/${imgFile}` : "/images/items/rueckseite.png";
|
||||||
? `/images/cards/${imgFile}`
|
|
||||||
: "/images/items/rueckseite.png";
|
|
||||||
return `
|
return `
|
||||||
<img class="booster-slot-img" src="${img}" alt="${card?.name || ""}" draggable="false"
|
<img class="booster-slot-img" src="${img}" alt="${card?.name || ''}" draggable="false"
|
||||||
onerror="this.src='/images/items/rueckseite.png'">
|
onerror="this.src='/images/items/rueckseite.png'">
|
||||||
${card?.attack != null ? `<span class="bs-stat-atk">${card.attack}</span>` : ""}
|
${card?.attack != null ? `<span class="bs-stat-atk">${card.attack}</span>` : ""}
|
||||||
${card?.defends != null ? `<span class="bs-stat-def">${card.defends}</span>` : ""}
|
${card?.defends != null ? `<span class="bs-stat-def">${card.defends}</span>` : ""}
|
||||||
${card?.cooldown != null ? `<span class="bs-stat-cd">${card.cooldown}</span>` : ""}
|
${card?.cooldown!= null ? `<span class="bs-stat-cd">${card.cooldown}</span>` : ""}
|
||||||
${card?.rarity ? `<div class="bs-rarity">${rarityImgs(card.rarity, 11)}</div>` : ""}
|
${card?.rarity ? `<div class="bs-rarity">${rarityImgs(card.rarity, 11)}</div>` : ""}
|
||||||
<div class="bs-card-name">${card?.name || ""}</div>
|
<div class="bs-card-name">${card?.name || ''}</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,52 +45,49 @@ export async function loadEvents() {
|
|||||||
|
|
||||||
if (!document.querySelector('link[href="/css/events.css"]')) {
|
if (!document.querySelector('link[href="/css/events.css"]')) {
|
||||||
const link = document.createElement("link");
|
const link = document.createElement("link");
|
||||||
link.rel = "stylesheet";
|
link.rel = "stylesheet";
|
||||||
link.href = "/css/events.css";
|
link.href = "/css/events.css";
|
||||||
document.head.appendChild(link);
|
document.head.appendChild(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
const events = [
|
const events = [
|
||||||
{
|
{ id: 1, img: "/images/items/runenhaufen.png", label: "Booster Öffnen", type: "booster" },
|
||||||
id: 1,
|
{ id: 2, img: "/images/items/runenhaufen.png", label: "Textzeile 2" },
|
||||||
img: "/images/items/runenhaufen.png",
|
{ id: 3, img: "/images/items/runenhaufen.png", label: "Textzeile 3" },
|
||||||
label: "Booster Öffnen",
|
{ id: 4, img: "/images/items/holz.png", label: "Holz Spenden", type: "wood", woodCost: 100 },
|
||||||
type: "booster",
|
{ id: 5, img: "/images/items/runenhaufen.png", label: "Textzeile 5" },
|
||||||
},
|
|
||||||
{ id: 2, img: "/images/items/1v1.png", label: "1 v 1" },
|
|
||||||
{ id: 3, img: "/images/items/2v2.png", label: "2 v 2" },
|
|
||||||
{ id: 4, img: "/images/items/holz.png", label: "Holz spenden" },
|
|
||||||
{ id: 5, img: "/images/items/goldmuenze.png", label: "Gold spenden" },
|
|
||||||
];
|
];
|
||||||
|
|
||||||
// Täglichen Status vom Server laden
|
// Täglichen Status + Holz-Bestand parallel laden
|
||||||
let completedToday = [];
|
let completedToday = [];
|
||||||
|
let playerWood = 0;
|
||||||
try {
|
try {
|
||||||
const statusRes = await fetch("/api/daily/status");
|
const [statusRes, hudRes] = await Promise.all([
|
||||||
if (statusRes.ok) {
|
fetch("/api/daily/status"),
|
||||||
const statusData = await statusRes.json();
|
fetch("/api/hud"),
|
||||||
completedToday = statusData.completed || [];
|
]);
|
||||||
}
|
if (statusRes.ok) completedToday = (await statusRes.json()).completed || [];
|
||||||
|
if (hudRes.ok) playerWood = (await hudRes.json()).wood || 0;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Daily-Status laden fehlgeschlagen", e);
|
console.error("Laden fehlgeschlagen", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
body.innerHTML = `
|
body.innerHTML = `
|
||||||
<div class="events-grid" id="events-grid">
|
<div class="events-grid" id="events-grid">
|
||||||
${events
|
${events.map(ev => {
|
||||||
.map((ev) => {
|
const done = completedToday.includes(ev.id);
|
||||||
const done = completedToday.includes(ev.id);
|
const locked = !done && ev.woodCost && playerWood < ev.woodCost;
|
||||||
return `
|
const cls = done ? ' event-done' : locked ? ' event-locked' : '';
|
||||||
<div class="event-card${done ? " event-done" : ""}" data-event-id="${ev.id}" data-type="${ev.type || ""}" data-done="${done}">
|
return `
|
||||||
|
<div class="event-card${cls}" data-event-id="${ev.id}" data-type="${ev.type || ''}" data-done="${done}" data-locked="${locked}">
|
||||||
<div class="event-card-img-wrap">
|
<div class="event-card-img-wrap">
|
||||||
<img src="${ev.img}" alt="${ev.label}" draggable="false">
|
<img src="${ev.img}" alt="${ev.label}" draggable="false">
|
||||||
${done ? `<div class="event-done-overlay">✓</div>` : ""}
|
${done ? `<div class="event-done-overlay"></div>` : ''}
|
||||||
|
${locked ? `<div class="event-locked-overlay"><span>🪵 ${ev.woodCost} Holz<br>benötigt</span></div>` : ''}
|
||||||
</div>
|
</div>
|
||||||
<span class="event-card-label">${ev.label}</span>
|
<span class="event-card-label">${ev.label}</span>
|
||||||
${done ? `<span class="event-done-label">Bereits erledigt</span>` : ""}
|
|
||||||
</div>`;
|
</div>`;
|
||||||
})
|
}).join("")}
|
||||||
.join("")}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Booster UI -->
|
<!-- Booster UI -->
|
||||||
@ -105,15 +99,31 @@ export async function loadEvents() {
|
|||||||
<span class="booster-stapel-hint" id="booster-hint">Klicken zum Öffnen</span>
|
<span class="booster-stapel-hint" id="booster-hint">Klicken zum Öffnen</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="booster-slots" id="booster-slots">
|
<div class="booster-slots" id="booster-slots">
|
||||||
${Array.from(
|
${Array.from({length: 5}, (_, i) => `
|
||||||
{ length: 5 },
|
|
||||||
(_, i) => `
|
|
||||||
<div class="booster-slot" id="booster-slot-${i}">
|
<div class="booster-slot" id="booster-slot-${i}">
|
||||||
<div class="booster-slot-inner">
|
<div class="booster-slot-inner">
|
||||||
<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">
|
<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">
|
||||||
</div>
|
</div>
|
||||||
</div>`,
|
</div>`).join("")}
|
||||||
).join("")}
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Holz-Spenden UI -->
|
||||||
|
<div id="wood-ui" class="booster-ui" style="display:none;">
|
||||||
|
<button class="booster-back-btn" id="wood-back-btn">← Zurück</button>
|
||||||
|
<div class="booster-stage">
|
||||||
|
<div class="booster-left">
|
||||||
|
<img id="wood-btn" src="/images/items/holz.png" alt="Holz Spenden" draggable="false" class="booster-stapel-img">
|
||||||
|
<span class="booster-stapel-hint" id="wood-hint">100 Holz spenden</span>
|
||||||
|
</div>
|
||||||
|
<div class="booster-slots" id="wood-slots">
|
||||||
|
${Array.from({length: 5}, (_, i) => `
|
||||||
|
<div class="booster-slot" id="wood-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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -129,32 +139,39 @@ export async function loadEvents() {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const overlay = body.querySelector("#event-detail-overlay");
|
const overlay = body.querySelector("#event-detail-overlay");
|
||||||
const edpImg = body.querySelector("#edp-img");
|
const edpImg = body.querySelector("#edp-img");
|
||||||
const edpTitle = body.querySelector("#edp-title");
|
const edpTitle = body.querySelector("#edp-title");
|
||||||
const edpBody = body.querySelector("#edp-body");
|
const edpBody = body.querySelector("#edp-body");
|
||||||
const boosterUi = body.querySelector("#booster-ui");
|
const boosterUi = body.querySelector("#booster-ui");
|
||||||
|
const woodUi = body.querySelector("#wood-ui");
|
||||||
const eventsGrid = body.querySelector("#events-grid");
|
const eventsGrid = body.querySelector("#events-grid");
|
||||||
|
|
||||||
/* ── Event-Karten ── */
|
/* ── Event-Karten ── */
|
||||||
body.querySelectorAll(".event-card").forEach((card) => {
|
body.querySelectorAll(".event-card").forEach(card => {
|
||||||
card.addEventListener("click", () => {
|
card.addEventListener("click", () => {
|
||||||
// Bereits erledigt → nicht anklickbar
|
if (card.dataset.done === "true") return;
|
||||||
if (card.dataset.done === "true") return;
|
if (card.dataset.locked === "true") return;
|
||||||
|
|
||||||
if (card.dataset.type === "booster") {
|
if (card.dataset.type === "booster") {
|
||||||
eventsGrid.style.display = "none";
|
eventsGrid.style.display = "none";
|
||||||
boosterUi.style.display = "flex";
|
boosterUi.style.display = "flex";
|
||||||
resetBooster();
|
resetBooster();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (card.dataset.type === "wood") {
|
||||||
|
eventsGrid.style.display = "none";
|
||||||
|
woodUi.style.display = "flex";
|
||||||
|
resetWood();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const id = Number(card.dataset.eventId);
|
const id = Number(card.dataset.eventId);
|
||||||
const ev = events.find((e) => e.id === id);
|
const ev = events.find(e => e.id === id);
|
||||||
if (!ev) return;
|
if (!ev) return;
|
||||||
edpImg.src = ev.img;
|
edpImg.src = ev.img;
|
||||||
edpImg.alt = ev.label;
|
edpImg.alt = ev.label;
|
||||||
edpTitle.textContent = ev.label;
|
edpTitle.textContent = ev.label;
|
||||||
edpBody.textContent = "Inhalt folgt...";
|
edpBody.textContent = "Inhalt folgt...";
|
||||||
overlay.classList.add("active");
|
overlay.classList.add("active");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -168,24 +185,16 @@ export async function loadEvents() {
|
|||||||
body: JSON.stringify({ eventId }),
|
body: JSON.stringify({ eventId }),
|
||||||
});
|
});
|
||||||
// Karte visuell als erledigt markieren
|
// Karte visuell als erledigt markieren
|
||||||
const card = body.querySelector(
|
const card = body.querySelector(`.event-card[data-event-id="${eventId}"]`);
|
||||||
`.event-card[data-event-id="${eventId}"]`,
|
|
||||||
);
|
|
||||||
if (card) {
|
if (card) {
|
||||||
card.dataset.done = "true";
|
card.dataset.done = "true";
|
||||||
card.classList.add("event-done");
|
card.classList.add("event-done");
|
||||||
const wrap = card.querySelector(".event-card-img-wrap");
|
const wrap = card.querySelector(".event-card-img-wrap");
|
||||||
if (wrap && !wrap.querySelector(".event-done-overlay")) {
|
if (wrap && !wrap.querySelector(".event-done-overlay")) {
|
||||||
wrap.insertAdjacentHTML(
|
wrap.insertAdjacentHTML("beforeend", `<div class="event-done-overlay">✓</div>`);
|
||||||
"beforeend",
|
|
||||||
`<div class="event-done-overlay">✓</div>`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (!card.querySelector(".event-done-label")) {
|
if (!card.querySelector(".event-done-label")) {
|
||||||
card.insertAdjacentHTML(
|
card.insertAdjacentHTML("beforeend", `<span class="event-done-label">Bereits erledigt</span>`);
|
||||||
"beforeend",
|
|
||||||
`<span class="event-done-label">Bereits erledigt</span>`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -193,40 +202,45 @@ export async function loadEvents() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body
|
body.querySelector("#edp-close-btn").addEventListener("click", () => overlay.classList.remove("active"));
|
||||||
.querySelector("#edp-close-btn")
|
overlay.addEventListener("click", e => { if (e.target === overlay) overlay.classList.remove("active"); });
|
||||||
.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", () => {
|
body.querySelector("#booster-back-btn").addEventListener("click", () => {
|
||||||
// Gesperrt nur wenn Slot gerade läuft
|
|
||||||
if (isSpinning) return;
|
if (isSpinning) return;
|
||||||
// Erlaubt wenn: Booster-Daily bereits erledigt ODER alle Karten enthüllt
|
|
||||||
const boosterCard = body.querySelector('.event-card[data-type="booster"]');
|
const boosterCard = body.querySelector('.event-card[data-type="booster"]');
|
||||||
const boosterDone = boosterCard?.dataset.done === "true";
|
const boosterDone = boosterCard?.dataset.done === "true";
|
||||||
if (!allRevealed && !boosterDone) return;
|
if (!allRevealed && !boosterDone) return;
|
||||||
eventsGrid.style.display = "";
|
eventsGrid.style.display = "";
|
||||||
boosterUi.style.display = "none";
|
boosterUi.style.display = "none";
|
||||||
clearAllIntervals();
|
clearAllIntervals();
|
||||||
isSpinning = false;
|
isSpinning = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
body.querySelector("#wood-back-btn").addEventListener("click", () => {
|
||||||
|
if (isWoodSpinning) return;
|
||||||
|
const woodCard = body.querySelector('.event-card[data-type="wood"]');
|
||||||
|
const woodDone = woodCard?.dataset.done === "true";
|
||||||
|
if (!woodRevealed && !woodDone) return;
|
||||||
|
eventsGrid.style.display = "";
|
||||||
|
woodUi.style.display = "none";
|
||||||
|
clearWoodIntervals();
|
||||||
|
isWoodSpinning = false;
|
||||||
|
});
|
||||||
|
|
||||||
// KEIN document.addEventListener("keydown") hier –
|
// KEIN document.addEventListener("keydown") hier –
|
||||||
// ESC wird zentral in quickmenu.js behandelt (verhindert Listener-Stapelung)
|
// ESC wird zentral in quickmenu.js behandelt (verhindert Listener-Stapelung)
|
||||||
|
|
||||||
/* ── Booster Zustand ── */
|
/* ── Booster Zustand ── */
|
||||||
let allCards = [];
|
let allCards = [];
|
||||||
let isSpinning = false;
|
let isSpinning = false;
|
||||||
let allRevealed = false; // true sobald alle 5 Karten aufgedeckt + gespeichert
|
let allRevealed = false; // true sobald alle 5 Karten aufgedeckt + gespeichert
|
||||||
let spinIntervals = {}; // { index: intervalId }
|
let spinIntervals = {}; // { index: intervalId }
|
||||||
let slotLocked = {}; // { index: true } → verhindert Überschreiben nach reveal
|
let slotLocked = {}; // { index: true } → verhindert Überschreiben nach reveal
|
||||||
|
|
||||||
function clearAllIntervals() {
|
function clearAllIntervals() {
|
||||||
Object.values(spinIntervals).forEach((id) => clearInterval(id));
|
Object.values(spinIntervals).forEach(id => clearInterval(id));
|
||||||
spinIntervals = {};
|
spinIntervals = {};
|
||||||
slotLocked = {};
|
slotLocked = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function preloadCards() {
|
async function preloadCards() {
|
||||||
@ -242,23 +256,19 @@ export async function loadEvents() {
|
|||||||
|
|
||||||
function resetBooster() {
|
function resetBooster() {
|
||||||
clearAllIntervals();
|
clearAllIntervals();
|
||||||
isSpinning = false;
|
isSpinning = false;
|
||||||
allRevealed = false;
|
allRevealed = false;
|
||||||
|
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
const inner = body.querySelector(
|
const inner = body.querySelector(`#booster-slot-${i} .booster-slot-inner`);
|
||||||
`#booster-slot-${i} .booster-slot-inner`,
|
|
||||||
);
|
|
||||||
inner.innerHTML = `<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">`;
|
inner.innerHTML = `<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">`;
|
||||||
body
|
body.querySelector(`#booster-slot-${i}`).classList.remove("revealed", "spinning");
|
||||||
.querySelector(`#booster-slot-${i}`)
|
|
||||||
.classList.remove("revealed", "spinning");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const stapel = body.querySelector("#booster-stapel");
|
const stapel = body.querySelector("#booster-stapel");
|
||||||
stapel.classList.remove("used");
|
stapel.classList.remove("used");
|
||||||
stapel.style.opacity = "1";
|
stapel.style.opacity = "1";
|
||||||
stapel.style.cursor = "pointer";
|
stapel.style.cursor = "pointer";
|
||||||
body.querySelector("#booster-hint").textContent = "Klicken zum Öffnen";
|
body.querySelector("#booster-hint").textContent = "Klicken zum Öffnen";
|
||||||
preloadCards();
|
preloadCards();
|
||||||
}
|
}
|
||||||
@ -266,7 +276,7 @@ export async function loadEvents() {
|
|||||||
/* ── Slot drehen – 350ms, damit man die Karten erkennt ── */
|
/* ── Slot drehen – 350ms, damit man die Karten erkennt ── */
|
||||||
function startSpinSlot(index) {
|
function startSpinSlot(index) {
|
||||||
slotLocked[index] = false;
|
slotLocked[index] = false;
|
||||||
const slot = body.querySelector(`#booster-slot-${index}`);
|
const slot = body.querySelector(`#booster-slot-${index}`);
|
||||||
const inner = slot.querySelector(".booster-slot-inner");
|
const inner = slot.querySelector(".booster-slot-inner");
|
||||||
slot.classList.add("spinning");
|
slot.classList.add("spinning");
|
||||||
|
|
||||||
@ -281,13 +291,13 @@ export async function loadEvents() {
|
|||||||
|
|
||||||
/* ── Slot enthüllen – Sperre setzen BEVOR clearInterval ── */
|
/* ── Slot enthüllen – Sperre setzen BEVOR clearInterval ── */
|
||||||
function revealSlot(index, card) {
|
function revealSlot(index, card) {
|
||||||
slotLocked[index] = true; // zuerst sperren
|
slotLocked[index] = true; // zuerst sperren
|
||||||
clearInterval(spinIntervals[index]); // dann stoppen
|
clearInterval(spinIntervals[index]); // dann stoppen
|
||||||
delete spinIntervals[index];
|
delete spinIntervals[index];
|
||||||
|
|
||||||
console.log(`[Booster] Slot ${index} enthüllt:`, card);
|
console.log(`[Booster] Slot ${index} enthüllt:`, card);
|
||||||
|
|
||||||
const slot = body.querySelector(`#booster-slot-${index}`);
|
const slot = body.querySelector(`#booster-slot-${index}`);
|
||||||
const inner = slot.querySelector(".booster-slot-inner");
|
const inner = slot.querySelector(".booster-slot-inner");
|
||||||
slot.classList.remove("spinning");
|
slot.classList.remove("spinning");
|
||||||
slot.classList.add("revealed");
|
slot.classList.add("revealed");
|
||||||
@ -312,17 +322,17 @@ export async function loadEvents() {
|
|||||||
const stapel = body.querySelector("#booster-stapel");
|
const stapel = body.querySelector("#booster-stapel");
|
||||||
stapel.classList.add("used");
|
stapel.classList.add("used");
|
||||||
stapel.style.opacity = "0.35";
|
stapel.style.opacity = "0.35";
|
||||||
stapel.style.cursor = "default";
|
stapel.style.cursor = "default";
|
||||||
body.querySelector("#booster-hint").textContent = "Wird gezogen...";
|
body.querySelector("#booster-hint").textContent = "Wird gezogen...";
|
||||||
|
|
||||||
// Zurück-Button während der Animation sperren
|
// Zurück-Button während der Animation sperren
|
||||||
const backBtn = body.querySelector("#booster-back-btn");
|
const backBtn = body.querySelector("#booster-back-btn");
|
||||||
backBtn.style.opacity = "0.35";
|
backBtn.style.opacity = "0.35";
|
||||||
backBtn.style.cursor = "not-allowed";
|
backBtn.style.cursor = "not-allowed";
|
||||||
|
|
||||||
let drawnCards = [];
|
let drawnCards = [];
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/api/booster/open", { method: "POST" });
|
const res = await fetch("/api/booster/open", { method: "POST" });
|
||||||
const text = await res.text();
|
const text = await res.text();
|
||||||
console.log("[Booster] API Antwort raw:", text);
|
console.log("[Booster] API Antwort raw:", text);
|
||||||
const data = JSON.parse(text);
|
const data = JSON.parse(text);
|
||||||
@ -341,38 +351,170 @@ export async function loadEvents() {
|
|||||||
setTimeout(() => revealSlot(i, drawnCards[i]), (i + 1) * 5000);
|
setTimeout(() => revealSlot(i, drawnCards[i]), (i + 1) * 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(
|
setTimeout(async () => {
|
||||||
async () => {
|
body.querySelector("#booster-hint").textContent = "Karten werden gespeichert...";
|
||||||
body.querySelector("#booster-hint").textContent =
|
isSpinning = false;
|
||||||
"Karten werden gespeichert...";
|
|
||||||
isSpinning = false;
|
|
||||||
|
|
||||||
// Karten in user_cards speichern
|
// Karten in user_cards speichern
|
||||||
try {
|
try {
|
||||||
const cardIds = drawnCards.map((c) => c.id);
|
const cardIds = drawnCards.map(c => c.id);
|
||||||
const saveRes = await fetch("/api/booster/save", {
|
const saveRes = await fetch("/api/booster/save", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ cardIds }),
|
body: JSON.stringify({ cardIds }),
|
||||||
});
|
});
|
||||||
if (!saveRes.ok) throw new Error(saveRes.status);
|
if (!saveRes.ok) throw new Error(saveRes.status);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Karten speichern fehlgeschlagen", e);
|
console.error("Karten speichern fehlgeschlagen", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Booster-Daily als erledigt markieren (event_id = 1)
|
// Booster-Daily als erledigt markieren (event_id = 1)
|
||||||
await markDailyComplete(1);
|
await markDailyComplete(1);
|
||||||
|
|
||||||
allRevealed = true;
|
allRevealed = true;
|
||||||
body.querySelector("#booster-hint").textContent =
|
body.querySelector("#booster-hint").textContent = "Alle Karten erhalten! ✓";
|
||||||
"Alle Karten erhalten! ✓";
|
const backBtn = body.querySelector("#booster-back-btn");
|
||||||
const backBtn = body.querySelector("#booster-back-btn");
|
backBtn.style.opacity = "1";
|
||||||
backBtn.style.opacity = "1";
|
backBtn.style.cursor = "pointer";
|
||||||
backBtn.style.cursor = "pointer";
|
}, 5 * 5000 + 500);
|
||||||
},
|
|
||||||
5 * 5000 + 500,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
preloadCards();
|
preloadCards();
|
||||||
|
|
||||||
|
/* ================================
|
||||||
|
Holz-Spenden Zustand
|
||||||
|
================================ */
|
||||||
|
let isWoodSpinning = false;
|
||||||
|
let woodRevealed = false;
|
||||||
|
let woodIntervals = {};
|
||||||
|
let woodLocked = {};
|
||||||
|
let rarity3Cards = [];
|
||||||
|
|
||||||
|
async function preloadRarity3() {
|
||||||
|
if (rarity3Cards.length) return;
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/booster/cards");
|
||||||
|
if (!res.ok) throw new Error(res.status);
|
||||||
|
const all = await res.json();
|
||||||
|
rarity3Cards = all.filter(c => parseInt(c.rarity) === 3);
|
||||||
|
// Fallback: wenn keine rarity-3 vorhanden alle nehmen
|
||||||
|
if (!rarity3Cards.length) rarity3Cards = all;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Rarity-3 Karten laden fehlgeschlagen", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearWoodIntervals() {
|
||||||
|
Object.values(woodIntervals).forEach(id => clearInterval(id));
|
||||||
|
woodIntervals = {};
|
||||||
|
woodLocked = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetWood() {
|
||||||
|
clearWoodIntervals();
|
||||||
|
isWoodSpinning = false;
|
||||||
|
woodRevealed = false;
|
||||||
|
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
const inner = body.querySelector(`#wood-slot-${i} .booster-slot-inner`);
|
||||||
|
inner.innerHTML = `<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">`;
|
||||||
|
body.querySelector(`#wood-slot-${i}`).classList.remove("revealed", "spinning");
|
||||||
|
}
|
||||||
|
|
||||||
|
const btn = body.querySelector("#wood-btn");
|
||||||
|
btn.classList.remove("used");
|
||||||
|
btn.style.opacity = "1";
|
||||||
|
btn.style.cursor = "pointer";
|
||||||
|
body.querySelector("#wood-hint").textContent = "100 Holz spenden";
|
||||||
|
preloadRarity3();
|
||||||
|
}
|
||||||
|
|
||||||
|
function startWoodSlot(index) {
|
||||||
|
woodLocked[index] = false;
|
||||||
|
const slot = body.querySelector(`#wood-slot-${index}`);
|
||||||
|
const inner = slot.querySelector(".booster-slot-inner");
|
||||||
|
slot.classList.add("spinning");
|
||||||
|
|
||||||
|
const iv = setInterval(() => {
|
||||||
|
if (!rarity3Cards.length || woodLocked[index]) return;
|
||||||
|
const rnd = rarity3Cards[Math.floor(Math.random() * rarity3Cards.length)];
|
||||||
|
inner.innerHTML = cardHTML(rnd, true);
|
||||||
|
}, 150);
|
||||||
|
|
||||||
|
woodIntervals[index] = iv;
|
||||||
|
}
|
||||||
|
|
||||||
|
function revealWoodSlot(index, card) {
|
||||||
|
woodLocked[index] = true;
|
||||||
|
clearInterval(woodIntervals[index]);
|
||||||
|
delete woodIntervals[index];
|
||||||
|
|
||||||
|
const slot = body.querySelector(`#wood-slot-${index}`);
|
||||||
|
const inner = slot.querySelector(".booster-slot-inner");
|
||||||
|
slot.classList.remove("spinning");
|
||||||
|
slot.classList.add("revealed");
|
||||||
|
inner.innerHTML = cardHTML(card, true);
|
||||||
|
setTimeout(() => {
|
||||||
|
if (slot.classList.contains("revealed")) inner.innerHTML = cardHTML(card, true);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.querySelector("#wood-btn").addEventListener("click", async () => {
|
||||||
|
if (isWoodSpinning) return;
|
||||||
|
if (!rarity3Cards.length) await preloadRarity3();
|
||||||
|
if (!rarity3Cards.length) return;
|
||||||
|
|
||||||
|
isWoodSpinning = true;
|
||||||
|
|
||||||
|
const btn = body.querySelector("#wood-btn");
|
||||||
|
btn.classList.add("used");
|
||||||
|
btn.style.opacity = "0.35";
|
||||||
|
btn.style.cursor = "default";
|
||||||
|
body.querySelector("#wood-hint").textContent = "Wird verarbeitet...";
|
||||||
|
|
||||||
|
const backBtn = body.querySelector("#wood-back-btn");
|
||||||
|
backBtn.style.opacity = "0.35";
|
||||||
|
backBtn.style.cursor = "not-allowed";
|
||||||
|
|
||||||
|
// API aufrufen – 100 Holz abziehen + Karte ziehen
|
||||||
|
let drawnCard = null;
|
||||||
|
try {
|
||||||
|
const res = await fetch("/api/booster/wood-donate", { method: "POST" });
|
||||||
|
const data = await res.json();
|
||||||
|
if (!res.ok) {
|
||||||
|
body.querySelector("#wood-hint").textContent = data.error || "Fehler";
|
||||||
|
isWoodSpinning = false;
|
||||||
|
btn.classList.remove("used");
|
||||||
|
btn.style.opacity = "1";
|
||||||
|
btn.style.cursor = "pointer";
|
||||||
|
backBtn.style.opacity = "1";
|
||||||
|
backBtn.style.cursor = "pointer";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
drawnCard = data.card;
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Holz-Spenden fehlgeschlagen", e);
|
||||||
|
resetWood();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alle 5 Slots starten
|
||||||
|
for (let i = 0; i < 5; i++) startWoodSlot(i);
|
||||||
|
|
||||||
|
// Nach 5 Sekunden alle gleichzeitig enthüllen (dieselbe Karte)
|
||||||
|
setTimeout(() => {
|
||||||
|
for (let i = 0; i < 5; i++) revealWoodSlot(i, drawnCard);
|
||||||
|
|
||||||
|
body.querySelector("#wood-hint").textContent = "Karte erhalten! ✓";
|
||||||
|
isWoodSpinning = false;
|
||||||
|
woodRevealed = true;
|
||||||
|
|
||||||
|
markDailyComplete(4);
|
||||||
|
|
||||||
|
backBtn.style.opacity = "1";
|
||||||
|
backBtn.style.cursor = "pointer";
|
||||||
|
}, 5000);
|
||||||
|
});
|
||||||
|
|
||||||
|
preloadRarity3();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -143,4 +143,49 @@ router.post("/booster/save", async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* ================================
|
||||||
|
POST /api/booster/wood-donate
|
||||||
|
100 Holz bezahlen → 1 zufällige Rarity-3 Karte
|
||||||
|
================================ */
|
||||||
|
router.post("/booster/wood-donate", async (req, res) => {
|
||||||
|
if (!req.session?.user) return res.status(401).json({ error: "Nicht eingeloggt" });
|
||||||
|
|
||||||
|
const userId = req.session.user.id;
|
||||||
|
try {
|
||||||
|
// Holz prüfen
|
||||||
|
const [[currency]] = await db.query(
|
||||||
|
"SELECT wood FROM account_currency WHERE account_id = ?", [userId]
|
||||||
|
);
|
||||||
|
if (!currency || currency.wood < 100) {
|
||||||
|
return res.status(400).json({ error: "Nicht genug Holz (100 benötigt)" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rarity-3 Karten laden
|
||||||
|
const [pool] = await db.query(
|
||||||
|
"SELECT id, name, image, icon, max_level, rarity, attack, defends, cooldown FROM cards WHERE rarity = 3"
|
||||||
|
);
|
||||||
|
if (!pool.length) return res.status(400).json({ error: "Keine Rarity-3 Karten verfügbar" });
|
||||||
|
|
||||||
|
// 100 Holz abziehen
|
||||||
|
await db.query(
|
||||||
|
"UPDATE account_currency SET wood = wood - 100 WHERE account_id = ?", [userId]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 1 zufällige Rarity-3 Karte ziehen
|
||||||
|
const card = pool[Math.floor(Math.random() * pool.length)];
|
||||||
|
|
||||||
|
// Direkt in user_cards speichern
|
||||||
|
await db.query(
|
||||||
|
`INSERT INTO user_cards (user_id, card_id, amount) VALUES (?, ?, 1)
|
||||||
|
ON DUPLICATE KEY UPDATE amount = amount + 1`,
|
||||||
|
[userId, card.id]
|
||||||
|
);
|
||||||
|
|
||||||
|
res.json({ card });
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
res.status(500).json({ error: "DB Fehler" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user