export async function loadArena() { const ui = document.querySelector(".building-ui"); ui.innerHTML = `
βš”οΈ Kampfarena

WΓ€hle deinen Kampfmodus

πŸ—‘οΈ
1v1
Einzelkampf – Beweis deine StΓ€rke im Duell
βš”οΈ
2v2
VerbΓΌnde dich mit einem Kameraden im Kampf
πŸ›‘οΈ
4v4
Schlachtruf – FΓΌhre deine Truppe zum Sieg
`; injectArenaStyles(); initArenaModes(); } /* ── Styles ────────────────────────────────────────────────────────────────── */ function injectArenaStyles() { if (document.getElementById("arena-popup-styles")) return; const style = document.createElement("style"); style.id = "arena-popup-styles"; style.textContent = ` @keyframes arenaFadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes arenaScaleIn { from { transform: scale(0.94); opacity: 0; } to { transform: scale(1); opacity: 1; } } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } /* ── Queue Status Box ── */ #arena-queue-status { margin-top: 18px; padding: 12px 20px; border-radius: 10px; background: rgba(255, 215, 80, 0.08); border: 1px solid rgba(255, 215, 80, 0.3); color: #1a1a1a; font-family: "Cinzel", serif; font-size: 13px; letter-spacing: 1px; text-align: center; animation: pulse 2s ease-in-out infinite; } #arena-queue-status .qs-cancel { display: inline-block; margin-top: 8px; font-size: 11px; color: rgba(255,100,100,0.8); cursor: pointer; text-decoration: underline; animation: none; } #arena-queue-status .qs-cancel:hover { color: #e74c3c; } /* ── Backdrop ── */ #arena-backdrop { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.82); backdrop-filter: blur(5px); z-index: 9998; animation: arenaFadeIn 0.25s ease; } /* ── Popup ── */ #arena-popup { position: fixed; inset: 50px; z-index: 9999; display: flex; flex-direction: column; border-radius: 14px; overflow: hidden; box-shadow: 0 0 0 1px rgba(255, 215, 80, 0.35), 0 30px 90px rgba(0, 0, 0, 0.85), 0 0 60px rgba(255, 215, 80, 0.08); animation: arenaScaleIn 0.28s cubic-bezier(0.22, 1, 0.36, 1); } /* ── Titelleiste ── */ #arena-popup-titlebar { display: flex; align-items: center; justify-content: space-between; background: rgba(10, 8, 5, 0.95); border-bottom: 1px solid rgba(255, 215, 80, 0.3); padding: 0 16px; height: 42px; flex-shrink: 0; user-select: none; } #arena-popup-titlebar .ap-left { display: flex; align-items: center; gap: 10px; } #arena-popup-titlebar .ap-dots { display: flex; gap: 7px; } #arena-popup-titlebar .ap-dot { width: 13px; height: 13px; border-radius: 50%; cursor: pointer; transition: filter 0.15s; } #arena-popup-titlebar .ap-dot:hover { filter: brightness(1.3); } #arena-popup-titlebar .ap-dot.close { background: #e74c3c; border: 1px solid rgba(0,0,0,0.25); } #arena-popup-titlebar .ap-dot.min { background: #f1c40f; border: 1px solid rgba(0,0,0,0.25); } #arena-popup-titlebar .ap-dot.expand { background: #2ecc71; border: 1px solid rgba(0,0,0,0.25); } #arena-popup-titlebar .ap-title { font-family: "Cinzel", serif; font-size: 13px; letter-spacing: 4px; color: rgba(255, 215, 80, 0.85); text-transform: uppercase; text-shadow: 0 1px 8px rgba(0,0,0,0.8); } #arena-popup-titlebar .ap-url { font-size: 11px; color: rgba(255,255,255,0.22); letter-spacing: 1px; } /* ── Match-Found Overlay ── */ #match-found-overlay { position: fixed; inset: 0; z-index: 10000; background: rgba(0,0,0,0.9); display: flex; flex-direction: column; align-items: center; justify-content: center; animation: arenaFadeIn 0.3s ease; } #match-found-overlay .mfo-title { font-family: "Cinzel", serif; font-size: 36px; color: #ffd750; text-shadow: 0 0 30px rgba(255,215,80,0.6); letter-spacing: 6px; margin-bottom: 12px; } #match-found-overlay .mfo-vs { font-family: "Cinzel", serif; font-size: 18px; color: rgba(255,255,255,0.75); letter-spacing: 3px; } #match-found-overlay .mfo-bar { width: 300px; height: 4px; background: rgba(255,215,80,0.2); border-radius: 2px; margin-top: 24px; overflow: hidden; } #match-found-overlay .mfo-bar-fill { height: 100%; background: #ffd750; width: 0%; border-radius: 2px; transition: width 1.5s ease; } /* ── iframe ── */ #arena-popup iframe { flex: 1; border: none; width: 100%; display: block; } /* ── Card: gesucht-Zustand ── */ .arena-mode-card.searching { opacity: 0.6; pointer-events: none; border-color: rgba(255,215,80,0.5) !important; } `; document.head.appendChild(style); } /* ── Socket-Referenz holen ─────────────────────────────────────────────────── */ function getSocket() { // Wird von der Haupt-App als window._socket bereitgestellt return window._socket || null; } /* ── Klick-Handler initialisieren ─────────────────────────────────────────── */ function initArenaModes() { document.querySelectorAll(".arena-mode-card").forEach((card) => { card.addEventListener("click", () => { const mode = card.dataset.mode; if (mode === "1v1") { handle1v1Click(card); } else { console.log("Arena Modus gewΓ€hlt:", mode); // Platzhalter fΓΌr 2v2 / 4v4 } }); }); } /* ── 1v1: Hauptlogik ───────────────────────────────────────────────────────── */ async function handle1v1Click(card) { const socket = getSocket(); if (!socket) { showArenaError("Keine Verbindung zum Server. Bitte Seite neu laden."); return; } // Bereits in Suche? if (card.classList.contains("searching")) return; // Spielerdaten laden let me; try { const res = await fetch("/arena/me"); if (!res.ok) throw new Error("Status " + res.status); me = await res.json(); } catch (err) { console.error("[1v1] Spielerdaten konnten nicht geladen werden:", err); showArenaError("Spielerdaten konnten nicht geladen werden."); return; } // UI: Suche lΓ€uft setCardSearching(card, true); showQueueStatus(me.level); // Sicherstellen, dass keine alten Listener hΓ€ngen socket.off("match_found"); socket.off("queue_status"); // Queue-Status empfangen socket.on("queue_status", (data) => { if (data.status === "waiting") { showQueueStatus(me.level, data.poolSize); } else if (data.status === "left") { setCardSearching(card, false); hideQueueStatus(); } }); // Match gefunden socket.once("match_found", (data) => { socket.off("queue_status"); setCardSearching(card, false); hideQueueStatus(); showMatchFoundOverlay(me.name, data.opponent.name, () => { openArenaPopup( `/arena/1v1?match=${encodeURIComponent(data.matchId)}&slot=${encodeURIComponent(data.mySlot)}`, data.opponent.name, data.matchId, ); }); }); // Matchmaking starten socket.emit("join_1v1", { id: me.id, name: me.name, level: me.level, }); } /* ── Queue abbrechen ───────────────────────────────────────────────────────── */ function cancelQueue(card) { const socket = getSocket(); if (socket) { socket.emit("leave_1v1"); socket.off("match_found"); socket.off("queue_status"); } setCardSearching(card, false); hideQueueStatus(); } /* ── Match-Found Splash ────────────────────────────────────────────────────── */ function showMatchFoundOverlay(myName, opponentName, onDone) { // Verhindert doppeltes Γ–ffnen if (document.getElementById("match-found-overlay")) return; const overlay = document.createElement("div"); overlay.id = "match-found-overlay"; overlay.innerHTML = `
βš”οΈ Match gefunden!
${myName}  vs  ${opponentName}
`; document.body.appendChild(overlay); // Ladebalken animieren requestAnimationFrame(() => { const bar = document.getElementById("mfBar"); if (bar) bar.style.width = "100%"; }); // Nach 1.6s zum Spielfeld setTimeout(() => { overlay.remove(); onDone(); }, 1600); } /* ── Popup ΓΆffnen ──────────────────────────────────────────────────────────── */ function openArenaPopup(src, opponentName, matchId) { // Vorhandenen Popup schließen (falls mehrfach) document.getElementById("arena-backdrop")?.remove(); document.getElementById("arena-popup")?.remove(); const backdrop = document.createElement("div"); backdrop.id = "arena-backdrop"; const popup = document.createElement("div"); popup.id = "arena-popup"; const title = opponentName ? `βš”οΈ 1v1  Β·  vs ${opponentName}` : "βš”οΈ Arena  Β·  1v1"; popup.innerHTML = `
${title}
${matchId || src}
`; document.body.appendChild(backdrop); document.body.appendChild(popup); // Backdrop-Klick deaktiviert – Fenster nur ΓΌber Aufgeben/Spielende schließbar } /* ── UI Hilfsfunktionen ────────────────────────────────────────────────────── */ function setCardSearching(card, searching) { const label = card.querySelector(".arena-mode-label"); const desc = card.querySelector(".arena-mode-desc"); if (searching) { card.classList.add("searching"); label.textContent = "⏳ Suche…"; desc.textContent = "Warte auf passenden Gegner…"; } else { card.classList.remove("searching"); label.textContent = "1v1"; desc.textContent = "Einzelkampf – Beweis deine StΓ€rke im Duell"; } } function showQueueStatus(myLevel, poolSize) { const box = document.getElementById("arena-queue-status"); if (!box) return; const range = 5; const min = Math.max(1, myLevel - range); const max = myLevel + range; const pool = poolSize ? ` Β· ${poolSize} Spieler im Pool` : ""; box.style.display = "block"; box.innerHTML = ` ⏳ Suche Gegner (Level ${min}–${max})${pool}
Suche abbrechen `; // Cancel-Button – Card-Referenz ΓΌber data-attribute document.getElementById("qs-cancel-btn")?.addEventListener("click", () => { const card = document.querySelector(".arena-mode-card[data-mode='1v1']"); if (card) cancelQueue(card); }); } function hideQueueStatus() { const box = document.getElementById("arena-queue-status"); if (box) box.style.display = "none"; } function showArenaError(msg) { const box = document.getElementById("arena-queue-status"); if (!box) return; box.style.display = "block"; box.style.animation = "none"; box.style.borderColor = "rgba(231,76,60,0.5)"; box.style.color = "#e74c3c"; box.textContent = "❌ " + msg; setTimeout(() => { box.style.display = "none"; box.style.animation = ""; box.style.borderColor = ""; box.style.color = ""; }, 3000); }