Skip to content

Commit

Permalink
Merge pull request #215 from JeliHacker/add_timer
Browse files Browse the repository at this point in the history
Add timer
  • Loading branch information
geoffrey-wu authored Oct 12, 2023
2 parents 6a9d93f + 73daabb commit 2657b15
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 20 deletions.
23 changes: 23 additions & 0 deletions client/multiplayer/room.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@
<link href="/bootstrap/light.css" rel="stylesheet">
<link href="/bootstrap/dark.css" rel="stylesheet" id="custom-css">
<script src="/apply-theme.js"></script>

<style>
.timer {
background: linear-gradient(#444444, #333333);
display: block;
padding: 4px;
text-align: center;
font-size: 250%;
margin: 0;
}

.timer .fraction {
font-size: 50%;
}
</style>
</head>

<body>
Expand Down Expand Up @@ -76,6 +91,10 @@
</div>
<div class="row" id="info">
<div class="options col-12 col-lg-3 col-xxl-2 d-lg-block order-lg-1 mb-5" id="options">
<div class="timer" id="timer">
<span class="face">10</span><span class="fraction">.0</span>
</div>
<hr>
<div class="accordion" id="player-accordion"></div>
<hr>
<div class="form-floating mb-1">
Expand Down Expand Up @@ -156,6 +175,10 @@
<input class="form-check-input" id="toggle-rebuzz" type="checkbox" role="switch">
<label class="form-check-label" for="toggle-rebuzz">Allow rebuzzes</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" id="toggle-timer" type="checkbox" role="switch" checked disabled>
<label class="form-check-label" for="toggle-timer">Enable timer</label>
</div>
<p class="mb-1 text-muted" id="private-chat-warning"><i>chat is disabled in public rooms</i></p>
</div>
</div>
Expand Down
59 changes: 54 additions & 5 deletions client/multiplayer/room.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,10 @@ socket.onmessage = function (event) {
socketOnStart(data);
break;

case 'timer-update':
updateTimerDisplay(data.timeRemaining);
break;

case 'toggle-powermark-only':
logEvent(data.username, `${data.powermarkOnly ? 'enabled' : 'disabled'} powermark only`);
document.getElementById('toggle-powermark-only').checked = data.powermarkOnly;
Expand Down Expand Up @@ -174,10 +178,18 @@ socket.onmessage = function (event) {
document.getElementById('toggle-powermark-only').disabled = data.selectBySetName;
break;

case 'toggle-timer':
logEvent(data.username, `${data.timer ? 'enabled' : 'disabled'} the timer`);
document.getElementById('toggle-timer').checked = data.timer;
document.getElementById('timer').classList.toggle('d-none');
break;

case 'toggle-visibility':
logEvent(data.username, `made the room ${data.public ? 'public' : 'private'}`);
document.getElementById('toggle-visibility').checked = data.public;
document.getElementById('chat').disabled = data.public;
document.getElementById('toggle-timer').disabled = data.public;
document.getElementById('toggle-timer').checked = true;
break;

case 'update-categories':
Expand Down Expand Up @@ -263,6 +275,11 @@ const socketOnConnectionAcknowledged = async (message) => {
document.getElementById('chat').disabled = message.public;
document.getElementById('toggle-rebuzz').checked = message.rebuzz;
document.getElementById('toggle-skip').checked = message.skip;
document.getElementById('toggle-timer').checked = message.timer;
document.getElementById('toggle-timer').disabled = message.public;
if (!message.timer) {
document.getElementById('timer').classList.add('d-none');
}
document.getElementById('toggle-visibility').checked = message.public;
document.getElementById('reading-speed').value = message.readingSpeed;
document.getElementById('reading-speed-display').textContent = message.readingSpeed;
Expand Down Expand Up @@ -328,6 +345,10 @@ const socketOnEndOfSet = () => {
};

const socketOnGiveAnswer = async (message) => {
document.getElementById('answer-input').value = '';
document.getElementById('answer-input-group').classList.add('d-none');
document.getElementById('answer-input').blur();

const { userId, username, givenAnswer, directive, directedPrompt, score, celerity } = message;

logGiveAnswer(username, givenAnswer, false, directive);
Expand Down Expand Up @@ -448,6 +469,8 @@ const socketOnNext = (message) => {
document.getElementById('buzz').disabled = false;
document.getElementById('pause').textContent = 'Pause';
document.getElementById('pause').disabled = false;

updateTimerDisplay(100);
};

const socketOnNoQuestionsFound = () => {
Expand Down Expand Up @@ -686,14 +709,34 @@ function updateDifficulties(difficulties) {
}


function submitAnswer() {
const answer = document.getElementById('answer-input').value;

document.getElementById('answer-input').value = '';
document.getElementById('answer-input-group').classList.add('d-none');
document.getElementById('answer-input').blur();

socket.send(JSON.stringify({
type: 'give-answer',
givenAnswer: answer,
}));
}


function updateTimerDisplay(time) {
const seconds = Math.floor(time / 10);
const tenths = time % 10;

document.querySelector('.timer .face').innerText = seconds;
document.querySelector('.timer .fraction').innerText = '.' + tenths;
}


document.getElementById('answer-form').addEventListener('submit', function (event) {
event.preventDefault();
event.stopPropagation();

const answer = document.getElementById('answer-input').value;
document.getElementById('answer-input').value = '';
document.getElementById('answer-input-group').classList.add('d-none');
document.getElementById('answer-input').blur();

socket.send(JSON.stringify({
type: 'give-answer',
Expand All @@ -713,7 +756,6 @@ document.getElementById('buzz').addEventListener('click', function () {
socket.send(JSON.stringify({ type: 'give-answer-live-update', message: '' }));
});


document.getElementById('category-modal').addEventListener('hidden.bs.modal', function () {
if (changedCategories) {
socket.send(JSON.stringify({ type: 'update-categories', categories: validCategories, subcategories: validSubcategories }));
Expand Down Expand Up @@ -788,7 +830,10 @@ document.getElementById('packet-number').addEventListener('change', function ()

document.getElementById('pause').addEventListener('click', function () {
this.blur();
socket.send(JSON.stringify({ type: 'pause' }));
let seconds = parseFloat(document.querySelector('.timer .face').innerText);
let tenths = parseFloat(document.querySelector('.timer .fraction').innerText);
let pausedTime = (seconds + tenths) * 10;
socket.send(JSON.stringify({ type: 'pause', pausedTime: pausedTime }));
});


Expand Down Expand Up @@ -845,6 +890,10 @@ document.getElementById('toggle-powermark-only').addEventListener('click', funct
socket.send(JSON.stringify({ type: 'toggle-powermark-only', powermarkOnly: this.checked }));
});

document.getElementById('toggle-timer').addEventListener('click', function () {
this.blur();
socket.send(JSON.stringify({ type: 'toggle-timer', timer: this.checked }));
});

document.getElementById('toggle-visibility').addEventListener('click', function () {
this.blur();
Expand Down
105 changes: 90 additions & 15 deletions server/TossupRoom.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class TossupRoom {
this.timeoutID = null;
this.buzzedIn = null;
this.buzzes = [];
this.liveAnswer = '';
this.paused = false;
this.queryingQuestion = false;
this.questionNumber = 0;
Expand Down Expand Up @@ -61,9 +62,16 @@ class TossupRoom {
readingSpeed: 50,
selectBySetName: false,
skip: false,
timer: true,
};

this.rateLimitExceeded = new Set();

this.timerInterval = null;
this.timeRemaining = 0;

this.DEAD_TIME_LIMIT = 5; // time to buzz after question is read
this.ANSWER_TIME_LIMIT = 10; // time to give answer after buzzing
}

connection(socket, userId, username) {
Expand Down Expand Up @@ -131,6 +139,7 @@ class TossupRoom {
rebuzz: this.settings.rebuzz,
selectBySetName: this.settings.selectBySetName,
skip: this.settings.skip,
timer: this.settings.timer,
}));

if (this.questionProgress > 0 && this.tossup?.question) {
Expand Down Expand Up @@ -213,6 +222,7 @@ class TossupRoom {
break;

case 'give-answer-live-update':
this.liveAnswer = message.message;
this.sendSocketMessage({
type: 'give-answer-live-update',
username: this.players[userId].username,
Expand Down Expand Up @@ -242,7 +252,7 @@ class TossupRoom {
break;

case 'pause':
this.pause(userId);
this.pause(userId, message.pausedTime);
break;

case 'reading-speed':
Expand Down Expand Up @@ -302,11 +312,25 @@ class TossupRoom {
});
break;

case 'toggle-timer':
if (this.settings.public) {
return;
}

this.settings.timer = message.timer;
this.sendSocketMessage({
type: 'toggle-timer',
timer: this.settings.timer,
username: this.players[userId].username,
});
break;

case 'toggle-visibility':
if (this.isPermanent)
break;

this.settings.public = message.public;
this.settings.timer = true;
this.sendSocketMessage({
type: 'toggle-visibility',
public: this.settings.public,
Expand Down Expand Up @@ -415,21 +439,26 @@ class TossupRoom {
userId: userId,
username: this.players[userId].username,
});
} else {
this.buzzedIn = userId;
this.buzzes.push(userId);
clearTimeout(this.timeoutID);
this.sendSocketMessage({
type: 'buzz',
userId: userId,
username: this.players[userId].username,
});

this.sendSocketMessage({
type: 'update-question',
word: '(#)',
});
return;
}

this.buzzedIn = userId;
this.buzzes.push(userId);
clearTimeout(this.timeoutID);
this.sendSocketMessage({
type: 'buzz',
userId: userId,
username: this.players[userId].username,
});

this.sendSocketMessage({
type: 'update-question',
word: '(#)',
});

this.startServerTimer(this.ANSWER_TIME_LIMIT * 10, () => {
this.giveAnswer(userId, this.liveAnswer);
});
}

createPlayer(userId) {
Expand All @@ -447,6 +476,13 @@ class TossupRoom {
}

giveAnswer(userId, givenAnswer) {
this.liveAnswer = '';
clearInterval(this.timerInterval);
this.sendSocketMessage({
type: 'timer-update',
timeRemaining: this.ANSWER_TIME_LIMIT * 10,
});

if (Object.keys(this.tossup).length === 0)
return;

Expand Down Expand Up @@ -476,6 +512,10 @@ class TossupRoom {
this.readQuestion(Date.now());
}
break;
case 'prompt':
this.startServerTimer(this.ANSWER_TIME_LIMIT * 10, () => {
this.giveAnswer(userId, this.liveAnswer);
});
}

this.sendSocketMessage({
Expand Down Expand Up @@ -523,6 +563,9 @@ class TossupRoom {

if (this.paused) {
clearTimeout(this.timeoutID);
clearInterval(this.timerInterval);
} else if (this.wordIndex >= this.questionSplit.length) {
this.startServerTimer(this.timeRemaining, this.revealQuestion.bind(this));
} else {
this.readQuestion(Date.now());
}
Expand All @@ -537,6 +580,7 @@ class TossupRoom {
async readQuestion(expectedReadTime) {
if (Object.keys(this.tossup).length === 0) return;
if (this.wordIndex >= this.questionSplit.length) {
this.startServerTimer(this.DEAD_TIME_LIMIT * 10, this.revealQuestion.bind(this));
return;
}

Expand Down Expand Up @@ -591,6 +635,37 @@ class TossupRoom {
socket.send(message);
}
}

/**
*
* @param {number} time
* @param {Function} callback - called when timer is up
* @returns
*/
startServerTimer(time, callback) {
if (this.settings.timer === false) {
return;
}

if (this.timerInterval) {
clearInterval(this.timerInterval);
}

this.timeRemaining = time;

this.timerInterval = setInterval(() => {
if (this.timeRemaining <= 0) {
clearInterval(this.timerInterval);
callback();
}

this.sendSocketMessage({
type: 'timer-update',
timeRemaining: this.timeRemaining,
});
this.timeRemaining--;
}, 100);
}
}

const tossupRooms = {};
Expand Down

0 comments on commit 2657b15

Please sign in to comment.