/* * Announcements chat plugin * By Spandamn */ export interface AnnouncementOptions { activityNumber?: number; source: string; timeoutMins?: number; timerEnd?: number; } export interface AnnouncementData extends AnnouncementOptions { readonly activityid: 'announcement'; } export class Announcement extends Rooms.MinorActivity { readonly activityid = 'announcement' as ID; name = 'Announcement'; activityNumber: number; source: string; constructor(room: Room, options: AnnouncementOptions) { super(room); this.activityNumber = options.activityNumber || room.nextGameNumber(); this.source = options.source; this.setTimer(options); } generateAnnouncement() { return `

${this.source}

`; } displayTo(user: User, connection: Connection | null = null) { const recipient = connection || user; recipient.sendTo(this.room, `|uhtml|announcement${this.activityNumber}|${this.generateAnnouncement()}`); } display() { const announcement = this.generateAnnouncement(); for (const id in this.room.users) { const thisUser = this.room.users[id]; thisUser.sendTo(this.room, `|uhtml|announcement${this.activityNumber}|${announcement}`); } } onConnect(user: User, connection: Connection | null = null) { this.displayTo(user, connection); } destroy() { this.room.send(`|uhtmlchange|announcement${this.activityNumber}|
(${this.room.tr`The announcement has ended.`})
`); this.room.setMinorActivity(null); } toJSON(): AnnouncementData { return { source: this.source, activityNumber: this.activityNumber, timeoutMins: this.timeoutMins, timerEnd: this.timerEnd, activityid: 'announcement', }; } save() { this.room.settings.minorActivity = this.toJSON(); this.room.saveSettings(); } } export const commands: Chat.ChatCommands = { announcement: { htmlcreate: 'new', create: 'new', new(target, room, user, connection, cmd, message) { room = this.requireRoom(); if (!target) return this.parse('/help announcement new'); target = target.trim(); if (room.battle) return this.errorReply(this.tr`Battles do not support announcements.`); const text = this.filter(target); if (target !== text) return this.errorReply(this.tr`You are not allowed to use filtered words in announcements.`); const supportHTML = cmd === 'htmlcreate'; this.checkCan('minigame', null, room); if (supportHTML) this.checkCan('declare', null, room); this.checkChat(); if (room.minorActivity) { return this.errorReply(this.tr`There is already a poll or announcement in progress in this room.`); } const source = supportHTML ? this.checkHTML(Chat.collapseLineBreaksHTML(target)) : Chat.formatText(target, true); room.setMinorActivity(new Announcement(room, { source })); this.roomlog(`${user.name} used ${message}`); this.modlog('ANNOUNCEMENT'); return this.privateModAction(room.tr`An announcement was started by ${user.name}.`); }, newhelp: [`/announcement create [announcement] - Creates an announcement. Requires: % @ # ~`], htmledit: 'edit', edit(target, room, user, connection, cmd, message) { room = this.requireRoom(); const announcement = this.requireMinorActivity(Announcement); if (!target) return this.parse('/help announcement edit'); target = target.trim(); const text = this.filter(target); if (target !== text) return this.errorReply(this.tr`You are not allowed to use filtered words in announcements.`); const supportHTML = cmd === 'htmledit'; this.checkCan('minigame', null, room); if (supportHTML) this.checkCan('declare', null, room); this.checkChat(); const source = supportHTML ? this.checkHTML(Chat.collapseLineBreaksHTML(target)) : Chat.formatText(target, true); announcement.source = source; announcement.save(); this.roomlog(`${user.name} used ${message}`); this.modlog('ANNOUNCEMENT EDIT'); this.privateModAction(room.tr`The announcement was edited by ${user.name}.`); this.parse('/announcement display'); }, edithelp: [`/announcement edit [announcement] - Edits the announcement. Requires: % @ # ~`], timer(target, room, user) { room = this.requireRoom(); const announcement = this.requireMinorActivity(Announcement); if (target) { this.checkCan('minigame', null, room); if (target === 'clear') { if (!announcement.endTimer()) return this.errorReply(this.tr`There is no timer to clear.`); return this.add(this.tr`The announcement timer was turned off.`); } const timeoutMins = parseFloat(target); if (isNaN(timeoutMins) || timeoutMins <= 0 || timeoutMins > 7 * 24 * 60) { return this.errorReply(this.tr`Time should be a number of minutes less than one week.`); } announcement.setTimer({ timeoutMins }); room.add(`The announcement timer was turned on: the announcement will end in ${timeoutMins} minute${Chat.plural(timeoutMins)}.`); this.modlog('ANNOUNCEMENT TIMER', null, `${timeoutMins} minutes`); return this.privateModAction(`The announcement timer was set to ${timeoutMins} minute${Chat.plural(timeoutMins)} by ${user.name}.`); } else { if (!this.runBroadcast()) return; if (announcement.timeout) { return this.sendReply(`The announcement timer is on and will end in ${announcement.timeoutMins} minute${Chat.plural(announcement.timeoutMins)}.`); } else { return this.sendReply(this.tr`The announcement timer is off.`); } } }, timerhelp: [ `/announcement timer [minutes] - Sets the announcement to automatically end after [minutes] minutes. Requires: % @ # ~`, `/announcement timer clear - Clears the announcement's timer. Requires: % @ # ~`, ], close: 'end', stop: 'end', end(target, room, user) { room = this.requireRoom(); this.checkCan('minigame', null, room); this.checkChat(); const announcement = this.requireMinorActivity(Announcement); announcement.end(room); this.modlog('ANNOUNCEMENT END'); this.privateModAction(room.tr`The announcement was ended by ${user.name}.`); }, endhelp: [`/announcement end - Ends a announcement and displays the results. Requires: % @ # ~`], show: '', display: '', ''(target, room, user, connection) { room = this.requireRoom(); const announcement = this.requireMinorActivity(Announcement); if (!this.runBroadcast()) return; room.update(); if (this.broadcasting) { announcement.display(); } else { announcement.displayTo(user, connection); } }, displayhelp: [`/announcement display - Displays the announcement`], }, announcementhelp: [ `/announcement allows rooms to run their own announcements. These announcements are limited to one announcement at a time per room.`, `Accepts the following commands:`, `/announcement create [announcement] - Creates a announcement. Requires: % @ # ~`, `/announcement htmlcreate [announcement] - Creates a announcement, with HTML allowed. Requires: # ~`, `/announcement edit [announcement] - Edits the announcement. Requires: % @ # ~`, `/announcement htmledit [announcement] - Edits the announcement, with HTML allowed. Requires: # ~`, `/announcement timer [minutes] - Sets the announcement to automatically end after [minutes]. Requires: % @ # ~`, `/announcement display - Displays the announcement`, `/announcement end - Ends a announcement. Requires: % @ # ~`, ], }; process.nextTick(() => { Chat.multiLinePattern.register('/announcement (new|create|htmlcreate|edit|htmledit) '); }); // should handle restarts and also hotpatches for (const room of Rooms.rooms.values()) { if (room.settings.minorActivity?.activityid === 'announcement') { room.setMinorActivity(new Announcement(room, room.settings.minorActivity), true); } }