diff --git a/client/play/TossupBonusClient.js b/client/play/TossupBonusClient.js
index ca0e380bc..793571d12 100644
--- a/client/play/TossupBonusClient.js
+++ b/client/play/TossupBonusClient.js
@@ -2,7 +2,9 @@ import { BonusClientMixin } from './BonusClient.js';
import { TossupClientMixin } from './TossupClient.js';
import QuestionClient from './QuestionClient.js';
-export default class TossupBonusClient extends BonusClientMixin(TossupClientMixin(QuestionClient)) {
+export default class TossupBonusClient extends BonusClientMixin(
+ TossupClientMixin(QuestionClient)
+) {
constructor (room, userId, socket) {
super(room, userId, socket);
attachEventListeners(room, socket);
@@ -11,8 +13,10 @@ export default class TossupBonusClient extends BonusClientMixin(TossupClientMixi
onmessage (message) {
const data = JSON.parse(message);
switch (data.type) {
- case 'toggle-enable-bonuses': return this.toggleEnableBonuses(data);
- default: return super.onmessage(message);
+ case 'toggle-enable-bonuses':
+ return this.toggleEnableBonuses(data);
+ default:
+ return super.onmessage(message);
}
}
@@ -27,8 +31,13 @@ export default class TossupBonusClient extends BonusClientMixin(TossupClientMixi
}
function attachEventListeners (room, socket) {
- document.getElementById('toggle-enable-bonuses').addEventListener('click', function () {
- this.blur();
- socket.sendToServer({ type: 'toggle-enable-bonuses', enableBonuses: this.checked });
- });
+ document
+ .getElementById('toggle-enable-bonuses')
+ .addEventListener('click', function () {
+ this.blur();
+ socket.sendToServer({
+ type: 'toggle-enable-bonuses',
+ enableBonuses: this.checked
+ });
+ });
}
diff --git a/client/play/TossupClient.js b/client/play/TossupClient.js
index 8c62e6401..77698e11b 100644
--- a/client/play/TossupClient.js
+++ b/client/play/TossupClient.js
@@ -3,99 +3,125 @@ import QuestionClient from './QuestionClient.js';
import audio from '../audio/index.js';
import { MODE_ENUM } from '../../quizbowl/constants.js';
-export const TossupClientMixin = (ClientClass) => class extends ClientClass {
- constructor (room, userId, socket) {
- super(room, userId, socket);
- attachEventListeners(room, socket);
- }
-
- onmessage (message) {
- const data = JSON.parse(message);
- switch (data.type) {
- case 'buzz': return this.buzz(data);
- case 'end-current-tossup': return this.endCurrentTossup(data);
- case 'give-tossup-answer': return this.giveTossupAnswer(data);
- case 'pause': return this.pause(data);
- case 'reveal-tossup-answer': return this.revealTossupAnswer(data);
- case 'set-reading-speed': return this.setReadingSpeed(data);
- case 'start-next-tossup': return this.startNextTossup(data);
- case 'toggle-powermark-only': return this.togglePowermarkOnly(data);
- case 'toggle-rebuzz': return this.toggleRebuzz(data);
- case 'update-question': return this.updateQuestion(data);
- default: return super.onmessage(message);
+export const TossupClientMixin = (ClientClass) =>
+ class extends ClientClass {
+ constructor (room, userId, socket) {
+ super(room, userId, socket);
+ attachEventListeners(room, socket);
}
- }
- buzz ({ userId }) {
- document.getElementById('buzz').disabled = true;
- document.getElementById('next').disabled = true;
- document.getElementById('pause').disabled = true;
- if (userId === this.USER_ID && audio.soundEffects) { audio.buzz.play(); }
- }
+ onmessage (message) {
+ const data = JSON.parse(message);
+ switch (data.type) {
+ case 'buzz':
+ return this.buzz(data);
+ case 'end-current-tossup':
+ return this.endCurrentTossup(data);
+ case 'give-tossup-answer':
+ return this.giveTossupAnswer(data);
+ case 'pause':
+ return this.pause(data);
+ case 'reveal-tossup-answer':
+ return this.revealTossupAnswer(data);
+ case 'set-reading-speed':
+ return this.setReadingSpeed(data);
+ case 'start-next-tossup':
+ return this.startNextTossup(data);
+ case 'toggle-powermark-only':
+ return this.togglePowermarkOnly(data);
+ case 'toggle-rebuzz':
+ return this.toggleRebuzz(data);
+ case 'toggle-stop-on-power':
+ return this.toggleStopOnPower(data);
+ case 'update-question':
+ return this.updateQuestion(data);
+ default:
+ return super.onmessage(message);
+ }
+ }
+
+ buzz ({ userId }) {
+ document.getElementById('buzz').disabled = true;
+ document.getElementById('next').disabled = true;
+ document.getElementById('pause').disabled = true;
+ if (userId === this.USER_ID && audio.soundEffects) {
+ audio.buzz.play();
+ }
+ }
+
+ endCurrentTossup ({ starred, tossup }) {
+ addTossupGameCard({ starred, tossup });
+ }
+
+ giveTossupAnswer ({ directive, directedPrompt, score, userId }) {
+ super.giveAnswer({ directive, directedPrompt, score, userId });
+
+ if (directive !== 'prompt') {
+ document.getElementById('next').disabled = false;
+ }
+ }
+
+ pause ({ paused }) {
+ document.getElementById('pause').textContent = paused
+ ? 'Resume'
+ : 'Pause';
+ }
+
+ revealTossupAnswer ({ answer, question }) {
+ document.getElementById('question').innerHTML = question;
+ document.getElementById('answer').innerHTML = 'ANSWER: ' + answer;
+ document.getElementById('pause').disabled = true;
+ }
+
+ setMode ({ mode }) {
+ super.setMode({ mode });
+ switch (mode) {
+ case MODE_ENUM.SET_NAME:
+ document.getElementById('toggle-powermark-only').disabled = true;
+ document.getElementById('toggle-standard-only').disabled = true;
+ break;
+ case MODE_ENUM.RANDOM:
+ document.getElementById('toggle-powermark-only').disabled = false;
+ document.getElementById('toggle-standard-only').disabled = false;
+ break;
+ }
+ }
+
+ setReadingSpeed ({ readingSpeed }) {
+ document.getElementById('reading-speed').value = readingSpeed;
+ document.getElementById('reading-speed-display').textContent =
+ readingSpeed;
+ }
+
+ startNextTossup ({ tossup, packetLength }) {
+ this.startNextQuestion({ question: tossup, packetLength });
+ document.getElementById('buzz').textContent = 'Buzz';
+ document.getElementById('buzz').disabled = false;
+ document.getElementById('pause').textContent = 'Pause';
+ document.getElementById('pause').disabled = false;
+ this.room.tossup = tossup;
+ }
- endCurrentTossup ({ starred, tossup }) {
- addTossupGameCard({ starred, tossup });
- }
+ togglePowermarkOnly ({ powermarkOnly }) {
+ document.getElementById('toggle-powermark-only').checked = powermarkOnly;
+ }
- giveTossupAnswer ({ directive, directedPrompt, score, userId }) {
- super.giveAnswer({ directive, directedPrompt, score, userId });
+ toggleRebuzz ({ rebuzz }) {
+ document.getElementById('toggle-rebuzz').checked = rebuzz;
+ }
- if (directive !== 'prompt') {
- document.getElementById('next').disabled = false;
+ toggleStopOnPower ({ stopOnPower }) {
+ console.log('TossupClient.toggleStopOnPower called');
+ document.getElementById('toggle-stop-on-power').checked = stopOnPower;
}
- }
-
- pause ({ paused }) {
- document.getElementById('pause').textContent = paused ? 'Resume' : 'Pause';
- }
-
- revealTossupAnswer ({ answer, question }) {
- document.getElementById('question').innerHTML = question;
- document.getElementById('answer').innerHTML = 'ANSWER: ' + answer;
- document.getElementById('pause').disabled = true;
- }
-
- setMode ({ mode }) {
- super.setMode({ mode });
- switch (mode) {
- case MODE_ENUM.SET_NAME:
- document.getElementById('toggle-powermark-only').disabled = true;
- document.getElementById('toggle-standard-only').disabled = true;
- break;
- case MODE_ENUM.RANDOM:
- document.getElementById('toggle-powermark-only').disabled = false;
- document.getElementById('toggle-standard-only').disabled = false;
- break;
+
+ updateQuestion ({ word }) {
+ if (word === '(*)' || word === '[*]') {
+ return;
+ }
+ document.getElementById('question').innerHTML += word + ' ';
}
- }
-
- setReadingSpeed ({ readingSpeed }) {
- document.getElementById('reading-speed').value = readingSpeed;
- document.getElementById('reading-speed-display').textContent = readingSpeed;
- }
-
- startNextTossup ({ tossup, packetLength }) {
- this.startNextQuestion({ question: tossup, packetLength });
- document.getElementById('buzz').textContent = 'Buzz';
- document.getElementById('buzz').disabled = false;
- document.getElementById('pause').textContent = 'Pause';
- document.getElementById('pause').disabled = false;
- this.room.tossup = tossup;
- }
-
- togglePowermarkOnly ({ powermarkOnly }) {
- document.getElementById('toggle-powermark-only').checked = powermarkOnly;
- }
-
- toggleRebuzz ({ rebuzz }) {
- document.getElementById('toggle-rebuzz').checked = rebuzz;
- }
-
- updateQuestion ({ word }) {
- if (word === '(*)' || word === '[*]') { return; }
- document.getElementById('question').innerHTML += word + ' ';
- }
-};
+ };
function attachEventListeners (room, socket) {
document.getElementById('buzz').addEventListener('click', function () {
@@ -106,29 +132,58 @@ function attachEventListeners (room, socket) {
document.getElementById('pause').addEventListener('click', function () {
this.blur();
- const seconds = parseFloat(document.querySelector('.timer .face').textContent);
- const tenths = parseFloat(document.querySelector('.timer .fraction').textContent);
+ const seconds = parseFloat(
+ document.querySelector('.timer .face').textContent
+ );
+ const tenths = parseFloat(
+ document.querySelector('.timer .fraction').textContent
+ );
const pausedTime = (seconds + tenths) * 10;
socket.sendToServer({ type: 'pause', pausedTime });
});
- document.getElementById('reading-speed').addEventListener('change', function () {
- socket.sendToServer({ type: 'set-reading-speed', readingSpeed: this.value });
- });
-
- document.getElementById('reading-speed').addEventListener('input', function () {
- document.getElementById('reading-speed-display').textContent = this.value;
- });
-
- document.getElementById('toggle-powermark-only').addEventListener('click', function () {
- this.blur();
- socket.sendToServer({ type: 'toggle-powermark-only', powermarkOnly: this.checked });
- });
-
- document.getElementById('toggle-rebuzz').addEventListener('click', function () {
- this.blur();
- socket.sendToServer({ type: 'toggle-rebuzz', rebuzz: this.checked });
- });
+ document
+ .getElementById('reading-speed')
+ .addEventListener('change', function () {
+ socket.sendToServer({
+ type: 'set-reading-speed',
+ readingSpeed: this.value
+ });
+ });
+
+ document
+ .getElementById('reading-speed')
+ .addEventListener('input', function () {
+ document.getElementById('reading-speed-display').textContent = this.value;
+ });
+
+ document
+ .getElementById('toggle-powermark-only')
+ .addEventListener('click', function () {
+ this.blur();
+ socket.sendToServer({
+ type: 'toggle-powermark-only',
+ powermarkOnly: this.checked
+ });
+ });
+
+ document
+ .getElementById('toggle-rebuzz')
+ .addEventListener('click', function () {
+ this.blur();
+ socket.sendToServer({ type: 'toggle-rebuzz', rebuzz: this.checked });
+ });
+
+ document
+ .getElementById('toggle-stop-on-power')
+ .addEventListener('click', function () {
+ console.log('stop-on-power checkbox has been checked');
+ this.blur();
+ socket.sendToServer({
+ type: 'toggle-stop-on-power',
+ stopOnPower: this.checked
+ });
+ });
}
const TossupClient = TossupClientMixin(QuestionClient);
diff --git a/client/play/mp/MultiplayerTossupBonusClient.js b/client/play/mp/MultiplayerTossupBonusClient.js
index c6de9bf5c..88ff32899 100644
--- a/client/play/mp/MultiplayerTossupBonusClient.js
+++ b/client/play/mp/MultiplayerTossupBonusClient.js
@@ -39,6 +39,7 @@ export const MultiplayerClientMixin = (ClientClass) => class extends ClientClass
case 'toggle-lock': return this.toggleLock(data);
case 'toggle-login-required': return this.toggleLoginRequired(data);
case 'toggle-public': return this.togglePublic(data);
+ case 'toggle-stop-on-power': return this.toggleStopOnPower(data);
default: return super.onmessage(event.data);
}
}
@@ -712,6 +713,10 @@ export const MultiplayerClientMixin = (ClientClass) => class extends ClientClass
});
}
+ stopOnPower ({ stopOnPower, username }) {
+ this.logEventConditionally(username, `${stopOnPower ? 'enabled' : 'disabled'} stop on power`);
+ }
+
vkInit ({ targetUsername, threshold }) {
this.logEventConditionally(`A votekick has been started against user ${targetUsername} and needs ${threshold} votes to succeed.`);
}
diff --git a/client/play/mp/room.html b/client/play/mp/room.html
index 2a8ecca22..fa4a5637f 100644
--- a/client/play/mp/room.html
+++ b/client/play/mp/room.html
@@ -185,6 +185,10 @@
+
+
+
+
diff --git a/client/play/mp/room.jsx b/client/play/mp/room.jsx
index 66546c0f8..ad3c332d8 100644
--- a/client/play/mp/room.jsx
+++ b/client/play/mp/room.jsx
@@ -23,16 +23,20 @@ const room = {
showingOffline: false,
teams: {},
tossup: {},
- username: window.localStorage.getItem('multiplayer-username') || getRandomName()
+ username:
+ window.localStorage.getItem('multiplayer-username') || getRandomName()
};
let oldCategories = JSON.stringify(room.categoryManager.export());
-const ROOM_NAME = decodeURIComponent(window.location.pathname.split('/').at(-1));
+const ROOM_NAME = decodeURIComponent(
+ window.location.pathname.split('/').at(-1)
+);
const USER_ID = window.localStorage.getItem('USER_ID') || 'unknown';
const socket = new window.WebSocket(
- window.location.href.replace('http', 'ws').split('?')[0] + '?' +
+ window.location.href.replace('http', 'ws').split('?')[0] +
+ '?' +
new URLSearchParams({
...Object.fromEntries(new URLSearchParams(window.location.search)),
roomName: ROOM_NAME,
@@ -52,7 +56,9 @@ socket.sendToServer = (data) => socket.send(JSON.stringify(data));
socket.onclose = function (event) {
const { code } = event;
- if (code !== 3000) { window.alert('Disconnected from server'); }
+ if (code !== 3000) {
+ window.alert('Disconnected from server');
+ }
clearInterval(PING_INTERVAL_ID);
};
@@ -60,7 +66,12 @@ const client = new MultiplayerTossupBonusClient(room, USER_ID, socket);
socket.onmessage = (message) => client.onmessage(message);
document.getElementById('answer-input').addEventListener('input', function () {
- socket.send(JSON.stringify({ type: 'give-answer-live-update', givenAnswer: this.value }));
+ socket.send(
+ JSON.stringify({
+ type: 'give-answer-live-update',
+ givenAnswer: this.value
+ })
+ );
});
document.getElementById('chat').addEventListener('click', function () {
@@ -70,55 +81,86 @@ document.getElementById('chat').addEventListener('click', function () {
socket.send(JSON.stringify({ type: 'chat-live-update', message: '' }));
});
-document.getElementById('chat-form').addEventListener('submit', function (event) {
- event.preventDefault();
- event.stopPropagation();
+document
+ .getElementById('chat-form')
+ .addEventListener('submit', function (event) {
+ event.preventDefault();
+ event.stopPropagation();
- const message = document.getElementById('chat-input').value;
- document.getElementById('chat-input').value = '';
- document.getElementById('chat-input-group').classList.add('d-none');
- document.getElementById('chat-input').blur();
+ const message = document.getElementById('chat-input').value;
+ document.getElementById('chat-input').value = '';
+ document.getElementById('chat-input-group').classList.add('d-none');
+ document.getElementById('chat-input').blur();
- socket.send(JSON.stringify({ type: 'chat', message }));
-});
+ socket.send(JSON.stringify({ type: 'chat', message }));
+ });
document.getElementById('chat-input').addEventListener('input', function () {
- socket.send(JSON.stringify({ type: 'chat-live-update', message: this.value }));
+ socket.send(
+ JSON.stringify({ type: 'chat-live-update', message: this.value })
+ );
});
const styleSheet = document.createElement('style');
-styleSheet.textContent = room.showingOffline ? '' : '.offline { display: none; }';
+styleSheet.textContent = room.showingOffline
+ ? ''
+ : '.offline { display: none; }';
document.head.appendChild(styleSheet);
-document.getElementById('toggle-offline-players').addEventListener('click', function () {
- room.showingOffline = this.checked;
- this.blur();
- if (room.showingOffline) {
- styleSheet.textContent = '';
- } else {
- styleSheet.textContent = '.offline { display: none; }';
- }
-});
-
-document.getElementById('toggle-controlled').addEventListener('click', function () {
- this.blur();
- socket.send(JSON.stringify({ type: 'toggle-controlled', controlled: this.checked }));
-});
+document
+ .getElementById('toggle-offline-players')
+ .addEventListener('click', function () {
+ room.showingOffline = this.checked;
+ this.blur();
+ if (room.showingOffline) {
+ styleSheet.textContent = '';
+ } else {
+ styleSheet.textContent = '.offline { display: none; }';
+ }
+ });
+
+document
+ .getElementById('toggle-controlled')
+ .addEventListener('click', function () {
+ this.blur();
+ socket.send(
+ JSON.stringify({ type: 'toggle-controlled', controlled: this.checked })
+ );
+ });
document.getElementById('toggle-lock').addEventListener('click', function () {
this.blur();
socket.send(JSON.stringify({ type: 'toggle-lock', lock: this.checked }));
});
-document.getElementById('toggle-login-required').addEventListener('click', function () {
- this.blur();
- socket.send(JSON.stringify({ type: 'toggle-login-required', loginRequired: this.checked }));
-});
+document
+ .getElementById('toggle-login-required')
+ .addEventListener('click', function () {
+ this.blur();
+ socket.send(
+ JSON.stringify({
+ type: 'toggle-login-required',
+ loginRequired: this.checked
+ })
+ );
+ });
document.getElementById('toggle-skip').addEventListener('click', function () {
this.blur();
socket.send(JSON.stringify({ type: 'toggle-skip', skip: this.checked }));
});
+document
+ .getElementById('toggle-stop-on-power')
+ .addEventListener('click', function () {
+ this.blur();
+ socket.send(
+ JSON.stringify({
+ type: 'toggle-stop-on-power',
+ stopOnPower: this.checked
+ })
+ );
+ });
+
document.getElementById('toggle-public').addEventListener('click', function () {
this.blur();
socket.send(JSON.stringify({ type: 'toggle-public', public: this.checked }));
@@ -130,7 +172,13 @@ document.getElementById('reveal').addEventListener('click', function () {
});
document.getElementById('username').addEventListener('change', function () {
- socket.send(JSON.stringify({ type: 'set-username', userId: USER_ID, username: this.value }));
+ socket.send(
+ JSON.stringify({
+ type: 'set-username',
+ userId: USER_ID,
+ username: this.value
+ })
+ );
room.username = this.value;
window.localStorage.setItem('multiplayer-username', room.username);
});
@@ -144,7 +192,7 @@ document.addEventListener('keydown', (event) => {
socket.send(JSON.stringify({ type: 'chat', message: '' }));
}
- if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement.tagName)) return;
+ if (['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement.tagName)) { return; }
switch (event.key?.toLowerCase()) {
case ' ':
@@ -154,17 +202,27 @@ document.addEventListener('keydown', (event) => {
document.getElementById('buzz').click();
}
// Prevent spacebar from scrolling the page
- if (event.target === document.body) { event.preventDefault(); }
+ if (event.target === document.body) {
+ event.preventDefault();
+ }
break;
- case 'e': return document.getElementById('toggle-settings').click();
- case 'k': return document.getElementsByClassName('card-header-clickable')[0].click();
- case 'p': return document.getElementById('pause').click();
- case 't': return document.getElementsByClassName('star-tossup')[0].click();
- case 'y': return navigator.clipboard.writeText(room.tossup._id ?? '');
+ case 'e':
+ return document.getElementById('toggle-settings').click();
+ case 'k':
+ return document
+ .getElementsByClassName('card-header-clickable')[0]
+ .click();
+ case 'p':
+ return document.getElementById('pause').click();
+ case 't':
+ return document.getElementsByClassName('star-tossup')[0].click();
+ case 'y':
+ return navigator.clipboard.writeText(room.tossup._id ?? '');
case 'n':
- case 's': return document.getElementById('next').click();
+ case 's':
+ return document.getElementById('next').click();
}
});
@@ -184,7 +242,12 @@ ReactDOM.createRoot(document.getElementById('category-modal-root')).render(
categoryManager={room.categoryManager}
onClose={() => {
if (oldCategories !== JSON.stringify(room.categoryManager.export())) {
- socket.send(JSON.stringify({ type: 'set-categories', ...room.categoryManager.export() }));
+ socket.send(
+ JSON.stringify({
+ type: 'set-categories',
+ ...room.categoryManager.export()
+ })
+ );
}
oldCategories = JSON.stringify(room.categoryManager.export());
}}
@@ -194,6 +257,12 @@ ReactDOM.createRoot(document.getElementById('category-modal-root')).render(
ReactDOM.createRoot(document.getElementById('difficulty-dropdown-root')).render(
socket.send(JSON.stringify({ type: 'set-difficulties', difficulties: getDropdownValues('difficulties') }))}
+ onChange={() =>
+ socket.send(
+ JSON.stringify({
+ type: 'set-difficulties',
+ difficulties: getDropdownValues('difficulties')
+ })
+ )}
/>
);
diff --git a/client/play/tossups/SoloTossupClient.js b/client/play/tossups/SoloTossupClient.js
index 1f8ee763a..f36147ba7 100644
--- a/client/play/tossups/SoloTossupClient.js
+++ b/client/play/tossups/SoloTossupClient.js
@@ -9,6 +9,7 @@ const settingsVersion = '2024-11-02';
export default class SoloTossupClient extends TossupClient {
constructor (room, userId, socket, aiBot) {
+ console.log('SoloTossupClient constructor called');
super(room, userId, socket);
this.aiBot = aiBot;
}
@@ -16,16 +17,23 @@ export default class SoloTossupClient extends TossupClient {
onmessage (message) {
const data = JSON.parse(message);
switch (data.type) {
- case 'clear-stats': return this.clearStats(data);
- case 'toggle-ai-mode': return this.toggleAiMode(data);
- case 'toggle-correct': return this.toggleCorrect(data);
- case 'toggle-type-to-answer': return this.toggleTypeToAnswer(data);
- default: return super.onmessage(message);
+ case 'clear-stats':
+ return this.clearStats(data);
+ case 'toggle-ai-mode':
+ return this.toggleAiMode(data);
+ case 'toggle-correct':
+ return this.toggleCorrect(data);
+ case 'toggle-type-to-answer':
+ return this.toggleTypeToAnswer(data);
+ default:
+ return super.onmessage(message);
}
}
buzz ({ timer, userId, username }) {
- if (userId !== this.USER_ID) { return; }
+ if (userId !== this.USER_ID) {
+ return;
+ }
super.buzz({ userId });
@@ -44,9 +52,19 @@ export default class SoloTossupClient extends TossupClient {
endCurrentTossup ({ isSkip, starred, tossup }) {
super.endCurrentTossup({ starred, tossup });
- if (!isSkip && this.room.previousTossup.userId === this.USER_ID && (this.room.mode !== MODE_ENUM.LOCAL)) {
+ if (
+ !isSkip &&
+ this.room.previousTossup.userId === this.USER_ID &&
+ this.room.mode !== MODE_ENUM.LOCAL
+ ) {
const previous = this.room.previousTossup;
- const pointValue = previous.isCorrect ? (previous.inPower ? previous.powerValue : 10) : (previous.endOfQuestion ? 0 : previous.negValue);
+ const pointValue = previous.isCorrect
+ ? previous.inPower
+ ? previous.powerValue
+ : 10
+ : previous.endOfQuestion
+ ? 0
+ : previous.negValue;
questionStats.recordTossup({
_id: previous.tossup._id,
celerity: previous.celerity,
@@ -57,10 +75,19 @@ export default class SoloTossupClient extends TossupClient {
}
}
- async giveTossupAnswer ({ directive, directedPrompt, perQuestionCelerity, score, tossup, userId }) {
+ async giveTossupAnswer ({
+ directive,
+ directedPrompt,
+ perQuestionCelerity,
+ score,
+ tossup,
+ userId
+ }) {
super.giveTossupAnswer({ directive, directedPrompt, score, userId });
- if (directive === 'prompt') { return; }
+ if (directive === 'prompt') {
+ return;
+ }
if (userId === this.USER_ID) {
this.updateStatDisplay(this.room.players[this.USER_ID]);
@@ -92,125 +119,205 @@ export default class SoloTossupClient extends TossupClient {
document.getElementById('next').textContent = 'Next';
document.getElementById('toggle-correct').classList.remove('d-none');
- document.getElementById('toggle-correct').textContent = this.room.previousTossup.isCorrect ? 'I was wrong' : 'I was right';
+ document.getElementById('toggle-correct').textContent = this.room
+ .previousTossup.isCorrect
+ ? 'I was wrong'
+ : 'I was right';
}
- setCategories ({ alternateSubcategories, categories, subcategories, percentView, categoryPercents }) {
+ setCategories ({
+ alternateSubcategories,
+ categories,
+ subcategories,
+ percentView,
+ categoryPercents
+ }) {
super.setCategories();
- window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...this.room.query, version: queryVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-query',
+ JSON.stringify({ ...this.room.query, version: queryVersion })
+ );
}
setDifficulties ({ difficulties }) {
- window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...this.room.query, version: queryVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-query',
+ JSON.stringify({ ...this.room.query, version: queryVersion })
+ );
}
setMaxYear ({ maxYear }) {
super.setMaxYear({ maxYear });
- window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...this.room.query, version: queryVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-query',
+ JSON.stringify({ ...this.room.query, version: queryVersion })
+ );
}
setMinYear ({ minYear }) {
super.setMinYear({ minYear });
- window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...this.room.query, version: queryVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-query',
+ JSON.stringify({ ...this.room.query, version: queryVersion })
+ );
}
setPacketNumbers ({ packetNumbers }) {
super.setPacketNumbers({ packetNumbers });
- window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...this.room.query, version: queryVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-query',
+ JSON.stringify({ ...this.room.query, version: queryVersion })
+ );
}
setReadingSpeed ({ readingSpeed }) {
super.setReadingSpeed({ readingSpeed });
- window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...this.room.settings, version: settingsVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-settings',
+ JSON.stringify({ ...this.room.settings, version: settingsVersion })
+ );
}
async setSetName ({ setName, setLength }) {
super.setSetName({ setName, setLength });
- window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...this.room.query, version: queryVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-query',
+ JSON.stringify({ ...this.room.query, version: queryVersion })
+ );
}
setStrictness ({ strictness }) {
super.setStrictness({ strictness });
- window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...this.room.settings, version: settingsVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-settings',
+ JSON.stringify({ ...this.room.settings, version: settingsVersion })
+ );
}
toggleAiMode ({ aiMode }) {
- if (aiMode) { upsertPlayerItem(this.aiBot.player); }
+ if (aiMode) {
+ upsertPlayerItem(this.aiBot.player);
+ }
this.aiBot.active = aiMode;
document.getElementById('ai-settings').disabled = !aiMode;
document.getElementById('toggle-ai-mode').checked = aiMode;
- document.getElementById('player-list-group').classList.toggle('d-none', !aiMode);
- document.getElementById('player-list-group-hr').classList.toggle('d-none', !aiMode);
- window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...this.room.settings, version: settingsVersion }));
+ document
+ .getElementById('player-list-group')
+ .classList.toggle('d-none', !aiMode);
+ document
+ .getElementById('player-list-group-hr')
+ .classList.toggle('d-none', !aiMode);
+ window.localStorage.setItem(
+ 'singleplayer-tossup-settings',
+ JSON.stringify({ ...this.room.settings, version: settingsVersion })
+ );
}
toggleCorrect ({ correct, userId }) {
this.updateStatDisplay(this.room.players[this.USER_ID]);
- document.getElementById('toggle-correct').textContent = correct ? 'I was wrong' : 'I was right';
+ document.getElementById('toggle-correct').textContent = correct
+ ? 'I was wrong'
+ : 'I was right';
}
togglePowermarkOnly ({ powermarkOnly }) {
super.togglePowermarkOnly({ powermarkOnly });
- window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...this.room.query, version: queryVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-query',
+ JSON.stringify({ ...this.room.query, version: queryVersion })
+ );
}
toggleRebuzz ({ rebuzz }) {
super.toggleRebuzz({ rebuzz });
- window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...this.room.settings, version: settingsVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-settings',
+ JSON.stringify({ ...this.room.settings, version: settingsVersion })
+ );
+ }
+
+ toggleStopOnPower ({ stopOnPower }) {
+ console.log('SoloTossupClient.toggleStopOnPower called');
+ super.toggleStopOnPower({ stopOnPower });
+ window.localStorage.setItem(
+ 'singleplayer-tossup-settings',
+ JSON.stringify({ ...this.room.settings, version: settingsVersion })
+ );
}
setMode ({ mode }) {
switch (mode) {
case MODE_ENUM.SET_NAME:
- document.getElementById('local-packet-settings').classList.add('d-none');
+ document
+ .getElementById('local-packet-settings')
+ .classList.add('d-none');
break;
case MODE_ENUM.RANDOM:
- document.getElementById('local-packet-settings').classList.add('d-none');
+ document
+ .getElementById('local-packet-settings')
+ .classList.add('d-none');
break;
case MODE_ENUM.STARRED:
document.getElementById('difficulty-settings').classList.add('d-none');
- document.getElementById('local-packet-settings').classList.add('d-none');
+ document
+ .getElementById('local-packet-settings')
+ .classList.add('d-none');
document.getElementById('set-settings').classList.add('d-none');
document.getElementById('toggle-powermark-only').disabled = true;
document.getElementById('toggle-standard-only').disabled = true;
break;
case MODE_ENUM.LOCAL:
document.getElementById('difficulty-settings').classList.add('d-none');
- document.getElementById('local-packet-settings').classList.remove('d-none');
+ document
+ .getElementById('local-packet-settings')
+ .classList.remove('d-none');
document.getElementById('set-settings').classList.add('d-none');
document.getElementById('toggle-powermark-only').disabled = true;
document.getElementById('toggle-standard-only').disabled = true;
break;
}
super.setMode({ mode });
- window.localStorage.setItem('singleplayer-tossup-mode', JSON.stringify({ mode, version: modeVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-mode',
+ JSON.stringify({ mode, version: modeVersion })
+ );
}
toggleStandardOnly ({ standardOnly }) {
super.toggleStandardOnly({ standardOnly });
- window.localStorage.setItem('singleplayer-tossup-query', JSON.stringify({ ...this.room.query, version: queryVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-query',
+ JSON.stringify({ ...this.room.query, version: queryVersion })
+ );
}
toggleTimer ({ timer }) {
super.toggleTimer({ timer });
- window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...this.room.settings, version: settingsVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-settings',
+ JSON.stringify({ ...this.room.settings, version: settingsVersion })
+ );
}
toggleTypeToAnswer ({ typeToAnswer }) {
document.getElementById('type-to-answer').checked = typeToAnswer;
- window.localStorage.setItem('singleplayer-tossup-settings', JSON.stringify({ ...this.room.settings, version: settingsVersion }));
+ window.localStorage.setItem(
+ 'singleplayer-tossup-settings',
+ JSON.stringify({ ...this.room.settings, version: settingsVersion })
+ );
}
/**
- * Updates the displayed stat line.
- */
+ * Updates the displayed stat line.
+ */
updateStatDisplay ({ powers, tens, negs, tuh, points, celerity }) {
const averageCelerity = celerity.correct.average.toFixed(3);
- const plural = (tuh === 1) ? '' : 's';
- document.getElementById('statline').innerHTML = `${powers}/${tens}/${negs} with ${tuh} tossup${plural} seen (${points} pts, celerity: ${averageCelerity})`;
+ const plural = tuh === 1 ? '' : 's';
+ document.getElementById('statline').innerHTML =
+ `${powers}/${tens}/${negs} with ${tuh} tossup${plural} seen (${points} pts, celerity: ${averageCelerity})`;
// disable clear stats button if no stats
- document.getElementById('clear-stats').disabled = (tuh === 0);
+ document.getElementById('clear-stats').disabled = tuh === 0;
}
}
diff --git a/client/play/tossups/index.html b/client/play/tossups/index.html
index e6409c303..fdae302ee 100644
--- a/client/play/tossups/index.html
+++ b/client/play/tossups/index.html
@@ -173,6 +173,10 @@
+
+
+
+
diff --git a/client/play/tossups/index.jsx b/client/play/tossups/index.jsx
index 621ca9c48..f5a83d332 100644
--- a/client/play/tossups/index.jsx
+++ b/client/play/tossups/index.jsx
@@ -123,6 +123,7 @@ if (window.localStorage.getItem('singleplayer-tossup-settings')) {
socket.sendToServer({ type: 'set-reading-speed', ...savedSettings });
socket.sendToServer({ type: 'toggle-ai-mode', ...savedSettings });
socket.sendToServer({ type: 'toggle-rebuzz', ...savedSettings });
+ socket.sendToServer({ type: 'toggle-stop-on-power', ...savedSettings });
socket.sendToServer({ type: 'toggle-timer', ...savedSettings });
socket.sendToServer({ type: 'toggle-type-to-answer', ...savedSettings });
} catch {
diff --git a/quizbowl/TossupRoom.js b/quizbowl/TossupRoom.js
index ea301e50a..58dd2632e 100644
--- a/quizbowl/TossupRoom.js
+++ b/quizbowl/TossupRoom.js
@@ -1,293 +1,450 @@
-import { ANSWER_TIME_LIMIT, DEAD_TIME_LIMIT, MODE_ENUM, TOSSUP_PROGRESS_ENUM } from './constants.js';
+import {
+ ANSWER_TIME_LIMIT,
+ DEAD_TIME_LIMIT,
+ MODE_ENUM,
+ TOSSUP_PROGRESS_ENUM
+} from './constants.js';
import insertTokensIntoHTML from './insert-tokens-into-html.js';
import QuestionRoom from './QuestionRoom.js';
-export const TossupRoomMixin = (QuestionRoomClass) => class extends QuestionRoomClass {
- constructor (name, categoryManager, supportedQuestionTypes = ['tossup']) {
- super(name, categoryManager, supportedQuestionTypes);
-
- this.timeoutID = null;
- /**
- * @type {string | null}
- * The userId of the player who buzzed in.
- * We should ensure that buzzedIn is null before calling any readQuestion.
- */
- this.buzzedIn = null;
- this.buzzes = [];
- this.buzzpointIndices = [];
- this.liveAnswer = '';
- this.paused = false;
- this.questionSplit = [];
- this.tossup = {};
- this.tossupProgress = TOSSUP_PROGRESS_ENUM.NOT_STARTED;
- this.wordIndex = 0;
-
- this.query = {
- ...this.query,
- powermarkOnly: false
- };
-
- this.settings = {
- ...this.settings,
- rebuzz: false,
- readingSpeed: 50
- };
-
- this.previousTossup = {
- celerity: 0,
- endOfQuestion: false,
- isCorrect: true,
- inPower: false,
- negValue: -5,
- powerValue: 15,
- tossup: {},
- userId: null
- };
- }
-
- async message (userId, message) {
- switch (message.type) {
- case 'buzz': return this.buzz(userId, message);
- case 'give-answer': return this.giveTossupAnswer(userId, message);
- case 'next': return this.next(userId, message);
- case 'pause': return this.pause(userId, message);
- case 'set-reading-speed': return this.setReadingSpeed(userId, message);
- case 'toggle-powermark-only': return this.togglePowermarkOnly(userId, message);
- case 'toggle-rebuzz': return this.toggleRebuzz(userId, message);
- default: return super.message(userId, message);
+export const TossupRoomMixin = (QuestionRoomClass) =>
+ class extends QuestionRoomClass {
+ constructor (name, categoryManager, supportedQuestionTypes = ['tossup']) {
+ super(name, categoryManager, supportedQuestionTypes);
+
+ this.timeoutID = null;
+ /**
+ * @type {string | null}
+ * The userId of the player who buzzed in.
+ * We should ensure that buzzedIn is null before calling any readQuestion.
+ */
+ this.buzzedIn = null;
+ this.buzzes = [];
+ this.buzzpointIndices = [];
+ this.liveAnswer = '';
+ this.paused = false;
+ this.questionSplit = [];
+ this.tossup = {};
+ this.stopOnPowerEnded = false;
+ this.tossupProgress = TOSSUP_PROGRESS_ENUM.NOT_STARTED;
+ this.wordIndex = 0;
+
+ this.query = {
+ ...this.query,
+ powermarkOnly: false
+ };
+
+ this.settings = {
+ ...this.settings,
+ rebuzz: false,
+ stopOnPower: false,
+ readingSpeed: 50
+ };
+
+ this.previousTossup = {
+ celerity: 0,
+ endOfQuestion: false,
+ isCorrect: true,
+ inPower: false,
+ negValue: -5,
+ powerValue: 15,
+ tossup: {},
+ userId: null
+ };
}
- }
- buzz (userId) {
- if (!this.settings.rebuzz && this.buzzes.includes(userId)) { return; }
- if (this.tossupProgress !== TOSSUP_PROGRESS_ENUM.READING) { return; }
-
- const username = this.players[userId].username;
- if (this.buzzedIn) {
- return this.emitMessage({ type: 'lost-buzzer-race', userId, username });
+ async message (userId, message) {
+ switch (message.type) {
+ case 'buzz':
+ return this.buzz(userId, message);
+ case 'give-answer':
+ return this.giveTossupAnswer(userId, message);
+ case 'next':
+ return this.next(userId, message);
+ case 'pause':
+ return this.pause(userId, message);
+ case 'set-reading-speed':
+ return this.setReadingSpeed(userId, message);
+ case 'toggle-powermark-only':
+ return this.togglePowermarkOnly(userId, message);
+ case 'toggle-rebuzz':
+ return this.toggleRebuzz(userId, message);
+ case 'toggle-stop-on-power':
+ return this.toggleStopOnPower(userId, message);
+ default:
+ return super.message(userId, message);
+ }
}
- clearTimeout(this.timeoutID);
- this.buzzedIn = userId;
- this.buzzes.push(userId);
- this.buzzpointIndices.push(this.questionSplit.slice(0, this.wordIndex).join(' ').length);
- this.paused = false;
+ buzz (userId) {
+ if (!this.settings.rebuzz && this.buzzes.includes(userId)) {
+ return;
+ }
+ if (this.tossupProgress !== TOSSUP_PROGRESS_ENUM.READING) {
+ return;
+ }
- this.emitMessage({ type: 'buzz', userId, username });
- this.emitMessage({ type: 'update-question', word: '(#)' });
+ const username = this.players[userId].username;
+ if (this.buzzedIn) {
+ return this.emitMessage({ type: 'lost-buzzer-race', userId, username });
+ }
- this.startServerTimer(
- ANSWER_TIME_LIMIT * 10,
- (time) => this.emitMessage({ type: 'timer-update', timeRemaining: time }),
- () => this.giveTossupAnswer(userId, { givenAnswer: this.liveAnswer })
- );
- }
+ clearTimeout(this.timeoutID);
+ this.buzzedIn = userId;
+ this.buzzes.push(userId);
+ this.buzzpointIndices.push(
+ this.questionSplit.slice(0, this.wordIndex).join(' ').length
+ );
+ this.paused = false;
- endCurrentTossup (userId) {
- if (this.buzzedIn) { return false; } // prevents skipping when someone has buzzed in
- if (this.queryingQuestion) { return false; }
- const isSkip = this.tossupProgress === TOSSUP_PROGRESS_ENUM.READING;
- if (isSkip && !this.settings.skip) { return false; }
+ this.emitMessage({ type: 'buzz', userId, username });
+ this.emitMessage({ type: 'update-question', word: '(#)' });
- clearInterval(this.timer.interval);
- clearTimeout(this.timeoutID);
- this.emitMessage({ type: 'timer-update', timeRemaining: 0 });
+ this.startServerTimer(
+ ANSWER_TIME_LIMIT * 10,
+ (time) =>
+ this.emitMessage({ type: 'timer-update', timeRemaining: time }),
+ () => this.giveTossupAnswer(userId, { givenAnswer: this.liveAnswer })
+ );
+ }
- this.buzzedIn = null;
- this.buzzes = [];
- this.buzzpointIndices = [];
- this.paused = false;
+ endCurrentTossup (userId) {
+ if (this.buzzedIn) {
+ return false;
+ } // prevents skipping when someone has buzzed in
+ if (this.queryingQuestion) {
+ return false;
+ }
+ const isSkip = this.tossupProgress === TOSSUP_PROGRESS_ENUM.READING;
+ if (isSkip && !this.settings.skip) {
+ return false;
+ }
- if (this.tossupProgress !== TOSSUP_PROGRESS_ENUM.ANSWER_REVEALED) { this.revealTossupAnswer(); }
+ clearInterval(this.timer.interval);
+ clearTimeout(this.timeoutID);
+ this.emitMessage({ type: 'timer-update', timeRemaining: 0 });
- const starred = this.mode === MODE_ENUM.STARRED ? true : (this.mode === MODE_ENUM.LOCAL ? false : null);
- this.emitMessage({ type: 'end-current-tossup', isSkip, starred, tossup: this.tossup });
- return true;
- }
+ this.buzzedIn = null;
+ this.buzzes = [];
+ this.buzzpointIndices = [];
+ this.paused = false;
- giveTossupAnswer (userId, { givenAnswer }) {
- if (typeof givenAnswer !== 'string') { return false; }
- if (this.buzzedIn !== userId) { return false; }
+ if (this.tossupProgress !== TOSSUP_PROGRESS_ENUM.ANSWER_REVEALED) {
+ this.revealTossupAnswer();
+ }
+
+ const starred =
+ this.mode === MODE_ENUM.STARRED
+ ? true
+ : this.mode === MODE_ENUM.LOCAL
+ ? false
+ : null;
+ this.emitMessage({
+ type: 'end-current-tossup',
+ isSkip,
+ starred,
+ tossup: this.tossup
+ });
+ return true;
+ }
- this.liveAnswer = '';
- clearInterval(this.timer.interval);
- this.emitMessage({ type: 'timer-update', timeRemaining: ANSWER_TIME_LIMIT * 10 });
+ giveTossupAnswer (userId, { givenAnswer }) {
+ if (typeof givenAnswer !== 'string') {
+ return false;
+ }
+ if (this.buzzedIn !== userId) {
+ return false;
+ }
- if (Object.keys(this.tossup || {}).length === 0) { return; }
+ this.liveAnswer = '';
+ clearInterval(this.timer.interval);
+ this.emitMessage({
+ type: 'timer-update',
+ timeRemaining: ANSWER_TIME_LIMIT * 10
+ });
+
+ if (Object.keys(this.tossup || {}).length === 0) {
+ return;
+ }
+
+ const { celerity, directive, directedPrompt, points } = this.scoreTossup({
+ givenAnswer
+ });
+
+ switch (directive) {
+ case 'accept':
+ this.buzzedIn = null;
+ this.revealTossupAnswer();
+ this.players[userId].updateStats(points, celerity);
+ Object.values(this.players).forEach((player) => {
+ player.tuh++;
+ });
+ break;
+ case 'reject':
+ this.buzzedIn = null;
+ this.players[userId].updateStats(points, celerity);
+ if (
+ !this.settings.rebuzz &&
+ this.buzzes.length === Object.keys(this.sockets).length
+ ) {
+ this.revealTossupAnswer();
+ Object.values(this.players).forEach((player) => {
+ player.tuh++;
+ });
+ } else {
+ this.readQuestion(Date.now());
+ }
+ break;
+ case 'prompt':
+ this.startServerTimer(
+ ANSWER_TIME_LIMIT * 10,
+ (time) =>
+ this.emitMessage({ type: 'timer-update', timeRemaining: time }),
+ () =>
+ this.giveTossupAnswer(userId, { givenAnswer: this.liveAnswer })
+ );
+ }
+
+ this.emitMessage({
+ type: 'give-tossup-answer',
+ userId,
+ username: this.players[userId].username,
+ givenAnswer,
+ directive,
+ directedPrompt,
+ score: points,
+ celerity: this.players[userId].celerity.correct.average,
+ // the below fields are used to record buzzpoint data
+ tossup: this.tossup,
+ perQuestionCelerity: celerity
+ });
+ }
- const { celerity, directive, directedPrompt, points } = this.scoreTossup({ givenAnswer });
+ async next (userId) {
+ if (this.tossupProgress === TOSSUP_PROGRESS_ENUM.NOT_STARTED) {
+ return await this.startNextTossup(userId);
+ }
+ const allowed = this.endCurrentTossup(userId);
+ if (allowed) {
+ await this.startNextTossup(userId);
+ }
+ }
- switch (directive) {
- case 'accept':
- this.buzzedIn = null;
- this.revealTossupAnswer();
- this.players[userId].updateStats(points, celerity);
- Object.values(this.players).forEach(player => { player.tuh++; });
- break;
- case 'reject':
- this.buzzedIn = null;
- this.players[userId].updateStats(points, celerity);
- if (!this.settings.rebuzz && this.buzzes.length === Object.keys(this.sockets).length) {
- this.revealTossupAnswer();
- Object.values(this.players).forEach(player => { player.tuh++; });
- } else {
- this.readQuestion(Date.now());
- }
- break;
- case 'prompt':
+ pause (userId) {
+ if (this.buzzedIn) {
+ return false;
+ }
+ if (this.tossupProgress === TOSSUP_PROGRESS_ENUM.ANSWER_REVEALED) {
+ return false;
+ }
+
+ this.paused = !this.paused;
+ if (this.paused) {
+ clearTimeout(this.timeoutID);
+ clearInterval(this.timer.interval);
+ } else if (this.wordIndex >= this.questionSplit.length) {
this.startServerTimer(
- ANSWER_TIME_LIMIT * 10,
- (time) => this.emitMessage({ type: 'timer-update', timeRemaining: time }),
- () => this.giveTossupAnswer(userId, { givenAnswer: this.liveAnswer })
+ this.timer.timeRemaining,
+ (time) =>
+ this.emitMessage({ type: 'timer-update', timeRemaining: time }),
+ () => this.revealTossupAnswer()
);
+ } else {
+ this.readQuestion(Date.now());
+ }
+ const username = this.players[userId].username;
+ this.emitMessage({ type: 'pause', paused: this.paused, username });
}
- this.emitMessage({
- type: 'give-tossup-answer',
- userId,
- username: this.players[userId].username,
- givenAnswer,
- directive,
- directedPrompt,
- score: points,
- celerity: this.players[userId].celerity.correct.average,
- // the below fields are used to record buzzpoint data
- tossup: this.tossup,
- perQuestionCelerity: celerity
- });
- }
-
- async next (userId) {
- if (this.tossupProgress === TOSSUP_PROGRESS_ENUM.NOT_STARTED) {
- return await this.startNextTossup(userId);
+ async readQuestion (expectedReadTime) {
+ if (Object.keys(this.tossup || {}).length === 0) {
+ return;
+ }
+ if (this.wordIndex >= this.questionSplit.length) {
+ this.startServerTimer(
+ DEAD_TIME_LIMIT * 10,
+ (time) =>
+ this.emitMessage({ type: 'timer-update', timeRemaining: time }),
+ () => this.revealTossupAnswer()
+ );
+ return;
+ }
+
+ const word = this.questionSplit[this.wordIndex];
+
+ // stop reading and start timer if power and stopOnPower is enabled
+ if ((word === '(*)' || word === '[*]') && this.settings.stopOnPower) {
+ this.stopOnPowerEnded = true;
+ this.startServerTimer(
+ DEAD_TIME_LIMIT * 10,
+ (time) =>
+ this.emitMessage({ type: 'timer-update', timeRemaining: time }),
+ () => this.revealTossupAnswer()
+ );
+ return;
+ }
+
+ this.wordIndex++;
+ this.emitMessage({ type: 'update-question', word });
+
+ // calculate time needed before reading next word
+ let time = Math.log(word.length) + 1;
+ if (
+ (word.endsWith('.') &&
+ word.charCodeAt(word.length - 2) > 96 &&
+ word.charCodeAt(word.length - 2) < 123) ||
+ word.slice(-2) === '.\u201d' ||
+ word.slice(-2) === '!\u201d' ||
+ word.slice(-2) === '?\u201d'
+ ) {
+ time += 2.5;
+ } else if (word.endsWith(',') || word.slice(-2) === ',\u201d') {
+ time += 1.5;
+ } else if (word === '(*)' || word === '[*]') {
+ time = 0;
+ }
+
+ time = time * 0.9 * (140 - this.settings.readingSpeed);
+ const delay = time - Date.now() + expectedReadTime;
+
+ this.timeoutID = setTimeout(() => {
+ this.readQuestion(time + expectedReadTime);
+ }, delay);
}
- const allowed = this.endCurrentTossup(userId);
- if (allowed) { await this.startNextTossup(userId); }
- }
- pause (userId) {
- if (this.buzzedIn) { return false; }
- if (this.tossupProgress === TOSSUP_PROGRESS_ENUM.ANSWER_REVEALED) { return false; }
+ revealTossupAnswer () {
+ if (Object.keys(this.tossup || {}).length === 0) return;
+ this.tossupProgress = TOSSUP_PROGRESS_ENUM.ANSWER_REVEALED;
+ this.tossup.markedQuestion = insertTokensIntoHTML(
+ this.tossup.question,
+ this.tossup.question_sanitized,
+ { ' (#) ': this.buzzpointIndices }
+ );
+ this.emitMessage({
+ type: 'reveal-tossup-answer',
+ question: insertTokensIntoHTML(
+ this.tossup.question,
+ this.tossup.question_sanitized,
+ { ' (#) ': this.buzzpointIndices }
+ ),
+ answer: this.tossup.answer
+ });
+ }
- this.paused = !this.paused;
- if (this.paused) {
- clearTimeout(this.timeoutID);
- clearInterval(this.timer.interval);
- } else if (this.wordIndex >= this.questionSplit.length) {
- this.startServerTimer(
- this.timer.timeRemaining,
- (time) => this.emitMessage({ type: 'timer-update', timeRemaining: time }),
- () => this.revealTossupAnswer()
+ scoreTossup ({ givenAnswer }) {
+ const celerity =
+ this.questionSplit.slice(this.wordIndex).join(' ').length /
+ this.tossup.question.length;
+ const endOfQuestion = this.settings.stopOnPower
+ ? this.stopOnPowerEnded
+ : this.wordIndex === this.questionSplit.length;
+ const inPower =
+ Math.max(
+ this.questionSplit.indexOf('(*)'),
+ this.questionSplit.indexOf('[*]')
+ ) >= this.wordIndex;
+ const { directive, directedPrompt } = this.checkAnswer(
+ this.tossup.answer,
+ givenAnswer,
+ this.settings.strictness
);
- } else {
+ const isCorrect = directive === 'accept';
+ const points = this.settings.stopOnPower
+ ? isCorrect
+ ? 10
+ : this.stopOnPowerEnded
+ ? 0
+ : this.previousTossup.negValue
+ : isCorrect
+ ? inPower
+ ? this.previousTossup.powerValue
+ : 10
+ : endOfQuestion
+ ? 0
+ : this.previousTossup.negValue;
+
+ this.previousTossup = {
+ ...this.previousTossup,
+ celerity,
+ endOfQuestion,
+ inPower,
+ isCorrect,
+ tossup: this.tossup,
+ userId: this.buzzedIn
+ };
+
+ return {
+ celerity,
+ directive,
+ directedPrompt,
+ endOfQuestion,
+ inPower,
+ points
+ };
+ }
+
+ setReadingSpeed (userId, { readingSpeed }) {
+ if (isNaN(readingSpeed)) {
+ return false;
+ }
+ if (readingSpeed > 100) {
+ readingSpeed = 100;
+ }
+ if (readingSpeed < 0) {
+ readingSpeed = 0;
+ }
+
+ this.settings.readingSpeed = readingSpeed;
+ const username = this.players[userId].username;
+ this.emitMessage({ type: 'set-reading-speed', username, readingSpeed });
+ }
+
+ async startNextTossup (userId) {
+ const username = this.players[userId].username;
+ this.tossup = await this.getNextQuestion('tossups');
+ this.queryingQuestion = false;
+ if (!this.tossup) {
+ return;
+ }
+ this.emitMessage({
+ type: 'start-next-tossup',
+ packetLength: this.packet.tossups.length,
+ tossup: this.tossup,
+ userId,
+ username
+ });
+ this.questionSplit = this.tossup.question_sanitized
+ .split(' ')
+ .filter((word) => word !== '');
+ this.wordIndex = 0;
+ this.tossupProgress = TOSSUP_PROGRESS_ENUM.READING;
+ clearTimeout(this.timeoutID);
this.readQuestion(Date.now());
}
- const username = this.players[userId].username;
- this.emitMessage({ type: 'pause', paused: this.paused, username });
- }
- async readQuestion (expectedReadTime) {
- if (Object.keys(this.tossup || {}).length === 0) { return; }
- if (this.wordIndex >= this.questionSplit.length) {
- this.startServerTimer(
- DEAD_TIME_LIMIT * 10,
- (time) => this.emitMessage({ type: 'timer-update', timeRemaining: time }),
- () => this.revealTossupAnswer()
- );
- return;
+ togglePowermarkOnly (userId, { powermarkOnly }) {
+ this.query.powermarkOnly = powermarkOnly;
+ const username = this.players[userId].username;
+ this.adjustQuery(['powermarkOnly'], [powermarkOnly]);
+ this.emitMessage({
+ type: 'toggle-powermark-only',
+ powermarkOnly,
+ username
+ });
}
- const word = this.questionSplit[this.wordIndex];
- this.wordIndex++;
- this.emitMessage({ type: 'update-question', word });
-
- // calculate time needed before reading next word
- let time = Math.log(word.length) + 1;
- if ((word.endsWith('.') && word.charCodeAt(word.length - 2) > 96 && word.charCodeAt(word.length - 2) < 123) ||
- word.slice(-2) === '.\u201d' || word.slice(-2) === '!\u201d' || word.slice(-2) === '?\u201d') {
- time += 2.5;
- } else if (word.endsWith(',') || word.slice(-2) === ',\u201d') {
- time += 1.5;
- } else if (word === '(*)' || word === '[*]') {
- time = 0;
+ toggleRebuzz (userId, { rebuzz }) {
+ this.settings.rebuzz = rebuzz;
+ const username = this.players[userId].username;
+ this.emitMessage({ type: 'toggle-rebuzz', rebuzz, username });
}
- time = time * 0.9 * (140 - this.settings.readingSpeed);
- const delay = time - Date.now() + expectedReadTime;
-
- this.timeoutID = setTimeout(() => {
- this.readQuestion(time + expectedReadTime);
- }, delay);
- }
-
- revealTossupAnswer () {
- if (Object.keys(this.tossup || {}).length === 0) return;
- this.tossupProgress = TOSSUP_PROGRESS_ENUM.ANSWER_REVEALED;
- this.tossup.markedQuestion = insertTokensIntoHTML(this.tossup.question, this.tossup.question_sanitized, { ' (#) ': this.buzzpointIndices });
- this.emitMessage({
- type: 'reveal-tossup-answer',
- question: insertTokensIntoHTML(this.tossup.question, this.tossup.question_sanitized, { ' (#) ': this.buzzpointIndices }),
- answer: this.tossup.answer
- });
- }
-
- scoreTossup ({ givenAnswer }) {
- const celerity = this.questionSplit.slice(this.wordIndex).join(' ').length / this.tossup.question.length;
- const endOfQuestion = (this.wordIndex === this.questionSplit.length);
- const inPower = Math.max(this.questionSplit.indexOf('(*)'), this.questionSplit.indexOf('[*]')) >= this.wordIndex;
- const { directive, directedPrompt } = this.checkAnswer(this.tossup.answer, givenAnswer, this.settings.strictness);
- const isCorrect = directive === 'accept';
- const points = isCorrect ? (inPower ? this.previousTossup.powerValue : 10) : (endOfQuestion ? 0 : this.previousTossup.negValue);
-
- this.previousTossup = {
- ...this.previousTossup,
- celerity,
- endOfQuestion,
- inPower,
- isCorrect,
- tossup: this.tossup,
- userId: this.buzzedIn
- };
-
- return { celerity, directive, directedPrompt, endOfQuestion, inPower, points };
- }
-
- setReadingSpeed (userId, { readingSpeed }) {
- if (isNaN(readingSpeed)) { return false; }
- if (readingSpeed > 100) { readingSpeed = 100; }
- if (readingSpeed < 0) { readingSpeed = 0; }
-
- this.settings.readingSpeed = readingSpeed;
- const username = this.players[userId].username;
- this.emitMessage({ type: 'set-reading-speed', username, readingSpeed });
- }
-
- async startNextTossup (userId) {
- const username = this.players[userId].username;
- this.tossup = await this.getNextQuestion('tossups');
- this.queryingQuestion = false;
- if (!this.tossup) { return; }
- this.emitMessage({ type: 'start-next-tossup', packetLength: this.packet.tossups.length, tossup: this.tossup, userId, username });
- this.questionSplit = this.tossup.question_sanitized.split(' ').filter(word => word !== '');
- this.wordIndex = 0;
- this.tossupProgress = TOSSUP_PROGRESS_ENUM.READING;
- clearTimeout(this.timeoutID);
- this.readQuestion(Date.now());
- }
-
- togglePowermarkOnly (userId, { powermarkOnly }) {
- this.query.powermarkOnly = powermarkOnly;
- const username = this.players[userId].username;
- this.adjustQuery(['powermarkOnly'], [powermarkOnly]);
- this.emitMessage({ type: 'toggle-powermark-only', powermarkOnly, username });
- }
-
- toggleRebuzz (userId, { rebuzz }) {
- this.settings.rebuzz = rebuzz;
- const username = this.players[userId].username;
- this.emitMessage({ type: 'toggle-rebuzz', rebuzz, username });
- }
-};
+ toggleStopOnPower (userId, { stopOnPower }) {
+ this.settings.stopOnPower = stopOnPower;
+ const username = this.players[userId].username;
+ this.emitMessage({ type: 'toggle-stop-on-power', stopOnPower, username });
+ }
+ };
const TossupRoom = TossupRoomMixin(QuestionRoom);
export default TossupRoom;