"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var room_settings_exports = {};
__export(room_settings_exports, {
RoomSections: () => RoomSections,
commands: () => commands,
pages: () => pages,
roomSettings: () => roomSettings,
sections: () => sections
});
module.exports = __toCommonJS(room_settings_exports);
var import_lib = require("../../lib");
/**
* Room settings commands
* Pokemon Showdown - http://pokemonshowdown.com/
*
* Commands for settings relating to room setting filtering.
*
* @license MIT
*/
const RANKS = Config.groupsranking;
const SLOWCHAT_MINIMUM = 2;
const SLOWCHAT_MAXIMUM = 60;
const SLOWCHAT_USER_REQUIREMENT = 10;
const sections = [
"official",
"battleformats",
"languages",
"entertainment",
"gaming",
"lifehobbies",
"onsitegames"
];
const RoomSections = {
sectionNames: {
official: "Official",
battleformats: "Battle formats",
languages: "Languages",
entertainment: "Entertainment",
gaming: "Gaming",
lifehobbies: "Life & hobbies",
onsitegames: "On-site games"
},
sections
};
const commands = {
roomsetting: "roomsettings",
roomsettings(target, room, user, connection) {
room = this.requireRoom();
if (room.battle)
return this.errorReply("This command cannot be used in battle rooms.");
let uhtml = "uhtml";
if (!target) {
room.update();
} else {
void this.parse(`/${target}`);
uhtml = "uhtmlchange";
}
let output = import_lib.Utils.html`
Room Settings for ${room.title} `;
for (const handler of Chat.roomSettings) {
const setting = handler(room, user, connection);
if (typeof setting.permission === "string")
setting.permission = user.can(setting.permission, null, room);
output += `${setting.label}: `;
for (const option of setting.options) {
if (option[1] === true) {
output += import_lib.Utils.html` `;
} else {
if (!setting.permission)
continue;
output += import_lib.Utils.html` `;
}
}
output += ` `;
}
output += "
";
user.sendTo(room, `|${uhtml}|roomsettings|${output}`);
},
roomsettingshelp: [`/roomsettings - Shows current room settings with buttons to change them (if you can).`],
modchat(target, room, user) {
room = this.requireRoom();
if (!target) {
const modchatSetting = room.settings.modchat || "OFF";
return this.sendReply(`Moderated chat is currently set to: ${modchatSetting}`);
}
if (user.locked) {
return this.errorReply(`/modchat - Access denied.`);
} else {
this.checkCan("modchat", null, room);
}
if (room.settings.modchat && room.settings.modchat.length <= 1 && !room.auth.atLeast(user, room.settings.modchat) && // Upper Staff should probably be able to set /modchat & in secret rooms
!user.can("bypassall")) {
return this.errorReply(`/modchat - Access denied for changing a setting currently at ${room.settings.modchat}.`);
}
if (room.requestModchat) {
const error = room.requestModchat(user);
if (error)
return this.errorReply(error);
}
if (room.battle?.forcedSettings.modchat && !user.can("rangeban")) {
return this.errorReply(
`This battle is required to have modchat on due to one of the players having a username that starts with ${room.battle.forcedSettings.modchat}.`
);
}
target = target.toLowerCase().trim();
const currentModchat = room.settings.modchat;
switch (target) {
case "off":
case "false":
case "no":
case "disable":
room.settings.modchat = null;
break;
case "ac":
case "autoconfirmed":
room.settings.modchat = "autoconfirmed";
break;
case "trusted":
room.settings.modchat = "trusted";
break;
case "player":
target = Users.PLAYER_SYMBOL;
default:
if (!Users.Auth.isAuthLevel(target) || ["\u203D", "!"].includes(target)) {
this.errorReply(`The rank '${target}' was unrecognized as a modchat level.`);
return this.parse("/help modchat");
}
const modchatLevelHigherThanUserRank = !room.auth.atLeast(user, target) && !user.can("bypassall");
if (modchatLevelHigherThanUserRank || !Users.Auth.hasPermission(user, "modchat", target, room)) {
return this.errorReply(`/modchat - Access denied for setting to ${target}.`);
}
room.settings.modchat = target;
break;
}
if (currentModchat === room.settings.modchat) {
return this.errorReply(`Modchat is already set to ${currentModchat || "off"}.`);
}
if (!room.settings.modchat) {
this.add('|raw|
Moderated chat was set to ${modchatSetting}! Only users of rank ${modchatSetting} and higher can talk.
`);
}
if (room.requestModchat && !room.settings.modchat)
room.requestModchat(null);
this.privateModAction(`${user.name} set modchat to ${room.settings.modchat || "off"}`);
this.modlog("MODCHAT", null, `to ${room.settings.modchat || "false"}`);
room.saveSettings();
},
modchathelp: [
`/modchat [off/autoconfirmed/trusted/+/%/@/*/player/#/&] - Set the level of moderated chat. Requires: % \u2606 for off/autoconfirmed/+ options, * @ # & for all the options`
],
automodchat(target, room, user) {
room = this.requireRoom();
if (!target) {
if (!room.settings.autoModchat)
return this.sendReply(`This room has automodchat OFF.`);
const { rank: curRank, time: curTime } = room.settings.autoModchat;
return this.sendReply(`Automodchat is currently set to set modchat to ${curRank} after ${curTime} minutes.`);
}
this.checkCan("declare", null, room);
if (this.meansNo(toID(target))) {
if (!room.settings.autoModchat)
return this.errorReply(`Auto modchat is not set.`);
delete room.settings.autoModchat;
room.saveSettings();
if (room.modchatTimer)
clearTimeout(room.modchatTimer);
this.privateModAction(`${user.name} turned off automatic modchat.`);
return this.modlog(`AUTOMODCHAT`, null, "OFF");
}
let [rawTime, rank] = import_lib.Utils.splitFirst(target, ",").map((i) => i.trim());
if (!rawTime) {
return this.parse(`/help automodchat`);
}
if (!rank) {
if (room.settings.autoModchat) {
rank = room.settings.autoModchat.rank;
} else {
return this.parse(`/help automodchat`);
}
}
const validGroups = [...Config.groupsranking, "trusted"];
if (!validGroups.includes(rank)) {
return this.errorReply(`Invalid rank.`);
}
const time = parseInt(rawTime);
if (isNaN(time) || time > 480 || time < 5) {
return this.errorReply("Invalid duration. Choose a number under 480 (in minutes) and over 5 minutes.");
}
room.settings.autoModchat = {
rank,
time,
active: false
};
this.privateModAction(`${user.name} set automodchat to rank ${rank} and timeout ${time} minutes.`);
this.modlog(`AUTOMODCHAT`, null, `${rank}: ${time} minutes`);
room.saveSettings();
},
automodchathelp: [
`/automodchat [number], [rank] - Sets modchat [rank] to automatically turn on after [number] minutes with no staff.`,
`[number] must be between 5 and 480. Requires: # &`,
`/automodchat off - Turns off automodchat.`
],
ionext() {
this.errorReply(`"ionext" is an outdated feature. Hidden battles now have password-protected URLs, making them fully secure against eavesdroppers.`);
this.errorReply(`You probably want to switch from /ionext to /hidenext, and from /ioo to /hideroom`);
},
ioo() {
this.errorReply(`"ioo" is an outdated feature. Hidden battles now have password-protected URLs, making them fully secure against eavesdroppers.`);
this.errorReply(`You probably want to switch from /ioo to /hideroom`);
},
inviteonlynext(target, room, user) {
const groupConfig = Config.groups[Users.PLAYER_SYMBOL];
if (!groupConfig?.editprivacy)
return this.errorReply(`/ionext - Access denied.`);
if (this.meansNo(target)) {
user.battleSettings.inviteOnly = false;
user.update();
this.sendReply("Your next battle will be publicly visible.");
} else {
user.battleSettings.inviteOnly = true;
user.update();
this.sendReply(`Your next battle will be invite-only${Rooms.RoomBattle.battleForcedSetting(user, "privacy") ? `, unless it is rated` : ``}.`);
}
},
inviteonlynexthelp: [
`/inviteonlynext - Sets your next battle to be invite-only.`,
`/inviteonlynext off - Sets your next battle to be publicly visible.`
],
inviteonly(target, room, user, connection, cmd) {
room = this.requireRoom();
if (!target)
return this.parse("/help inviteonly");
if (this.meansYes(target)) {
return this.parse("/modjoin %");
} else {
return this.parse(`/modjoin ${target}`);
}
},
inviteonlyhelp: [
`/inviteonly [on|off] - Sets modjoin %. Users can't join unless invited with /invite. Requires: # &`,
`/ioo - Shortcut for /inviteonly on`,
`/inviteonlynext OR /ionext - Sets your next battle to be invite-only.`,
`/ionext off - Sets your next battle to be publicly visible.`
],
modjoin(target, room, user) {
room = this.requireRoom();
if (!target) {
const modjoinSetting = room.settings.modjoin === true ? "SYNC" : room.settings.modjoin || "OFF";
return this.sendReply(`Modjoin is currently set to: ${modjoinSetting}`);
}
if (room.battle) {
this.checkCan("editprivacy", null, room);
if (room.battle.forcedSettings.privacy) {
return this.errorReply(
`This battle is required to be public due to a player having a name prefixed by '${room.battle.forcedSettings.privacy}'.`
);
}
if (room.battle.inviteOnlySetter && !user.can("mute", null, room) && room.battle.inviteOnlySetter !== user.id) {
return this.errorReply(`Only the person who set this battle to be invite-only can turn it off.`);
}
room.battle.inviteOnlySetter = user.id;
} else if (room.settings.isPersonal) {
this.checkCan("editroom", null, room);
} else {
this.checkCan("makeroom");
}
if (room.tour && !room.tour.allowModjoin) {
return this.errorReply(`You can't do this in tournaments where modjoin is prohibited.`);
}
if (target === "player")
target = Users.PLAYER_SYMBOL;
if (this.meansNo(target)) {
if (!room.settings.modjoin)
return this.errorReply(`Modjoin is already turned off in this room.`);
room.settings.modjoin = null;
this.add(`|raw|
This room is no longer invite only! Anyone may now join.
`);
this.addModAction(`${user.name} turned off modjoin.`);
this.modlog("MODJOIN", null, "OFF");
if (room.battle)
room.battle.inviteOnlySetter = null;
room.saveSettings();
return;
} else if (target === "sync") {
if (room.settings.modjoin === true)
return this.errorReply(`Modjoin is already set to sync modchat in this room.`);
room.settings.modjoin = true;
this.add(`|raw|
Moderated join is set to sync with modchat! Only users who can speak in modchat can join.
`);
this.addModAction(`${user.name} set modjoin to sync with modchat.`);
this.modlog("MODJOIN SYNC");
} else if (target === "ac" || target === "autoconfirmed") {
if (room.settings.modjoin === "autoconfirmed")
return this.errorReply(`Modjoin is already set to autoconfirmed.`);
room.settings.modjoin = "autoconfirmed";
this.add(`|raw|
Moderated join is set to autoconfirmed! Users must be rank autoconfirmed or invited with /invite to join
`);
this.addModAction(`${user.name} set modjoin to autoconfirmed.`);
this.modlog("MODJOIN", null, "autoconfirmed");
} else if (Users.Auth.isAuthLevel(target) && !["\u203D", "!"].includes(target)) {
if (room.battle && !user.can("makeroom") && !"+%".includes(target)) {
return this.errorReply(`/modjoin - Access denied from setting modjoin past % in battles.`);
}
if (room.settings.isPersonal && !user.can("makeroom") && !"+%".includes(target)) {
return this.errorReply(`/modjoin - Access denied from setting modjoin past % in group chats.`);
}
if (room.settings.modjoin === target)
return this.errorReply(`Modjoin is already set to ${target} in this room.`);
room.settings.modjoin = target;
this.add(`|raw|
This room is now invite only! Users must be rank ${target} or invited with /invite to join
`);
this.addModAction(`${user.name} set modjoin to ${target}.`);
this.modlog("MODJOIN", null, target);
} else {
this.errorReply(`Unrecognized modjoin setting.`);
void this.parse("/help modjoin");
return false;
}
room.saveSettings();
if (target === "sync" && !room.settings.modchat) {
const lowestGroup = Config.groupsranking.filter((group) => {
const groupInfo = Users.Auth.getGroup(group);
return groupInfo.symbol !== Users.Auth.defaultSymbol() && room.auth.atLeast(user, group) && Users.Auth.isValidSymbol(groupInfo.symbol);
})[0];
if (lowestGroup)
void this.parse(`/modchat ${lowestGroup}`);
}
if (!room.settings.isPrivate)
return this.parse("/hiddenroom");
},
modjoinhelp: [
`/modjoin [+|%|@|*|player|&|#|off] - Sets modjoin. Users lower than the specified rank can't join this room unless they have a room rank. Requires: \u2606 # &`,
`/modjoin [sync|off] - Sets modjoin. Only users who can speak in modchat can join this room. Requires: \u2606 # &`
],
roomlanguage(target, room, user) {
room = this.requireRoom();
if (!target) {
return this.sendReply(`This room's primary language is ${Chat.languages.get(room.settings.language || "") || "English"}`);
}
this.checkCan("editroom", null, room);
const targetLanguage = toID(target);
if (!Chat.languages.has(targetLanguage))
return this.errorReply(`"${target}" is not a supported language.`);
room.settings.language = targetLanguage === "english" ? false : targetLanguage;
room.saveSettings();
this.modlog(`LANGUAGE`, null, Chat.languages.get(targetLanguage));
this.sendReply(`The room's language has been set to ${Chat.languages.get(targetLanguage)}`);
},
roomlanguagehelp: [
`/roomlanguage [language] - Sets the the language for the room, which changes language of a few commands. Requires # &`,
`Supported Languages: English, Spanish, Italian, French, Simplified Chinese, Traditional Chinese, Japanese, Hindi, Turkish, Dutch, German.`
],
slowchat(target, room, user) {
room = this.requireRoom();
if (!target) {
const slowchatSetting2 = room.settings.slowchat || "OFF";
return this.sendReply(`Slow chat is currently set to: ${slowchatSetting2}`);
}
this.checkChat();
this.checkCan("modchat", null, room);
let targetInt = parseInt(target);
if (this.meansNo(target)) {
if (!room.settings.slowchat)
return this.errorReply(`Slow chat is already disabled in this room.`);
room.settings.slowchat = false;
} else if (targetInt) {
if (!user.can("bypassall") && room.userCount < SLOWCHAT_USER_REQUIREMENT) {
return this.errorReply(`This room must have at least ${SLOWCHAT_USER_REQUIREMENT} users to set slowchat; it only has ${room.userCount} right now.`);
}
if (room.settings.slowchat === targetInt) {
return this.errorReply(`Slow chat is already set to ${room.settings.slowchat} seconds in this room.`);
}
if (targetInt < SLOWCHAT_MINIMUM)
targetInt = SLOWCHAT_MINIMUM;
if (targetInt > SLOWCHAT_MAXIMUM)
targetInt = SLOWCHAT_MAXIMUM;
room.settings.slowchat = targetInt;
} else {
return this.parse("/help slowchat");
}
const slowchatSetting = room.settings.slowchat || "OFF";
this.privateModAction(`${user.name} set slowchat to ${slowchatSetting}`);
this.modlog("SLOWCHAT", null, "" + slowchatSetting);
room.saveSettings();
},
slowchathelp: [
`/slowchat [number] - Sets a limit on how often users in the room can send messages, between 2 and 60 seconds. Requires @ # &`,
`/slowchat off - Disables slowchat in the room. Requires @ # &`
],
permission: "permissions",
permissions: {
clear: "set",
set(target, room, user) {
let [perm, rank] = this.splitOne(target);
room = this.requireRoom();
if (rank === "default")
rank = "";
if (!room.persist)
return this.errorReply(`This room does not allow customizing permissions.`);
if (!target || !perm)
return this.parse(`/permissions help`);
if (rank && rank !== "whitelist" && !Config.groupsranking.includes(rank)) {
return this.errorReply(`${rank} is not a valid rank.`);
}
const validPerms = Users.Auth.supportedRoomPermissions(room);
if (!validPerms.some((p) => p === perm || p.startsWith(`${perm} `))) {
return this.errorReply(`${perm} is not a valid room permission.`);
}
if (!room.auth.atLeast(user, "#")) {
return this.errorReply(`/permissions set - You must be at least a Room Owner to set permissions.`);
}
if (Users.Auth.ROOM_PERMISSIONS.includes(perm) && !Users.Auth.hasPermission(user, perm, null, room)) {
return this.errorReply(`/permissions set - You can't set the permission "${perm}" because you don't have it.`);
}
const currentPermissions = room.settings.permissions || {};
if (currentPermissions[perm] === (rank || void 0)) {
return this.errorReply(`${perm} is already set to ${rank || "default"}.`);
}
if (rank) {
currentPermissions[perm] = rank;
room.settings.permissions = currentPermissions;
} else {
delete currentPermissions[perm];
if (!Object.keys(currentPermissions).length)
delete room.settings.permissions;
}
room.saveSettings();
if (!rank)
rank = `default`;
this.modlog(`SETPERMISSION`, null, `${perm}: ${rank}`);
this.refreshPage(`permissions-${room.roomid}`);
return this.privateModAction(`${user.name} set the required rank for ${perm} to ${rank}.`);
},
sethelp: [
`/permissions set [command], [rank symbol] - sets the required permission to use the command [command] to [rank]. Requires: # &`,
`/permissions clear [command] - resets the required permission to use the command [command] to the default. Requires: # &`
],
view(target, room, user) {
room = this.requireRoom();
return this.parse(`/join view-permissions-${room.roomid}`);
},
help: "",
""(target, room, user) {
room = this.requireRoom();
const allPermissions = Users.Auth.supportedRoomPermissions(room);
const permissionGroups = allPermissions.filter((perm) => !perm.startsWith("/"));
const permissions = allPermissions.filter((perm) => {
const handler = Chat.parseCommand(perm)?.handler;
if (handler?.isPrivate && !user.can("lock"))
return false;
return perm.startsWith("/") && !perm.includes(" ");
});
const subPermissions = allPermissions.filter((perm) => perm.startsWith("/") && perm.includes(" ")).filter((perm) => {
const handler = Chat.parseCommand(perm)?.handler;
if (handler?.isPrivate && !user.can("lock"))
return false;
return perm.startsWith("/") && perm.includes(" ");
});
const subPermissionsByNamespace = {};
for (const perm of subPermissions) {
const [namespace] = perm.split(" ", 1);
if (!subPermissionsByNamespace[namespace])
subPermissionsByNamespace[namespace] = [];
subPermissionsByNamespace[namespace].push(perm);
}
let buffer = `Room permissions help:`;
buffer += `
Groupchats are temporary rooms, and will expire if there hasn't been any activity in 40 minutes.
You can invite new users using /invite. Be careful with who you invite!
Commands: | |
As creator of this groupchat, you are entirely responsible for what occurs in this chatroom. Global rules apply at all times.
If this room is used to break global rules or disrupt other areas of the server, you as the creator will be held accountable and punished.
`
});
if (!targetRoom) {
return this.errorReply(`An unknown error occurred while trying to create the room '${title}'.`);
}
targetRoom.auth.set(user.id, parent ? "#" : Users.HOST_SYMBOL);
user.joinRoom(targetRoom.roomid);
user.popup(`You've just made a groupchat; it is now your responsibility, regardless of whether or not you actively partake in the room. For more info, read your groupchat's staff intro.`);
if (parent)
this.modlog("SUBROOMGROUPCHAT", null, title);
},
makegroupchathelp: [
`/makegroupchat [roomname] - Creates an invite-only group chat named [roomname].`,
`/subroomgroupchat [roomname] - Creates a subroom groupchat of the current room. Can only be used in a public room you have staff in.`,
`Only users who are staff in a public room or global auth can make groupchats.`
],
groupchatuptime: "roomuptime",
roomuptime(target, room, user, connection, cmd) {
if (!this.runBroadcast())
return;
if (!room)
return this.errorReply(`Can only be used in a room.`);
if (!room.settings.creationTime)
room.settings.creationTime = Date.now();
const uptime = Chat.toDurationString(Date.now() - room.settings.creationTime);
this.sendReplyBox(`Room uptime: ${uptime}`);
},
roomuptimehelp: [`/roomuptime - Displays the uptime of the room.`],
deregisterchatroom(target, room, user) {
this.checkCan("makeroom");
this.errorReply("NOTE: You probably want to use `/deleteroom` now that it exists.");
const id = toID(target);
if (!id)
return this.parse("/help deregisterchatroom");
const targetRoom = Rooms.search(id);
if (!targetRoom)
return this.errorReply(`The room '${target}' doesn't exist.`);
target = targetRoom.title || targetRoom.roomid;
const isPrivate = targetRoom.settings.isPrivate;
const staffRoom = Rooms.get("staff");
const upperStaffRoom = Rooms.get("upperstaff");
if (Rooms.global.deregisterChatRoom(id)) {
this.sendReply(`The room '${target}' was deregistered.`);
this.sendReply("It will be deleted as of the next server restart.");
target = import_lib.Utils.escapeHTML(target);
if (isPrivate) {
if (upperStaffRoom) {
upperStaffRoom.add(`|raw|
Private chat room deregistered by ${user.id}: ${target}
`).update();
}
} else {
if (staffRoom) {
staffRoom.add(`|raw|
Public chat room deregistered: ${target}
`).update();
}
if (upperStaffRoom) {
upperStaffRoom.add(`|raw|
Public chat room deregistered by ${user.id}: ${target}
`).update();
}
}
return;
}
return this.errorReply(`The room "${target}" isn't registered.`);
},
deregisterchatroomhelp: [
`/deregisterchatroom [roomname] - Deletes room [roomname] after the next server restart. Requires: &`
],
deletechatroom: "deleteroom",
deletegroupchat: "deleteroom",
dgc: "deleteroom",
deleteroom(target, room, user, connection, cmd) {
room = this.requireRoom();
const roomid = target.trim();
if (!roomid) {
if (!room.settings.isPersonal || !["deletegroupchat", "dgc"].includes(cmd)) {
return this.parse(`/help deleteroom`);
}
} else {
const targetRoom = Rooms.search(roomid);
if (targetRoom !== room) {
return this.parse(`/help deleteroom`);
}
}
if (room.roomid.startsWith("groupchat-")) {
this.checkCan("gamemanagement", null, room);
} else {
this.checkCan("makeroom");
}
const title = room.title || room.roomid;
if (room.persist) {
if (room.settings.isPrivate) {
const upperStaffRoom = Rooms.get("upperstaff");
if (upperStaffRoom) {
upperStaffRoom.add(
import_lib.Utils.html`|raw|
Private chat room ` + `deleted by ${user.id}: ${title}
Public chat ` + `room deleted by ${user.id}: ${title}
`
).update();
}
}
}
room.add(`|raw|
This room has been deleted.
`);
room.update();
room.send(`|expire|This room has been deleted.`);
room.destroy();
},
deleteroomhelp: [
`/deleteroom [roomname] - Deletes room [roomname]. Must be typed in the room to delete. Requires: &`,
`/deletegroupchat - Deletes the current room, if it's a groupchat. Requires: \u2605 # &`
],
rename() {
this.errorReply("Did you mean /renameroom?");
},
renamegroupchat: "renameroom",
renameroom(target, room, user, connection, cmd) {
room = this.requireRoom();
if (room.game || room.minorActivity || room.tour) {
return this.errorReply("Cannot rename room while a tour/poll/game is running.");
}
if (room.battle) {
return this.errorReply("Cannot rename battle rooms.");
}
const oldTitle = room.title;
const isGroupchat = cmd === "renamegroupchat";
if (!toID(target))
return this.parse("/help renameroom");
if (room.persist && isGroupchat)
return this.errorReply(`This isn't a groupchat.`);
if (!room.persist && !isGroupchat)
return this.errorReply(`Use /renamegroupchat instead.`);
if (isGroupchat) {
if (!user.can("lock"))
this.checkCan("declare", null, room);
const existingRoom = Rooms.search(toID(target));
if (existingRoom && !existingRoom.settings.modjoin) {
return this.errorReply(`Your groupchat name is too similar to existing chat room '${existingRoom.title}'.`);
}
if (this.filter(target) !== target) {
return this.errorReply("Invalid title.");
}
if (target.includes(",") || target.includes("|") || target.includes("[") || target.includes("-")) {
return this.errorReply("Room titles can't contain any of: ,|[-");
}
target = `[G] ${target}`;
} else {
this.checkCan("makeroom");
}
const creatorID = room.roomid.split("-")[1];
const id = isGroupchat ? `groupchat-${creatorID}-${toID(target)}` : void 0;
const oldID = room.roomid;
room.rename(target, id);
Chat.handleRoomRename(oldID, id || toID(target), room);
this.modlog(`RENAME${isGroupchat ? "GROUPCHAT" : "ROOM"}`, null, `from ${oldTitle}`);
const privacy = room.settings.isPrivate === true ? "Private" : !room.settings.isPrivate ? "Public" : `${room.settings.isPrivate.charAt(0).toUpperCase()}${room.settings.isPrivate.slice(1)}`;
if (!isGroupchat) {
Rooms.global.notifyRooms(
room.settings.isPrivate === true ? ["upperstaff"] : ["upperstaff", "staff"],
import_lib.Utils.html`|raw|
${privacy} chat room ${oldTitle} renamed to ${target}
`
);
}
room.add(import_lib.Utils.html`|raw|
The room has been renamed to ${target}
`).update();
},
renameroomhelp: [`/renameroom [new title] - Renames the current room to [new title]. Case-sensitive. Requires &`],
hideroom: "privateroom",
hiddenroom: "privateroom",
secretroom: "privateroom",
publicroom: "privateroom",
unlistroom: "privateroom",
privateroom(target, room, user, connection, cmd) {
room = this.requireRoom();
if (room.battle) {
this.checkCan("editprivacy", null, room);
if (room.battle.forcedSettings.privacy) {
return this.errorReply(`This battle is required to be public because a player has a name prefixed by '${room.battle.forcedSettings.privacy}'.`);
}
if (room.tour?.forcePublic) {
return this.errorReply(`This battle can't be hidden, because the tournament is set to be forced public.`);
}
} else if (room.settings.isPersonal) {
this.checkCan("editroom", null, room);
} else {
this.checkCan("makeroom");
}
let setting;
switch (cmd) {
case "privateroom":
return this.parse("/help privateroom");
case "publicroom":
setting = false;
break;
case "secretroom":
this.checkCan("rangeban");
setting = true;
break;
case "unlistroom":
this.checkCan("rangeban");
setting = "unlisted";
break;
default:
if (room.settings.isPrivate === true && target !== "force") {
return this.sendReply(`This room is a secret room. Use "/publicroom" to make it public, or "/hiddenroom force" to force it hidden.`);
}
setting = "hidden";
break;
}
if (this.meansNo(target)) {
return this.errorReply(`Please specify what privacy setting you want for this room: /hiddenroom, /secretroom, or /publicroom`);
}
if (!setting) {
if (!room.settings.isPrivate) {
return this.errorReply(`This room is already public.`);
}
if (room.parent && room.parent.settings.isPrivate) {
return this.errorReply(`This room's parent ${room.parent.title} must be public for this room to be public.`);
}
if (room.settings.isPersonal && !room.battle) {
return this.errorReply(`This room can't be made public.`);
}
if (room.privacySetter && user.can("nooverride", null, room) && !user.can("makeroom")) {
if (!room.privacySetter.has(user.id)) {
const privacySetters = [...room.privacySetter].join(", ");
return this.errorReply(`You can't make the room public since you didn't make it private - only ${privacySetters} can.`);
}
room.privacySetter.delete(user.id);
if (room.privacySetter.size) {
const privacySetters = [...room.privacySetter].join(", ");
return this.sendReply(`You are no longer forcing the room to stay private, but ${privacySetters} also need${Chat.plural(room.privacySetter, "", "s")} to use /publicroom to make the room public.`);
}
}
room.privacySetter = null;
this.addModAction(`${user.name} made this room public.`);
this.modlog("PUBLICROOM");
room.setPrivate(false);
} else {
const settingName = setting === true ? "secret" : setting;
if (room.subRooms) {
if (settingName === "secret")
return this.errorReply("Secret rooms cannot have subrooms.");
for (const subRoom of room.subRooms.values()) {
if (!subRoom.settings.isPrivate) {
return this.errorReply(`Subroom ${subRoom.title} must be private to make this room private.`);
}
}
}
if (room.settings.isPrivate === setting) {
if (room.privacySetter && !room.privacySetter.has(user.id)) {
room.privacySetter.add(user.id);
return this.sendReply(`This room is already ${settingName}, but is now forced to stay that way until you use /publicroom.`);
}
return this.errorReply(`This room is already ${settingName}.`);
}
this.addModAction(`${user.name} made this room ${settingName}.`);
this.modlog(`${settingName.toUpperCase()}ROOM`);
if (!room.settings.isPersonal && !room.battle)
room.setSection();
room.setPrivate(setting);
room.privacySetter = /* @__PURE__ */ new Set([user.id]);
}
},
privateroomhelp: [
`/secretroom - Makes a room secret. Secret rooms are visible to & and up. Requires: &`,
`/hiddenroom [on/off] - Makes a room hidden. Hidden rooms are visible to % and up, and inherit global ranks. Requires: \u2606 &`,
`/publicroom - Makes a room public. Requires: \u2606 &`
],
hidenext(target, room, user) {
const groupConfig = Config.groups[Users.PLAYER_SYMBOL];
if (!groupConfig?.editprivacy)
return this.errorReply(`/hidenext - Access denied.`);
if (this.meansNo(target)) {
user.battleSettings.hidden = false;
user.update();
this.sendReply("Your next battle will be publicly visible.");
} else {
user.battleSettings.hidden = true;
user.update();
this.sendReply(`Your next battle will be hidden${Rooms.RoomBattle.battleForcedSetting(user, "privacy") ? `, unless it is rated` : ``}.`);
}
},
hidenexthelp: [
`/hidenext - Sets your next battle to be hidden.`,
`/hidenext off - Sets your next battle to be publicly visible.`
],
officialchatroom: "officialroom",
officialroom() {
this.parse(`/setroomsection official`);
},
roomspotlight(target, room, user) {
this.checkCan("makeroom");
room = this.requireRoom();
if (!target)
return this.parse(`/help roomspotlight`);
if (!room.persist) {
return this.errorReply(`/roomspotlight - You can't spotlight this room.`);
}
if (this.meansNo(target)) {
if (!room.settings.spotlight)
return this.errorReply(`This chatroom is not being spotlighted.`);
this.addModAction(`${user.name} removed this chatroom from the spotlight.`);
this.globalModlog("UNSPOTLIGHT");
delete room.settings.spotlight;
room.saveSettings();
} else {
if (room.settings.spotlight === target)
return this.errorReply("This chat room is already spotlighted.");
this.addModAction(`${user.name} spotlighted this room with the message "${target}".`);
this.globalModlog("SPOTLIGHT");
room.settings.spotlight = target;
room.saveSettings();
}
},
roomspotlighthelp: [
`/roomspotlight [spotlight] - Makes the room this command is used in a spotlight room for the [spotlight] category on the roomlist. Requires: &`,
`/roomspotlight off - Removes the room this command is used in from the list of spotlight rooms. Requires: &`
],
setsubroom: "subroom",
subroom(target, room, user) {
room = this.requireRoom();
if (!user.can("makeroom"))
return this.errorReply(`/subroom - Access denied. Did you mean /subrooms?`);
if (!target)
return this.parse("/help subroom");
if (!room.persist)
return this.errorReply(`Temporary rooms cannot be subrooms.`);
if (room.parent) {
return this.errorReply(`This room is already a subroom. To change which room this subroom belongs to, remove the subroom first.`);
}
if (room.subRooms) {
return this.errorReply(`This room is already a parent room, and a parent room cannot be made as a subroom.`);
}
const parent = Rooms.search(target);
if (!parent)
return this.errorReply(`The room '${target}' does not exist.`);
if (parent.type !== "chat")
return this.errorReply(`Parent room '${target}' must be a chat room.`);
if (parent.parent)
return this.errorReply(`Subrooms cannot have subrooms.`);
if (parent.settings.isPrivate === true)
return this.errorReply(`Only public and hidden rooms can have subrooms.`);
if (parent.settings.isPrivate && !room.settings.isPrivate) {
return this.errorReply(`Private rooms cannot have public subrooms.`);
}
if (!parent.persist)
return this.errorReply(`Temporary rooms cannot be parent rooms.`);
if (room === parent)
return this.errorReply(`You cannot set a room to be a subroom of itself.`);
const settingsList = Rooms.global.settingsList;
const parentIndex = settingsList.findIndex((r) => r.title === parent.title);
const index = settingsList.findIndex((r) => r.title === room.title);
if (parentIndex > index) {
[settingsList[parentIndex], settingsList[index]] = [settingsList[index], settingsList[parentIndex]];
}
room.setParent(parent);
this.modlog("SUBROOM", null, `of ${parent.title}`);
return this.addModAction(`This room was set as a subroom of ${parent.title} by ${user.name}.`);
},
removesubroom: "unsubroom",
desubroom: "unsubroom",
unsubroom(target, room, user) {
room = this.requireRoom();
this.checkCan("makeroom");
if (!room.parent || !room.persist) {
return this.errorReply(`This room is not currently a subroom of a public room.`);
}
room.setParent(null);
this.modlog("UNSUBROOM");
return this.addModAction(`This room was unset as a subroom by ${user.name}.`);
},
unsubroomhelp: [`/unsubroom - Unmarks the current room as a subroom. Requires: &`],
parentroom: "subrooms",
subrooms(target, room, user, connection, cmd) {
room = this.requireRoom();
if (cmd === "parentroom") {
if (!room.parent)
return this.errorReply(`This room is not a subroom.`);
return this.sendReply(`This is a subroom of ${room.parent.title}.`);
}
if (!room.persist)
return this.errorReply(`Temporary rooms cannot have subrooms.`);
if (!this.runBroadcast())
return;
const showSecret = !this.broadcasting && user.can("mute", null, room);
const subRooms = room.getSubRooms(showSecret);
if (!subRooms.length)
return this.sendReply(`This room doesn't have any subrooms.`);
const subRoomText = subRooms.map(
(subRoom) => import_lib.Utils.html`${subRoom.title} ${subRoom.settings.desc}`
);
return this.sendReplyBox(`
`);
},
subroomhelp: [
`/subroom [room] - Marks the current room as a subroom of [room]. Requires: &`,
`/unsubroom - Unmarks the current room as a subroom. Requires: &`,
`/subrooms - Displays the current room's subrooms.`,
`/parentroom - Displays the current room's parent room.`
],
roomdesc(target, room, user) {
room = this.requireRoom();
if (!target) {
if (!this.runBroadcast())
return;
if (!room.settings.desc)
return this.sendReply(`This room does not have a description set.`);
this.sendReplyBox(import_lib.Utils.html`The room description is: ${room.settings.desc}`);
return;
}
this.checkCan("makeroom");
if (target.length > 80) {
return this.errorReply(`Error: Room description is too long (must be at most 80 characters).`);
}
const normalizedTarget = " " + target.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim() + " ";
if (normalizedTarget.includes(" welcome ")) {
return this.errorReply(`Error: Room description must not contain the word "welcome".`);
}
if (normalizedTarget.startsWith(" discuss ")) {
return this.errorReply(`Error: Room description must not start with the word "discuss".`);
}
if (normalizedTarget.startsWith(" talk about ") || normalizedTarget.startsWith(" talk here about ")) {
return this.errorReply(`Error: Room description must not start with the phrase "talk about".`);
}
room.settings.desc = target;
this.sendReply(`(The room description is now: ${target})`);
this.privateModAction(`${user.name} changed the roomdesc to: "${target}".`);
this.modlog("ROOMDESC", null, `to "${target}"`);
room.saveSettings();
},
roomdeschelp: [`/roomdesc [description] - Sets the [description] of the current room. Requires: &`],
topic: "roomintro",
roomintro(target, room, user, connection, cmd) {
room = this.requireRoom();
if (!target) {
if (!this.runBroadcast())
return;
if (!room.settings.introMessage)
return this.sendReply("This room does not have an introduction set.");
this.sendReply('|raw|
");
if (!this.broadcasting && user.can("declare", null, room, "roomintro") && cmd !== "topic") {
const code = import_lib.Utils.escapeHTML(room.settings.introMessage).replace(/\n/g, " ");
this.sendReplyBox(`Source:/roomintro ${code}`);
}
return;
}
this.checkCan("editroom", null, room);
if (this.meansNo(target) || target === "delete")
return this.errorReply('Did you mean "/deleteroomintro"?');
this.checkHTML(target);
if (!target.includes("<")) {
const re = /(https?:\/\/(([\w.-]+)+(:\d+)?(\/([\w/_.]*(\?\S+)?)?)?))/g;
target = target.replace(re, '$1');
}
if (target.substr(0, 11) === "/roomintro ")
target = target.substr(11);
room.settings.introMessage = target.replace(/\r/g, "");
this.sendReply("(The room introduction has been changed to:)");
this.sendReply(`|raw|
${room.settings.introMessage.replace(/\n/g, "")}
`);
this.privateModAction(`${user.name} changed the roomintro.`);
this.modlog("ROOMINTRO");
this.roomlog(room.settings.introMessage.replace(/\n/g, ""));
room.saveSettings();
},
roomintrohelp: [
`/roomintro - Display the room introduction of the current room.`,
`/roomintro [content] - Set an introduction for the room. Requires: # &`
],
deletetopic: "deleteroomintro",
deleteroomintro(target, room, user) {
room = this.requireRoom();
this.checkCan("declare", null, room);
if (!room.settings.introMessage)
return this.errorReply("This room does not have a introduction set.");
this.privateModAction(`${user.name} deleted the roomintro.`);
this.modlog("DELETEROOMINTRO");
this.roomlog(target);
delete room.settings.introMessage;
room.saveSettings();
},
deleteroomintrohelp: [`/deleteroomintro - Deletes the current room's introduction. Requires: # &`],
stafftopic: "staffintro",
staffintro(target, room, user, connection, cmd) {
room = this.requireRoom();
if (!target) {
this.checkCan("mute", null, room);
if (!room.settings.staffMessage)
return this.sendReply("This room does not have a staff introduction set.");
this.sendReply(`|raw|
${room.settings.staffMessage.replace(/\n/g, ``)}
`);
if (user.can("ban", null, room, "staffintro") && cmd !== "stafftopic") {
const code = import_lib.Utils.escapeHTML(room.settings.staffMessage).replace(/\n/g, " ");
this.sendReplyBox(`Source:/staffintro ${code}`);
}
return;
}
this.checkCan("ban", null, room);
this.checkChat();
if (this.meansNo(target) || target === "delete")
return this.errorReply('Did you mean "/deletestaffintro"?');
this.checkHTML(target);
if (!target.includes("<")) {
const re = /(https?:\/\/(([\w.-]+)+(:\d+)?(\/([\w/_.]*(\?\S+)?)?)?))/g;
target = target.replace(re, '$1');
}
if (target.substr(0, 12) === "/staffintro ")
target = target.substr(12);
room.settings.staffMessage = target.replace(/\r/g, "");
this.sendReply("(The staff introduction has been changed to:)");
this.sendReply(`|raw|
${target.replace(/\n/g, ``)}
`);
this.privateModAction(`${user.name} changed the staffintro.`);
this.modlog("STAFFINTRO");
this.roomlog(room.settings.staffMessage.replace(/\n/g, ``));
room.saveSettings();
},
staffintrohelp: [`/staffintro [content] - Set an introduction for staff members. Requires: @ # &`],
deletestafftopic: "deletestaffintro",
deletestaffintro(target, room, user) {
room = this.requireRoom();
this.checkCan("ban", null, room);
if (!room.settings.staffMessage)
return this.errorReply("This room does not have a staff introduction set.");
this.privateModAction(`${user.name} deleted the staffintro.`);
this.modlog("DELETESTAFFINTRO");
this.roomlog(target);
delete room.settings.staffMessage;
room.saveSettings();
},
deletestaffintrohelp: [`/deletestaffintro - Deletes the current room's staff introduction. Requires: @ # &`],
roomalias(target, room, user) {
room = this.requireRoom();
if (!target) {
if (!this.runBroadcast())
return;
if (!room.settings.aliases)
return this.sendReplyBox("This room does not have any aliases.");
return this.sendReplyBox(`This room has the following aliases: ${room.settings.aliases.join(", ")}`);
}
this.checkCan("makeroom");
if (target.includes(",")) {
this.errorReply(`Invalid room alias: ${target.trim()}`);
return this.parse("/help roomalias");
}
const alias = toID(target);
if (!alias.length)
return this.errorReply("Only alphanumeric characters are valid in an alias.");
if (Rooms.get(alias) || Rooms.aliases.has(alias)) {
return this.errorReply("You cannot set an alias to an existing room or alias.");
}
if (room.settings.isPersonal)
return this.errorReply("Personal rooms can't have aliases.");
Rooms.aliases.set(alias, room.roomid);
this.privateModAction(`${user.name} added the room alias '${alias}'.`);
this.modlog("ROOMALIAS", null, alias);
if (!room.settings.aliases)
room.settings.aliases = [];
room.settings.aliases.push(alias);
room.saveSettings();
},
roomaliashelp: [
`/roomalias - displays a list of all room aliases of the room the command was entered in.`,
`/roomalias [alias] - adds the given room alias to the room the command was entered in. Requires: &`,
`/removeroomalias [alias] - removes the given room alias of the room the command was entered in. Requires: &`
],
deleteroomalias: "removeroomalias",
deroomalias: "removeroomalias",
unroomalias: "removeroomalias",
removeroomalias(target, room, user) {
room = this.requireRoom();
if (!room.settings.aliases)
return this.errorReply("This room does not have any aliases.");
this.checkCan("makeroom");
if (target.includes(",")) {
this.errorReply(`Invalid room alias: ${target.trim()}`);
return this.parse("/help removeroomalias");
}
const alias = toID(target);
if (!alias || !Rooms.aliases.has(alias))
return this.errorReply("Please specify an existing alias.");
if (Rooms.aliases.get(alias) !== room.roomid) {
return this.errorReply("You may only remove an alias from the current room.");
}
this.privateModAction(`${user.name} removed the room alias '${alias}'.`);
this.modlog("REMOVEALIAS", null, alias);
const aliasIndex = room.settings.aliases.indexOf(alias);
if (aliasIndex >= 0) {
room.settings.aliases.splice(aliasIndex, 1);
if (!room.settings.aliases.length)
room.settings.aliases = void 0;
Rooms.aliases.delete(alias);
room.saveSettings();
}
},
removeroomaliashelp: [
`/removeroomalias [alias] - removes the given room alias of the room the command was entered in. Requires: &`
],
resettierdisplay: "roomtierdisplay",
roomtierdisplay(target, room, user, connection, cmd) {
room = this.requireRoom();
const resetTier = cmd === "resettierdisplay";
if (!target) {
if (!this.runBroadcast())
return;
return this.sendReplyBox(
`This room is currently displaying ${room.settings.dataCommandTierDisplay} as the tier when using /data.`
);
}
this.checkCan("declare", null, room);
const displayIDToName = {
tiers: "tiers",
doublestiers: "doubles tiers",
nationaldextiers: "National Dex tiers",
numbers: "numbers"
};
if (!resetTier) {
if (!(toID(target) in displayIDToName)) {
this.errorReply(`Invalid tier display: ${target.trim()}`);
return this.parse(`/help roomtierdisplay`);
}
room.settings.dataCommandTierDisplay = displayIDToName[toID(target)];
this.sendReply(`(The room's tier display is now: ${displayIDToName[toID(target)]})`);
this.privateModAction(`${user.name} changed the room's tier display to: ${displayIDToName[toID(target)]}.`);
this.modlog("ROOMTIERDISPLAY", null, `to ${displayIDToName[toID(target)]}`);
} else {
room.settings.dataCommandTierDisplay = "tiers";
this.sendReply(`(The room's tier display is now: tiers)`);
this.privateModAction(`${user.name} reset the room's tier display.`);
this.modlog("RESETTIERDISPLAY", null, `to tiers`);
}
room.saveSettings();
},
roomtierdisplayhelp: [
`/roomtierdisplay - displays the current room's display.`,
`/roomtierdisplay [option] - changes the current room's tier display. Valid options are: tiers, doubles tiers, numbers. Requires: # &`,
`/resettierdisplay - resets the current room's tier display. Requires: # &`
],
setroomsection: "roomsection",
roomsection(target, room, user) {
room = this.requireRoom();
const sectionNames = RoomSections.sectionNames;
if (!target) {
if (!this.runBroadcast())
return;
this.sendReplyBox(import_lib.Utils.html`This room is ${room.settings.section ? `in the ${sectionNames[room.settings.section]} section` : `not in a section`}.`);
return;
}
this.checkCan("gdeclare");
const section = room.setSection(target);
this.sendReply(`The room section is now: ${section ? sectionNames[section] : "none"}`);
this.privateGlobalModAction(`${user.name} changed the room section of ${room.title} to ${section ? sectionNames[section] : "none"}.`);
this.globalModlog("ROOMSECTION", null, section || "none");
},
roomsectionhelp: [
`/roomsection [section] - Sets the room this is used in to the specified [section]. Requires: &`,
`Valid sections: ${sections.join(", ")}`
],
roomdefaultformat(target, room, user) {
room = this.requireRoom();
this.checkCan("editroom", null, room);
if (!target) {
this.checkBroadcast();
if (room.settings.defaultFormat) {
this.sendReply(`This room's default format is ${room.settings.defaultFormat}.`);
} else {
this.sendReply(`This room has no default format.`);
}
return;
}
if (this.meansNo(target)) {
delete room.settings.defaultFormat;
room.saveSettings();
this.modlog(`DEFAULTFORMAT`, null, "off");
this.privateModAction(`${user.name} removed this room's default format.`);
return;
}
target = toID(target);
const format = Dex.formats.get(target);
if (format.exists) {
target = format.name;
}
const { isMatch } = this.extractFormat(target);
if (!isMatch)
throw new Chat.ErrorMessage(`Unrecognized format or mod "${target}"`);
room.settings.defaultFormat = target;
room.saveSettings();
this.modlog(`DEFAULTFORMAT`, null, target);
this.privateModAction(`${user.name} set this room's default format to ${target}.`);
},
roomdefaultformathelp: [
`/roomdefaultformat [format] or [mod] or gen[number] - Sets this room's default format/mod. Requires: # &`,
`/roomdefaultformat off - Clears this room's default format/mod. Requires: # &`,
`Affected commands: /details, /coverage, /effectiveness, /weakness, /learn`
]
};
const roomSettings = [
// modchat
(room, user) => ({
label: "Modchat",
permission: "modchat",
options: [
"off",
"autoconfirmed",
"trusted",
...RANKS.slice(1).filter((symbol) => Users.Auth.hasPermission(user, "modchat", symbol, room))
].map((rank) => [rank, rank === (room.settings.modchat || "off") || `modchat ${rank || "off"}`])
}),
(room, user) => ({
label: "Modjoin",
permission: room.settings.isPersonal ? user.can("editroom", null, room) : user.can("makeroom"),
options: [
"off",
"autoconfirmed",
// groupchat ROs can set modjoin, but only to +
// first rank is for modjoin off
...RANKS.slice(1, room.settings.isPersonal && !user.can("makeroom") ? 2 : void 0)
].map((rank) => [rank, rank === (room.settings.modjoin || "off") || `modjoin ${rank || "off"}`])
}),
(room) => ({
label: "Language",
permission: "editroom",
options: [...Chat.languages].map(
([id, name]) => [name, id === (room.settings.language || "english") || `roomlanguage ${id || "off"}`]
)
}),
(room) => ({
label: "Stretch filter",
permission: "editroom",
options: [
[`off`, !room.settings.filterStretching || "stretchfilter off"],
[`on`, room.settings.filterStretching || "stretchfilter on"]
]
}),
(room) => ({
label: "Caps filter",
permission: "editroom",
options: [
[`off`, !room.settings.filterCaps || "capsfilter off"],
[`on`, room.settings.filterCaps || "capsfilter on"]
]
}),
(room) => ({
label: "Emoji filter",
permission: "editroom",
options: [
[`off`, !room.settings.filterEmojis || "emojifilter off"],
[`on`, room.settings.filterEmojis || "emojifilter on"]
]
}),
(room) => ({
label: "Link filter",
permission: "editroom",
options: [
[`off`, !room.settings.filterLinks || "linkfilter off"],
[`on`, room.settings.filterLinks || "linkfilter on"]
]
}),
(room) => ({
label: "Slowchat",
permission: room.userCount < SLOWCHAT_USER_REQUIREMENT ? "bypassall" : "editroom",
options: ["off", 5, 10, 20, 30, 60].map(
(time) => [`${time}`, time === (room.settings.slowchat || "off") || `slowchat ${time || "off"}`]
)
}),
(room) => ({
label: "/data Tier display",
permission: "editroom",
options: [
[`tiers`, (room.settings.dataCommandTierDisplay ?? "tiers") === "tiers" || `roomtierdisplay tiers`],
[`doubles tiers`, room.settings.dataCommandTierDisplay === "doubles tiers" || `roomtierdisplay doubles tiers`],
[
`National Dex tiers`,
room.settings.dataCommandTierDisplay === "National Dex tiers" || `roomtierdisplay National Dex tiers`
],
[`numbers`, room.settings.dataCommandTierDisplay === "numbers" || `roomtierdisplay numbers`]
]
}),
(room) => ({
label: "/requestshow",
permission: "declare",
options: [
[`off`, !room.settings.requestShowEnabled || `showapprovals off`],
[`on`, room.settings.requestShowEnabled || `showapprovals on`]
]
})
];
const pages = {
permissions(args, user, connection) {
this.title = `[Permissions]`;
const room = this.requireRoom();
this.checkCan("mute", null, room);
const roomGroups = ["default", ...Config.groupsranking.slice(1)];
const permissions = room.settings.permissions || {};
let buf = `
Command permissions for ${room.title}
`;
buf += `
`;
buf += `
Permission
Required rank
`;
let atLeastOne = false;
for (const permission in permissions) {
const requiredRank = permissions[permission];
atLeastOne = true;
buf += `