-
-
-
π‘οΈ
-
1v1
-
Einzelkampf β Beweis deine StΓ€rke im Duell
+
+
+
βοΈ 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
+
-
-
-
βοΈ
-
2v2
-
VerbΓΌnde dich mit einem Kameraden im Kampf
-
-
-
-
π‘οΈ
-
4v4
-
Schlachtruf β FΓΌhre deine Truppe zum Sieg
-
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
Offene Teams
+
Keine offenen Teams vorhanden.
+
+
`;
@@ -214,6 +237,146 @@ function injectArenaStyles() {
pointer-events: none;
border-color: rgba(255,215,80,0.5) !important;
}
+
+ /* ββ 2v2 Lobby Screen ββ */
+ #arena-2v2-screen {
+ flex-direction: column;
+ gap: 14px;
+ padding: 16px;
+ height: 100%;
+ overflow-y: auto;
+ }
+ .arena-lobby-header {
+ display: flex;
+ align-items: center;
+ gap: 16px;
+ }
+ .arena-back-btn {
+ background: none;
+ border: 1px solid rgba(255,200,80,0.3);
+ color: #c8960c;
+ font-family: "Cinzel", serif;
+ font-size: 12px;
+ padding: 4px 12px;
+ border-radius: 4px;
+ cursor: pointer;
+ }
+ .arena-back-btn:hover { background: rgba(200,150,12,0.15); }
+ .arena-lobby-actions { display: flex; gap: 10px; margin-bottom: 4px; }
+ .arena-btn-create {
+ background: linear-gradient(#4a3018, #2a1a08);
+ border: 2px solid #8b6a3c;
+ border-radius: 7px;
+ color: #f0d9a6;
+ font-family: "Cinzel", serif;
+ font-size: 12px;
+ padding: 8px 16px;
+ cursor: pointer;
+ transition: 0.2s;
+ }
+ .arena-btn-create:hover { border-color: #f0d060; }
+ .arena-lobby-title {
+ font-family: "Cinzel", serif;
+ font-size: 13px;
+ color: #a08060;
+ letter-spacing: 1px;
+ margin-bottom: 6px;
+ }
+ .arena-lobby-empty {
+ font-family: "Cinzel", serif;
+ font-size: 12px;
+ color: #606060;
+ padding: 12px 0;
+ }
+ .arena-lobby-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ background: linear-gradient(#2a1a08, #1a0f04);
+ border: 1px solid #6b4b2a;
+ border-radius: 8px;
+ padding: 10px 14px;
+ margin-bottom: 6px;
+ }
+ .arena-lobby-row-info { display: flex; align-items: center; gap: 12px; }
+ .arena-lobby-leader { font-family: "Cinzel", serif; font-size: 13px; color: #f0d9a6; }
+ .arena-lobby-level { font-size: 11px; color: #a08060; }
+ .arena-lobby-count { font-size: 11px; color: #6a9a4a; }
+ .arena-btn-join {
+ background: linear-gradient(#1a4a18, #0f2a0e);
+ border: 2px solid #4a8a3c;
+ border-radius: 6px;
+ color: #a0e090;
+ font-family: "Cinzel", serif;
+ font-size: 11px;
+ padding: 5px 12px;
+ cursor: pointer;
+ transition: 0.2s;
+ }
+ .arena-btn-join:hover { border-color: #8ae060; color: #c0f0a0; }
+
+ /* ββ Team-Panel ββ */
+ .arena-team-box {
+ background: linear-gradient(#2a1a08, #1a0f04);
+ border: 2px solid #6b4b2a;
+ border-radius: 10px;
+ padding: 14px;
+ }
+ .arena-team-title {
+ font-family: "Cinzel", serif;
+ font-size: 13px;
+ color: #f0d060;
+ letter-spacing: 2px;
+ margin-bottom: 10px;
+ }
+ .arena-team-player {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ padding: 7px 10px;
+ border: 1px solid #3a2810;
+ border-radius: 6px;
+ margin-bottom: 5px;
+ background: rgba(255,255,255,0.03);
+ }
+ .arena-team-player.ready { border-color: #4a8a3c; background: rgba(74,138,60,0.1); }
+ .arena-team-player-name { font-family: "Cinzel", serif; font-size: 12px; color: #f0d9a6; flex: 1; }
+ .arena-team-player-level { font-size: 11px; color: #a08060; }
+ .arena-team-player-status { font-size: 11px; }
+ .arena-waiting-partner {
+ font-family: "Cinzel", serif;
+ font-size: 11px;
+ color: #a08060;
+ text-align: center;
+ padding: 8px;
+ animation: pulse 2s ease-in-out infinite;
+ }
+ .arena-btn-ready {
+ width: 100%;
+ margin-top: 10px;
+ background: linear-gradient(#1a4a18, #0f2a0e);
+ border: 2px solid #4a8a3c;
+ border-radius: 8px;
+ color: #a0e090;
+ font-family: "Cinzel", serif;
+ font-size: 14px;
+ padding: 10px;
+ cursor: pointer;
+ transition: 0.2s;
+ }
+ .arena-btn-ready:hover:not([disabled]) { border-color: #8ae060; background: linear-gradient(#2a6a28, #1a3a18); }
+ .arena-btn-ready.active { border-color: #8ae060; color: #c0f0a0; cursor: default; }
+ .arena-searching-box {
+ font-family: "Cinzel", serif;
+ font-size: 12px;
+ color: #dceb15;
+ text-align: center;
+ padding: 10px;
+ border: 1px solid rgba(255,215,80,0.3);
+ border-radius: 8px;
+ margin-top: 8px;
+ animation: pulse 2s ease-in-out infinite;
+ }
`;
document.head.appendChild(style);
}
@@ -229,17 +392,186 @@ function initArenaModes() {
document.querySelectorAll(".arena-mode-card").forEach((card) => {
card.addEventListener("click", () => {
const mode = card.dataset.mode;
-
if (mode === "1v1") {
handle1v1Click(card);
+ } else if (mode === "2v2") {
+ open2v2Lobby();
} else {
console.log("Arena Modus gewΓ€hlt:", mode);
- // Platzhalter fΓΌr 2v2 / 4v4
}
});
});
}
+/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+ 2v2 LOBBY
+ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
+let my2v2TeamId = null;
+let myArenaData = null;
+
+async function open2v2Lobby() {
+ const socket = getSocket();
+ if (!socket) { showArenaError("Keine Verbindung zum Server."); return; }
+
+ // Spielerdaten laden
+ if (!myArenaData) {
+ try {
+ const res = await fetch("/arena/me");
+ if (!res.ok) throw new Error(res.status);
+ myArenaData = await res.json();
+ } catch {
+ showArenaError("Spielerdaten konnten nicht geladen werden.");
+ return;
+ }
+ }
+
+ // Screen wechseln
+ document.getElementById("arena-mode-screen").style.display = "none";
+ document.getElementById("arena-2v2-screen").style.display = "flex";
+
+ // Lobbyliste anfordern
+ socket.emit("get_2v2_lobbies");
+
+ // ZurΓΌck-Button
+ document.getElementById("arena-2v2-back").onclick = () => {
+ leave2v2Team(socket);
+ document.getElementById("arena-2v2-screen").style.display = "none";
+ document.getElementById("arena-mode-screen").style.display = "";
+ my2v2TeamId = null;
+ };
+
+ // Team erstellen
+ document.getElementById("arena-create-team-btn").onclick = () => {
+ socket.emit("create_2v2_team", myArenaData);
+ };
+
+ // Socket-Listener registrieren (einmalig)
+ socket.off("2v2_lobbies");
+ socket.off("2v2_team_joined");
+ socket.off("2v2_team_update");
+ socket.off("2v2_partner_left");
+ socket.off("2v2_searching");
+ socket.off("match_found_2v2");
+ socket.off("2v2_error");
+
+ socket.on("2v2_lobbies", (list) => render2v2LobbyList(list, socket));
+
+ socket.on("2v2_team_joined", (data) => {
+ my2v2TeamId = data.teamId;
+ document.getElementById("arena-team-panel").style.display = "block";
+ document.getElementById("arena-lobby-section").style.display = "none";
+ });
+
+ socket.on("2v2_team_update", (data) => render2v2TeamPanel(data, socket));
+
+ socket.on("2v2_partner_left", (data) => {
+ const status = document.getElementById("arena-team-status");
+ if (status) status.innerHTML = `
β οΈ ${data.name} hat das Team verlassen.`;
+ // Bereit-Button zurΓΌcksetzen
+ render2v2TeamPanel({ teamId: my2v2TeamId, players: [{ name: myArenaData.name, level: myArenaData.level, ready: false }], count: 1 }, socket);
+ });
+
+ socket.on("2v2_searching", () => {
+ const status = document.getElementById("arena-team-status");
+ if (status) status.innerHTML = `
β³ Suche nach Gegnerteamβ¦
`;
+ const actions = document.getElementById("arena-team-actions");
+ if (actions) actions.innerHTML = "";
+ });
+
+ socket.on("match_found_2v2", (data) => {
+ socket.off("2v2_lobbies");
+ socket.off("2v2_team_update");
+ socket.off("2v2_partner_left");
+ socket.off("2v2_searching");
+
+ showMatchFoundOverlay(myArenaData.name, `Team ${data.myTeam === 1 ? 2 : 1}`, () => {
+ document.getElementById("arena-2v2-screen").style.display = "none";
+ document.getElementById("arena-mode-screen").style.display = "";
+ openArenaPopup(
+ `/arena/2v2?match=${encodeURIComponent(data.matchId)}&slot=${encodeURIComponent(data.mySlot)}`,
+ data.opponents?.join(" & ") || "Gegner",
+ data.matchId,
+ );
+ });
+ });
+
+ socket.on("2v2_error", (data) => {
+ const status = document.getElementById("arena-team-status");
+ if (status) { status.innerHTML = `
β ${data.message}`; }
+ });
+}
+
+function render2v2LobbyList(list, socket) {
+ const el = document.getElementById("arena-lobby-list");
+ if (!el) return;
+ if (!list.length) {
+ el.innerHTML = `
Keine offenen Teams vorhanden.
`;
+ return;
+ }
+ el.innerHTML = list.map(team => `
+
+
+ βοΈ ${team.leader}
+ Lvl ${team.leaderLevel}
+ ${team.count}/2 Spieler
+
+
+
+ `).join("");
+
+ el.querySelectorAll(".arena-btn-join").forEach(btn => {
+ btn.addEventListener("click", () => {
+ socket.emit("join_2v2_team", { teamId: btn.dataset.teamid, playerData: myArenaData });
+ });
+ });
+}
+
+function render2v2TeamPanel(data, socket) {
+ const playersEl = document.getElementById("arena-team-players");
+ const actionsEl = document.getElementById("arena-team-actions");
+ const statusEl = document.getElementById("arena-team-status");
+ if (!playersEl || !actionsEl) return;
+
+ playersEl.innerHTML = data.players.map(p => `
+
+ ${p.name}
+ Lvl ${p.level}
+ ${p.ready ? 'β
Bereit' : 'β Wartet'}
+
+ `).join("");
+
+ if (data.count < 2) {
+ actionsEl.innerHTML = `
Warte auf Partnerβ¦
`;
+ if (statusEl) statusEl.innerHTML = "";
+ } else {
+ const myEntry = data.players.find(p => p.name === myArenaData?.name);
+ const iAmReady = myEntry?.ready;
+ actionsEl.innerHTML = iAmReady
+ ? `
`
+ : `
`;
+
+ if (!iAmReady) {
+ document.getElementById("arena-ready-btn")?.addEventListener("click", () => {
+ socket.emit("2v2_player_ready", { teamId: my2v2TeamId });
+ });
+ }
+ }
+}
+
+function leave2v2Team(socket) {
+ if (my2v2TeamId) {
+ socket.emit("leave_2v2_team");
+ my2v2TeamId = null;
+ }
+ socket.off("2v2_lobbies");
+ socket.off("2v2_team_joined");
+ socket.off("2v2_team_update");
+ socket.off("2v2_partner_left");
+ socket.off("2v2_searching");
+ socket.off("match_found_2v2");
+ socket.off("2v2_error");
+}
+
/* ββ 1v1: Hauptlogik βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
async function handle1v1Click(card) {
const socket = getSocket();
diff --git a/public/js/quickmenu/events.js b/public/js/quickmenu/events.js
index 3296827..69239a1 100644
--- a/public/js/quickmenu/events.js
+++ b/public/js/quickmenu/events.js
@@ -202,16 +202,30 @@ export async function loadEvents() {