guess screen schöner
parent
88c1547d59
commit
acaed6c73e
|
|
@ -117,7 +117,7 @@ public class GameController {
|
||||||
private void startRound(Context ctx) {
|
private void startRound(Context ctx) {
|
||||||
String gameId = ctx.pathParam("gameId");
|
String gameId = ctx.pathParam("gameId");
|
||||||
ctx.json(Map.of("status", "ok"));
|
ctx.json(Map.of("status", "ok"));
|
||||||
webSocketHandler.broadcastRoundStart(gameId);
|
webSocketHandler.broadcastRoundStart(gameId,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void guess(Context ctx) {
|
private void guess(Context ctx) {
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@
|
||||||
if (!allTracks.isEmpty()) {
|
if (!allTracks.isEmpty()) {
|
||||||
service.startRound(gameId, allTracks);
|
service.startRound(gameId, allTracks);
|
||||||
}
|
}
|
||||||
broadcastRoundStart(gameId);
|
broadcastRoundStart(gameId, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -147,11 +147,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
service.startRound(gameId, allTracks);
|
service.startRound(gameId, allTracks);
|
||||||
broadcastRoundStart(gameId);
|
broadcastRoundStart(gameId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Broadcastet den Runden-Start (Song + Optionen) an alle Clients. */
|
/** Broadcastet den Runden-Start (Song + Optionen) an alle Clients. */
|
||||||
public void broadcastRoundStart(String gameId) {
|
public void broadcastRoundStart(String gameId, boolean initial) {
|
||||||
var game = service.getOrCreateGame(gameId);
|
var game = service.getOrCreateGame(gameId);
|
||||||
List<String> opts = game.players();
|
List<String> opts = game.players();
|
||||||
String songUri = game.currentSong();
|
String songUri = game.currentSong();
|
||||||
|
|
@ -163,7 +163,8 @@
|
||||||
"ownerOptions", opts,
|
"ownerOptions", opts,
|
||||||
"songUri", songUri,
|
"songUri", songUri,
|
||||||
"allTracks", allTracks,
|
"allTracks", allTracks,
|
||||||
"trackInfos", trackInfos
|
"trackInfos", trackInfos,
|
||||||
|
"initial", initial
|
||||||
));
|
));
|
||||||
broadcastToAll(gameId, msg);
|
broadcastToAll(gameId, msg);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
<style>
|
<style>
|
||||||
:root{
|
:root{
|
||||||
--bg:#121212; --card:#181818; --border:#282828; --text:#fff; --muted:#b3b3b3;
|
--bg:#121212; --card:#181818; --border:#282828; --text:#fff; --muted:#b3b3b3;
|
||||||
--accent:#1db954; --accent-press:#169e47; --glow:rgba(29,185,84,.25);
|
--accent: #ffffff; --accent-press:#169e47; --glow:rgba(29,185,84,.25);
|
||||||
--radius:16px; --shadow:0 10px 30px rgba(0,0,0,.35)
|
--radius:16px; --shadow:0 10px 30px rgba(0,0,0,.35)
|
||||||
}
|
}
|
||||||
*{box-sizing:border-box}
|
*{box-sizing:border-box}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
<style>
|
<style>
|
||||||
:root{
|
:root{
|
||||||
--bg:#121212; --elev:#181818; --border:#282828; --text:#fff; --muted:#b3b3b3;
|
--bg:#121212; --elev:#181818; --border:#282828; --text:#fff; --muted:#b3b3b3;
|
||||||
--accent:#1db954; --accent-press:#169e47; --glow:rgba(29,185,84,.25);
|
--accent: #ffffff; --accent-press:#169e47; --glow:rgba(29,185,84,.25);
|
||||||
--radius:16px; --shadow:0 10px 30px rgba(0,0,0,.35);
|
--radius:16px; --shadow:0 10px 30px rgba(0,0,0,.35);
|
||||||
}
|
}
|
||||||
*{box-sizing:border-box}
|
*{box-sizing:border-box}
|
||||||
|
|
@ -152,6 +152,16 @@
|
||||||
.wedge.disabled { pointer-events:none; opacity:.85; }
|
.wedge.disabled { pointer-events:none; opacity:.85; }
|
||||||
.wedge-label { fill:#fff; font-weight:700; font-size:35px; pointer-events:none; }
|
.wedge-label { fill:#fff; font-weight:700; font-size:35px; pointer-events:none; }
|
||||||
|
|
||||||
|
/* Zahl unter dem Namen im SVG */
|
||||||
|
.wedge-delta{
|
||||||
|
font-weight:900; font-size:35px; fill:#fff; pointer-events:none;
|
||||||
|
/* Lesbarkeit auf dunklem Hintergrund */
|
||||||
|
paint-order: stroke fill; stroke:#000; stroke-width:3px;
|
||||||
|
}
|
||||||
|
.wedge-delta.correct{ fill: var(--accent); }
|
||||||
|
.wedge-delta.wrong { fill: #ffffff; }
|
||||||
|
|
||||||
|
|
||||||
/* === Winner Overlay === */
|
/* === Winner Overlay === */
|
||||||
.win-overlay{position:fixed; inset:0; display:none; align-items:center; justify-content:center;
|
.win-overlay{position:fixed; inset:0; display:none; align-items:center; justify-content:center;
|
||||||
background: radial-gradient(1000px 600px at 50% -10%, rgba(29,185,84,.18), transparent 60%), rgba(0,0,0,.72);
|
background: radial-gradient(1000px 600px at 50% -10%, rgba(29,185,84,.18), transparent 60%), rgba(0,0,0,.72);
|
||||||
|
|
@ -187,6 +197,50 @@
|
||||||
border-color:var(--accent);
|
border-color:var(--accent);
|
||||||
box-shadow:0 0 0 4px var(--glow);
|
box-shadow:0 0 0 4px var(--glow);
|
||||||
}
|
}
|
||||||
|
/* === Round Recap (Ergebnis der Runde) === */
|
||||||
|
#result .recap{
|
||||||
|
border:1px solid var(--border); background:#0f0f0f;
|
||||||
|
border-radius:16px; padding:14px; box-shadow:var(--shadow);
|
||||||
|
animation:recap-pop .25s ease;
|
||||||
|
}
|
||||||
|
#result .recap-hd{
|
||||||
|
display:flex; align-items:center; justify-content:space-between;
|
||||||
|
margin-bottom:10px; font-weight:800; letter-spacing:.02em;
|
||||||
|
}
|
||||||
|
#result .recap-list{
|
||||||
|
list-style:none; margin:0; padding:0;
|
||||||
|
display:flex; flex-direction:column; gap:8px;
|
||||||
|
}
|
||||||
|
#result .recap-item{
|
||||||
|
display:flex; align-items:center; justify-content:space-between; gap:10px;
|
||||||
|
background:#101010; border:1px solid var(--border);
|
||||||
|
border-radius:12px; padding:10px 12px;
|
||||||
|
}
|
||||||
|
#result .recap-left{ display:flex; align-items:center; gap:12px; flex-wrap:wrap }
|
||||||
|
#result .recap-user{ font-weight:800 }
|
||||||
|
#result .chips{ display:flex; gap:6px; flex-wrap:wrap }
|
||||||
|
#result .chip{
|
||||||
|
font-weight:700; padding:6px 10px; border-radius:999px;
|
||||||
|
border:1px solid var(--border); background:#0f0f0f; color:#fff;
|
||||||
|
}
|
||||||
|
#result .chip.correct{
|
||||||
|
background:var(--accent); color:#0a0a0a; border-color:transparent;
|
||||||
|
box-shadow:0 0 0 4px var(--glow);
|
||||||
|
}
|
||||||
|
#result .chip.wrong{ background:#2a0c11; border-color:#7a1822 }
|
||||||
|
#result .chip.muted{ color:var(--muted) }
|
||||||
|
|
||||||
|
#result .delta{ min-width:64px; text-align:right; font-weight:900 }
|
||||||
|
#result .delta.positive{ color:var(--accent) }
|
||||||
|
#result .delta.negative{ color:#e22134 }
|
||||||
|
#result .delta.neutral{ color:#cfcfcf }
|
||||||
|
|
||||||
|
@keyframes recap-pop{
|
||||||
|
from{ transform:translateY(6px); opacity:.0 }
|
||||||
|
to{ transform:none; opacity:1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
<style>
|
<style>
|
||||||
:root{
|
:root{
|
||||||
--bg:#121212; --card:#181818; --border:#282828; --text:#fff;
|
--bg:#121212; --card:#181818; --border:#282828; --text:#fff;
|
||||||
--muted:#b3b3b3; --accent:#1db954; --accent-press:#169e47; --glow:rgba(29,185,84,.25);
|
--muted:#b3b3b3; --accent: #ffffff; --accent-press:#169e47; --glow:rgba(29,185,84,.25);
|
||||||
--radius:16px; --shadow:0 10px 30px rgba(0,0,0,.35)
|
--radius:16px; --shadow:0 10px 30px rgba(0,0,0,.35)
|
||||||
}
|
}
|
||||||
*{box-sizing:border-box}
|
*{box-sizing:border-box}
|
||||||
|
|
|
||||||
|
|
@ -132,10 +132,51 @@ function wedgePath(cx, cy, r, a0, a1){
|
||||||
const largeArc = ((a1 - a0 + 360) % 360) > 180 ? 1 : 0;
|
const largeArc = ((a1 - a0 + 360) % 360) > 180 ? 1 : 0;
|
||||||
return `M ${cx} ${cy} L ${p0.x} ${p0.y} A ${r} ${r} 0 ${largeArc} 1 ${p1.x} ${p1.y} Z`;
|
return `M ${cx} ${cy} L ${p0.x} ${p0.y} A ${r} ${r} 0 ${largeArc} 1 ${p1.x} ${p1.y} Z`;
|
||||||
}
|
}
|
||||||
|
// Zahl unter dem Namen im Pie-Label setzen/entfernen
|
||||||
|
function setWedgeDeltaByUser(user, text, kind /* 'correct' | 'wrong' */) {
|
||||||
|
const svg = document.querySelector("#options svg.options-svg");
|
||||||
|
if (!svg) return;
|
||||||
|
|
||||||
|
const label = Array.from(svg.querySelectorAll("text.wedge-label"))
|
||||||
|
.find(t => t.getAttribute("data-user") === user);
|
||||||
|
if (!label) return;
|
||||||
|
|
||||||
|
// Entfernen?
|
||||||
|
if (!text) {
|
||||||
|
const old = Array.from(svg.querySelectorAll("text.wedge-delta"))
|
||||||
|
.find(t => t.getAttribute("data-user") === user);
|
||||||
|
if (old) old.remove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let delta = Array.from(svg.querySelectorAll("text.wedge-delta"))
|
||||||
|
.find(t => t.getAttribute("data-user") === user);
|
||||||
|
if (!delta) {
|
||||||
|
delta = document.createElementNS(SVGNS, "text");
|
||||||
|
delta.setAttribute("class", "wedge-delta");
|
||||||
|
delta.setAttribute("data-user", user);
|
||||||
|
delta.setAttribute("text-anchor", "middle");
|
||||||
|
delta.setAttribute("dominant-baseline", "hanging");
|
||||||
|
// Outline für bessere Lesbarkeit (Backup, falls CSS nicht greift)
|
||||||
|
delta.setAttribute("stroke", "#000");
|
||||||
|
delta.setAttribute("stroke-width", "3");
|
||||||
|
delta.setAttribute("paint-order", "stroke fill");
|
||||||
|
svg.appendChild(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
delta.setAttribute("x", label.getAttribute("x"));
|
||||||
|
delta.setAttribute("y", parseFloat(label.getAttribute("y")) + 18);
|
||||||
|
delta.textContent = text;
|
||||||
|
delta.classList.toggle("correct", kind === "correct");
|
||||||
|
delta.classList.toggle("wrong", kind === "wrong");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Auswahl-Set für Multi-Guess (pro Runde zurückgesetzt)
|
// Auswahl-Set für Multi-Guess (pro Runde zurückgesetzt)
|
||||||
let selectedGuesses = new Set();
|
let selectedGuesses = new Set();
|
||||||
let lastScores = null;
|
let lastScores = null;
|
||||||
|
let initializedScoreboard = false; // <- neu
|
||||||
|
|
||||||
|
|
||||||
function ensureSubmitBtn(optionsDiv) {
|
function ensureSubmitBtn(optionsDiv) {
|
||||||
let btn = document.getElementById("submitGuesses");
|
let btn = document.getElementById("submitGuesses");
|
||||||
|
|
@ -153,19 +194,24 @@ function ensureSubmitBtn(optionsDiv) {
|
||||||
|
|
||||||
|
|
||||||
// 6) Neue Runde anzeigen
|
// 6) Neue Runde anzeigen
|
||||||
async function handleRoundStart({ ownerOptions, songUri, trackInfos }) {
|
async function handleRoundStart({ ownerOptions, songUri, trackInfos, initial }) {
|
||||||
// UI zurücksetzen
|
// UI zurücksetzen
|
||||||
resultP.textContent = "";
|
resultP.textContent = "";
|
||||||
optionsDiv.innerHTML = "";
|
optionsDiv.innerHTML = "";
|
||||||
songEmbed.innerHTML = "";
|
songEmbed.innerHTML = "";
|
||||||
//scoreboard zurücksetzen
|
//scoreboard zurücksetzen
|
||||||
scoreboard.innerHTML = "";
|
//scoreboard.innerHTML = "";
|
||||||
selectedGuesses = new Set();
|
selectedGuesses = new Set();
|
||||||
ownerOptions.forEach(user => {
|
|
||||||
const li = document.createElement("li");
|
if (initial === true && scoreboard) {
|
||||||
li.textContent = `${user}: 0 Punkte`;
|
lastScores = null;
|
||||||
scoreboard.appendChild(li);
|
scoreboard.innerHTML = "";
|
||||||
});
|
(ownerOptions || []).forEach(u => {
|
||||||
|
const li = document.createElement("li");
|
||||||
|
li.innerHTML = `<span>${u}</span><b>0 Punkte</b>`;
|
||||||
|
scoreboard.appendChild(li);
|
||||||
|
});
|
||||||
|
}
|
||||||
const nextBtn = document.getElementById("nextRound");
|
const nextBtn = document.getElementById("nextRound");
|
||||||
if (nextBtn) {
|
if (nextBtn) {
|
||||||
nextBtn.hidden = true;
|
nextBtn.hidden = true;
|
||||||
|
|
@ -241,6 +287,7 @@ async function handleRoundStart({ ownerOptions, songUri, trackInfos }) {
|
||||||
text.setAttribute("x", P.x);
|
text.setAttribute("x", P.x);
|
||||||
text.setAttribute("y", P.y);
|
text.setAttribute("y", P.y);
|
||||||
text.setAttribute("class", "wedge-label");
|
text.setAttribute("class", "wedge-label");
|
||||||
|
text.setAttribute("data-user", user); // <— NEU: verbindet Label mit User
|
||||||
text.setAttribute("text-anchor", "middle");
|
text.setAttribute("text-anchor", "middle");
|
||||||
text.setAttribute("dominant-baseline", "middle");
|
text.setAttribute("dominant-baseline", "middle");
|
||||||
text.textContent = user;
|
text.textContent = user;
|
||||||
|
|
@ -332,78 +379,196 @@ function renderScoreboard(scores) {
|
||||||
//let lastScores = null;
|
//let lastScores = null;
|
||||||
|
|
||||||
|
|
||||||
|
// function handleRoundResult({ scores, guesses, owner }) {
|
||||||
|
// renderScoreboard(scores);
|
||||||
|
// lastScores = scores;
|
||||||
|
//
|
||||||
|
// (() => {
|
||||||
|
// // Button verstecken/disable und Eingaben sperren
|
||||||
|
// const sb = document.getElementById('submitGuesses');
|
||||||
|
// if (sb) { sb.disabled = true; sb.hidden = true; }
|
||||||
|
// document.querySelectorAll('#options .wedge').forEach(w => w.classList.add('disabled'));
|
||||||
|
// // lokale Auswahl leeren (optional)
|
||||||
|
// try { selectedGuesses.clear?.(); } catch(_) {}
|
||||||
|
// })();
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// const wedges = document.querySelectorAll("#options .wedge");
|
||||||
|
//
|
||||||
|
// // Owner-Slice immer grün
|
||||||
|
// wedges.forEach(w => {
|
||||||
|
// if (w.getAttribute("data-user") === owner) w.classList.add("correct");
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// // Nur die EIGENE Auswahl einfärben: rot wenn falsch, sonst grün
|
||||||
|
// // const myGuess = guesses?.[username];
|
||||||
|
// // if (myGuess) {
|
||||||
|
// // const myWedge = Array.from(wedges).find(w => w.getAttribute("data-user") === myGuess);
|
||||||
|
// // if (myWedge) {
|
||||||
|
// // if (myGuess === owner) {
|
||||||
|
// // myWedge.classList.add("correct");
|
||||||
|
// // } else {
|
||||||
|
// // myWedge.classList.add("wrong"); // nur dieser wird rot
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // }
|
||||||
|
// // } catch (e) {}
|
||||||
|
// const my = guesses?.[username];
|
||||||
|
// const myArr = Array.isArray(my) ? my : (typeof my === "string" ? [my] : []);
|
||||||
|
// if (myArr.length) {
|
||||||
|
// myArr.forEach(sel => {
|
||||||
|
// const w = Array.from(wedges).find(x => x.getAttribute("data-user") === sel);
|
||||||
|
// if (!w) return;
|
||||||
|
// if (sel === owner) w.classList.add("correct");
|
||||||
|
// else w.classList.add("wrong");
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// } catch (_) {}
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// // resultP.innerHTML = "";
|
||||||
|
// // Object.entries(guesses || {}).forEach(([user, guess]) => {
|
||||||
|
// // const correct = guess === owner;
|
||||||
|
// // const icon = correct ? "✅" : "❌";
|
||||||
|
// // const delta = correct ? "+3" : "-1";
|
||||||
|
// // const p = document.createElement("p");
|
||||||
|
// // p.textContent = `${icon} ${user} hat auf ${guess} getippt${correct ? " (richtig!)" : " (falsch)"} [${delta}]`;
|
||||||
|
// // resultP.appendChild(p);
|
||||||
|
// // });
|
||||||
|
// resultP.innerHTML = "";
|
||||||
|
// Object.entries(guesses || {}).forEach(([user, g]) => {
|
||||||
|
// const list = Array.isArray(g) ? g : (typeof g === "string" ? [g] : []);
|
||||||
|
// const correct = list.includes(owner);
|
||||||
|
// const wrongCount = list.length - (correct ? 1 : 0);
|
||||||
|
// //const delta = (correct ? 3 : 0) - wrongCount;
|
||||||
|
// const bonus = wrongCount === 0 ? 1 : 0; // fehlerfrei-Bonus
|
||||||
|
// const delta = (correct ? 3 : 0) - wrongCount + bonus;
|
||||||
|
// const icon = correct ? "✅" : "❌";
|
||||||
|
// const picks = list.length ? list.join(", ") : "—";
|
||||||
|
// const p = document.createElement("p");
|
||||||
|
// //p.textContent = `${icon} ${user} hat auf ${picks} getippt${correct ? " (richtig!)" : ""} [${delta >= 0 ? "+" : ""}${delta}]`;
|
||||||
|
// p.textContent = `${icon} ${user} hat auf ${picks} getippt${correct ? " (richtig!)" : ""}${bonus ? " (+1 Bonus)" : ""} [${delta >= 0 ? "+" : ""}${delta}]`;
|
||||||
|
// resultP.appendChild(p);
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// const nextBtn = document.getElementById("nextRound");
|
||||||
|
// nextBtn.hidden = false;
|
||||||
|
// nextBtn.disabled = false;
|
||||||
|
// nextBtn.onclick = () => {
|
||||||
|
// socket.send(JSON.stringify({ type: "next-round" }));
|
||||||
|
// nextBtn.hidden = true;
|
||||||
|
// nextBtn.disabled = true;
|
||||||
|
// resultP.textContent = "";
|
||||||
|
// startBtn.hidden = true;
|
||||||
|
// startBtn.disabled = true;
|
||||||
|
// roundArea.hidden = true;
|
||||||
|
// //const submitBtn = document.getElementById("submitGuesses");
|
||||||
|
// //if (submitBtn) submitBtn.hidden = true;
|
||||||
|
// const submitBtn = document.getElementById("submitGuesses");
|
||||||
|
// if (submitBtn) { submitBtn.hidden = true; submitBtn.disabled = true; }
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
// zeigt/entfernt den kleinen +3 / -1 Badge
|
||||||
|
function setWedgeDelta(wedgeEl, text) {
|
||||||
|
let tag = wedgeEl.querySelector('.delta-tag');
|
||||||
|
if (!text) { if (tag) tag.remove(); return; }
|
||||||
|
if (!tag) {
|
||||||
|
tag = document.createElement('span');
|
||||||
|
tag.className = 'delta-tag';
|
||||||
|
wedgeEl.appendChild(tag);
|
||||||
|
}
|
||||||
|
tag.textContent = text;
|
||||||
|
}
|
||||||
|
|
||||||
function handleRoundResult({ scores, guesses, owner }) {
|
function handleRoundResult({ scores, guesses, owner }) {
|
||||||
renderScoreboard(scores);
|
renderScoreboard(scores);
|
||||||
lastScores = scores;
|
lastScores = scores;
|
||||||
|
|
||||||
|
// Eingaben sperren & Submit ausblenden
|
||||||
(() => {
|
(() => {
|
||||||
// Button verstecken/disable und Eingaben sperren
|
|
||||||
const sb = document.getElementById('submitGuesses');
|
const sb = document.getElementById('submitGuesses');
|
||||||
if (sb) { sb.disabled = true; sb.hidden = true; }
|
if (sb) { sb.disabled = true; sb.hidden = true; }
|
||||||
document.querySelectorAll('#options .wedge').forEach(w => w.classList.add('disabled'));
|
document.querySelectorAll('#options .wedge').forEach(w => w.classList.add('disabled'));
|
||||||
// lokale Auswahl leeren (optional)
|
|
||||||
try { selectedGuesses.clear?.(); } catch(_) {}
|
try { selectedGuesses.clear?.(); } catch(_) {}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
// Wedges einfärben: Owner immer grün, eigene falsche rot
|
||||||
try {
|
try {
|
||||||
const wedges = document.querySelectorAll("#options .wedge");
|
const wedges = document.querySelectorAll("#options .wedge");
|
||||||
|
|
||||||
|
// (NEU) Alle alten Delta-Zahlen entfernen
|
||||||
|
const svg = document.querySelector("#options svg.options-svg");
|
||||||
|
if (svg) svg.querySelectorAll("text.wedge-delta").forEach(n => n.remove());
|
||||||
|
|
||||||
|
// Optional: global immer +3 am Owner anzeigen?
|
||||||
|
const SHOW_GLOBAL_DELTAS = false; // <- auf true setzen, wenn alle es sehen sollen
|
||||||
|
|
||||||
// Owner-Slice immer grün
|
// Owner-Slice immer grün
|
||||||
wedges.forEach(w => {
|
wedges.forEach(w => {
|
||||||
if (w.getAttribute("data-user") === owner) w.classList.add("correct");
|
if (w.getAttribute("data-user") === owner) {
|
||||||
|
w.classList.add("correct");
|
||||||
|
if (SHOW_GLOBAL_DELTAS) setWedgeDeltaByUser(owner, "+3", "correct"); // (NEU)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Nur die EIGENE Auswahl einfärben: rot wenn falsch, sonst grün
|
|
||||||
// const myGuess = guesses?.[username];
|
|
||||||
// if (myGuess) {
|
|
||||||
// const myWedge = Array.from(wedges).find(w => w.getAttribute("data-user") === myGuess);
|
|
||||||
// if (myWedge) {
|
|
||||||
// if (myGuess === owner) {
|
|
||||||
// myWedge.classList.add("correct");
|
|
||||||
// } else {
|
|
||||||
// myWedge.classList.add("wrong"); // nur dieser wird rot
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// } catch (e) {}
|
|
||||||
const my = guesses?.[username];
|
const my = guesses?.[username];
|
||||||
const myArr = Array.isArray(my) ? my : (typeof my === "string" ? [my] : []);
|
const myArr = Array.isArray(my) ? my : (typeof my === "string" ? [my] : []);
|
||||||
if (myArr.length) {
|
if (myArr.length) {
|
||||||
myArr.forEach(sel => {
|
myArr.forEach(sel => {
|
||||||
const w = Array.from(wedges).find(x => x.getAttribute("data-user") === sel);
|
const w = Array.from(wedges).find(x => x.getAttribute("data-user") === sel);
|
||||||
if (!w) return;
|
if (!w) return;
|
||||||
if (sel === owner) w.classList.add("correct");
|
|
||||||
else w.classList.add("wrong");
|
if (sel === owner) {
|
||||||
|
w.classList.add("correct");
|
||||||
|
setWedgeDeltaByUser(sel, "+3", "correct"); // (NEU)
|
||||||
|
} else {
|
||||||
|
w.classList.add("wrong");
|
||||||
|
setWedgeDeltaByUser(sel, "-1", "wrong"); // (NEU)
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
||||||
|
|
||||||
// resultP.innerHTML = "";
|
// Schöne Recap-Card rendern
|
||||||
// Object.entries(guesses || {}).forEach(([user, guess]) => {
|
const toChip = (text, cls="") => `<span class="chip ${cls}">${text}</span>`;
|
||||||
// const correct = guess === owner;
|
const listItems = Object.entries(guesses || {}).map(([user, g]) => {
|
||||||
// const icon = correct ? "✅" : "❌";
|
const arr = Array.isArray(g) ? g : (typeof g === "string" ? [g] : []);
|
||||||
// const delta = correct ? "+3" : "-1";
|
const correct = arr.includes(owner);
|
||||||
// const p = document.createElement("p");
|
const wrongCount = arr.length - (correct ? 1 : 0);
|
||||||
// p.textContent = `${icon} ${user} hat auf ${guess} getippt${correct ? " (richtig!)" : " (falsch)"} [${delta}]`;
|
const bonus = wrongCount === 0 ? 1 : 0; // fehlerfrei-Bonus
|
||||||
// resultP.appendChild(p);
|
|
||||||
// });
|
|
||||||
resultP.innerHTML = "";
|
|
||||||
Object.entries(guesses || {}).forEach(([user, g]) => {
|
|
||||||
const list = Array.isArray(g) ? g : (typeof g === "string" ? [g] : []);
|
|
||||||
const correct = list.includes(owner);
|
|
||||||
const wrongCount = list.length - (correct ? 1 : 0);
|
|
||||||
//const delta = (correct ? 3 : 0) - wrongCount;
|
|
||||||
const bonus = wrongCount === 0 ? 1 : 0; // fehlerfrei-Bonus
|
|
||||||
const delta = (correct ? 3 : 0) - wrongCount + bonus;
|
const delta = (correct ? 3 : 0) - wrongCount + bonus;
|
||||||
const icon = correct ? "✅" : "❌";
|
|
||||||
const picks = list.length ? list.join(", ") : "—";
|
|
||||||
const p = document.createElement("p");
|
|
||||||
//p.textContent = `${icon} ${user} hat auf ${picks} getippt${correct ? " (richtig!)" : ""} [${delta >= 0 ? "+" : ""}${delta}]`;
|
|
||||||
p.textContent = `${icon} ${user} hat auf ${picks} getippt${correct ? " (richtig!)" : ""}${bonus ? " (+1 Bonus)" : ""} [${delta >= 0 ? "+" : ""}${delta}]`;
|
|
||||||
resultP.appendChild(p);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
const chips = arr.length
|
||||||
|
? arr.map(sel => toChip(sel, sel === owner ? "correct" : "wrong")).join("")
|
||||||
|
: toChip("—", "muted");
|
||||||
|
|
||||||
|
const deltaCls = delta > 0 ? "positive" : delta < 0 ? "negative" : "neutral";
|
||||||
|
const deltaTxt = `${delta >= 0 ? "+" : ""}${delta}`;
|
||||||
|
|
||||||
|
return `
|
||||||
|
<li class="recap-item">
|
||||||
|
<div class="recap-left">
|
||||||
|
<div class="recap-user">${user}</div>
|
||||||
|
<div class="chips">${chips}</div>
|
||||||
|
</div>
|
||||||
|
<div class="delta ${deltaCls}">${deltaTxt}</div>
|
||||||
|
</li>`;
|
||||||
|
}).join("");
|
||||||
|
|
||||||
|
resultP.innerHTML = `
|
||||||
|
<div class="recap">
|
||||||
|
<div class="recap-hd">
|
||||||
|
<span>Rundenergebnis</span>
|
||||||
|
<span class="pill">Song von <b>${owner}</b></span>
|
||||||
|
</div>
|
||||||
|
<ul class="recap-list">${listItems}</ul>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Weiter-Button freigeben
|
||||||
const nextBtn = document.getElementById("nextRound");
|
const nextBtn = document.getElementById("nextRound");
|
||||||
nextBtn.hidden = false;
|
nextBtn.hidden = false;
|
||||||
nextBtn.disabled = false;
|
nextBtn.disabled = false;
|
||||||
|
|
@ -415,14 +580,13 @@ function handleRoundResult({ scores, guesses, owner }) {
|
||||||
startBtn.hidden = true;
|
startBtn.hidden = true;
|
||||||
startBtn.disabled = true;
|
startBtn.disabled = true;
|
||||||
roundArea.hidden = true;
|
roundArea.hidden = true;
|
||||||
//const submitBtn = document.getElementById("submitGuesses");
|
|
||||||
//if (submitBtn) submitBtn.hidden = true;
|
|
||||||
const submitBtn = document.getElementById("submitGuesses");
|
const submitBtn = document.getElementById("submitGuesses");
|
||||||
if (submitBtn) { submitBtn.hidden = true; submitBtn.disabled = true; }
|
if (submitBtn) { submitBtn.hidden = true; submitBtn.disabled = true; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 8) Spielende -> Start-Button zurück
|
// 8) Spielende -> Start-Button zurück
|
||||||
function handleGameEnd({ winner }) {
|
function handleGameEnd({ winner }) {
|
||||||
const overlay = document.getElementById("winnerOverlay");
|
const overlay = document.getElementById("winnerOverlay");
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
<style>
|
<style>
|
||||||
:root{
|
:root{
|
||||||
--bg:#121212; --card:#181818; --border:#282828; --text:#fff; --muted:#b3b3b3;
|
--bg:#121212; --card:#181818; --border:#282828; --text:#fff; --muted:#b3b3b3;
|
||||||
--accent:#1db954; --accent-press:#169e47; --glow:rgba(29,185,84,.25);
|
--accent: #ffffff; --accent-press:#169e47; --glow:rgba(29,185,84,.25);
|
||||||
--radius:16px; --shadow:0 10px 30px rgba(0,0,0,.35)
|
--radius:16px; --shadow:0 10px 30px rgba(0,0,0,.35)
|
||||||
}
|
}
|
||||||
*{box-sizing:border-box}
|
*{box-sizing:border-box}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue