{ "version": 3, "sources": ["../../../../server/chat-plugins/hangman.ts"], "sourcesContent": ["/*\r\n* Hangman chat plugin\r\n* By bumbadadabum and Zarel. Art by crobat.\r\n*/\r\nimport {FS, Utils} from '../../lib';\r\n\r\nconst HANGMAN_FILE = 'config/chat-plugins/hangman.json';\r\n\r\nconst DIACRITICS_AFTER_UNDERSCORE = /_[\\u0300-\\u036f\\u0483-\\u0489\\u0610-\\u0615\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06ED\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E]+/g;\r\nconst MAX_HANGMAN_LENGTH = 30;\r\nconst MAX_INDIVIDUAL_WORD_LENGTH = 20;\r\nconst MAX_HINT_LENGTH = 150;\r\n\r\ninterface HangmanEntry {\r\n\thints: string[];\r\n\ttags?: string[];\r\n}\r\n\r\n// futureproofing this into one single object so that new params can be added\r\n// more easily\r\ninterface HangmanOptions {\r\n\tallowCreator?: boolean;\r\n}\r\n\r\nexport let hangmanData: {[roomid: string]: {[phrase: string]: HangmanEntry}} = {};\r\n\r\ntry {\r\n\thangmanData = JSON.parse(FS(HANGMAN_FILE).readSync());\r\n\tlet save = false;\r\n\tfor (const roomid in hangmanData) {\r\n\t\tconst roomData = hangmanData[roomid] || {};\r\n\t\tconst roomKeys = Object.keys(roomData);\r\n\t\tif (roomKeys.length && !roomData[roomKeys[0]].hints) {\r\n\t\t\tsave = true;\r\n\t\t\tfor (const key of roomKeys) {\r\n\t\t\t\troomData[key] = {hints: roomData[key] as any};\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\tif (save) {\r\n\t\tFS(HANGMAN_FILE).writeUpdate(() => JSON.stringify(hangmanData));\r\n\t}\r\n} catch {}\r\n\r\nconst maxMistakes = 6;\r\n\r\nexport class Hangman extends Rooms.SimpleRoomGame {\r\n\tgameNumber: number;\r\n\tcreator: ID;\r\n\tword: string;\r\n\thint: string;\r\n\tincorrectGuesses: number;\r\n\toptions: HangmanOptions;\r\n\r\n\tguesses: string[];\r\n\tletterGuesses: string[];\r\n\tlastGuesser: string;\r\n\twordSoFar: string[];\r\n\treadonly checkChat = true;\r\n\r\n\tconstructor(\r\n\t\troom: Room,\r\n\t\tuser: User,\r\n\t\tword: string,\r\n\t\thint = '',\r\n\t\tgameOptions: HangmanOptions = {}\r\n\t) {\r\n\t\tsuper(room);\r\n\r\n\t\tthis.gameNumber = room.nextGameNumber();\r\n\r\n\t\tthis.gameid = 'hangman' as ID;\r\n\t\tthis.title = 'Hangman';\r\n\t\tthis.creator = user.id;\r\n\t\tthis.word = word;\r\n\t\tthis.hint = hint;\r\n\t\tthis.incorrectGuesses = 0;\r\n\t\tthis.options = gameOptions;\r\n\r\n\t\tthis.guesses = [];\r\n\t\tthis.letterGuesses = [];\r\n\t\tthis.lastGuesser = '';\r\n\t\tthis.wordSoFar = [];\r\n\r\n\t\tfor (const letter of word) {\r\n\t\t\tif (/[a-zA-Z]/.test(letter)) {\r\n\t\t\t\tthis.wordSoFar.push('_');\r\n\t\t\t} else {\r\n\t\t\t\tthis.wordSoFar.push(letter);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tchoose(user: User, word: string) {\r\n\t\tif (user.id === this.creator && !this.options.allowCreator) {\r\n\t\t\tthrow new Chat.ErrorMessage(\"You can't guess in your own hangman game.\");\r\n\t\t}\r\n\r\n\t\tconst sanitized = word.replace(/[^A-Za-z ]/g, '');\r\n\t\tconst normalized = toID(sanitized);\r\n\t\tif (normalized.length < 1) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Use \"/guess [letter]\" to guess a letter, or \"/guess [phrase]\" to guess the entire Hangman phrase.`);\r\n\t\t}\r\n\t\tif (sanitized.length > MAX_HANGMAN_LENGTH) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Guesses must be ${MAX_HANGMAN_LENGTH} or fewer letters \u2013 \"${word}\" is too long.`);\r\n\t\t}\r\n\r\n\t\tfor (const guessid of this.guesses) {\r\n\t\t\tif (normalized === toID(guessid)) throw new Chat.ErrorMessage(`Your guess \"${word}\" has already been guessed.`);\r\n\t\t}\r\n\r\n\t\tif (sanitized.length > 1) {\r\n\t\t\tif (!this.guessWord(sanitized, user.name)) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(`Your guess \"${sanitized}\" is invalid.`);\r\n\t\t\t} else {\r\n\t\t\t\tthis.room.addByUser(user, `${user.name} guessed \"${sanitized}\"!`);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\tif (!this.guessLetter(sanitized, user.name)) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(`Your guess \"${sanitized}\" is not a valid letter.`);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tguessLetter(letter: string, guesser: string) {\r\n\t\tletter = letter.toUpperCase();\r\n\t\tif (this.guesses.includes(letter)) return false;\r\n\t\tif (this.word.toUpperCase().includes(letter)) {\r\n\t\t\tfor (let i = 0; i < this.word.length; i++) {\r\n\t\t\t\tif (this.word[i].toUpperCase() === letter) {\r\n\t\t\t\t\tthis.wordSoFar[i] = this.word[i];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\tif (!this.wordSoFar.includes('_')) {\r\n\t\t\t\tthis.incorrectGuesses = -1;\r\n\t\t\t\tthis.guesses.push(letter);\r\n\t\t\t\tthis.letterGuesses.push(`${letter}1`);\r\n\t\t\t\tthis.lastGuesser = guesser;\r\n\t\t\t\tthis.finish();\r\n\t\t\t\treturn true;\r\n\t\t\t}\r\n\t\t\tthis.letterGuesses.push(`${letter}1`);\r\n\t\t} else {\r\n\t\t\tthis.incorrectGuesses++;\r\n\t\t\tthis.letterGuesses.push(`${letter}0`);\r\n\t\t}\r\n\r\n\t\tthis.guesses.push(letter);\r\n\t\tthis.lastGuesser = guesser;\r\n\t\tthis.update();\r\n\t\treturn true;\r\n\t}\r\n\r\n\tguessWord(word: string, guesser: string) {\r\n\t\tconst ourWord = toID(this.word.replace(/[0-9]+/g, ''));\r\n\t\tconst guessedWord = toID(word.replace(/[0-9]+/g, ''));\r\n\t\tconst wordSoFar = this.wordSoFar.filter(letter => /[a-zA-Z_]/.test(letter)).join('').toLowerCase();\r\n\r\n\t\t// Can't be a correct guess if the lengths don't match\r\n\t\tif (ourWord.length !== guessedWord.length) return false;\r\n\r\n\t\tfor (let i = 0; i < ourWord.length; i++) {\r\n\t\t\tif (wordSoFar.charAt(i) === '_') {\r\n\t\t\t\t// Can't be a correct guess if it contains letters already guessed\r\n\t\t\t\tif (this.letterGuesses.some(guess => guess.toLowerCase().startsWith(guessedWord.charAt(i)))) return false;\r\n\t\t\t} else if (wordSoFar.charAt(i) !== guessedWord.charAt(i)) {\r\n\t\t\t\t// Can't be a correct guess if the guess has incorrect letters in already guessed indexes\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (ourWord === guessedWord) {\r\n\t\t\tfor (const [i, letter] of this.wordSoFar.entries()) {\r\n\t\t\t\tif (letter === '_') {\r\n\t\t\t\t\tthis.wordSoFar[i] = this.word[i];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tthis.incorrectGuesses = -1;\r\n\t\t\tthis.guesses.push(word);\r\n\t\t\tthis.lastGuesser = guesser;\r\n\t\t\tthis.finish();\r\n\t\t} else {\r\n\t\t\tthis.incorrectGuesses++;\r\n\t\t\tthis.guesses.push(word);\r\n\t\t\tthis.lastGuesser = guesser;\r\n\t\t\tthis.update();\r\n\t\t}\r\n\t\treturn true;\r\n\t}\r\n\r\n\thangingMan() {\r\n\t\treturn ``;\r\n\t}\r\n\r\n\tgenerateWindow() {\r\n\t\tlet result = 0;\r\n\r\n\t\tif (this.incorrectGuesses === maxMistakes) {\r\n\t\t\tresult = 1;\r\n\t\t} else if (!this.wordSoFar.includes('_')) {\r\n\t\t\tresult = 2;\r\n\t\t}\r\n\r\n\t\tconst color = result === 1 ? 'red' : (result === 2 ? 'green' : 'blue');\r\n\t\tconst message = `${result === 1 ? 'Too bad! The mon has been hanged.' : (result === 2 ? 'The word has been guessed. Congratulations!' : 'Hangman')}`;\r\n\t\tlet output = `
`;\r\n\t\toutput += `

${message}

`;\r\n\t\toutput += `
${this.hangingMan()}`;\r\n\r\n\t\tlet escapedWord = this.wordSoFar.map(Utils.escapeHTML);\r\n\t\tif (result === 1) {\r\n\t\t\tconst word = this.word;\r\n\t\t\tescapedWord = escapedWord.map((letter, index) =>\r\n\t\t\t\tletter === '_' ? `${word.charAt(index)}` : letter);\r\n\t\t}\r\n\t\tconst wordString = escapedWord.join('').replace(DIACRITICS_AFTER_UNDERSCORE, '_');\r\n\r\n\t\tif (this.hint) output += Utils.html`
(Hint: ${this.hint})
`;\r\n\t\toutput += `

${wordString}

`;\r\n\t\tif (this.guesses.length) {\r\n\t\t\tif (this.letterGuesses.length) {\r\n\t\t\t\toutput += 'Letters: ' + this.letterGuesses.map(\r\n\t\t\t\t\tg => `${g[0]}`\r\n\t\t\t\t).join(', ');\r\n\t\t\t}\r\n\t\t\tif (result === 2) {\r\n\t\t\t\toutput += Utils.html`
Winner: ${this.lastGuesser}`;\r\n\t\t\t} else if (this.guesses[this.guesses.length - 1].length === 1) {\r\n\t\t\t\t// last guess was a letter\r\n\t\t\t\toutput += Utils.html` – ${this.lastGuesser}`;\r\n\t\t\t} else {\r\n\t\t\t\toutput += Utils.html`
Guessed: ${this.guesses[this.guesses.length - 1]} ` +\r\n\t\t\t\t\t`– ${this.lastGuesser}`;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\toutput += '
';\r\n\r\n\t\treturn output;\r\n\t}\r\n\r\n\tdisplay(user: User, broadcast = false) {\r\n\t\tif (broadcast) {\r\n\t\t\tthis.room.add(`|uhtml|hangman${this.gameNumber}|${this.generateWindow()}`);\r\n\t\t} else {\r\n\t\t\tuser.sendTo(this.room, `|uhtml|hangman${this.gameNumber}|${this.generateWindow()}`);\r\n\t\t}\r\n\t}\r\n\r\n\tupdate() {\r\n\t\tthis.room.uhtmlchange(`hangman${this.gameNumber}`, this.generateWindow());\r\n\r\n\t\tif (this.incorrectGuesses === maxMistakes) {\r\n\t\t\tthis.finish();\r\n\t\t}\r\n\t}\r\n\r\n\tend() {\r\n\t\tthis.room.uhtmlchange(`hangman${this.gameNumber}`, '
(The game of hangman was ended.)
');\r\n\t\tthis.room.add(\"The game of hangman was ended.\");\r\n\t\tthis.room.game = null;\r\n\t}\r\n\r\n\tfinish() {\r\n\t\tthis.room.uhtmlchange(`hangman${this.gameNumber}`, '
(The game of hangman has ended – scroll down to see the results)
');\r\n\t\tthis.room.add(`|html|${this.generateWindow()}`);\r\n\t\tthis.room.game = null;\r\n\t}\r\n\tstatic save() {\r\n\t\tFS(HANGMAN_FILE).writeUpdate(() => JSON.stringify(hangmanData));\r\n\t}\r\n\tstatic getRandom(room: RoomID, tag?: string) {\r\n\t\tif (!hangmanData[room]) {\r\n\t\t\thangmanData[room] = {};\r\n\t\t\tthis.save();\r\n\t\t}\r\n\t\tlet phrases = Object.keys(hangmanData[room]);\r\n\t\tif (!phrases.length) throw new Chat.ErrorMessage(`The room ${room} has no saved hangman words.`);\r\n\t\tif (tag) {\r\n\t\t\ttag = toID(tag);\r\n\t\t\tphrases = phrases.filter(key => hangmanData[room][key].tags?.map(toID).includes(tag as ID));\r\n\t\t\tif (!phrases.length) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(`No terms found with tag ${tag}`);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tconst shuffled = Utils.randomElement(phrases);\r\n\t\tconst entry = hangmanData[room][shuffled];\r\n\t\treturn {\r\n\t\t\tquestion: shuffled,\r\n\t\t\thint: Utils.randomElement(entry.hints),\r\n\t\t};\r\n\t}\r\n\tstatic validateParams(params: string[]) {\r\n\t\t// NFD splits diacritics apart from letters, allowing the letters to be guessed\r\n\t\t// underscore is used to signal \"letter hasn't been guessed yet\", so replace it with Japanese underscore as a workaround\r\n\t\tconst phrase = params[0].normalize('NFD').trim().replace(/_/g, '\\uFF3F');\r\n\r\n\t\tif (!phrase.length) throw new Chat.ErrorMessage(\"Enter a valid word\");\r\n\t\tif (phrase.length > MAX_HANGMAN_LENGTH) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Phrase must be less than ${MAX_HANGMAN_LENGTH} characters long.`);\r\n\t\t}\r\n\t\tif (phrase.split(' ').some(w => w.length > MAX_INDIVIDUAL_WORD_LENGTH)) {\r\n\t\t\tthrow new Chat.ErrorMessage(`Each word in the phrase must be less than ${MAX_INDIVIDUAL_WORD_LENGTH} characters long.`);\r\n\t\t}\r\n\t\tif (!/[a-zA-Z]/.test(phrase)) throw new Chat.ErrorMessage(\"Word must contain at least one letter.\");\r\n\t\tlet hint;\r\n\t\tif (params.length > 1) {\r\n\t\t\thint = params.slice(1).join(',').trim();\r\n\t\t\tif (hint.length > MAX_HINT_LENGTH) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(`Hint must be less than ${MAX_HINT_LENGTH} characters long.`);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn {phrase, hint};\r\n\t}\r\n}\r\n\r\nexport const commands: Chat.ChatCommands = {\r\n\thangman: {\r\n\t\tcreate: 'new',\r\n\t\tnew(target, room, user, connection) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\ttarget = target.trim();\r\n\t\t\tconst text = this.filter(target);\r\n\t\t\tif (target !== text) return this.errorReply(\"You are not allowed to use filtered words in hangmans.\");\r\n\t\t\tconst params = text.split(',');\r\n\r\n\t\t\tthis.checkCan('minigame', null, room);\r\n\t\t\tif (room.settings.hangmanDisabled) return this.errorReply(\"Hangman is disabled for this room.\");\r\n\t\t\tthis.checkChat();\r\n\t\t\tif (room.game) return this.errorReply(`There is already a game of ${room.game.title} in progress in this room.`);\r\n\r\n\t\t\tif (!params) return this.errorReply(\"No word entered.\");\r\n\t\t\tconst {phrase, hint} = Hangman.validateParams(params);\r\n\r\n\t\t\tconst game = new Hangman(room, user, phrase, hint);\r\n\t\t\troom.game = game;\r\n\t\t\tgame.display(user, true);\r\n\r\n\t\t\tthis.modlog('HANGMAN');\r\n\t\t\treturn this.addModAction(`A game of hangman was started by ${user.name} \u2013 use /guess to play!`);\r\n\t\t},\r\n\t\tcreatehelp: [\"/hangman create [word], [hint] - Makes a new hangman game. Requires: % @ # &\"],\r\n\r\n\t\tguess(target, room, user) {\r\n\t\t\tconst word = this.filter(target);\r\n\t\t\tif (word !== target) return this.errorReply(`You may not use filtered words in guesses.`);\r\n\t\t\tthis.parse(`/choose ${target}`);\r\n\t\t},\r\n\t\tguesshelp: [\r\n\t\t\t`/guess [letter] - Makes a guess for the letter entered.`,\r\n\t\t\t`/guess [word] - Same as a letter, but guesses an entire word.`,\r\n\t\t],\r\n\r\n\t\tstop: 'end',\r\n\t\tend(target, room, user) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\tthis.checkCan('minigame', null, room);\r\n\t\t\tthis.checkChat();\r\n\t\t\tconst game = this.requireGame(Hangman);\r\n\t\t\tgame.end();\r\n\t\t\tthis.modlog('ENDHANGMAN');\r\n\t\t\treturn this.privateModAction(`The game of hangman was ended by ${user.name}.`);\r\n\t\t},\r\n\t\tendhelp: [\"/hangman end - Ends the game of hangman before the man is hanged or word is guessed. Requires: % @ # &\"],\r\n\r\n\t\tdisable(target, room, user) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\tthis.checkCan('gamemanagement', null, room);\r\n\t\t\tif (room.settings.hangmanDisabled) {\r\n\t\t\t\treturn this.errorReply(\"Hangman is already disabled.\");\r\n\t\t\t}\r\n\t\t\troom.settings.hangmanDisabled = true;\r\n\t\t\troom.saveSettings();\r\n\t\t\treturn this.sendReply(\"Hangman has been disabled for this room.\");\r\n\t\t},\r\n\r\n\t\tenable(target, room, user) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\tthis.checkCan('gamemanagement', null, room);\r\n\t\t\tif (!room.settings.hangmanDisabled) {\r\n\t\t\t\treturn this.errorReply(\"Hangman is already enabled.\");\r\n\t\t\t}\r\n\t\t\tdelete room.settings.hangmanDisabled;\r\n\t\t\troom.saveSettings();\r\n\t\t\treturn this.sendReply(\"Hangman has been enabled for this room.\");\r\n\t\t},\r\n\r\n\t\tdisplay(target, room, user) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\tconst game = this.requireGame(Hangman);\r\n\t\t\tif (!this.runBroadcast()) return;\r\n\t\t\troom.update();\r\n\r\n\t\t\tgame.display(user, this.broadcasting);\r\n\t\t},\r\n\r\n\t\t''(target, room, user) {\r\n\t\t\treturn this.parse('/help hangman');\r\n\t\t},\r\n\r\n\t\trandom(target, room, user) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\tthis.checkCan('mute', null, room);\r\n\t\t\tif (room.game) {\r\n\t\t\t\tthrow new Chat.ErrorMessage(`There is already a game of ${room.game.title} running.`);\r\n\t\t\t}\r\n\t\t\ttarget = toID(target);\r\n\t\t\tconst {question, hint} = Hangman.getRandom(room.roomid, target);\r\n\t\t\tconst game = new Hangman(room, user, question, hint, {allowCreator: true});\r\n\t\t\troom.game = game;\r\n\t\t\tthis.addModAction(`${user.name} started a random game of hangman - use /guess to play!`);\r\n\t\t\tgame.display(user, true);\r\n\t\t\tthis.modlog(`HANGMAN RANDOM`, null, target ? `tag: ${target}` : '');\r\n\t\t},\r\n\t\taddrandom(target, room, user) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\tthis.checkCan('mute', null, room);\r\n\t\t\tif (!hangmanData[room.roomid]) hangmanData[room.roomid] = {};\r\n\t\t\tif (!target) return this.parse('/help hangman');\r\n\t\t\t// validation\r\n\t\t\tconst args = target.split(target.includes('|') ? '|' : ',');\r\n\t\t\tconst {phrase} = Hangman.validateParams(args);\r\n\t\t\tif (!hangmanData[room.roomid][phrase]) hangmanData[room.roomid][phrase] = {hints: []};\r\n\t\t\targs.shift();\r\n\t\t\thangmanData[room.roomid][phrase].hints.push(...args);\r\n\t\t\tHangman.save();\r\n\t\t\tthis.privateModAction(`${user.name} added a random hangman with ${Chat.count(args.length, 'hints')}.`);\r\n\t\t\tthis.modlog(`HANGMAN ADDRANDOM`, null, `${phrase}: ${args.join(', ')}`);\r\n\t\t},\r\n\t\trr: 'removerandom',\r\n\t\tremoverandom(target, room, user) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\tthis.checkCan('mute', null, room);\r\n\t\t\tlet [word, ...hints] = target.split(',');\r\n\t\t\tif (!toID(target) || !word) return this.parse('/help hangman');\r\n\t\t\tfor (const [i, hint] of hints.entries()) {\r\n\t\t\t\tif (hint.startsWith('room:')) {\r\n\t\t\t\t\tconst newID = hint.slice(5);\r\n\t\t\t\t\tconst targetRoom = Rooms.search(newID);\r\n\t\t\t\t\tif (!targetRoom) {\r\n\t\t\t\t\t\treturn this.errorReply(`Invalid room: ${newID}`);\r\n\t\t\t\t\t}\r\n\t\t\t\t\tthis.room = targetRoom;\r\n\t\t\t\t\troom = targetRoom;\r\n\t\t\t\t\thints.splice(i, 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!hangmanData[room.roomid]) {\r\n\t\t\t\treturn this.errorReply(\"There are no hangman words for this room.\");\r\n\t\t\t}\r\n\t\t\tconst roomKeys = Object.keys(hangmanData[room.roomid]);\r\n\t\t\tconst roomKeyIDs = roomKeys.map(toID);\r\n\t\t\tconst index = roomKeyIDs.indexOf(toID(word));\r\n\t\t\tif (index < 0) {\r\n\t\t\t\treturn this.errorReply(`That word is not a saved hangman.`);\r\n\t\t\t}\r\n\t\t\tword = roomKeys[index];\r\n\t\t\thints = hints.map(toID);\r\n\r\n\t\t\tif (!hints.length) {\r\n\t\t\t\tdelete hangmanData[room.roomid][word];\r\n\t\t\t\tthis.privateModAction(`${user.name} deleted the hangman entry for '${word}'`);\r\n\t\t\t\tthis.modlog(`HANGMAN REMOVERANDOM`, null, word);\r\n\t\t\t} else {\r\n\t\t\t\thangmanData[room.roomid][word].hints = hangmanData[room.roomid][word].hints.filter(item => !hints.includes(toID(item)));\r\n\t\t\t\tif (!hangmanData[room.roomid][word].hints.length) {\r\n\t\t\t\t\tdelete hangmanData[room.roomid][word];\r\n\t\t\t\t}\r\n\t\t\t\tthis.privateModAction(`${user.name} deleted ${Chat.count(hints, 'hints')} for the hangman term '${word}'`);\r\n\t\t\t\tthis.modlog(`HANGMAN REMOVERANDOM`, null, `${word}: ${hints.join(', ')}`);\r\n\t\t\t}\r\n\t\t\tthis.refreshPage(`hangman-${room.roomid}`);\r\n\t\t\tHangman.save();\r\n\t\t},\r\n\t\taddtag(target, room, user) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\tthis.checkCan('mute', null, room);\r\n\t\t\tlet [term, ...tags] = target.split(',');\r\n\t\t\t// only a .trim() because toID will make it unable to find the term if it has caps\r\n\t\t\tterm = term.trim();\r\n\t\t\ttags = tags.map(i => toID(i)).filter(Boolean);\r\n\t\t\tif (!term || !tags || !tags.length) {\r\n\t\t\t\treturn this.parse('/help hangman');\r\n\t\t\t}\r\n\t\t\tif (!hangmanData[room.roomid]) {\r\n\t\t\t\thangmanData[room.roomid] = {};\r\n\t\t\t}\r\n\t\t\tif (!hangmanData[room.roomid][term]) {\r\n\t\t\t\treturn this.errorReply(`Term ${term} not found.`);\r\n\t\t\t}\r\n\t\t\tif (!hangmanData[room.roomid][term].tags) hangmanData[room.roomid][term].tags = [];\r\n\t\t\tfor (const [i, tag] of tags.entries()) {\r\n\t\t\t\tif (hangmanData[room.roomid][term].tags!.includes(tag)) {\r\n\t\t\t\t\tthis.errorReply(`The tag ${tag} is already on the term ${term} and has been skipped.`);\r\n\t\t\t\t\ttags.splice(i, 1);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif (!tags.length) {\r\n\t\t\t\tthis.errorReply(`Specify at least one valid tag.`);\r\n\t\t\t\treturn this.parse(`/help hangman`);\r\n\t\t\t}\r\n\t\t\thangmanData[room.roomid][term].tags!.push(...tags);\r\n\t\t\tHangman.save();\r\n\t\t\tthis.privateModAction(`${user.name} added ${Chat.count(tags, \"tags\")} to the hangman term ${term}`);\r\n\t\t\tthis.modlog(`HANGMAN ADDTAG`, null, `${term}: ${tags.map(Utils.escapeHTML).join(', ')}`);\r\n\t\t\tthis.refreshPage(`hangman-${room.roomid}`);\r\n\t\t},\r\n\t\tuntag(target, room, user) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\tthis.checkCan('mute', null, room);\r\n\t\t\tif (!toID(target)) {\r\n\t\t\t\treturn this.parse(`/help hangman`);\r\n\t\t\t}\r\n\t\t\tlet [term, ...tags] = target.split(',');\r\n\t\t\ttags = tags.map(i => toID(i)).filter(Boolean);\r\n\t\t\tif (!term || !tags) {\r\n\t\t\t\treturn this.parse('/help hangman');\r\n\t\t\t}\r\n\t\t\tif (!hangmanData[room.roomid]) {\r\n\t\t\t\treturn this.errorReply(`This room has no hangman terms.`);\r\n\t\t\t}\r\n\t\t\tif (!hangmanData[room.roomid][term]) {\r\n\t\t\t\treturn this.errorReply(`That term was not found.`);\r\n\t\t\t}\r\n\t\t\tif (!hangmanData[room.roomid][term].tags) {\r\n\t\t\t\treturn this.errorReply(`That term has no tags.`);\r\n\t\t\t}\r\n\t\t\tif (tags.length) {\r\n\t\t\t\tthis.privateModAction(`${user.name} removed ${Chat.count(tags, \"tags\")} from the hangman term ${term}`);\r\n\t\t\t\tthis.modlog(`HANGMAN UNTAG`, null, `${term}: ${tags.map(Utils.escapeHTML).join(', ')}`);\r\n\t\t\t\thangmanData[room.roomid][term].tags = hangmanData[room.roomid][term].tags?.filter(t => !tags.includes(t));\r\n\t\t\t} else {\r\n\t\t\t\tthis.privateModAction(`${user.name} removed all tags from the hangman term ${term}`);\r\n\t\t\t\tthis.modlog(`HANGMAN UNTAG`, null, `${term}`);\r\n\t\t\t\thangmanData[room.roomid][term].tags = [];\r\n\t\t\t}\r\n\r\n\t\t\tif (!hangmanData[room.roomid][term].tags!.length) {\r\n\t\t\t\tdelete hangmanData[room.roomid][term].tags;\r\n\t\t\t}\r\n\t\t\tHangman.save();\r\n\t\t\tthis.refreshPage(`hangman-${room.roomid}`);\r\n\t\t},\r\n\t\tview: 'terms',\r\n\t\tterms(target, room, user) {\r\n\t\t\troom = this.requireRoom();\r\n\t\t\treturn this.parse(`/j view-hangman-${target || room.roomid}`);\r\n\t\t},\r\n\t},\r\n\r\n\thangmanhelp: [\r\n\t\t`/hangman allows users to play the popular game hangman in PS rooms.`,\r\n\t\t`Accepts the following commands:`,\r\n\t\t`/hangman create [word], [hint] - Makes a new hangman game. Requires: % @ # &`,\r\n\t\t`/hangman guess [letter] - Makes a guess for the letter entered.`,\r\n\t\t`/hangman guess [word] - Same as a letter, but guesses an entire word.`,\r\n\t\t`/hangman display - Displays the game.`,\r\n\t\t`/hangman end - Ends the game of hangman before the man is hanged or word is guessed. Requires: % @ # &`,\r\n\t\t`/hangman [enable/disable] - Enables or disables hangman from being started in a room. Requires: # &`,\r\n\t\t`/hangman random [tag]- Runs a random hangman, if the room has any added. `,\r\n\t\t`If a tag is given, randomizes from only terms with those tags. Requires: % @ # &`,\r\n\t\t`/hangman addrandom [word], [...hints] - Adds an entry for [word] with the [hints] provided to the room's hangman pool. Requires: % @ # &`,\r\n\t\t`/hangman removerandom [word][, hints] - Removes data from the hangman entry for [word]. If hints are given, removes only those hints.` +\r\n\t\t` Otherwise it removes the entire entry. Requires: % @ & #`,\r\n\t\t`/hangman addtag [word], [...tags] - Adds tags to the hangman term matching [word]. Requires: % @ & #`,\r\n\t\t`/hangman untag [term][, ...tags] - Removes tags from the hangman [term]. If tags are given, removes only those tags. Requires: % @ # * `,\r\n\t\t`/hangman terms - Displays all random hangman in a room. Requires: % @ # &`,\r\n\t],\r\n};\r\n\r\nexport const pages: Chat.PageTable = {\r\n\thangman(args, user) {\r\n\t\tconst room = this.requireRoom();\r\n\t\tthis.title = `[Hangman]`;\r\n\t\tthis.checkCan('mute', null, room);\r\n\t\tlet buf = `
`;\r\n\t\tbuf += `

Hangman entries on ${room.title}

`;\r\n\t\tconst roomTerms = hangmanData[room.roomid];\r\n\t\tif (!roomTerms) {\r\n\t\t\treturn this.errorReply(`No hangman terms found for ${room.title}.`);\r\n\t\t}\r\n\t\tfor (const t in roomTerms) {\r\n\t\t\tbuf += `
`;\r\n\t\t\tbuf += `

${t}


`;\r\n\t\t\tif (user.can('mute', null, room, 'hangman addrandom')) {\r\n\t\t\t\tbuf += `Hints: `;\r\n\t\t\t\tbuf += roomTerms[t].hints.map(\r\n\t\t\t\t\thint => `${hint} `\r\n\t\t\t\t).join(', ');\r\n\t\t\t\tbuf += ``;\r\n\t\t\t\tif (roomTerms[t].tags) {\r\n\t\t\t\t\tbuf += `
Tags: `;\r\n\t\t\t\t\tbuf += roomTerms[t].tags?.map(\r\n\t\t\t\t\t\ttag => `${tag} `\r\n\t\t\t\t\t).join(', ');\r\n\t\t\t\t\tbuf += ``;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tbuf += `

`;\r\n\t\t}\r\n\t\tbuf += `
`;\r\n\t\treturn buf;\r\n\t},\r\n};\r\n\r\nexport const roomSettings: Chat.SettingsHandler = room => ({\r\n\tlabel: \"Hangman\",\r\n\tpermission: 'editroom',\r\n\toptions: [\r\n\t\t[`disabled`, room.settings.hangmanDisabled || 'hangman disable'],\r\n\t\t[`enabled`, !room.settings.hangmanDisabled || 'hangman enable'],\r\n\t],\r\n});\r\n"], "mappings": "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", "names": [] }