320 lines
9.7 KiB
JavaScript
320 lines
9.7 KiB
JavaScript
let interval = 0;
|
|
let resetTime = 30;
|
|
let timer = resetTime * 2;
|
|
let race = 7;
|
|
let alternateBreak = false;
|
|
let player1 = 'Player 1';
|
|
let player2 = 'Player 2';
|
|
let activePlayer = 1;
|
|
let breakedPlayer = 1;
|
|
let element;
|
|
let audioCtx;
|
|
|
|
document.body.oncontextmenu = function () {
|
|
return false;
|
|
}; // i know this is useless. it was just distracting me ;)
|
|
|
|
/* get data from cookie if possible */
|
|
if (document.cookie.length) {
|
|
var cookies = document.cookie.split('; ').reduce((prev, current) => {
|
|
const [name, ...value] = current.split('=');
|
|
prev[name] = value.join('=');
|
|
return prev;
|
|
}, {});
|
|
resetTime = cookies.resetTime ?? resetTime;
|
|
timer = resetTime * 2;
|
|
updateDisplay();
|
|
race = cookies.race ?? race;
|
|
document.querySelector('.display-race').innerText = race;
|
|
player1 = cookies.player1 ?? player1;
|
|
document.querySelector('#player1 .player-name').innerText = player1;
|
|
player2 = cookies.player2 ?? player2;
|
|
document.querySelector('#player2 .player-name').innerText = player2;
|
|
alternateBreak = cookies.alternateBreak ? (cookies.alternateBreak == 'true') : alternateBreak;
|
|
}
|
|
|
|
document.getElementById('welcome-play').addEventListener('click', toggleWelcome);
|
|
|
|
// Player
|
|
function setPlayername() {
|
|
var name = prompt('Enter name:', this.innerText);
|
|
if (name) {
|
|
this.innerText = name;
|
|
}
|
|
player1 = document.querySelector('#player1 .player-name').innerText;
|
|
document.cookie = "player1=" + player1;
|
|
player2 = document.querySelector('#player2 .player-name').innerText;
|
|
document.cookie = "player2=" + player2;
|
|
}
|
|
|
|
document.querySelectorAll('.player-name').forEach(element => element.addEventListener('click', setPlayername));
|
|
|
|
function toggleActivePlayer() {
|
|
document.querySelector('#player' + activePlayer + ' .player-name').classList.remove('active');
|
|
activePlayer = activePlayer == 1 ? 2 : 1;
|
|
document.querySelector('#player' + activePlayer + ' .player-name').classList.add('active');
|
|
}
|
|
|
|
document.querySelectorAll('.player-name').forEach(function (element) {
|
|
onLongPress(element, toggleActivePlayer);
|
|
});
|
|
|
|
function increasePlayerScore() {
|
|
if (interval) {
|
|
toggleTimer();
|
|
}
|
|
timer = resetTime * 2;
|
|
updateDisplay();
|
|
|
|
this.innerText = Number.parseInt(this.innerText) + 1;
|
|
if (alternateBreak) {
|
|
breakedPlayer = breakedPlayer == 1 ? 2 : 1;
|
|
} else {
|
|
breakedPlayer = this.dataset.player;
|
|
}
|
|
if (activePlayer != breakedPlayer) {
|
|
toggleActivePlayer();
|
|
}
|
|
document.querySelector('.display-break.active').classList.remove('active');
|
|
document.getElementById("display-break-player" + breakedPlayer).classList.add('active');
|
|
}
|
|
|
|
document.querySelectorAll('td.player-score').forEach(element => element.addEventListener('click', increasePlayerScore));
|
|
|
|
function setPlayerScore(element) {
|
|
var score = prompt('Enter current score:', element.innerText)
|
|
element.innerText = score ? score : element.innerText;
|
|
}
|
|
|
|
document.querySelectorAll('.player-score').forEach(function (element) {
|
|
onLongPress(element, () => setPlayerScore(element));
|
|
});
|
|
|
|
function playerExtension() {
|
|
timer += resetTime;
|
|
updateDisplay();
|
|
this.classList.remove('active');
|
|
}
|
|
|
|
document.querySelectorAll('.player-extension').forEach(element => element.addEventListener('click', playerExtension));
|
|
document.querySelectorAll('.player-extension').forEach(function (element) {
|
|
onLongPress(element, () => element.classList.toggle('active'));
|
|
});
|
|
|
|
// Display
|
|
function toggleBreakedPlayer() {
|
|
document.querySelectorAll('.display-break').forEach(element => element.classList.toggle('active'));
|
|
breakedPlayer = breakedPlayer == 1 ? 2 : 1;
|
|
}
|
|
|
|
document.querySelectorAll('.display-break').forEach(function (element) {
|
|
onLongPress(element, () => toggleBreakedPlayer());
|
|
});
|
|
|
|
function resetTimer() {
|
|
timer = resetTime;
|
|
updateDisplay();
|
|
}
|
|
|
|
document.querySelector('.display-timer').addEventListener('click', resetTimer);
|
|
|
|
function setTimer(element) {
|
|
if (interval) {
|
|
toggleTimer();
|
|
}
|
|
var newTimer = prompt('Enter current time:', element.innerText);
|
|
element.innerText = newTimer ? newTimer : element.innerText;
|
|
timer = newTimer ? Number.parseInt(newTimer) : timer;
|
|
}
|
|
|
|
element = document.querySelector('.display-timer');
|
|
onLongPress(element, () => setTimer(element));
|
|
|
|
// Controls
|
|
function toggleTimer() {
|
|
if (timer == 0) {
|
|
return;
|
|
}
|
|
if (!interval) {
|
|
interval = setInterval(runTimer, 1000);
|
|
runTimer();
|
|
} else {
|
|
clearInterval(interval);
|
|
interval = null;
|
|
}
|
|
document.querySelector('#controls-play i').classList.toggle('fa-play');
|
|
document.querySelector('#controls-play i').classList.toggle('fa-pause');
|
|
}
|
|
|
|
document.getElementById('controls-play').addEventListener('click', toggleTimer);
|
|
|
|
function switchPlayer() {
|
|
resetTimer();
|
|
toggleActivePlayer();
|
|
if (!interval) {
|
|
toggleTimer();
|
|
}
|
|
}
|
|
|
|
document.getElementById('controls-switch').addEventListener('click', switchPlayer);
|
|
element = document.getElementById('controls-switch');
|
|
onLongPress(element, () => {
|
|
switchPlayer();
|
|
timer = resetTime * 2;
|
|
updateDisplay();
|
|
});
|
|
|
|
function toggleSettings() {
|
|
document.getElementById('main').classList.toggle('invisible');
|
|
document.getElementById('settings').classList.toggle('invisible');
|
|
document.getElementById('settings-time').value = resetTime;
|
|
document.getElementById('settings-race').value = race;
|
|
document.getElementById('settings-alternate').checked = alternateBreak;
|
|
}
|
|
|
|
document.getElementById('controls-settings').addEventListener('click', toggleSettings);
|
|
|
|
// Modals
|
|
// Welcome screen
|
|
function toggleWelcome() {
|
|
document.getElementById('main').classList.toggle('invisible');
|
|
document.getElementById('welcome').classList.toggle('invisible');
|
|
document.body.requestFullscreen();
|
|
screen.orientation.lock('landscape');
|
|
}
|
|
|
|
// settings
|
|
function resetGame() {
|
|
document.querySelectorAll('.player-score').forEach(element => element.innerText = 0);
|
|
if (activePlayer == 2) {
|
|
toggleActivePlayer();
|
|
}
|
|
if (breakedPlayer == 2) {
|
|
toggleBreakedPlayer();
|
|
}
|
|
if (interval) {
|
|
toggleTimer();
|
|
}
|
|
timer = resetTime * 2;
|
|
updateDisplay();
|
|
document.querySelectorAll('.player-extension').forEach(element => element.classList.add('active'));
|
|
document.body.requestFullscreen();
|
|
screen.orientation.lock('landscape');
|
|
toggleSettings();
|
|
}
|
|
|
|
document.getElementById('settings-reset').addEventListener('click', resetGame);
|
|
|
|
function setFullscreen() {
|
|
document.body.requestFullscreen();
|
|
screen.orientation.lock('landscape');
|
|
}
|
|
|
|
document.getElementById('settings-fullscreen').addEventListener('click', setFullscreen);
|
|
|
|
function toggleAbout() {
|
|
document.getElementById('about').classList.toggle('invisible');
|
|
document.getElementById('settings').classList.toggle('invisible');
|
|
}
|
|
document.getElementById('settings-about').addEventListener('click', toggleAbout);
|
|
document.getElementById('about-cancel').addEventListener('click', toggleAbout);
|
|
|
|
document.getElementById('settings-cancel').addEventListener('click', toggleSettings);
|
|
|
|
function saveSettings() {
|
|
var inputtime = document.getElementById('settings-time').value;
|
|
if (isNaN(inputtime) || inputtime <= 0) {
|
|
alert("Must input numbers > 0");
|
|
return false;
|
|
}
|
|
resetTime = Math.floor(inputtime)
|
|
document.cookie = "resetTime=" + resetTime;
|
|
resetTimer();
|
|
var newRace = document.getElementById('settings-race').value;
|
|
race = newRace ? newRace : race;
|
|
document.cookie = "race=" + race;
|
|
document.querySelector('.display-race').innerText = race;
|
|
alternateBreak = document.getElementById('settings-alternate').checked;
|
|
document.cookie = "alternateBreak=" + alternateBreak;
|
|
toggleSettings();
|
|
}
|
|
|
|
document.getElementById('settings-save').addEventListener('click', saveSettings);
|
|
|
|
// update timer + bar concurrently
|
|
function updateDisplay() {
|
|
document.querySelector('.display-timer').innerText = timer;
|
|
document.querySelector('.display-bar').style.background = "linear-gradient(90deg, rgba(0,0,0,1) -200%, rgba(255,0,0,1) " + (Math.ceil(100 - (timer / resetTime) * 300)) + "%, rgba(0,241,32,1) 100%)";
|
|
}
|
|
|
|
function runTimer() {
|
|
if (timer < 0) {
|
|
toggleTimer();
|
|
return;
|
|
}
|
|
updateDisplay();
|
|
timer--;
|
|
|
|
if (timer < 0) {
|
|
beep(1000, 1212);
|
|
toggleTimer();
|
|
return;
|
|
}
|
|
|
|
if (timer < 5) {
|
|
beep(100, 606);
|
|
}
|
|
}
|
|
|
|
// Helpers
|
|
function onLongPress(element, callback) {
|
|
let timer;
|
|
|
|
element.addEventListener('touchstart', () => {
|
|
timer = setTimeout(() => {
|
|
timer = null;
|
|
callback();
|
|
}, 500);
|
|
});
|
|
|
|
function cancel() {
|
|
clearTimeout(timer);
|
|
}
|
|
|
|
element.addEventListener('touchend', cancel);
|
|
element.addEventListener('touchmove', cancel);
|
|
}
|
|
|
|
//duration of the tone in milliseconds. Default is 500
|
|
//frequency of the tone in hertz. default is 440
|
|
//volume of the tone. Default is 1, off is 0.
|
|
//type of tone. Possible values are sine, square, sawtooth, triangle, and custom. Default is sine.
|
|
//callback to use on end of tone
|
|
function beep(duration, frequency, volume, type, callback) {
|
|
if (!audioCtx) {
|
|
audioCtx = new (window.AudioContext || window.webkitAudioContext || window.audioContext);
|
|
}
|
|
var oscillator = audioCtx.createOscillator();
|
|
var gainNode = audioCtx.createGain();
|
|
|
|
oscillator.connect(gainNode);
|
|
gainNode.connect(audioCtx.destination);
|
|
|
|
if (volume) {
|
|
gainNode.gain.value = volume;
|
|
}
|
|
if (frequency) {
|
|
oscillator.frequency.value = frequency;
|
|
}
|
|
if (type) {
|
|
oscillator.type = type;
|
|
}
|
|
if (callback) {
|
|
oscillator.onended = callback;
|
|
}
|
|
|
|
oscillator.start(audioCtx.currentTime);
|
|
oscillator.stop(audioCtx.currentTime + ((duration || 500) / 1000));
|
|
};
|
|
|