modified: templates/quiz_buzzer_multiplayer.html

This commit is contained in:
2025-11-15 18:14:58 +01:00
parent 575fcd3f8c
commit c488e5c4bc

View File

@@ -243,6 +243,9 @@
let decayRate = parseInt(localStorage.getItem('buzzer_decay_rate')) || 50; let decayRate = parseInt(localStorage.getItem('buzzer_decay_rate')) || 50;
let gameStarted = false; let gameStarted = false;
let currentBuzzer = null; let currentBuzzer = null;
let buzzedPlayers = []; // Liste der Spieler die schon gebuzzert haben
let canBuzz = false; // Kann man buzzern?
let pendingPoints = 0; // Punkte die noch nicht gezählt wurden
// Lade Team-Namen und Anzahl // Lade Team-Namen und Anzahl
const teamCount = parseInt(localStorage.getItem('team_count')) || 4; const teamCount = parseInt(localStorage.getItem('team_count')) || 4;
@@ -256,6 +259,14 @@
{ id: 4, name: teamNames[3] || 'Spieler 4', score: {{ player_scores[3] if player_scores else 0 }} } { id: 4, name: teamNames[3] || 'Spieler 4', score: {{ player_scores[3] if player_scores else 0 }} }
]; ];
// Leertaste zum Buzzern
document.addEventListener('keydown', function(e) {
if (e.code === 'Space' && canBuzz && !currentBuzzer) {
e.preventDefault();
triggerBuzz();
}
});
window.onSpotifyWebPlaybackSDKReady = () => { window.onSpotifyWebPlaybackSDKReady = () => {
const token = '{{ access_token }}'; const token = '{{ access_token }}';
const player = new Spotify.Player({ const player = new Spotify.Player({
@@ -330,6 +341,7 @@
gameStarted = true; gameStarted = true;
document.getElementById('startButton').classList.add('disabled'); document.getElementById('startButton').classList.add('disabled');
document.getElementById('startButton').style.cursor = 'wait'; document.getElementById('startButton').style.cursor = 'wait';
document.getElementById('buzzerHint').style.display = 'block';
const device_id = window.deviceId; const device_id = window.deviceId;
const startPosition = getOption('startPosition', 'start'); const startPosition = getOption('startPosition', 'start');
@@ -344,21 +356,19 @@
.then(() => { .then(() => {
console.log('Play command sent'); console.log('Play command sent');
document.getElementById('startButton').style.display = 'none'; document.getElementById('startButton').style.display = 'none';
// Aktiviere Buzzer canBuzz = true;
for (let i = 1; i <= 4; i++) {
document.getElementById(`buzzer${i}`).classList.remove('disabled');
}
}) })
.catch(error => console.error('Error starting playback:', error)); .catch(error => console.error('Error starting playback:', error));
} }
function startBuzzerTimer() { function startBuzzerTimer() {
startTime = Date.now(); startTime = Date.now();
canBuzz = true;
updateTimer(); updateTimer();
} }
function updateTimer() { function updateTimer() {
if (currentBuzzer) return; if (!canBuzz && currentBuzzer) return;
const elapsed = (Date.now() - startTime) / 1000; const elapsed = (Date.now() - startTime) / 1000;
const timerDisplay = document.getElementById('buzzerTimer'); const timerDisplay = document.getElementById('buzzerTimer');
@@ -394,11 +404,11 @@
return points; return points;
} }
function buzz(playerId) { function triggerBuzz() {
if (currentBuzzer !== null) return; if (currentBuzzer !== null) return;
if (!gameStarted || !startTime) return; if (!canBuzz) return;
currentBuzzer = playerId; canBuzz = false; // Verhindere weitere Buzzes
buzzTime = Date.now(); buzzTime = Date.now();
const elapsed = (buzzTime - startTime) / 1000; const elapsed = (buzzTime - startTime) / 1000;
@@ -408,17 +418,33 @@
window.spotifyPlayer.pause(); window.spotifyPlayer.pause();
} }
// Markiere Spieler // Zeige Spielerauswahl
document.getElementById(`player${playerId}`).classList.add('buzzed'); document.getElementById('playerSelection').style.display = 'block';
document.getElementById('currentPlayer').textContent = `${players[playerId - 1].name} hat gebuzzert!`; document.getElementById('currentPlayer').textContent = 'Wer hat gebuzzert?';
pendingPoints = calculatePoints(elapsed);
// Deaktiviere alle Buzzer }
for (let i = 1; i <= 4; i++) {
document.getElementById(`buzzer${i}`).classList.add('disabled'); function selectPlayer(playerId) {
if (buzzedPlayers.includes(playerId)) {
alert('Dieser Spieler hat bereits gebuzzert!');
return;
} }
currentBuzzer = playerId;
buzzedPlayers.push(playerId);
// Markiere Spieler
document.getElementById(`player${playerId}`).classList.add('buzzed');
document.getElementById('currentPlayer').textContent = `${players[playerId - 1].name} antwortet...`;
// Verstecke Spielerauswahl, zeige Antwortfeld
document.getElementById('playerSelection').style.display = 'none';
document.getElementById('answerSection').classList.add('active'); document.getElementById('answerSection').classList.add('active');
window.earnedPoints = calculatePoints(elapsed); window.earnedPoints = pendingPoints;
}
function buzz(playerId) {
selectPlayer(playerId);
} }
function setCorrectAnswer() { function setCorrectAnswer() {
@@ -486,6 +512,10 @@
const guess = document.getElementById('answerInput').value; const guess = document.getElementById('answerInput').value;
if (!guess) return; if (!guess) return;
// Disable input während Prüfung
document.getElementById('answerInput').disabled = true;
document.querySelector('button[onclick="checkAnswer()"]').disabled = true;
fetch('/check_answer_buzzer', { fetch('/check_answer_buzzer', {
method: 'POST', method: 'POST',
headers: { 'Content-Type': 'application/json' }, headers: { 'Content-Type': 'application/json' },
@@ -495,7 +525,8 @@
game_mode: currentGameMode, game_mode: currentGameMode,
playlist_id: '{{ playlist_id }}', playlist_id: '{{ playlist_id }}',
earned_points: window.earnedPoints, earned_points: window.earnedPoints,
player_id: currentBuzzer player_id: currentBuzzer,
apply_points: false // Punkte NICHT sofort anwenden
}) })
}) })
.then(response => response.json()) .then(response => response.json())
@@ -503,45 +534,95 @@
const resultContainer = document.getElementById('resultContainer'); const resultContainer = document.getElementById('resultContainer');
if (data.correct) { if (data.correct) {
players[currentBuzzer - 1].score += window.earnedPoints; // Speichere Punkte, aber wende sie noch NICHT an
updateScoreboard(); pendingPoints = window.earnedPoints;
resultContainer.innerHTML = ` resultContainer.innerHTML = `
<div style="background:linear-gradient(135deg, rgba(76, 175, 80, 0.2) 0%, rgba(56, 142, 60, 0.2) 100%); padding:20px; border-radius:12px; border:2px solid #4CAF50;"> <div style="background:linear-gradient(135deg, rgba(76, 175, 80, 0.2) 0%, rgba(56, 142, 60, 0.2) 100%); padding:20px; border-radius:12px; border:2px solid #4CAF50;">
<h3 style="color:#4CAF50; margin-bottom:10px;">✅ ${i18n.correct || 'Correct'}</h3> <h3 style="color:#4CAF50; margin-bottom:10px;">✅ ${i18n.correct || 'Richtig'}</h3>
<p style="font-size:1.5em; margin:10px 0;"><strong style="color:#1DB954;">+${window.earnedPoints}</strong> Punkte für ${players[currentBuzzer - 1].name}!</p> <p style="font-size:1.5em; margin:10px 0;"><strong style="color:#1DB954;">+${window.earnedPoints}</strong> Punkte für ${players[currentBuzzer - 1].name}!</p>
<div style="margin-top:20px; padding:20px; background:rgba(15,20,25,0.8); border-radius:12px;">
<h4 style="color:#1DB954; margin-bottom:15px;">Song Info:</h4>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Titel:</strong> <span style="color:#e0e0e0;">{{ track.name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Künstler:</strong> <span style="color:#e0e0e0;">{{ track.artists[0].name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Album:</strong> <span style="color:#e0e0e0;">{{ track.album.name | clean }}</span></p>
<a href="{{ track.external_urls.spotify }}" target="_blank" style="display:inline-block; margin-top:10px; padding:8px 16px; background:linear-gradient(135deg, #1DB954 0%, #1ed760 100%); color:#fff; text-decoration:none; border-radius:20px; font-weight:600;">Auf Spotify öffnen</a>
</div>
</div> </div>
`; `;
document.getElementById('nextQuestionBtn').style.display = 'inline-block';
document.getElementById('nextQuestionBtn').onclick = function() {
// Wende Punkte beim Klick auf "Nächster Song" an
players[currentBuzzer - 1].score += pendingPoints;
updateScoreboard();
window.location.href = '/quiz/{{ playlist_id }}?mode={{ game_mode }}&buzzer=1&local_multiplayer=1';
};
} else { } else {
// Minuspunkte: 25% der möglichen Punkte
const minusPoints = Math.floor(window.earnedPoints * 0.25);
pendingPoints = -minusPoints;
resultContainer.innerHTML = ` resultContainer.innerHTML = `
<div style="background:linear-gradient(135deg, rgba(244, 67, 54, 0.2) 0%, rgba(211, 47, 47, 0.2) 100%); padding:20px; border-radius:12px; border:2px solid #f44336;"> <div style="background:linear-gradient(135deg, rgba(244, 67, 54, 0.2) 0%, rgba(211, 47, 47, 0.2) 100%); padding:20px; border-radius:12px; border:2px solid #f44336;">
<h3 style="color:#f44336; margin-bottom:10px;">❌ ${i18n.incorrect || 'Incorrect'}</h3> <h3 style="color:#f44336; margin-bottom:10px;">❌ Falsch</h3>
<p style="font-size:1.1em; margin:10px 0;">${i18n.your_answer || 'Your answer'}: <strong style="color:#f44336;">${guess}</strong></p> <p style="font-size:1.1em; margin:10px 0;">Deine Antwort: <strong style="color:#f44336;">${guess}</strong></p>
<p style="font-size:1.1em; margin:10px 0;">${i18n.correct_answer || 'Correct answer'}: <strong style="color:#4CAF50;">${data.correct_answer}</strong></p> <p style="font-size:1.1em; margin:10px 0;"><strong style="color:#f44336;">-${minusPoints}</strong> Punkte für ${players[currentBuzzer - 1].name}</p>
<div style="margin-top:20px;">
<button class="btn" onclick="continueGame()" style="background:linear-gradient(135deg, #FFA500 0%, #FF8C00 100%);">🔄 Weiterbuzzern</button>
<button class="btn" onclick="showSolution()" style="background:linear-gradient(135deg, #1DB954 0%, #1ed760 100%);">📝 Lösung anzeigen</button>
</div>
</div> </div>
`; `;
} }
if (data.comparison) {
resultContainer.innerHTML += `
<div style="margin-top:20px; padding:20px; background:rgba(15,20,25,0.8); border-radius:12px;">
<h4 style="color:#1DB954; margin-bottom:15px;">${i18n.song_info || 'Song Info'}:</h4>
<p style="margin:8px 0;"><strong style="color:#1DB954;">${i18n.title || 'Title'}:</strong> <span style="color:#e0e0e0;">{{ track.name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">${i18n.artist || 'Artist'}:</strong> <span style="color:#e0e0e0;">{{ track.artists[0].name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">${i18n.album || 'Album'}:</strong> <span style="color:#e0e0e0;">{{ track.album.name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">${i18n.year || 'Year'}:</strong> <span style="color:#e0e0e0;">{{ track.album.release_date[:4] }}</span></p>
<a href="{{ track.external_urls.spotify }}" target="_blank" style="display:inline-block; margin-top:10px; padding:8px 16px; background:linear-gradient(135deg, #1DB954 0%, #1ed760 100%); color:#fff; text-decoration:none; border-radius:20px; font-weight:600; transition:all 0.3s ease;">${i18n.open_on_spotify || 'Open on Spotify'}</a>
</div>
`;
}
document.getElementById('nextQuestionBtn').style.display = 'inline-block';
}) })
.catch(error => { .catch(error => {
console.error('Error checking answer:', error); console.error('Error checking answer:', error);
}); });
} }
function continueGame() {
// Wende Minuspunkte an
players[currentBuzzer - 1].score += pendingPoints;
updateScoreboard();
// Reset für nächsten Buzzer
document.getElementById('answerSection').classList.remove('active');
document.getElementById('answerInput').value = '';
document.getElementById('answerInput').disabled = false;
document.querySelector('button[onclick="checkAnswer()"]').disabled = false;
document.getElementById('resultContainer').innerHTML = '';
document.getElementById(`player${currentBuzzer}`).classList.remove('buzzed');
currentBuzzer = null;
canBuzz = true;
// Musik weiterspielen
if (window.spotifyPlayer) {
window.spotifyPlayer.resume();
}
// Timer weiterlaufen lassen
buzzTimer = requestAnimationFrame(updateTimer);
}
function showSolution() {
// Wende Minuspunkte an
players[currentBuzzer - 1].score += pendingPoints;
updateScoreboard();
const resultContainer = document.getElementById('resultContainer');
resultContainer.innerHTML = `
<div style="margin-top:20px; padding:20px; background:rgba(15,20,25,0.8); border-radius:12px; border:2px solid #1DB954;">
<h4 style="color:#1DB954; margin-bottom:15px;">Lösung:</h4>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Titel:</strong> <span style="color:#e0e0e0;">{{ track.name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Künstler:</strong> <span style="color:#e0e0e0;">{{ track.artists[0].name | clean }}</span></p>
<p style="margin:8px 0;"><strong style="color:#1DB954;">Album:</strong> <span style="color:#e0e0e0;">{{ track.album.name | clean }}</span></p>
<a href="{{ track.external_urls.spotify }}" target="_blank" style="display:inline-block; margin-top:10px; padding:8px 16px; background:linear-gradient(135deg, #1DB954 0%, #1ed760 100%); color:#fff; text-decoration:none; border-radius:20px; font-weight:600;">Auf Spotify öffnen</a>
</div>
`;
document.getElementById('nextQuestionBtn').style.display = 'inline-block';
}
function switchGameMode(mode) { function switchGameMode(mode) {
window.location.href = `/reset_quiz/{{ playlist_id }}?next_mode=${mode}&buzzer=1&local_multiplayer=1`; window.location.href = `/reset_quiz/{{ playlist_id }}?next_mode=${mode}&buzzer=1&local_multiplayer=1`;
} }
@@ -592,23 +673,35 @@
<div class="current-player" id="currentPlayer">Drücke START um zu beginnen</div> <div class="current-player" id="currentPlayer">Drücke START um zu beginnen</div>
<!-- Buzzer Buttons --> <!-- Buzzer Hint -->
<div class="buzzer-grid"> <div id="buzzerHint" style="text-align:center; font-size:1.5em; color:#1DB954; margin:20px 0; display:none;">
<button class="player-buzzer start" id="startButton" onclick="startGame()"> ⌨️ Drücke LEERTASTE zum Buzzern!
</div>
<!-- Player Selection (versteckt bis gebuzzert) -->
<div id="playerSelection" style="display:none; text-align:center; margin:30px 0;">
<h3 style="margin-bottom:20px; color:#1DB954;">Wer hat gebuzzert?</h3>
<div class="buzzer-grid">
<button class="player-buzzer" id="selectPlayer1" onclick="selectPlayer(1)">
Spieler 1
</button>
<button class="player-buzzer" id="selectPlayer2" onclick="selectPlayer(2)">
Spieler 2
</button>
<button class="player-buzzer" id="selectPlayer3" onclick="selectPlayer(3)">
Spieler 3
</button>
<button class="player-buzzer" id="selectPlayer4" onclick="selectPlayer(4)">
Spieler 4
</button>
</div>
</div>
<!-- START Button -->
<div style="text-align:center; margin:30px 0;">
<button class="player-buzzer start" id="startButton" onclick="startGame()" style="width:300px; height:200px; font-size:2em;">
▶️<br>START ▶️<br>START
</button> </button>
<button class="player-buzzer disabled" id="buzzer1" onclick="buzz(1)">
🔴<br>Spieler 1
</button>
<button class="player-buzzer disabled" id="buzzer2" onclick="buzz(2)">
🔴<br>Spieler 2
</button>
<button class="player-buzzer disabled" id="buzzer3" onclick="buzz(3)">
🔴<br>Spieler 3
</button>
<button class="player-buzzer disabled" id="buzzer4" onclick="buzz(4)">
🔴<br>Spieler 4
</button>
</div> </div>
<!-- Answer Section --> <!-- Answer Section -->