Spaces:
Running
Running
{ | |
"version": 3, | |
"sources": ["../../../../server/chat-plugins/trivia/trivia.ts"], | |
"sourcesContent": ["/*\n * Trivia plugin\n * Written by Morfent\n */\n\nimport { Utils } from '../../../lib';\nimport { type Leaderboard, LEADERBOARD_ENUM, type TriviaDatabase, TriviaSQLiteDatabase } from './database';\n\nconst MAIN_CATEGORIES: { [k: string]: string } = {\n\tae: 'Arts and Entertainment',\n\tpokemon: 'Pok\\u00E9mon',\n\tsg: 'Science and Geography',\n\tsh: 'Society and Humanities',\n};\n\nconst SPECIAL_CATEGORIES: { [k: string]: string } = {\n\tmisc: 'Miscellaneous',\n\tevent: 'Event',\n\teventused: 'Event (used)',\n\tsubcat: 'Sub-Category 1',\n\tsubcat2: 'Sub-Category 2',\n\tsubcat3: 'Sub-Category 3',\n\tsubcat4: 'Sub-Category 4',\n\tsubcat5: 'Sub-Category 5',\n\toldae: 'Old Arts and Entertainment',\n\toldsg: 'Old Science and Geography',\n\toldsh: 'Old Society and Humanities',\n\toldpoke: 'Old Pok\\u00E9mon',\n};\n\nconst ALL_CATEGORIES: { [k: string]: string } = { ...SPECIAL_CATEGORIES, ...MAIN_CATEGORIES };\n\n/**\n * Aliases for keys in the ALL_CATEGORIES object.\n */\nconst CATEGORY_ALIASES: { [k: string]: ID } = {\n\tpoke: 'pokemon' as ID,\n\tsubcat1: 'subcat' as ID,\n};\n\nconst MODES: { [k: string]: string } = {\n\tfirst: 'First',\n\tnumber: 'Number',\n\ttimer: 'Timer',\n\ttriumvirate: 'Triumvirate',\n};\n\nconst LENGTHS: { [k: string]: { cap: number | false, prizes: number[] } } = {\n\tshort: {\n\t\tcap: 20,\n\t\tprizes: [3, 2, 1],\n\t},\n\tmedium: {\n\t\tcap: 35,\n\t\tprizes: [4, 2, 1],\n\t},\n\tlong: {\n\t\tcap: 50,\n\t\tprizes: [5, 3, 1],\n\t},\n\tinfinite: {\n\t\tcap: false,\n\t\tprizes: [5, 3, 1],\n\t},\n};\n\nObject.setPrototypeOf(MAIN_CATEGORIES, null);\nObject.setPrototypeOf(SPECIAL_CATEGORIES, null);\nObject.setPrototypeOf(ALL_CATEGORIES, null);\nObject.setPrototypeOf(MODES, null);\nObject.setPrototypeOf(LENGTHS, null);\n\nconst SIGNUP_PHASE = 'signups';\nconst QUESTION_PHASE = 'question';\nconst INTERMISSION_PHASE = 'intermission';\n\nconst MASTERMIND_ROUNDS_PHASE = 'rounds';\nconst MASTERMIND_FINALS_PHASE = 'finals';\n\nconst MOVE_QUESTIONS_AFTER_USE_FROM_CATEGORY = 'event';\nconst MOVE_QUESTIONS_AFTER_USE_TO_CATEGORY = 'eventused';\n\nconst START_TIMEOUT = 30 * 1000;\nconst MASTERMIND_FINALS_START_TIMEOUT = 30 * 1000;\nconst INTERMISSION_INTERVAL = 20 * 1000;\nconst MASTERMIND_INTERMISSION_INTERVAL = 500; // 0.5 seconds\nconst PAUSE_INTERMISSION = 5 * 1000;\n\nconst MAX_QUESTION_LENGTH = 252;\nconst MAX_ANSWER_LENGTH = 32;\n\nexport interface TriviaQuestion {\n\tquestion: string;\n\tcategory: string;\n\tanswers: string[];\n\tuser?: string;\n\t/** UNIX timestamp in milliseconds */\n\taddedAt?: number;\n}\n\nexport interface TriviaLeaderboardData {\n\t[userid: string]: TriviaLeaderboardScore;\n}\nexport interface TriviaLeaderboardScore {\n\tscore: number;\n\ttotalPoints: number;\n\ttotalCorrectAnswers: number;\n}\nexport interface TriviaGame {\n\tmode: string;\n\t/** if number, question cap, else score cap */\n\tlength: keyof typeof LENGTHS | number;\n\tcategory: string;\n\tstartTime: number;\n\tcreator?: string;\n\tgivesPoints?: boolean;\n}\n\ntype TriviaLadder = ID[][];\nexport type TriviaHistory = TriviaGame & { scores: { [k: string]: number } };\n\nexport interface TriviaData {\n\t/** category:questions */\n\tquestions?: { [k: string]: TriviaQuestion[] };\n\tsubmissions?: { [k: string]: TriviaQuestion[] };\n\tleaderboard?: TriviaLeaderboardData;\n\taltLeaderboard?: TriviaLeaderboardData;\n\t/* `scores` key is a user ID */\n\thistory?: TriviaHistory[];\n\tmoveEventQuestions?: boolean;\n}\n\ninterface TopPlayer {\n\tid: string;\n\tplayer: TriviaPlayer;\n\tname: string;\n}\n\nexport const database: TriviaDatabase = new TriviaSQLiteDatabase('config/chat-plugins/triviadata.json');\n\n/** from:to Map */\nexport const pendingAltMerges = new Map<ID, ID>();\n\nfunction getTriviaGame(room: Room | null) {\n\tif (!room) {\n\t\tthrow new Chat.ErrorMessage(`This command can only be used in the Trivia room.`);\n\t}\n\tconst game = room.game;\n\tif (!game) {\n\t\tthrow new Chat.ErrorMessage(room.tr`There is no game in progress.`);\n\t}\n\tif (game.gameid !== 'trivia') {\n\t\tthrow new Chat.ErrorMessage(room.tr`The currently running game is not Trivia, it's ${game.title}.`);\n\t}\n\treturn game as Trivia;\n}\n\nfunction getMastermindGame(room: Room | null) {\n\tif (!room) {\n\t\tthrow new Chat.ErrorMessage(`This command can only be used in the Trivia room.`);\n\t}\n\tconst game = room.game;\n\tif (!game) {\n\t\tthrow new Chat.ErrorMessage(room.tr`There is no game in progress.`);\n\t}\n\tif (game.gameid !== 'mastermind') {\n\t\tthrow new Chat.ErrorMessage(room.tr`The currently running game is not Mastermind, it's ${game.title}.`);\n\t}\n\treturn game as Mastermind;\n}\n\nfunction getTriviaOrMastermindGame(room: Room | null) {\n\ttry {\n\t\treturn getMastermindGame(room);\n\t} catch {\n\t\treturn getTriviaGame(room);\n\t}\n}\n\n/**\n * Generates and broadcasts the HTML for a generic announcement containing\n * a title and an optional message.\n */\nfunction broadcast(room: BasicRoom, title: string, message?: string) {\n\tlet buffer = `<div class=\"broadcast-blue\"><strong>${title}</strong>`;\n\tif (message) buffer += `<br />${message}`;\n\tbuffer += '</div>';\n\n\treturn room.addRaw(buffer).update();\n}\n\nasync function getQuestions(\n\tcategories: ID[] | 'random',\n\torder: 'newestfirst' | 'oldestfirst' | 'random',\n\tlimit = 1000\n): Promise<TriviaQuestion[]> {\n\tif (categories === 'random') {\n\t\tconst history = await database.getHistory(1);\n\t\tconst lastCategoryID = toID(history?.[0].category).replace(\"random\", \"\");\n\t\tconst randCategory = Utils.randomElement(\n\t\t\tObject.keys(MAIN_CATEGORIES)\n\t\t\t\t.filter(cat => toID(MAIN_CATEGORIES[cat]) !== lastCategoryID)\n\t\t);\n\t\treturn database.getQuestions([randCategory], limit, { order });\n\t} else {\n\t\tconst questions = [];\n\t\tfor (const category of categories) {\n\t\t\tif (category === 'all') {\n\t\t\t\tquestions.push(...(await database.getQuestions('all', limit, { order })));\n\t\t\t} else if (!ALL_CATEGORIES[category]) {\n\t\t\t\tthrow new Chat.ErrorMessage(`\"${category}\" is an invalid category.`);\n\t\t\t}\n\t\t}\n\t\tquestions.push(...(await database.getQuestions(categories.filter(c => c !== 'all'), limit, { order })));\n\t\treturn questions;\n\t}\n}\n\n/**\n * Records a pending alt merge\n */\nexport async function requestAltMerge(from: ID, to: ID) {\n\tif (from === to) throw new Chat.ErrorMessage(`You cannot merge leaderboard entries with yourself!`);\n\tif (!(await database.getLeaderboardEntry(from, 'alltime'))) {\n\t\tthrow new Chat.ErrorMessage(`The user '${from}' does not have an entry in the Trivia leaderboard.`);\n\t}\n\tif (!(await database.getLeaderboardEntry(to, 'alltime'))) {\n\t\tthrow new Chat.ErrorMessage(`The user '${to}' does not have an entry in the Trivia leaderboard.`);\n\t}\n\tpendingAltMerges.set(from, to);\n}\n\n/**\n * Checks that it has been approved by both users,\n * and merges two alts on the Trivia leaderboard.\n */\nexport async function mergeAlts(from: ID, to: ID) {\n\tif (pendingAltMerges.get(from) !== to) {\n\t\tthrow new Chat.ErrorMessage(`Both '${from}' and '${to}' must use /trivia mergescore to approve the merge.`);\n\t}\n\n\tif (!(await database.getLeaderboardEntry(to, 'alltime'))) {\n\t\tthrow new Chat.ErrorMessage(`The user '${to}' does not have an entry in the Trivia leaderboard.`);\n\t}\n\tif (!(await database.getLeaderboardEntry(from, 'alltime'))) {\n\t\tthrow new Chat.ErrorMessage(`The user '${from}' does not have an entry in the Trivia leaderboard.`);\n\t}\n\n\tawait database.mergeLeaderboardEntries(from, to);\n\tcachedLadder.invalidateCache();\n}\n\n// TODO: fix /trivia review\nclass Ladder {\n\tcache: Record<Leaderboard, { ladder: TriviaLadder, ranks: TriviaLeaderboardData } | null>;\n\tconstructor() {\n\t\tthis.cache = {\n\t\t\talltime: null,\n\t\t\tnonAlltime: null,\n\t\t\tcycle: null,\n\t\t};\n\t}\n\n\tinvalidateCache() {\n\t\tlet k: keyof Ladder['cache'];\n\t\tfor (k in this.cache) {\n\t\t\tthis.cache[k] = null;\n\t\t}\n\t}\n\n\tasync get(leaderboard: Leaderboard = 'alltime') {\n\t\tif (!this.cache[leaderboard]) await this.computeCachedLadder();\n\t\treturn this.cache[leaderboard];\n\t}\n\n\tasync computeCachedLadder() {\n\t\tconst leaderboards = await database.getLeaderboards();\n\t\tfor (const [lb, data] of Object.entries(leaderboards) as [Leaderboard, TriviaLeaderboardData][]) {\n\t\t\tconst leaders = Object.entries(data);\n\t\t\tconst ladder: TriviaLadder = [];\n\t\t\tconst ranks: TriviaLeaderboardData = {};\n\t\t\tfor (const [leader] of leaders) {\n\t\t\t\tranks[leader] = { score: 0, totalPoints: 0, totalCorrectAnswers: 0 };\n\t\t\t}\n\t\t\tfor (const key of ['score', 'totalPoints', 'totalCorrectAnswers'] as (keyof TriviaLeaderboardScore)[]) {\n\t\t\t\tUtils.sortBy(leaders, ([, scores]) => -scores[key]);\n\n\t\t\t\tlet max = Infinity;\n\t\t\t\tlet rank = -1;\n\t\t\t\tfor (const [leader, scores] of leaders) {\n\t\t\t\t\tconst score = scores[key];\n\t\t\t\t\tif (max !== score) {\n\t\t\t\t\t\trank++;\n\t\t\t\t\t\tmax = score;\n\t\t\t\t\t}\n\t\t\t\t\tif (key === 'score' && rank < 500) {\n\t\t\t\t\t\tif (!ladder[rank]) ladder[rank] = [];\n\t\t\t\t\t\tladder[rank].push(leader as ID);\n\t\t\t\t\t}\n\t\t\t\t\tranks[leader][key] = rank + 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.cache[lb] = { ladder, ranks };\n\t\t}\n\t}\n}\n\nexport const cachedLadder = new Ladder();\n\nclass TriviaPlayer extends Rooms.RoomGamePlayer<Trivia> {\n\tpoints: number;\n\tcorrectAnswers: number;\n\tanswer: string;\n\tcurrentAnsweredAt: number[];\n\tlastQuestion: number;\n\tansweredAt: number[];\n\tisCorrect: boolean;\n\tisAbsent: boolean;\n\n\tconstructor(user: User, game: Trivia) {\n\t\tsuper(user, game);\n\t\tthis.points = 0;\n\t\tthis.correctAnswers = 0;\n\t\tthis.answer = '';\n\t\tthis.currentAnsweredAt = [];\n\t\tthis.lastQuestion = 0;\n\t\tthis.answeredAt = [];\n\t\tthis.isCorrect = false;\n\t\tthis.isAbsent = false;\n\t}\n\n\tsetAnswer(answer: string, isCorrect?: boolean) {\n\t\tthis.answer = answer;\n\t\tthis.currentAnsweredAt = process.hrtime();\n\t\tthis.isCorrect = !!isCorrect;\n\t}\n\n\tincrementPoints(points = 0, lastQuestion = 0) {\n\t\tthis.points += points;\n\t\tthis.answeredAt = this.currentAnsweredAt;\n\t\tthis.lastQuestion = lastQuestion;\n\t\tthis.correctAnswers++;\n\t}\n\n\tclearAnswer() {\n\t\tthis.answer = '';\n\t\tthis.isCorrect = false;\n\t}\n\n\ttoggleAbsence() {\n\t\tthis.isAbsent = !this.isAbsent;\n\t}\n\n\treset() {\n\t\tthis.points = 0;\n\t\tthis.correctAnswers = 0;\n\t\tthis.answer = '';\n\t\tthis.answeredAt = [];\n\t\tthis.isCorrect = false;\n\t}\n}\n\nexport class Trivia extends Rooms.RoomGame<TriviaPlayer> {\n\toverride readonly gameid = 'trivia' as ID;\n\tkickedUsers: Set<string>;\n\tcanLateJoin: boolean;\n\tgame: TriviaGame;\n\tquestions: TriviaQuestion[];\n\tisPaused = false;\n\tphase: string;\n\tphaseTimeout: NodeJS.Timeout | null;\n\tquestionNumber: number;\n\tcurQuestion: string;\n\tcurAnswers: string[];\n\taskedAt: number[];\n\tcategories: ID[];\n\tconstructor(\n\t\troom: Room, mode: string, categories: ID[], givesPoints: boolean,\n\t\tlength: keyof typeof LENGTHS | number, questions: TriviaQuestion[], creator: string,\n\t\tisRandomMode = false, isSubGame = false, isRandomCategory = false,\n\t) {\n\t\tsuper(room, isSubGame);\n\t\tthis.title = 'Trivia';\n\t\tthis.allowRenames = true;\n\t\tthis.playerCap = Number.MAX_SAFE_INTEGER;\n\n\t\tthis.kickedUsers = new Set();\n\t\tthis.canLateJoin = true;\n\n\t\tthis.categories = categories;\n\t\tconst uniqueCategories = new Set(this.categories\n\t\t\t.map(cat => {\n\t\t\t\tif (cat === 'all') return 'All';\n\t\t\t\treturn ALL_CATEGORIES[CATEGORY_ALIASES[cat] || cat];\n\t\t\t}));\n\t\tlet category = [...uniqueCategories].join(' + ');\n\t\tif (isRandomCategory) category = this.room.tr`Random (${category})`;\n\n\t\tthis.game = {\n\t\t\tmode: (isRandomMode ? `Random (${MODES[mode]})` : MODES[mode]),\n\t\t\tlength,\n\t\t\tcategory,\n\t\t\tcreator,\n\t\t\tgivesPoints,\n\t\t\tstartTime: Date.now(),\n\t\t};\n\n\t\tthis.questions = questions;\n\n\t\tthis.phase = SIGNUP_PHASE;\n\t\tthis.phaseTimeout = null;\n\n\t\tthis.questionNumber = 0;\n\t\tthis.curQuestion = '';\n\t\tthis.curAnswers = [];\n\t\tthis.askedAt = [];\n\n\t\tthis.init();\n\t}\n\n\tsetPhaseTimeout(callback: (...args: any[]) => void, timeout: number) {\n\t\tif (this.phaseTimeout) {\n\t\t\tclearTimeout(this.phaseTimeout);\n\t\t}\n\t\tthis.phaseTimeout = setTimeout(callback, timeout);\n\t}\n\n\tgetCap() {\n\t\tif (this.game.length in LENGTHS) return { points: LENGTHS[this.game.length].cap };\n\t\tif (typeof this.game.length === 'number') return { questions: this.game.length };\n\t\tthrow new Error(`Couldn't determine cap for Trivia game with length ${this.game.length}`);\n\t}\n\n\tgetDisplayableCap() {\n\t\tconst cap = this.getCap();\n\t\tif (cap.questions) return `${cap.questions} questions`;\n\t\tif (cap.points) return `${cap.points} points`;\n\t\treturn `Infinite`;\n\t}\n\n\t/**\n\t * How long the players should have to answer a question.\n\t */\n\tgetRoundLength() {\n\t\treturn 12 * 1000 + 500;\n\t}\n\n\taddTriviaPlayer(user: User) {\n\t\tif (this.playerTable[user.id]) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You have already signed up for this game.`);\n\t\t}\n\t\tfor (const id of user.previousIDs) {\n\t\t\tif (this.playerTable[id]) throw new Chat.ErrorMessage(this.room.tr`You have already signed up for this game.`);\n\t\t}\n\t\tif (this.kickedUsers.has(user.id)) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You were kicked from the game and thus cannot join it again.`);\n\t\t}\n\t\tfor (const id of user.previousIDs) {\n\t\t\tif (this.playerTable[id]) {\n\t\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You have already signed up for this game.`);\n\t\t\t}\n\t\t\tif (this.kickedUsers.has(id)) {\n\t\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You were kicked from the game and cannot join until the next game.`);\n\t\t\t}\n\t\t}\n\n\t\tfor (const id in this.playerTable) {\n\t\t\tconst targetUser = Users.get(id);\n\t\t\tif (targetUser) {\n\t\t\t\tconst isSameUser = (\n\t\t\t\t\ttargetUser.previousIDs.includes(user.id) ||\n\t\t\t\t\ttargetUser.previousIDs.some(tarId => user.previousIDs.includes(tarId)) ||\n\t\t\t\t\t!Config.noipchecks && targetUser.ips.some(ip => user.ips.includes(ip))\n\t\t\t\t);\n\t\t\t\tif (isSameUser) throw new Chat.ErrorMessage(this.room.tr`You have already signed up for this game.`);\n\t\t\t}\n\t\t}\n\t\tif (this.phase !== SIGNUP_PHASE && !this.canLateJoin) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`This game does not allow latejoins.`);\n\t\t}\n\t\tthis.addPlayer(user);\n\t}\n\n\tmakePlayer(user: User): TriviaPlayer {\n\t\treturn new TriviaPlayer(user, this);\n\t}\n\n\tdestroy() {\n\t\tif (this.phaseTimeout) clearTimeout(this.phaseTimeout);\n\t\tthis.phaseTimeout = null;\n\t\tthis.kickedUsers.clear();\n\t\tsuper.destroy();\n\t}\n\n\tonConnect(user: User) {\n\t\tconst player = this.playerTable[user.id];\n\t\tif (!player?.isAbsent) return false;\n\n\t\tplayer.toggleAbsence();\n\t}\n\n\tonLeave(user: User, oldUserID: ID) {\n\t\t// The user cannot participate, but their score should be kept\n\t\t// regardless in cases of disconnects.\n\t\tconst player = this.playerTable[oldUserID || user.id];\n\t\tif (!player || player.isAbsent) return false;\n\n\t\tplayer.toggleAbsence();\n\t}\n\n\t/**\n\t * Handles setup that shouldn't be done from the constructor.\n\t */\n\tinit() {\n\t\tconst signupsMessage = this.game.givesPoints ?\n\t\t\t`Signups for a new Trivia game have begun!` : `Signups for a new unranked Trivia game have begun!`;\n\t\tbroadcast(\n\t\t\tthis.room,\n\t\t\tthis.room.tr(signupsMessage),\n\t\t\tthis.room.tr`Mode: ${this.game.mode} | Category: ${this.game.category} | Cap: ${this.getDisplayableCap()}<br />` +\n\t\t\t`<button class=\"button\" name=\"send\" value=\"/trivia join\">` + this.room.tr`Sign up for the Trivia game!` + `</button>` +\n\t\t\tthis.room.tr` (You can also type <code>/trivia join</code> to sign up manually.)`\n\t\t);\n\t}\n\n\tgetDescription() {\n\t\treturn this.room.tr`Mode: ${this.game.mode} | Category: ${this.game.category} | Cap: ${this.getDisplayableCap()}`;\n\t}\n\n\t/**\n\t * Formats the player list for display when using /trivia players.\n\t */\n\tformatPlayerList(settings: { max: number | null, requirePoints?: boolean }) {\n\t\treturn this.getTopPlayers(settings).map(player => {\n\t\t\tconst buf = Utils.html`${player.name} (${player.player.points || \"0\"})`;\n\t\t\treturn player.player.isAbsent ? `<span style=\"color: #444444\">${buf}</span>` : buf;\n\t\t}).join(', ');\n\t}\n\n\t/**\n\t * Kicks a player from the game, preventing them from joining it again\n\t * until the next game begins.\n\t */\n\tkick(user: User) {\n\t\tif (!this.playerTable[user.id]) {\n\t\t\tif (this.kickedUsers.has(user.id)) {\n\t\t\t\tthrow new Chat.ErrorMessage(this.room.tr`User ${user.name} has already been kicked from the game.`);\n\t\t\t}\n\n\t\t\tfor (const id of user.previousIDs) {\n\t\t\t\tif (this.kickedUsers.has(id)) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.room.tr`User ${user.name} has already been kicked from the game.`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const kickedUserid of this.kickedUsers) {\n\t\t\t\tconst kickedUser = Users.get(kickedUserid);\n\t\t\t\tif (kickedUser) {\n\t\t\t\t\tconst isSameUser = (\n\t\t\t\t\t\tkickedUser.previousIDs.includes(user.id) ||\n\t\t\t\t\t\tkickedUser.previousIDs.some(id => user.previousIDs.includes(id)) ||\n\t\t\t\t\t\t!Config.noipchecks && kickedUser.ips.some(ip => user.ips.includes(ip))\n\t\t\t\t\t);\n\t\t\t\t\tif (isSameUser) throw new Chat.ErrorMessage(this.room.tr`User ${user.name} has already been kicked from the game.`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`User ${user.name} is not a player in the game.`);\n\t\t}\n\n\t\tthis.kickedUsers.add(user.id);\n\t\tfor (const id of user.previousIDs) {\n\t\t\tthis.kickedUsers.add(id);\n\t\t}\n\n\t\tthis.removePlayer(this.playerTable[user.id]);\n\t}\n\n\tleave(user: User) {\n\t\tif (!this.playerTable[user.id]) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You are not a player in the current game.`);\n\t\t}\n\t\tthis.removePlayer(this.playerTable[user.id]);\n\t}\n\n\t/**\n\t * Starts the question loop for a trivia game in its signup phase.\n\t */\n\tstart() {\n\t\tif (this.phase !== SIGNUP_PHASE) throw new Chat.ErrorMessage(this.room.tr`The game has already been started.`);\n\n\t\tbroadcast(this.room, this.room.tr`The game will begin in ${START_TIMEOUT / 1000} seconds...`);\n\t\tthis.phase = INTERMISSION_PHASE;\n\t\tthis.setPhaseTimeout(() => void this.askQuestion(), START_TIMEOUT);\n\t}\n\n\tpause() {\n\t\tif (this.isPaused) throw new Chat.ErrorMessage(this.room.tr`The trivia game is already paused.`);\n\t\tif (this.phase === QUESTION_PHASE) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You cannot pause the trivia game during a question.`);\n\t\t}\n\t\tthis.isPaused = true;\n\t\tbroadcast(this.room, this.room.tr`The Trivia game has been paused.`);\n\t}\n\n\tresume() {\n\t\tif (!this.isPaused) throw new Chat.ErrorMessage(this.room.tr`The trivia game is not paused.`);\n\t\tthis.isPaused = false;\n\t\tbroadcast(this.room, this.room.tr`The Trivia game has been resumed.`);\n\t\tif (this.phase === INTERMISSION_PHASE) this.setPhaseTimeout(() => void this.askQuestion(), PAUSE_INTERMISSION);\n\t}\n\n\t/**\n\t * Broadcasts the next question on the questions list to the room and sets\n\t * a timeout to tally the answers received.\n\t */\n\tasync askQuestion() {\n\t\tif (this.isPaused) return;\n\t\tif (!this.questions.length) {\n\t\t\tconst cap = this.getCap();\n\t\t\tif (!cap.questions && !cap.points) {\n\t\t\t\tif (this.game.length === 'infinite') {\n\t\t\t\t\tthis.questions = await database.getQuestions(this.categories, 1000, {\n\t\t\t\t\t\torder: this.game.mode.startsWith('Random') ? 'random' : 'oldestfirst',\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t// If there's no score cap, we declare a winner when we run out of questions,\n\t\t\t\t// instead of ending a game with a stalemate\n\t\t\t\tvoid this.win(`The game of Trivia has ended because there are no more questions!`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (this.phaseTimeout) clearTimeout(this.phaseTimeout);\n\t\t\tthis.phaseTimeout = null;\n\t\t\tbroadcast(\n\t\t\t\tthis.room,\n\t\t\t\tthis.room.tr`No questions are left!`,\n\t\t\t\tthis.room.tr`The game has reached a stalemate`\n\t\t\t);\n\t\t\tif (this.room) this.destroy();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.phase = QUESTION_PHASE;\n\t\tthis.askedAt = process.hrtime();\n\n\t\tconst question = this.questions.shift()!;\n\t\tthis.questionNumber++;\n\t\tthis.curQuestion = question.question;\n\t\tthis.curAnswers = question.answers;\n\t\tthis.sendQuestion(question);\n\t\tthis.setTallyTimeout();\n\n\t\t// Move question categories if needed\n\t\tif (question.category === MOVE_QUESTIONS_AFTER_USE_FROM_CATEGORY && await database.shouldMoveEventQuestions()) {\n\t\t\tawait database.moveQuestionToCategory(question.question, MOVE_QUESTIONS_AFTER_USE_TO_CATEGORY);\n\t\t}\n\t}\n\n\tsetTallyTimeout() {\n\t\tthis.setPhaseTimeout(() => void this.tallyAnswers(), this.getRoundLength());\n\t}\n\n\t/**\n\t * Broadcasts to the room what the next question is.\n\t */\n\tsendQuestion(question: TriviaQuestion) {\n\t\tbroadcast(\n\t\t\tthis.room,\n\t\t\tthis.room.tr`Question ${this.questionNumber}: ${question.question}`,\n\t\t\tthis.room.tr`Category: ${ALL_CATEGORIES[question.category]}`\n\t\t);\n\t}\n\n\t/**\n\t * This is a noop here since it'd defined properly by subclasses later on.\n\t * All this is obligated to do is take a user and their answer as args;\n\t * the behaviour of this method can be entirely arbitrary otherwise.\n\t */\n\tanswerQuestion(answer: string, user: User): string | void {}\n\n\t/**\n\t * Verifies whether or not an answer is correct. In longer answers, small\n\t * typos can be made and still have the answer be considered correct.\n\t */\n\tverifyAnswer(targetAnswer: string) {\n\t\treturn this.curAnswers.some(answer => {\n\t\t\tconst mla = this.maxLevenshteinAllowed(answer.length);\n\t\t\treturn (answer === targetAnswer) || (Utils.levenshtein(targetAnswer, answer, mla) <= mla);\n\t\t});\n\t}\n\n\t/**\n\t * Return the maximum Levenshtein distance that is allowable for answers of the given length.\n\t */\n\tmaxLevenshteinAllowed(answerLength: number) {\n\t\tif (answerLength > 5) {\n\t\t\treturn 2;\n\t\t}\n\n\t\tif (answerLength > 4) {\n\t\t\treturn 1;\n\t\t}\n\n\t\treturn 0;\n\t}\n\t/**\n\t * This is a noop here since it'd defined properly by mode subclasses later\n\t * on. This calculates the points a correct responder earns, which is\n\t * typically between 1-5.\n\t */\n\tcalculatePoints(diff: number, totalDiff: number) {}\n\n\t/**\n\t * This is a noop here since it's defined properly by mode subclasses later\n\t * on. This is obligated to update the game phase, but it can be entirely\n\t * arbitrary otherwise.\n\t */\n\ttallyAnswers(): void | Promise<void> {}\n\n\t/**\n\t * Ends the game after a player's score has exceeded the score cap.\n\t */\n\tasync win(buffer: string) {\n\t\tif (this.phaseTimeout) clearTimeout(this.phaseTimeout);\n\t\tthis.phaseTimeout = null;\n\t\tconst winners = this.getTopPlayers({ max: 3, requirePoints: true });\n\t\tbuffer += `<br />${this.getWinningMessage(winners)}`;\n\t\tbroadcast(this.room, this.room.tr`The answering period has ended!`, buffer);\n\n\t\tfor (const i in this.playerTable) {\n\t\t\tconst player = this.playerTable[i];\n\t\t\tconst user = Users.get(player.id);\n\t\t\tif (!user) continue;\n\t\t\tuser.sendTo(\n\t\t\t\tthis.room.roomid,\n\t\t\t\t(this.game.givesPoints ? this.room.tr`You gained ${player.points} points and answered ` : this.room.tr`You answered `) +\n\t\t\t\tthis.room.tr`${player.correctAnswers} questions correctly.`\n\t\t\t);\n\t\t}\n\n\t\tconst buf = this.getStaffEndMessage(winners, winner => winner.player.name);\n\t\tconst logbuf = this.getStaffEndMessage(winners, winner => winner.id);\n\t\tthis.room.sendMods(`(${buf}!)`);\n\t\tthis.room.roomlog(buf);\n\t\tthis.room.modlog({\n\t\t\taction: 'TRIVIAGAME',\n\t\t\tloggedBy: toID(this.game.creator),\n\t\t\tnote: logbuf,\n\t\t});\n\n\t\tif (this.game.givesPoints) {\n\t\t\tconst prizes = this.getPrizes();\n\t\t\t// these are for the non-all-time leaderboard\n\t\t\t// only the #1 player gets a prize on the all-time leaderboard\n\t\t\tconst scores = new Map<ID, number>();\n\t\t\tfor (let i = 0; i < winners.length; i++) {\n\t\t\t\tscores.set(winners[i].id as ID, prizes[i]);\n\t\t\t}\n\n\t\t\tfor (const userid in this.playerTable) {\n\t\t\t\tconst player = this.playerTable[userid];\n\t\t\t\tif (!player.points) continue;\n\n\t\t\t\tvoid database.updateLeaderboardForUser(userid as ID, {\n\t\t\t\t\talltime: {\n\t\t\t\t\t\tscore: userid === winners[0].id ? prizes[0] : 0,\n\t\t\t\t\t\ttotalPoints: player.points,\n\t\t\t\t\t\ttotalCorrectAnswers: player.correctAnswers,\n\t\t\t\t\t},\n\t\t\t\t\tnonAlltime: {\n\t\t\t\t\t\tscore: scores.get(userid as ID) || 0,\n\t\t\t\t\t\ttotalPoints: player.points,\n\t\t\t\t\t\ttotalCorrectAnswers: player.correctAnswers,\n\t\t\t\t\t},\n\t\t\t\t\tcycle: {\n\t\t\t\t\t\tscore: scores.get(userid as ID) || 0,\n\t\t\t\t\t\ttotalPoints: player.points,\n\t\t\t\t\t\ttotalCorrectAnswers: player.correctAnswers,\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tcachedLadder.invalidateCache();\n\t\t}\n\n\t\tif (typeof this.game.length === 'number') this.game.length = `${this.game.length} questions`;\n\n\t\tconst scores = Object.fromEntries(this.getTopPlayers({ max: null })\n\t\t\t.map(player => [player.player.id, player.player.points]));\n\t\tif (this.game.givesPoints) {\n\t\t\tawait database.addHistory([{\n\t\t\t\t...this.game,\n\t\t\t\tlength: typeof this.game.length === 'number' ? `${this.game.length} questions` : this.game.length,\n\t\t\t\tscores,\n\t\t\t}]);\n\t\t}\n\n\t\tthis.destroy();\n\t}\n\n\tgetPrizes() {\n\t\t// Reward players more in longer infinite games\n\t\tconst multiplier = this.game.length === 'infinite' ? Math.floor(this.questionNumber / 25) || 1 : 1;\n\t\treturn (LENGTHS[this.game.length]?.prizes || [5, 3, 1]).map(prize => prize * multiplier);\n\t}\n\n\tgetTopPlayers(\n\t\toptions: { max: number | null, requirePoints?: boolean } = { max: null, requirePoints: true }\n\t): TopPlayer[] {\n\t\tconst ranks = [];\n\t\tfor (const userid in this.playerTable) {\n\t\t\tconst user = Users.get(userid);\n\t\t\tconst player = this.playerTable[userid];\n\t\t\tif ((options.requirePoints && !player.points) || !user) continue;\n\t\t\tranks.push({ id: userid, player, name: user.name });\n\t\t}\n\t\tUtils.sortBy(ranks, ({ player }) => (\n\t\t\t[-player.points, player.lastQuestion, hrtimeToNanoseconds(player.answeredAt)]\n\t\t));\n\t\treturn options.max === null ? ranks : ranks.slice(0, options.max);\n\t}\n\n\tgetWinningMessage(winners: TopPlayer[]) {\n\t\tconst prizes = this.getPrizes();\n\t\tconst [p1, p2, p3] = winners;\n\n\t\tif (!p1) return `No winners this game!`;\n\t\tlet initialPart = this.room.tr`${Utils.escapeHTML(p1.name)} won the game with a final score of <strong>${p1.player.points}</strong>`;\n\t\tif (!this.game.givesPoints) {\n\t\t\treturn `${initialPart}.`;\n\t\t} else {\n\t\t\tinitialPart += this.room.tr`, and `;\n\t\t}\n\n\t\tswitch (winners.length) {\n\t\tcase 1:\n\t\t\treturn this.room.tr`${initialPart}their leaderboard score has increased by <strong>${prizes[0]}</strong> points!`;\n\t\tcase 2:\n\t\t\treturn this.room.tr`${initialPart}their leaderboard score has increased by <strong>${prizes[0]}</strong> points! ` +\n\t\t\t\tthis.room.tr`${Utils.escapeHTML(p2.name)} was a runner-up and their leaderboard score has increased by <strong>${prizes[1]}</strong> points!`;\n\t\tcase 3:\n\t\t\treturn initialPart + Utils.html`${this.room.tr`${p2.name} and ${p3.name} were runners-up. `}` +\n\t\t\t\tthis.room.tr`Their leaderboard score has increased by ${prizes[0]}, ${prizes[1]}, and ${prizes[2]}, respectively!`;\n\t\t}\n\t}\n\n\tgetStaffEndMessage(winners: TopPlayer[], mapper: (k: TopPlayer) => string) {\n\t\tlet message = \"\";\n\t\tif (winners.length) {\n\t\t\tconst winnerParts: ((k: TopPlayer) => string)[] = [\n\t\t\t\twinner => this.room.tr`User ${mapper(winner)} won the game of ` +\n\t\t\t\t\t(this.game.givesPoints ? this.room.tr`ranked ` : this.room.tr`unranked `) +\n\t\t\t\t\tthis.room.tr`${this.game.mode} mode trivia under the ${this.game.category} category with ` +\n\t\t\t\t\tthis.room.tr`a cap of ${this.getDisplayableCap()} ` +\n\t\t\t\t\tthis.room.tr`with ${winner.player.points} points and ` +\n\t\t\t\t\tthis.room.tr`${winner.player.correctAnswers} correct answers`,\n\t\t\t\twinner => this.room.tr` Second place: ${mapper(winner)} (${winner.player.points} points)`,\n\t\t\t\twinner => this.room.tr`, third place: ${mapper(winner)} (${winner.player.points} points)`,\n\t\t\t];\n\t\t\tfor (const [i, winner] of winners.entries()) {\n\t\t\t\tmessage += winnerParts[i](winner);\n\t\t\t}\n\t\t} else {\n\t\t\tmessage = `No participants in the game of ` +\n\t\t\t\t(this.game.givesPoints ? this.room.tr`ranked ` : this.room.tr`unranked `) +\n\t\t\t\tthis.room.tr`${this.game.mode} mode trivia under the ${this.game.category} category with ` +\n\t\t\t\tthis.room.tr`a cap of ${this.getDisplayableCap()}`;\n\t\t}\n\t\treturn `${message}`;\n\t}\n\n\tend(user: User) {\n\t\tbroadcast(this.room, Utils.html`${this.room.tr`The game was forcibly ended by ${user.name}.`}`);\n\t\tthis.destroy();\n\t}\n}\n\n/**\n * Helper function for timer and number modes. Milliseconds are not precise\n * enough to score players properly in rare cases.\n */\nconst hrtimeToNanoseconds = (hrtime: number[]) => hrtime[0] * 1e9 + hrtime[1];\n\n/**\n * First mode rewards points to the first user to answer the question\n * correctly.\n */\nexport class FirstModeTrivia extends Trivia {\n\tanswerQuestion(answer: string, user: User) {\n\t\tconst player = this.playerTable[user.id];\n\t\tif (!player) throw new Chat.ErrorMessage(this.room.tr`You are not a player in the current trivia game.`);\n\t\tif (this.isPaused) throw new Chat.ErrorMessage(this.room.tr`The trivia game is paused.`);\n\t\tif (this.phase !== QUESTION_PHASE) throw new Chat.ErrorMessage(this.room.tr`There is no question to answer.`);\n\t\tif (player.answer) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You have already attempted to answer the current question.`);\n\t\t}\n\t\tif (!this.verifyAnswer(answer)) return;\n\n\t\tif (this.phaseTimeout) clearTimeout(this.phaseTimeout);\n\t\tthis.phase = INTERMISSION_PHASE;\n\n\t\tconst points = this.calculatePoints();\n\t\tplayer.setAnswer(answer);\n\t\tplayer.incrementPoints(points, this.questionNumber);\n\n\t\tconst players = user.name;\n\t\tconst buffer = Utils.html`${this.room.tr`Correct: ${players}`}<br />` +\n\t\t\tthis.room.tr`Answer(s): ${this.curAnswers.join(', ')}` + `<br />` +\n\t\t\tthis.room.tr`They gained <strong>5</strong> points!` + `<br />` +\n\t\t\tthis.room.tr`The top 5 players are: ${this.formatPlayerList({ max: 5 })}`;\n\n\t\tconst cap = this.getCap();\n\t\tif ((cap.points && player.points >= cap.points) || (cap.questions && this.questionNumber >= cap.questions)) {\n\t\t\tvoid this.win(buffer);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const i in this.playerTable) {\n\t\t\tthis.playerTable[i].clearAnswer();\n\t\t}\n\n\t\tbroadcast(this.room, this.room.tr`The answering period has ended!`, buffer);\n\t\tthis.setAskTimeout();\n\t}\n\n\tcalculatePoints() {\n\t\treturn 5;\n\t}\n\n\ttallyAnswers(): void {\n\t\tif (this.isPaused) return;\n\t\tthis.phase = INTERMISSION_PHASE;\n\n\t\tfor (const i in this.playerTable) {\n\t\t\tconst player = this.playerTable[i];\n\t\t\tplayer.clearAnswer();\n\t\t}\n\n\t\tbroadcast(\n\t\t\tthis.room,\n\t\t\tthis.room.tr`The answering period has ended!`,\n\t\t\tthis.room.tr`Correct: no one...` + `<br />` +\n\t\t\tthis.room.tr`Answers: ${this.curAnswers.join(', ')}` + `<br />` +\n\t\t\tthis.room.tr`Nobody gained any points.` + `<br />` +\n\t\t\tthis.room.tr`The top 5 players are: ${this.formatPlayerList({ max: 5 })}`\n\t\t);\n\t\tthis.setAskTimeout();\n\t}\n\n\tsetAskTimeout() {\n\t\tthis.setPhaseTimeout(() => void this.askQuestion(), INTERMISSION_INTERVAL);\n\t}\n}\n\n/**\n * Timer mode rewards up to 5 points to all players who answer correctly\n * depending on how quickly they answer the question.\n */\nexport class TimerModeTrivia extends Trivia {\n\tanswerQuestion(answer: string, user: User) {\n\t\tconst player = this.playerTable[user.id];\n\t\tif (!player) throw new Chat.ErrorMessage(this.room.tr`You are not a player in the current trivia game.`);\n\t\tif (this.isPaused) throw new Chat.ErrorMessage(this.room.tr`The trivia game is paused.`);\n\t\tif (this.phase !== QUESTION_PHASE) throw new Chat.ErrorMessage(this.room.tr`There is no question to answer.`);\n\n\t\tconst isCorrect = this.verifyAnswer(answer);\n\t\tplayer.setAnswer(answer, isCorrect);\n\t}\n\n\t/**\n\t * The difference between the time the player answered the question and\n\t * when the question was asked, in nanoseconds.\n\t * The difference between the time scoring began and the time the question\n\t * was asked, in nanoseconds.\n\t */\n\tcalculatePoints(diff: number, totalDiff: number) {\n\t\treturn Math.floor(6 - 5 * diff / totalDiff);\n\t}\n\n\ttallyAnswers() {\n\t\tif (this.isPaused) return;\n\t\tthis.phase = INTERMISSION_PHASE;\n\n\t\tlet buffer = (\n\t\t\tthis.room.tr`Answer(s): ${this.curAnswers.join(', ')}<br />` +\n\t\t\t`<table style=\"width: 100%; background-color: #9CBEDF; margin: 2px 0\">` +\n\t\t\t`<tr style=\"background-color: #6688AA\">` +\n\t\t\t`<th style=\"width: 100px\">Points gained</th>` +\n\t\t\t`<th>${this.room.tr`Correct`}</th>` +\n\t\t\t`</tr>`\n\t\t);\n\t\tconst innerBuffer = new Map<number, [string, number][]>([5, 4, 3, 2, 1].map(n => [n, []]));\n\n\t\tconst now = hrtimeToNanoseconds(process.hrtime());\n\t\tconst askedAt = hrtimeToNanoseconds(this.askedAt);\n\t\tconst totalDiff = now - askedAt;\n\t\tconst cap = this.getCap();\n\n\t\tlet winner = cap.questions && this.questionNumber >= cap.questions;\n\n\t\tfor (const userid in this.playerTable) {\n\t\t\tconst player = this.playerTable[userid];\n\t\t\tif (!player.isCorrect) {\n\t\t\t\tplayer.clearAnswer();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst playerAnsweredAt = hrtimeToNanoseconds(player.currentAnsweredAt);\n\t\t\tconst diff = playerAnsweredAt - askedAt;\n\t\t\tconst points = this.calculatePoints(diff, totalDiff);\n\t\t\tplayer.incrementPoints(points, this.questionNumber);\n\n\t\t\tconst pointBuffer = innerBuffer.get(points) || [];\n\t\t\tpointBuffer.push([player.name, playerAnsweredAt]);\n\n\t\t\tif (cap.points && player.points >= cap.points) {\n\t\t\t\twinner = true;\n\t\t\t}\n\n\t\t\tplayer.clearAnswer();\n\t\t}\n\n\t\tlet rowAdded = false;\n\t\tfor (const [pointValue, players] of innerBuffer) {\n\t\t\tif (!players.length) continue;\n\n\t\t\trowAdded = true;\n\t\t\tconst playerNames = Utils.sortBy(players, ([name, answeredAt]) => answeredAt)\n\t\t\t\t.map(([name]) => name);\n\t\t\tbuffer += (\n\t\t\t\t'<tr style=\"background-color: #6688AA\">' +\n\t\t\t\t`<td style=\"text-align: center\">${pointValue}</td>` +\n\t\t\t\tUtils.html`<td>${playerNames.join(', ')}</td>` +\n\t\t\t\t'</tr>'\n\t\t\t);\n\t\t}\n\n\t\tif (!rowAdded) {\n\t\t\tbuffer += (\n\t\t\t\t'<tr style=\"background-color: #6688AA\">' +\n\t\t\t\t'<td style=\"text-align: center\">—</td>' +\n\t\t\t\t`<td>${this.room.tr`No one answered correctly...`}</td>` +\n\t\t\t\t'</tr>'\n\t\t\t);\n\t\t}\n\n\t\tbuffer += '</table>';\n\t\tbuffer += `<br />${this.room.tr`The top 5 players are: ${this.formatPlayerList({ max: 5 })}`}`;\n\n\t\tif (winner) {\n\t\t\treturn this.win(buffer);\n\t\t} else {\n\t\t\tbroadcast(this.room, this.room.tr`The answering period has ended!`, buffer);\n\t\t}\n\t\tthis.setPhaseTimeout(() => void this.askQuestion(), INTERMISSION_INTERVAL);\n\t}\n}\n\n/**\n * Number mode rewards up to 5 points to all players who answer correctly\n * depending on the ratio of correct players to total players (lower ratio is\n * better).\n */\nexport class NumberModeTrivia extends Trivia {\n\tanswerQuestion(answer: string, user: User) {\n\t\tconst player = this.playerTable[user.id];\n\t\tif (!player) throw new Chat.ErrorMessage(this.room.tr`You are not a player in the current trivia game.`);\n\t\tif (this.isPaused) throw new Chat.ErrorMessage(this.room.tr`The trivia game is paused.`);\n\t\tif (this.phase !== QUESTION_PHASE) throw new Chat.ErrorMessage(this.room.tr`There is no question to answer.`);\n\n\t\tconst isCorrect = this.verifyAnswer(answer);\n\t\tplayer.setAnswer(answer, isCorrect);\n\t}\n\n\tcalculatePoints(correctPlayers: number) {\n\t\treturn correctPlayers && (6 - Math.floor(5 * correctPlayers / this.playerCount));\n\t}\n\n\tgetRoundLength() {\n\t\treturn 6 * 1000;\n\t}\n\n\ttallyAnswers() {\n\t\tif (this.isPaused) return;\n\t\tthis.phase = INTERMISSION_PHASE;\n\n\t\tlet buffer;\n\t\tconst innerBuffer = Utils.sortBy(\n\t\t\tObject.values(this.playerTable)\n\t\t\t\t.filter(player => !!player.isCorrect)\n\t\t\t\t.map(player => [player.name, hrtimeToNanoseconds(player.currentAnsweredAt)]),\n\t\t\t([player, answeredAt]) => answeredAt\n\t\t);\n\n\t\tconst points = this.calculatePoints(innerBuffer.length);\n\t\tconst cap = this.getCap();\n\t\tlet winner = cap.questions && this.questionNumber >= cap.questions;\n\t\tif (points) {\n\t\t\tfor (const userid in this.playerTable) {\n\t\t\t\tconst player = this.playerTable[userid];\n\t\t\t\tif (player.isCorrect) player.incrementPoints(points, this.questionNumber);\n\n\t\t\t\tif (cap.points && player.points >= cap.points) {\n\t\t\t\t\twinner = true;\n\t\t\t\t}\n\n\t\t\t\tplayer.clearAnswer();\n\t\t\t}\n\n\t\t\tconst players = Utils.escapeHTML(innerBuffer.map(([playerName]) => playerName).join(', '));\n\t\t\tbuffer = this.room.tr`Correct: ${players}` + `<br />` +\n\t\t\t\tthis.room.tr`Answer(s): ${this.curAnswers.join(', ')}<br />` +\n\t\t\t\t`${Chat.plural(innerBuffer, this.room.tr`Each of them gained <strong>${points}</strong> point(s)!`, this.room.tr`They gained <strong>${points}</strong> point(s)!`)}`;\n\t\t} else {\n\t\t\tfor (const userid in this.playerTable) {\n\t\t\t\tconst player = this.playerTable[userid];\n\t\t\t\tplayer.clearAnswer();\n\t\t\t}\n\n\t\t\tbuffer = this.room.tr`Correct: no one...` + `<br />` +\n\t\t\t\tthis.room.tr`Answer(s): ${this.curAnswers.join(', ')}<br />` +\n\t\t\t\tthis.room.tr`Nobody gained any points.`;\n\t\t}\n\n\t\tbuffer += `<br />${this.room.tr`The top 5 players are: ${this.formatPlayerList({ max: 5 })}`}`;\n\n\t\tif (winner) {\n\t\t\treturn this.win(buffer);\n\t\t} else {\n\t\t\tbroadcast(this.room, this.room.tr`The answering period has ended!`, buffer);\n\t\t}\n\t\tthis.setPhaseTimeout(() => void this.askQuestion(), INTERMISSION_INTERVAL);\n\t}\n}\n\n/**\n * Triumvirate mode rewards points to the top three users to answer the question correctly.\n */\nexport class TriumvirateModeTrivia extends Trivia {\n\tanswerQuestion(answer: string, user: User) {\n\t\tconst player = this.playerTable[user.id];\n\t\tif (!player) throw new Chat.ErrorMessage(this.room.tr`You are not a player in the current trivia game.`);\n\t\tif (this.isPaused) throw new Chat.ErrorMessage(this.room.tr`The trivia game is paused.`);\n\t\tif (this.phase !== QUESTION_PHASE) throw new Chat.ErrorMessage(this.room.tr`There is no question to answer.`);\n\t\tplayer.setAnswer(answer, this.verifyAnswer(answer));\n\t\tconst correctAnswers = Object.keys(this.playerTable).filter(id => this.playerTable[id].isCorrect).length;\n\t\tif (correctAnswers === 3) {\n\t\t\tif (this.phaseTimeout) clearTimeout(this.phaseTimeout);\n\t\t\tvoid this.tallyAnswers();\n\t\t}\n\t}\n\n\tcalculatePoints(answerNumber: number) {\n\t\treturn 5 - answerNumber * 2; // 5 points to 1st, 3 points to 2nd, 1 point to 1st\n\t}\n\n\ttallyAnswers() {\n\t\tif (this.isPaused) return;\n\t\tthis.phase = INTERMISSION_PHASE;\n\t\tconst correctPlayers = Object.values(this.playerTable).filter(p => p.isCorrect);\n\t\tUtils.sortBy(correctPlayers, p => hrtimeToNanoseconds(p.currentAnsweredAt));\n\n\t\tconst cap = this.getCap();\n\t\tlet winner = cap.questions && this.questionNumber >= cap.questions;\n\t\tconst playersWithPoints = [];\n\t\tfor (const player of correctPlayers) {\n\t\t\tconst points = this.calculatePoints(correctPlayers.indexOf(player));\n\t\t\tplayer.incrementPoints(points, this.questionNumber);\n\t\t\tplayersWithPoints.push(`${Utils.escapeHTML(player.name)} (${points})`);\n\t\t\tif (cap.points && player.points >= cap.points) {\n\t\t\t\twinner = true;\n\t\t\t}\n\t\t}\n\t\tfor (const i in this.playerTable) {\n\t\t\tthis.playerTable[i].clearAnswer();\n\t\t}\n\n\t\tlet buffer = ``;\n\t\tif (playersWithPoints.length) {\n\t\t\tconst players = playersWithPoints.join(\", \");\n\t\t\tbuffer = this.room.tr`Correct: ${players}<br />` +\n\t\t\t\tthis.room.tr`Answers: ${this.curAnswers.join(', ')}<br />` +\n\t\t\t\tthis.room.tr`The top 5 players are: ${this.formatPlayerList({ max: 5 })}`;\n\t\t} else {\n\t\t\tbuffer = this.room.tr`Correct: no one...` + `<br />` +\n\t\t\t\tthis.room.tr`Answers: ${this.curAnswers.join(', ')}<br />` +\n\t\t\t\tthis.room.tr`Nobody gained any points.` + `<br />` +\n\t\t\t\tthis.room.tr`The top 5 players are: ${this.formatPlayerList({ max: 5 })}`;\n\t\t}\n\n\t\tif (winner) return this.win(buffer);\n\t\tbroadcast(this.room, this.room.tr`The answering period has ended!`, buffer);\n\t\tthis.setPhaseTimeout(() => void this.askQuestion(), INTERMISSION_INTERVAL);\n\t}\n}\n\n/**\n * Mastermind is a separate, albeit similar, game from regular Trivia.\n *\n * In Mastermind, each player plays their own personal round of Trivia,\n * and the top n players from those personal rounds go on to the finals,\n * which is a game of First mode trivia that ends after a specified interval.\n */\nexport class Mastermind extends Rooms.SimpleRoomGame {\n\toverride readonly gameid = 'mastermind' as ID;\n\t/** userid:score Map */\n\tleaderboard: Map<ID, { score: number, hasLeft?: boolean }>;\n\tphase: string;\n\tcurrentRound: MastermindRound | MastermindFinals | null;\n\tnumFinalists: number;\n\n\tconstructor(room: Room, numFinalists: number) {\n\t\tsuper(room);\n\n\t\tthis.leaderboard = new Map();\n\t\tthis.title = 'Mastermind';\n\t\tthis.allowRenames = true;\n\t\tthis.playerCap = Number.MAX_SAFE_INTEGER;\n\t\tthis.phase = SIGNUP_PHASE;\n\t\tthis.currentRound = null;\n\t\tthis.numFinalists = numFinalists;\n\t\tthis.init();\n\t}\n\n\tinit() {\n\t\tbroadcast(\n\t\t\tthis.room,\n\t\t\tthis.room.tr`Signups for a new Mastermind game have begun!`,\n\t\t\tthis.room.tr`The top <strong>${this.numFinalists}</strong> players will advance to the finals!` + `<br />` +\n\t\t\tthis.room.tr`Type <code>/mastermind join</code> to sign up for the game.`\n\t\t);\n\t}\n\n\taddTriviaPlayer(user: User) {\n\t\tif (user.previousIDs.concat(user.id).some(id => id in this.playerTable)) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You have already signed up for this game.`);\n\t\t}\n\n\t\tfor (const targetUser of Object.keys(this.playerTable).map(id => Users.get(id))) {\n\t\t\tif (!targetUser) continue;\n\t\t\tconst isSameUser = (\n\t\t\t\ttargetUser.previousIDs.includes(user.id) ||\n\t\t\t\ttargetUser.previousIDs.some(tarId => user.previousIDs.includes(tarId)) ||\n\t\t\t\t!Config.noipchecks && targetUser.ips.some(ip => user.ips.includes(ip))\n\t\t\t);\n\t\t\tif (isSameUser) throw new Chat.ErrorMessage(this.room.tr`You have already signed up for this game.`);\n\t\t}\n\n\t\tthis.addPlayer(user);\n\t}\n\n\tformatPlayerList() {\n\t\treturn Utils.sortBy(\n\t\t\tObject.values(this.playerTable),\n\t\t\tplayer => -(this.leaderboard.get(player.id)?.score || 0)\n\t\t).map(player => {\n\t\t\tconst isFinalist = this.currentRound instanceof MastermindFinals && player.id in this.currentRound.playerTable;\n\t\t\tconst name = isFinalist ? Utils.html`<strong>${player.name}</strong>` : Utils.escapeHTML(player.name);\n\t\t\treturn `${name} (${this.leaderboard.get(player.id)?.score || \"0\"})`;\n\t\t}).join(', ');\n\t}\n\n\t/**\n\t * Starts a new round for a particular player.\n\t * @param playerID the user ID of the player\n\t * @param category the category to ask questions in (e.g. Pok\u00E9mon)\n\t * @param questions an array of TriviaQuestions to be asked\n\t * @param timeout the period of time to end the round after (in seconds)\n\t */\n\tstartRound(playerID: ID, category: ID, questions: TriviaQuestion[], timeout: number) {\n\t\tif (this.currentRound) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`There is already a round of Mastermind in progress.`);\n\t\t}\n\t\tif (!(playerID in this.playerTable)) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`That user is not signed up for Mastermind!`);\n\t\t}\n\t\tif (this.leaderboard.has(playerID)) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`The user \"${playerID}\" has already played their round of Mastermind.`);\n\t\t}\n\t\tif (this.playerCount <= this.numFinalists) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You cannot start the game of Mastermind until there are more players than finals slots.`);\n\t\t}\n\n\t\tthis.phase = MASTERMIND_ROUNDS_PHASE;\n\n\t\tthis.currentRound = new MastermindRound(this.room, category, questions, playerID);\n\t\tsetTimeout(() => {\n\t\t\tif (!this.currentRound) return;\n\t\t\tconst points = this.currentRound.playerTable[playerID]?.points;\n\t\t\tconst player = this.playerTable[playerID].name;\n\t\t\tbroadcast(\n\t\t\t\tthis.room,\n\t\t\t\tthis.room.tr`The round of Mastermind has ended!`,\n\t\t\t\tpoints ? this.room.tr`${player} earned ${points} points!` : undefined\n\t\t\t);\n\n\t\t\tthis.leaderboard.set(playerID, { score: points || 0 });\n\t\t\tthis.currentRound.destroy();\n\t\t\tthis.currentRound = null;\n\t\t}, timeout * 1000);\n\t}\n\n\t/**\n\t * Starts the Mastermind finals.\n\t * According the specification given by Trivia auth,\n\t * Mastermind finals are always in the 'all' category.\n\t * @param timeout timeout in seconds\n\t */\n\tasync startFinals(timeout: number) {\n\t\tif (this.currentRound) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`There is already a round of Mastermind in progress.`);\n\t\t}\n\t\tfor (const player in this.playerTable) {\n\t\t\tif (!this.leaderboard.has(toID(player))) {\n\t\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You cannot start finals until the user '${player}' has played a round.`);\n\t\t\t}\n\t\t}\n\n\t\tconst questions = await getQuestions(['all' as ID], 'random');\n\t\tif (!questions.length) throw new Chat.ErrorMessage(this.room.tr`There are no questions in the Trivia database.`);\n\n\t\tthis.currentRound = new MastermindFinals(this.room, 'all' as ID, questions, this.getTopPlayers(this.numFinalists));\n\n\t\tthis.phase = MASTERMIND_FINALS_PHASE;\n\t\tsetTimeout(() => {\n\t\t\tvoid (async () => {\n\t\t\t\tif (this.currentRound) {\n\t\t\t\t\tawait this.currentRound.win();\n\t\t\t\t\tconst [winner, second, third] = this.currentRound.getTopPlayers();\n\t\t\t\t\tthis.currentRound.destroy();\n\t\t\t\t\tthis.currentRound = null;\n\n\t\t\t\t\tlet buf = this.room.tr`No one scored any points, so it's a tie!`;\n\t\t\t\t\tif (winner) {\n\t\t\t\t\t\tconst winnerName = Utils.escapeHTML(winner.name);\n\t\t\t\t\t\tbuf = this.room.tr`${winnerName} won the game of Mastermind with ${winner.player.points} points!`;\n\t\t\t\t\t}\n\n\t\t\t\t\tlet smallBuf;\n\t\t\t\t\tif (second && third) {\n\t\t\t\t\t\tconst secondPlace = Utils.escapeHTML(second.name);\n\t\t\t\t\t\tconst thirdPlace = Utils.escapeHTML(third.name);\n\t\t\t\t\t\tsmallBuf = `<br />${this.room.tr`${secondPlace} and ${thirdPlace} were runners-up with ${second.player.points} and ${third.player.points} points, respectively.`}`;\n\t\t\t\t\t} else if (second) {\n\t\t\t\t\t\tconst secondPlace = Utils.escapeHTML(second.name);\n\t\t\t\t\t\tsmallBuf = `<br />${this.room.tr`${secondPlace} was a runner up with ${second.player.points} points.`}`;\n\t\t\t\t\t}\n\n\t\t\t\t\tbroadcast(this.room, buf, smallBuf);\n\t\t\t\t}\n\t\t\t\tthis.destroy();\n\t\t\t})();\n\t\t}, timeout * 1000);\n\t}\n\n\t/**\n\t * NOT guaranteed to return an array of length n.\n\t *\n\t * See the Trivia auth discord: https://discord.com/channels/280211330307194880/444675649731428352/788204647402831913\n\t */\n\tgetTopPlayers(n: number) {\n\t\tif (n < 0) return [];\n\n\t\tconst sortedPlayerIDs = Utils.sortBy(\n\t\t\t[...this.leaderboard].filter(([, info]) => !info.hasLeft),\n\t\t\t([, info]) => -info.score\n\t\t).map(([userid]) => userid);\n\n\t\tif (sortedPlayerIDs.length <= n) return sortedPlayerIDs;\n\n\t\t/** The number of points required to be in the top n */\n\t\tconst cutoff = this.leaderboard.get(sortedPlayerIDs[n - 1])!;\n\t\twhile (n < sortedPlayerIDs.length && this.leaderboard.get(sortedPlayerIDs[n])! === cutoff) {\n\t\t\tn++;\n\t\t}\n\t\treturn sortedPlayerIDs.slice(0, n);\n\t}\n\n\tend(user: User) {\n\t\tbroadcast(this.room, this.room.tr`The game of Mastermind was forcibly ended by ${user.name}.`);\n\t\tif (this.currentRound) this.currentRound.destroy();\n\t\tthis.destroy();\n\t}\n\n\tleave(user: User) {\n\t\tif (!this.playerTable[user.id]) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`You are not a player in the current game.`);\n\t\t}\n\t\tconst lbEntry = this.leaderboard.get(user.id);\n\t\tif (lbEntry) {\n\t\t\tthis.leaderboard.set(user.id, { ...lbEntry, hasLeft: true });\n\t\t}\n\t\tthis.removePlayer(this.playerTable[user.id]);\n\t}\n\n\tkick(toKick: User, kicker: User) {\n\t\tif (!this.playerTable[toKick.id]) {\n\t\t\tthrow new Chat.ErrorMessage(this.room.tr`User ${toKick.name} is not a player in the game.`);\n\t\t}\n\n\t\tif (this.numFinalists > (this.players.length - 1)) {\n\t\t\tthrow new Chat.ErrorMessage(\n\t\t\t\tthis.room.tr`Kicking ${toKick.name} would leave this game of Mastermind without enough players to reach ${this.numFinalists} finalists.`\n\t\t\t);\n\t\t}\n\n\t\tthis.leaderboard.delete(toKick.id);\n\n\t\tif (this.currentRound?.playerTable[toKick.id]) {\n\t\t\tif (this.currentRound instanceof MastermindFinals) {\n\t\t\t\tthis.currentRound.kick(toKick);\n\t\t\t} else /* it's a regular round */ {\n\t\t\t\tthis.currentRound.end(kicker);\n\t\t\t}\n\t\t}\n\n\t\tthis.removePlayer(this.playerTable[toKick.id]);\n\t}\n}\n\nexport class MastermindRound extends FirstModeTrivia {\n\tconstructor(room: Room, category: ID, questions: TriviaQuestion[], playerID?: ID) {\n\t\tsuper(room, 'first', [category], false, 'infinite', questions, 'Automatically Created', false, true);\n\n\t\tthis.playerCap = 1;\n\t\tif (playerID) {\n\t\t\tconst player = Users.get(playerID);\n\t\t\tconst targetUsername = playerID;\n\t\t\tif (!player) throw new Chat.ErrorMessage(this.room.tr`User \"${targetUsername}\" not found.`);\n\t\t\tthis.addPlayer(player);\n\t\t}\n\t\tthis.game.mode = 'Mastermind';\n\t\tthis.start();\n\t}\n\n\tinit() {\n\t}\n\tstart() {\n\t\tconst player = Object.values(this.playerTable)[0];\n\t\tconst name = Utils.escapeHTML(player.name);\n\t\tbroadcast(this.room, this.room.tr`A Mastermind round in the ${this.game.category} category for ${name} is starting!`);\n\t\tplayer.sendRoom(\n\t\t\t`|tempnotify|mastermind|Your Mastermind round is starting|Your round of Mastermind is starting in the Trivia room.`\n\t\t);\n\n\t\tthis.phase = INTERMISSION_PHASE;\n\t\tthis.setPhaseTimeout(() => void this.askQuestion(), MASTERMIND_INTERMISSION_INTERVAL);\n\t}\n\n\twin(): Promise<void> {\n\t\tif (this.phaseTimeout) clearTimeout(this.phaseTimeout);\n\t\tthis.phaseTimeout = null;\n\t\treturn Promise.resolve();\n\t}\n\n\taddTriviaPlayer(user: User): string | undefined {\n\t\tthrow new Chat.ErrorMessage(`This is a round of Mastermind; to join the overall game of Mastermind, use /mm join`);\n\t}\n\n\tsetTallyTimeout() {\n\t\t// Players must use /mastermind pass to pass on a question\n\t}\n\n\tpass() {\n\t\tthis.tallyAnswers();\n\t}\n\n\tsetAskTimeout() {\n\t\tthis.setPhaseTimeout(() => void this.askQuestion(), MASTERMIND_INTERMISSION_INTERVAL);\n\t}\n\n\tdestroy() {\n\t\tsuper.destroy();\n\t}\n}\n\nexport class MastermindFinals extends MastermindRound {\n\tconstructor(room: Room, category: ID, questions: TriviaQuestion[], players: ID[]) {\n\t\tsuper(room, category, questions);\n\t\tthis.playerCap = players.length;\n\t\tfor (const id of players) {\n\t\t\tconst player = Users.get(id);\n\t\t\tif (!player) continue;\n\t\t\tthis.addPlayer(player);\n\t\t}\n\t}\n\n\toverride start() {\n\t\tbroadcast(this.room, this.room.tr`The Mastermind finals are starting!`);\n\t\tthis.phase = INTERMISSION_PHASE;\n\t\t// Use the regular start timeout since there are many players\n\t\tthis.setPhaseTimeout(() => void this.askQuestion(), MASTERMIND_FINALS_START_TIMEOUT);\n\t}\n\n\tasync win() {\n\t\tawait super.win();\n\t\tconst points = new Map<string, number>();\n\t\tfor (const id in this.playerTable) {\n\t\t\tpoints.set(id, this.playerTable[id].points);\n\t\t}\n\t}\n\n\tsetTallyTimeout = FirstModeTrivia.prototype.setTallyTimeout;\n\n\tpass() {\n\t\tthrow new Chat.ErrorMessage(this.room.tr`You cannot pass in the finals.`);\n\t}\n}\n\nconst triviaCommands: Chat.ChatCommands = {\n\tsortednew: 'new',\n\tnewsorted: 'new',\n\tunrankednew: 'new',\n\tnewunranked: 'new',\n\tasync new(target, room, user, connection, cmd) {\n\t\tconst randomizeQuestionOrder = !cmd.includes('sorted');\n\t\tconst givesPoints = !cmd.includes('unranked');\n\n\t\troom = this.requireRoom('trivia' as RoomID);\n\t\tthis.checkCan('show', null, room);\n\t\tthis.checkChat();\n\t\tif (room.game) {\n\t\t\treturn this.errorReply(this.tr`There is already a game of ${room.game.title} in progress.`);\n\t\t}\n\n\t\tconst targets = (target ? target.split(',') : []);\n\t\tif (targets.length < 3) return this.errorReply(\"Usage: /trivia new [mode], [category], [length]\");\n\n\t\tlet mode: string = toID(targets[0]);\n\t\tif (['triforce', 'tri'].includes(mode)) mode = 'triumvirate';\n\t\tconst isRandomMode = (mode === 'random');\n\t\tif (isRandomMode) {\n\t\t\tconst acceptableModes = Object.keys(MODES).filter(curMode => curMode !== 'first');\n\t\t\tmode = Utils.shuffle(acceptableModes)[0];\n\t\t}\n\t\tif (!MODES[mode]) return this.errorReply(this.tr`\"${mode}\" is an invalid mode.`);\n\n\t\tlet categories: ID[] | 'random' = targets[1]\n\t\t\t.split('+')\n\t\t\t.map(cat => {\n\t\t\t\tconst id = toID(cat);\n\t\t\t\treturn CATEGORY_ALIASES[id] || id;\n\t\t\t});\n\t\tif (categories[0] === 'random') {\n\t\t\tif (categories.length > 1) throw new Chat.ErrorMessage(`You cannot combine random with another category.`);\n\t\t\tcategories = 'random';\n\t\t}\n\n\t\tconst questions = await getQuestions(categories, randomizeQuestionOrder ? 'random' : 'oldestfirst');\n\n\t\tlet length: ID | number = toID(targets[2]);\n\t\tif (!LENGTHS[length]) {\n\t\t\tlength = parseInt(length);\n\t\t\tif (isNaN(length) || length < 1) return this.errorReply(this.tr`\"${length}\" is an invalid game length.`);\n\t\t}\n\n\t\t// Assume that infinite mode will last for at least 75 points\n\t\tconst questionsNecessary = typeof length === 'string' ? (LENGTHS[length].cap || 75) / 5 : length;\n\t\tif (questions.length < questionsNecessary) {\n\t\t\tif (categories === 'random') {\n\t\t\t\treturn this.errorReply(\n\t\t\t\t\tthis.tr`There are not enough questions in the randomly chosen category to finish a trivia game.`\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (categories.length === 1 && categories[0] === 'all') {\n\t\t\t\treturn this.errorReply(\n\t\t\t\t\tthis.tr`There are not enough questions in the trivia database to finish a trivia game.`\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn this.errorReply(\n\t\t\t\tthis.tr`There are not enough questions under the specified categories to finish a trivia game.`\n\t\t\t);\n\t\t}\n\n\t\tlet _Trivia;\n\t\tif (mode === 'first') {\n\t\t\t_Trivia = FirstModeTrivia;\n\t\t} else if (mode === 'number') {\n\t\t\t_Trivia = NumberModeTrivia;\n\t\t} else if (mode === 'triumvirate') {\n\t\t\t_Trivia = TriumvirateModeTrivia;\n\t\t} else {\n\t\t\t_Trivia = TimerModeTrivia;\n\t\t}\n\n\t\tconst isRandomCategory = categories === 'random';\n\t\tcategories = isRandomCategory ? [questions[0].category as ID] : categories as ID[];\n\t\troom.game = new _Trivia(\n\t\t\troom, mode, categories, givesPoints, length, questions,\n\t\t\tuser.name, isRandomMode, false, isRandomCategory\n\t\t);\n\t},\n\tnewhelp: [\n\t\t`/trivia new [mode], [categories], [length] - Begin a new Trivia game.`,\n\t\t`/trivia unrankednew [mode], [category], [length] - Begin a new Trivia game that does not award leaderboard points.`,\n\t\t`/trivia sortednew [mode], [category], [length] \u2014 Begin a new Trivia game in which the question order is not randomized.`,\n\t\t`Requires: + % @ # ~`,\n\t],\n\n\tjoin(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tgetTriviaGame(room).addTriviaPlayer(user);\n\t\tthis.sendReply(this.tr`You are now signed up for this game!`);\n\t},\n\tjoinhelp: [`/trivia join - Join the current game of Trivia or Mastermind.`],\n\n\tkick(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tthis.checkChat();\n\t\tthis.checkCan('mute', null, room);\n\n\t\tconst { targetUser } = this.requireUser(target, { allowOffline: true });\n\t\tgetTriviaOrMastermindGame(room).kick(targetUser, user);\n\t},\n\tkickhelp: [`/trivia kick [username] - Kick players from a trivia game by username. Requires: % @ # ~`],\n\n\tleave(target, room, user) {\n\t\tgetTriviaGame(room).leave(user);\n\t\tthis.sendReply(this.tr`You have left the current game of Trivia.`);\n\t},\n\tleavehelp: [`/trivia leave - Makes the player leave the game.`],\n\n\tstart(target, room) {\n\t\troom = this.requireRoom();\n\t\tthis.checkCan('show', null, room);\n\t\tthis.checkChat();\n\n\t\tgetTriviaGame(room).start();\n\t},\n\tstarthelp: [`/trivia start - Ends the signup phase of a trivia game and begins the game. Requires: + % @ # ~`],\n\n\tanswer(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tthis.checkChat();\n\t\tlet game: Trivia | MastermindRound | MastermindFinals;\n\t\ttry {\n\t\t\tconst mastermindRound = getMastermindGame(room).currentRound;\n\t\t\tif (!mastermindRound) throw new Error;\n\t\t\tgame = mastermindRound;\n\t\t} catch {\n\t\t\tgame = getTriviaGame(room);\n\t\t}\n\n\t\tconst answer = toID(target);\n\t\tif (!answer) return this.errorReply(this.tr`No valid answer was entered.`);\n\n\t\tif (room.game?.gameid === 'trivia' && !Object.keys(game.playerTable).includes(user.id)) {\n\t\t\tgame.addTriviaPlayer(user);\n\t\t}\n\t\tgame.answerQuestion(answer, user);\n\t\tthis.sendReply(this.tr`You have selected \"${answer}\" as your answer.`);\n\t},\n\tanswerhelp: [`/trivia answer OR /ta [answer] - Answer a pending question.`],\n\n\tresume: 'pause',\n\tpause(target, room, user, connection, cmd) {\n\t\troom = this.requireRoom();\n\t\tthis.checkCan('show', null, room);\n\t\tthis.checkChat();\n\t\tif (cmd === 'pause') {\n\t\t\tgetTriviaGame(room).pause();\n\t\t} else {\n\t\t\tgetTriviaGame(room).resume();\n\t\t}\n\t},\n\tpausehelp: [`/trivia pause - Pauses a trivia game. Requires: + % @ # ~`],\n\tresumehelp: [`/trivia resume - Resumes a paused trivia game. Requires: + % @ # ~`],\n\n\tend(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tthis.checkCan('show', null, room);\n\t\tthis.checkChat();\n\n\t\tgetTriviaOrMastermindGame(room).end(user);\n\t},\n\tendhelp: [`/trivia end - Forcibly end a trivia game. Requires: + % @ # ~`],\n\n\tgetwinners: 'win',\n\tasync win(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tthis.checkCan('show', null, room);\n\t\tthis.checkChat();\n\n\t\tconst game = getTriviaGame(room);\n\t\tif (game.game.length !== 'infinite' && !user.can('editroom', null, room)) {\n\t\t\treturn this.errorReply(\n\t\t\t\tthis.tr`Only Room Owners and higher can force a Trivia game to end with winners in a non-infinite length.`\n\t\t\t);\n\t\t}\n\t\tawait game.win(this.tr`${user.name} ended the game of Trivia!`);\n\t},\n\twinhelp: [`/trivia win - End a trivia game and tally the points to find winners. Requires: + % @ # ~ in Infinite length, else # ~`],\n\n\t'': 'status',\n\tplayers: 'status',\n\tstatus(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tif (!this.runBroadcast()) return false;\n\t\tconst game = getTriviaGame(room);\n\n\t\tconst targetUser = this.getUserOrSelf(target);\n\t\tif (!targetUser) return this.errorReply(this.tr`User ${target} does not exist.`);\n\t\tlet buffer = `${game.isPaused ? this.tr`There is a paused trivia game` : this.tr`There is a trivia game in progress`}, ` +\n\t\t\tthis.tr`and it is in its ${game.phase} phase.` + `<br />` +\n\t\t\tthis.tr`Mode: ${game.game.mode} | Category: ${game.game.category} | Cap: ${game.getDisplayableCap()}`;\n\n\t\tconst player = game.playerTable[targetUser.id];\n\t\tif (player) {\n\t\t\tif (!this.broadcasting) {\n\t\t\t\tbuffer += `<br />${this.tr`Current score: ${player.points} | Correct Answers: ${player.correctAnswers}`}`;\n\t\t\t}\n\t\t} else if (targetUser.id !== user.id) {\n\t\t\treturn this.errorReply(this.tr`User ${targetUser.name} is not a player in the current trivia game.`);\n\t\t}\n\t\tbuffer += `<br />${this.tr`Players: ${game.formatPlayerList({ max: null, requirePoints: false })}`}`;\n\n\t\tthis.sendReplyBox(buffer);\n\t},\n\tstatushelp: [`/trivia status [player] - lists the player's standings (your own if no player is specified) and the list of players in the current trivia game.`],\n\n\tsubmit: 'add',\n\tasync add(target, room, user, connection, cmd) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\t\tif (cmd === 'add') this.checkCan('mute', null, room);\n\t\tif (cmd === 'submit') this.checkCan('show', null, room);\n\t\tif (!target) return false;\n\t\tthis.checkChat();\n\n\t\tconst questions: TriviaQuestion[] = [];\n\t\tconst params = target.split('\\n').map(str => str.split('|'));\n\t\tfor (const param of params) {\n\t\t\tif (param.length !== 3) {\n\t\t\t\tthis.errorReply(this.tr`Invalid arguments specified in \"${param}\". View /trivia help for more information.`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst categoryID = toID(param[0]);\n\t\t\tconst category = CATEGORY_ALIASES[categoryID] || categoryID;\n\t\t\tif (!ALL_CATEGORIES[category]) {\n\t\t\t\tthis.errorReply(this.tr`'${param[0].trim()}' is not a valid category. View /trivia help for more information.`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (cmd === 'submit' && !MAIN_CATEGORIES[category]) {\n\t\t\t\tthis.errorReply(this.tr`You cannot submit questions in the '${ALL_CATEGORIES[category]}' category`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst question = Utils.escapeHTML(param[1].trim());\n\t\t\tif (!question) {\n\t\t\t\tthis.errorReply(this.tr`'${param[1].trim()}' is not a valid question.`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (question.length > MAX_QUESTION_LENGTH) {\n\t\t\t\tthis.errorReply(\n\t\t\t\t\tthis.tr`Question \"${param[1].trim()}\" is too long! It must remain under ${MAX_QUESTION_LENGTH} characters.`\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tawait database.ensureQuestionDoesNotExist(question);\n\t\t\tconst cache = new Set();\n\t\t\tconst answers = param[2].split(',')\n\t\t\t\t.map(toID)\n\t\t\t\t.filter(answer => !cache.has(answer) && !!cache.add(answer));\n\t\t\tif (!answers.length) {\n\t\t\t\tthis.errorReply(this.tr`No valid answers were specified for question '${param[1].trim()}'.`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (answers.some(answer => answer.length > MAX_ANSWER_LENGTH)) {\n\t\t\t\tthis.errorReply(\n\t\t\t\t\tthis.tr`Some of the answers entered for question '${param[1].trim()}' were too long!\\n` +\n\t\t\t\t\t`They must remain under ${MAX_ANSWER_LENGTH} characters.`\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tquestions.push({\n\t\t\t\tcategory,\n\t\t\t\tquestion,\n\t\t\t\tanswers,\n\t\t\t\tuser: user.id,\n\t\t\t\taddedAt: Date.now(),\n\t\t\t});\n\t\t}\n\n\t\tlet formattedQuestions = '';\n\t\tfor (const [index, question] of questions.entries()) {\n\t\t\tformattedQuestions += `'${question.question}' in ${question.category}`;\n\t\t\tif (index !== questions.length - 1) formattedQuestions += ', ';\n\t\t}\n\n\t\tif (cmd === 'add') {\n\t\t\tawait database.addQuestions(questions);\n\t\t\tthis.modlog('TRIVIAQUESTION', null, `added ${formattedQuestions}`);\n\t\t\tthis.privateModAction(`Questions ${formattedQuestions} were added to the question database by ${user.name}.`);\n\t\t} else {\n\t\t\tawait database.addQuestionSubmissions(questions);\n\t\t\tif (!user.can('mute', null, room)) this.sendReply(`Questions '${formattedQuestions}' were submitted for review.`);\n\t\t\tthis.modlog('TRIVIAQUESTION', null, `submitted ${formattedQuestions}`);\n\t\t\tthis.privateModAction(`Questions ${formattedQuestions} were submitted to the submission database by ${user.name} for review.`);\n\t\t}\n\t},\n\tsubmithelp: [`/trivia submit [category] | [question] | [answer1], [answer2] ... [answern] - Adds question(s) to the submission database for staff to review. Requires: + % @ # ~`],\n\taddhelp: [`/trivia add [category] | [question] | [answer1], [answer2], ... [answern] - Adds question(s) to the question database. Requires: % @ # ~`],\n\n\tasync review(target, room) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\t\tthis.checkCan('ban', null, room);\n\n\t\tconst submissions = await database.getSubmissions();\n\t\tif (!submissions.length) return this.sendReply(this.tr`No questions await review.`);\n\n\t\tlet innerBuffer = '';\n\t\tfor (const [index, question] of submissions.entries()) {\n\t\t\tinnerBuffer += `<tr><td><strong>${index + 1}</strong></td><td>${question.category}</td><td>${question.question}</td><td>${question.answers.join(\", \")}</td><td>${question.user}</td></tr>`;\n\t\t}\n\n\t\tconst buffer = `|raw|<div class=\"ladder\"><table>` +\n\t\t\t`<tr><td colspan=\"6\"><strong>${Chat.count(submissions.length, \"</strong> questions\")} awaiting review:</td></tr>` +\n\t\t\t`<tr><th>#</th><th>${this.tr`Category`}</th><th>${this.tr`Question`}</th><th>${this.tr`Answer(s)`}</th><th>${this.tr`Submitted By`}</th></tr>` +\n\t\t\tinnerBuffer +\n\t\t\t`</table></div>`;\n\n\t\tthis.sendReply(buffer);\n\t},\n\treviewhelp: [`/trivia review - View the list of submitted questions. Requires: @ # ~`],\n\n\treject: 'accept',\n\tasync accept(target, room, user, connection, cmd) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\t\tthis.checkCan('ban', null, room);\n\t\tthis.checkChat();\n\n\t\ttarget = target.trim();\n\t\tif (!target) return false;\n\n\t\tconst isAccepting = cmd === 'accept';\n\t\tconst submissions = await database.getSubmissions();\n\n\t\tif (toID(target) === 'all') {\n\t\t\tif (isAccepting) await database.addQuestions(submissions);\n\t\t\tawait database.clearSubmissions();\n\t\t\tconst questionText = submissions.map(q => `\"${q.question}\"`).join(', ');\n\t\t\tconst message = `${(isAccepting ? \"added\" : \"removed\")} all questions (${questionText}) from the submission database.`;\n\t\t\tthis.modlog(`TRIVIAQUESTION`, null, message);\n\t\t\treturn this.privateModAction(`${user.name} ${message}`);\n\t\t}\n\n\t\tif (/\\d+(?:-\\d+)?(?:, ?\\d+(?:-\\d+)?)*$/.test(target)) {\n\t\t\tconst indices = target.split(',');\n\t\t\tconst questions: string[] = [];\n\n\t\t\t// Parse number ranges and add them to the list of indices,\n\t\t\t// then remove them in addition to entries that aren't valid index numbers\n\t\t\tfor (let i = indices.length; i--;) {\n\t\t\t\tif (!indices[i].includes('-')) {\n\t\t\t\t\tconst index = Number(indices[i]);\n\t\t\t\t\tif (Number.isInteger(index) && index > 0 && index <= submissions.length) {\n\t\t\t\t\t\tquestions.push(submissions[index - 1].question);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tindices.splice(i, 1);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst range = indices[i].split('-');\n\t\t\t\tconst left = Number(range[0]);\n\t\t\t\tlet right = Number(range[1]);\n\t\t\t\tif (!Number.isInteger(left) || !Number.isInteger(right) ||\n\t\t\t\t\tleft < 1 || right > submissions.length || left === right) {\n\t\t\t\t\tindices.splice(i, 1);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tdo {\n\t\t\t\t\tquestions.push(submissions[right - 1].question);\n\t\t\t\t} while (--right >= left);\n\n\t\t\t\tindices.splice(i, 1);\n\t\t\t}\n\n\t\t\tconst indicesLen = indices.length;\n\t\t\tif (!indicesLen) {\n\t\t\t\treturn this.errorReply(\n\t\t\t\t\tthis.tr`'${target}' is not a valid set of submission index numbers.\\n` +\n\t\t\t\t\tthis.tr`View /trivia review and /trivia help for more information.`\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (isAccepting) {\n\t\t\t\tawait database.acceptSubmissions(questions);\n\t\t\t} else {\n\t\t\t\tawait database.deleteSubmissions(questions);\n\t\t\t}\n\n\t\t\tconst questionText = questions.map(q => `\"${q}\"`).join(', ');\n\t\t\tconst message = `${(isAccepting ? \"added \" : \"removed \")}submission number${(indicesLen > 1 ? \"s \" : \" \")}${target} (${questionText})`;\n\t\t\tthis.modlog('TRIVIAQUESTION', null, message);\n\t\t\treturn this.privateModAction(`${user.name} ${message} from the submission database.`);\n\t\t}\n\n\t\tthis.errorReply(this.tr`'${target}' is an invalid argument. View /trivia help questions for more information.`);\n\t},\n\taccepthelp: [`/trivia accept [index1], [index2], ... [indexn] OR all - Add questions from the submission database to the question database using their index numbers or ranges of them. Requires: @ # ~`],\n\trejecthelp: [`/trivia reject [index1], [index2], ... [indexn] OR all - Remove questions from the submission database using their index numbers or ranges of them. Requires: @ # ~`],\n\n\tasync delete(target, room, user) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\t\tthis.checkCan('mute', null, room);\n\t\tthis.checkChat();\n\n\t\ttarget = target.trim();\n\t\tif (!target) return this.parse(`/help trivia delete`);\n\n\t\tconst question = Utils.escapeHTML(target).trim();\n\t\tif (!question) {\n\t\t\treturn this.errorReply(this.tr`'${target}' is not a valid argument. View /trivia help questions for more information.`);\n\t\t}\n\n\t\tconst { category } = await database.ensureQuestionExists(question);\n\t\tawait database.deleteQuestion(question);\n\n\t\tthis.modlog('TRIVIAQUESTION', null, `removed '${target}' from ${category}`);\n\t\treturn this.privateModAction(room.tr`${user.name} removed question '${target}' (category: ${category}) from the question database.`);\n\t},\n\tdeletehelp: [`/trivia delete [question] - Delete a question from the trivia database. Requires: % @ # ~`],\n\n\tasync move(target, room, user) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\t\tthis.checkCan('mute', null, room);\n\t\tthis.checkChat();\n\n\t\ttarget = target.trim();\n\t\tif (!target) return false;\n\n\t\tconst params = target.split('\\n').map(str => str.split('|'));\n\t\tfor (const param of params) {\n\t\t\tif (param.length !== 2) {\n\t\t\t\tthis.errorReply(this.tr`Invalid arguments specified in \"${param}\". View /trivia help for more information.`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst categoryID = toID(param[0]);\n\t\t\tconst category = CATEGORY_ALIASES[categoryID] || categoryID;\n\t\t\tif (!ALL_CATEGORIES[category]) {\n\t\t\t\tthis.errorReply(this.tr`'${param[0].trim()}' is not a valid category. View /trivia help for more information.`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst question = Utils.escapeHTML(param[1].trim());\n\t\t\tif (!question) {\n\t\t\t\tthis.errorReply(this.tr`'${param[1].trim()}' is not a valid question.`);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst { category: oldCat } = await database.ensureQuestionExists(question);\n\t\t\tawait database.moveQuestionToCategory(question, category);\n\t\t\tthis.modlog('TRIVIAQUESTION', null, `changed category for '${param[1].trim()}' from '${oldCat}' to '${param[0]}'`);\n\t\t\treturn this.privateModAction(\n\t\t\t\tthis.tr`${user.name} changed question category from '${oldCat}' to '${param[0]}' for '${param[1].trim()}' ` +\n\t\t\t\tthis.tr`from the question database.`\n\t\t\t);\n\t\t}\n\t},\n\tmovehelp: [\n\t\t`/trivia move [category] | [question] - Change the category of a question in the trivia database. Requires: % @ # ~`,\n\t],\n\n\tasync migrate(target, room, user) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\t\tthis.checkCan('editroom', null, room);\n\n\t\tconst [sourceCategory, destinationCategory] = target.split(',').map(toID);\n\n\t\tfor (const category of [sourceCategory, destinationCategory]) {\n\t\t\tif (category in MAIN_CATEGORIES) {\n\t\t\t\tthrow new Chat.ErrorMessage(`Main categories cannot be used with /trivia migrate. If you need to migrate to or from a main category, contact a technical Administrator.`);\n\t\t\t}\n\t\t\tif (!(category in ALL_CATEGORIES)) throw new Chat.ErrorMessage(`\"${category}\" is not a valid category`);\n\t\t}\n\n\t\tconst sourceCategoryName = ALL_CATEGORIES[sourceCategory];\n\t\tconst destinationCategoryName = ALL_CATEGORIES[destinationCategory];\n\n\t\tconst command = `/trivia migrate ${sourceCategory}, ${destinationCategory}`;\n\t\tif (user.lastCommand !== command) {\n\t\t\tthis.sendReply(`Are you SURE that you want to PERMANENTLY move all questions in the category ${sourceCategoryName} to ${destinationCategoryName}?`);\n\t\t\tthis.sendReply(`This cannot be undone.`);\n\t\t\tthis.sendReply(`Type the command again to confirm.`);\n\n\t\t\tuser.lastCommand = command;\n\t\t\treturn;\n\t\t}\n\t\tuser.lastCommand = '';\n\n\t\tconst numQs = await database.migrateCategory(sourceCategory, destinationCategory);\n\t\tthis.modlog(`TRIVIAQUESTION MIGRATE`, null, `${sourceCategoryName} to ${destinationCategoryName}`);\n\t\tthis.privateModAction(`${user.name} migrated all ${numQs} questions in the category ${sourceCategoryName} to ${destinationCategoryName}.`);\n\t},\n\tmigratehelp: [\n\t\t`/trivia migrate [source category], [destination category] \u2014 Moves all questions in a category to another category. Requires: # ~`,\n\t],\n\n\tasync edit(target, room, user) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\t\tthis.checkCan('mute', null, room);\n\n\t\tlet isQuestionOnly = false;\n\t\tlet isAnswersOnly = false;\n\t\tconst args = target.split('|').map(arg => arg.trim());\n\n\t\tlet oldQuestionText = args.shift();\n\t\tif (toID(oldQuestionText) === 'question') {\n\t\t\tisQuestionOnly = true;\n\t\t\toldQuestionText = args.shift();\n\t\t} else if (toID(oldQuestionText) === 'answers') {\n\t\t\tisAnswersOnly = true;\n\t\t\toldQuestionText = args.shift();\n\t\t}\n\t\tif (!oldQuestionText) return this.parse(`/help trivia edit`);\n\n\t\tconst { category } = await database.ensureQuestionExists(Utils.escapeHTML(oldQuestionText));\n\n\t\tlet newQuestionText: string | undefined;\n\t\tif (!isAnswersOnly) {\n\t\t\tnewQuestionText = args.shift();\n\t\t\tif (!newQuestionText) {\n\t\t\t\tisAnswersOnly = true; // for modlog formatting\n\t\t\t} else {\n\t\t\t\tif (newQuestionText.length > MAX_QUESTION_LENGTH) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(`The new question text is too long. The limit is ${MAX_QUESTION_LENGTH} characters.`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst answers: ID[] = [];\n\t\tif (!isQuestionOnly) {\n\t\t\tconst answerArgs = args.shift();\n\t\t\tif (!answerArgs) {\n\t\t\t\tif (isAnswersOnly) throw new Chat.ErrorMessage(`You must specify new answers.`);\n\t\t\t\tisQuestionOnly = true; // for modlog formatting\n\t\t\t} else {\n\t\t\t\tfor (const arg of answerArgs?.split(',') || []) {\n\t\t\t\t\tconst answer = toID(arg);\n\t\t\t\t\tif (!answer) {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`Answers cannot be empty; double-check your syntax.`);\n\t\t\t\t\t}\n\t\t\t\t\tif (answer.length > MAX_ANSWER_LENGTH) {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`The answer '${answer}' is too long. The limit is ${MAX_ANSWER_LENGTH} characters.`);\n\t\t\t\t\t}\n\t\t\t\t\tif (answers.includes(answer)) {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`You may not specify duplicate answers.`);\n\t\t\t\t\t}\n\t\t\t\t\tanswers.push(answer);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// We _could_ edit it in place but I think this isn't that much overhead and\n\t\t// it keeps the API simpler (we'd still have to SELECT from the questions table to get the ID,\n\t\t// and passing a SQLite ID around is an implementation detail).\n\t\tif (!isQuestionOnly && !answers.length) {\n\t\t\tthrow new Chat.ErrorMessage(`You must specify at least one answer.`);\n\t\t}\n\t\tawait database.editQuestion(\n\t\t\tUtils.escapeHTML(oldQuestionText),\n\t\t\t// Cast is safe because if `newQuestionText` is undefined, `isAnswersOnly` is true.\n\t\t\tisAnswersOnly ? undefined : Utils.escapeHTML(newQuestionText!),\n\t\t\tisQuestionOnly ? undefined : answers\n\t\t);\n\n\t\tlet actionString = `edited question '${oldQuestionText}' in ${category}`;\n\t\tif (!isAnswersOnly) actionString += ` to '${newQuestionText}'`;\n\t\tif (answers.length) {\n\t\t\tactionString += ` and changed the answers to ${answers.join(', ')}`;\n\t\t}\n\t\tthis.modlog('TRIVIAQUESTION EDIT', null, actionString);\n\t\tthis.privateModAction(`${user.name} ${actionString}.`);\n\t},\n\tedithelp: [\n\t\t`/trivia edit <old question text> | <new question text> | <answer1, answer2, ...> - Edit a question in the trivia database, replacing answers if specified. Requires: % @ # ~`,\n\t\t`/trivia edit question | <old question text> | <new question text> - Alternative syntax for /trivia edit.`,\n\t\t`/trivia edit answers | <old question text> | <new answers> - Alternative syntax for /trivia edit.`,\n\t],\n\n\tasync qs(target, room, user) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\n\t\tlet buffer = \"|raw|<div class=\\\"ladder\\\" style=\\\"overflow-y: scroll; max-height: 300px;\\\"><table>\";\n\t\tif (!target) {\n\t\t\tif (!this.runBroadcast()) return false;\n\n\t\t\tconst counts = await database.getQuestionCounts();\n\t\t\tif (!counts.total) return this.sendReplyBox(this.tr`No questions have been submitted yet.`);\n\n\t\t\tbuffer += `<tr><th>Category</th><th>${this.tr`Question Count`}</th></tr>`;\n\t\t\t// we want all the named categories and also all the categories in SQL, without duplication\n\t\t\tfor (const category of new Set([...Object.keys(ALL_CATEGORIES), ...Object.keys(counts)])) {\n\t\t\t\tconst name = ALL_CATEGORIES[category] || category;\n\t\t\t\tif (category === 'random' || category === 'total') continue;\n\t\t\t\tconst tally = counts[category] || 0;\n\t\t\t\tbuffer += `<tr><td>${name}</td><td>${tally} (${((tally * 100) / counts.total).toFixed(2)}%)</td></tr>`;\n\t\t\t}\n\t\t\tbuffer += `<tr><td><strong>${this.tr`Total`}</strong></td><td><strong>${counts.total}</strong></td></table></div>`;\n\n\t\t\treturn this.sendReply(buffer);\n\t\t}\n\n\t\tthis.checkCan('mute', null, room);\n\n\t\ttarget = toID(target);\n\t\tconst category = CATEGORY_ALIASES[target] || target;\n\t\tif (category === 'random') return false;\n\t\tif (!ALL_CATEGORIES[category]) {\n\t\t\treturn this.errorReply(this.tr`'${target}' is not a valid category. View /help trivia for more information.`);\n\t\t}\n\n\t\tconst list = await database.getQuestions([category], Number.MAX_SAFE_INTEGER, { order: 'oldestfirst' });\n\t\tif (!list.length) {\n\t\t\tbuffer += `<tr><td>${this.tr`There are no questions in the ${ALL_CATEGORIES[category]} category.`}</td></table></div>`;\n\t\t\treturn this.sendReply(buffer);\n\t\t}\n\n\t\tif (user.can('ban', null, room)) {\n\t\t\tconst cat = ALL_CATEGORIES[category];\n\t\t\tbuffer += `<tr><td colspan=\"3\">${this.tr`There are <strong>${list.length}</strong> questions in the ${cat} category.`}</td></tr>` +\n\t\t\t\t`<tr><th>#</th><th>${this.tr`Question`}</th><th>${this.tr`Answer(s)`}</th></tr>`;\n\t\t\tfor (const [i, entry] of list.entries()) {\n\t\t\t\tbuffer += `<tr><td><strong>${(i + 1)}</strong></td><td>${entry.question}</td><td>${entry.answers.join(\", \")}</td><tr>`;\n\t\t\t}\n\t\t} else {\n\t\t\tconst cat = target;\n\t\t\tbuffer += `<td colspan=\"2\">${this.tr`There are <strong>${list.length}</strong> questions in the ${cat} category.`}</td></tr>` +\n\t\t\t\t`<tr><th>#</th><th>${this.tr`Question`}</th></tr>`;\n\t\t\tfor (const [i, entry] of list.entries()) {\n\t\t\t\tbuffer += `<tr><td><strong>${(i + 1)}</strong></td><td>${entry.question}</td></tr>`;\n\t\t\t}\n\t\t}\n\t\tbuffer += \"</table></div>\";\n\n\t\tthis.sendReply(buffer);\n\t},\n\tqshelp: [\n\t\t\"/trivia qs - View the distribution of questions in the question database.\",\n\t\t\"/trivia qs [category] - View the questions in the specified category. Requires: % @ # ~\",\n\t],\n\n\tcssearch: 'search',\n\tcasesensitivesearch: 'search',\n\tdoublespacesearch: 'search',\n\tasync search(target, room, user, connection, cmd) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\t\tthis.checkCan('show', null, room);\n\n\t\tlet type, query;\n\t\tif (cmd === 'doublespacesearch') {\n\t\t\tquery = [' '];\n\t\t\ttype = target;\n\t\t} else {\n\t\t\t[type, ...query] = target.split(',');\n\t\t\tif (!target.includes(',')) return this.errorReply(this.tr`No valid search arguments entered.`);\n\t\t}\n\n\t\ttype = toID(type);\n\t\tlet options;\n\n\t\tif (/^q(?:uestion)?s?$/.test(type)) {\n\t\t\toptions = { searchSubmissions: false, caseSensitive: cmd !== 'search' };\n\t\t} else if (/^sub(?:mission)?s?$/.test(type)) {\n\t\t\toptions = { searchSubmissions: true, caseSensitive: cmd !== 'search' };\n\t\t} else {\n\t\t\treturn this.sendReplyBox(\n\t\t\t\tthis.tr`No valid search category was entered. Valid categories: submissions, subs, questions, qs`\n\t\t\t);\n\t\t}\n\n\t\tlet queryString = query.join(',');\n\t\tif (cmd !== 'doublespacesearch') queryString = queryString.trim();\n\t\tif (!queryString) return this.errorReply(this.tr`No valid search query was entered.`);\n\n\t\tconst results = await database.searchQuestions(queryString, options);\n\t\tif (!results.length) return this.sendReply(this.tr`No results found under the ${type} list.`);\n\n\t\tlet buffer = `|raw|<div class=\"ladder\"><table><tr><th>#</th><th>${this.tr`Category`}</th><th>${this.tr`Question`}</th></tr>` +\n\t\t\t`<tr><td colspan=\"3\">${this.tr`There are <strong>${results.length}</strong> matches for your query:`}</td></tr>`;\n\t\tbuffer += results.map(\n\t\t\t(q, i) => this.tr`<tr><td><strong>${i + 1}</strong></td><td>${q.category}</td><td>${q.question}</td></tr>`\n\t\t).join('');\n\t\tbuffer += \"</table></div>\";\n\n\t\tthis.sendReply(buffer);\n\t},\n\tsearchhelp: [\n\t\t`/trivia search [type], [query] - Searches for questions based on their type and their query. This command is case-insensitive. Valid types: submissions, subs, questions, qs. Requires: + % @ * ~`,\n\t\t`/trivia casesensitivesearch [type], [query] - Like /trivia search, but is case sensitive (capital letters matter). Requires: + % @ * ~`,\n\t\t`/trivia doublespacesearch [type] \u2014 Searches for questions with back-to-back space characters. Requires: + % @ * ~`,\n\t],\n\n\tasync moveusedevent(target, room, user) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\t\tconst fromCatName = ALL_CATEGORIES[MOVE_QUESTIONS_AFTER_USE_FROM_CATEGORY];\n\t\tconst toCatName = ALL_CATEGORIES[MOVE_QUESTIONS_AFTER_USE_TO_CATEGORY];\n\t\tconst currentSetting = await database.shouldMoveEventQuestions();\n\n\t\tif (target) {\n\t\t\tthis.checkCan('editroom', null, room);\n\n\t\t\tconst isEnabling = this.meansYes(target);\n\t\t\tif (isEnabling) {\n\t\t\t\tif (currentSetting) throw new Chat.ErrorMessage(`Moving used event questions is already enabled.`);\n\t\t\t\tawait database.setShouldMoveEventQuestions(true);\n\t\t\t} else if (this.meansNo(target)) {\n\t\t\t\tif (!currentSetting) throw new Chat.ErrorMessage(`Moving used event questions is already disabled.`);\n\t\t\t\tawait database.setShouldMoveEventQuestions(false);\n\t\t\t} else {\n\t\t\t\treturn this.parse(`/help trivia moveusedevent`);\n\t\t\t}\n\n\t\t\tthis.modlog(`TRIVIA MOVE USED EVENT QUESTIONS`, null, isEnabling ? 'ON' : 'OFF');\n\t\t\tthis.sendReply(\n\t\t\t\t`Trivia questions in the ${fromCatName} category will ${isEnabling ? 'now' : 'no longer'} be moved to the ${toCatName} category after they are used.`\n\t\t\t);\n\t\t} else {\n\t\t\tthis.sendReply(\n\t\t\t\tcurrentSetting ?\n\t\t\t\t\t`Trivia questions in the ${fromCatName} category will be moved to the ${toCatName} category after use.` :\n\t\t\t\t\t`Moving event questions after usage is currently disabled.`\n\t\t\t);\n\t\t}\n\t},\n\tmoveusedeventhelp: [\n\t\t`/trivia moveusedevent - Tells you whether or not moving used event questions to a different category is enabled.`,\n\t\t`/trivia moveusedevent [on or off] - Toggles moving used event questions to a different category. Requires: # ~`,\n\t],\n\n\tasync rank(target, room, user) {\n\t\troom = this.requireRoom('trivia' as RoomID);\n\t\tthis.runBroadcast();\n\n\t\tlet name;\n\t\tlet userid;\n\t\tif (!target) {\n\t\t\tname = Utils.escapeHTML(user.name);\n\t\t\tuserid = user.id;\n\t\t} else {\n\t\t\tname = Utils.escapeHTML(target);\n\t\t\tuserid = toID(target);\n\t\t}\n\n\t\tconst allTimeScore = await database.getLeaderboardEntry(userid, 'alltime');\n\t\tif (!allTimeScore) return this.sendReplyBox(this.tr`User '${name}' has not played any Trivia games yet.`);\n\t\tconst score = (\n\t\t\tawait database.getLeaderboardEntry(userid, 'nonAlltime') ||\n\t\t\t{ score: 0, totalPoints: 0, totalCorrectAnswers: 0 }\n\t\t);\n\t\tconst cycleScore = await database.getLeaderboardEntry(userid, 'cycle');\n\n\t\tconst ranks = (await cachedLadder.get('nonAlltime'))?.ranks[userid];\n\t\tconst allTimeRanks = (await cachedLadder.get('alltime'))?.ranks[userid];\n\t\tconst cycleRanks = (await cachedLadder.get('cycle'))?.ranks[userid];\n\n\t\tfunction display(\n\t\t\tscores: TriviaLeaderboardScore | null,\n\t\t\tranking: TriviaLeaderboardScore | undefined,\n\t\t\tkey: keyof TriviaLeaderboardScore,\n\t\t) {\n\t\t\tif (!scores?.[key]) return `<td>N/A</td>`;\n\t\t\treturn Utils.html`<td>${scores[key]}${ranking?.[key] ? ` (rank ${ranking[key]})` : ``}</td>`;\n\t\t}\n\n\t\tthis.sendReplyBox(\n\t\t\t`<div class=\"ladder\"><table>` +\n\t\t\t`<tr><th>${name}</th><th>Cycle Ladder</th><th>All-time Score Ladder</th><th>All-time Wins Ladder</th></tr>` +\n\t\t\t`<tr><td>Leaderboard score</td>` +\n\t\t\tdisplay(cycleScore, cycleRanks, 'score') +\n\t\t\tdisplay(score, ranks, 'score') +\n\t\t\tdisplay(allTimeScore, allTimeRanks, 'score') +\n\t\t\t`</tr>` +\n\t\t\t`<tr><td>Total game points</td>` +\n\t\t\tdisplay(cycleScore, cycleRanks, 'totalPoints') +\n\t\t\tdisplay(score, ranks, 'totalPoints') +\n\t\t\tdisplay(allTimeScore, allTimeRanks, 'totalPoints') +\n\t\t\t`</tr>` +\n\t\t\t`<tr><td>Total correct answers</td>` +\n\t\t\tdisplay(cycleScore, cycleRanks, 'totalCorrectAnswers') +\n\t\t\tdisplay(score, ranks, 'totalCorrectAnswers') +\n\t\t\tdisplay(allTimeScore, allTimeRanks, 'totalCorrectAnswers') +\n\t\t\t`</tr>` +\n\t\t\t`</table></div>`\n\t\t);\n\t},\n\trankhelp: [`/trivia rank [username] - View the rank of the specified user. If no name is given, view your own.`],\n\n\talltimescoreladder: 'ladder',\n\tscoreladder: 'ladder',\n\twinsladder: 'ladder',\n\talltimewinsladder: 'ladder',\n\tasync ladder(target, room, user, connection, cmd) {\n\t\troom = this.requireRoom('trivia' as RoomID);\n\t\tif (!this.runBroadcast()) return false;\n\n\t\tlet leaderboard: Leaderboard = 'cycle';\n\t\t// TODO: rename leaderboards in the code once the naming scheme has been stable for a few months\n\t\tif (cmd.includes('wins')) leaderboard = 'alltime';\n\t\tif (cmd.includes('score')) leaderboard = 'nonAlltime';\n\n\t\tconst ladder = (await cachedLadder.get(leaderboard))?.ladder;\n\t\tif (!ladder?.length) return this.errorReply(this.tr`No Trivia games have been played yet.`);\n\n\t\tlet buffer = \"|raw|<div class=\\\"ladder\\\" style=\\\"overflow-y: scroll; max-height: 300px;\\\"><table>\" +\n\t\t\t`<tr><th>${this.tr`Rank`}</th><th>${this.tr`User`}</th><th>${this.tr`Leaderboard score`}</th><th>${this.tr`Total game points`}</th><th>${this.tr`Total correct answers`}</th></tr>`;\n\t\tlet num = parseInt(target);\n\t\tif (!num || num < 0) num = 100;\n\t\tif (num > ladder.length) num = ladder.length;\n\t\tfor (let i = Math.max(0, num - 100); i < num; i++) {\n\t\t\tconst leaders = ladder[i];\n\t\t\tfor (const leader of leaders) {\n\t\t\t\tconst rank = await database.getLeaderboardEntry(leader, leaderboard);\n\t\t\t\tif (!rank) continue; // should never happen\n\t\t\t\tconst leaderObj = Users.getExact(leader as unknown as string);\n\t\t\t\tconst leaderid = leaderObj ? Utils.escapeHTML(leaderObj.name) : leader as unknown as string;\n\t\t\t\tbuffer += `<tr><td><strong>${(i + 1)}</strong></td><td>${leaderid}</td><td>${rank.score}</td><td>${rank.totalPoints}</td><td>${rank.totalCorrectAnswers}</td></tr>`;\n\t\t\t}\n\t\t}\n\t\tbuffer += \"</table></div>\";\n\n\t\treturn this.sendReply(buffer);\n\t},\n\tladderhelp: [\n\t\t`/trivia ladder [n] - Displays the top [n] users on the cycle-specific Trivia leaderboard. If [n] isn't specified, shows 100 users.`,\n\t\t`/trivia alltimewinsladder [n] - Like /trivia ladder, but displays the all-time Trivia leaderboard.`,\n\t\t`/trivia alltimescoreladder [n] - Like /trivia ladder, but displays the Trivia leaderboard which is neither all-time nor cycle-specific.`,\n\t],\n\n\tresetladder: 'resetcycleleaderboard',\n\tresetcycleladder: 'resetcycleleaderboard',\n\tasync resetcycleleaderboard(target, room, user) {\n\t\troom = this.requireRoom('trivia' as RoomID);\n\t\tthis.checkCan('editroom', null, room);\n\n\t\tif (user.lastCommand !== '/trivia resetcycleleaderboard') {\n\t\t\tuser.lastCommand = '/trivia resetcycleleaderboard';\n\t\t\tthis.errorReply(`Are you sure you want to reset the Trivia cycle-specific leaderboard? This action is IRREVERSIBLE.`);\n\t\t\tthis.errorReply(`To confirm, retype the command.`);\n\t\t\treturn;\n\t\t}\n\t\tuser.lastCommand = '';\n\n\t\tawait database.clearCycleLeaderboard();\n\t\tthis.privateModAction(`${user.name} reset the cycle-specific Trivia leaderboard.`);\n\t\tthis.modlog('TRIVIA LEADERBOARDRESET', null, 'cycle-specific leaderboard');\n\t},\n\tresetcycleleaderboardhelp: [`/trivia resetcycleleaderboard - Resets the cycle-specific Trivia leaderboard. Requires: # ~`],\n\n\tclearquestions: 'clearqs',\n\tasync clearqs(target, room, user) {\n\t\troom = this.requireRoom('questionworkshop' as RoomID);\n\t\tthis.checkCan('declare', null, room);\n\t\ttarget = toID(target);\n\t\tconst category = CATEGORY_ALIASES[target] || target;\n\t\tif (ALL_CATEGORIES[category]) {\n\t\t\tif (SPECIAL_CATEGORIES[category]) {\n\t\t\t\tawait database.clearCategory(category);\n\t\t\t\tthis.modlog(`TRIVIA CATEGORY CLEAR`, null, SPECIAL_CATEGORIES[category]);\n\t\t\t\treturn this.privateModAction(room.tr`${user.name} removed all questions of category '${category}'.`);\n\t\t\t} else {\n\t\t\t\treturn this.errorReply(this.tr`You cannot clear the category '${ALL_CATEGORIES[category]}'.`);\n\t\t\t}\n\t\t} else {\n\t\t\treturn this.errorReply(this.tr`'${category}' is an invalid category.`);\n\t\t}\n\t},\n\tclearqshelp: [`/trivia clearqs [category] - Remove all questions of the given category. Requires: # ~`],\n\n\tpastgames: 'history',\n\tasync history(target, room, user) {\n\t\troom = this.requireRoom('trivia' as RoomID);\n\t\tif (!this.runBroadcast()) return false;\n\n\t\tlet lines = 10;\n\t\tif (target) {\n\t\t\tlines = parseInt(target);\n\t\t\tif (lines < 1 || lines > 100 || isNaN(lines)) {\n\t\t\t\tthrow new Chat.ErrorMessage(`You must specify a number of games to view the history of between 1 and 100.`);\n\t\t\t}\n\t\t}\n\t\tconst games = await database.getHistory(lines);\n\t\tconst buf = [];\n\t\tfor (const [i, game] of games.entries()) {\n\t\t\tlet gameInfo = Utils.html`<b>${i + 1}.</b> ${this.tr`${game.mode} mode, ${game.length} length Trivia game in the ${game.category} category`}`;\n\t\t\tif (game.creator) gameInfo += Utils.html` ${this.tr`hosted by ${game.creator}`}`;\n\t\t\tgameInfo += '.';\n\t\t\tbuf.push(gameInfo);\n\t\t}\n\n\t\treturn this.sendReplyBox(buf.join('<br />'));\n\t},\n\thistoryhelp: [`/trivia history [n] - View a list of the n most recently played trivia games. Defaults to 10.`],\n\n\tasync lastofficialscore(target, room, user) {\n\t\troom = this.requireRoom('trivia' as RoomID);\n\t\tthis.runBroadcast();\n\n\t\tconst scores = Object.entries(await database.getScoresForLastGame())\n\t\t\t.map(([userid, score]) => `${userid} (${score})`)\n\t\t\t.join(', ');\n\t\tthis.sendReplyBox(`The scores for the last Trivia game are: ${scores}`);\n\t},\n\tlastofficialscorehelp: [`/trivia lastofficialscore - View the scores from the last Trivia game. Intended for bots.`],\n\n\tremovepoints: 'addpoints',\n\tasync addpoints(target, room, user, connection, cmd) {\n\t\troom = this.requireRoom('trivia' as RoomID);\n\t\tthis.checkCan('editroom', null, room);\n\n\t\tconst [userid, pointString] = this.splitOne(target).map(toID);\n\n\t\tconst points = parseInt(pointString);\n\t\tif (isNaN(points)) return this.errorReply(`You must specify a number of points to add/remove.`);\n\t\tconst isRemoval = cmd === 'removepoints';\n\n\t\tconst change = { score: isRemoval ? -points : points, totalPoints: 0, totalCorrectAnswers: 0 };\n\t\tawait database.updateLeaderboardForUser(userid, {\n\t\t\talltime: change,\n\t\t\tnonAlltime: change,\n\t\t\tcycle: change,\n\t\t});\n\t\tcachedLadder.invalidateCache();\n\n\t\tthis.modlog(`TRIVIAPOINTS ${isRemoval ? 'REMOVE' : 'ADD'}`, userid, `${points} points`);\n\t\tthis.privateModAction(\n\t\t\tisRemoval ?\n\t\t\t\t`${user.name} removed ${points} points from ${userid}'s Trivia leaderboard score.` :\n\t\t\t\t`${user.name} added ${points} points to ${userid}'s Trivia leaderboard score.`\n\t\t);\n\t},\n\taddpointshelp: [\n\t\t`/trivia removepoints [user], [points] - Remove points from a given user's score on the Trivia leaderboard.`,\n\t\t`/trivia addpoints [user], [points] - Add points to a given user's score on the Trivia leaderboard.`,\n\t\t`Requires: # ~`,\n\t],\n\n\tasync removeleaderboardentry(target, room, user) {\n\t\troom = this.requireRoom('trivia' as RoomID);\n\t\tthis.checkCan('editroom', null, room);\n\n\t\tconst userid = toID(target);\n\t\tif (!userid) return this.parse('/help trivia removeleaderboardentry');\n\t\tif (!(await database.getLeaderboardEntry(userid, 'alltime'))) {\n\t\t\treturn this.errorReply(`The user '${userid}' has no Trivia leaderboard entry.`);\n\t\t}\n\n\t\tconst command = `/trivia removeleaderboardentry ${userid}`;\n\t\tif (user.lastCommand !== command) {\n\t\t\tuser.lastCommand = command;\n\t\t\tthis.sendReply(`Are you sure you want to DELETE ALL LEADERBOARD SCORES FOR '${userid}'?`);\n\t\t\tthis.sendReply(`If so, type ${command} to confirm.`);\n\t\t\treturn;\n\t\t}\n\t\tuser.lastCommand = '';\n\n\t\tawait Promise.all(\n\t\t\t(Object.keys(LEADERBOARD_ENUM) as Leaderboard[])\n\t\t\t\t.map(lb => database.deleteLeaderboardEntry(userid, lb))\n\t\t);\n\t\tcachedLadder.invalidateCache();\n\n\t\tthis.modlog(`TRIVIAPOINTS DELETE`, userid);\n\t\tthis.privateModAction(`${user.name} removed ${userid}'s Trivia leaderboard entries.`);\n\t},\n\tremoveleaderboardentryhelp: [\n\t\t`/trivia removeleaderboardentry [user] \u2014 Remove all leaderboard entries for a user. Requires: # ~`,\n\t],\n\n\tmergealt: 'mergescore',\n\tmergescores: 'mergescore',\n\tasync mergescore(target, room, user) {\n\t\tconst altid = toID(target);\n\t\tif (!altid) return this.parse('/help trivia mergescore');\n\n\t\ttry {\n\t\t\tawait mergeAlts(user.id, altid);\n\t\t\treturn this.sendReply(`Your Trivia leaderboard score has been transferred to '${altid}'!`);\n\t\t} catch (err: any) {\n\t\t\tif (!err.message.includes('/trivia mergescore')) throw err;\n\n\t\t\tawait requestAltMerge(altid, user.id);\n\t\t\treturn this.sendReply(\n\t\t\t\t`A Trivia leaderboard score merge with ${altid} is now pending! ` +\n\t\t\t\t`To complete the merge, log in on the account '${altid}' and type /trivia mergescore ${user.id}`\n\t\t\t);\n\t\t}\n\t},\n\tmergescorehelp: [\n\t\t`/trivia mergescore [user] \u2014 Merge another user's Trivia leaderboard score with yours.`,\n\t],\n\n\thelp(target, room, user) {\n\t\treturn this.parse(`${this.cmdToken}help trivia`);\n\t},\n\ttriviahelp() {\n\t\tthis.sendReply(\n\t\t\t`|html|<div class=\"infobox\">` +\n\t\t\t`<strong>Categories</strong>: <code>Arts & Entertainment</code>, <code>Pokémon</code>, <code>Science & Geography</code>, <code>Society & Humanities</code>, <code>Random</code>, and <code>All</code>.<br />` +\n\t\t\t`<details><summary><strong>Modes</strong></summary><ul>` +\n\t\t\t`\t<li>First: the first correct responder gains 5 points.</li>` +\n\t\t\t`\t<li>Timer: each correct responder gains up to 5 points based on how quickly they answer.</li>` +\n\t\t\t`\t<li>Number: each correct responder gains up to 5 points based on how many participants are correct.</li>` +\n\t\t\t`\t<li>Triumvirate: The first correct responder gains 5 points, the second 3 points, and the third 1 point.</li>` +\n\t\t\t`\t<li>Random: randomly chooses one of First, Timer, Number, or Triumvirate.</li>` +\n\t\t\t`</ul></details>` +\n\t\t\t`<details><summary><strong>Game lengths</strong></summary><ul>` +\n\t\t\t`\t<li>Short: 20 point score cap. The winner gains 3 leaderboard points.</li>` +\n\t\t\t`\t<li>Medium: 35 point score cap. The winner gains 4 leaderboard points.</li>` +\n\t\t\t`\t<li>Long: 50 point score cap. The winner gains 5 leaderboard points.</li>` +\n\t\t\t`\t<li>Infinite: No score cap. The winner gains 5 leaderboard points, which increases the more questions they answer.</li>` +\n\t\t\t`\t<li>You may also specify a number for length; in this case, the game will end after that number of questions have been asked.</li>` +\n\t\t\t`</ul></details>` +\n\t\t\t`<details><summary><strong>Game commands</strong></summary><ul>` +\n\t\t\t`\t<li><code>/trivia new [mode], [categories], [length]</code> - Begin signups for a new Trivia game. <code>[categories]</code> can be either one category, or a <code>+</code>-separated list of categories. Requires: + % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia unrankednew [mode], [category], [length]</code> - Begin a new Trivia game that does not award leaderboard points. Requires: + % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia sortednew [mode], [category], [length]</code> \u2014 Begin a new Trivia game in which the question order is not randomized. Requires: + % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia join</code> - Join a game of Trivia or Mastermind during signups.</li>` +\n\t\t\t`\t<li><code>/trivia start</code> - Begin the game once enough users have signed up. Requires: + % @ # ~</li>` +\n\t\t\t`\t<li><code>/ta [answer]</code> - Answer the current question.</li>` +\n\t\t\t`\t<li><code>/trivia kick [username]</code> - Disqualify a participant from the current trivia game. Requires: % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia leave</code> - Makes the player leave the game.</li>` +\n\t\t\t`\t<li><code>/trivia end</code> - End a trivia game. Requires: + % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia win</code> - End a trivia game and tally the points to find winners. Requires: + % @ # ~ in Infinite length, else # ~</li>` +\n\t\t\t`\t<li><code>/trivia pause</code> - Pauses a trivia game. Requires: + % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia resume</code> - Resumes a paused trivia game. Requires: + % @ # ~</li>` +\n\t\t\t`</ul></details>` +\n\t\t\t`\t<details><summary><strong>Question-modifying commands</strong></summary><ul>` +\n\t\t\t`\t<li><code>/trivia submit [category] | [question] | [answer1], [answer2] ... [answern]</code> - Adds question(s) to the submission database for staff to review. Requires: + % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia review</code> - View the list of submitted questions. Requires: @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia accept [index1], [index2], ... [indexn] OR all</code> - Add questions from the submission database to the question database using their index numbers or ranges of them. Requires: @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia reject [index1], [index2], ... [indexn] OR all</code> - Remove questions from the submission database using their index numbers or ranges of them. Requires: @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia add [category] | [question] | [answer1], [answer2], ... [answern]</code> - Adds question(s) to the question database. Requires: % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia delete [question]</code> - Delete a question from the trivia database. Requires: % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia move [category] | [question]</code> - Change the category of question in the trivia database. Requires: % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia migrate [source category], [destination category]</code> \u2014 Moves all questions in a category to another category. Requires: # ~</li>` +\n\t\t\tUtils.html`<li><code>${'/trivia edit <old question text> | <new question text> | <answer1, answer2, ...>'}</code>: Edit a question in the trivia database, replacing answers if specified. Requires: % @ # ~` +\n\t\t\tUtils.html`<li><code>${'/trivia edit answers | <old question text> | <new answers>'}</code>: Replaces the answers of a question. Requires: % @ # ~</li>` +\n\t\t\tUtils.html`<li><code>${'/trivia edit question | <old question text> | <new question text>'}</code>: Edits only the text of a question. Requires: % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia qs</code> - View the distribution of questions in the question database.</li>` +\n\t\t\t`\t<li><code>/trivia qs [category]</code> - View the questions in the specified category. Requires: % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia clearqs [category]</code> - Clear all questions in the given category. Requires: # ~</li>` +\n\t\t\t`\t<li><code>/trivia moveusedevent</code> - Tells you whether or not moving used event questions to a different category is enabled.</li>` +\n\t\t\t`\t<li><code>/trivia moveusedevent [on or off]</code> - Toggles moving used event questions to a different category. Requires: # ~</li>` +\n\t\t\t`</ul></details>` +\n\t\t\t`<details><summary><strong>Informational commands</strong></summary><ul>` +\n\t\t\t`\t<li><code>/trivia search [type], [query]</code> - Searches for questions based on their type and their query. Valid types: <code>submissions</code>, <code>subs</code>, <code>questions</code>, <code>qs</code>. Requires: + % @ # ~</li>` +\n\t\t\t`\t<li><code>/trivia casesensitivesearch [type], [query]</code> - Like <code>/trivia search</code>, but is case sensitive (i.e., capitalization matters). Requires: + % @ * ~</li>` +\n\t\t\t`\t<li><code>/trivia status [player]</code> - lists the player's standings (your own if no player is specified) and the list of players in the current trivia game.</li>` +\n\t\t\t`\t<li><code>/trivia rank [username]</code> - View the rank of the specified user. If none is given, view your own.</li>` +\n\t\t\t`\t<li><code>/trivia history</code> - View a list of the 10 most recently played trivia games.</li>` +\n\t\t\t`\t<li><code>/trivia lastofficialscore</code> - View the scores from the last Trivia game. Intended for bots.</li>` +\n\t\t\t`</ul></details>` +\n\t\t\t`<details><summary><strong>Leaderboard commands</strong></summary><ul>` +\n\t\t\t`\t<li><code>/trivia ladder [n]</code> - Displays the top <code>[n]</code> users on the cycle-specific Trivia leaderboard. If <code>[n]</code> isn't specified, shows 100 users.</li>` +\n\t\t\t`\t<li><code>/trivia alltimewinsladder</code> - Like <code>/trivia ladder</code>, but displays the all-time wins Trivia leaderboard (formerly all-time).</li>` +\n\t\t\t`\t<li><code>/trivia alltimescoreladder</code> - Like <code>/trivia ladder</code>, but displays the all-time score Trivia leaderboard (formerly non\u2014all-time)</li>` +\n\t\t\t`\t<li><code>/trivia resetcycleleaderboard</code> - Resets the cycle-specific Trivia leaderboard. Requires: # ~` +\n\t\t\t`\t<li><code>/trivia mergescore [user]</code> \u2014 Merge another user's Trivia leaderboard score with yours.</li>` +\n\t\t\t`\t<li><code>/trivia addpoints [user], [points]</code> - Add points to a given user's score on the Trivia leaderboard. Requires: # ~</li>` +\n\t\t\t`\t<li><code>/trivia removepoints [user], [points]</code> - Remove points from a given user's score on the Trivia leaderboard. Requires: # ~</li>` +\n\t\t\t`\t<li><code>/trivia removeleaderboardentry [user]</code> \u2014 Remove all Trivia leaderboard entries for a user. Requires: # ~</li>` +\n\t\t\t`</ul></details>`\n\t\t);\n\t},\n};\n\nconst mastermindCommands: Chat.ChatCommands = {\n\tanswer: triviaCommands.answer,\n\tend: triviaCommands.end,\n\tkick: triviaCommands.kick,\n\n\tnew(target, room, user) {\n\t\troom = this.requireRoom('trivia' as RoomID);\n\t\tthis.checkCan('show', null, room);\n\n\t\tconst finalists = parseInt(target);\n\t\tif (isNaN(finalists) || finalists < 2) {\n\t\t\treturn this.errorReply(this.tr`You must specify a number that is at least 2 for finalists.`);\n\t\t}\n\n\t\troom.game = new Mastermind(room, finalists);\n\t},\n\tnewhelp: [\n\t\t`/mastermind new [number of finalists] \u2014 Starts a new game of Mastermind with the specified number of finalists. Requires: + % @ # ~`,\n\t],\n\n\tasync start(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tthis.checkCan('show', null, room);\n\t\tthis.checkChat();\n\t\tconst game = getMastermindGame(room);\n\n\t\tlet [category, timeoutString, player] = target.split(',').map(toID);\n\t\tif (!player) return this.parse(`/help mastermind start`);\n\n\t\tcategory = CATEGORY_ALIASES[category] || category;\n\t\tif (!(category in ALL_CATEGORIES)) {\n\t\t\treturn this.errorReply(this.tr`${category} is not a valid category.`);\n\t\t}\n\t\tconst categoryName = ALL_CATEGORIES[category];\n\t\tconst timeout = parseInt(timeoutString);\n\t\tif (isNaN(timeout) || timeout < 1 || (timeout * 1000) > Chat.MAX_TIMEOUT_DURATION) {\n\t\t\treturn this.errorReply(this.tr`You must specify a round length of at least 1 second.`);\n\t\t}\n\n\t\tconst questions = await getQuestions([category], 'random');\n\t\tif (!questions.length) {\n\t\t\treturn this.errorReply(this.tr`There are no questions in the ${categoryName} category.`);\n\t\t}\n\n\t\tgame.startRound(player, category, questions, timeout);\n\t},\n\tstarthelp: [\n\t\t`/mastermind start [category], [length in seconds], [player] \u2014 Starts a round of Mastermind for a player. Requires: + % @ # ~`,\n\t],\n\n\tasync finals(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tthis.checkCan('show', null, room);\n\t\tthis.checkChat();\n\t\tconst game = getMastermindGame(room);\n\t\tif (!target) return this.parse(`/help mastermind finals`);\n\n\t\tconst timeout = parseInt(target);\n\t\tif (isNaN(timeout) || timeout < 1 || (timeout * 1000) > Chat.MAX_TIMEOUT_DURATION) {\n\t\t\treturn this.errorReply(this.tr`You must specify a length of at least 1 second.`);\n\t\t}\n\n\t\tawait game.startFinals(timeout);\n\t},\n\tfinalshelp: [`/mastermind finals [length in seconds] \u2014 Starts the Mastermind finals. Requires: + % @ # ~`],\n\n\tjoin(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tgetMastermindGame(room).addTriviaPlayer(user);\n\t\tthis.sendReply(this.tr`You are now signed up for this game!`);\n\t},\n\tjoinhelp: [`/mastermind join \u2014 Joins the current game of Mastermind.`],\n\n\tleave(target, room, user) {\n\t\tgetMastermindGame(room).leave(user);\n\t\tthis.sendReply(this.tr`You have left the current game of Mastermind.`);\n\t},\n\tleavehelp: [`/mastermind leave - Makes the player leave the game.`],\n\n\tpass(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tconst round = getMastermindGame(room).currentRound;\n\t\tif (!round) return this.errorReply(this.tr`No round of Mastermind is currently being played.`);\n\t\tif (!(user.id in round.playerTable)) {\n\t\t\treturn this.errorReply(this.tr`You are not a player in the current round of Mastermind.`);\n\t\t}\n\t\tround.pass();\n\t},\n\tpasshelp: [`/mastermind pass \u2014 Passes on the current question. Must be the player of the current round of Mastermind.`],\n\n\t'': 'players',\n\tplayers(target, room, user) {\n\t\troom = this.requireRoom();\n\t\tif (!this.runBroadcast()) return false;\n\t\tconst game = getMastermindGame(room);\n\n\t\tlet buf = this.tr`There is a Mastermind game in progress, and it is in its ${game.phase} phase.`;\n\t\tbuf += `<br /><hr>${this.tr`Players`}: ${game.formatPlayerList()}`;\n\n\t\tthis.sendReplyBox(buf);\n\t},\n\n\thelp() {\n\t\treturn this.parse(`${this.cmdToken}help mastermind`);\n\t},\n\n\tmastermindhelp() {\n\t\tif (!this.runBroadcast()) return;\n\t\tconst commandHelp = [\n\t\t\t`<code>/mastermind new [number of finalists]</code>: starts a new game of Mastermind with the specified number of finalists. Requires: + % @ # ~`,\n\t\t\t`<code>/mastermind start [category], [length in seconds], [player]</code>: starts a round of Mastermind for a player. Requires: + % @ # ~`,\n\t\t\t`<code>/mastermind finals [length in seconds]</code>: starts the Mastermind finals. Requires: + % @ # ~`,\n\t\t\t`<code>/mastermind kick [user]</code>: kicks a user from the current game of Mastermind. Requires: % @ # ~`,\n\t\t\t`<code>/mastermind join</code>: joins the current game of Mastermind.`,\n\t\t\t`<code>/mastermind answer OR /mma [answer]</code>: answers a question in a round of Mastermind.`,\n\t\t\t`<code>/mastermind pass OR /mmp</code>: passes on the current question. Must be the player of the current round of Mastermind.`,\n\t\t];\n\t\treturn this.sendReplyBox(\n\t\t\t`<strong>Mastermind</strong> is a game in which each player tries to score as many points as possible in a timed round where only they can answer, ` +\n\t\t\t`and the top X players advance to the finals, which is a timed game of Trivia in which only the first player to answer a question recieves points.` +\n\t\t\t`<details><summary><strong>Commands</strong></summary>${commandHelp.join('<br />')}</details>`\n\t\t);\n\t},\n};\n\nexport const commands: Chat.ChatCommands = {\n\tmm: mastermindCommands,\n\tmastermind: mastermindCommands,\n\tmastermindhelp: mastermindCommands.mastermindhelp,\n\tmma: mastermindCommands.answer,\n\tmmp: mastermindCommands.pass,\n\ttrivia: triviaCommands,\n\tta: triviaCommands.answer,\n\ttriviahelp: triviaCommands.triviahelp,\n};\n\nprocess.nextTick(() => {\n\tChat.multiLinePattern.register('/trivia add ', '/trivia submit ', '/trivia move ');\n});\n"], | |
"mappings": "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", | |
"names": ["scores", "category"] | |
} | |