/** * The Studio: Artist of the Day plugin * This is a daily activity where users nominate the featured artist for the day, which is selected randomly once voting has ended. * Only works in a room with the id 'thestudio' */ 'use strict'; function toArtistId(artist) { // toId would return '' for foreign/sadistic artists return artist.toLowerCase().replace(/\s/g, '').replace(/\b&\b/g, ''); } let artistOfTheDay = { pendingNominations: false, nominations: new Map(), removedNominators: [], }; let theStudio = Rooms.get('thestudio'); if (theStudio) { if (theStudio.plugin) { artistOfTheDay = theStudio.plugin; } else { theStudio.plugin = artistOfTheDay; } } let commands = { start: function (target, room, user) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!room.chatRoomData || !this.can('mute', null, room)) return false; if (!this.canTalk()) return; if (artistOfTheDay.pendingNominations) return this.sendReply("Nominations for the Artist of the Day are already in progress."); let nominations = artistOfTheDay.nominations; let prenominations = room.chatRoomData.prenominations; if (prenominations && prenominations.length) { for (let i = 0; i < prenominations.length; i++) { let prenomination = prenominations[i]; nominations.set(Users.get(prenomination[0].userid) || prenomination[0], prenomination[1]); } } artistOfTheDay.pendingNominations = true; room.chatRoomData.prenominations = []; Rooms.global.writeChatRoomData(); room.addRaw( "
Nominations for the Artist of the Day have begun!
" + "Use /aotd nom to nominate an artist.
" ); this.privateModCommand("(" + user.name + " began nominations for the Artist of the Day.)"); }, starthelp: ["/aotd start - Start nominations for the Artist of the Day. Requires: % @ # & ~"], end: function (target, room, user) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!room.chatRoomData || !this.can('mute', null, room)) return false; if (!this.canTalk()) return; if (!artistOfTheDay.pendingNominations) return this.sendReply("Nominations for the Artist of the Day are not in progress."); if (!artistOfTheDay.nominations.size) return this.sendReply("No nominations have been submitted yet."); let nominations = Array.from(artistOfTheDay.nominations); let artist = nominations[~~(Math.random() * nominations.length)][1]; artistOfTheDay.pendingNominations = false; artistOfTheDay.nominations.clear(); artistOfTheDay.removedNominators = []; room.chatRoomData.artistOfTheDay = artist; Rooms.global.writeChatRoomData(); room.addRaw( "
Nominations for the Artist of the Day have ended!
" + "Randomly selected artist: " + Chat.escapeHTML(artist) + "
" ); this.privateModCommand("(" + user.name + " ended nominations for the Artist of the Day.)"); }, endhelp: ["/aotd end - End nominations for the Artist of the Day and set it to a randomly selected artist. Requires: % @ # & ~"], prenom: function (target, room, user) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!target) this.parse('/help aotd prenom'); if (!room.chatRoomData || !target) return false; if (!this.canTalk()) return; if (artistOfTheDay.pendingNominations) return this.sendReply("Nominations for the Artist of the Day are in progress."); if (!room.chatRoomData.prenominations) room.chatRoomData.prenominations = []; let userid = user.userid; let prenominationId = toArtistId(target); if (!prenominationId) return this.sendReply("" + target + " is not a valid artist name."); if (room.chatRoomData.artistOfTheDay && toArtistId(room.chatRoomData.artistOfTheDay) === prenominationId) return this.sendReply("" + target + " is already the current Artist of the Day."); let prenominations = room.chatRoomData.prenominations; let prenominationIndex = -1; let latestIp = user.latestIp; for (let i = 0; i < prenominations.length; i++) { if (toArtistId(prenominations[i][1]) === prenominationId) return this.sendReply("" + target + " has already been prenominated."); if (prenominationIndex < 0) { let prenominator = prenominations[i][0]; if (prenominator.userid === userid || prenominator.ips[latestIp]) { prenominationIndex = i; break; } } } if (prenominationIndex >= 0) { prenominations[prenominationIndex][1] = target; Rooms.global.writeChatRoomData(); return this.sendReply("Your prenomination was changed to " + target + "."); } prenominations.push([{name: user.name, userid: userid, ips: user.ips}, target]); Rooms.global.writeChatRoomData(); this.sendReply("" + target + " was submitted for the next nomination period for the Artist of the Day."); }, prenomhelp: ["/aotd prenom [artist] - Nominate an artist for the Artist of the Day between nomination periods."], nom: function (target, room, user) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!target) this.parse('/help aotd nom'); if (!room.chatRoomData || !target) return false; if (!this.canTalk()) return; if (!artistOfTheDay.pendingNominations) return this.sendReply("Nominations for the Artist of the Day are not in progress."); let removedNominators = artistOfTheDay.removedNominators; if (removedNominators.includes(user)) return this.sendReply("Since your nomination has been removed, you cannot submit another artist until the next round."); let alts = user.getAlts(); for (let i = 0; i < removedNominators.length; i++) { if (alts.includes(removedNominators[i].name)) return this.sendReply("Since your nomination has been removed, you cannot submit another artist until the next round."); } let nominationId = toArtistId(target); if (room.chatRoomData.artistOfTheDay && toArtistId(room.chatRoomData.artistOfTheDay) === nominationId) return this.sendReply("" + target + " was the last Artist of the Day."); let userid = user.userid; let latestIp = user.latestIp; for (let data of artistOfTheDay.nominations) { let nominator = data[0]; if (nominator.ips[latestIp] && nominator.userid !== userid || alts.includes(nominator.name)) return this.sendReply("You have already submitted a nomination for the Artist of the Day under the name " + nominator.name + "."); if (toArtistId(data[1]) === nominationId) return this.sendReply("" + target + " has already been nominated."); } let response = "" + user.name + (artistOfTheDay.nominations.has(user) ? " changed their nomination from " + artistOfTheDay.nominations.get(user) + " to " + target + "." : " nominated " + target + " for the Artist of the Day."); artistOfTheDay.nominations.set(user, target); room.add(response); }, nomhelp: ["/aotd nom [artist] - Nominate an artist for the Artist of the Day."], viewnoms: function (target, room, user) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!room.chatRoomData) return false; let buffer = ""; if (!artistOfTheDay.pendingNominations) { if (!user.can('mute', null, room)) return false; let prenominations = room.chatRoomData.prenominations; if (!prenominations || !prenominations.length) return this.sendReplyBox("No prenominations have been submitted yet."); prenominations = prenominations.sort((a, b) => { if (a[1] > b[1]) return 1; if (a[1] < b[1]) return -1; return 0; }); buffer += "Current prenominations: (" + prenominations.length + ")"; for (let i = 0; i < prenominations.length; i++) { buffer += "
" + "- " + Chat.escapeHTML(prenominations[i][1]) + " (submitted by " + Chat.escapeHTML(prenominations[i][0].name) + ")"; } return this.sendReplyBox(buffer); } if (!this.runBroadcast()) return false; if (!artistOfTheDay.nominations.size) return this.sendReplyBox("No nominations have been submitted yet."); let nominations = Array.from(artistOfTheDay.nominations).sort((a, b) => a[1].localeCompare(b[1])); buffer += "Current nominations (" + nominations.length + "):"; for (let i = 0; i < nominations.length; i++) { buffer += "
" + "- " + Chat.escapeHTML(nominations[i][1]) + " (submitted by " + Chat.escapeHTML(nominations[i][0].name) + ")"; } this.sendReplyBox(buffer); }, viewnomshelp: ["/aotd viewnoms - View the current nominations for the Artist of the Day. Requires: % @ * # & ~"], removenom: function (target, room, user) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!target) this.parse('/help aotd removenom'); if (!room.chatRoomData || !target || !this.can('mute', null, room)) return false; if (!this.canTalk()) return; if (!artistOfTheDay.pendingNominations) return this.sendReply("Nominations for the Artist of the Day are not in progress."); if (!artistOfTheDay.nominations.size) return this.sendReply("No nominations have been submitted yet."); target = this.splitTarget(target); let name = this.targetUsername; let userid = toId(name); if (!userid) return this.errorReply("'" + name + "' is not a valid username."); for (let nominator of artistOfTheDay.nominations.keys()) { if (nominator.userid === userid) { artistOfTheDay.nominations.delete(nominator); artistOfTheDay.removedNominators.push(nominator); return this.privateModCommand("(" + user.name + " removed " + nominator.name + "'s nomination for the Artist of the Day.)"); } } this.sendReply("User '" + name + "' has no nomination for the Artist of the Day."); }, removenomhelp: ["/aotd removenom [username] - Remove a user\'s nomination for the Artist of the Day and prevent them from voting again until the next round. Requires: % @ * # & ~"], set: function (target, room, user) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!target) this.parse('/help aotd set'); if (!room.chatRoomData || !this.can('mute', null, room)) return false; if (!this.canTalk()) return; if (!toId(target)) return this.errorReply("No valid artist was specified."); if (artistOfTheDay.pendingNominations) return this.sendReply("The Artist of the Day cannot be set while nominations are in progress."); room.chatRoomData.artistOfTheDay = target; Rooms.global.writeChatRoomData(); this.privateModCommand("(" + user.name + " set the Artist of the Day to " + target + ".)"); }, sethelp: ["/aotd set [artist] - Set the Artist of the Day. Requires: % @ * # & ~"], quote: function (target, room, user) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!room.chatRoomData) return false; if (!target) { if (!this.runBroadcast()) return; if (!room.chatRoomData.artistQuoteOfTheDay) return this.sendReplyBox("The Artist Quote of the Day has not been set."); return this.sendReplyBox( "The current Artist Quote of the Day is:
" + "\"" + room.chatRoomData.artistQuoteOfTheDay + "\"" ); } if (!this.can('mute', null, room)) return false; if (target === 'off' || target === 'disable' || target === 'reset') { if (!room.chatRoomData.artistQuoteOfTheDay) return this.sendReply("The Artist Quote of the Day has already been reset."); delete room.chatRoomData.artistQuoteOfTheDay; this.sendReply("The Artist Quote of the Day was reset by " + Chat.escapeHTML(user.name) + "."); this.logModCommand(user.name + " reset the Artist Quote of the Day."); Rooms.global.writeChatRoomData(); return; } room.chatRoomData.artistQuoteOfTheDay = Chat.escapeHTML(target); Rooms.global.writeChatRoomData(); room.addRaw( "
The Artist Quote of the Day has been updated by " + Chat.escapeHTML(user.name) + ".
" + "Quote: " + room.chatRoomData.artistQuoteOfTheDay + "
" ); this.logModCommand(Chat.escapeHTML(user.name) + " updated the artist quote of the day to \"" + room.chatRoomData.artistQuoteOfTheDay + "\"."); }, quotehelp: [ "/aotd quote - View the current Artist Quote of the Day.", "/aotd quote [quote] - Set the Artist Quote of the Day. Requires: # & ~", ], song: function (target, room, user) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!target) return this.parse('/help aotd song'); if (!room.chatRoomData || !this.can('mute', null, room)) return false; if (!this.canTalk()) return; if (target === 'off' || target === 'disable') { room.chatRoomData.songOfTheDayHTML = false; Rooms.global.writeChatRoomData(); return this.privateModCommand(`(${user.name} has disabled the Song of the Day.)`); } else if (target.includes(',')) { let title = target.split(',')[0].trim(); let link = target.split(',')[1].trim(); room.chatRoomData.songOfTheDayHTML = Chat.html`${title}.`; Rooms.global.writeChatRoomData(); return this.privateModCommand(`(${user.name} set the Song of the Day to ${title} (Link: ${link})`); } else { return this.parse('/help aotd song'); } }, songhelp: [ "/aotd song [song], [link] - Sets the Song of the Day. Requires % @ * # & ~", "/aotd song [off|disable] - Turns the Song of the Day off. Requires % @ * # & ~", ], '': function (target, room) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!room.chatRoomData || !this.runBroadcast()) return false; let song = (room.chatRoomData.songOfTheDayHTML ? '
The Song of the Day is ' + room.chatRoomData.songOfTheDayHTML : ''); this.sendReplyBox("The Artist of the Day " + (room.chatRoomData.artistOfTheDay ? "is " + Chat.escapeHTML(room.chatRoomData.artistOfTheDay) + "." : "has not been set yet.") + song); }, help: function (target, room) { if (room.id !== 'thestudio') return this.errorReply('This command can only be used in The Studio.'); if (!room.chatRoomData || !this.runBroadcast()) return false; this.sendReply("Use /help aotd to view help for all commands, or /help aotd [command] for help on a specific command."); }, }; exports.commands = { aotd: commands, aotdhelp: [ "The Studio: Artist of the Day plugin commands:", "- /aotd - View the Artist of the Day.", "- /aotd start - Start nominations for the Artist of the Day. Requires: % @ * # & ~", "- /aotd nom [artist] - Nominate an artist for the Artist of the Day.", "- /aotd viewnoms - View the current nominations for the Artist of the Day. Requires: % @ * # & ~", "- /aotd removenom [username] - Remove a user's nomination for the Artist of the Day and prevent them from voting again until the next round. Requires: % @ # & ~", "- /aotd end - End nominations for the Artist of the Day and set it to a randomly selected artist. Requires: % @ * # & ~", "- /aotd prenom [artist] - Nominate an artist for the Artist of the Day between nomination periods.", "- /aotd set [artist] - Set the Artist of the Day. Requires: % @ * # & ~", "- /aotd quote - View the current Artist Quote of the Day.", "- /aotd quote [quote] - Set the Artist Quote of the Day. Requires: # & ~", "- /aotd song [song], [link] - Sets the Song of the Day. Requires % @ * # & ~", "- /aotd song [off|disable] - Turns the Song of the Day off. Requires % @ * # & ~", ], };