From a516399e84f3dc0642d1d3c596c19a6068f87c53 Mon Sep 17 00:00:00 2001 From: cay Date: Fri, 10 Apr 2026 07:41:08 +0100 Subject: [PATCH] tdjdey --- public/css/1v1.css | 38 +++++++++ views/1v1-battlefield.ejs | 167 ++++++++++++++++++++++++++------------ 2 files changed, 151 insertions(+), 54 deletions(-) diff --git a/public/css/1v1.css b/public/css/1v1.css index a067f78..f3bce43 100644 --- a/public/css/1v1.css +++ b/public/css/1v1.css @@ -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; diff --git a/views/1v1-battlefield.ejs b/views/1v1-battlefield.ejs index a47a1eb..f90ba25 100644 --- a/views/1v1-battlefield.ejs +++ b/views/1v1-battlefield.ejs @@ -224,14 +224,13 @@ `; hand.appendChild(deckSlot); - // ── Slots 2–4: aufgedeckte Handkarten ──────────────── + // ── Slots 2–4: 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 = ``; + s.innerHTML = '🃏'; 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 = '🃏'; + 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 = ` +
+ ${atkVal != null ? `${atkVal}` : ""} + ${defVal != null ? `${defVal}` : ""} + ${card.cooldown != null + ? `${isReady ? "✓" : currentCd}` + : ""} +
`; + + const readyBadge = isReady + ? `
SPIELEN
` + : ""; + + slot.innerHTML = card.image + ? ` + ${statsHtml}${readyBadge}` + : `
+ ⚔️ + ${card.name} +
${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 ? ` -
- ${hasAtk ? `${atkVal}` : ""} - ${hasDef ? `${defVal}` : ""} - ${hasCd ? `${cdVal}` : ""} -
` : ""; - - slot.innerHTML = card.image - ? ` - ${statsHtml}` - : `
- ⚔️ - ${card.name} -
- ${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;