diff --git a/public/css/events.css b/public/css/events.css index c2c5aee..9fd464a 100644 --- a/public/css/events.css +++ b/public/css/events.css @@ -31,7 +31,7 @@ justify-content: center; padding: 6px; 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 { @@ -413,19 +413,23 @@ } /* Wood-UI: Bild + Slot auf gleiche Größe wie Booster-Slots zwingen */ -#wood-ui .booster-stage { +#wood-ui .booster-stage, +#gold-ui .booster-stage { justify-content: center; align-items: center; gap: 20px; } #wood-ui .booster-left, -#wood-ui .booster-slot { +#wood-ui .booster-slot, +#gold-ui .booster-left, +#gold-ui .booster-slot { flex: 0 0 calc((100% - 50px) / 6); max-width: calc((100% - 50px) / 6); } -.wood-stamp { +.wood-stamp, +.gold-stamp { position: absolute; top: 50%; left: 50%; @@ -436,7 +440,7 @@ color: #e85010; background: rgba(0, 0, 0, 0.5); font-family: "Cinzel", serif; - font-size: 14px; + font-size: 8px; font-weight: bold; letter-spacing: 1px; white-space: nowrap; @@ -445,6 +449,13 @@ text-shadow: 0 0 6px rgba(200, 64, 10, 0.6); } +.gold-stamp { + border-color: #b8960a; + color: #f0c020; + box-shadow: 0 0 6px rgba(200, 160, 10, 0.5); + text-shadow: 0 0 6px rgba(200, 160, 10, 0.6); +} + .event-done-overlay { position: absolute; inset: 0; diff --git a/public/js/quickmenu.js b/public/js/quickmenu.js index 1a30304..9ce799d 100644 --- a/public/js/quickmenu.js +++ b/public/js/quickmenu.js @@ -117,6 +117,9 @@ function isBoosterSpinning() { const woodUi = document.getElementById("wood-ui"); if (woodUi && woodUi.style.display !== "none" && woodUi.querySelector(".booster-slot.spinning")) return true; + const goldUi = document.getElementById("gold-ui"); + if (goldUi && goldUi.style.display !== "none" && goldUi.querySelector(".booster-slot.spinning")) return true; + return false; } diff --git a/public/js/quickmenu/events.js b/public/js/quickmenu/events.js index 8e6edf9..b4d9eb1 100644 --- a/public/js/quickmenu/events.js +++ b/public/js/quickmenu/events.js @@ -55,19 +55,24 @@ export async function loadEvents() { { 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/holz.png", label: "Holz Spenden", type: "wood", woodCost: 100 }, - { id: 5, img: "/images/items/runenhaufen.png", label: "Textzeile 5" }, + { id: 5, img: "/images/items/gold.png", label: "Gold Spenden", type: "gold", goldCost: 100 }, ]; // Täglichen Status + Holz-Bestand parallel laden let completedToday = []; let playerWood = 0; + let playerGold = 0; try { const [statusRes, hudRes] = await Promise.all([ fetch("/api/daily/status"), fetch("/api/hud"), ]); if (statusRes.ok) completedToday = (await statusRes.json()).completed || []; - if (hudRes.ok) playerWood = (await hudRes.json()).wood || 0; + if (hudRes.ok) { + const hud = await hudRes.json(); + playerWood = hud.wood || 0; + playerGold = hud.gold || 0; + } } catch (e) { console.error("Laden fehlgeschlagen", e); } @@ -76,14 +81,18 @@ export async function loadEvents() {
`;
+ body.querySelector(`#gold-slot-0`).classList.remove("revealed", "spinning");
+
+ const btn = body.querySelector("#gold-btn");
+ const stamp = body.querySelector("#gold-stamp");
+ btn.classList.remove("used");
+ btn.style.opacity = "1";
+ btn.style.cursor = "pointer";
+ if (stamp) stamp.style.display = "";
+ body.querySelector("#gold-hint").textContent = "100 Gold spenden";
+ preloadRarity3();
+ }
+
+ function startGoldSlot(index) {
+ goldLocked[index] = false;
+ const slot = body.querySelector(`#gold-slot-${index}`);
+ const inner = slot.querySelector(".booster-slot-inner");
+ slot.classList.add("spinning");
+
+ const iv = setInterval(() => {
+ if (!rarity3Cards.length || goldLocked[index]) return;
+ const rnd = rarity3Cards[Math.floor(Math.random() * rarity3Cards.length)];
+ inner.innerHTML = cardHTML(rnd, true);
+ }, 150);
+
+ goldIntervals[index] = iv;
+ }
+
+ function revealGoldSlot(index, card) {
+ goldLocked[index] = true;
+ clearInterval(goldIntervals[index]);
+ delete goldIntervals[index];
+
+ const slot = body.querySelector(`#gold-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("#gold-btn").addEventListener("click", async () => {
+ if (isGoldSpinning) return;
+ if (!rarity3Cards.length) await preloadRarity3();
+ if (!rarity3Cards.length) return;
+
+ isGoldSpinning = true;
+
+ const btn = body.querySelector("#gold-btn");
+ const stamp = body.querySelector("#gold-stamp");
+ btn.classList.add("used");
+ btn.style.opacity = "0.35";
+ btn.style.cursor = "default";
+ if (stamp) stamp.style.display = "none";
+ body.querySelector("#gold-hint").textContent = "Wird verarbeitet...";
+
+ const backBtn = body.querySelector("#gold-back-btn");
+ backBtn.style.opacity = "0.35";
+ backBtn.style.cursor = "not-allowed";
+
+ let drawnCard = null;
+ try {
+ const res = await fetch("/api/booster/gold-donate", { method: "POST" });
+ const data = await res.json();
+ if (!res.ok) {
+ body.querySelector("#gold-hint").textContent = data.error || "Fehler";
+ isGoldSpinning = false;
+ btn.classList.remove("used");
+ btn.style.opacity = "1";
+ btn.style.cursor = "pointer";
+ if (stamp) stamp.style.display = "";
+ backBtn.style.opacity = "1";
+ backBtn.style.cursor = "pointer";
+ return;
+ }
+ drawnCard = data.card;
+ } catch (e) {
+ console.error("Gold-Spenden fehlgeschlagen", e);
+ resetGold();
+ return;
+ }
+
+ startGoldSlot(0);
+
+ setTimeout(() => {
+ revealGoldSlot(0, drawnCard);
+ body.querySelector("#gold-hint").textContent = "Karte erhalten! ✓";
+ isGoldSpinning = false;
+ goldRevealed = true;
+ markDailyComplete(5);
+ backBtn.style.opacity = "1";
+ backBtn.style.cursor = "pointer";
+ }, 5000);
+ });
}
diff --git a/routes/booster.js b/routes/booster.js
index bad06a0..469c415 100644
--- a/routes/booster.js
+++ b/routes/booster.js
@@ -188,4 +188,44 @@ router.post("/booster/wood-donate", async (req, res) => {
}
});
+/* ================================
+ POST /api/booster/gold-donate
+ 100 Gold bezahlen → 1 zufällige Rarity-3 Karte
+================================ */
+router.post("/booster/gold-donate", async (req, res) => {
+ if (!req.session?.user) return res.status(401).json({ error: "Nicht eingeloggt" });
+
+ const userId = req.session.user.id;
+ try {
+ const [[currency]] = await db.query(
+ "SELECT gold FROM account_currency WHERE account_id = ?", [userId]
+ );
+ if (!currency || currency.gold < 100) {
+ return res.status(400).json({ error: "Nicht genug Gold (100 benötigt)" });
+ }
+
+ 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" });
+
+ await db.query(
+ "UPDATE account_currency SET gold = gold - 100 WHERE account_id = ?", [userId]
+ );
+
+ const card = pool[Math.floor(Math.random() * pool.length)];
+
+ 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;