tgkdtz
This commit is contained in:
parent
7d5209a45d
commit
e572f0d3a1
@ -590,6 +590,53 @@ body {
|
||||
box-shadow: 0 0 calc(var(--s) * 16) rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
/* ── Zug-Timer (Top Bar Mitte) ── */
|
||||
#turn-timer-wrap {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#turn-timer-svg {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tt-track {
|
||||
fill: none;
|
||||
stroke: rgba(255,255,255,0.1);
|
||||
stroke-width: 4;
|
||||
}
|
||||
|
||||
.tt-fill {
|
||||
fill: none;
|
||||
stroke: #27ae60;
|
||||
stroke-width: 4;
|
||||
stroke-linecap: round;
|
||||
transform: rotate(-90deg);
|
||||
transform-origin: center;
|
||||
stroke-dasharray: 113.1; /* 2π×18 */
|
||||
stroke-dashoffset: 0;
|
||||
transition: stroke-dashoffset 0.9s linear, stroke 0.3s ease;
|
||||
}
|
||||
|
||||
#turn-timer-num {
|
||||
position: absolute;
|
||||
font-family: "Cinzel", serif;
|
||||
font-size: calc(var(--s) * 13);
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
text-shadow: 0 1px 4px rgba(0,0,0,0.9);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
@keyframes tt-pulse {
|
||||
0%, 100% { opacity: 1; transform: scale(1); }
|
||||
50% { opacity: 0.6; transform: scale(1.15); }
|
||||
}
|
||||
|
||||
/* ── Karten-Stats Overlay – exakt wie Slotmaschine ── */
|
||||
.card-stat-overlay {
|
||||
position: absolute;
|
||||
|
||||
@ -100,6 +100,16 @@
|
||||
<div class="board">
|
||||
<div class="top-bar">
|
||||
<div class="game-title"><%= title || "Spielfeld" %></div>
|
||||
|
||||
<!-- Zug-Timer mittig -->
|
||||
<div id="turn-timer-wrap" style="display:none;">
|
||||
<svg id="turn-timer-svg" viewBox="0 0 44 44" width="44" height="44">
|
||||
<circle cx="22" cy="22" r="18" class="tt-track"/>
|
||||
<circle cx="22" cy="22" r="18" class="tt-fill" id="tt-circle"/>
|
||||
</svg>
|
||||
<div id="turn-timer-num">20</div>
|
||||
</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>
|
||||
@ -363,10 +373,139 @@
|
||||
}
|
||||
})();
|
||||
|
||||
/* ── Zug beenden: CD ticken + Karte ziehen ─────────── */
|
||||
/* ══════════════════════════════════════════════════════
|
||||
ZUG-TIMER (20 Sekunden)
|
||||
══════════════════════════════════════════════════════ */
|
||||
const TURN_SECONDS = 20;
|
||||
const TT_CIRCUM = 2 * Math.PI * 18; // r=18
|
||||
let turnTimerInt = null;
|
||||
let turnSecsLeft = TURN_SECONDS;
|
||||
|
||||
function startTurnTimer() {
|
||||
clearInterval(turnTimerInt);
|
||||
turnSecsLeft = TURN_SECONDS;
|
||||
updateTimerUI(turnSecsLeft);
|
||||
|
||||
const wrap = document.getElementById("turn-timer-wrap");
|
||||
if (wrap) wrap.style.display = "flex";
|
||||
|
||||
turnTimerInt = setInterval(() => {
|
||||
turnSecsLeft--;
|
||||
updateTimerUI(turnSecsLeft);
|
||||
if (turnSecsLeft <= 0) {
|
||||
clearInterval(turnTimerInt);
|
||||
// Zeit abgelaufen → Zug automatisch beenden
|
||||
if (isMyTurn) {
|
||||
tickHandCooldowns();
|
||||
drawNextCard();
|
||||
setTurnState(false);
|
||||
socket.emit("end_turn", { matchId, slot: mySlot });
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function stopTurnTimer() {
|
||||
clearInterval(turnTimerInt);
|
||||
const wrap = document.getElementById("turn-timer-wrap");
|
||||
if (wrap) wrap.style.display = "none";
|
||||
}
|
||||
|
||||
function updateTimerUI(secs) {
|
||||
const num = document.getElementById("turn-timer-num");
|
||||
const circle = document.getElementById("tt-circle");
|
||||
if (num) num.textContent = secs;
|
||||
if (circle) {
|
||||
circle.style.strokeDashoffset = TT_CIRCUM * (1 - secs / TURN_SECONDS);
|
||||
circle.style.stroke = secs > 10 ? "#27ae60" : secs > 5 ? "#f39c12" : "#e74c3c";
|
||||
if (secs <= 5) {
|
||||
num.style.color = "#e74c3c";
|
||||
num.style.animation = "tt-pulse 0.5s ease-in-out infinite";
|
||||
} else {
|
||||
num.style.color = "#fff";
|
||||
num.style.animation = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ══════════════════════════════════════════════════════
|
||||
ZUG-SYSTEM
|
||||
══════════════════════════════════════════════════════ */
|
||||
|
||||
// Bin ich der linke Spieler? Wird nach Seitenzuweisung gesetzt.
|
||||
let amILeftPlayer = null;
|
||||
let isMyTurn = false;
|
||||
|
||||
function setTurnState(myTurn) {
|
||||
isMyTurn = myTurn;
|
||||
const btn = document.getElementById("end-turn-btn");
|
||||
if (!btn) return;
|
||||
|
||||
if (myTurn) {
|
||||
btn.disabled = false;
|
||||
btn.textContent = "Zug beenden";
|
||||
btn.style.opacity = "1";
|
||||
document.getElementById("turn-indicator")?.remove();
|
||||
startTurnTimer();
|
||||
} else {
|
||||
btn.disabled = true;
|
||||
btn.style.opacity = "0.4";
|
||||
stopTurnTimer();
|
||||
showTurnIndicator();
|
||||
}
|
||||
}
|
||||
|
||||
function showTurnIndicator() {
|
||||
document.getElementById("turn-indicator")?.remove();
|
||||
const ind = document.createElement("div");
|
||||
ind.id = "turn-indicator";
|
||||
ind.style.cssText = `
|
||||
position:fixed; bottom:calc(var(--s)*200); left:50%;
|
||||
transform:translateX(-50%);
|
||||
background:linear-gradient(135deg,rgba(20,20,40,0.95),rgba(10,10,25,0.95));
|
||||
border:1px solid rgba(200,160,60,0.5);
|
||||
border-radius:calc(var(--s)*8);
|
||||
color:rgba(255,215,80,0.75);
|
||||
font-family:'Cinzel',serif;
|
||||
font-size:calc(var(--s)*11);
|
||||
letter-spacing:calc(var(--s)*3);
|
||||
padding:calc(var(--s)*8) calc(var(--s)*20);
|
||||
z-index:100;
|
||||
pointer-events:none;
|
||||
text-transform:uppercase;
|
||||
box-shadow:0 4px 20px rgba(0,0,0,0.6);
|
||||
`;
|
||||
ind.textContent = "⏳ Gegner ist am Zug";
|
||||
document.body.appendChild(ind);
|
||||
}
|
||||
|
||||
/* ── Zug beenden: CD ticken + Karte ziehen + Server informieren ── */
|
||||
document.getElementById("end-turn-btn")?.addEventListener("click", () => {
|
||||
if (!isMyTurn) return;
|
||||
clearInterval(turnTimerInt);
|
||||
tickHandCooldowns();
|
||||
drawNextCard();
|
||||
setTurnState(false);
|
||||
socket.emit("end_turn", { matchId, slot: mySlot });
|
||||
});
|
||||
|
||||
/* ── Server: Zugwechsel ──────────────────────────────── */
|
||||
socket.on("turn_change", data => {
|
||||
// data.activeSlot = "player1" | "player2"
|
||||
const myActualSlot = amILeftPlayer === null
|
||||
? mySlot
|
||||
: (amILeftPlayer ? "player1" : "player2");
|
||||
|
||||
const nowMyTurn = data.activeSlot === myActualSlot ||
|
||||
data.activeSlot === mySlot;
|
||||
setTurnState(nowMyTurn);
|
||||
});
|
||||
|
||||
// Fallback falls Server kein turn_change sendet:
|
||||
// eigenes end_turn bestätigen wir nach kurzer Verzögerung selbst
|
||||
socket.on("turn_started", data => {
|
||||
const nowMyTurn = data.slot === mySlot;
|
||||
setTurnState(nowMyTurn);
|
||||
});
|
||||
|
||||
/* ── Hilfsfunktion: Karte mit Stats in einen Slot rendern ── */
|
||||
@ -411,9 +550,14 @@
|
||||
const socket = io();
|
||||
|
||||
/* Account-ID laden dann arena_join senden */
|
||||
let myIngameName = null;
|
||||
fetch("/arena/me")
|
||||
.then(r => r.json())
|
||||
.then(me => {
|
||||
// Eigenen Namen sofort im Avatar anzeigen
|
||||
myIngameName = me.ingame_name || me.username || me.name || me.id || "Ich";
|
||||
const myNameEl = document.getElementById(amIPlayer1 ? "nameLeft" : "nameRight");
|
||||
if (myNameEl) myNameEl.textContent = myIngameName;
|
||||
socket.emit("arena_join", { matchId, slot: mySlot, accountId: me.id });
|
||||
})
|
||||
.catch(() => {
|
||||
@ -487,22 +631,34 @@
|
||||
document.getElementById("nameLeft").textContent = leftName;
|
||||
document.getElementById("nameRight").textContent = rightName;
|
||||
|
||||
// Platzhalter-Icon durch Namen ersetzen falls noch kein Bild
|
||||
// Platzhalter: nur den Ingame-Namen anzeigen, kein Icon
|
||||
["avLeft", "avRight"].forEach(avId => {
|
||||
const av = document.getElementById(avId);
|
||||
const ph = av?.querySelector(".av-placeholder");
|
||||
const name = avId === "avLeft" ? leftName : rightName;
|
||||
if (ph) ph.innerHTML = `
|
||||
<div class="av-icon" style="font-size:calc(var(--s)*26);opacity:0.5;">
|
||||
${avId === "avLeft" ? "⚔" : "🛡"}
|
||||
</div>
|
||||
<div style="font-family:'Cinzel',serif;font-size:calc(var(--s)*11);
|
||||
color:rgba(255,215,80,0.9);text-align:center;padding:0 6px;
|
||||
word-break:break-word;line-height:1.3;">${name}</div>`;
|
||||
<div style="
|
||||
font-family:'Cinzel',serif;
|
||||
font-size:calc(var(--s)*13);
|
||||
font-weight:700;
|
||||
color:#ffd750;
|
||||
text-align:center;
|
||||
padding:0 8px;
|
||||
word-break:break-word;
|
||||
line-height:1.4;
|
||||
text-shadow:0 2px 8px rgba(0,0,0,0.9),0 0 20px rgba(0,0,0,0.8);
|
||||
">${name}</div>`;
|
||||
});
|
||||
|
||||
document.getElementById("board-lock-overlay")?.remove();
|
||||
document.getElementById("end-turn-btn").disabled = false;
|
||||
|
||||
// Festlegen ob ich der linke Spieler bin
|
||||
// flip=false: player1=links, flip=true: player1=rechts
|
||||
amILeftPlayer = flip ? (mySlot === "player2") : (mySlot === "player1");
|
||||
|
||||
// Linker Spieler beginnt
|
||||
setTurnState(amILeftPlayer);
|
||||
socket.emit("end_turn_init", { matchId, starterSlot: flip ? "player2" : "player1" });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user