dok/views/1v1_spielfeld.ejs
2026-03-18 11:36:52 +00:00

298 lines
10 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="de">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= title || "Spielfeld" %></title>
<link
href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="/css/1v1.css" />
</head>
<body>
<!-- Warte-Overlay bis Gegner verbunden ist -->
<div id="connecting-overlay">
<div class="spinner"></div>
<div>Warte auf Gegner…</div>
<p>Verbindung wird hergestellt</p>
</div>
<div class="board">
<!-- TOP BAR -->
<div class="top-bar">
<div class="game-title"><%= title || "Spielfeld" %></div>
<div class="top-icons">
<div class="top-icon">⚙</div>
<div class="top-icon">🗺</div>
<div class="top-icon">📖</div>
<div class="top-icon">🏆</div>
</div>
<div class="top-bar-actions">
<button class="bereit-btn" id="bereit-btn" onclick="handleBereit()">✔ BEREIT</button>
<button class="end-turn-btn" id="end-turn-btn" disabled>Zug beenden</button>
<button class="aufgeben-btn" id="aufgeben-btn" onclick="handleAufgeben()">🏳 Aufgeben</button>
</div>
</div>
<!-- Spielfeld-Sperre bis beide Spieler bereit sind -->
<div id="board-lock-overlay"></div>
<!-- LEFT AVATAR (Spieler 1) -->
<div class="avatar avatar-left" id="avLeft">
<input
type="file"
accept="image/*"
onchange="loadAvatar(this, 'avImgL', 'avLeft')"
/>
<img id="avImgL" class="av-img" />
<div class="av-placeholder" id="avPhL">
<div class="av-icon">⚔</div>
</div>
<div class="av-name" id="nameLeft"><%= player1 || "Spieler 1" %></div>
<div class="av-stats">
<div class="stat hp">
<span class="s-icon">❤</span>
<span class="s-val" id="hpLeft"><%= player1hp || 20 %></span>
</div>
<div class="stat mana">
<span class="s-icon">💧</span>
<span class="s-val" id="manaLeft"><%= player1mana || 3 %></span>
</div>
</div>
<div class="hp-orb" id="orbLeft"><%= player1hp || 15 %></div>
</div>
<!-- RIGHT AVATAR (Spieler 2) -->
<div class="avatar avatar-right" id="avRight">
<input
type="file"
accept="image/*"
onchange="loadAvatar(this, 'avImgR', 'avRight')"
/>
<img id="avImgR" class="av-img" />
<div class="av-placeholder" id="avPhR">
<div class="av-icon">🛡</div>
</div>
<div class="av-name" id="nameRight"><%= player2 || "Spieler 2" %></div>
<div class="av-stats">
<div class="stat hp">
<span class="s-icon">❤</span>
<span class="s-val" id="hpRight"><%= player2hp || 20 %></span>
</div>
<div class="stat mana">
<span class="s-icon">💧</span>
<span class="s-val" id="manaRight"><%= player2mana || 3 %></span>
</div>
</div>
<div class="hp-orb" id="orbRight"><%= player2hp || 15 %></div>
</div>
<!-- CENTER CARD ROWS -->
<div class="card-area">
<div class="row-label">Reihe 1</div>
<div class="card-row" id="row1"></div>
<div class="row-label">Reihe 2</div>
<div class="card-row" id="row2"></div>
</div>
<!-- BOTTOM BAR -->
<div class="bottom-bar">
<!-- HAND -->
<div class="hand-area" id="handArea"></div>
<!-- ACTION BUTTONS -->
<div class="action-hud">
<div class="action-row">
<div class="action-btn" title="Angriff">⚔</div>
<div class="action-btn" title="Magie">✨</div>
<div class="action-btn" title="Verteidigung">🛡</div>
</div>
<div class="action-row">
<div class="action-btn" title="Heilen">💊</div>
<div class="action-btn" title="Karte ziehen">🃏</div>
<div class="action-btn" title="Einstellungen">⚙</div>
</div>
</div>
</div>
</div>
<!-- Socket.io (wird vom Parent-Fenster geerbt oder eigenständig geladen) -->
<script src="/socket.io/socket.io.js"></script>
<script>
// ── Spielfeld-Karten aufbauen ──────────────────────────────────────────
["row1", "row2"].forEach((id) => {
const row = document.getElementById(id);
for (let i = 1; i <= 11; i++) {
const s = document.createElement("div");
s.className = "card-slot";
if (id === "row1" && i === 1) {
s.innerHTML = `
<img
src="/images/playcards/Silberklinge.png"
alt="Silberklinge"
style="width:100%;height:100%;object-fit:cover;border-radius:7px;"
>
`;
} else {
s.innerHTML =
'<span class="slot-icon">✦</span><span class="slot-num">' +
i +
"</span>";
}
row.appendChild(s);
}
});
// ── Hand-Karten aufbauen ───────────────────────────────────────────────
const hand = document.getElementById("handArea");
const silberklinge = document.createElement("div");
silberklinge.className = "hand-slot";
silberklinge.innerHTML = `
<img
src="/images/playcards/Silberklinge.png"
alt="Silberklinge"
style="width:100%;height:100%;object-fit:cover;border-radius:7px;"
>
`;
hand.appendChild(silberklinge);
for (let i = 1; i < 8; i++) {
const s = document.createElement("div");
s.className = "hand-slot";
s.innerHTML = '<span class="hs-icon">🃏</span>';
hand.appendChild(s);
}
// ── Match-Daten aus URL ────────────────────────────────────────────────
const urlParams = new URLSearchParams(window.location.search);
const matchId = urlParams.get("match") || "<%= matchId || '' %>";
const mySlot = urlParams.get("slot") || "<%= mySlot || 'player1' %>";
const amIPlayer1 = mySlot === "player1";
// ── Socket.io: Gegner-Namen live empfangen ─────────────────────────────
const socket = io();
socket.emit("arena_join", { matchId, slot: mySlot });
socket.on("arena_opponent_joined", (data) => {
// Gegner-Name anzeigen
const opponentName = data.name || "Gegner";
if (amIPlayer1) {
document.getElementById("nameRight").textContent = opponentName;
} else {
document.getElementById("nameLeft").textContent = opponentName;
}
// Overlay entfernen
const overlay = document.getElementById("connecting-overlay");
if (overlay) overlay.remove();
});
// Beide Spieler sind verbunden → beide benachrichtigen
socket.on("arena_ready", (data) => {
const overlay = document.getElementById("connecting-overlay");
if (overlay) overlay.remove();
// Namen setzen
document.getElementById("nameLeft").textContent = data.player1 || "Spieler 1";
document.getElementById("nameRight").textContent = data.player2 || "Spieler 2";
});
// ── Bereit-System ─────────────────────────────────────────────────────
let myReady = false;
function handleBereit() {
if (myReady) return;
myReady = true;
const btn = document.getElementById("bereit-btn");
btn.textContent = "✔ BEREIT";
btn.classList.add("bereit-clicked");
btn.disabled = true;
socket.emit("player_ready", { matchId, slot: mySlot });
}
socket.on("ready_status", (data) => {
// data.readyCount = wie viele Spieler bereits bereit sind
if (data.readyCount === 2) {
// Beide bereit → Sperre aufheben
const lock = document.getElementById("board-lock-overlay");
if (lock) lock.remove();
const bereitBtn = document.getElementById("bereit-btn");
if (bereitBtn) bereitBtn.remove();
const endBtn = document.getElementById("end-turn-btn");
if (endBtn) endBtn.disabled = false;
}
});
function handleAufgeben() {
// Funktion offen hier kann später die Aufgabe-Logik rein
socket.emit("player_surrender", { matchId, slot: mySlot });
}
// ─────────────────────────────────────────────────────────────────────
// ── Avatar laden (lokal) ──────────────────────────────────────────────
function loadAvatar(input, imgId, parentId) {
const file = input.files[0];
if (!file) return;
const r = new FileReader();
r.onload = (e) => {
const img = document.getElementById(imgId);
img.src = e.target.result;
img.style.display = "block";
const parent = document.getElementById(parentId);
const ph = parent.querySelector(".av-placeholder");
if (ph) ph.style.display = "none";
};
r.readAsDataURL(file);
}
function loadPortrait(input, imgId) {
const file = input.files[0];
if (!file) return;
const r = new FileReader();
r.onload = (e) => {
const img = document.getElementById(imgId);
img.src = e.target.result;
img.style.display = "block";
img.parentElement.querySelector("span").style.display = "none";
};
r.readAsDataURL(file);
}
</script>
</body>
</html>