diff --git a/templates/quiz_buzzer_multiplayer.html b/templates/quiz_buzzer_multiplayer.html index b601264..7dbd639 100644 --- a/templates/quiz_buzzer_multiplayer.html +++ b/templates/quiz_buzzer_multiplayer.html @@ -255,6 +255,8 @@ // Lade Team-Namen und Anzahl const teamCount = parseInt(localStorage.getItem('team_count')) || 4; const teamNames = JSON.parse(localStorage.getItem('team_names') || '["Spieler 1", "Spieler 2", "Spieler 3", "Spieler 4"]'); + const buzzerMode = localStorage.getItem('buzzer_mode') || 'central'; + const keyMappings = JSON.parse(localStorage.getItem('key_mappings') || '{"1":"Q","2":"W","3":"E","4":"R"}'); // Spieler-Daten let players = [ @@ -264,15 +266,39 @@ { id: 4, name: teamNames[3] || 'Spieler 4', score: {{ player_scores[3] if player_scores else 0 }} } ]; - // Leertaste zum Starten/Buzzern, aber nicht in Eingabefeldern + // Tastatur-Events für beide Modi document.addEventListener('keydown', function(e) { const active = document.activeElement; const isInput = active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA'); - if (e.code === 'Space' && !isInput) { - e.preventDefault(); - if (!gameStarted) { + if (isInput) return; // Keine Aktionen in Eingabefeldern + + const key = e.key.toUpperCase(); + + if (!gameStarted) { + // Im persönlichen Modus: Nur die erste Spieler-Taste startet + if (buzzerMode === 'personal' && key === keyMappings['1']) { + e.preventDefault(); startGame(); - } else if (canBuzz && !currentBuzzer) { + } + // Im zentralen Modus: Leertaste startet + else if (buzzerMode === 'central' && e.code === 'Space') { + e.preventDefault(); + startGame(); + } + } else if (canBuzz && !currentBuzzer) { + // Persönlicher Modus: Jede Spieler-Taste buzzert direkt + if (buzzerMode === 'personal') { + for (let i = 1; i <= teamCount; i++) { + if (key === keyMappings[i.toString()] && !buzzedPlayers.includes(i)) { + e.preventDefault(); + triggerBuzzPersonal(i); + return; + } + } + } + // Zentraler Modus: Leertaste -> Spielerauswahl + else if (buzzerMode === 'central' && e.code === 'Space') { + e.preventDefault(); triggerBuzz(); } } @@ -339,6 +365,18 @@ } } } + + // Update Buzzer-Hint basierend auf Modus + const hintElement = document.getElementById('buzzerHint'); + if (buzzerMode === 'personal') { + let hintText = '⌨️ Buzzer-Tasten: '; + for (let i = 1; i <= teamCount; i++) { + hintText += `${players[i-1].name}=[${keyMappings[i.toString()]}] `; + } + hintElement.innerHTML = hintText; + } else { + hintElement.innerHTML = '⌨️ Drücke LEERTASTE zum Buzzern!'; + } } function updateScoreboard() { @@ -451,6 +489,49 @@ pendingPoints = points; } + function triggerBuzzPersonal(playerId) { + if (currentBuzzer !== null) return; + if (!canBuzz) return; + if (buzzedPlayers.includes(playerId)) { + alert(`${players[playerId - 1].name} hat bereits gebuzzert!`); + return; + } + + canBuzz = false; // Verhindere weitere Buzzes + buzzTime = Date.now(); + const elapsed = (buzzTime - startTime) / 1000; + + // Stoppe Timer-Updates + cancelAnimationFrame(buzzTimer); + + // Friere Timer-Anzeige ein + const timerDisplay = document.getElementById('buzzerTimer'); + const pointsDisplay = document.getElementById('pointsDisplay'); + timerDisplay.textContent = elapsed.toFixed(2) + 's'; + const points = calculatePoints(elapsed); + pointsDisplay.textContent = points + ' Punkte'; + + // Speichere die Zeit beim Buzzern für spätere Berechnung + window.pausedAt = Date.now(); + + if (window.spotifyPlayer) { + window.spotifyPlayer.pause(); + } + + // Direkt Spieler setzen (keine Auswahl nötig) + currentBuzzer = playerId; + buzzedPlayers.push(playerId); + pendingPoints = points; + + // Markiere Spieler + document.getElementById(`player${playerId}`).classList.add('buzzed'); + document.getElementById('currentPlayer').textContent = `${players[playerId - 1].name} antwortet...`; + + // Zeige Antwortfeld direkt (keine Spielerauswahl) + document.getElementById('answerSection').classList.add('active'); + window.earnedPoints = pendingPoints; + } + function selectPlayer(playerId) { if (buzzedPlayers.includes(playerId)) { alert('Dieser Spieler hat bereits gebuzzert!'); @@ -668,6 +749,14 @@ gracePeriod = parseInt(localStorage.getItem('buzzer_grace_period')) || 5; decayRate = parseInt(localStorage.getItem('buzzer_decay_rate')) || 50; document.getElementById('pointsDisplay').textContent = maxPoints + ' Punkte'; + + // Update Starttext basierend auf Modus + const currentPlayerText = document.getElementById('currentPlayer'); + if (buzzerMode === 'personal') { + currentPlayerText.textContent = `Drücke [${keyMappings['1']}] zum Starten`; + } else { + currentPlayerText.textContent = 'Drücke LEERTASTE zum Starten'; + } }; diff --git a/templates/team_setup.html b/templates/team_setup.html index eb7f823..9f1c191 100644 --- a/templates/team_setup.html +++ b/templates/team_setup.html @@ -135,9 +135,149 @@ text-align: center; margin-top: 30px; } + .buzzer-mode-section { + margin-bottom: 30px; + padding: 20px; + background: rgba(15, 20, 25, 0.5); + border-radius: 15px; + border: 2px solid rgba(29, 185, 84, 0.2); + } + .mode-label { + font-size: 1.2em; + margin-bottom: 15px; + color: #e0e0e0; + text-align: center; + } + .mode-buttons { + display: flex; + justify-content: center; + gap: 15px; + flex-wrap: wrap; + margin-bottom: 20px; + } + .mode-btn { + padding: 12px 25px; + border-radius: 12px; + border: 2px solid rgba(29, 185, 84, 0.3); + background: rgba(15, 20, 25, 0.8); + color: #e0e0e0; + font-size: 1em; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + } + .mode-btn:hover { + border-color: #1DB954; + transform: translateY(-2px); + } + .mode-btn.active { + background: linear-gradient(135deg, #1DB954 0%, #1ed760 100%); + border-color: #1DB954; + color: white; + box-shadow: 0 4px 15px rgba(29, 185, 84, 0.5); + } + .key-mapping-section { + display: none; + margin-top: 20px; + } + .key-mapping-section.active { + display: block; + } + .key-input-group { + display: flex; + align-items: center; + gap: 15px; + margin-bottom: 15px; + } + .key-label { + flex: 1; + font-size: 1em; + color: #e0e0e0; + } + .key-input { + flex: 1; + padding: 10px 15px; + border-radius: 8px; + border: 2px solid rgba(29, 185, 84, 0.3); + background: rgba(15, 20, 25, 0.9); + color: #1DB954; + font-size: 1.1em; + font-weight: bold; + text-align: center; + cursor: pointer; + transition: all 0.3s ease; + } + .key-input:focus { + outline: none; + border-color: #1DB954; + box-shadow: 0 0 10px rgba(29, 185, 84, 0.5); + } + .key-input.disabled { + opacity: 0.4; + cursor: not-allowed; + } + .info-text { + font-size: 0.9em; + color: #999; + text-align: center; + margin-top: 10px; + font-style: italic; + } @@ -206,6 +372,44 @@ +