Compare commits
3 Commits
5435901143
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f08013ebaf | ||
|
|
8c3dd493bf | ||
|
|
cc07d21138 |
@@ -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 (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();
|
||||
}
|
||||
// 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';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
@@ -135,9 +135,157 @@
|
||||
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;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
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) {
|
||||
teamCount = count;
|
||||
@@ -151,12 +299,22 @@
|
||||
// Enable/Disable Inputs
|
||||
for (let i = 1; i <= 4; i++) {
|
||||
const input = document.getElementById(`team${i}`);
|
||||
const keyInput = document.getElementById(`key${i}`);
|
||||
|
||||
if (i <= count) {
|
||||
input.disabled = false;
|
||||
input.classList.remove('disabled');
|
||||
if (keyInput) {
|
||||
keyInput.disabled = false;
|
||||
keyInput.classList.remove('disabled');
|
||||
}
|
||||
} else {
|
||||
input.disabled = true;
|
||||
input.classList.add('disabled');
|
||||
if (keyInput) {
|
||||
keyInput.disabled = true;
|
||||
keyInput.classList.add('disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,12 +332,16 @@
|
||||
// Speichere in localStorage
|
||||
localStorage.setItem('team_names', JSON.stringify(teams));
|
||||
localStorage.setItem('team_count', teamCount);
|
||||
localStorage.setItem('buzzer_mode', buzzerMode);
|
||||
localStorage.setItem('key_mappings', JSON.stringify(keyMappings));
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
// Lade gespeicherte Werte
|
||||
const savedCount = parseInt(localStorage.getItem('team_count')) || 2;
|
||||
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
|
||||
setTeamCount(savedCount);
|
||||
@@ -190,6 +352,18 @@
|
||||
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>
|
||||
</head>
|
||||
@@ -206,6 +380,44 @@
|
||||
</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="team-input-group">
|
||||
<label class="team-label" for="team1">Team 1</label>
|
||||
|
||||
Reference in New Issue
Block a user