Win banner
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>Wolf & Schafe | Online</title>
|
||||
<title>Wolf & Schafe</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #f0f2f5;
|
||||
@@ -91,7 +91,6 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Connection Dot */
|
||||
.conn-dot {
|
||||
display: inline-block;
|
||||
width: 8px;
|
||||
@@ -126,6 +125,7 @@
|
||||
width: 100%;
|
||||
border: 3px solid var(--black);
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
svg {
|
||||
@@ -175,13 +175,56 @@
|
||||
stroke-dasharray: 4;
|
||||
}
|
||||
|
||||
/* Victory Banner */
|
||||
#victory-banner {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border: 5px solid var(--black);
|
||||
padding: 20px;
|
||||
z-index: 20;
|
||||
text-align: center;
|
||||
box-shadow: 8px 8px 0px var(--black);
|
||||
pointer-events: none;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
#victory-banner h2 {
|
||||
margin: 0;
|
||||
font-size: 1.8rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.winner-glow {
|
||||
animation: winner-pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes winner-pulse {
|
||||
0% {
|
||||
filter: drop-shadow(0 0 2px #ffd700);
|
||||
stroke-width: 2.5;
|
||||
}
|
||||
|
||||
50% {
|
||||
filter: drop-shadow(0 0 12px #ffd700);
|
||||
stroke-width: 6;
|
||||
}
|
||||
|
||||
100% {
|
||||
filter: drop-shadow(0 0 2px #ffd700);
|
||||
stroke-width: 2.5;
|
||||
}
|
||||
}
|
||||
|
||||
#overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -218,7 +261,26 @@
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Toast Popup Styles */
|
||||
.restart-pulse {
|
||||
animation: btn-pulse 1.5s infinite;
|
||||
background: var(--green) !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
@keyframes btn-pulse {
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
#toast {
|
||||
visibility: hidden;
|
||||
min-width: 200px;
|
||||
@@ -273,8 +335,8 @@
|
||||
<h1 style="text-align: center; margin: 0; border-bottom: 4px solid var(--black); padding-bottom: 10px;">WOLF &
|
||||
SCHAFE</h1>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 10px;">
|
||||
<button class="btn btn-green" onclick="createRoom()">+ ONLINE</button>
|
||||
<button class="btn" onclick="startLocal()">+ LOKAL</button>
|
||||
<button class="btn btn-green" onclick="createRoom()">+ ONLINE SPIEL</button>
|
||||
<button class="btn" onclick="startLocal()">+ LOKAL SPIELEN</button>
|
||||
</div>
|
||||
<h3 style="margin: 15px 0 5px 0;">Offene Räume:</h3>
|
||||
<div id="roomList">Suche Räume...</div>
|
||||
@@ -296,11 +358,17 @@
|
||||
<div>WARTEN AUF GEGNER...</div>
|
||||
<p style="font-size: 0.7rem; margin-top: 10px; padding: 0 10px;">Link kopieren und Freund einladen!</p>
|
||||
</div>
|
||||
|
||||
<div id="victory-banner" class="hidden">
|
||||
<h2 id="winner-text">GEWONNEN!</h2>
|
||||
<p style="margin: 5px 0 0 0; font-size: 0.8rem;">SPIEL BEENDET</p>
|
||||
</div>
|
||||
|
||||
<svg viewBox="0 0 600 420"></svg>
|
||||
</div>
|
||||
|
||||
<div class="controls">
|
||||
<button class="btn" id="copyBtn">Link Kopieren</button>
|
||||
<button class="btn" id="copyBtn">Kopieren</button>
|
||||
<button class="btn" id="restartBtn">Restart</button>
|
||||
<button class="btn" onclick="location.href='/'">Lobby</button>
|
||||
</div>
|
||||
@@ -324,7 +392,6 @@
|
||||
|
||||
function initLocalState() {
|
||||
state = { wolf: 5, sheep: [0, 1, 3], turn: "sheep", moveCount: 0, winner: null, lastMove: null };
|
||||
myRole = "sheep"; // Initial role, will toggle
|
||||
document.getElementById("lobby").classList.add("hidden");
|
||||
document.getElementById("game").classList.remove("hidden");
|
||||
document.getElementById("roomInfo").style.visibility = "hidden";
|
||||
@@ -335,7 +402,6 @@
|
||||
|
||||
function connect() {
|
||||
if (isLocal) return initLocalState();
|
||||
|
||||
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
||||
ws = new WebSocket(`${protocol}://${location.host}?room=${roomId}&sessionId=${sessionId}`);
|
||||
|
||||
@@ -358,14 +424,11 @@
|
||||
};
|
||||
}
|
||||
|
||||
// Logic for local movement
|
||||
function handleLocalMove(from, to) {
|
||||
const allowed = (state.turn === "wolf") ? bWolf[from] : bSheep[from];
|
||||
if (!allowed?.includes(to) || state.sheep.includes(to) || state.wolf === to) return;
|
||||
|
||||
if (state.turn === "wolf") { state.wolf = to; state.turn = "sheep"; }
|
||||
else { state.sheep[state.sheep.indexOf(from)] = to; state.turn = "wolf"; }
|
||||
|
||||
state.moveCount++;
|
||||
state.winner = checkWinConditions(state);
|
||||
render();
|
||||
@@ -392,14 +455,8 @@
|
||||
});
|
||||
}
|
||||
|
||||
function createRoom() {
|
||||
const id = Math.random().toString(36).substring(7);
|
||||
window.location.search = `?room=${id}`;
|
||||
}
|
||||
|
||||
function startLocal() {
|
||||
window.location.search = `?mode=local`;
|
||||
}
|
||||
function createRoom() { window.location.search = `?room=${Math.random().toString(36).substring(7)}`; }
|
||||
function startLocal() { window.location.search = `?mode=local`; }
|
||||
|
||||
document.getElementById("restartBtn").onclick = () => {
|
||||
if (isLocal) initLocalState();
|
||||
@@ -416,45 +473,53 @@
|
||||
l.setAttribute("class", "edge"); svg.appendChild(l);
|
||||
});
|
||||
|
||||
// In local mode, "your role" is always the current turn's role
|
||||
const effectiveRole = isLocal ? state.turn : myRole;
|
||||
|
||||
const badge = document.getElementById("idBadge");
|
||||
badge.innerText = effectiveRole === "wolf" ? "WOLF" : "SCHAFE";
|
||||
badge.className = `id-box is-${effectiveRole}`;
|
||||
|
||||
const statusEl = document.getElementById("status");
|
||||
if (state.winner) statusEl.innerHTML = `SIEG: ${state.winner.toUpperCase()}!`;
|
||||
else statusEl.innerHTML = `${(isLocal || state.turn === myRole) ? 'DEIN ZUG' : 'WARTEN...'}<br><small>ZUG ${state.moveCount}/40</small>`;
|
||||
const banner = document.getElementById("victory-banner");
|
||||
const restartBtn = document.getElementById("restartBtn");
|
||||
|
||||
if (state.winner) {
|
||||
banner.classList.remove("hidden");
|
||||
const winMsg = state.winner === "wolf" ? "WOLF GEWINNT!" : "SCHAFE GEWINNEN!";
|
||||
document.getElementById("winner-text").innerText = winMsg;
|
||||
document.getElementById("winner-text").style.color = state.winner === "wolf" ? "var(--wolf)" : "var(--sheep)";
|
||||
statusEl.innerHTML = "ENDE";
|
||||
restartBtn.classList.add("restart-pulse");
|
||||
} else {
|
||||
banner.classList.add("hidden");
|
||||
restartBtn.classList.remove("restart-pulse");
|
||||
statusEl.innerHTML = `${(isLocal || state.turn === myRole) ? 'DEIN ZUG' : 'WARTEN...'}<br><small>ZUG ${state.moveCount}/40</small>`;
|
||||
}
|
||||
|
||||
for (let i = 0; i <= 10; i++) {
|
||||
const [x, y] = pos[i];
|
||||
const isWolf = state.wolf === i;
|
||||
const isSheep = state.sheep.includes(i);
|
||||
const type = isWolf ? "wolf" : (isSheep ? "sheep" : "empty");
|
||||
const isWinnerPiece = (state.winner === "wolf" && isWolf) || (state.winner === "sheep" && isSheep);
|
||||
const isPossible = selected !== null && (effectiveRole === "wolf" ? bWolf[selected] : bSheep[selected]).includes(i) && !isWolf && !isSheep;
|
||||
|
||||
const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
||||
g.onclick = () => {
|
||||
if (!isLocal && (state.turn !== myRole || state.winner)) return;
|
||||
if (isLocal && state.winner) return;
|
||||
|
||||
const isMine = (effectiveRole === "wolf" && isWolf) || (effectiveRole === "sheep" && isSheep);
|
||||
if (isMine) {
|
||||
selected = i;
|
||||
} else if (isPossible) {
|
||||
if (isMine) selected = i;
|
||||
else if (isPossible) {
|
||||
if (isLocal) handleLocalMove(selected, i);
|
||||
else ws.send(JSON.stringify({ from: selected, to: i }));
|
||||
selected = null;
|
||||
} else {
|
||||
selected = null;
|
||||
}
|
||||
} else selected = null;
|
||||
render();
|
||||
};
|
||||
|
||||
const c = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
||||
c.setAttribute("cx", x); c.setAttribute("cy", y); c.setAttribute("r", 25);
|
||||
c.setAttribute("class", `node-circle ${type} ${selected === i ? 'selected' : ''} ${isPossible ? 'possible' : ''}`);
|
||||
c.setAttribute("class", `node-circle ${type} ${selected === i ? 'selected' : ''} ${isPossible ? 'possible' : ''} ${isWinnerPiece ? 'winner-glow' : ''}`);
|
||||
g.appendChild(c);
|
||||
|
||||
const t = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
||||
@@ -466,9 +531,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Copy logic
|
||||
document.getElementById("copyBtn").onclick = async () => {
|
||||
const url = window.location.href.split('&')[0].split('?')[0] + `?room=${roomId}`;
|
||||
const url = window.location.origin + window.location.pathname + `?room=${roomId}`;
|
||||
try { await navigator.clipboard.writeText(url); showToast(); } catch (err) { }
|
||||
};
|
||||
function showToast() { const t = document.getElementById("toast"); t.className = "show"; setTimeout(() => { t.className = ""; }, 3000); }
|
||||
|
||||
Reference in New Issue
Block a user