From 1750ff2f9fa41c164faea87c41de8d6d98e1a008 Mon Sep 17 00:00:00 2001 From: Lawrence Tong Date: Sun, 17 May 2026 20:54:11 -0500 Subject: [PATCH 1/2] fix!: lock difficulty in permanent rooms --- client/play/mp/MultiplayerTossupBonusClient.js | 1 + server/multiplayer/ServerMultiplayerRoomMixin.js | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/client/play/mp/MultiplayerTossupBonusClient.js b/client/play/mp/MultiplayerTossupBonusClient.js index 2c4e6ce8f..6bf0953c6 100644 --- a/client/play/mp/MultiplayerTossupBonusClient.js +++ b/client/play/mp/MultiplayerTossupBonusClient.js @@ -175,6 +175,7 @@ export const MultiplayerClientMixin = (ClientClass) => class extends ClientClass document.getElementById('set-strictness').disabled = true; document.getElementById('set-mode').disabled = true; document.getElementById('toggle-public').disabled = true; + document.getElementById('difficulties').querySelectorAll('input').forEach(input => { input.disabled = true; }); if (isVerified) { document.getElementById('toggle-login-required').disabled = true; } diff --git a/server/multiplayer/ServerMultiplayerRoomMixin.js b/server/multiplayer/ServerMultiplayerRoomMixin.js index e73596134..102e81803 100644 --- a/server/multiplayer/ServerMultiplayerRoomMixin.js +++ b/server/multiplayer/ServerMultiplayerRoomMixin.js @@ -277,6 +277,11 @@ const ServerMultiplayerRoomMixin = (RoomClass) => class extends RoomClass { super.setCategories({ userId, username }, { categories, subcategories, alternateSubcategories, percentView, categoryPercents }); } + setDifficulties ({ userId, username }, { difficulties }) { + if (this.isPermanent || !this.allowed(userId)) { return; } + super.setDifficulties({ userId, username }, { difficulties }); + } + setMode ({ userId, username }, { mode }) { if (this.isPermanent || !this.allowed(userId)) { return; } if (this.mode !== MODE_ENUM.SET_NAME && this.mode !== MODE_ENUM.RANDOM) { return; } From f8f7dbf51a9d361fe6ed8d847f5b1bf6e19760eb Mon Sep 17 00:00:00 2001 From: Lawrence Tong Date: Sun, 17 May 2026 21:17:15 -0500 Subject: [PATCH 2/2] feat: set difficulties for each permanent room --- client/play/mp/MultiplayerTossupBonusClient.js | 6 +++++- server/multiplayer/ServerMultiplayerRoomMixin.js | 4 +++- server/multiplayer/constants.js | 12 +++++++++--- server/multiplayer/handle-wss-connection.js | 14 ++++++++++---- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/client/play/mp/MultiplayerTossupBonusClient.js b/client/play/mp/MultiplayerTossupBonusClient.js index 6bf0953c6..bd7338c5d 100644 --- a/client/play/mp/MultiplayerTossupBonusClient.js +++ b/client/play/mp/MultiplayerTossupBonusClient.js @@ -138,6 +138,7 @@ export const MultiplayerClientMixin = (ClientClass) => class extends ClientClass buzzedIn, canBuzz, currentQuestionType, + fixedDifficulties, isPermanent, isVerified, ownerId, @@ -175,12 +176,15 @@ export const MultiplayerClientMixin = (ClientClass) => class extends ClientClass document.getElementById('set-strictness').disabled = true; document.getElementById('set-mode').disabled = true; document.getElementById('toggle-public').disabled = true; - document.getElementById('difficulties').querySelectorAll('input').forEach(input => { input.disabled = true; }); if (isVerified) { document.getElementById('toggle-login-required').disabled = true; } } + if (fixedDifficulties) { + document.getElementById('difficulties').querySelectorAll('input').forEach(input => { input.disabled = true; }); + } + for (const userId of Object.keys(players)) { const teamId = players[userId].teamId; players[userId].celerity = players[userId].celerity.correct.average; diff --git a/server/multiplayer/ServerMultiplayerRoomMixin.js b/server/multiplayer/ServerMultiplayerRoomMixin.js index 102e81803..30f22bdec 100644 --- a/server/multiplayer/ServerMultiplayerRoomMixin.js +++ b/server/multiplayer/ServerMultiplayerRoomMixin.js @@ -24,6 +24,7 @@ const ServerMultiplayerRoomMixin = (RoomClass) => class extends RoomClass { this.ownerId = ownerId; this.isPermanent = isPermanent; this.isVerified = isVerified; + this.fixedDifficulties = false; this.checkAnswer = checkAnswer; this.getPacketCount = getNumPackets; @@ -148,6 +149,7 @@ const ServerMultiplayerRoomMixin = (RoomClass) => class extends RoomClass { canBuzz: this.settings.rebuzz || !this.buzzes.includes(userId), currentQuestionType: this.currentQuestionType, isPermanent: this.isPermanent, + fixedDifficulties: this.fixedDifficulties, isVerified: this.isVerified, mode: this.mode, ownerId: this.ownerId, @@ -278,7 +280,7 @@ const ServerMultiplayerRoomMixin = (RoomClass) => class extends RoomClass { } setDifficulties ({ userId, username }, { difficulties }) { - if (this.isPermanent || !this.allowed(userId)) { return; } + if (this.fixedDifficulties || !this.allowed(userId)) { return; } super.setDifficulties({ userId, username }, { difficulties }); } diff --git a/server/multiplayer/constants.js b/server/multiplayer/constants.js index 4b052ea33..5f95aaa61 100644 --- a/server/multiplayer/constants.js +++ b/server/multiplayer/constants.js @@ -13,17 +13,23 @@ export const PERMANENT_ROOMS = [ { name: 'msquizbowl', categories: CATEGORIES, - subcategories: SUBCATEGORIES + subcategories: SUBCATEGORIES, + difficulties: [1], + fixedDifficulties: true }, { name: 'hsquizbowl', categories: CATEGORIES, - subcategories: SUBCATEGORIES + subcategories: SUBCATEGORIES, + difficulties: [2, 3], + fixedDifficulties: true }, { name: 'collegequizbowl', categories: CATEGORIES, - subcategories: SUBCATEGORIES + subcategories: SUBCATEGORIES, + difficulties: [7, 8, 9], + fixedDifficulties: true }, { name: 'literature', diff --git a/server/multiplayer/handle-wss-connection.js b/server/multiplayer/handle-wss-connection.js index 9d82b31d6..2b08c390f 100644 --- a/server/multiplayer/handle-wss-connection.js +++ b/server/multiplayer/handle-wss-connection.js @@ -21,16 +21,22 @@ const DOMPurify = createDOMPurify(window); export const tossupBonusRooms = {}; const connectionsByIp = new Map(); for (const room of PERMANENT_ROOMS) { - const { name, categories, subcategories } = room; - tossupBonusRooms[name] = new ServerTossupBonusRoom( + const { name, categories, subcategories, difficulties, fixedDifficulties = false } = room; + const r = new ServerTossupBonusRoom( name, Symbol('unique permanent room owner'), true, new CategoryManager(categories, subcategories), false ); + if (difficulties) { r.query.difficulties = difficulties; } + r.fixedDifficulties = fixedDifficulties; + tossupBonusRooms[name] = r; } for (const room of VERIFIED_ROOMS) { - const { name, categories, subcategories } = room; - tossupBonusRooms[name] = new ServerTossupBonusRoom( + const { name, categories, subcategories, difficulties, fixedDifficulties = false } = room; + const r = new ServerTossupBonusRoom( name, Symbol('unique verified room owner'), true, new CategoryManager(categories, subcategories), true ); + if (difficulties) { r.query.difficulties = difficulties; } + r.fixedDifficulties = fixedDifficulties; + tossupBonusRooms[name] = r; } /**