Compare commits
3 Commits
5435901143
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f08013ebaf | ||
|
|
8c3dd493bf | ||
|
|
cc07d21138 |
@@ -255,6 +255,8 @@
|
|||||||
// 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;
|
||||||
const teamNames = JSON.parse(localStorage.getItem('team_names') || '["Spieler 1", "Spieler 2", "Spieler 3", "Spieler 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
|
// Spieler-Daten
|
||||||
let players = [
|
let players = [
|
||||||
@@ -264,15 +266,39 @@
|
|||||||
{ 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 Starten/Buzzern, aber nicht in Eingabefeldern
|
// Tastatur-Events für beide Modi
|
||||||
document.addEventListener('keydown', function(e) {
|
document.addEventListener('keydown', function(e) {
|
||||||
const active = document.activeElement;
|
const active = document.activeElement;
|
||||||
const isInput = active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA');
|
const isInput = active && (active.tagName === 'INPUT' || active.tagName === 'TEXTAREA');
|
||||||
if (e.code === 'Space' && !isInput) {
|
if (isInput) return; // Keine Aktionen in Eingabefeldern
|
||||||
e.preventDefault();
|
|
||||||
|
const key = e.key.toUpperCase();
|
||||||
|
|
||||||
if (!gameStarted) {
|
if (!gameStarted) {
|
||||||
|
// Im persönlichen Modus: Nur die erste Spieler-Taste startet
|
||||||
|
if (buzzerMode === 'personal' && key === keyMappings['1']) {
|
||||||
|
e.preventDefault();
|
||||||
startGame();
|
startGame();
|
||||||
|
}
|
||||||
|
// Im zentralen Modus: Leertaste startet
|
||||||
|
else if (buzzerMode === 'central' && e.code === 'Space') {
|
||||||
|
e.preventDefault();
|
||||||
|
startGame();
|
||||||
|
}
|
||||||
} else if (canBuzz && !currentBuzzer) {
|
} 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();
|
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() {
|
function updateScoreboard() {
|
||||||
@@ -451,6 +489,49 @@
|
|||||||
pendingPoints = points;
|
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) {
|
function selectPlayer(playerId) {
|
||||||
if (buzzedPlayers.includes(playerId)) {
|
if (buzzedPlayers.includes(playerId)) {
|
||||||
alert('Dieser Spieler hat bereits gebuzzert!');
|
alert('Dieser Spieler hat bereits gebuzzert!');
|
||||||
@@ -668,6 +749,14 @@
|
|||||||
gracePeriod = parseInt(localStorage.getItem('buzzer_grace_period')) || 5;
|
gracePeriod = parseInt(localStorage.getItem('buzzer_grace_period')) || 5;
|
||||||
decayRate = parseInt(localStorage.getItem('buzzer_decay_rate')) || 50;
|
decayRate = parseInt(localStorage.getItem('buzzer_decay_rate')) || 50;
|
||||||
document.getElementById('pointsDisplay').textContent = maxPoints + ' Punkte';
|
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';
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|||||||
@@ -135,9 +135,157 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 30px;
|
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;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
let teamCount = 2;
|
let teamCount = 2;
|
||||||
|
let buzzerMode = 'central'; // 'central' oder 'personal'
|
||||||
|
let keyMappings = {1: 'Q', 2: 'W', 3: 'E', 4: 'R'};
|
||||||
|
|
||||||
|
function setBuzzerMode(mode) {
|
||||||
|
buzzerMode = mode;
|
||||||
|
|
||||||
|
// Update aktive Button
|
||||||
|
document.querySelectorAll('.mode-btn').forEach(btn => {
|
||||||
|
btn.classList.remove('active');
|
||||||
|
});
|
||||||
|
document.getElementById(`mode-${mode}`).classList.add('active');
|
||||||
|
|
||||||
|
// Zeige/Verstecke Tastenauswahl
|
||||||
|
const keySection = document.getElementById('keyMappingSection');
|
||||||
|
if (mode === 'personal') {
|
||||||
|
keySection.classList.add('active');
|
||||||
|
} else {
|
||||||
|
keySection.classList.remove('active');
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem('buzzer_mode', mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setKeyForPlayer(playerNum) {
|
||||||
|
const input = document.getElementById(`key${playerNum}`);
|
||||||
|
if (input.disabled) return;
|
||||||
|
|
||||||
|
input.value = 'Drücke eine Taste...';
|
||||||
|
input.focus();
|
||||||
|
|
||||||
|
const handleKeyPress = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const key = e.key.toUpperCase();
|
||||||
|
|
||||||
|
// Entferne Event-Listener sofort
|
||||||
|
document.removeEventListener('keydown', handleKeyPress);
|
||||||
|
|
||||||
|
// Prüfe ob Taste bereits vergeben
|
||||||
|
let isUsed = false;
|
||||||
|
for (let i = 1; i <= 4; i++) {
|
||||||
|
if (i !== playerNum && keyMappings[i] === key) {
|
||||||
|
isUsed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isUsed) {
|
||||||
|
alert(`Die Taste "${key}" ist bereits vergeben!`);
|
||||||
|
input.value = keyMappings[playerNum];
|
||||||
|
input.blur();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
keyMappings[playerNum] = key;
|
||||||
|
input.value = key;
|
||||||
|
input.blur();
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('keydown', handleKeyPress);
|
||||||
|
}
|
||||||
|
|
||||||
function setTeamCount(count) {
|
function setTeamCount(count) {
|
||||||
teamCount = count;
|
teamCount = count;
|
||||||
@@ -151,12 +299,22 @@
|
|||||||
// Enable/Disable Inputs
|
// Enable/Disable Inputs
|
||||||
for (let i = 1; i <= 4; i++) {
|
for (let i = 1; i <= 4; i++) {
|
||||||
const input = document.getElementById(`team${i}`);
|
const input = document.getElementById(`team${i}`);
|
||||||
|
const keyInput = document.getElementById(`key${i}`);
|
||||||
|
|
||||||
if (i <= count) {
|
if (i <= count) {
|
||||||
input.disabled = false;
|
input.disabled = false;
|
||||||
input.classList.remove('disabled');
|
input.classList.remove('disabled');
|
||||||
|
if (keyInput) {
|
||||||
|
keyInput.disabled = false;
|
||||||
|
keyInput.classList.remove('disabled');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
input.disabled = true;
|
input.disabled = true;
|
||||||
input.classList.add('disabled');
|
input.classList.add('disabled');
|
||||||
|
if (keyInput) {
|
||||||
|
keyInput.disabled = true;
|
||||||
|
keyInput.classList.add('disabled');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,12 +332,16 @@
|
|||||||
// Speichere in localStorage
|
// Speichere in localStorage
|
||||||
localStorage.setItem('team_names', JSON.stringify(teams));
|
localStorage.setItem('team_names', JSON.stringify(teams));
|
||||||
localStorage.setItem('team_count', teamCount);
|
localStorage.setItem('team_count', teamCount);
|
||||||
|
localStorage.setItem('buzzer_mode', buzzerMode);
|
||||||
|
localStorage.setItem('key_mappings', JSON.stringify(keyMappings));
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
// Lade gespeicherte Werte
|
// Lade gespeicherte Werte
|
||||||
const savedCount = parseInt(localStorage.getItem('team_count')) || 2;
|
const savedCount = parseInt(localStorage.getItem('team_count')) || 2;
|
||||||
const savedNames = JSON.parse(localStorage.getItem('team_names') || '[]');
|
const savedNames = JSON.parse(localStorage.getItem('team_names') || '[]');
|
||||||
|
const savedMode = localStorage.getItem('buzzer_mode') || 'central';
|
||||||
|
const savedKeys = JSON.parse(localStorage.getItem('key_mappings') || '{"1":"Q","2":"W","3":"E","4":"R"}');
|
||||||
|
|
||||||
// Setze Team-Anzahl
|
// Setze Team-Anzahl
|
||||||
setTeamCount(savedCount);
|
setTeamCount(savedCount);
|
||||||
@@ -190,6 +352,18 @@
|
|||||||
document.getElementById(`team${index + 1}`).value = name;
|
document.getElementById(`team${index + 1}`).value = name;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Setze Buzzer-Modus
|
||||||
|
setBuzzerMode(savedMode);
|
||||||
|
|
||||||
|
// Setze Tasten
|
||||||
|
keyMappings = savedKeys;
|
||||||
|
for (let i = 1; i <= 4; i++) {
|
||||||
|
const keyInput = document.getElementById(`key${i}`);
|
||||||
|
if (keyInput) {
|
||||||
|
keyInput.value = keyMappings[i] || 'Q';
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
@@ -206,6 +380,44 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="buzzer-mode-section">
|
||||||
|
<div class="mode-label">🎮 Buzzer-Modus</div>
|
||||||
|
<div class="mode-buttons">
|
||||||
|
<button class="mode-btn active" id="mode-central" onclick="setBuzzerMode('central')">
|
||||||
|
Zentraler Modus<br>
|
||||||
|
<span style="font-size:0.85em; font-weight:normal;">(Eine Taste für alle)</span>
|
||||||
|
</button>
|
||||||
|
<button class="mode-btn" id="mode-personal" onclick="setBuzzerMode('personal')">
|
||||||
|
Persönlicher Modus<br>
|
||||||
|
<span style="font-size:0.85em; font-weight:normal;">(Eigene Taste pro Spieler)</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="key-mapping-section" id="keyMappingSection">
|
||||||
|
<div class="info-text">Klicke auf ein Feld und drücke die gewünschte Taste</div>
|
||||||
|
|
||||||
|
<div class="key-input-group">
|
||||||
|
<div class="key-label">Team 1 Buzzer:</div>
|
||||||
|
<input type="text" class="key-input" id="key1" value="Q" readonly onclick="setKeyForPlayer(1)">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="key-input-group">
|
||||||
|
<div class="key-label">Team 2 Buzzer:</div>
|
||||||
|
<input type="text" class="key-input" id="key2" value="W" readonly onclick="setKeyForPlayer(2)">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="key-input-group">
|
||||||
|
<div class="key-label">Team 3 Buzzer:</div>
|
||||||
|
<input type="text" class="key-input disabled" id="key3" value="E" readonly onclick="setKeyForPlayer(3)" disabled>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="key-input-group">
|
||||||
|
<div class="key-label">Team 4 Buzzer:</div>
|
||||||
|
<input type="text" class="key-input disabled" id="key4" value="R" readonly onclick="setKeyForPlayer(4)" disabled>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="teams-section">
|
<div class="teams-section">
|
||||||
<div class="team-input-group">
|
<div class="team-input-group">
|
||||||
<label class="team-label" for="team1">Team 1</label>
|
<label class="team-label" for="team1">Team 1</label>
|
||||||
|
|||||||
Reference in New Issue
Block a user