This commit is contained in:
cay 2026-04-10 07:41:08 +01:00
parent 3f1467adff
commit a516399e84
2 changed files with 151 additions and 54 deletions

View File

@ -659,6 +659,44 @@ body {
border-color: rgba(255, 215, 80, 0.6);
}
/* Hand-Slot: Karte ist spielbereit (CD = 0) */
.hand-slot.hand-slot-ready {
border-color: rgba(80, 220, 80, 0.9) !important;
border-style: solid !important;
box-shadow:
0 0 calc(var(--s) * 18) rgba(60, 200, 60, 0.5),
0 calc(var(--s) * 4) calc(var(--s) * 12) rgba(0,0,0,0.4);
}
/* CD-Badge wenn Karte spielbereit */
.cs-cd.cs-cd-ready {
background: rgba(20, 140, 20, 0.9);
border-color: #60ff60;
color: #b0ffb0;
font-size: calc(var(--s) * 7);
}
/* "SPIELEN" Badge oben-mittig wenn CD = 0 */
.hand-slot-ready-badge {
position: absolute;
top: calc(var(--s) * 4);
left: 50%;
transform: translateX(-50%);
background: linear-gradient(135deg, rgba(20,120,20,0.92), rgba(10,80,10,0.92));
border: 1px solid #60d060;
border-radius: calc(var(--s) * 4);
color: #a0ffa0;
font-family: "Cinzel", serif;
font-size: calc(var(--s) * 7);
font-weight: bold;
letter-spacing: calc(var(--s) * 1);
padding: calc(var(--s) * 2) calc(var(--s) * 5);
pointer-events: none;
z-index: 6;
white-space: nowrap;
text-shadow: 0 1px 4px rgba(0,0,0,0.8);
}
/* Spielfeld-Sperre */
#board-lock-overlay {
position: absolute;

View File

@ -224,14 +224,13 @@
<span class="deck-count" id="deck-count">—</span>`;
hand.appendChild(deckSlot);
// ── Slots 24: aufgedeckte Handkarten ────────────────
// ── Slots 24: aufgedeckte Handkarten (leer bis API lädt) ───
const handCardIds = ["hand-card-1", "hand-card-2", "hand-card-3"];
handCardIds.forEach(id => {
const s = document.createElement("div");
s.className = "hand-slot hand-slot-card";
s.id = id;
s.innerHTML = `<img src="/images/cards/Silberklinge.png"
style="width:100%;height:100%;object-fit:cover;border-radius:7px;">`;
s.innerHTML = '<span class="hs-icon">🃏</span>';
hand.appendChild(s);
});
@ -243,73 +242,133 @@
hand.appendChild(s);
}
// ── Deck via API laden und Karten anzeigen ────────────
// ══════════════════════════════════════════════════════
// HAND & DECK SYSTEM
// ══════════════════════════════════════════════════════
let deckQueue = [];
// State pro Slot: { card, currentCd } oder null = leer
const handSlotState = {};
handCardIds.forEach(id => { handSlotState[id] = null; });
/* ── Slot rendern ──────────────────────────────────── */
function renderHandSlot(id) {
const slot = document.getElementById(id);
const state = handSlotState[id];
if (!slot) return;
if (!state) {
slot.innerHTML = '<span class="hs-icon">🃏</span>';
slot.classList.remove("hand-slot-ready");
return;
}
const { card, currentCd } = state;
const isReady = currentCd <= 0;
const atkVal = card.attack ?? null;
const defVal = card.defends ?? null;
const statsHtml = `
<div class="card-stat-overlay">
${atkVal != null ? `<span class="cs-atk">${atkVal}</span>` : ""}
${defVal != null ? `<span class="cs-def">${defVal}</span>` : ""}
${card.cooldown != null
? `<span class="cs-cd ${isReady ? "cs-cd-ready" : ""}">${isReady ? "✓" : currentCd}</span>`
: ""}
</div>`;
const readyBadge = isReady
? `<div class="hand-slot-ready-badge">SPIELEN</div>`
: "";
slot.innerHTML = card.image
? `<img src="/images/cards/${card.image}"
onerror="this.src='/images/items/rueckseite.png'"
title="${card.name}"
style="width:100%;height:100%;object-fit:cover;border-radius:7px;display:block;">
${statsHtml}${readyBadge}`
: `<div style="display:flex;flex-direction:column;align-items:center;
justify-content:center;height:100%;gap:4px;font-family:Cinzel,serif;">
<span style="font-size:18px;">⚔️</span>
<span style="font-size:9px;color:#f0d9a6;text-align:center;">${card.name}</span>
</div>${statsHtml}${readyBadge}`;
slot.classList.toggle("hand-slot-ready", isReady);
}
/* ── Karte in Hand-Slot legen ──────────────────────── */
function setHandSlot(id, card) {
handSlotState[id] = { card, currentCd: card.cooldown ?? 0 };
renderHandSlot(id);
}
/* ── Karte vom Deck ziehen ─────────────────────────── */
function drawNextCard() {
if (deckQueue.length === 0) return;
const freeSlot = handCardIds.find(id => handSlotState[id] === null);
if (!freeSlot) return; // alle Slots belegt → Karte bleibt im Deck
const card = deckQueue.shift();
setHandSlot(freeSlot, card);
const countEl = document.getElementById("deck-count");
if (countEl) countEl.textContent = deckQueue.length;
}
/* ── Cooldowns beim Zug-Ende reduzieren ────────────── */
function tickHandCooldowns() {
handCardIds.forEach(id => {
const state = handSlotState[id];
if (!state) return;
if (state.currentCd > 0) state.currentCd--;
renderHandSlot(id);
});
}
/* ── Deck laden ────────────────────────────────────── */
(async () => {
try {
// Deck-ID aus URL-Parameter (von arena.js mitgegeben)
const urlP = new URLSearchParams(window.location.search);
const deckId = urlP.get("deck") || sessionStorage.getItem("selectedDeckId");
if (!deckId) return;
const [deckRes, cardsRes] = await Promise.all([
fetch("/api/decks"),
fetch("/api/decks/" + deckId + "/cards")
]);
if (!deckRes.ok || !cardsRes.ok) return;
const cardsRes = await fetch("/api/decks/" + deckId + "/cards");
if (!cardsRes.ok) return;
const cards = await cardsRes.json();
const decks = await deckRes.json();
const deck = decks.find(d => d.id == deckId);
if (deck) {
const countEl = document.getElementById("deck-count");
if (countEl) countEl.textContent = deck.card_count;
// Karten nach amount auffalten
const expanded = [];
cards.forEach(card => {
for (let i = 0; i < (card.amount ?? 1); i++) expanded.push(card);
});
// Mischen (Fisher-Yates)
for (let i = expanded.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[expanded[i], expanded[j]] = [expanded[j], expanded[i]];
}
const cards = await cardsRes.json();
// DEBUG: alle Karten-Felder anzeigen
console.log("[Battlefield] Karten aus API:", cards.slice(0,3).map(c => ({
name: c.name, attack: c.attack, defends: c.defends, cooldown: c.cooldown
})));
// Erste 3 Karten aufgedeckt anzeigen
// Erste 3 in die Hand
handCardIds.forEach((id, i) => {
const card = cards[i];
const slot = document.getElementById(id);
if (!slot || !card) return;
// Feldnamen aus der API (attack, defends, cooldown)
const atkVal = card.attack ?? null;
const defVal = card.defends ?? null;
const cdVal = card.cooldown ?? null;
const hasAtk = atkVal != null;
const hasDef = defVal != null;
const hasCd = cdVal != null;
const showStats = hasAtk || hasDef || hasCd;
const statsHtml = showStats ? `
<div class="card-stat-overlay">
${hasAtk ? `<span class="cs-atk">${atkVal}</span>` : ""}
${hasDef ? `<span class="cs-def">${defVal}</span>` : ""}
${hasCd ? `<span class="cs-cd">${cdVal}</span>` : ""}
</div>` : "";
slot.innerHTML = card.image
? `<img src="/images/cards/${card.image}"
onerror="this.src='/images/items/rueckseite.png'"
title="${card.name}"
style="width:100%;height:100%;object-fit:cover;border-radius:7px;display:block;">
${statsHtml}`
: `<div style="display:flex;flex-direction:column;align-items:center;
justify-content:center;height:100%;gap:4px;font-family:Cinzel,serif;">
<span style="font-size:18px;">⚔️</span>
<span style="font-size:9px;color:#f0d9a6;text-align:center;">${card.name}</span>
</div>
${statsHtml}`;
if (expanded[i]) setHandSlot(id, expanded[i]);
});
// Rest als Deck-Queue
deckQueue = expanded.slice(3);
const countEl = document.getElementById("deck-count");
if (countEl) countEl.textContent = deckQueue.length;
} catch(e) {
console.error("[Battlefield] Deck laden:", e);
}
})();
/* ── Zug beenden: CD ticken + Karte ziehen ─────────── */
document.getElementById("end-turn-btn")?.addEventListener("click", () => {
tickHandCooldowns();
drawNextCard();
});
/* ── Hilfsfunktion: Karte mit Stats in einen Slot rendern ── */
function renderCardInSlot(slot, card) {
if (!slot || !card) return;