tszk
This commit is contained in:
parent
0d68978d4e
commit
c988486d63
@ -1,7 +1,6 @@
|
||||
/* ================================
|
||||
Events Grid
|
||||
================================ */
|
||||
|
||||
.events-grid {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
@ -50,9 +49,8 @@
|
||||
}
|
||||
|
||||
/* ================================
|
||||
Detail-Popup (Overlay)
|
||||
Detail-Popup
|
||||
================================ */
|
||||
|
||||
#event-detail-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
@ -88,50 +86,34 @@
|
||||
|
||||
#event-detail-popup .edp-close {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 8px;
|
||||
background: none;
|
||||
border: none;
|
||||
color: #888;
|
||||
font-size: 11px;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
top: 6px; right: 8px;
|
||||
background: none; border: none;
|
||||
color: #888; font-size: 11px; cursor: pointer; line-height: 1;
|
||||
transition: color 0.1s;
|
||||
}
|
||||
|
||||
#event-detail-popup .edp-close:hover { color: #fff; }
|
||||
|
||||
#event-detail-popup .edp-img {
|
||||
display: block;
|
||||
margin: 0 auto 8px;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
object-fit: contain;
|
||||
image-rendering: pixelated;
|
||||
display: block; margin: 0 auto 8px;
|
||||
width: 44px; height: 44px;
|
||||
object-fit: contain; image-rendering: pixelated;
|
||||
}
|
||||
|
||||
#event-detail-popup .edp-title {
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
color: #f5c842;
|
||||
margin-bottom: 6px;
|
||||
text-align: center; font-size: 11px; font-weight: bold;
|
||||
color: #f5c842; margin-bottom: 6px;
|
||||
}
|
||||
|
||||
#event-detail-popup .edp-body {
|
||||
font-size: 10px;
|
||||
color: #cccccc;
|
||||
line-height: 1.6;
|
||||
text-align: center;
|
||||
font-size: 10px; color: #cccccc; line-height: 1.6; text-align: center;
|
||||
}
|
||||
|
||||
/* ================================
|
||||
Booster UI
|
||||
Booster UI – Container
|
||||
================================ */
|
||||
|
||||
.booster-ui {
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
gap: 14px;
|
||||
padding: 10px 0;
|
||||
width: 100%;
|
||||
}
|
||||
@ -148,12 +130,12 @@
|
||||
font-family: "Cinzel", serif;
|
||||
transition: background 0.15s, color 0.15s;
|
||||
}
|
||||
|
||||
.booster-back-btn:hover {
|
||||
background: rgba(200, 150, 12, 0.15);
|
||||
color: #f0d060;
|
||||
}
|
||||
|
||||
/* Alle 6 Elemente (Stapel + 5 Slots) in einem einzigen Flex-Container */
|
||||
.booster-stage {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
@ -161,6 +143,7 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ── Stapel ── */
|
||||
.booster-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -206,11 +189,11 @@
|
||||
display: contents;
|
||||
}
|
||||
|
||||
/* ── Einzelner Slot ── */
|
||||
.booster-slot {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
@ -228,22 +211,12 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Dreh-Animation */
|
||||
/* Drehen */
|
||||
.booster-slot.spinning .booster-slot-inner {
|
||||
border-color: rgba(200, 150, 12, 0.5);
|
||||
box-shadow: 0 0 12px rgba(200, 150, 12, 0.25);
|
||||
}
|
||||
|
||||
.booster-slot.spinning .booster-slot-img {
|
||||
animation: slotFlicker 0.08s steps(1) infinite;
|
||||
}
|
||||
|
||||
@keyframes slotFlicker {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.75; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
/* Enthüllt */
|
||||
.booster-slot.revealed .booster-slot-inner {
|
||||
border-color: #c8960c;
|
||||
@ -267,12 +240,97 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
.booster-slot-name {
|
||||
font-size: 10px;
|
||||
color: #c8960c;
|
||||
text-align: center;
|
||||
/* ================================
|
||||
Karten-Stats innerhalb der Slots
|
||||
(identisch mit carddeck.js)
|
||||
================================ */
|
||||
|
||||
/* Angriff – rechts mittig */
|
||||
.bs-stat-atk {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 40%;
|
||||
transform: translateY(-50%);
|
||||
background: rgba(180, 40, 20, 0.88);
|
||||
border: 1px solid #ff6040;
|
||||
border-radius: 45px;
|
||||
color: #fff;
|
||||
font-family: "Cinzel", serif;
|
||||
letter-spacing: 0.5px;
|
||||
min-height: 14px;
|
||||
word-break: break-word;
|
||||
font-size: 9px;
|
||||
font-weight: bold;
|
||||
padding: 1px 4px;
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Verteidigung – links mittig */
|
||||
.bs-stat-def {
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
top: 40%;
|
||||
transform: translateY(-50%);
|
||||
background: rgba(20, 80, 180, 0.88);
|
||||
border: 1px solid #4090ff;
|
||||
border-radius: 45px;
|
||||
color: #fff;
|
||||
font-family: "Cinzel", serif;
|
||||
font-size: 9px;
|
||||
font-weight: bold;
|
||||
padding: 1px 4px;
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Cooldown – unten rechts, Kreis */
|
||||
.bs-stat-cd {
|
||||
position: absolute;
|
||||
bottom: 6px;
|
||||
right: 5px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-radius: 50%;
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
border: 1px solid #f0d060;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: "Cinzel", serif;
|
||||
font-size: 8px;
|
||||
font-weight: bold;
|
||||
color: #f0d9a6;
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Kristalle – mittig unten */
|
||||
.bs-rarity {
|
||||
position: absolute;
|
||||
top: 72%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 1px;
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Kartenname – ganz unten */
|
||||
.bs-card-name {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 2px 3px;
|
||||
background: linear-gradient(transparent, rgba(0,0,0,0.82));
|
||||
font-family: "Cinzel", serif;
|
||||
font-size: 7px;
|
||||
color: #f0d9a6;
|
||||
text-align: center;
|
||||
line-height: 1.3;
|
||||
border-radius: 0 0 4px 4px;
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@ -1,10 +1,45 @@
|
||||
/* ================================
|
||||
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;
|
||||
|
||||
/* ================================
|
||||
CSS einmalig laden
|
||||
================================ */
|
||||
if (!document.querySelector('link[href="/css/events.css"]')) {
|
||||
const link = document.createElement("link");
|
||||
link.rel = "stylesheet";
|
||||
@ -12,9 +47,6 @@ export async function loadEvents() {
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
/* ================================
|
||||
Event-Daten
|
||||
================================ */
|
||||
const events = [
|
||||
{ id: 1, img: "/images/items/runenhaufen.png", label: "Booster Öffnen", type: "booster" },
|
||||
{ id: 2, img: "/images/items/runenhaufen.png", label: "Textzeile 2" },
|
||||
@ -23,9 +55,6 @@ export async function loadEvents() {
|
||||
{ id: 5, img: "/images/items/runenhaufen.png", label: "Textzeile 5" },
|
||||
];
|
||||
|
||||
/* ================================
|
||||
Haupt-HTML
|
||||
================================ */
|
||||
body.innerHTML = `
|
||||
<div class="events-grid" id="events-grid">
|
||||
${events.map(ev => `
|
||||
@ -37,7 +66,7 @@ export async function loadEvents() {
|
||||
</div>`).join("")}
|
||||
</div>
|
||||
|
||||
<!-- Booster Öffnen UI -->
|
||||
<!-- 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">
|
||||
@ -51,7 +80,6 @@ export async function loadEvents() {
|
||||
<div class="booster-slot-inner">
|
||||
<img class="booster-slot-img" src="/images/items/rueckseite.png" alt="?" draggable="false">
|
||||
</div>
|
||||
<div class="booster-slot-name"></div>
|
||||
</div>`).join("")}
|
||||
</div>
|
||||
</div>
|
||||
@ -68,9 +96,6 @@ export async function loadEvents() {
|
||||
</div>
|
||||
`;
|
||||
|
||||
/* ================================
|
||||
Referenzen
|
||||
================================ */
|
||||
const overlay = body.querySelector("#event-detail-overlay");
|
||||
const edpImg = body.querySelector("#edp-img");
|
||||
const edpTitle = body.querySelector("#edp-title");
|
||||
@ -78,9 +103,7 @@ export async function loadEvents() {
|
||||
const boosterUi = body.querySelector("#booster-ui");
|
||||
const eventsGrid = body.querySelector("#events-grid");
|
||||
|
||||
/* ================================
|
||||
Event-Karten Klick
|
||||
================================ */
|
||||
/* ── Event-Karten ── */
|
||||
body.querySelectorAll(".event-card").forEach(card => {
|
||||
card.addEventListener("click", () => {
|
||||
if (card.dataset.type === "booster") {
|
||||
@ -100,15 +123,9 @@ export async function loadEvents() {
|
||||
});
|
||||
});
|
||||
|
||||
/* ================================
|
||||
Detail-Popup schließen
|
||||
================================ */
|
||||
body.querySelector("#edp-close-btn").addEventListener("click", () => overlay.classList.remove("active"));
|
||||
overlay.addEventListener("click", e => { if (e.target === overlay) overlay.classList.remove("active"); });
|
||||
|
||||
/* ================================
|
||||
Zurück-Button
|
||||
================================ */
|
||||
body.querySelector("#booster-back-btn").addEventListener("click", () => {
|
||||
eventsGrid.style.display = "";
|
||||
boosterUi.style.display = "none";
|
||||
@ -125,9 +142,7 @@ export async function loadEvents() {
|
||||
}
|
||||
});
|
||||
|
||||
/* ================================
|
||||
Booster Zustand
|
||||
================================ */
|
||||
/* ── Booster Zustand ── */
|
||||
let allCards = [];
|
||||
let isSpinning = false;
|
||||
let spinIntervals = [];
|
||||
@ -137,80 +152,61 @@ export async function loadEvents() {
|
||||
spinIntervals = [];
|
||||
}
|
||||
|
||||
/* ================================
|
||||
Karten vorladen
|
||||
================================ */
|
||||
async function preloadCards() {
|
||||
if (allCards.length) return;
|
||||
try {
|
||||
const res = await fetch("/api/booster/cards");
|
||||
allCards = await res.json();
|
||||
if (!res.ok) throw new Error(res.status);
|
||||
allCards = await res.json();
|
||||
} catch (e) {
|
||||
console.error("Karten laden fehlgeschlagen", e);
|
||||
}
|
||||
}
|
||||
|
||||
/* ================================
|
||||
Booster zurücksetzen
|
||||
================================ */
|
||||
function resetBooster() {
|
||||
clearAllIntervals();
|
||||
isSpinning = false;
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const slot = body.querySelector(`#booster-slot-${i}`);
|
||||
slot.querySelector(".booster-slot-img").src = "/images/items/rueckseite.png";
|
||||
slot.querySelector(".booster-slot-name").textContent = "";
|
||||
slot.classList.remove("revealed", "spinning");
|
||||
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 lassen
|
||||
================================ */
|
||||
/* ── Slot drehen – 350ms, damit man die Karten erkennt ── */
|
||||
function startSpinSlot(index) {
|
||||
const slot = body.querySelector(`#booster-slot-${index}`);
|
||||
const imgEl = slot.querySelector(".booster-slot-img");
|
||||
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)];
|
||||
imgEl.src = rnd.image ? `/images/cards/${rnd.image}` : "/images/items/rueckseite.png";
|
||||
}, 80);
|
||||
inner.innerHTML = cardHTML(rnd, true);
|
||||
}, 350);
|
||||
|
||||
spinIntervals[index] = iv;
|
||||
}
|
||||
|
||||
/* ================================
|
||||
Slot enthüllen
|
||||
================================ */
|
||||
/* ── Slot enthüllen ── */
|
||||
function revealSlot(index, card) {
|
||||
clearInterval(spinIntervals[index]);
|
||||
|
||||
const slot = body.querySelector(`#booster-slot-${index}`);
|
||||
const imgEl = slot.querySelector(".booster-slot-img");
|
||||
const nameEl = slot.querySelector(".booster-slot-name");
|
||||
|
||||
const slot = body.querySelector(`#booster-slot-${index}`);
|
||||
const inner = slot.querySelector(".booster-slot-inner");
|
||||
slot.classList.remove("spinning");
|
||||
slot.classList.add("revealed");
|
||||
|
||||
imgEl.src = card?.image ? `/images/cards/${card.image}` : "/images/items/rueckseite.png";
|
||||
nameEl.textContent = card?.name || "???";
|
||||
inner.innerHTML = cardHTML(card, true);
|
||||
}
|
||||
|
||||
/* ================================
|
||||
Booster-Stapel Klick → Öffnen
|
||||
================================ */
|
||||
/* ── Stapel klicken ── */
|
||||
body.querySelector("#booster-stapel").addEventListener("click", async () => {
|
||||
if (isSpinning) return;
|
||||
if (!allCards.length) await preloadCards();
|
||||
@ -224,7 +220,6 @@ export async function loadEvents() {
|
||||
stapel.style.cursor = "default";
|
||||
body.querySelector("#booster-hint").textContent = "Wird gezogen...";
|
||||
|
||||
// 5 Karten vom Server ziehen
|
||||
let drawnCards = [];
|
||||
try {
|
||||
const res = await fetch("/api/booster/open", { method: "POST" });
|
||||
@ -236,21 +231,17 @@ export async function loadEvents() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Alle Slots gleichzeitig drehen
|
||||
for (let i = 0; i < 5; i++) startSpinSlot(i);
|
||||
|
||||
// Nacheinander alle 5 Sekunden eine Karte enthüllen
|
||||
for (let i = 0; i < 5; i++) {
|
||||
setTimeout(() => revealSlot(i, drawnCards[i]), (i + 1) * 5000);
|
||||
}
|
||||
|
||||
// Nach letzter Karte: Fertig-Meldung
|
||||
setTimeout(() => {
|
||||
body.querySelector("#booster-hint").textContent = "Alle Karten enthüllt!";
|
||||
isSpinning = false;
|
||||
}, 5 * 5000 + 500);
|
||||
});
|
||||
|
||||
// Karten sofort vorladen
|
||||
preloadCards();
|
||||
}
|
||||
|
||||
@ -1,11 +1,10 @@
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const db = require("../database/database");
|
||||
const router = express.Router();
|
||||
const db = require("../database/database");
|
||||
|
||||
/* ================================
|
||||
Gewichtete Zufallsauswahl
|
||||
================================ */
|
||||
|
||||
function weightedRandom(weights) {
|
||||
const total = weights.reduce((s, w) => s + w.weight, 0);
|
||||
let r = Math.random() * total;
|
||||
@ -19,7 +18,6 @@ function weightedRandom(weights) {
|
||||
/* ================================
|
||||
Gewichte je Spielerlevel
|
||||
================================ */
|
||||
|
||||
function getWeights(playerLevel) {
|
||||
if (playerLevel < 10) return [
|
||||
{ maxLevel: 1, weight: 85 },
|
||||
@ -43,14 +41,6 @@ function getWeights(playerLevel) {
|
||||
{ maxLevel: 4, weight: 7 },
|
||||
{ maxLevel: 5, weight: 4 },
|
||||
];
|
||||
if (playerLevel < 50) return [
|
||||
{ maxLevel: 1, weight: 47 },
|
||||
{ maxLevel: 2, weight: 25 },
|
||||
{ maxLevel: 3, weight: 15 },
|
||||
{ maxLevel: 4, weight: 8 },
|
||||
{ maxLevel: 5, weight: 4.5 },
|
||||
{ maxLevel: 6, weight: 0.5 },
|
||||
];
|
||||
return [
|
||||
{ maxLevel: 1, weight: 47 },
|
||||
{ maxLevel: 2, weight: 25 },
|
||||
@ -63,15 +53,13 @@ function getWeights(playerLevel) {
|
||||
|
||||
/* ================================
|
||||
GET /api/booster/cards
|
||||
Alle Karten für die Slot-Animation
|
||||
Alle Karten inkl. Stats für Slot-Animation
|
||||
================================ */
|
||||
|
||||
router.get("/booster/cards", async (req, res) => {
|
||||
if (!req.session?.user) return res.status(401).json({ error: "Nicht eingeloggt" });
|
||||
|
||||
try {
|
||||
const [cards] = await db.query(
|
||||
"SELECT id, name, image, max_level, rarity FROM cards ORDER BY id"
|
||||
"SELECT id, name, image, max_level, rarity, attack, defends, cooldown FROM cards ORDER BY id"
|
||||
);
|
||||
res.json(cards);
|
||||
} catch (err) {
|
||||
@ -82,55 +70,39 @@ router.get("/booster/cards", async (req, res) => {
|
||||
|
||||
/* ================================
|
||||
POST /api/booster/open
|
||||
Gibt 5 gewichtete Zufallskarten zurück
|
||||
5 gewichtete Zufallskarten inkl. Stats
|
||||
================================ */
|
||||
|
||||
router.post("/booster/open", async (req, res) => {
|
||||
if (!req.session?.user) return res.status(401).json({ error: "Nicht eingeloggt" });
|
||||
|
||||
const userId = req.session.user.id;
|
||||
|
||||
try {
|
||||
// Spielerlevel direkt aus accounts
|
||||
const [[account]] = await db.query(
|
||||
"SELECT level FROM accounts WHERE id = ?",
|
||||
[userId]
|
||||
"SELECT level FROM accounts WHERE id = ?", [userId]
|
||||
);
|
||||
const playerLevel = account?.level ?? 1;
|
||||
const weights = getWeights(playerLevel);
|
||||
const maxAllowed = Math.max(...weights.map(w => w.maxLevel));
|
||||
|
||||
// Alle erlaubten Karten laden
|
||||
const [allCards] = await db.query(
|
||||
"SELECT id, name, image, max_level, rarity FROM cards WHERE max_level <= ?",
|
||||
"SELECT id, name, image, max_level, rarity, attack, defends, cooldown FROM cards WHERE max_level <= ?",
|
||||
[maxAllowed]
|
||||
);
|
||||
|
||||
if (!allCards.length) {
|
||||
return res.status(400).json({ error: "Keine Karten verfügbar" });
|
||||
}
|
||||
if (!allCards.length) return res.status(400).json({ error: "Keine Karten verfügbar" });
|
||||
|
||||
// 5 Karten zufällig ziehen
|
||||
const result = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const targetLevel = weightedRandom(weights);
|
||||
|
||||
// Karten mit diesem max_level filtern
|
||||
let pool = allCards.filter(c => c.max_level === targetLevel);
|
||||
|
||||
// Fallback: nächstniedrigeres Level nehmen
|
||||
if (!pool.length) {
|
||||
for (let fallback = targetLevel - 1; fallback >= 1; fallback--) {
|
||||
pool = allCards.filter(c => c.max_level === fallback);
|
||||
for (let fb = targetLevel - 1; fb >= 1; fb--) {
|
||||
pool = allCards.filter(c => c.max_level === fb);
|
||||
if (pool.length) break;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: irgendeine erlaubte Karte
|
||||
if (!pool.length) pool = allCards;
|
||||
|
||||
const card = pool[Math.floor(Math.random() * pool.length)];
|
||||
result.push(card);
|
||||
result.push(pool[Math.floor(Math.random() * pool.length)]);
|
||||
}
|
||||
|
||||
res.json({ cards: result, playerLevel });
|
||||
|
||||
Loading…
Reference in New Issue
Block a user