mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-03-21 17:25:10 -05:00
Use Chat.ErrorMessage instead of errorReply in more places (#11017)
This commit is contained in:
parent
40f4915925
commit
9ff1398c69
|
|
@ -126,11 +126,11 @@ export const commands: Chat.ChatCommands = {
|
|||
this.canUseConsole();
|
||||
const species = Dex.species.get(target);
|
||||
if (species.id === Config.potd) {
|
||||
return this.errorReply(`The PotD is already set to ${species.name}`);
|
||||
throw new Chat.ErrorMessage(`The PotD is already set to ${species.name}`);
|
||||
}
|
||||
if (!species.exists) return this.errorReply(`Pokemon "${target}" not found.`);
|
||||
if (!species.exists) throw new Chat.ErrorMessage(`Pokemon "${target}" not found.`);
|
||||
if (!Dex.species.getFullLearnset(species.id).length) {
|
||||
return this.errorReply(`That Pokemon has no learnset and cannot be used as the PotD.`);
|
||||
throw new Chat.ErrorMessage(`That Pokemon has no learnset and cannot be used as the PotD.`);
|
||||
}
|
||||
Config.potd = species.id;
|
||||
for (const process of Rooms.PM.processes) {
|
||||
|
|
@ -188,7 +188,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse('/help ' + cmd);
|
||||
this.checkChat();
|
||||
let [rank, html] = this.splitOne(target);
|
||||
if (!(rank in Config.groups)) return this.errorReply(`Group '${rank}' does not exist.`);
|
||||
if (!(rank in Config.groups)) throw new Chat.ErrorMessage(`Group '${rank}' does not exist.`);
|
||||
html = this.checkHTML(html);
|
||||
this.checkCan('addhtml', null, room);
|
||||
html = Chat.collapseLineBreaksHTML(html);
|
||||
|
|
@ -235,7 +235,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkChat();
|
||||
|
||||
const [rank, uhtml] = this.splitOne(target);
|
||||
if (!(rank in Config.groups)) return this.errorReply(`Group '${rank}' does not exist.`);
|
||||
if (!(rank in Config.groups)) throw new Chat.ErrorMessage(`Group '${rank}' does not exist.`);
|
||||
let [name, html] = this.splitOne(uhtml);
|
||||
name = toID(name);
|
||||
html = this.checkHTML(html);
|
||||
|
|
@ -267,12 +267,12 @@ export const commands: Chat.ChatCommands = {
|
|||
if (cmd.startsWith('d')) {
|
||||
source = '';
|
||||
} else if (!source || source.length > 18) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`Specify a source username to take the color from. Name must be <19 characters.`
|
||||
);
|
||||
}
|
||||
if (!userid || userid.length > 18) {
|
||||
return this.errorReply(`Specify a valid name to set a new color for. Names must be <19 characters.`);
|
||||
throw new Chat.ErrorMessage(`Specify a valid name to set a new color for. Names must be <19 characters.`);
|
||||
}
|
||||
const [res, error] = await LoginServer.request('updatenamecolor', {
|
||||
userid,
|
||||
|
|
@ -280,10 +280,10 @@ export const commands: Chat.ChatCommands = {
|
|||
by: user.id,
|
||||
});
|
||||
if (error) {
|
||||
return this.errorReply(error.message);
|
||||
throw new Chat.ErrorMessage(error.message);
|
||||
}
|
||||
if (!res || res.actionerror) {
|
||||
return this.errorReply(res?.actionerror || "The loginserver is currently disabled.");
|
||||
throw new Chat.ErrorMessage(res?.actionerror || "The loginserver is currently disabled.");
|
||||
}
|
||||
if (source) {
|
||||
return this.sendReply(
|
||||
|
|
@ -602,7 +602,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.canUseConsole();
|
||||
|
||||
if (Monitor.updateServerLock) {
|
||||
return this.errorReply("Wait for /updateserver to finish before hotpatching.");
|
||||
throw new Chat.ErrorMessage("Wait for /updateserver to finish before hotpatching.");
|
||||
}
|
||||
|
||||
await this.parse(`/rebuild`);
|
||||
|
|
@ -617,10 +617,10 @@ export const commands: Chat.ChatCommands = {
|
|||
Utils.clearRequireCache({ exclude: ['/lib/process-manager'] });
|
||||
if (target === 'all') {
|
||||
if (lock['all']) {
|
||||
return this.errorReply(`Hot-patching all has been disabled by ${lock['all'].by} (${lock['all'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching all has been disabled by ${lock['all'].by} (${lock['all'].reason})`);
|
||||
}
|
||||
if (Config.disablehotpatchall) {
|
||||
return this.errorReply("This server does not allow for the use of /hotpatch all");
|
||||
throw new Chat.ErrorMessage("This server does not allow for the use of /hotpatch all");
|
||||
}
|
||||
|
||||
for (const hotpatch of hotpatches) {
|
||||
|
|
@ -628,19 +628,21 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
} else if (target === 'chat' || target === 'commands') {
|
||||
if (lock['tournaments']) {
|
||||
return this.errorReply(`Hot-patching tournaments has been disabled by ${lock['tournaments'].by} (${lock['tournaments'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching tournaments has been disabled by ${lock['tournaments'].by} (${lock['tournaments'].reason})`);
|
||||
}
|
||||
if (lock['chat']) {
|
||||
return this.errorReply(`Hot-patching chat has been disabled by ${lock['chat'].by} (${lock['chat'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching chat has been disabled by ${lock['chat'].by} (${lock['chat'].reason})`);
|
||||
}
|
||||
|
||||
this.sendReply("Hotpatching chat commands...");
|
||||
|
||||
const disabledCommands = Chat.allCommands().filter(c => c.disabled).map(c => `/${c.fullCmd}`);
|
||||
if (cmd !== 'forcehotpatch' && disabledCommands.length) {
|
||||
this.errorReply(`${Chat.count(disabledCommands.length, "commands")} are disabled right now.`);
|
||||
this.errorReply(`Hotpatching will enable them. Use /forcehotpatch chat if you're sure.`);
|
||||
return this.errorReply(`Currently disabled: ${disabledCommands.join(', ')}`);
|
||||
throw new Chat.ErrorMessage([
|
||||
`${Chat.count(disabledCommands.length, "commands")} are disabled right now.`,
|
||||
`Hotpatching will enable them. Use /forcehotpatch chat if you're sure.`,
|
||||
`Currently disabled: ${disabledCommands.join(', ')}`,
|
||||
]);
|
||||
}
|
||||
|
||||
const oldPlugins = Chat.plugins;
|
||||
|
|
@ -662,7 +664,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.sendReply("DONE");
|
||||
} else if (target === 'processmanager') {
|
||||
if (lock['processmanager']) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`Hot-patching formats has been disabled by ${lock['processmanager'].by} ` +
|
||||
`(${lock['processmanager'].reason})`
|
||||
);
|
||||
|
|
@ -700,7 +702,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.sendReply('DONE');
|
||||
} else if (target === 'usersp' || target === 'roomsp') {
|
||||
if (lock[target]) {
|
||||
return this.errorReply(`Hot-patching ${target} has been disabled by ${lock[target].by} (${lock[target].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching ${target} has been disabled by ${lock[target].by} (${lock[target].reason})`);
|
||||
}
|
||||
let newProto: any, oldProto: any, message: string;
|
||||
switch (target) {
|
||||
|
|
@ -752,7 +754,7 @@ export const commands: Chat.ChatCommands = {
|
|||
);
|
||||
} else if (target === 'tournaments') {
|
||||
if (lock['tournaments']) {
|
||||
return this.errorReply(`Hot-patching tournaments has been disabled by ${lock['tournaments'].by} (${lock['tournaments'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching tournaments has been disabled by ${lock['tournaments'].by} (${lock['tournaments'].reason})`);
|
||||
}
|
||||
this.sendReply("Hotpatching tournaments...");
|
||||
|
||||
|
|
@ -761,13 +763,13 @@ export const commands: Chat.ChatCommands = {
|
|||
this.sendReply("DONE");
|
||||
} else if (target === 'formats' || target === 'battles') {
|
||||
if (lock['formats']) {
|
||||
return this.errorReply(`Hot-patching formats has been disabled by ${lock['formats'].by} (${lock['formats'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching formats has been disabled by ${lock['formats'].by} (${lock['formats'].reason})`);
|
||||
}
|
||||
if (lock['battles']) {
|
||||
return this.errorReply(`Hot-patching battles has been disabled by ${lock['battles'].by} (${lock['battles'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching battles has been disabled by ${lock['battles'].by} (${lock['battles'].reason})`);
|
||||
}
|
||||
if (lock['validator']) {
|
||||
return this.errorReply(`Hot-patching the validator has been disabled by ${lock['validator'].by} (${lock['validator'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching the validator has been disabled by ${lock['validator'].by} (${lock['validator'].reason})`);
|
||||
}
|
||||
this.sendReply("Hotpatching formats...");
|
||||
|
||||
|
|
@ -793,10 +795,10 @@ export const commands: Chat.ChatCommands = {
|
|||
this.sendReply("DONE. New login server requests will use the new code.");
|
||||
} else if (target === 'learnsets' || target === 'validator') {
|
||||
if (lock['validator']) {
|
||||
return this.errorReply(`Hot-patching the validator has been disabled by ${lock['validator'].by} (${lock['validator'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching the validator has been disabled by ${lock['validator'].by} (${lock['validator'].reason})`);
|
||||
}
|
||||
if (lock['formats']) {
|
||||
return this.errorReply(`Hot-patching formats has been disabled by ${lock['formats'].by} (${lock['formats'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching formats has been disabled by ${lock['formats'].by} (${lock['formats'].reason})`);
|
||||
}
|
||||
|
||||
this.sendReply("Hotpatching validator...");
|
||||
|
|
@ -806,7 +808,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.sendReply("DONE. Any battles started after now will have teams be validated according to the new code.");
|
||||
} else if (target === 'punishments') {
|
||||
if (lock['punishments']) {
|
||||
return this.errorReply(`Hot-patching punishments has been disabled by ${lock['punishments'].by} (${lock['punishments'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching punishments has been disabled by ${lock['punishments'].by} (${lock['punishments'].reason})`);
|
||||
}
|
||||
|
||||
this.sendReply("Hotpatching punishments...");
|
||||
|
|
@ -820,7 +822,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.sendReply("DONE");
|
||||
} else if (target === 'modlog') {
|
||||
if (lock['modlog']) {
|
||||
return this.errorReply(`Hot-patching modlogs has been disabled by ${lock['modlog'].by} (${lock['modlog'].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching modlogs has been disabled by ${lock['modlog'].by} (${lock['modlog'].reason})`);
|
||||
}
|
||||
this.sendReply("Hotpatching modlog...");
|
||||
|
||||
|
|
@ -840,14 +842,14 @@ export const commands: Chat.ChatCommands = {
|
|||
this.sendReply("Disabling hot-patch has been moved to its own command:");
|
||||
return this.parse('/help nohotpatch');
|
||||
} else {
|
||||
return this.errorReply("Your hot-patch command was unrecognized.");
|
||||
throw new Chat.ErrorMessage("Your hot-patch command was unrecognized.");
|
||||
}
|
||||
} catch (e: any) {
|
||||
Rooms.global.notifyRooms(
|
||||
['development', 'staff'] as RoomID[],
|
||||
`|c|${user.getIdentity()}|/log ${user.name} used /hotpatch ${target} - but something failed while trying to hot-patch.`
|
||||
);
|
||||
return this.errorReply(`Something failed while trying to hot-patch ${target}: \n${e.stack}`);
|
||||
throw new Chat.ErrorMessage([`Something failed while trying to hot-patch ${target}:`, e.stack]);
|
||||
}
|
||||
Rooms.global.notifyRooms(
|
||||
['development', 'staff'] as RoomID[],
|
||||
|
|
@ -890,18 +892,18 @@ export const commands: Chat.ChatCommands = {
|
|||
];
|
||||
|
||||
if (!validDisable.includes(hotpatch)) {
|
||||
return this.errorReply(`Disabling hotpatching "${hotpatch}" is not supported.`);
|
||||
throw new Chat.ErrorMessage(`Disabling hotpatching "${hotpatch}" is not supported.`);
|
||||
}
|
||||
const enable = ['allowhotpatch', 'yeshotpatch'].includes(cmd);
|
||||
|
||||
if (enable) {
|
||||
if (!lock[hotpatch]) return this.errorReply(`Hot-patching ${hotpatch} is not disabled.`);
|
||||
if (!lock[hotpatch]) throw new Chat.ErrorMessage(`Hot-patching ${hotpatch} is not disabled.`);
|
||||
|
||||
delete lock[hotpatch];
|
||||
this.sendReply(`You have enabled hot-patching ${hotpatch}.`);
|
||||
} else {
|
||||
if (lock[hotpatch]) {
|
||||
return this.errorReply(`Hot-patching ${hotpatch} has already been disabled by ${lock[hotpatch].by} (${lock[hotpatch].reason})`);
|
||||
throw new Chat.ErrorMessage(`Hot-patching ${hotpatch} has already been disabled by ${lock[hotpatch].by} (${lock[hotpatch].reason})`);
|
||||
}
|
||||
lock[hotpatch] = {
|
||||
by: user.name,
|
||||
|
|
@ -1051,14 +1053,14 @@ export const commands: Chat.ChatCommands = {
|
|||
if (['!', '/'].some(c => target.startsWith(c))) target = target.slice(1);
|
||||
const parsed = Chat.parseCommand(`/${target}`);
|
||||
if (!parsed) {
|
||||
return this.errorReply(`Command "/${target}" is in an invalid format.`);
|
||||
throw new Chat.ErrorMessage(`Command "/${target}" is in an invalid format.`);
|
||||
}
|
||||
const { handler, fullCmd } = parsed;
|
||||
if (!handler) {
|
||||
return this.errorReply(`Command "/${target}" not found.`);
|
||||
throw new Chat.ErrorMessage(`Command "/${target}" not found.`);
|
||||
}
|
||||
if (handler.disabled) {
|
||||
return this.errorReply(`Command "/${target}" is already disabled`);
|
||||
throw new Chat.ErrorMessage(`Command "/${target}" is already disabled`);
|
||||
}
|
||||
handler.disabled = true;
|
||||
this.addGlobalModAction(`${user.name} disabled the command /${fullCmd}.`);
|
||||
|
|
@ -1075,7 +1077,7 @@ export const commands: Chat.ChatCommands = {
|
|||
disableladder(target, room, user) {
|
||||
this.checkCan('disableladder');
|
||||
if (Ladders.disabled) {
|
||||
return this.errorReply(`/disableladder - Ladder is already disabled.`);
|
||||
throw new Chat.ErrorMessage(`/disableladder - Ladder is already disabled.`);
|
||||
}
|
||||
|
||||
Ladders.disabled = true;
|
||||
|
|
@ -1101,7 +1103,7 @@ export const commands: Chat.ChatCommands = {
|
|||
enableladder(target, room, user) {
|
||||
this.checkCan('disableladder');
|
||||
if (!Ladders.disabled) {
|
||||
return this.errorReply(`/enable - Ladder is already enabled.`);
|
||||
throw new Chat.ErrorMessage(`/enable - Ladder is already enabled.`);
|
||||
}
|
||||
Ladders.disabled = false;
|
||||
|
||||
|
|
@ -1145,13 +1147,13 @@ export const commands: Chat.ChatCommands = {
|
|||
if (Config.autolockdown === undefined) Config.autolockdown = true;
|
||||
if (this.meansYes(target)) {
|
||||
if (Config.autolockdown) {
|
||||
return this.errorReply("The server is already set to automatically kill itself upon the final battle finishing.");
|
||||
throw new Chat.ErrorMessage("The server is already set to automatically kill itself upon the final battle finishing.");
|
||||
}
|
||||
Config.autolockdown = true;
|
||||
this.privateGlobalModAction(`${user.name} used /autolockdownkill on (autokill on final battle finishing)`);
|
||||
} else if (this.meansNo(target)) {
|
||||
if (!Config.autolockdown) {
|
||||
return this.errorReply("The server is already set to not automatically kill itself upon the final battle finishing.");
|
||||
throw new Chat.ErrorMessage("The server is already set to not automatically kill itself upon the final battle finishing.");
|
||||
}
|
||||
Config.autolockdown = false;
|
||||
this.privateGlobalModAction(`${user.name} used /autolockdownkill off (no autokill on final battle finishing)`);
|
||||
|
|
@ -1189,10 +1191,10 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('lockdown');
|
||||
|
||||
if (!Rooms.global.lockdown) {
|
||||
return this.errorReply("We're not under lockdown right now.");
|
||||
throw new Chat.ErrorMessage("We're not under lockdown right now.");
|
||||
}
|
||||
if (Rooms.global.lockdown !== true && cmd === 'crashfixed') {
|
||||
return this.errorReply('/crashfixed - There is no active crash.');
|
||||
throw new Chat.ErrorMessage('/crashfixed - There is no active crash.');
|
||||
}
|
||||
|
||||
const message = cmd === 'crashfixed' ?
|
||||
|
|
@ -1221,7 +1223,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('lockdown');
|
||||
|
||||
if (Config.emergency) {
|
||||
return this.errorReply("We're already in emergency mode.");
|
||||
throw new Chat.ErrorMessage("We're already in emergency mode.");
|
||||
}
|
||||
Config.emergency = true;
|
||||
for (const curRoom of Rooms.rooms.values()) {
|
||||
|
|
@ -1238,7 +1240,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('lockdown');
|
||||
|
||||
if (!Config.emergency) {
|
||||
return this.errorReply("We're not in emergency mode.");
|
||||
throw new Chat.ErrorMessage("We're not in emergency mode.");
|
||||
}
|
||||
Config.emergency = false;
|
||||
for (const curRoom of Rooms.rooms.values()) {
|
||||
|
|
@ -1255,7 +1257,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('lockdown');
|
||||
|
||||
if (!Rooms.global.lockdown) {
|
||||
return this.errorReply("The server is not under lockdown right now.");
|
||||
throw new Chat.ErrorMessage("The server is not under lockdown right now.");
|
||||
}
|
||||
|
||||
const battleRooms = [...Rooms.rooms.values()].filter(x => x.battle?.rated && !x.battle?.ended);
|
||||
|
|
@ -1288,11 +1290,11 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!Config.usepostgres) noSave = true;
|
||||
|
||||
if (Rooms.global.lockdown !== true && noSave) {
|
||||
return this.errorReply("For safety reasons, using /kill without saving battles can only be done during lockdown.");
|
||||
throw new Chat.ErrorMessage("For safety reasons, using /kill without saving battles can only be done during lockdown.");
|
||||
}
|
||||
|
||||
if (Monitor.updateServerLock) {
|
||||
return this.errorReply("Wait for /updateserver to finish before using /kill.");
|
||||
throw new Chat.ErrorMessage("Wait for /updateserver to finish before using /kill.");
|
||||
}
|
||||
|
||||
if (!noSave) {
|
||||
|
|
@ -1347,8 +1349,8 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('lockdown');
|
||||
if (user.lastCommand !== 'refreshpage') {
|
||||
user.lastCommand = 'refreshpage';
|
||||
this.errorReply(`Are you sure you wish to refresh the page for every user online?`);
|
||||
return this.errorReply(`If you are sure, please type /refreshpage again to confirm.`);
|
||||
throw new Chat.ErrorMessage([`Are you sure you wish to refresh the page for every user online?`,
|
||||
`If you are sure, please type /refreshpage again to confirm.`]);
|
||||
}
|
||||
Rooms.global.sendAll('|refresh|');
|
||||
this.stafflog(`${user.name} used /refreshpage`);
|
||||
|
|
@ -1360,7 +1362,7 @@ export const commands: Chat.ChatCommands = {
|
|||
async updateserver(target, room, user, connection) {
|
||||
this.canUseConsole();
|
||||
if (Monitor.updateServerLock) {
|
||||
return this.errorReply(`/updateserver - Another update is already in progress (or a previous update crashed).`);
|
||||
throw new Chat.ErrorMessage(`/updateserver - Another update is already in progress (or a previous update crashed).`);
|
||||
}
|
||||
|
||||
const validPrivateCodePath = Config.privatecodepath && path.isAbsolute(Config.privatecodepath);
|
||||
|
|
@ -1401,12 +1403,12 @@ export const commands: Chat.ChatCommands = {
|
|||
['staff', 'development'],
|
||||
`|c|${user.getIdentity()}|/log ${user.name} used /updateloginserver - but something failed while updating.`
|
||||
);
|
||||
return this.errorReply(`${err.message}\n${err.stack}`);
|
||||
throw new Chat.ErrorMessage([err.message, err.stack || '']);
|
||||
}
|
||||
if (!result) return this.errorReply('No result received.');
|
||||
if (!result) throw new Chat.ErrorMessage('No result received.');
|
||||
this.stafflog(`[o] ${result.success || ""} [e] ${result.actionerror || ""}`);
|
||||
if (result.actionerror) {
|
||||
return this.errorReply(result.actionerror);
|
||||
throw new Chat.ErrorMessage(result.actionerror);
|
||||
}
|
||||
let message = `${user.name} used /updateloginserver`;
|
||||
if (result.updated) {
|
||||
|
|
@ -1434,12 +1436,12 @@ export const commands: Chat.ChatCommands = {
|
|||
['staff', 'development'],
|
||||
`|c|${user.getIdentity()}|/log ${user.name} used /updateclient - but something failed while updating.`
|
||||
);
|
||||
return this.errorReply(`${err.message}\n${err.stack}`);
|
||||
throw new Chat.ErrorMessage([err.message, err.stack || '']);
|
||||
}
|
||||
if (!result) return this.errorReply('No result received.');
|
||||
if (!result) throw new Chat.ErrorMessage('No result received.');
|
||||
this.stafflog(`[o] ${result.success || ""} [e] ${result.actionerror || ""}`);
|
||||
if (result.actionerror) {
|
||||
return this.errorReply(result.actionerror);
|
||||
throw new Chat.ErrorMessage(result.actionerror);
|
||||
}
|
||||
let message = `${user.name} used /updateclient`;
|
||||
if (result.updated) {
|
||||
|
|
@ -1529,12 +1531,12 @@ export const commands: Chat.ChatCommands = {
|
|||
async evalsql(target, room) {
|
||||
this.canUseConsole();
|
||||
this.runBroadcast(true);
|
||||
if (!Config.usesqlite) return this.errorReply(`SQLite is disabled.`);
|
||||
if (!Config.usesqlite) throw new Chat.ErrorMessage(`SQLite is disabled.`);
|
||||
const logRoom = Rooms.get('upperstaff') || Rooms.get('staff');
|
||||
if (!target) return this.errorReply(`Specify a database to access and a query.`);
|
||||
if (!target) throw new Chat.ErrorMessage(`Specify a database to access and a query.`);
|
||||
const [db, query] = Utils.splitFirst(target, ',').map(item => item.trim());
|
||||
if (!FS('./databases').readdirSync().includes(`${db}.db`)) {
|
||||
return this.errorReply(`The database file ${db}.db was not found.`);
|
||||
throw new Chat.ErrorMessage(`The database file ${db}.db was not found.`);
|
||||
}
|
||||
if (room && this.message.startsWith('>>sql')) {
|
||||
this.broadcasting = true;
|
||||
|
|
@ -1613,7 +1615,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.canUseConsole();
|
||||
if (!this.runBroadcast(true)) return;
|
||||
if (!room.battle) {
|
||||
return this.errorReply("/evalbattle - This isn't a battle room.");
|
||||
throw new Chat.ErrorMessage("/evalbattle - This isn't a battle room.");
|
||||
}
|
||||
|
||||
void room.battle.stream.write(`>eval ${target.replace(/\n/g, '\f')}`);
|
||||
|
|
@ -1628,8 +1630,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('forcewin');
|
||||
if (!target) return this.parse('/help editbattle');
|
||||
if (!room.battle) {
|
||||
this.errorReply("/editbattle - This is not a battle room.");
|
||||
return false;
|
||||
throw new Chat.ErrorMessage("/editbattle - This is not a battle room.");
|
||||
}
|
||||
const battle = room.battle;
|
||||
let cmd;
|
||||
|
|
@ -1774,7 +1775,7 @@ export const pages: Chat.PageTable = {
|
|||
const [botid, ...pageArgs] = args;
|
||||
const pageid = pageArgs.join('-');
|
||||
if (pageid.length > 300) {
|
||||
return this.errorReply(`The page ID specified is too long.`);
|
||||
throw new Chat.ErrorMessage(`The page ID specified is too long.`);
|
||||
}
|
||||
const bot = Users.get(botid);
|
||||
if (!bot) {
|
||||
|
|
|
|||
|
|
@ -682,8 +682,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
if (!avatar) {
|
||||
if (silent) return false;
|
||||
this.errorReply("Unrecognized avatar - make sure you're on the right account?");
|
||||
return false;
|
||||
throw new Chat.ErrorMessage("Unrecognized avatar - make sure you're on the right account?");
|
||||
}
|
||||
|
||||
this.runBroadcast();
|
||||
|
|
@ -929,7 +928,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse(`/help moveavatars`);
|
||||
}
|
||||
if (!customAvatars[from]?.allowed.length) {
|
||||
return this.errorReply(`That user has no avatars.`);
|
||||
throw new Chat.ErrorMessage(`That user has no avatars.`);
|
||||
}
|
||||
const existing = customAvatars[to]?.allowed.filter(Boolean);
|
||||
customAvatars[to] = { ...customAvatars[from] };
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ export const commands: Chat.ChatCommands = {
|
|||
mee: 'me',
|
||||
me(target, room, user) {
|
||||
if (this.cmd === 'mee' && /[A-Z-a-z0-9/]/.test(target.charAt(0))) {
|
||||
return this.errorReply(this.tr`/mee - must not start with a letter or number`);
|
||||
throw new Chat.ErrorMessage(this.tr`/mee - must not start with a letter or number`);
|
||||
}
|
||||
target = this.checkChat(`/${this.cmd} ${target || ''}`);
|
||||
|
||||
|
|
@ -303,9 +303,9 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkRecursion();
|
||||
|
||||
const targetRoom = Rooms.search(targetId.trim());
|
||||
if (!targetRoom) return this.errorReply(`Room not found.`);
|
||||
if (!targetRoom) throw new Chat.ErrorMessage(`Room not found.`);
|
||||
if (message.trim().startsWith('/msgroom ')) {
|
||||
return this.errorReply(`Please do not nest /msgroom inside itself.`);
|
||||
throw new Chat.ErrorMessage(`Please do not nest /msgroom inside itself.`);
|
||||
}
|
||||
const subcontext = new Chat.CommandContext({ room: targetRoom, message, user, connection });
|
||||
await subcontext.parse();
|
||||
|
|
@ -316,7 +316,7 @@ export const commands: Chat.ChatCommands = {
|
|||
reply(target, room, user) {
|
||||
if (!target) return this.parse('/help reply');
|
||||
if (!user.lastPM) {
|
||||
return this.errorReply(this.tr`No one has PMed you yet.`);
|
||||
throw new Chat.ErrorMessage(this.tr`No one has PMed you yet.`);
|
||||
}
|
||||
return this.parse(`/msg ${user.lastPM || ''}, ${target}`);
|
||||
},
|
||||
|
|
@ -344,7 +344,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse(`/offlinemsg ${targetUsername},${message}`);
|
||||
}
|
||||
user.lastCommand = 'pm';
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
this.tr`User ${targetUsername} is offline. Send the message again to confirm. If you are using /msg, use /offlinemsg instead.`
|
||||
);
|
||||
}
|
||||
|
|
@ -364,11 +364,11 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse(`/offlinemsg ${targetUser.getLastId()},${message}`);
|
||||
}
|
||||
user.lastCommand = 'pm';
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
this.tr`User ${targetUsername} is offline. Send the message again to confirm. If you are using /msg, use /offlinemsg instead.`
|
||||
);
|
||||
}
|
||||
return this.errorReply(`${targetUsername} is offline.`);
|
||||
throw new Chat.ErrorMessage(`${targetUsername} is offline.`);
|
||||
}
|
||||
|
||||
return this.parse(message);
|
||||
|
|
@ -383,7 +383,7 @@ export const commands: Chat.ChatCommands = {
|
|||
target = target.trim();
|
||||
if (!target) return this.parse('/help offlinemsg');
|
||||
if (!Chat.PrivateMessages.offlineIsEnabled) {
|
||||
return this.errorReply(`Offline private messages have been disabled.`);
|
||||
throw new Chat.ErrorMessage(`Offline private messages have been disabled.`);
|
||||
}
|
||||
let [username, message] = Utils.splitFirst(target, ',').map(i => i.trim());
|
||||
const userid = toID(username);
|
||||
|
|
@ -392,12 +392,12 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse('/help offlinemsg');
|
||||
}
|
||||
if (Chat.parseCommand(message)) {
|
||||
return this.errorReply(`You cannot send commands in offline PMs.`);
|
||||
throw new Chat.ErrorMessage(`You cannot send commands in offline PMs.`);
|
||||
}
|
||||
if (userid === user.id) {
|
||||
return this.errorReply(`You cannot send offline PMs to yourself.`);
|
||||
throw new Chat.ErrorMessage(`You cannot send offline PMs to yourself.`);
|
||||
} else if (userid.startsWith('guest')) {
|
||||
return this.errorReply('You cannot send offline PMs to guests.');
|
||||
throw new Chat.ErrorMessage('You cannot send offline PMs to guests.');
|
||||
}
|
||||
if (Users.get(userid)?.connected) {
|
||||
this.sendReply(`That user is online, so a normal PM is being sent.`);
|
||||
|
|
@ -436,10 +436,10 @@ export const commands: Chat.ChatCommands = {
|
|||
targetRoom = room;
|
||||
}
|
||||
if (users.length > 1 && !user.trusted) {
|
||||
return this.errorReply("You do not have permission to mass-invite users.");
|
||||
throw new Chat.ErrorMessage("You do not have permission to mass-invite users.");
|
||||
}
|
||||
if (users.length > 10) {
|
||||
return this.errorReply("You cannot invite more than 10 users at once.");
|
||||
throw new Chat.ErrorMessage("You cannot invite more than 10 users at once.");
|
||||
}
|
||||
for (const toInvite of users) {
|
||||
this.parse(`/pm ${toInvite}, /invite ${targetRoom}`);
|
||||
|
|
@ -448,24 +448,24 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
|
||||
const targetRoom = Rooms.search(target);
|
||||
if (!targetRoom) return this.errorReply(this.tr`The room "${target}" was not found.`);
|
||||
if (!targetRoom) throw new Chat.ErrorMessage(this.tr`The room "${target}" was not found.`);
|
||||
|
||||
const invitesBlocked = pmTarget.settings.blockInvites;
|
||||
if (invitesBlocked) {
|
||||
if (invitesBlocked === true ? !user.can('lock') : !Users.globalAuth.atLeast(user, invitesBlocked as GroupSymbol)) {
|
||||
Chat.maybeNotifyBlocked('invite', pmTarget, user);
|
||||
return this.errorReply(`This user is currently blocking room invites.`);
|
||||
throw new Chat.ErrorMessage(`This user is currently blocking room invites.`);
|
||||
}
|
||||
}
|
||||
if (!targetRoom.checkModjoin(pmTarget)) {
|
||||
this.room = targetRoom;
|
||||
this.parse(`/roomvoice ${pmTarget.name}`);
|
||||
if (!targetRoom.checkModjoin(pmTarget)) {
|
||||
return this.errorReply(this.tr`You do not have permission to invite people into this room.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You do not have permission to invite people into this room.`);
|
||||
}
|
||||
}
|
||||
if (pmTarget.id in targetRoom.users) {
|
||||
return this.errorReply(this.tr`This user is already in "${targetRoom.title}".`);
|
||||
throw new Chat.ErrorMessage(this.tr`This user is already in "${targetRoom.title}".`);
|
||||
}
|
||||
return this.checkChat(`/invite ${targetRoom.roomid}`);
|
||||
},
|
||||
|
|
@ -487,7 +487,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const isOffline = cmd.includes('offline');
|
||||
const msg = isOffline ? `offline ` : ``;
|
||||
if (!isOffline && user.settings.blockPMs === (target || true)) {
|
||||
return this.errorReply(this.tr`You are already blocking ${msg}private messages! To unblock, use /unblockpms`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are already blocking ${msg}private messages! To unblock, use /unblockpms`);
|
||||
}
|
||||
if (Users.Auth.isAuthLevel(target)) {
|
||||
if (!isOffline) user.settings.blockPMs = target;
|
||||
|
|
@ -528,7 +528,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const isOffline = cmd.includes('offline');
|
||||
const msg = isOffline ? 'offline ' : '';
|
||||
if (isOffline ? !(await Chat.PrivateMessages.getSettings(user.id)) : !user.settings.blockPMs) {
|
||||
return this.errorReply(this.tr`You are not blocking ${msg}private messages! To block, use /blockpms`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are not blocking ${msg}private messages! To block, use /blockpms`);
|
||||
}
|
||||
if (isOffline) {
|
||||
await Chat.PrivateMessages.deleteSettings(user.id);
|
||||
|
|
@ -549,14 +549,14 @@ export const commands: Chat.ChatCommands = {
|
|||
const unblock = cmd.includes('unblock');
|
||||
if (unblock) {
|
||||
if (!user.settings.blockInvites) {
|
||||
return this.errorReply(`You are not blocking room invites! To block, use /blockinvites.`);
|
||||
throw new Chat.ErrorMessage(`You are not blocking room invites! To block, use /blockinvites.`);
|
||||
}
|
||||
user.settings.blockInvites = false;
|
||||
this.sendReply(`You are no longer blocking room invites.`);
|
||||
} else {
|
||||
if (toID(target) === 'ac') target = 'autoconfirmed';
|
||||
if (user.settings.blockInvites === (target || true)) {
|
||||
return this.errorReply("You are already blocking room invites - to unblock, use /unblockinvites");
|
||||
throw new Chat.ErrorMessage("You are already blocking room invites - to unblock, use /unblockinvites");
|
||||
}
|
||||
if (target in Config.groups) {
|
||||
user.settings.blockInvites = target as GroupSymbol;
|
||||
|
|
@ -579,16 +579,16 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
status(target, room, user, connection, cmd) {
|
||||
if (user.locked || user.semilocked) {
|
||||
return this.errorReply(this.tr`Your status cannot be updated while you are locked or semilocked.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Your status cannot be updated while you are locked or semilocked.`);
|
||||
}
|
||||
if (!target) return this.parse('/help status');
|
||||
|
||||
const maxLength = 70;
|
||||
if (target.length > maxLength) {
|
||||
return this.errorReply(this.tr`Your status is too long; it must be under ${maxLength} characters.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Your status is too long; it must be under ${maxLength} characters.`);
|
||||
}
|
||||
target = this.statusfilter(target);
|
||||
if (!target) return this.errorReply(this.tr`Your status contains a banned word.`);
|
||||
if (!target) throw new Chat.ErrorMessage(this.tr`Your status contains a banned word.`);
|
||||
|
||||
user.setUserMessage(target);
|
||||
this.sendReply(this.tr`Your status has been set to: ${target}.`);
|
||||
|
|
@ -648,7 +648,7 @@ export const commands: Chat.ChatCommands = {
|
|||
unaway: 'back',
|
||||
unafk: 'back',
|
||||
back(target, room, user) {
|
||||
if (user.statusType === 'online') return this.errorReply(this.tr`You are already marked as back.`);
|
||||
if (user.statusType === 'online') throw new Chat.ErrorMessage(this.tr`You are already marked as back.`);
|
||||
const statusType = user.statusType;
|
||||
user.setStatusType('online');
|
||||
|
||||
|
|
@ -693,19 +693,19 @@ export const commands: Chat.ChatCommands = {
|
|||
hiderank(target, room, user, connection, cmd) {
|
||||
const userGroup = Users.Auth.getGroup(Users.globalAuth.get(user.id));
|
||||
if (!userGroup['hiderank'] || !user.registered) {
|
||||
return this.errorReply(`/hiderank - Access denied.`);
|
||||
throw new Chat.ErrorMessage(`/hiderank - Access denied.`);
|
||||
}
|
||||
|
||||
const isShow = cmd === 'showrank';
|
||||
const group = (isShow ? Users.globalAuth.get(user.id) : (target.trim() || Users.Auth.defaultSymbol()) as GroupSymbol);
|
||||
if (user.tempGroup === group) {
|
||||
return this.errorReply(this.tr`You already have the temporary symbol '${group}'.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You already have the temporary symbol '${group}'.`);
|
||||
}
|
||||
if (!Users.Auth.isValidSymbol(group) || !(group in Config.groups)) {
|
||||
return this.errorReply(this.tr`You must specify a valid group symbol.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You must specify a valid group symbol.`);
|
||||
}
|
||||
if (!isShow && Config.groups[group].rank > Config.groups[user.tempGroup].rank) {
|
||||
return this.errorReply(this.tr`You may only set a temporary symbol below your current rank.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You may only set a temporary symbol below your current rank.`);
|
||||
}
|
||||
user.tempGroup = group;
|
||||
user.updateIdentity();
|
||||
|
|
@ -725,7 +725,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const languageID = toID(target);
|
||||
if (!Chat.languages.has(languageID)) {
|
||||
const languages = [...Chat.languages.values()].join(', ');
|
||||
return this.errorReply(this.tr`Valid languages are: ${languages}`);
|
||||
throw new Chat.ErrorMessage(this.tr`Valid languages are: ${languages}`);
|
||||
}
|
||||
user.language = languageID;
|
||||
user.update();
|
||||
|
|
@ -781,24 +781,24 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const battle = room.battle;
|
||||
if (!battle) {
|
||||
return this.errorReply(this.tr`Must be in a battle.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Must be in a battle.`);
|
||||
}
|
||||
const targetUser = Users.getExact(target);
|
||||
if (!targetUser) {
|
||||
return this.errorReply(this.tr`User ${target} not found.`);
|
||||
throw new Chat.ErrorMessage(this.tr`User ${target} not found.`);
|
||||
}
|
||||
if (!battle.playerTable[user.id]) {
|
||||
return this.errorReply(this.tr`Must be a player in this battle.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Must be a player in this battle.`);
|
||||
}
|
||||
if (!battle.allowExtraction[targetUser.id]) {
|
||||
return this.errorReply(this.tr`${targetUser.name} has not requested extraction.`);
|
||||
throw new Chat.ErrorMessage(this.tr`${targetUser.name} has not requested extraction.`);
|
||||
}
|
||||
if (battle.allowExtraction[targetUser.id].has(user.id)) {
|
||||
return this.errorReply(this.tr`You have already consented to extraction with ${targetUser.name}.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You have already consented to extraction with ${targetUser.name}.`);
|
||||
}
|
||||
battle.allowExtraction[targetUser.id].add(user.id);
|
||||
this.addModAction(room.tr`${user.name} consents to sharing battle team and choices with ${targetUser.name}.`);
|
||||
if (!battle.inputLog) return this.errorReply(this.tr`No input log found.`);
|
||||
if (!battle.inputLog) throw new Chat.ErrorMessage(this.tr`No input log found.`);
|
||||
if (Object.keys(battle.playerTable).length === battle.allowExtraction[targetUser.id].size) {
|
||||
this.addModAction(room.tr`${targetUser.name} has extracted the battle input log.`);
|
||||
const inputLog = battle.inputLog.map(Utils.escapeHTML).join(`<br />`);
|
||||
|
|
@ -817,7 +817,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const battle = room.battle;
|
||||
if (!battle) {
|
||||
return this.errorReply(this.tr`This command only works in battle rooms.`);
|
||||
throw new Chat.ErrorMessage(this.tr`This command only works in battle rooms.`);
|
||||
}
|
||||
if (!battle.inputLog) {
|
||||
this.errorReply(this.tr`This command only works when the battle has ended - if the battle has stalled, use /offertie.`);
|
||||
|
|
@ -826,7 +826,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
this.checkCan('exportinputlog', null, room);
|
||||
if (user.can('forcewin') || Dex.formats.get(battle.format).team) {
|
||||
if (!battle.inputLog) return this.errorReply(this.tr`No input log found.`);
|
||||
if (!battle.inputLog) throw new Chat.ErrorMessage(this.tr`No input log found.`);
|
||||
this.addModAction(room.tr`${user.name} has extracted the battle input log.`);
|
||||
const inputLog = battle.inputLog.map(Utils.escapeHTML).join(`<br />`);
|
||||
user.sendTo(
|
||||
|
|
@ -860,7 +860,7 @@ export const commands: Chat.ChatCommands = {
|
|||
Utils.html`|html|${user.name} wants to extract the battle input log. <button name="send" value="/allowexportinputlog ${user.id}">Share your team and choices with "${user.name}"</button>`
|
||||
);
|
||||
}
|
||||
if (logExported) return this.errorReply(this.tr`You already extracted the battle input log.`);
|
||||
if (logExported) throw new Chat.ErrorMessage(this.tr`You already extracted the battle input log.`);
|
||||
this.sendReply(this.tr`Battle input log re-requested.`);
|
||||
}
|
||||
},
|
||||
|
|
@ -870,10 +870,10 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('importinputlog');
|
||||
const formatIndex = target.indexOf(`"formatid":"`);
|
||||
const nextQuoteIndex = target.indexOf(`"`, formatIndex + 12);
|
||||
if (formatIndex < 0 || nextQuoteIndex < 0) return this.errorReply(this.tr`Invalid input log.`);
|
||||
if (formatIndex < 0 || nextQuoteIndex < 0) throw new Chat.ErrorMessage(this.tr`Invalid input log.`);
|
||||
target = target.replace(/\r/g, '');
|
||||
if ((`\n` + target).includes(`\n>eval `) && !user.hasConsoleAccess(connection)) {
|
||||
return this.errorReply(this.tr`Your input log contains untrusted code - you must have console access to use it.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Your input log contains untrusted code - you must have console access to use it.`);
|
||||
}
|
||||
|
||||
const formatid = target.slice(formatIndex + 12, nextQuoteIndex);
|
||||
|
|
@ -899,22 +899,22 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const battle = room.battle;
|
||||
if (!showAll && !target) return this.parse(`/help showset`);
|
||||
if (!battle) return this.errorReply(this.tr`This command can only be used in a battle.`);
|
||||
if (!battle) throw new Chat.ErrorMessage(this.tr`This command can only be used in a battle.`);
|
||||
let team = await battle.getTeam(user);
|
||||
if (!team) return this.errorReply(this.tr`You are not a player and don't have a team.`);
|
||||
if (!team) throw new Chat.ErrorMessage(this.tr`You are not a player and don't have a team.`);
|
||||
|
||||
if (!showAll) {
|
||||
const parsed = parseInt(target);
|
||||
if (isNaN(parsed)) {
|
||||
const id = toID(target);
|
||||
const matchedSet = team.find(set => toID(set.name) === id || toID(set.species) === id);
|
||||
if (!matchedSet) return this.errorReply(this.tr`You don't have a Pokémon matching "${target}" in your team.`);
|
||||
if (!matchedSet) throw new Chat.ErrorMessage(this.tr`You don't have a Pokémon matching "${target}" in your team.`);
|
||||
team = [matchedSet];
|
||||
} else {
|
||||
const setIndex = parsed - 1;
|
||||
const indexedSet = team[setIndex];
|
||||
if (!indexedSet) {
|
||||
return this.errorReply(this.tr`You don't have a Pokémon #${parsed} on your team - your team only has ${team.length} Pokémon.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You don't have a Pokémon #${parsed} on your team - your team only has ${team.length} Pokémon.`);
|
||||
}
|
||||
team = [indexedSet];
|
||||
}
|
||||
|
|
@ -941,23 +941,23 @@ export const commands: Chat.ChatCommands = {
|
|||
acceptopenteamsheets(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom();
|
||||
const battle = room.battle;
|
||||
if (!battle) return this.errorReply(this.tr`Must be in a battle room.`);
|
||||
if (!battle) throw new Chat.ErrorMessage(this.tr`Must be in a battle room.`);
|
||||
const player = battle.playerTable[user.id];
|
||||
if (!player) {
|
||||
return this.errorReply(this.tr`Must be a player to agree to open team sheets.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Must be a player to agree to open team sheets.`);
|
||||
}
|
||||
const format = Dex.formats.get(battle.options.format);
|
||||
if (!Dex.formats.getRuleTable(format).has('openteamsheets')) {
|
||||
return this.errorReply(this.tr`This format does not allow requesting open team sheets. You can both manually agree to it by using !showteam hidestats.`);
|
||||
throw new Chat.ErrorMessage(this.tr`This format does not allow requesting open team sheets. You can both manually agree to it by using !showteam hidestats.`);
|
||||
}
|
||||
if (battle.turn > 0) {
|
||||
return this.errorReply(this.tr`You cannot agree to open team sheets after Team Preview. Each player can still show their own sheet by using this command: !showteam hidestats`);
|
||||
throw new Chat.ErrorMessage(this.tr`You cannot agree to open team sheets after Team Preview. Each player can still show their own sheet by using this command: !showteam hidestats`);
|
||||
}
|
||||
if (battle.players.some(curPlayer => curPlayer.wantsOpenTeamSheets === false)) {
|
||||
return this.errorReply(this.tr`An opponent has already rejected open team sheets.`);
|
||||
throw new Chat.ErrorMessage(this.tr`An opponent has already rejected open team sheets.`);
|
||||
}
|
||||
if (player.wantsOpenTeamSheets !== null) {
|
||||
return this.errorReply(this.tr`You have already made your decision about agreeing to open team sheets.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You have already made your decision about agreeing to open team sheets.`);
|
||||
}
|
||||
player.wantsOpenTeamSheets = true;
|
||||
player.sendRoom(Utils.html`|uhtmlchange|otsrequest|`);
|
||||
|
|
@ -972,20 +972,20 @@ export const commands: Chat.ChatCommands = {
|
|||
rejectopenteamsheets(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const battle = room.battle;
|
||||
if (!battle) return this.errorReply(this.tr`Must be in a battle room.`);
|
||||
if (!battle) throw new Chat.ErrorMessage(this.tr`Must be in a battle room.`);
|
||||
const player = battle.playerTable[user.id];
|
||||
if (!player) {
|
||||
return this.errorReply(this.tr`Must be a player to reject open team sheets.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Must be a player to reject open team sheets.`);
|
||||
}
|
||||
const format = Dex.formats.get(battle.options.format);
|
||||
if (!Dex.formats.getRuleTable(format).has('openteamsheets')) {
|
||||
return this.errorReply(this.tr`This format does not allow requesting open team sheets.`);
|
||||
throw new Chat.ErrorMessage(this.tr`This format does not allow requesting open team sheets.`);
|
||||
}
|
||||
if (battle.turn > 0) {
|
||||
return this.errorReply(this.tr`You cannot reject open team sheets after Team Preview.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You cannot reject open team sheets after Team Preview.`);
|
||||
}
|
||||
if (player.wantsOpenTeamSheets !== null) {
|
||||
return this.errorReply(this.tr`You have already made your decision about agreeing to open team sheets.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You have already made your decision about agreeing to open team sheets.`);
|
||||
}
|
||||
player.wantsOpenTeamSheets = false;
|
||||
for (const otherPlayer of battle.players) {
|
||||
|
|
@ -1002,19 +1002,19 @@ export const commands: Chat.ChatCommands = {
|
|||
offertie(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom();
|
||||
const battle = room.battle;
|
||||
if (!battle) return this.errorReply(this.tr`Must be in a battle room.`);
|
||||
if (!battle) throw new Chat.ErrorMessage(this.tr`Must be in a battle room.`);
|
||||
if (!Config.allowrequestingties) {
|
||||
return this.errorReply(this.tr`This server does not allow offering ties.`);
|
||||
throw new Chat.ErrorMessage(this.tr`This server does not allow offering ties.`);
|
||||
}
|
||||
if (room.tour) {
|
||||
return this.errorReply(this.tr`You can't offer ties in tournaments.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You can't offer ties in tournaments.`);
|
||||
}
|
||||
if (battle.turn < 100) {
|
||||
return this.errorReply(this.tr`It's too early to tie, please play until turn 100.`);
|
||||
throw new Chat.ErrorMessage(this.tr`It's too early to tie, please play until turn 100.`);
|
||||
}
|
||||
this.checkCan('roomvoice', null, room);
|
||||
if (cmd === 'accepttie' && !battle.players.some(player => player.wantsTie)) {
|
||||
return this.errorReply(this.tr`No other player is requesting a tie right now. It was probably canceled.`);
|
||||
throw new Chat.ErrorMessage(this.tr`No other player is requesting a tie right now. It was probably canceled.`);
|
||||
}
|
||||
const player = battle.playerTable[user.id];
|
||||
if (!battle.players.some(curPlayer => curPlayer.wantsTie)) {
|
||||
|
|
@ -1031,12 +1031,12 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
} else {
|
||||
if (!player) {
|
||||
return this.errorReply(this.tr`Must be a player to accept ties.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Must be a player to accept ties.`);
|
||||
}
|
||||
if (!player.wantsTie) {
|
||||
player.wantsTie = true;
|
||||
} else {
|
||||
return this.errorReply(this.tr`You have already agreed to a tie.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You have already agreed to a tie.`);
|
||||
}
|
||||
player.sendRoom(Utils.html`|uhtmlchange|offertie|`);
|
||||
this.add(this.tr`${user.name} accepted the tie.`);
|
||||
|
|
@ -1054,13 +1054,13 @@ export const commands: Chat.ChatCommands = {
|
|||
rejecttie(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const battle = room.battle;
|
||||
if (!battle) return this.errorReply(this.tr`Must be in a battle room.`);
|
||||
if (!battle) throw new Chat.ErrorMessage(this.tr`Must be in a battle room.`);
|
||||
const player = battle.playerTable[user.id];
|
||||
if (!player) {
|
||||
return this.errorReply(this.tr`Must be a player to reject ties.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Must be a player to reject ties.`);
|
||||
}
|
||||
if (!battle.players.some(curPlayer => curPlayer.wantsTie)) {
|
||||
return this.errorReply(this.tr`No other player is requesting a tie right now. It was probably canceled.`);
|
||||
throw new Chat.ErrorMessage(this.tr`No other player is requesting a tie right now. It was probably canceled.`);
|
||||
}
|
||||
if (player.wantsTie) player.wantsTie = false;
|
||||
for (const otherPlayer of battle.players) {
|
||||
|
|
@ -1081,9 +1081,9 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
forfeit(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.game) return this.errorReply(this.tr`This room doesn't have an active game.`);
|
||||
if (!room.game) throw new Chat.ErrorMessage(this.tr`This room doesn't have an active game.`);
|
||||
if (!room.game.forfeit) {
|
||||
return this.errorReply(this.tr`This kind of game can't be forfeited.`);
|
||||
throw new Chat.ErrorMessage(this.tr`This kind of game can't be forfeited.`);
|
||||
}
|
||||
room.game.forfeit(user);
|
||||
},
|
||||
|
|
@ -1094,8 +1094,8 @@ export const commands: Chat.ChatCommands = {
|
|||
guess: 'choose',
|
||||
choose(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.game) return this.errorReply(this.tr`This room doesn't have an active game.`);
|
||||
if (!room.game.choose) return this.errorReply(this.tr`This game doesn't support /choose`);
|
||||
if (!room.game) throw new Chat.ErrorMessage(this.tr`This room doesn't have an active game.`);
|
||||
if (!room.game.choose) throw new Chat.ErrorMessage(this.tr`This game doesn't support /choose`);
|
||||
if (room.game.checkChat) this.checkChat();
|
||||
room.game.choose(user, target);
|
||||
},
|
||||
|
|
@ -1129,8 +1129,8 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
undo(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.game) return this.errorReply(this.tr`This room doesn't have an active game.`);
|
||||
if (!room.game.undo) return this.errorReply(this.tr`This game doesn't support /undo`);
|
||||
if (!room.game) throw new Chat.ErrorMessage(this.tr`This room doesn't have an active game.`);
|
||||
if (!room.game.undo) throw new Chat.ErrorMessage(this.tr`This game doesn't support /undo`);
|
||||
|
||||
room.game.undo(user, target);
|
||||
},
|
||||
|
|
@ -1141,7 +1141,7 @@ export const commands: Chat.ChatCommands = {
|
|||
uploadreplay: 'savereplay',
|
||||
async savereplay(target, room, user, connection) {
|
||||
if (!room?.battle) {
|
||||
return this.errorReply(this.tr`You can only save replays for battles.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You can only save replays for battles.`);
|
||||
}
|
||||
|
||||
const options = (target === 'forpunishment' || target === 'silent') ? target : undefined;
|
||||
|
|
@ -1150,12 +1150,12 @@ export const commands: Chat.ChatCommands = {
|
|||
savereplayhelp: [`/savereplay - Saves the replay for the current battle.`],
|
||||
|
||||
hidereplay(target, room, user, connection) {
|
||||
if (!room?.battle) return this.errorReply(`Must be used in a battle.`);
|
||||
if (!room?.battle) throw new Chat.ErrorMessage(`Must be used in a battle.`);
|
||||
this.checkCan('joinbattle', null, room);
|
||||
if (room.tour?.forcePublic) {
|
||||
return this.errorReply(this.tr`This battle can't have hidden replays, because the tournament is set to be forced public.`);
|
||||
throw new Chat.ErrorMessage(this.tr`This battle can't have hidden replays, because the tournament is set to be forced public.`);
|
||||
}
|
||||
if (room.hideReplay) return this.errorReply(this.tr`The replay for this battle is already set to hidden.`);
|
||||
if (room.hideReplay) throw new Chat.ErrorMessage(this.tr`The replay for this battle is already set to hidden.`);
|
||||
room.hideReplay = true;
|
||||
// If a replay has already been saved, /savereplay again to update the uploaded replay's hidden status
|
||||
if (room.battle.replaySaved) this.parse('/savereplay');
|
||||
|
|
@ -1166,8 +1166,8 @@ export const commands: Chat.ChatCommands = {
|
|||
addplayer: 'invitebattle',
|
||||
invitebattle(target, room, user, connection) {
|
||||
room = this.requireRoom();
|
||||
if (!room.battle) return this.errorReply(this.tr`You can only do this in battle rooms.`);
|
||||
if (room.rated) return this.errorReply(this.tr`You can only add a Player to unrated battles.`);
|
||||
if (!room.battle) throw new Chat.ErrorMessage(this.tr`You can only do this in battle rooms.`);
|
||||
if (room.rated) throw new Chat.ErrorMessage(this.tr`You can only add a Player to unrated battles.`);
|
||||
|
||||
this.checkCan('joinbattle', null, room);
|
||||
|
||||
|
|
@ -1181,29 +1181,29 @@ export const commands: Chat.ChatCommands = {
|
|||
const player = battle[slot];
|
||||
|
||||
if (!player) {
|
||||
return this.errorReply(`This battle does not support having players in ${slot}`);
|
||||
throw new Chat.ErrorMessage(`This battle does not support having players in ${slot}`);
|
||||
}
|
||||
if (!targetUser) {
|
||||
battle.sendInviteForm(connection);
|
||||
return this.errorReply(this.tr`User ${name} not found.`);
|
||||
throw new Chat.ErrorMessage(this.tr`User ${name} not found.`);
|
||||
}
|
||||
if (player.id) {
|
||||
battle.sendInviteForm(connection);
|
||||
return this.errorReply(this.tr`This room already has a player in slot ${slot}.`);
|
||||
throw new Chat.ErrorMessage(this.tr`This room already has a player in slot ${slot}.`);
|
||||
}
|
||||
if (player.invite) {
|
||||
battle.sendInviteForm(connection);
|
||||
return this.errorReply(`Someone else (${player.invite}) has already been invited to be ${slot}!`);
|
||||
throw new Chat.ErrorMessage(`Someone else (${player.invite}) has already been invited to be ${slot}!`);
|
||||
}
|
||||
if (targetUser.id in battle.playerTable) {
|
||||
battle.sendInviteForm(connection);
|
||||
return this.errorReply(this.tr`${targetUser.name} is already a player in this battle.`);
|
||||
throw new Chat.ErrorMessage(this.tr`${targetUser.name} is already a player in this battle.`);
|
||||
}
|
||||
|
||||
if (targetUser.settings.blockChallenges && !user.can('bypassblocks', targetUser)) {
|
||||
battle.sendInviteForm(connection);
|
||||
Chat.maybeNotifyBlocked('challenge', targetUser, user);
|
||||
return this.errorReply(this.tr`The user '${targetUser.name}' is not accepting challenges right now.`);
|
||||
throw new Chat.ErrorMessage(this.tr`The user '${targetUser.name}' is not accepting challenges right now.`);
|
||||
}
|
||||
|
||||
// INVITE
|
||||
|
|
@ -1239,11 +1239,11 @@ export const commands: Chat.ChatCommands = {
|
|||
const chall = Ladders.challenges.resolveAcceptCommand(this);
|
||||
|
||||
const targetRoom = Rooms.get(chall.roomid);
|
||||
if (!targetRoom) return this.errorReply(`Room ${chall.roomid} not found`);
|
||||
if (!targetRoom) throw new Chat.ErrorMessage(`Room ${chall.roomid} not found`);
|
||||
const battle = targetRoom.battle!;
|
||||
const player = battle.players.find(maybe => maybe.invite === user.id);
|
||||
if (!player) {
|
||||
return this.errorReply(`You haven't been invited to that battle.`);
|
||||
throw new Chat.ErrorMessage(`You haven't been invited to that battle.`);
|
||||
}
|
||||
const slot = player.slot;
|
||||
if (player.id) {
|
||||
|
|
@ -1271,7 +1271,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('joinbattle', null, room);
|
||||
|
||||
if (!room.battle) return this.errorReply(this.tr`You can only do this in battle rooms.`);
|
||||
if (!room.battle) throw new Chat.ErrorMessage(this.tr`You can only do this in battle rooms.`);
|
||||
const invitesFull = room.battle.invitesFull();
|
||||
const challenges = Ladders.challenges.get(target as ID);
|
||||
|
||||
|
|
@ -1292,8 +1292,8 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
restoreplayers(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.battle) return this.errorReply(this.tr`You can only do this in battle rooms.`);
|
||||
if (room.rated) return this.errorReply(this.tr`You can only add a Player to unrated battles.`);
|
||||
if (!room.battle) throw new Chat.ErrorMessage(this.tr`You can only do this in battle rooms.`);
|
||||
if (room.rated) throw new Chat.ErrorMessage(this.tr`You can only add a Player to unrated battles.`);
|
||||
|
||||
let didSomething = false;
|
||||
for (const player of room.battle.players) {
|
||||
|
|
@ -1304,7 +1304,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
|
||||
if (!didSomething) {
|
||||
return this.errorReply(this.tr`Players could not be restored (maybe this battle already has two players?).`);
|
||||
throw new Chat.ErrorMessage(this.tr`Players could not be restored (maybe this battle already has two players?).`);
|
||||
}
|
||||
},
|
||||
restoreplayershelp: [
|
||||
|
|
@ -1314,8 +1314,8 @@ export const commands: Chat.ChatCommands = {
|
|||
joinbattle: 'joingame',
|
||||
joingame(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.game) return this.errorReply(this.tr`This room doesn't have an active game.`);
|
||||
if (!room.game.joinGame) return this.errorReply(this.tr`This game doesn't support /joingame`);
|
||||
if (!room.game) throw new Chat.ErrorMessage(this.tr`This room doesn't have an active game.`);
|
||||
if (!room.game.joinGame) throw new Chat.ErrorMessage(this.tr`This game doesn't support /joingame`);
|
||||
|
||||
room.game.joinGame(user, target);
|
||||
},
|
||||
|
|
@ -1325,8 +1325,8 @@ export const commands: Chat.ChatCommands = {
|
|||
partbattle: 'leavegame',
|
||||
leavegame(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.game) return this.errorReply(this.tr`This room doesn't have an active game.`);
|
||||
if (!room.game.leaveGame) return this.errorReply(this.tr`This game doesn't support /leavegame`);
|
||||
if (!room.game) throw new Chat.ErrorMessage(this.tr`This room doesn't have an active game.`);
|
||||
if (!room.game.leaveGame) throw new Chat.ErrorMessage(this.tr`This game doesn't support /leavegame`);
|
||||
|
||||
room.game.leaveGame(user);
|
||||
},
|
||||
|
|
@ -1335,9 +1335,9 @@ export const commands: Chat.ChatCommands = {
|
|||
kickbattle: 'kickgame',
|
||||
kickgame(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.battle) return this.errorReply(this.tr`You can only do this in battle rooms.`);
|
||||
if (!room.battle) throw new Chat.ErrorMessage(this.tr`You can only do this in battle rooms.`);
|
||||
if (room.battle.challengeType === 'tour' || room.battle.rated) {
|
||||
return this.errorReply(this.tr`You can only do this in unrated non-tour battles.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You can only do this in unrated non-tour battles.`);
|
||||
}
|
||||
const { targetUser, rest: reason } = this.requireUser(target, { allowOffline: true });
|
||||
this.checkCan('kick', targetUser, room);
|
||||
|
|
@ -1346,7 +1346,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.addModAction(room.tr`${targetUser.name} was kicked from a battle by ${user.name}.${displayReason}`);
|
||||
this.modlog('KICKBATTLE', targetUser, reason, { noip: 1, noalts: 1 });
|
||||
} else {
|
||||
this.errorReply("/kickbattle - User isn't in battle.");
|
||||
throw new Chat.ErrorMessage("/kickbattle - User isn't in battle.");
|
||||
}
|
||||
},
|
||||
kickbattlehelp: [`/kickbattle [username], [reason] - Kicks a user from a battle with reason. Requires: % @ ~`],
|
||||
|
|
@ -1362,7 +1362,7 @@ export const commands: Chat.ChatCommands = {
|
|||
target = toID(target);
|
||||
room = this.requireRoom();
|
||||
if (!room.game?.timer) {
|
||||
return this.errorReply(this.tr`You can only set the timer from inside a battle room.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You can only set the timer from inside a battle room.`);
|
||||
}
|
||||
const timer = room.game.timer as any;
|
||||
if (!timer.timerRequesters) {
|
||||
|
|
@ -1377,7 +1377,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const force = user.can('timer', null, room);
|
||||
if (!force && !room.game.playerTable[user.id]) {
|
||||
return this.errorReply(this.tr`Access denied.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Access denied.`);
|
||||
}
|
||||
if (this.meansNo(target) || target === 'stop') {
|
||||
if (timer.timerRequesters.size) {
|
||||
|
|
@ -1386,12 +1386,12 @@ export const commands: Chat.ChatCommands = {
|
|||
room.send(`|inactiveoff|${room.tr`Timer was turned off by staff. Please do not turn it back on until our staff say it's okay.`}`);
|
||||
}
|
||||
} else {
|
||||
this.errorReply(this.tr`The timer is already off.`);
|
||||
throw new Chat.ErrorMessage(this.tr`The timer is already off.`);
|
||||
}
|
||||
} else if (this.meansYes(target) || target === 'start') {
|
||||
timer.start(user);
|
||||
} else {
|
||||
this.errorReply(this.tr`"${target}" is not a recognized timer state.`);
|
||||
throw new Chat.ErrorMessage(this.tr`"${target}" is not a recognized timer state.`);
|
||||
}
|
||||
},
|
||||
timerhelp: [
|
||||
|
|
@ -1410,7 +1410,7 @@ export const commands: Chat.ChatCommands = {
|
|||
Config.forcetimer = true;
|
||||
this.addModAction(room.tr`Forcetimer is now ON: All battles will be timed. (set by ${user.name})`);
|
||||
} else {
|
||||
this.errorReply(this.tr`'${target}' is not a recognized forcetimer setting.`);
|
||||
throw new Chat.ErrorMessage(this.tr`'${target}' is not a recognized forcetimer setting.`);
|
||||
}
|
||||
},
|
||||
forcetimerhelp: [
|
||||
|
|
@ -1425,8 +1425,7 @@ export const commands: Chat.ChatCommands = {
|
|||
!room.battle &&
|
||||
!(room.game && typeof (room.game as any).tie === 'function' && typeof (room.game as any).win === 'function')
|
||||
) {
|
||||
this.errorReply("/forcewin - This is not a battle room.");
|
||||
return false;
|
||||
throw new Chat.ErrorMessage("/forcewin - This is not a battle room.");
|
||||
}
|
||||
|
||||
if (room.battle) room.battle.endType = 'forced';
|
||||
|
|
@ -1436,7 +1435,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return false;
|
||||
}
|
||||
const targetUser = Users.getExact(target);
|
||||
if (!targetUser) return this.errorReply(this.tr`User '${target}' not found.`);
|
||||
if (!targetUser) throw new Chat.ErrorMessage(this.tr`User '${target}' not found.`);
|
||||
|
||||
(room.game as any).win(targetUser);
|
||||
this.modlog('FORCEWIN', targetUser.id);
|
||||
|
|
@ -1517,7 +1516,7 @@ export const commands: Chat.ChatCommands = {
|
|||
blockchallenges(target, room, user) {
|
||||
if (toID(target) === 'ac') target = 'autoconfirmed';
|
||||
if (user.settings.blockChallenges === (target || true)) {
|
||||
return this.errorReply(this.tr`You are already blocking challenges!`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are already blocking challenges!`);
|
||||
}
|
||||
if (Users.Auth.isAuthLevel(target)) {
|
||||
user.settings.blockChallenges = target;
|
||||
|
|
@ -1542,7 +1541,7 @@ export const commands: Chat.ChatCommands = {
|
|||
unblockchalls: 'allowchallenges',
|
||||
unblockchallenges: 'allowchallenges',
|
||||
allowchallenges(target, room, user) {
|
||||
if (!user.settings.blockChallenges) return this.errorReply(this.tr`You are already available for challenges!`);
|
||||
if (!user.settings.blockChallenges) throw new Chat.ErrorMessage(this.tr`You are already available for challenges!`);
|
||||
user.settings.blockChallenges = false;
|
||||
user.update();
|
||||
this.sendReply(this.tr`You are available for challenges from now on.`);
|
||||
|
|
@ -1620,7 +1619,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (Monitor.countPrepBattle(connection.ip, connection)) {
|
||||
return;
|
||||
}
|
||||
if (!target) return this.errorReply(this.tr`Provide a valid format.`);
|
||||
if (!target) throw new Chat.ErrorMessage(this.tr`Provide a valid format.`);
|
||||
const originalFormat = Dex.formats.get(target);
|
||||
// Note: The default here of Anything Goes isn't normally hit; since the web client will send a default format
|
||||
const format = originalFormat.effectType === 'Format' ? originalFormat : Dex.formats.get('Anything Goes');
|
||||
|
|
@ -1807,7 +1806,7 @@ export const pages: Chat.PageTable = {
|
|||
receivedpms(query, user) {
|
||||
this.title = '[Received PMs]';
|
||||
if (!Chat.PrivateMessages.offlineIsEnabled) {
|
||||
return this.errorReply(`Offline PMs are presently disabled.`);
|
||||
throw new Chat.ErrorMessage(`Offline PMs are presently disabled.`);
|
||||
}
|
||||
return Chat.PrivateMessages.renderReceived(user);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -111,10 +111,10 @@ export const commands: Chat.ChatCommands = {
|
|||
const showRecursiveAlts = showAll && (cmd !== 'altsnorecurse');
|
||||
if (!targetUser) {
|
||||
if (showAll) return this.parse('/offlinewhois ' + target);
|
||||
return this.errorReply(`User ${target} not found.`);
|
||||
throw new Chat.ErrorMessage(`User ${target} not found.`);
|
||||
}
|
||||
if (showAll && !user.trusted && targetUser !== user) {
|
||||
return this.errorReply(`/${cmd} - Access denied.`);
|
||||
throw new Chat.ErrorMessage(`/${cmd} - Access denied.`);
|
||||
}
|
||||
|
||||
let buf = Utils.html`<strong class="username"><small style="display:none">${targetUser.tempGroup}</small>${targetUser.name}</strong> `;
|
||||
|
|
@ -354,10 +354,10 @@ export const commands: Chat.ChatCommands = {
|
|||
checkpunishment: 'offlinewhois',
|
||||
offlinewhois(target, room, user) {
|
||||
if (!user.trusted) {
|
||||
return this.errorReply("/offlinewhois - Access denied.");
|
||||
throw new Chat.ErrorMessage("/offlinewhois - Access denied.");
|
||||
}
|
||||
const userid = toID(target);
|
||||
if (!userid) return this.errorReply("Please enter a valid username.");
|
||||
if (!userid) throw new Chat.ErrorMessage("Please enter a valid username.");
|
||||
const targetUser = Users.get(userid);
|
||||
let buf = Utils.html`<strong class="username">${target}</strong>`;
|
||||
if (!targetUser?.connected) buf += ` <em style="color:gray">(offline)</em>`;
|
||||
|
|
@ -395,7 +395,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!user.can('alts') && !atLeastOne) {
|
||||
const hasJurisdiction = room && user.can('mute', null, room) && Punishments.roomUserids.nestedHas(room.roomid, userid);
|
||||
if (!hasJurisdiction) {
|
||||
return this.errorReply("/checkpunishment - User not found.");
|
||||
throw new Chat.ErrorMessage("/checkpunishment - User not found.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -453,7 +453,7 @@ export const commands: Chat.ChatCommands = {
|
|||
showpunishments(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) {
|
||||
return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
}
|
||||
return this.parse(`/join view-punishments-${room}`);
|
||||
},
|
||||
|
|
@ -470,7 +470,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse('/help host');
|
||||
this.checkCan('alts');
|
||||
target = target.trim();
|
||||
if (!net.isIPv4(target)) return this.errorReply('You must pass a valid IPv4 IP to /host.');
|
||||
if (!net.isIPv4(target)) throw new Chat.ErrorMessage('You must pass a valid IPv4 IP to /host.');
|
||||
const { dnsbl, host, hostType } = await IPTools.lookup(target);
|
||||
const dnsblMessage = dnsbl ? ` [${dnsbl}]` : ``;
|
||||
this.sendReply(`IP ${target}: ${host || "ERROR"} [${hostType}]${dnsblMessage}`);
|
||||
|
|
@ -487,7 +487,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const [ipOrHost, roomid] = this.splitOne(target);
|
||||
const targetRoom = roomid ? Rooms.get(roomid) : null;
|
||||
if (typeof targetRoom === 'undefined') {
|
||||
return this.errorReply(`The room "${roomid}" does not exist.`);
|
||||
throw new Chat.ErrorMessage(`The room "${roomid}" does not exist.`);
|
||||
}
|
||||
const results: string[] = [];
|
||||
const isAll = (cmd === 'ipsearchall');
|
||||
|
|
@ -520,7 +520,7 @@ export const commands: Chat.ChatCommands = {
|
|||
results.push(`${curUser.connected ? ONLINE_SYMBOL : OFFLINE_SYMBOL} ${curUser.name}`);
|
||||
}
|
||||
} else {
|
||||
return this.errorReply(`${ipOrHost} is not a valid IP, IP range, or host.`);
|
||||
throw new Chat.ErrorMessage(`${ipOrHost} is not a valid IP, IP range, or host.`);
|
||||
}
|
||||
|
||||
if (!results.length) {
|
||||
|
|
@ -546,7 +546,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const { targetUser: user2, rest: rest2 } = this.requireUser(rest);
|
||||
if (user1 === user2 || rest2) return this.parse(`/help checkchallenges`);
|
||||
if (!(user1.id in room.users) || !(user2.id in room.users)) {
|
||||
return this.errorReply(`Both users must be in this room.`);
|
||||
throw new Chat.ErrorMessage(`Both users must be in this room.`);
|
||||
}
|
||||
const chall = Ladders.challenges.search(user1.id, user2.id);
|
||||
|
||||
|
|
@ -603,7 +603,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const newTargets = dex.dataSearch(target);
|
||||
const showDetails = (cmd.startsWith('dt') || cmd === 'details');
|
||||
if (!newTargets?.length) {
|
||||
return this.errorReply(`No Pok\u00e9mon, item, move, ability or nature named '${target}' was found${Dex.gen > dex.gen ? ` in Gen ${dex.gen}` : ""}. (Check your spelling?)`);
|
||||
throw new Chat.ErrorMessage(`No Pok\u00e9mon, item, move, ability or nature named '${target}' was found${Dex.gen > dex.gen ? ` in Gen ${dex.gen}` : ""}. (Check your spelling?)`);
|
||||
}
|
||||
|
||||
for (const [i, newTarget] of newTargets.entries()) {
|
||||
|
|
@ -1063,7 +1063,7 @@ export const commands: Chat.ChatCommands = {
|
|||
matchup: 'effectiveness',
|
||||
effectiveness(target, room, user) {
|
||||
const { dex, targets } = this.splitFormat(target.split(/[,/]/));
|
||||
if (targets.length !== 2) return this.errorReply("Attacker and defender must be separated with a comma.");
|
||||
if (targets.length !== 2) throw new Chat.ErrorMessage("Attacker and defender must be separated with a comma.");
|
||||
|
||||
let searchMethods = ['types', 'moves', 'species'];
|
||||
const sourceMethods = ['types', 'moves'];
|
||||
|
|
@ -1176,9 +1176,9 @@ export const commands: Chat.ChatCommands = {
|
|||
// arg is a move?
|
||||
const move = dex.moves.get(arg);
|
||||
if (!move.exists) {
|
||||
return this.errorReply(`Type or move '${arg}' not found.`);
|
||||
throw new Chat.ErrorMessage(`Type or move '${arg}' not found.`);
|
||||
} else if (move.gen > dex.gen) {
|
||||
return this.errorReply(`Move '${arg}' is not available in Gen ${dex.gen}.`);
|
||||
throw new Chat.ErrorMessage(`Move '${arg}' is not available in Gen ${dex.gen}.`);
|
||||
}
|
||||
|
||||
if (!move.basePower && !move.basePowerCallback) continue;
|
||||
|
|
@ -1196,8 +1196,10 @@ export const commands: Chat.ChatCommands = {
|
|||
if (eff > bestCoverage[type]) bestCoverage[type] = eff;
|
||||
}
|
||||
}
|
||||
if (sources.length === 0) return this.errorReply("No moves using a type table for determining damage were specified.");
|
||||
if (sources.length > 4) return this.errorReply("Specify a maximum of 4 moves or types.");
|
||||
if (sources.length === 0) {
|
||||
throw new Chat.ErrorMessage("No moves using a type table for determining damage were specified.");
|
||||
}
|
||||
if (sources.length > 4) throw new Chat.ErrorMessage("Specify a maximum of 4 moves or types.");
|
||||
|
||||
// converts to fractional effectiveness, 0 for immune
|
||||
for (const type in bestCoverage) {
|
||||
|
|
@ -1901,7 +1903,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (targetId === 'all') targetId = '';
|
||||
const { totalMatches, sections } = findFormats(targetId, isOMSearch);
|
||||
|
||||
if (!totalMatches) return this.errorReply("No matched formats found.");
|
||||
if (!totalMatches) throw new Chat.ErrorMessage("No matched formats found.");
|
||||
|
||||
const format = totalMatches === 1 ? Dex.formats.get(Object.values(sections)[0].formats[0]) : null;
|
||||
|
||||
|
|
@ -2070,15 +2072,16 @@ export const commands: Chat.ChatCommands = {
|
|||
return;
|
||||
}
|
||||
if (!room) {
|
||||
return this.errorReply(`This is not a room you can set the rules of.`);
|
||||
throw new Chat.ErrorMessage(`This is not a room you can set the rules of.`);
|
||||
}
|
||||
const possibleRoom = Rooms.search(toID(target));
|
||||
const { totalMatches: formatMatches } = findFormats(toID(target));
|
||||
if (formatMatches && possibleRoom && cmd !== 'roomrules') {
|
||||
this.errorReply(`'${target}' is both a room and a tier. `);
|
||||
this.errorReply(`If you were looking for rules of that room, use /roomrules [room].`);
|
||||
this.errorReply(`Otherwise, use /tier [tiername].`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage([
|
||||
`'${target}' is both a room and a tier.`,
|
||||
`If you were looking for rules of that room, use /roomrules [room].`,
|
||||
`Otherwise, use /tier [tiername].`,
|
||||
]);
|
||||
}
|
||||
|
||||
if (possibleRoom) {
|
||||
|
|
@ -2094,13 +2097,13 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
this.checkCan('editroom', null, room);
|
||||
if (target.length > 150) {
|
||||
return this.errorReply(`Error: Room rules link is too long (must be under 150 characters). You can use a URL shortener to shorten the link.`);
|
||||
throw new Chat.ErrorMessage(`Error: Room rules link is too long (must be under 150 characters). You can use a URL shortener to shorten the link.`);
|
||||
}
|
||||
|
||||
target = target.trim();
|
||||
|
||||
if (target === 'delete' || target === 'remove') {
|
||||
if (!room.settings.rulesLink) return this.errorReply(`This room does not have rules set to remove.`);
|
||||
if (!room.settings.rulesLink) throw new Chat.ErrorMessage(`This room does not have rules set to remove.`);
|
||||
delete room.settings.rulesLink;
|
||||
this.privateModAction(`${user.name} has removed the room rules link.`);
|
||||
this.modlog('RULES', null, `removed room rules link`);
|
||||
|
|
@ -2373,7 +2376,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (pokemon.exists) {
|
||||
atLeastOne = true;
|
||||
if (pokemon.isNonstandard && pokemon.isNonstandard !== 'Past') {
|
||||
return this.errorReply(`${pokemon.name} is not a real Pok\u00e9mon.`);
|
||||
throw new Chat.ErrorMessage(`${pokemon.name} is not a real Pok\u00e9mon.`);
|
||||
}
|
||||
let baseSpecies = pokemon.baseSpecies;
|
||||
if (pokemon.id.startsWith('flabebe')) baseSpecies = 'Flabébé';
|
||||
|
|
@ -2386,7 +2389,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (item.exists) {
|
||||
atLeastOne = true;
|
||||
if (item.isNonstandard && item.isNonstandard !== 'Past') {
|
||||
return this.errorReply(`${item.name} is not a real item.`);
|
||||
throw new Chat.ErrorMessage(`${item.name} is not a real item.`);
|
||||
}
|
||||
let link = `${baseLink}${encodeURIComponent(item.name)}`;
|
||||
if (Dex.moves.get(item.name).exists) link += '_(item)';
|
||||
|
|
@ -2397,7 +2400,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (ability.exists) {
|
||||
atLeastOne = true;
|
||||
if (ability.isNonstandard && ability.isNonstandard !== 'Past') {
|
||||
return this.errorReply(`${ability.name} is not a real ability.`);
|
||||
throw new Chat.ErrorMessage(`${ability.name} is not a real ability.`);
|
||||
}
|
||||
const link = `${baseLink}${encodeURIComponent(ability.name)}_(Ability)`;
|
||||
this.sendReplyBox(`<a href="${link}">${ability.name} ability description</a>, provided by Bulbapedia`);
|
||||
|
|
@ -2407,7 +2410,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (move.exists) {
|
||||
atLeastOne = true;
|
||||
if (move.isNonstandard && move.isNonstandard !== 'Past') {
|
||||
return this.errorReply(`${move.name} is not a real move.`);
|
||||
throw new Chat.ErrorMessage(`${move.name} is not a real move.`);
|
||||
}
|
||||
const link = `${baseLink}${encodeURIComponent(move.name)}_(move)`;
|
||||
this.sendReplyBox(`<a href="${link}">${move.name} move description</a>, provided by Bulbapedia`);
|
||||
|
|
@ -2473,11 +2476,11 @@ export const commands: Chat.ChatCommands = {
|
|||
offset = Number(target.slice(modifierData.index));
|
||||
if (isNaN(offset)) return this.parse('/help dice');
|
||||
if (!Number.isSafeInteger(offset)) {
|
||||
return this.errorReply(`The specified offset must be an integer up to ${Number.MAX_SAFE_INTEGER}.`);
|
||||
throw new Chat.ErrorMessage(`The specified offset must be an integer up to ${Number.MAX_SAFE_INTEGER}.`);
|
||||
}
|
||||
}
|
||||
if (removeOutlier && diceQuantity <= 1) {
|
||||
return this.errorReply(`More than one dice should be rolled before removing outliers.`);
|
||||
throw new Chat.ErrorMessage(`More than one dice should be rolled before removing outliers.`);
|
||||
}
|
||||
target = target.slice(0, modifierData.index);
|
||||
}
|
||||
|
|
@ -2486,14 +2489,14 @@ export const commands: Chat.ChatCommands = {
|
|||
if (target.length) {
|
||||
diceFaces = Number(target);
|
||||
if (!Number.isSafeInteger(diceFaces) || diceFaces <= 0) {
|
||||
return this.errorReply(`Rolled dice must have a natural amount of faces up to ${Number.MAX_SAFE_INTEGER}.`);
|
||||
throw new Chat.ErrorMessage(`Rolled dice must have a natural amount of faces up to ${Number.MAX_SAFE_INTEGER}.`);
|
||||
}
|
||||
}
|
||||
|
||||
if (diceQuantity > 1) {
|
||||
// Make sure that we can deal with high rolls
|
||||
if (!Number.isSafeInteger(offset < 0 ? diceQuantity * diceFaces : diceQuantity * diceFaces + offset)) {
|
||||
return this.errorReply(`The maximum sum of rolled dice must be lower or equal than ${Number.MAX_SAFE_INTEGER}.`);
|
||||
throw new Chat.ErrorMessage(`The maximum sum of rolled dice must be lower or equal than ${Number.MAX_SAFE_INTEGER}.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2568,17 +2571,17 @@ export const commands: Chat.ChatCommands = {
|
|||
],
|
||||
|
||||
showimage(target, room, user) {
|
||||
return this.errorReply(`/showimage has been deprecated - use /show instead.`);
|
||||
throw new Chat.ErrorMessage(`/showimage has been deprecated - use /show instead.`);
|
||||
},
|
||||
|
||||
async requestshow(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkChat();
|
||||
if (!room.settings.requestShowEnabled) {
|
||||
return this.errorReply(`Media approvals are disabled in this room.`);
|
||||
throw new Chat.ErrorMessage(`Media approvals are disabled in this room.`);
|
||||
}
|
||||
if (user.can('showmedia', null, room, 'show')) return this.errorReply(`Use !show instead.`);
|
||||
if (room.pendingApprovals?.has(user.id)) return this.errorReply('You have a request pending already.');
|
||||
if (user.can('showmedia', null, room, 'show')) throw new Chat.ErrorMessage(`Use !show instead.`);
|
||||
if (room.pendingApprovals?.has(user.id)) throw new Chat.ErrorMessage('You have a request pending already.');
|
||||
if (!toID(target)) return this.parse(`/help requestshow`);
|
||||
|
||||
let [link, comment] = this.splitOne(target);
|
||||
|
|
@ -2596,7 +2599,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
}
|
||||
if (comment && this.checkChat(comment) !== comment) {
|
||||
return this.errorReply(`You cannot use filtered words in comments.`);
|
||||
throw new Chat.ErrorMessage(`You cannot use filtered words in comments.`);
|
||||
}
|
||||
if (!room.pendingApprovals) room.pendingApprovals = new Map();
|
||||
room.pendingApprovals.set(user.id, {
|
||||
|
|
@ -2622,14 +2625,14 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
if (!room.settings.requestShowEnabled) {
|
||||
return this.errorReply(`Media approvals are disabled in this room.`);
|
||||
throw new Chat.ErrorMessage(`Media approvals are disabled in this room.`);
|
||||
}
|
||||
const userid = toID(target);
|
||||
if (!userid) return this.parse(`/help approveshow`);
|
||||
const request = room.pendingApprovals?.get(userid);
|
||||
if (!request) return this.errorReply(`${userid} has no pending request.`);
|
||||
if (!request) throw new Chat.ErrorMessage(`${userid} has no pending request.`);
|
||||
if (userid === user.id) {
|
||||
return this.errorReply(`You can't approve your own /show request.`);
|
||||
throw new Chat.ErrorMessage(`You can't approve your own /show request.`);
|
||||
}
|
||||
room.pendingApprovals!.delete(userid);
|
||||
room.sendMods(`|uhtmlchange|request-${target}|`);
|
||||
|
|
@ -2642,7 +2645,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (resized) buf += Utils.html`<br /><a href="${request.link}" target="_blank">full-size image</a>`;
|
||||
} else {
|
||||
buf = await YouTube.generateVideoDisplay(request.link, false);
|
||||
if (!buf) return this.errorReply('Could not get YouTube video');
|
||||
if (!buf) throw new Chat.ErrorMessage('Could not get YouTube video');
|
||||
}
|
||||
buf += Utils.html`<br /><div class="infobox"><small>(Requested by ${request.name})</small>`;
|
||||
if (request.comment) {
|
||||
|
|
@ -2659,13 +2662,13 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
if (!room.settings.requestShowEnabled) {
|
||||
return this.errorReply(`Media approvals are disabled in this room.`);
|
||||
throw new Chat.ErrorMessage(`Media approvals are disabled in this room.`);
|
||||
}
|
||||
target = toID(target);
|
||||
if (!target) return this.parse(`/help denyshow`);
|
||||
|
||||
const entry = room.pendingApprovals?.get(target);
|
||||
if (!entry) return this.errorReply(`${target} has no pending request.`);
|
||||
if (!entry) throw new Chat.ErrorMessage(`${target} has no pending request.`);
|
||||
|
||||
room.pendingApprovals!.delete(target);
|
||||
room.sendMods(`|uhtmlchange|request-${target}|`);
|
||||
|
|
@ -2696,11 +2699,11 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
async show(target, room, user, connection) {
|
||||
if (!room?.persist && !this.pmTarget && !room?.roomid.startsWith('help-')) {
|
||||
return this.errorReply(`/show cannot be used in temporary rooms.`);
|
||||
throw new Chat.ErrorMessage(`/show cannot be used in temporary rooms.`);
|
||||
}
|
||||
if (!toID(target).trim()) return this.parse(`/help show`);
|
||||
if (Monitor.countNetRequests(connection.ip)) {
|
||||
return this.errorReply(`You are using this command too quickly. Wait a bit and try again.`);
|
||||
throw new Chat.ErrorMessage(`You are using this command too quickly. Wait a bit and try again.`);
|
||||
}
|
||||
|
||||
const [link, comment] = Utils.splitFirst(target, ',').map(f => f.trim());
|
||||
|
|
@ -2720,7 +2723,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.message = this.message.replace(/&ab_channel=(.*)(&|)/ig, '').replace(/https:\/\/www\./ig, '');
|
||||
} else if (Twitch.linkRegex.test(link)) {
|
||||
const channelId = Twitch.linkRegex.exec(link)?.[2]?.trim();
|
||||
if (!channelId) return this.errorReply(`Specify a Twitch channel.`);
|
||||
if (!channelId) throw new Chat.ErrorMessage(`Specify a Twitch channel.`);
|
||||
buf = Utils.html`Watching <b><a class="subtle" href="https://twitch.tv/${toID(channelId)}">${channelId}</a></b>...<br />`;
|
||||
buf += `<twitch src="${link}" />`;
|
||||
} else {
|
||||
|
|
@ -2741,13 +2744,13 @@ export const commands: Chat.ChatCommands = {
|
|||
buf = Utils.html`<img src="${link}" width="${width}" height="${height}" />`;
|
||||
if (resized) buf += Utils.html`<br /><a href="${link}" target="_blank">full-size image</a>`;
|
||||
} catch {
|
||||
return this.errorReply('Invalid image, audio, or video URL.');
|
||||
throw new Chat.ErrorMessage('Invalid image, audio, or video URL.');
|
||||
}
|
||||
}
|
||||
}
|
||||
if (comment) {
|
||||
if (this.checkChat(comment) !== comment) {
|
||||
return this.errorReply(`You cannot use filtered words in comments.`);
|
||||
throw new Chat.ErrorMessage(`You cannot use filtered words in comments.`);
|
||||
}
|
||||
buf += Utils.html`<br />(${comment})</div>`;
|
||||
}
|
||||
|
|
@ -2776,9 +2779,9 @@ export const commands: Chat.ChatCommands = {
|
|||
async registertime(target, room, user, connection) {
|
||||
this.runBroadcast();
|
||||
if (Monitor.countNetRequests(connection.ip)) {
|
||||
return this.errorReply(`You are using this command too quickly. Wait a bit and try again.`);
|
||||
throw new Chat.ErrorMessage(`You are using this command too quickly. Wait a bit and try again.`);
|
||||
}
|
||||
if (!user.autoconfirmed) return this.errorReply(`Only autoconfirmed users can use this command.`);
|
||||
if (!user.autoconfirmed) throw new Chat.ErrorMessage(`Only autoconfirmed users can use this command.`);
|
||||
target = toID(target);
|
||||
if (!target) target = user.id;
|
||||
let rawResult;
|
||||
|
|
@ -2817,14 +2820,14 @@ export const commands: Chat.ChatCommands = {
|
|||
// important to code block indentation.
|
||||
target = this.message.substr(this.cmdToken.length + this.cmd.length + (this.message.includes(' ') ? 1 : 0)).trimRight();
|
||||
if (!target) return this.parse('/help code');
|
||||
if (target.length >= 8192) return this.errorReply("Your code must be under 8192 characters long!");
|
||||
if (target.length >= 8192) throw new Chat.ErrorMessage("Your code must be under 8192 characters long!");
|
||||
if (target.length < 80 && !target.includes('\n') && !target.includes('```') && this.shouldBroadcast()) {
|
||||
return this.checkChat(`\`\`\`${target}\`\`\``);
|
||||
}
|
||||
|
||||
if (this.room?.settings.isPersonal !== false && this.shouldBroadcast()) {
|
||||
target = this.filter(target)!;
|
||||
if (!target) return this.errorReply(`Invalid code.`);
|
||||
if (!target) throw new Chat.ErrorMessage(`Invalid code.`);
|
||||
}
|
||||
|
||||
this.checkBroadcast(true, '!code');
|
||||
|
|
@ -3001,7 +3004,7 @@ export const commands: Chat.ChatCommands = {
|
|||
randtopic(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.settings.topics?.length) {
|
||||
return this.errorReply(`This room has no random topics to select from.`);
|
||||
throw new Chat.ErrorMessage(`This room has no random topics to select from.`);
|
||||
}
|
||||
this.runBroadcast();
|
||||
this.sendReply(Utils.html`|html|<div class="broadcast-blue">${Utils.randomElement(room.settings.topics)}</div>`);
|
||||
|
|
@ -3036,10 +3039,10 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const index = Number(toID(target)) - 1;
|
||||
if (isNaN(index)) {
|
||||
return this.errorReply(`Invalid topic index: ${target}. Must be a number.`);
|
||||
throw new Chat.ErrorMessage(`Invalid topic index: ${target}. Must be a number.`);
|
||||
}
|
||||
if (!room.settings.topics?.[index]) {
|
||||
return this.errorReply(`Topic ${index + 1} not found.`);
|
||||
throw new Chat.ErrorMessage(`Topic ${index + 1} not found.`);
|
||||
}
|
||||
const topic = room.settings.topics.splice(index, 1)[0];
|
||||
room.saveSettings();
|
||||
|
|
@ -3072,19 +3075,19 @@ export const pages: Chat.PageTable = {
|
|||
this.title = '[Alts Log]';
|
||||
const target = toID(query.shift());
|
||||
if (!target) {
|
||||
return this.errorReply(`Please specify a user to find alternate accounts for.`);
|
||||
throw new Chat.ErrorMessage(`Please specify a user to find alternate accounts for.`);
|
||||
}
|
||||
this.title += ` ${target}`;
|
||||
if (!Config.usesqlite) {
|
||||
return this.errorReply(`The alternate account log is currently disabled.`);
|
||||
throw new Chat.ErrorMessage(`The alternate account log is currently disabled.`);
|
||||
}
|
||||
const rawLimit = query.shift() || "100";
|
||||
const num = parseInt(rawLimit);
|
||||
if (num > 3000) {
|
||||
return this.errorReply(`3000 is the maximum number of results from the alternate account log.`);
|
||||
throw new Chat.ErrorMessage(`3000 is the maximum number of results from the alternate account log.`);
|
||||
}
|
||||
if (isNaN(num) || num < 1) {
|
||||
return this.errorReply(`The max results must be a real number that is at least one (received "${rawLimit}")`);
|
||||
throw new Chat.ErrorMessage(`The max results must be a real number that is at least one (received "${rawLimit}")`);
|
||||
}
|
||||
const showIPs = user.can('globalban');
|
||||
const results = await Chat.database.all(
|
||||
|
|
|
|||
|
|
@ -143,15 +143,15 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
if (!target) return this.parse('/help roomowner');
|
||||
const { targetUser, targetUsername, rest } = this.splitUser(target, { exactName: true });
|
||||
if (rest) return this.errorReply(`This command does not support specifying a reason.`);
|
||||
if (rest) throw new Chat.ErrorMessage(`This command does not support specifying a reason.`);
|
||||
const userid = toID(targetUsername);
|
||||
|
||||
if (!Users.isUsernameKnown(userid)) {
|
||||
return this.errorReply(`User '${targetUsername}' is offline and unrecognized, and so can't be promoted.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUsername}' is offline and unrecognized, and so can't be promoted.`);
|
||||
}
|
||||
|
||||
this.checkCan('makeroom');
|
||||
if (room.auth.getDirect(userid) === '#') return this.errorReply(`${targetUsername} is already a room owner.`);
|
||||
if (room.auth.getDirect(userid) === '#') throw new Chat.ErrorMessage(`${targetUsername} is already a room owner.`);
|
||||
|
||||
room.auth.set(userid, '#');
|
||||
const message = `${targetUsername} was appointed Room Owner by ${user.name}.`;
|
||||
|
|
@ -181,7 +181,7 @@ export const commands: Chat.ChatCommands = {
|
|||
roompromote(target, room, user, connection, cmd) {
|
||||
if (!room) {
|
||||
// this command isn't marked as room-only because it's usable in PMs through /invite
|
||||
return this.errorReply("This command is only available in rooms");
|
||||
throw new Chat.ErrorMessage("This command is only available in rooms");
|
||||
}
|
||||
this.checkChat();
|
||||
if (!target) return this.parse('/help roompromote');
|
||||
|
|
@ -193,23 +193,19 @@ export const commands: Chat.ChatCommands = {
|
|||
const nextGroup = Users.Auth.getGroup(nextSymbol);
|
||||
|
||||
if (!nextSymbol) {
|
||||
return this.errorReply("Please specify a group such as /roomvoice or /roomdeauth");
|
||||
throw new Chat.ErrorMessage("Please specify a group such as /roomvoice or /roomdeauth");
|
||||
}
|
||||
if (!Config.groups[nextSymbol]) {
|
||||
if (!force || !user.can('bypassall')) {
|
||||
this.errorReply(`Group '${nextSymbol}' does not exist.`);
|
||||
if (user.can('bypassall')) {
|
||||
this.errorReply(`If you want to promote to a nonexistent group, use /forceroompromote`);
|
||||
}
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`Group '${nextSymbol}' does not exist.${user.can('bypassall') ? ` If you want to promote to a nonexistent group, use /forceroompromote.` : ''}`);
|
||||
} else if (!Users.Auth.isValidSymbol(nextSymbol)) {
|
||||
// yes I know this excludes astral-plane characters and includes combining characters
|
||||
return this.errorReply(`Admins can forcepromote to nonexistent groups only if they are one character long`);
|
||||
throw new Chat.ErrorMessage(`Admins can forcepromote to nonexistent groups only if they are one character long`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!force && (nextGroup.globalonly || (nextGroup.battleonly && !room.battle))) {
|
||||
return this.errorReply(`Group 'room${nextGroup.id || nextSymbol}' does not exist as a room rank.`);
|
||||
throw new Chat.ErrorMessage(`Group 'room${nextGroup.id || nextSymbol}' does not exist as a room rank.`);
|
||||
}
|
||||
const nextGroupName = nextGroup.name || "regular user";
|
||||
|
||||
|
|
@ -329,7 +325,7 @@ export const commands: Chat.ChatCommands = {
|
|||
let targetRoom = room;
|
||||
if (target) targetRoom = Rooms.search(target)!;
|
||||
if (!targetRoom?.checkModjoin(user)) {
|
||||
return this.errorReply(`The room "${target}" does not exist.`);
|
||||
throw new Chat.ErrorMessage(`The room "${target}" does not exist.`);
|
||||
}
|
||||
const showAll = user.can('mute', null, targetRoom);
|
||||
|
||||
|
|
@ -521,7 +517,7 @@ export const commands: Chat.ChatCommands = {
|
|||
Chat.handleRoomClose(target as RoomID, user, connection);
|
||||
return;
|
||||
}
|
||||
return this.errorReply(`The room '${target}' does not exist.`);
|
||||
throw new Chat.ErrorMessage(`The room '${target}' does not exist.`);
|
||||
}
|
||||
Chat.handleRoomClose(targetRoom.roomid, user, connection);
|
||||
user.leaveRoom(targetRoom, connection);
|
||||
|
|
@ -538,7 +534,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse('/help warn');
|
||||
this.checkChat();
|
||||
if (room?.settings.isPersonal && !user.can('warn' as any)) {
|
||||
return this.errorReply("Warning is unavailable in group chats.");
|
||||
throw new Chat.ErrorMessage("Warning is unavailable in group chats.");
|
||||
}
|
||||
// If used in pms, staff, help tickets or battles, log the warn to the global modlog.
|
||||
const globalWarn = (
|
||||
|
|
@ -552,7 +548,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const saveReplay = globalWarn && room?.battle;
|
||||
if (!targetUser?.connected) {
|
||||
if (!globalWarn) return this.errorReply(`User '${targetUsername}' not found.`);
|
||||
if (!globalWarn) throw new Chat.ErrorMessage(`User '${targetUsername}' not found.`);
|
||||
if (room) {
|
||||
this.checkCan('warn', null, room);
|
||||
} else {
|
||||
|
|
@ -568,23 +564,23 @@ export const commands: Chat.ChatCommands = {
|
|||
return;
|
||||
}
|
||||
if (!globalWarn && !(targetUser.id in room.users)) {
|
||||
return this.errorReply(`User ${targetUsername} is not in the room ${room.roomid}.`);
|
||||
throw new Chat.ErrorMessage(`User ${targetUsername} is not in the room ${room.roomid}.`);
|
||||
}
|
||||
if (publicReason.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
if (room) {
|
||||
this.checkCan('warn', targetUser, room);
|
||||
} else {
|
||||
this.checkCan('lock', targetUser);
|
||||
}
|
||||
if (targetUser.can('makeroom')) return this.errorReply("You are not allowed to warn upper staff members.");
|
||||
if (targetUser.can('makeroom')) throw new Chat.ErrorMessage("You are not allowed to warn upper staff members.");
|
||||
|
||||
const now = Date.now();
|
||||
const timeout = now - targetUser.lastWarnedAt;
|
||||
if (timeout < 15 * 1000) {
|
||||
const remainder = (15 - (timeout / 1000)).toFixed(2);
|
||||
return this.errorReply(`You must wait ${remainder} more seconds before you can warn ${targetUser.name} again.`);
|
||||
throw new Chat.ErrorMessage(`You must wait ${remainder} more seconds before you can warn ${targetUser.name} again.`);
|
||||
}
|
||||
|
||||
const logMessage = `${targetUser.name} was warned by ${user.name}.${(publicReason ? ` (${publicReason})` : ``)}`;
|
||||
|
|
@ -621,33 +617,32 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
if (!target) return this.parse('/help redirect');
|
||||
if (room.settings.isPrivate || room.settings.isPersonal) {
|
||||
return this.errorReply("Users cannot be redirected from private or personal rooms.");
|
||||
throw new Chat.ErrorMessage("Users cannot be redirected from private or personal rooms.");
|
||||
}
|
||||
const { targetUser, targetUsername, rest: targetRoomid } = this.splitUser(target);
|
||||
const targetRoom = Rooms.search(targetRoomid);
|
||||
if (!targetRoom || targetRoom.settings.modjoin || targetRoom.settings.staffRoom) {
|
||||
return this.errorReply(`The room "${targetRoomid}" does not exist.`);
|
||||
throw new Chat.ErrorMessage(`The room "${targetRoomid}" does not exist.`);
|
||||
}
|
||||
this.checkCan('warn', targetUser, room);
|
||||
this.checkCan('warn', targetUser, targetRoom);
|
||||
|
||||
if (!user.can('rangeban', targetUser)) {
|
||||
this.errorReply(`Redirects have been deprecated. Instead of /redirect, use <<room links>> or /invite to guide users to the correct room, and punish if users don't cooperate.`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`Redirects have been deprecated. Instead of /redirect, use <<room links>> or /invite to guide users to the correct room, and punish if users don't cooperate.`);
|
||||
}
|
||||
|
||||
if (!targetUser?.connected) {
|
||||
return this.errorReply(`User ${targetUsername} not found.`);
|
||||
throw new Chat.ErrorMessage(`User ${targetUsername} not found.`);
|
||||
}
|
||||
if (targetRoom.roomid === "global") return this.errorReply(`Users cannot be redirected to the global room.`);
|
||||
if (targetRoom.roomid === "global") throw new Chat.ErrorMessage(`Users cannot be redirected to the global room.`);
|
||||
if (targetRoom.settings.isPrivate || targetRoom.settings.isPersonal) {
|
||||
return this.errorReply(`The room "${targetRoom.title}" is not public.`);
|
||||
throw new Chat.ErrorMessage(`The room "${targetRoom.title}" is not public.`);
|
||||
}
|
||||
if (targetUser.inRooms.has(targetRoom.roomid)) {
|
||||
return this.errorReply(`User ${targetUser.name} is already in the room ${targetRoom.title}!`);
|
||||
throw new Chat.ErrorMessage(`User ${targetUser.name} is already in the room ${targetRoom.title}!`);
|
||||
}
|
||||
if (!targetUser.inRooms.has(room.roomid)) {
|
||||
return this.errorReply(`User ${targetUsername} is not in the room ${room.roomid}.`);
|
||||
throw new Chat.ErrorMessage(`User ${targetUsername} is not in the room ${room.roomid}.`);
|
||||
}
|
||||
targetUser.leaveRoom(room.roomid);
|
||||
targetUser.popup(`You are in the wrong room; please go to <<${targetRoom.roomid}>> instead`);
|
||||
|
|
@ -667,15 +662,15 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkChat();
|
||||
|
||||
const { targetUser, inputUsername, targetUsername, rest: reason } = this.splitUser(target);
|
||||
if (!targetUser) return this.errorReply(`User '${targetUsername}' not found.`);
|
||||
if (!targetUser) throw new Chat.ErrorMessage(`User '${targetUsername}' not found.`);
|
||||
if (reason.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
const { publicReason, privateReason } = this.parseSpoiler(reason);
|
||||
|
||||
const muteDuration = ((cmd === 'hm' || cmd === 'hourmute') ? HOURMUTE_LENGTH : MUTE_LENGTH);
|
||||
this.checkCan('mute', targetUser, room);
|
||||
if (targetUser.can('makeroom')) return this.errorReply("You are not allowed to mute upper staff members.");
|
||||
if (targetUser.can('makeroom')) throw new Chat.ErrorMessage("You are not allowed to mute upper staff members.");
|
||||
const canBeMutedFurther = ((room.getMuteTime(targetUser) || 0) <= (muteDuration * 5 / 6));
|
||||
if (targetUser.locked ||
|
||||
(room.isMuted(targetUser) && !canBeMutedFurther) ||
|
||||
|
|
@ -723,7 +718,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
if (!target) return this.parse('/help unmute');
|
||||
const { targetUser, targetUsername, rest } = this.splitUser(target);
|
||||
if (rest) return this.errorReply(`This command does not support specifying a reason.`);
|
||||
if (rest) throw new Chat.ErrorMessage(`This command does not support specifying a reason.`);
|
||||
this.checkChat();
|
||||
this.checkCan('mute', null, room);
|
||||
|
||||
|
|
@ -735,7 +730,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.addModAction(`${(targetUser ? targetUser.name : successfullyUnmuted)} was unmuted by ${user.name}.`);
|
||||
this.modlog('UNMUTE', (targetUser || successfullyUnmuted), null, { noip: 1, noalts: 1 });
|
||||
} else {
|
||||
this.errorReply(`${(targetUser ? targetUser.name : targetUsername)} is not muted.`);
|
||||
throw new Chat.ErrorMessage(`${(targetUser ? targetUser.name : targetUsername)} is not muted.`);
|
||||
}
|
||||
},
|
||||
unmutehelp: [`/unmute [username] - Removes mute from user. Requires: % @ # ~`],
|
||||
|
|
@ -758,14 +753,14 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const { targetUser, inputUsername, targetUsername, rest: reason } = this.splitUser(target);
|
||||
const { publicReason, privateReason } = this.parseSpoiler(reason);
|
||||
if (!targetUser) return this.errorReply(`User '${targetUsername}' not found.`);
|
||||
if (!targetUser) throw new Chat.ErrorMessage(`User '${targetUsername}' not found.`);
|
||||
if (reason.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
this.checkCan('ban', targetUser, room);
|
||||
if (targetUser.can('makeroom')) return this.errorReply("You are not allowed to ban upper staff members.");
|
||||
if (targetUser.can('makeroom')) throw new Chat.ErrorMessage("You are not allowed to ban upper staff members.");
|
||||
if (Punishments.hasRoomPunishType(room, toID(targetUsername), 'BLACKLIST')) {
|
||||
return this.errorReply(`This user is already blacklisted from ${room.roomid}.`);
|
||||
throw new Chat.ErrorMessage(`This user is already blacklisted from ${room.roomid}.`);
|
||||
}
|
||||
const name = targetUser.getLastName();
|
||||
const userid = targetUser.getLastId();
|
||||
|
|
@ -777,7 +772,7 @@ export const commands: Chat.ChatCommands = {
|
|||
);
|
||||
}
|
||||
} else if (force) {
|
||||
return this.errorReply(`Use /${week ? 'week' : 'room'}ban; ${name} is not a trusted user.`);
|
||||
throw new Chat.ErrorMessage(`Use /${week ? 'week' : 'room'}ban; ${name} is not a trusted user.`);
|
||||
}
|
||||
if (!reason && !week && Punishments.isRoomBanned(targetUser, room.roomid)) {
|
||||
const problem = " but was already banned";
|
||||
|
|
@ -847,7 +842,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.globalModlog("UNROOMBAN", name);
|
||||
}
|
||||
} else {
|
||||
this.errorReply(`User '${target}' is not banned from this room.`);
|
||||
throw new Chat.ErrorMessage(`User '${target}' is not banned from this room.`);
|
||||
}
|
||||
},
|
||||
unbanhelp: [`/unban [username] - Unbans the user from the room you are in. Requires: @ # ~`],
|
||||
|
|
@ -874,12 +869,12 @@ export const commands: Chat.ChatCommands = {
|
|||
let userid: ID = toID(targetUsername);
|
||||
|
||||
if (!targetUser && !Punishments.search(userid).length && !force) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`User '${targetUsername}' not found. Use \`\`/force${month ? 'month' : (week ? 'week' : '')}lock\`\` if you need to to lock them anyway.`
|
||||
);
|
||||
}
|
||||
if (reason.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
this.checkCan('lock', userid);
|
||||
if (month) this.checkCan('rangeban');
|
||||
|
|
@ -907,7 +902,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.sendReply(`${name} is a trusted user. If you are sure you would like to lock them use /force${month ? 'month' : (week ? 'week' : '')}lock.`);
|
||||
}
|
||||
} else if (force && targetUser) {
|
||||
return this.errorReply(`Use /lock; ${name} is not a trusted user and is online.`);
|
||||
throw new Chat.ErrorMessage(`Use /lock; ${name} is not a trusted user and is online.`);
|
||||
}
|
||||
|
||||
const { privateReason, publicReason } = this.parseSpoiler(reason);
|
||||
|
|
@ -985,7 +980,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const targetUser = Users.get(target);
|
||||
if (targetUser?.namelocked) {
|
||||
return this.errorReply(`User ${targetUser.name} is namelocked, not locked. Use /unnamelock to unnamelock them.`);
|
||||
throw new Chat.ErrorMessage(`User ${targetUser.name} is namelocked, not locked. Use /unnamelock to unnamelock them.`);
|
||||
}
|
||||
let reason = '';
|
||||
if (targetUser?.locked && targetUser.locked.startsWith('#')) {
|
||||
|
|
@ -999,7 +994,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!reason) this.globalModlog("UNLOCK", toID(target));
|
||||
if (targetUser) targetUser.popup(`${user.name} has unlocked you.`);
|
||||
} else {
|
||||
this.errorReply(`User '${target}' is not locked.`);
|
||||
throw new Chat.ErrorMessage(`User '${target}' is not locked.`);
|
||||
}
|
||||
},
|
||||
unlockname(target, room, user) {
|
||||
|
|
@ -1008,12 +1003,12 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const userid = toID(target);
|
||||
if (userid.startsWith('guest')) {
|
||||
return this.errorReply(`You cannot unlock the guest userid - provide their original username instead.`);
|
||||
throw new Chat.ErrorMessage(`You cannot unlock the guest userid - provide their original username instead.`);
|
||||
}
|
||||
const punishment = Punishments.userids.getByType(userid, 'LOCK') || Punishments.userids.getByType(userid, 'NAMELOCK');
|
||||
if (!punishment) return this.errorReply("This name isn't locked.");
|
||||
if (!punishment) throw new Chat.ErrorMessage("This name isn't locked.");
|
||||
if (punishment.id === userid || Users.get(userid)?.previousIDs.includes(punishment.id as ID)) {
|
||||
return this.errorReply(`"${userid}" was specifically locked by a staff member (check the global modlog). Use /unlock if you really want to unlock this name.`);
|
||||
throw new Chat.ErrorMessage(`"${userid}" was specifically locked by a staff member (check the global modlog). Use /unlock if you really want to unlock this name.`);
|
||||
}
|
||||
Punishments.userids.delete(userid);
|
||||
Punishments.savePunishments();
|
||||
|
|
@ -1041,11 +1036,11 @@ export const commands: Chat.ChatCommands = {
|
|||
if (range) this.checkCan('rangeban');
|
||||
|
||||
if (!(range ? IPTools.ipRangeRegex : IPTools.ipRegex).test(target)) {
|
||||
return this.errorReply("Please enter a valid IP address.");
|
||||
throw new Chat.ErrorMessage("Please enter a valid IP address.");
|
||||
}
|
||||
|
||||
const punishment = Punishments.ips.get(target);
|
||||
if (!punishment) return this.errorReply(`${target} is not a locked/banned IP or IP range.`);
|
||||
if (!punishment) throw new Chat.ErrorMessage(`${target} is not a locked/banned IP or IP range.`);
|
||||
|
||||
Punishments.ips.delete(target);
|
||||
Punishments.savePunishments();
|
||||
|
|
@ -1086,13 +1081,13 @@ export const commands: Chat.ChatCommands = {
|
|||
let userid: ID = toID(targetUsername);
|
||||
|
||||
if (!targetUser && !force) {
|
||||
return this.errorReply(`User '${targetUsername}' not found. Use /forceglobalban to ban them anyway.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUsername}' not found. Use /forceglobalban to ban them anyway.`);
|
||||
}
|
||||
if (reason.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
if (!reason && REQUIRE_REASONS) {
|
||||
return this.errorReply("Global bans require a reason.");
|
||||
throw new Chat.ErrorMessage("Global bans require a reason.");
|
||||
}
|
||||
this.checkCan('globalban', targetUser);
|
||||
let name;
|
||||
|
|
@ -1168,7 +1163,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const name = Punishments.unban(target);
|
||||
|
||||
if (!name) {
|
||||
return this.errorReply(`User '${target}' is not globally banned.`);
|
||||
throw new Chat.ErrorMessage(`User '${target}' is not globally banned.`);
|
||||
}
|
||||
|
||||
this.addGlobalModAction(`${name} was globally unbanned by ${user.name}.`);
|
||||
|
|
@ -1179,12 +1174,11 @@ export const commands: Chat.ChatCommands = {
|
|||
deroomvoiceall(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('editroom', null, room);
|
||||
if (!room.auth.size) return this.errorReply("Room does not have roomauth.");
|
||||
if (!room.auth.size) throw new Chat.ErrorMessage("Room does not have roomauth.");
|
||||
if (!target) {
|
||||
user.lastCommand = '/deroomvoiceall';
|
||||
this.errorReply("THIS WILL DEROOMVOICE ALL ROOMVOICED USERS.");
|
||||
this.errorReply("To confirm, use: /deroomvoiceall confirm");
|
||||
return;
|
||||
throw new Chat.ErrorMessage(["THIS WILL DEROOMVOICE ALL ROOMVOICED USERS.",
|
||||
"To confirm, use: /deroomvoiceall confirm"]);
|
||||
}
|
||||
if (user.lastCommand !== '/deroomvoiceall' || target !== 'confirm') {
|
||||
return this.parse('/help deroomvoiceall');
|
||||
|
|
@ -1263,7 +1257,7 @@ export const commands: Chat.ChatCommands = {
|
|||
banip(target, room, user, connection, cmd) {
|
||||
const [ip, reason] = this.splitOne(target);
|
||||
if (!ip || !/^[0-9.]+(?:\.\*)?$/.test(ip)) return this.parse('/help banip');
|
||||
if (!reason) return this.errorReply("/banip requires a ban reason");
|
||||
if (!reason) throw new Chat.ErrorMessage("/banip requires a ban reason");
|
||||
|
||||
this.checkCan('rangeban');
|
||||
const ipDesc = `IP ${(ip.endsWith('*') ? `range ` : ``)}${ip}`;
|
||||
|
|
@ -1273,7 +1267,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const curPunishment = Punishments.ipSearch(ip, 'BAN');
|
||||
if (curPunishment?.type === 'BAN' && !time) {
|
||||
return this.errorReply(`The ${ipDesc} is already temporarily banned.`);
|
||||
throw new Chat.ErrorMessage(`The ${ipDesc} is already temporarily banned.`);
|
||||
}
|
||||
Punishments.punishRange(ip, reason, time, 'BAN');
|
||||
|
||||
|
|
@ -1304,7 +1298,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
this.checkCan('rangeban');
|
||||
if (!Punishments.ips.has(target)) {
|
||||
return this.errorReply(`${target} is not a locked/banned IP or IP range.`);
|
||||
throw new Chat.ErrorMessage(`${target} is not a locked/banned IP or IP range.`);
|
||||
}
|
||||
Punishments.ips.delete(target);
|
||||
|
||||
|
|
@ -1324,11 +1318,11 @@ export const commands: Chat.ChatCommands = {
|
|||
const targetUser = Users.get(targetUsername);
|
||||
const targetUserid = toID(targetUsername);
|
||||
if (!targetUserid || targetUserid.length > 18) {
|
||||
return this.errorReply(`Invalid userid.`);
|
||||
throw new Chat.ErrorMessage(`Invalid userid.`);
|
||||
}
|
||||
const force = this.cmd.includes('force');
|
||||
if (targetUser?.registered && !force) {
|
||||
return this.errorReply(`That user is registered. Either permalock them normally or use /forceyearlockname.`);
|
||||
throw new Chat.ErrorMessage(`That user is registered. Either permalock them normally or use /forceyearlockname.`);
|
||||
}
|
||||
const punishment = {
|
||||
type: 'YEARLOCK',
|
||||
|
|
@ -1351,7 +1345,7 @@ export const commands: Chat.ChatCommands = {
|
|||
lockip(target, room, user, connection, cmd) {
|
||||
const [ip, reason] = this.splitOne(target);
|
||||
if (!ip || !/^[0-9.]+(?:\.\*)?$/.test(ip)) return this.parse('/help lockip');
|
||||
if (!reason) return this.errorReply("/lockip requires a lock reason");
|
||||
if (!reason) throw new Chat.ErrorMessage("/lockip requires a lock reason");
|
||||
|
||||
this.checkCan('rangeban');
|
||||
const ipDesc = ip.endsWith('*') ? `IP range ${ip}` : `IP ${ip}`;
|
||||
|
|
@ -1360,7 +1354,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const curPunishment = Punishments.byWeight(Punishments.ipSearch(ip) || [])[0];
|
||||
if (!year && curPunishment && (curPunishment.type === 'BAN' || curPunishment.type === 'LOCK')) {
|
||||
const punishDesc = curPunishment.type === 'BAN' ? `temporarily banned` : `temporarily locked`;
|
||||
return this.errorReply(`The ${ipDesc} is already ${punishDesc}.`);
|
||||
throw new Chat.ErrorMessage(`The ${ipDesc} is already ${punishDesc}.`);
|
||||
}
|
||||
|
||||
const time = year ? Date.now() + 365 * 24 * 60 * 60 * 1000 : null;
|
||||
|
|
@ -1393,7 +1387,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkChat();
|
||||
|
||||
if (target.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The note is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The note is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
this.checkCan('receiveauthmessages', null, room);
|
||||
target = target.replace(/\n/g, "; ");
|
||||
|
|
@ -1446,42 +1440,40 @@ export const commands: Chat.ChatCommands = {
|
|||
let nextGroup = nextGroupName as GroupSymbol;
|
||||
if (nextGroupName === 'deauth') nextGroup = Users.Auth.defaultSymbol();
|
||||
if (!nextGroup) {
|
||||
return this.errorReply("Please specify a group such as /globalvoice or /globaldeauth");
|
||||
throw new Chat.ErrorMessage("Please specify a group such as /globalvoice or /globaldeauth");
|
||||
}
|
||||
if (!Config.groups[nextGroup]) {
|
||||
return this.errorReply(`Group '${nextGroup}' does not exist.`);
|
||||
throw new Chat.ErrorMessage(`Group '${nextGroup}' does not exist.`);
|
||||
}
|
||||
if (!cmd.startsWith('global')) {
|
||||
let groupid = Config.groups[nextGroup].id;
|
||||
if (!groupid && nextGroup === Users.Auth.defaultSymbol()) groupid = 'deauth' as ID;
|
||||
if (Config.groups[nextGroup].globalonly) return this.errorReply(`Did you mean "/global${groupid}"?`);
|
||||
if (Config.groups[nextGroup].roomonly) return this.errorReply(`Did you mean "/room${groupid}"?`);
|
||||
return this.errorReply(`Did you mean "/room${groupid}" or "/global${groupid}"?`);
|
||||
if (Config.groups[nextGroup].globalonly) throw new Chat.ErrorMessage(`Did you mean "/global${groupid}"?`);
|
||||
if (Config.groups[nextGroup].roomonly) throw new Chat.ErrorMessage(`Did you mean "/room${groupid}"?`);
|
||||
throw new Chat.ErrorMessage(`Did you mean "/room${groupid}" or "/global${groupid}"?`);
|
||||
}
|
||||
if (Config.groups[nextGroup].roomonly || Config.groups[nextGroup].battleonly) {
|
||||
return this.errorReply(`Group '${nextGroup}' does not exist as a global rank.`);
|
||||
throw new Chat.ErrorMessage(`Group '${nextGroup}' does not exist as a global rank.`);
|
||||
}
|
||||
|
||||
const groupName = Config.groups[nextGroup].name || "regular user";
|
||||
if (currentGroup === nextGroup) {
|
||||
return this.errorReply(`User '${name}' is already a ${groupName}`);
|
||||
throw new Chat.ErrorMessage(`User '${name}' is already a ${groupName}`);
|
||||
}
|
||||
if (!Users.Auth.hasPermission(user, 'promote', currentGroup)) {
|
||||
this.errorReply(`/${cmd} - Access denied for promoting from ${currentGroup}`);
|
||||
this.errorReply(`You can only promote to/from: ${Users.Auth.listJurisdiction(user, 'promote')}`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage([`/${cmd} - Access denied for promoting from ${currentGroup}`,
|
||||
`You can only promote to/from: ${Users.Auth.listJurisdiction(user, 'promote')}`]);
|
||||
}
|
||||
if (!Users.Auth.hasPermission(user, 'promote', nextGroup)) {
|
||||
this.errorReply(`/${cmd} - Access denied for promoting to ${groupName}`);
|
||||
this.errorReply(`You can only promote to/from: ${Users.Auth.listJurisdiction(user, 'promote')}`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage([`/${cmd} - Access denied for promoting to ${groupName}`,
|
||||
`You can only promote to/from: ${Users.Auth.listJurisdiction(user, 'promote')}`]);
|
||||
}
|
||||
|
||||
if (!Users.isUsernameKnown(userid)) {
|
||||
return this.errorReply(`/globalpromote - WARNING: '${name}' is offline and unrecognized. The username might be misspelled (either by you or the person who told you) or unregistered. Use /forcepromote if you're sure you want to risk it.`);
|
||||
throw new Chat.ErrorMessage(`/globalpromote - WARNING: '${name}' is offline and unrecognized. The username might be misspelled (either by you or the person who told you) or unregistered. Use /forcepromote if you're sure you want to risk it.`);
|
||||
}
|
||||
if (targetUser && !targetUser.registered) {
|
||||
return this.errorReply(`User '${name}' is unregistered, and so can't be promoted.`);
|
||||
throw new Chat.ErrorMessage(`User '${name}' is unregistered, and so can't be promoted.`);
|
||||
}
|
||||
if (nextGroup === Users.Auth.defaultSymbol()) {
|
||||
Users.globalAuth.delete(targetUser ? targetUser.id : userid);
|
||||
|
|
@ -1520,7 +1512,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const force = cmd.includes('force');
|
||||
const untrust = cmd.includes('un');
|
||||
const { targetUser, targetUsername, rest } = this.splitUser(target, { exactName: true });
|
||||
if (rest) return this.errorReply(`This command does not support specifying a reason.`);
|
||||
if (rest) throw new Chat.ErrorMessage(`This command does not support specifying a reason.`);
|
||||
const userid = toID(targetUsername);
|
||||
const name = targetUser?.name || targetUsername;
|
||||
|
||||
|
|
@ -1528,15 +1520,15 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
if (untrust) {
|
||||
if (currentGroup !== Users.Auth.defaultSymbol()) {
|
||||
return this.errorReply(`User '${name}' is trusted indirectly through global rank ${currentGroup}. Demote them from that rank to remove trusted status.`);
|
||||
throw new Chat.ErrorMessage(`User '${name}' is trusted indirectly through global rank ${currentGroup}. Demote them from that rank to remove trusted status.`);
|
||||
}
|
||||
const trustedSourceRooms = Rooms.global.chatRooms
|
||||
.filter(authRoom => authRoom.persist && authRoom.settings.isPrivate !== true && authRoom.auth.isStaff(userid))
|
||||
.map(authRoom => authRoom.auth.get(userid) + authRoom.roomid).join(' ');
|
||||
if (trustedSourceRooms.length && !Users.globalAuth.has(userid)) {
|
||||
return this.errorReply(`User '${name}' is trusted indirectly through room ranks ${trustedSourceRooms}. Demote them from those ranks to remove trusted status.`);
|
||||
throw new Chat.ErrorMessage(`User '${name}' is trusted indirectly through room ranks ${trustedSourceRooms}. Demote them from those ranks to remove trusted status.`);
|
||||
}
|
||||
if (!Users.globalAuth.has(userid)) return this.errorReply(`User '${name}' is not trusted.`);
|
||||
if (!Users.globalAuth.has(userid)) throw new Chat.ErrorMessage(`User '${name}' is not trusted.`);
|
||||
|
||||
if (targetUser) {
|
||||
targetUser.setGroup(Users.Auth.defaultSymbol());
|
||||
|
|
@ -1547,11 +1539,11 @@ export const commands: Chat.ChatCommands = {
|
|||
this.privateGlobalModAction(`${name} was set to no longer be a trusted user by ${user.name}.`);
|
||||
this.globalModlog('UNTRUSTUSER', userid);
|
||||
} else {
|
||||
if (!targetUser && !force) return this.errorReply(`User '${name}' is offline. Use /force${cmd} if you're sure.`);
|
||||
if (!targetUser && !force) throw new Chat.ErrorMessage(`User '${name}' is offline. Use /force${cmd} if you're sure.`);
|
||||
if (currentGroup) {
|
||||
if (Users.globalAuth.has(userid)) {
|
||||
if (currentGroup === Users.Auth.defaultSymbol()) return this.errorReply(`User '${name}' is already trusted.`);
|
||||
return this.errorReply(`User '${name}' has a global rank higher than trusted.`);
|
||||
if (currentGroup === Users.Auth.defaultSymbol()) throw new Chat.ErrorMessage(`User '${name}' is already trusted.`);
|
||||
throw new Chat.ErrorMessage(`User '${name}' has a global rank higher than trusted.`);
|
||||
}
|
||||
}
|
||||
if (targetUser) {
|
||||
|
|
@ -1630,13 +1622,13 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!name) return;
|
||||
name = name.slice(0, 18);
|
||||
const nextGroup = nextGroupName as GroupSymbol;
|
||||
if (!Config.groups[nextGroup]) return this.errorReply(`Group '${nextGroup}' does not exist.`);
|
||||
if (!Config.groups[nextGroup]) throw new Chat.ErrorMessage(`Group '${nextGroup}' does not exist.`);
|
||||
if (Config.groups[nextGroup].roomonly || Config.groups[nextGroup].battleonly) {
|
||||
return this.errorReply(`Group '${nextGroup}' does not exist as a global rank.`);
|
||||
throw new Chat.ErrorMessage(`Group '${nextGroup}' does not exist as a global rank.`);
|
||||
}
|
||||
|
||||
if (Users.isUsernameKnown(name)) {
|
||||
return this.errorReply("/forcepromote - Don't forcepromote unless you have to.");
|
||||
throw new Chat.ErrorMessage("/forcepromote - Don't forcepromote unless you have to.");
|
||||
}
|
||||
Users.globalAuth.set(name as ID, nextGroup);
|
||||
|
||||
|
|
@ -1669,7 +1661,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('declare', null, room);
|
||||
this.checkChat();
|
||||
if (target.length > 2000) return this.errorReply("Declares should not exceed 2000 characters.");
|
||||
if (target.length > 2000) throw new Chat.ErrorMessage("Declares should not exceed 2000 characters.");
|
||||
|
||||
for (const id in room.users) {
|
||||
room.users[id].sendTo(room, `|notify|${room.title} announcement!|${target}`);
|
||||
|
|
@ -1745,7 +1737,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkChat();
|
||||
let [rank, titleNotification] = this.splitOne(target);
|
||||
if (rank === 'all') rank = ` `;
|
||||
if (!(rank in Config.groups)) return this.errorReply(`Group '${rank}' does not exist.`);
|
||||
if (!(rank in Config.groups)) throw new Chat.ErrorMessage(`Group '${rank}' does not exist.`);
|
||||
const id = `${room.roomid}-rank-${(Config.groups[rank].id || `all`)}`;
|
||||
if (cmd === 'notifyoffrank') {
|
||||
if (rank === ' ') {
|
||||
|
|
@ -1760,7 +1752,7 @@ export const commands: Chat.ChatCommands = {
|
|||
title += ` (notification from ${user.name})`;
|
||||
}
|
||||
const [notification, highlight] = this.splitOne(notificationHighlight);
|
||||
if (notification.length > 300) return this.errorReply(`Notifications should not exceed 300 characters.`);
|
||||
if (notification.length > 300) throw new Chat.ErrorMessage(`Notifications should not exceed 300 characters.`);
|
||||
const message = `|tempnotify|${id}|${title}|${notification}${(highlight ? `|${highlight}` : ``)}`;
|
||||
if (rank === ' ') {
|
||||
room.send(message);
|
||||
|
|
@ -1782,7 +1774,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('addhtml', null, room);
|
||||
this.checkChat();
|
||||
const { targetUser, targetUsername, rest: titleNotification } = this.splitUser(target);
|
||||
if (!targetUser?.connected) return this.errorReply(`User '${targetUsername}' not found.`);
|
||||
if (!targetUser?.connected) throw new Chat.ErrorMessage(`User '${targetUsername}' not found.`);
|
||||
const id = `${room.roomid}-user-${toID(targetUsername)}`;
|
||||
if (cmd === 'notifyoffuser') {
|
||||
room.sendUser(targetUser, `|tempnotifyoff|${id}`);
|
||||
|
|
@ -1793,7 +1785,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!user.can('addhtml')) {
|
||||
title += ` (notification from ${user.name})`;
|
||||
}
|
||||
if (notification.length > 300) return this.errorReply(`Notifications should not exceed 300 characters.`);
|
||||
if (notification.length > 300) throw new Chat.ErrorMessage(`Notifications should not exceed 300 characters.`);
|
||||
const message = `|tempnotify|${id}|${title}|${notification}`;
|
||||
room.sendUser(targetUser, message);
|
||||
this.sendReply(`Sent a notification to ${targetUser.name}.`);
|
||||
|
|
@ -1817,16 +1809,16 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!targetUser && !offline) {
|
||||
const { targetUser: targetUserInexact, inputUsername } = this.splitUser(target);
|
||||
if (targetUserInexact) {
|
||||
return this.errorReply(`User has already changed their name to '${targetUserInexact.name}'.`);
|
||||
throw new Chat.ErrorMessage(`User has already changed their name to '${targetUserInexact.name}'.`);
|
||||
}
|
||||
return this.errorReply(`User '${inputUsername}' not found. (use /offlineforcerename to rename anyway.)`);
|
||||
throw new Chat.ErrorMessage(`User '${inputUsername}' not found. (use /offlineforcerename to rename anyway.)`);
|
||||
}
|
||||
if (Punishments.namefilterwhitelist.has(targetID)) {
|
||||
this.errorReply(`That name is blocked from being forcerenamed.`);
|
||||
const errorMessage = [`That name is blocked from being forcerenamed.`];
|
||||
if (user.can('bypassall')) {
|
||||
this.errorReply(`Use /noforcerename remove to remove it from the list if you wish to rename it.`);
|
||||
errorMessage.push(`Use /noforcerename remove to remove it from the list if you wish to rename it.`);
|
||||
}
|
||||
return false;
|
||||
throw new Chat.ErrorMessage(errorMessage);
|
||||
}
|
||||
this.checkCan('forcerename', targetID);
|
||||
const { publicReason, privateReason } = this.parseSpoiler(reason);
|
||||
|
|
@ -1877,7 +1869,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!targetId) return this.parse('/help noforcerename');
|
||||
this.checkCan('bypassall');
|
||||
if (!Punishments.whitelistName(targetId, user.name)) {
|
||||
return this.errorReply(`${targetUsername} is already on the noforcerename list.`);
|
||||
throw new Chat.ErrorMessage(`${targetUsername} is already on the noforcerename list.`);
|
||||
}
|
||||
this.addGlobalModAction(`${user.name} added the name ${targetId} to the no forcerename list.${rest ? ` (${rest})` : ''}`);
|
||||
this.globalModlog('NOFORCERENAME', targetId, rest);
|
||||
|
|
@ -1888,7 +1880,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!targetId) return this.parse('/help noforcerename');
|
||||
this.checkCan('bypassall');
|
||||
if (!Punishments.namefilterwhitelist.has(targetId)) {
|
||||
return this.errorReply(`${targetUsername} is not on the noforcerename list.`);
|
||||
throw new Chat.ErrorMessage(`${targetUsername} is not on the noforcerename list.`);
|
||||
}
|
||||
Punishments.unwhitelistName(targetId);
|
||||
this.addGlobalModAction(`${user.name} removed ${targetId} from the no forcerename list.${rest ? ` (${rest})` : ''}`);
|
||||
|
|
@ -1904,7 +1896,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const { targetUser, rest: reason } = this.requireUser(target, { allowOffline: true });
|
||||
this.checkCan('forcerename', targetUser);
|
||||
|
||||
if (!targetUser.userMessage) return this.errorReply(this.tr`${targetUser.name} does not have a status set.`);
|
||||
if (!targetUser.userMessage) throw new Chat.ErrorMessage(this.tr`${targetUser.name} does not have a status set.`);
|
||||
|
||||
const displayReason = reason ? `: ${reason}` : ``;
|
||||
this.privateGlobalModAction(this.tr`${targetUser.name}'s status "${targetUser.userMessage}" was cleared by ${user.name}${displayReason}.`);
|
||||
|
|
@ -1928,24 +1920,26 @@ export const commands: Chat.ChatCommands = {
|
|||
const userid = toID(targetUsername);
|
||||
|
||||
if (!targetUser && !force) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`User '${targetUsername}' not found. Use \`\`/force${week ? 'week' : ''}namelock\`\` if you need to namelock them anyway.`
|
||||
);
|
||||
}
|
||||
if (targetUser && targetUser.id !== toID(inputUsername) && !force) {
|
||||
return this.errorReply(`${inputUsername} has already changed their name to ${targetUser.name}. To namelock anyway, use /force${week ? 'week' : ''}namelock.`);
|
||||
throw new Chat.ErrorMessage(`${inputUsername} has already changed their name to ${targetUser.name}. To namelock anyway, use /force${week ? 'week' : ''}namelock.`);
|
||||
}
|
||||
this.checkCan('forcerename', userid);
|
||||
if (targetUser?.namelocked && !week) {
|
||||
return this.errorReply(`User '${targetUser.name}' is already namelocked.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' is already namelocked.`);
|
||||
}
|
||||
if (!force && !week) {
|
||||
const existingPunishments = Punishments.search(userid);
|
||||
for (const [,, punishment] of existingPunishments) {
|
||||
if (punishment.type === 'LOCK' && (punishment.expireTime - Date.now()) > (2 * DAY)) {
|
||||
this.errorReply(`User '${userid}' is already normally locked for more than 2 days.`);
|
||||
this.errorReply(`Use /weeknamelock to namelock them instead, so you don't decrease the existing punishment.`);
|
||||
return this.errorReply(`If you really need to override this, use /forcenamelock.`);
|
||||
throw new Chat.ErrorMessage([
|
||||
`User '${userid}' is already normally locked for more than 2 days.`,
|
||||
`Use /weeknamelock to namelock them instead, so you don't decrease the existing punishment.`,
|
||||
`If you really need to override this, use /forcenamelock.`,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1997,7 +1991,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const unlocked = Punishments.unnamelock(target);
|
||||
|
||||
if (!unlocked) {
|
||||
return this.errorReply(`User '${target}' is not namelocked.`);
|
||||
throw new Chat.ErrorMessage(`User '${target}' is not namelocked.`);
|
||||
}
|
||||
|
||||
this.addGlobalModAction(`${unlocked} was unnamelocked by ${user.name}.${reason}`);
|
||||
|
|
@ -2032,22 +2026,22 @@ export const commands: Chat.ChatCommands = {
|
|||
[lineCountString, reason] = Utils.splitFirst(reason, ',').map(p => p.trim());
|
||||
lineCount = parseInt(lineCountString);
|
||||
} else if (!cmd.includes('force')) {
|
||||
return this.errorReply(`Your reason was a number; use /hidelines if you wanted to clear a specific number of lines, or /forcehidetext if you really wanted your reason to be a number.`);
|
||||
throw new Chat.ErrorMessage(`Your reason was a number; use /hidelines if you wanted to clear a specific number of lines, or /forcehidetext if you really wanted your reason to be a number.`);
|
||||
}
|
||||
}
|
||||
const showAlts = cmd.includes('alt');
|
||||
if (!lineCount && hasLineCount) {
|
||||
return this.errorReply(`You must specify a number of messages to clear. To clear all messages, use /hidetext.`);
|
||||
throw new Chat.ErrorMessage(`You must specify a number of messages to clear. To clear all messages, use /hidetext.`);
|
||||
}
|
||||
if (reason.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
|
||||
if (!targetUser && !room.log.hasUsername(name)) {
|
||||
return this.errorReply(`User ${name} not found or has no roomlogs.`);
|
||||
throw new Chat.ErrorMessage(`User ${name} not found or has no roomlogs.`);
|
||||
}
|
||||
if (lineCount && showAlts) {
|
||||
return this.errorReply(`You can't specify a line count when using /hidealtstext.`);
|
||||
throw new Chat.ErrorMessage(`You can't specify a line count when using /hidealtstext.`);
|
||||
}
|
||||
const userid = toID(inputUsername);
|
||||
|
||||
|
|
@ -2099,20 +2093,20 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
if (!target) return this.parse('/help blacklist');
|
||||
this.checkChat();
|
||||
if (toID(target) === 'show') return this.errorReply(`You're looking for /showbl`);
|
||||
if (toID(target) === 'show') throw new Chat.ErrorMessage(`You're looking for /showbl`);
|
||||
|
||||
const { targetUser, targetUsername, rest: reason } = this.splitUser(target);
|
||||
if (!targetUser) {
|
||||
this.errorReply(`User ${targetUsername} not found.`);
|
||||
return this.errorReply(`If you want to blacklist an offline account by name (not IP), consider /blacklistname`);
|
||||
throw new Chat.ErrorMessage([`User ${targetUsername} not found.`,
|
||||
`If you want to blacklist an offline account by name (not IP), consider /blacklistname`]);
|
||||
}
|
||||
this.checkCan('editroom', targetUser, room);
|
||||
if (!room.persist) {
|
||||
return this.errorReply(`This room is not going to last long enough for a blacklist to matter - just ban the user`);
|
||||
throw new Chat.ErrorMessage(`This room is not going to last long enough for a blacklist to matter - just ban the user`);
|
||||
}
|
||||
const punishment = Punishments.isRoomBanned(targetUser, room.roomid);
|
||||
if (punishment && punishment.type === 'BLACKLIST') {
|
||||
return this.errorReply(`This user is already blacklisted from this room.`);
|
||||
throw new Chat.ErrorMessage(`This user is already blacklisted from this room.`);
|
||||
}
|
||||
const force = cmd === 'forceblacklist' || cmd === 'forcebl';
|
||||
if (targetUser.trusted) {
|
||||
|
|
@ -2122,13 +2116,13 @@ export const commands: Chat.ChatCommands = {
|
|||
);
|
||||
}
|
||||
} else if (force) {
|
||||
return this.errorReply(`Use /blacklist; ${targetUser.name} is not a trusted user.`);
|
||||
throw new Chat.ErrorMessage(`Use /blacklist; ${targetUser.name} is not a trusted user.`);
|
||||
}
|
||||
if (!reason && REQUIRE_REASONS) {
|
||||
return this.errorReply(`Blacklists require a reason.`);
|
||||
throw new Chat.ErrorMessage(`Blacklists require a reason.`);
|
||||
}
|
||||
if (reason.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
const name = targetUser.getLastName();
|
||||
const userid = targetUser.getLastId();
|
||||
|
|
@ -2189,29 +2183,30 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse(`/help battleban`);
|
||||
|
||||
const { targetUser, targetUsername, rest: reason } = this.splitUser(target);
|
||||
if (!targetUser) return this.errorReply(`User ${targetUsername} not found.`);
|
||||
if (!targetUser) throw new Chat.ErrorMessage(`User ${targetUsername} not found.`);
|
||||
if (target.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
if (!reason) {
|
||||
return this.errorReply(`Battle bans require a reason.`);
|
||||
throw new Chat.ErrorMessage(`Battle bans require a reason.`);
|
||||
}
|
||||
const includesUrl = reason.includes(`.${Config.routes.root}/`); // lgtm [js/incomplete-url-substring-sanitization]
|
||||
if (!room.battle && !includesUrl && cmd !== 'forcebattleban') {
|
||||
return this.errorReply(`Battle bans require a battle replay if used outside of a battle; if the battle has expired, use /forcebattleban.`);
|
||||
throw new Chat.ErrorMessage(`Battle bans require a battle replay if used outside of a battle; if the battle has expired, use /forcebattleban.`);
|
||||
}
|
||||
if (!user.can('rangeban', targetUser)) {
|
||||
this.errorReply(`Battlebans have been deprecated. Alternatives:`);
|
||||
this.errorReply(`- timerstalling and bragging about it: lock`);
|
||||
this.errorReply(`- other timerstalling: they're not timerstalling, leave them alone`);
|
||||
this.errorReply(`- bad nicknames: lock, locks prevent nicknames from appearing; you should always have been locking for this`);
|
||||
this.errorReply(`- ladder cheating: gban, get a moderator if necessary`);
|
||||
this.errorReply(`- serious ladder cheating: permaban, get an administrator`);
|
||||
this.errorReply(`- other: get an administrator`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage([
|
||||
`Battlebans have been deprecated. Alternatives:`,
|
||||
`- timerstalling and bragging about it: lock`,
|
||||
`- other timerstalling: they're not timerstalling, leave them alone`,
|
||||
`- bad nicknames: lock, locks prevent nicknames from appearing; you should always have been locking for this`,
|
||||
`- ladder cheating: gban, get a moderator if necessary`,
|
||||
`- serious ladder cheating: permaban, get an administrator`,
|
||||
`- other: get an administrator`,
|
||||
]);
|
||||
}
|
||||
if (Punishments.isBattleBanned(targetUser)) {
|
||||
return this.errorReply(`User '${targetUser.name}' is already banned from battling.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' is already banned from battling.`);
|
||||
}
|
||||
this.privateGlobalModAction(`${targetUser.name} was banned from starting new battles by ${user.name} (${reason})`);
|
||||
|
||||
|
|
@ -2245,7 +2240,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.globalModlog("UNBATTLEBAN", toID(target));
|
||||
if (targetUser) targetUser.popup(`${user.name} has allowed you to battle again.`);
|
||||
} else {
|
||||
this.errorReply(`User ${target} is not banned from battling.`);
|
||||
throw new Chat.ErrorMessage(`User ${target} is not banned from battling.`);
|
||||
}
|
||||
},
|
||||
unbattlebanhelp: [`/unbattleban [username] - [DEPRECATED] Allows a user to battle again. Requires: % @ ~`],
|
||||
|
|
@ -2257,22 +2252,20 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
if (!target) return this.parse(`/help groupchatban`);
|
||||
if (!user.can('rangeban')) {
|
||||
return this.errorReply(
|
||||
`/groupchatban has been deprecated.\n` +
|
||||
`For future groupchat misuse, lock the creator, it will take away their trusted status and their ability to make groupchats.`
|
||||
);
|
||||
throw new Chat.ErrorMessage([`/groupchatban has been deprecated.`,
|
||||
`For future groupchat misuse, lock the creator, it will take away their trusted status and their ability to make groupchats.`]);
|
||||
}
|
||||
|
||||
const { targetUser, targetUsername, rest: reason } = this.splitUser(target);
|
||||
if (!targetUser) return this.errorReply(`User ${targetUsername} not found.`);
|
||||
if (!targetUser) throw new Chat.ErrorMessage(`User ${targetUsername} not found.`);
|
||||
if (target.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
|
||||
const isMonth = cmd.startsWith('month');
|
||||
|
||||
if (!isMonth && Punishments.isGroupchatBanned(targetUser)) {
|
||||
return this.errorReply(`User '${targetUser.name}' is already banned from using groupchats.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' is already banned from using groupchats.`);
|
||||
}
|
||||
|
||||
const reasonText = reason ? `: ${reason}` : ``;
|
||||
|
|
@ -2330,7 +2323,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.globalModlog("UNGROUPCHATBAN", toID(target), ` by ${user.id}`);
|
||||
if (targetUser) targetUser.popup(`${user.name} has allowed you to use groupchats again.`);
|
||||
} else {
|
||||
this.errorReply(`User ${target} is not banned from using groupchats.`);
|
||||
throw new Chat.ErrorMessage(`User ${target} is not banned from using groupchats.`);
|
||||
}
|
||||
},
|
||||
ungroupchatbanhelp: [`/ungroupchatban [user] - Allows a groupchatbanned user to use groupchats again. Requires: % @ ~`],
|
||||
|
|
@ -2343,12 +2336,12 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkChat();
|
||||
this.checkCan('editroom', null, room);
|
||||
if (!room.persist) {
|
||||
return this.errorReply("This room is not going to last long enough for a blacklist to matter - just ban the user");
|
||||
throw new Chat.ErrorMessage("This room is not going to last long enough for a blacklist to matter - just ban the user");
|
||||
}
|
||||
|
||||
const [targetStr, reason] = target.split('|').map(val => val.trim());
|
||||
if (!targetStr || (!reason && REQUIRE_REASONS)) {
|
||||
return this.errorReply("Usage: /blacklistname name1, name2, ... | reason");
|
||||
throw new Chat.ErrorMessage("Usage: /blacklistname name1, name2, ... | reason");
|
||||
}
|
||||
|
||||
const targets = targetStr.split(',').map(s => toID(s));
|
||||
|
|
@ -2358,15 +2351,15 @@ export const commands: Chat.ChatCommands = {
|
|||
Punishments.roomUserids.nestedGetByType(room.roomid, userid, 'BLACKLIST')
|
||||
));
|
||||
if (duplicates.length) {
|
||||
return this.errorReply(`[${duplicates.join(', ')}] ${Chat.plural(duplicates, "are", "is")} already blacklisted.`);
|
||||
throw new Chat.ErrorMessage(`[${duplicates.join(', ')}] ${Chat.plural(duplicates, "are", "is")} already blacklisted.`);
|
||||
}
|
||||
const expireTime = this.cmd.includes('perma') ? Date.now() + (10 * 365 * 24 * 60 * 60 * 1000) : null;
|
||||
const action = expireTime ? 'PERMANAMEBLACKLIST' : 'NAMEBLACKLIST';
|
||||
|
||||
for (const userid of targets) {
|
||||
if (!userid) return this.errorReply(`User '${userid}' is not a valid userid.`);
|
||||
if (!userid) throw new Chat.ErrorMessage(`User '${userid}' is not a valid userid.`);
|
||||
if (!Users.Auth.hasPermission(user, 'ban', room.auth.get(userid), room)) {
|
||||
return this.errorReply(`/blacklistname - Access denied: ${userid} is of equal or higher authority than you.`);
|
||||
throw new Chat.ErrorMessage(`/blacklistname - Access denied: ${userid} is of equal or higher authority than you.`);
|
||||
}
|
||||
|
||||
Punishments.roomBlacklist(room, userid, expireTime, null, reason);
|
||||
|
|
@ -2405,7 +2398,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.globalModlog("UNBLACKLIST", name);
|
||||
}
|
||||
} else {
|
||||
this.errorReply(`User '${target}' is not blacklisted.`);
|
||||
throw new Chat.ErrorMessage(`User '${target}' is not blacklisted.`);
|
||||
}
|
||||
},
|
||||
unblacklisthelp: [`/unblacklist [username] - Unblacklists the user from the room you are in. Requires: # ~`],
|
||||
|
|
@ -2416,16 +2409,15 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
if (!target) {
|
||||
user.lastCommand = '/unblacklistall';
|
||||
this.errorReply("THIS WILL UNBLACKLIST ALL BLACKLISTED USERS IN THIS ROOM.");
|
||||
this.errorReply("To confirm, use: /unblacklistall confirm");
|
||||
return;
|
||||
throw new Chat.ErrorMessage(["THIS WILL UNBLACKLIST ALL BLACKLISTED USERS IN THIS ROOM.",
|
||||
"To confirm, use: /unblacklistall confirm"]);
|
||||
}
|
||||
if (user.lastCommand !== '/unblacklistall' || target !== 'confirm') {
|
||||
return this.parse('/help unblacklistall');
|
||||
}
|
||||
user.lastCommand = '';
|
||||
const unblacklisted = Punishments.roomUnblacklistAll(room);
|
||||
if (!unblacklisted) return this.errorReply("No users are currently blacklisted in this room to unblacklist.");
|
||||
if (!unblacklisted) throw new Chat.ErrorMessage("No users are currently blacklisted in this room to unblacklist.");
|
||||
this.addModAction(`All blacklists in this room have been lifted by ${user.name}.`);
|
||||
this.modlog('UNBLACKLISTALL');
|
||||
this.roomlog(`Unblacklisted users: ${unblacklisted.join(', ')}`);
|
||||
|
|
@ -2438,11 +2430,11 @@ export const commands: Chat.ChatCommands = {
|
|||
showbl: 'showblacklist',
|
||||
showblacklist(target, room, user, connection, cmd) {
|
||||
if (target) room = Rooms.search(target)!;
|
||||
if (!room) return this.errorReply(`The room "${target}" was not found.`);
|
||||
if (!room) throw new Chat.ErrorMessage(`The room "${target}" was not found.`);
|
||||
this.checkCan('mute', null, room);
|
||||
const SOON_EXPIRING_TIME = 3 * 30 * 24 * 60 * 60 * 1000; // 3 months
|
||||
|
||||
if (!room.persist) return this.errorReply("This room does not support blacklists.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This room does not support blacklists.");
|
||||
|
||||
const roomUserids = Punishments.roomUserids.get(room.roomid);
|
||||
if (!roomUserids || roomUserids.size === 0) {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export const commands: Chat.ChatCommands = {
|
|||
roomsetting: 'roomsettings',
|
||||
roomsettings(target, room, user, connection) {
|
||||
room = this.requireRoom();
|
||||
if (room.battle) return this.errorReply("This command cannot be used in battle rooms.");
|
||||
if (room.battle) throw new Chat.ErrorMessage("This command cannot be used in battle rooms.");
|
||||
let uhtml = 'uhtml';
|
||||
|
||||
if (!target) {
|
||||
|
|
@ -81,7 +81,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.sendReply(`Moderated chat is currently set to: ${modchatSetting}`);
|
||||
}
|
||||
if (user.locked) { // would put this below but it behaves weird if there's no modchat set
|
||||
return this.errorReply(`/modchat - Access denied.`);
|
||||
throw new Chat.ErrorMessage(`/modchat - Access denied.`);
|
||||
} else {
|
||||
this.checkCan('modchat', null, room);
|
||||
}
|
||||
|
|
@ -92,16 +92,16 @@ export const commands: Chat.ChatCommands = {
|
|||
// 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}.`);
|
||||
throw new Chat.ErrorMessage(`/modchat - Access denied for changing a setting currently at ${room.settings.modchat}.`);
|
||||
}
|
||||
if ((room as any).requestModchat) {
|
||||
const error = (room as GameRoom).requestModchat(user);
|
||||
if (error) return this.errorReply(error);
|
||||
if (error) throw new Chat.ErrorMessage(error);
|
||||
}
|
||||
|
||||
// only admins can force modchat on a forced public battle
|
||||
if (room.battle?.forcedSettings.modchat && !user.can('rangeban')) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`This battle is required to have modchat on due to one of the players having a username that starts with ` +
|
||||
`${room.battle.forcedSettings.modchat}.`
|
||||
);
|
||||
|
|
@ -134,13 +134,13 @@ export const commands: Chat.ChatCommands = {
|
|||
// Users shouldn't be able to set modchat above their own rank (except for ROs who are also Upper Staff)
|
||||
const modchatLevelHigherThanUserRank = !room.auth.atLeast(user, target) && !user.can('bypassall');
|
||||
if (modchatLevelHigherThanUserRank || !Users.Auth.hasPermission(user, 'modchat', target as GroupSymbol, room)) {
|
||||
return this.errorReply(`/modchat - Access denied for setting to ${target}.`);
|
||||
throw new Chat.ErrorMessage(`/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'}.`);
|
||||
throw new Chat.ErrorMessage(`Modchat is already set to ${currentModchat || 'off'}.`);
|
||||
}
|
||||
if (!room.settings.modchat) {
|
||||
this.add("|raw|<div class=\"broadcast-blue\"><strong>Moderated chat was disabled!</strong><br />Anyone may talk now.</div>");
|
||||
|
|
@ -167,7 +167,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
this.checkCan('declare', null, room);
|
||||
if (this.meansNo(toID(target))) {
|
||||
if (!room.settings.autoModchat) return this.errorReply(`Auto modchat is not set.`);
|
||||
if (!room.settings.autoModchat) throw new Chat.ErrorMessage(`Auto modchat is not set.`);
|
||||
delete room.settings.autoModchat;
|
||||
room.saveSettings();
|
||||
if (room.modchatTimer) clearTimeout(room.modchatTimer); // fallback just in case (should never happen)
|
||||
|
|
@ -187,11 +187,11 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const validGroups = [...Config.groupsranking as string[], 'trusted', 'autoconfirmed'];
|
||||
if (!validGroups.includes(rank)) {
|
||||
return this.errorReply(`Invalid rank.`);
|
||||
throw new Chat.ErrorMessage(`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.");
|
||||
throw new Chat.ErrorMessage("Invalid duration. Choose a number under 480 (in minutes) and over 5 minutes.");
|
||||
}
|
||||
room.settings.autoModchat = {
|
||||
rank, time, active: false,
|
||||
|
|
@ -207,17 +207,21 @@ export const commands: Chat.ChatCommands = {
|
|||
],
|
||||
|
||||
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`);
|
||||
throw new Chat.ErrorMessage([
|
||||
`"ionext" is an outdated feature. Hidden battles now have password-protected URLs, making them fully secure against eavesdroppers.`,
|
||||
`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`);
|
||||
throw new Chat.ErrorMessage([
|
||||
`"ioo" is an outdated feature. Hidden battles now have password-protected URLs, making them fully secure against eavesdroppers.`,
|
||||
`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 (!groupConfig?.editprivacy) throw new Chat.ErrorMessage(`/ionext - Access denied.`);
|
||||
if (this.meansNo(target)) {
|
||||
user.battleSettings.inviteOnly = false;
|
||||
user.update();
|
||||
|
|
@ -258,12 +262,12 @@ export const commands: Chat.ChatCommands = {
|
|||
if (room.battle) {
|
||||
this.checkCan('editprivacy', null, room);
|
||||
if (room.battle.forcedSettings.privacy) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`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.`);
|
||||
throw new Chat.ErrorMessage(`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) {
|
||||
|
|
@ -272,11 +276,11 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('makeroom');
|
||||
}
|
||||
if (room.tour && !room.tour.allowModjoin) {
|
||||
return this.errorReply(`You can't do this in tournaments where modjoin is prohibited.`);
|
||||
throw new Chat.ErrorMessage(`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.`);
|
||||
if (!room.settings.modjoin) throw new Chat.ErrorMessage(`Modjoin is already turned off in this room.`);
|
||||
room.settings.modjoin = null;
|
||||
this.add(`|raw|<div class="broadcast-blue"><strong>This room is no longer invite only!</strong><br />Anyone may now join.</div>`);
|
||||
this.addModAction(`${user.name} turned off modjoin.`);
|
||||
|
|
@ -285,25 +289,25 @@ export const commands: Chat.ChatCommands = {
|
|||
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.`);
|
||||
if (room.settings.modjoin === true) throw new Chat.ErrorMessage(`Modjoin is already set to sync modchat in this room.`);
|
||||
room.settings.modjoin = true;
|
||||
this.add(`|raw|<div class="broadcast-red"><strong>Moderated join is set to sync with modchat!</strong><br />Only users who can speak in modchat can join.</div>`);
|
||||
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.`);
|
||||
if (room.settings.modjoin === 'autoconfirmed') throw new Chat.ErrorMessage(`Modjoin is already set to autoconfirmed.`);
|
||||
room.settings.modjoin = 'autoconfirmed';
|
||||
this.add(`|raw|<div class="broadcast-red"><strong>Moderated join is set to autoconfirmed!</strong><br />Users must be rank autoconfirmed or invited with <code>/invite</code> to join</div>`);
|
||||
this.addModAction(`${user.name} set modjoin to autoconfirmed.`);
|
||||
this.modlog('MODJOIN', null, 'autoconfirmed');
|
||||
} else if (Users.Auth.isAuthLevel(target) && !['‽', '!'].includes(target)) {
|
||||
if (room.battle && !user.can('makeroom') && !'+%'.includes(target)) {
|
||||
return this.errorReply(`/modjoin - Access denied from setting modjoin past % in battles.`);
|
||||
throw new Chat.ErrorMessage(`/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.`);
|
||||
throw new Chat.ErrorMessage(`/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.`);
|
||||
if (room.settings.modjoin === target) throw new Chat.ErrorMessage(`Modjoin is already set to ${target} in this room.`);
|
||||
room.settings.modjoin = target;
|
||||
this.add(`|raw|<div class="broadcast-red"><strong>This room is now invite only!</strong><br />Users must be rank ${target} or invited with <code>/invite</code> to join</div>`);
|
||||
this.addModAction(`${user.name} set modjoin to ${target}.`);
|
||||
|
|
@ -340,7 +344,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('editroom', null, room);
|
||||
|
||||
const targetLanguage = toID(target);
|
||||
if (!Chat.languages.has(targetLanguage)) return this.errorReply(`"${target}" is not a supported language.`);
|
||||
if (!Chat.languages.has(targetLanguage)) throw new Chat.ErrorMessage(`"${target}" is not a supported language.`);
|
||||
|
||||
room.settings.language = targetLanguage === 'english' ? false : targetLanguage;
|
||||
|
||||
|
|
@ -364,14 +368,14 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
let targetInt = parseInt(target);
|
||||
if (this.meansNo(target)) {
|
||||
if (!room.settings.slowchat) return this.errorReply(`Slow chat is already disabled in this room.`);
|
||||
if (!room.settings.slowchat) throw new Chat.ErrorMessage(`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.`);
|
||||
throw new Chat.ErrorMessage(`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.`);
|
||||
throw new Chat.ErrorMessage(`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;
|
||||
|
|
@ -397,10 +401,10 @@ export const commands: Chat.ChatCommands = {
|
|||
let rank = displayRank;
|
||||
if (rank === 'default') rank = '';
|
||||
if (rank === 'all users') rank = Users.Auth.defaultSymbol();
|
||||
if (!room.persist) return this.errorReply(`This room does not allow customizing permissions.`);
|
||||
if (!room.persist) throw new Chat.ErrorMessage(`This room does not allow customizing permissions.`);
|
||||
if (!target || !perm) return this.parse(`/permissions help`);
|
||||
if (rank && rank !== 'whitelist' && !Config.groupsranking.includes(rank as EffectiveGroupSymbol)) {
|
||||
return this.errorReply(`${rank} is not a valid rank.`);
|
||||
throw new Chat.ErrorMessage(`${rank} is not a valid rank.`);
|
||||
}
|
||||
const validPerms = Users.Auth.supportedRoomPermissions(room);
|
||||
const sanitizedPerm = perm.replace('!', '/'); // handles ! commands so we don't have to add commands to the array twice
|
||||
|
|
@ -409,21 +413,21 @@ export const commands: Chat.ChatCommands = {
|
|||
p === sanitizedPerm || p === perm ||
|
||||
p.startsWith(`${sanitizedPerm} `) || p.startsWith(`${perm} `)
|
||||
))) {
|
||||
return this.errorReply(`${perm} is not a valid room permission.`);
|
||||
throw new Chat.ErrorMessage(`${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.`);
|
||||
throw new Chat.ErrorMessage(`/permissions set - You must be at least a Room Owner to set permissions.`);
|
||||
}
|
||||
if (
|
||||
Users.Auth.ROOM_PERMISSIONS.includes(perm as RoomPermission) &&
|
||||
!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.`);
|
||||
throw new Chat.ErrorMessage(`/permissions set - You can't set the permission "${perm}" because you don't have it.`);
|
||||
}
|
||||
|
||||
const currentPermissions = room.settings.permissions || {};
|
||||
if (currentPermissions[perm] === (rank || undefined)) {
|
||||
return this.errorReply(`${perm} is already set to ${displayRank || 'default'}.`);
|
||||
throw new Chat.ErrorMessage(`${perm} is already set to ${displayRank || 'default'}.`);
|
||||
}
|
||||
|
||||
if (rank) {
|
||||
|
|
@ -503,10 +507,10 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('editroom', null, room);
|
||||
|
||||
if (this.meansYes(target)) {
|
||||
if (room.settings.filterStretching) return this.errorReply(`This room's stretch filter is already ON`);
|
||||
if (room.settings.filterStretching) throw new Chat.ErrorMessage(`This room's stretch filter is already ON`);
|
||||
room.settings.filterStretching = true;
|
||||
} else if (this.meansNo(target)) {
|
||||
if (!room.settings.filterStretching) return this.errorReply(`This room's stretch filter is already OFF`);
|
||||
if (!room.settings.filterStretching) throw new Chat.ErrorMessage(`This room's stretch filter is already OFF`);
|
||||
room.settings.filterStretching = false;
|
||||
} else {
|
||||
return this.parse("/help stretchfilter");
|
||||
|
|
@ -532,10 +536,10 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('editroom', null, room);
|
||||
|
||||
if (this.meansYes(target)) {
|
||||
if (room.settings.filterCaps) return this.errorReply(`This room's caps filter is already ON`);
|
||||
if (room.settings.filterCaps) throw new Chat.ErrorMessage(`This room's caps filter is already ON`);
|
||||
room.settings.filterCaps = true;
|
||||
} else if (this.meansNo(target)) {
|
||||
if (!room.settings.filterCaps) return this.errorReply(`This room's caps filter is already OFF`);
|
||||
if (!room.settings.filterCaps) throw new Chat.ErrorMessage(`This room's caps filter is already OFF`);
|
||||
room.settings.filterCaps = false;
|
||||
} else {
|
||||
return this.parse("/help capsfilter");
|
||||
|
|
@ -560,10 +564,10 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('editroom', null, room);
|
||||
|
||||
if (this.meansYes(target)) {
|
||||
if (room.settings.filterEmojis) return this.errorReply(`This room's emoji filter is already ON`);
|
||||
if (room.settings.filterEmojis) throw new Chat.ErrorMessage(`This room's emoji filter is already ON`);
|
||||
room.settings.filterEmojis = true;
|
||||
} else if (this.meansNo(target)) {
|
||||
if (!room.settings.filterEmojis) return this.errorReply(`This room's emoji filter is already OFF`);
|
||||
if (!room.settings.filterEmojis) throw new Chat.ErrorMessage(`This room's emoji filter is already OFF`);
|
||||
room.settings.filterEmojis = false;
|
||||
} else {
|
||||
return this.parse("/help emojifilter");
|
||||
|
|
@ -587,10 +591,10 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('editroom', null, room);
|
||||
|
||||
if (this.meansYes(target)) {
|
||||
if (room.settings.filterLinks) return this.errorReply(`This room's link filter is already ON`);
|
||||
if (room.settings.filterLinks) throw new Chat.ErrorMessage(`This room's link filter is already ON`);
|
||||
room.settings.filterLinks = true;
|
||||
} else if (this.meansNo(target)) {
|
||||
if (!room.settings.filterLinks) return this.errorReply(`This room's link filter is already OFF`);
|
||||
if (!room.settings.filterLinks) throw new Chat.ErrorMessage(`This room's link filter is already OFF`);
|
||||
room.settings.filterLinks = false;
|
||||
} else {
|
||||
return this.parse("/help linkfilter");
|
||||
|
|
@ -613,7 +617,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('declare', null, room);
|
||||
|
||||
const regex = cmd.includes('regex');
|
||||
if (regex && !user.can('makeroom')) return this.errorReply("Regex banwords are only allowed for administrators.");
|
||||
if (regex && !user.can('makeroom')) throw new Chat.ErrorMessage("Regex banwords are only allowed for administrators.");
|
||||
if (!room.settings.banwords) room.settings.banwords = [];
|
||||
// Most of the regex code is copied from the client. TODO: unify them?
|
||||
// Regex banwords can have commas in the {1,5} pattern
|
||||
|
|
@ -634,7 +638,7 @@ export const commands: Chat.ChatCommands = {
|
|||
let banwordRegexLen = (room.banwordRegex instanceof RegExp) ? room.banwordRegex.source.length : 32;
|
||||
for (const word of words) {
|
||||
Chat.validateRegex(word);
|
||||
if (room.settings.banwords.includes(word)) return this.errorReply(`${word} is already a banned phrase.`);
|
||||
if (room.settings.banwords.includes(word)) throw new Chat.ErrorMessage(`${word} is already a banned phrase.`);
|
||||
|
||||
// Banword strings are joined, so account for the first string not having the prefix
|
||||
banwordRegexLen += (banwordRegexLen === 32) ? word.length : `|${word}`.length;
|
||||
|
|
@ -643,7 +647,7 @@ export const commands: Chat.ChatCommands = {
|
|||
// the server on compile. In this case, that would happen each
|
||||
// time a chat message gets tested for any banned phrases.
|
||||
if (banwordRegexLen >= (1 << 16 - 1)) {
|
||||
return this.errorReply("This room has too many banned phrases to add the ones given.");
|
||||
throw new Chat.ErrorMessage("This room has too many banned phrases to add the ones given.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -669,7 +673,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse('/help banword');
|
||||
this.checkCan('declare', null, room);
|
||||
|
||||
if (!room.settings.banwords) return this.errorReply("This room has no banned phrases.");
|
||||
if (!room.settings.banwords) throw new Chat.ErrorMessage("This room has no banned phrases.");
|
||||
|
||||
const regexMatch = target.match(/[^,]+(,\d*}[^,]*)?/g);
|
||||
if (!regexMatch) return this.parse('/help banword');
|
||||
|
|
@ -677,7 +681,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const words = regexMatch.map(word => word.replace(/\n/g, '').trim()).filter(word => word.length > 0);
|
||||
|
||||
for (const word of words) {
|
||||
if (!room.settings.banwords.includes(word)) return this.errorReply(`${word} is not a banned phrase in this room.`);
|
||||
if (!room.settings.banwords.includes(word)) throw new Chat.ErrorMessage(`${word} is not a banned phrase in this room.`);
|
||||
}
|
||||
|
||||
room.settings.banwords = room.settings.banwords.filter(w => !words.includes(w));
|
||||
|
|
@ -729,11 +733,11 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.sendReply(`Approvals are currently ${room.settings.requestShowEnabled ? `ENABLED` : `DISABLED`} for ${room}.`);
|
||||
}
|
||||
if (this.meansNo(target)) {
|
||||
if (!room.settings.requestShowEnabled) return this.errorReply(`Approvals are already disabled.`);
|
||||
if (!room.settings.requestShowEnabled) throw new Chat.ErrorMessage(`Approvals are already disabled.`);
|
||||
room.settings.requestShowEnabled = undefined;
|
||||
this.privateModAction(`${user.name} disabled approvals in this room.`);
|
||||
} else if (this.meansYes(target)) {
|
||||
if (room.settings.requestShowEnabled) return this.errorReply(`Approvals are already enabled.`);
|
||||
if (room.settings.requestShowEnabled) throw new Chat.ErrorMessage(`Approvals are already enabled.`);
|
||||
room.settings.requestShowEnabled = true;
|
||||
this.privateModAction(`${user.name} enabled the use of media approvals in this room.`);
|
||||
if (!room.settings.permissions || room.settings.permissions['/show'] === '@') {
|
||||
|
|
@ -743,7 +747,7 @@ export const commands: Chat.ChatCommands = {
|
|||
);
|
||||
}
|
||||
} else {
|
||||
return this.errorReply(`Unrecognized setting for approvals. Use 'on' or 'off'.`);
|
||||
throw new Chat.ErrorMessage(`Unrecognized setting for approvals. Use 'on' or 'off'.`);
|
||||
}
|
||||
room.saveSettings();
|
||||
return this.modlog(`SHOWAPPROVALS`, null, `${this.meansYes(target) ? `ON` : `OFF`}`);
|
||||
|
|
@ -793,7 +797,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const id = toID(target);
|
||||
if (!id || this.cmd === 'makechatroom') return this.parse('/help makechatroom');
|
||||
if (!Rooms.global.addChatRoom(target)) {
|
||||
return this.errorReply(`The room '${target}' already exists or it is using an invalid title.`);
|
||||
throw new Chat.ErrorMessage(`The room '${target}' already exists or it is using an invalid title.`);
|
||||
}
|
||||
|
||||
const targetRoom = Rooms.search(target);
|
||||
|
|
@ -830,21 +834,21 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkChat();
|
||||
if (!user.trusted) {
|
||||
return this.errorReply("You must be trusted (public room driver or global voice) to make a groupchat.");
|
||||
throw new Chat.ErrorMessage("You must be trusted (public room driver or global voice) to make a groupchat.");
|
||||
}
|
||||
|
||||
const groupchatbanned = Punishments.isGroupchatBanned(user);
|
||||
if (groupchatbanned) {
|
||||
const expireText = Punishments.checkPunishmentExpiration(groupchatbanned);
|
||||
return this.errorReply(`You are banned from using groupchats ${expireText}.`);
|
||||
throw new Chat.ErrorMessage(`You are banned from using groupchats ${expireText}.`);
|
||||
}
|
||||
|
||||
if (cmd === 'subroomgroupchat' || cmd === 'srgc') {
|
||||
if (!user.can('mute', null, room)) {
|
||||
return this.errorReply("You can only create subroom groupchats for rooms you're staff in.");
|
||||
throw new Chat.ErrorMessage("You can only create subroom groupchats for rooms you're staff in.");
|
||||
}
|
||||
if (room.battle) return this.errorReply("You cannot create a subroom of a battle.");
|
||||
if (room.settings.isPersonal) return this.errorReply("You cannot create a subroom of a groupchat.");
|
||||
if (room.battle) throw new Chat.ErrorMessage("You cannot create a subroom of a battle.");
|
||||
if (room.settings.isPersonal) throw new Chat.ErrorMessage("You cannot create a subroom of a groupchat.");
|
||||
}
|
||||
const parent = cmd === 'subroomgroupchat' || cmd === 'srgc' ? room.roomid : null;
|
||||
// this.checkCan('makegroupchat');
|
||||
|
|
@ -852,24 +856,24 @@ export const commands: Chat.ChatCommands = {
|
|||
// Title defaults to a random 8-digit number.
|
||||
let title = target.trim();
|
||||
if (title.length >= 32) {
|
||||
return this.errorReply("Title must be under 32 characters long.");
|
||||
throw new Chat.ErrorMessage("Title must be under 32 characters long.");
|
||||
} else if (!title) {
|
||||
title = (`${Math.floor(Math.random() * 100000000)}`);
|
||||
} else if (this.filter(title) !== title) {
|
||||
return this.errorReply("Invalid title.");
|
||||
throw new Chat.ErrorMessage("Invalid title.");
|
||||
}
|
||||
// `,` is a delimiter used by a lot of /commands
|
||||
// `|` and `[` are delimiters used by the protocol
|
||||
// `-` has special meaning in roomids
|
||||
if (title.includes(',') || title.includes('|') || title.includes('[') || title.includes('-')) {
|
||||
return this.errorReply("Room titles can't contain any of: ,|[-");
|
||||
throw new Chat.ErrorMessage("Room titles can't contain any of: ,|[-");
|
||||
}
|
||||
|
||||
// Even though they're different namespaces, to cut down on confusion, you
|
||||
// can't share names with registered chatrooms.
|
||||
const existingRoom = Rooms.search(toID(title));
|
||||
if (existingRoom && !existingRoom.settings.modjoin) {
|
||||
return this.errorReply(`Your group chat name is too similar to existing chat room '${title}'.`);
|
||||
throw new Chat.ErrorMessage(`Your group chat name is too similar to existing chat room '${title}'.`);
|
||||
}
|
||||
// Room IDs for groupchats are groupchat-TITLEID
|
||||
let titleid = toID(title);
|
||||
|
|
@ -878,13 +882,12 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const roomid = `groupchat-${parent || user.id}-${titleid}` as RoomID;
|
||||
// Titles must be unique.
|
||||
if (Rooms.search(roomid)) return this.errorReply(`A group chat named '${title}' already exists.`);
|
||||
if (Rooms.search(roomid)) throw new Chat.ErrorMessage(`A group chat named '${title}' already exists.`);
|
||||
// Tab title is prefixed with '[G]' to distinguish groupchats from
|
||||
// registered chatrooms
|
||||
|
||||
if (Monitor.countGroupChat(connection.ip)) {
|
||||
this.errorReply("Due to high load, you are limited to creating 4 group chats every hour.");
|
||||
return;
|
||||
throw new Chat.ErrorMessage("Due to high load, you are limited to creating 4 group chats every hour.");
|
||||
}
|
||||
|
||||
const titleMsg = Utils.html`Welcome to ${parent ? room.title : user.name}'s` +
|
||||
|
|
@ -902,7 +905,7 @@ export const commands: Chat.ChatCommands = {
|
|||
`<p>Groupchats are temporary rooms, and will expire if there hasn't been any activity in 40 minutes.</p><p>You can invite new users using <code>/invite</code>. Be careful with who you invite!</p><p>Commands: <button class="button" name="send" value="/roomhelp">Room Management</button> | <button class="button" name="send" value="/roomsettings">Room Settings</button> | <button class="button" name="send" value="/tournaments help">Tournaments</button></p><p>As creator of this groupchat, <u>you are entirely responsible for what occurs in this chatroom</u>. Global rules apply at all times.</p><p>If this room is used to break global rules or disrupt other areas of the server, <strong>you as the creator will be held accountable and punished</strong>.</p>`,
|
||||
});
|
||||
if (!targetRoom) {
|
||||
return this.errorReply(`An unknown error occurred while trying to create the room '${title}'.`);
|
||||
throw new Chat.ErrorMessage(`An unknown error occurred while trying to create the room '${title}'.`);
|
||||
}
|
||||
// The creator is a Room Owner in subroom groupchats and a Host otherwise..
|
||||
targetRoom.auth.set(user.id, parent ? '#' : Users.HOST_SYMBOL);
|
||||
|
|
@ -919,7 +922,7 @@ export const commands: Chat.ChatCommands = {
|
|||
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) throw new Chat.ErrorMessage(`Can only be used in a room.`);
|
||||
|
||||
// for hotpatching
|
||||
if (!room.settings.creationTime) room.settings.creationTime = Date.now();
|
||||
|
|
@ -934,7 +937,7 @@ export const commands: Chat.ChatCommands = {
|
|||
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.`);
|
||||
if (!targetRoom) throw new Chat.ErrorMessage(`The room '${target}' doesn't exist.`);
|
||||
target = targetRoom.title || targetRoom.roomid;
|
||||
const isPrivate = targetRoom.settings.isPrivate;
|
||||
const staffRoom = Rooms.get('staff');
|
||||
|
|
@ -957,7 +960,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
return;
|
||||
}
|
||||
return this.errorReply(`The room "${target}" isn't registered.`);
|
||||
throw new Chat.ErrorMessage(`The room "${target}" isn't registered.`);
|
||||
},
|
||||
deregisterchatroomhelp: [
|
||||
`/deregisterchatroom [roomname] - Deletes room [roomname] after the next server restart. Requires: ~`,
|
||||
|
|
@ -1024,36 +1027,36 @@ export const commands: Chat.ChatCommands = {
|
|||
],
|
||||
|
||||
rename() {
|
||||
this.errorReply("Did you mean /renameroom?");
|
||||
throw new Chat.ErrorMessage("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.");
|
||||
throw new Chat.ErrorMessage("Cannot rename room while a tour/poll/game is running.");
|
||||
}
|
||||
if (room.battle) {
|
||||
return this.errorReply("Cannot rename battle rooms.");
|
||||
throw new Chat.ErrorMessage("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 (room.persist && isGroupchat) throw new Chat.ErrorMessage(`This isn't a groupchat.`);
|
||||
if (!room.persist && !isGroupchat) throw new Chat.ErrorMessage(`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}'.`);
|
||||
throw new Chat.ErrorMessage(`Your groupchat name is too similar to existing chat room '${existingRoom.title}'.`);
|
||||
}
|
||||
if (this.filter(target) !== target) {
|
||||
return this.errorReply("Invalid title.");
|
||||
throw new Chat.ErrorMessage("Invalid title.");
|
||||
}
|
||||
// `,` is a delimiter used by a lot of /commands
|
||||
// `|` and `[` are delimiters used by the protocol
|
||||
// `-` has special meaning in roomids
|
||||
if (target.includes(',') || target.includes('|') || target.includes('[') || target.includes('-')) {
|
||||
return this.errorReply("Room titles can't contain any of: ,|[-");
|
||||
throw new Chat.ErrorMessage("Room titles can't contain any of: ,|[-");
|
||||
}
|
||||
} else {
|
||||
this.checkCan('makeroom');
|
||||
|
|
@ -1092,10 +1095,10 @@ export const commands: Chat.ChatCommands = {
|
|||
if (battle) {
|
||||
this.checkCan('editprivacy', null, room);
|
||||
if (battle.forcedSettings.privacy) {
|
||||
return this.errorReply(`This battle is required to be public because a player has a name prefixed by '${battle.forcedSettings.privacy}'.`);
|
||||
throw new Chat.ErrorMessage(`This battle is required to be public because a player has a name prefixed by '${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.`);
|
||||
throw new Chat.ErrorMessage(`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);
|
||||
|
|
@ -1127,23 +1130,23 @@ export const commands: Chat.ChatCommands = {
|
|||
break;
|
||||
}
|
||||
if (this.meansNo(target)) {
|
||||
return this.errorReply(`Please specify what privacy setting you want for this room: /hiddenroom, /secretroom, or /publicroom`);
|
||||
throw new Chat.ErrorMessage(`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.`);
|
||||
throw new Chat.ErrorMessage(`This room is already public.`);
|
||||
}
|
||||
if (room.parent?.settings.isPrivate) {
|
||||
return this.errorReply(`This room's parent ${room.parent.title} must be public for this room to be public.`);
|
||||
throw new Chat.ErrorMessage(`This room's parent ${room.parent.title} must be public for this room to be public.`);
|
||||
}
|
||||
if (room.settings.isPersonal && !battle) {
|
||||
return this.errorReply(`This room can't be made public.`);
|
||||
throw new Chat.ErrorMessage(`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.`);
|
||||
throw new Chat.ErrorMessage(`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) {
|
||||
|
|
@ -1158,10 +1161,10 @@ export const commands: Chat.ChatCommands = {
|
|||
} else {
|
||||
const settingName = (setting === true ? 'secret' : setting);
|
||||
if (room.subRooms && !room.bestOf) {
|
||||
if (settingName === 'secret') return this.errorReply("Secret rooms cannot have subrooms.");
|
||||
if (settingName === 'secret') throw new Chat.ErrorMessage("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.`);
|
||||
throw new Chat.ErrorMessage(`Subroom ${subRoom.title} must be private to make this room private.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1170,7 +1173,7 @@ export const commands: Chat.ChatCommands = {
|
|||
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}.`);
|
||||
throw new Chat.ErrorMessage(`This room is already ${settingName}.`);
|
||||
}
|
||||
this.addModAction(`${user.name} made this room ${settingName}.`);
|
||||
this.modlog(`${settingName.toUpperCase()}ROOM`);
|
||||
|
|
@ -1187,7 +1190,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
hidenext(target, room, user) {
|
||||
const groupConfig = Config.groups[Users.PLAYER_SYMBOL];
|
||||
if (!groupConfig?.editprivacy) return this.errorReply(`/hidenext - Access denied.`);
|
||||
if (!groupConfig?.editprivacy) throw new Chat.ErrorMessage(`/hidenext - Access denied.`);
|
||||
if (this.meansNo(target)) {
|
||||
user.battleSettings.hidden = false;
|
||||
user.update();
|
||||
|
|
@ -1213,16 +1216,16 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
if (!target) return this.parse(`/help roomspotlight`);
|
||||
if (!room.persist) {
|
||||
return this.errorReply(`/roomspotlight - You can't spotlight this room.`);
|
||||
throw new Chat.ErrorMessage(`/roomspotlight - You can't spotlight this room.`);
|
||||
}
|
||||
if (this.meansNo(target)) {
|
||||
if (!room.settings.spotlight) return this.errorReply(`This chatroom is not being spotlighted.`);
|
||||
if (!room.settings.spotlight) throw new Chat.ErrorMessage(`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.");
|
||||
if (room.settings.spotlight === target) throw new Chat.ErrorMessage("This chat room is already spotlighted.");
|
||||
this.addModAction(`${user.name} spotlighted this room with the message "${target}".`);
|
||||
this.globalModlog('SPOTLIGHT');
|
||||
room.settings.spotlight = target;
|
||||
|
|
@ -1237,28 +1240,28 @@ export const commands: Chat.ChatCommands = {
|
|||
setsubroom: 'subroom',
|
||||
subroom(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!user.can('makeroom')) return this.errorReply(`/subroom - Access denied. Did you mean /subrooms?`);
|
||||
if (!user.can('makeroom')) throw new Chat.ErrorMessage(`/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.persist) throw new Chat.ErrorMessage(`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.`);
|
||||
throw new Chat.ErrorMessage(`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.`);
|
||||
throw new Chat.ErrorMessage(`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) throw new Chat.ErrorMessage(`The room '${target}' does not exist.`);
|
||||
if (parent.type !== 'chat') throw new Chat.ErrorMessage(`Parent room '${target}' must be a chat room.`);
|
||||
if (parent.parent) throw new Chat.ErrorMessage(`Subrooms cannot have subrooms.`);
|
||||
if (parent.settings.isPrivate === true) throw new Chat.ErrorMessage(`Only public and hidden rooms can have subrooms.`);
|
||||
if (parent.settings.isPrivate && !room.settings.isPrivate) {
|
||||
return this.errorReply(`Private rooms cannot have public subrooms.`);
|
||||
throw new Chat.ErrorMessage(`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.`);
|
||||
if (!parent.persist) throw new Chat.ErrorMessage(`Temporary rooms cannot be parent rooms.`);
|
||||
if (room === parent) throw new Chat.ErrorMessage(`You cannot set a room to be a subroom of itself.`);
|
||||
|
||||
const settingsList = Rooms.global.settingsList;
|
||||
|
||||
|
|
@ -1282,7 +1285,7 @@ export const commands: Chat.ChatCommands = {
|
|||
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.`);
|
||||
throw new Chat.ErrorMessage(`This room is not currently a subroom of a public room.`);
|
||||
}
|
||||
|
||||
room.setParent(null);
|
||||
|
|
@ -1296,10 +1299,10 @@ export const commands: Chat.ChatCommands = {
|
|||
subrooms(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom();
|
||||
if (cmd === 'parentroom') {
|
||||
if (!room.parent) return this.errorReply(`This room is not a subroom.`);
|
||||
if (!room.parent) throw new Chat.ErrorMessage(`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 (!room.persist) throw new Chat.ErrorMessage(`Temporary rooms cannot have subrooms.`);
|
||||
|
||||
if (!this.runBroadcast()) return;
|
||||
|
||||
|
|
@ -1334,18 +1337,18 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
this.checkCan('makeroom');
|
||||
if (target.length > 80) {
|
||||
return this.errorReply(`Error: Room description is too long (must be at most 80 characters).`);
|
||||
throw new Chat.ErrorMessage(`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".`);
|
||||
throw new Chat.ErrorMessage(`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".`);
|
||||
throw new Chat.ErrorMessage(`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".`);
|
||||
throw new Chat.ErrorMessage(`Error: Room description must not start with the phrase "talk about".`);
|
||||
}
|
||||
|
||||
room.settings.desc = target;
|
||||
|
|
@ -1371,7 +1374,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return;
|
||||
}
|
||||
this.checkCan('editroom', null, room);
|
||||
if (this.meansNo(target) || target === 'delete') return this.errorReply('Did you mean "/deleteroomintro"?');
|
||||
if (this.meansNo(target) || target === 'delete') throw new Chat.ErrorMessage('Did you mean "/deleteroomintro"?');
|
||||
this.checkHTML(target);
|
||||
if (!target.includes("<")) {
|
||||
// not HTML, do some simple URL linking
|
||||
|
|
@ -1399,7 +1402,7 @@ export const commands: Chat.ChatCommands = {
|
|||
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.");
|
||||
if (!room.settings.introMessage) throw new Chat.ErrorMessage("This room does not have a introduction set.");
|
||||
|
||||
this.privateModAction(`${user.name} deleted the roomintro.`);
|
||||
this.modlog('DELETEROOMINTRO');
|
||||
|
|
@ -1424,7 +1427,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
this.checkCan('ban', null, room);
|
||||
this.checkChat();
|
||||
if (this.meansNo(target) || target === 'delete') return this.errorReply('Did you mean "/deletestaffintro"?');
|
||||
if (this.meansNo(target) || target === 'delete') throw new Chat.ErrorMessage('Did you mean "/deletestaffintro"?');
|
||||
this.checkHTML(target);
|
||||
if (!target.includes("<")) {
|
||||
// not HTML, do some simple URL linking
|
||||
|
|
@ -1448,7 +1451,7 @@ export const commands: Chat.ChatCommands = {
|
|||
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.");
|
||||
if (!room.settings.staffMessage) throw new Chat.ErrorMessage("This room does not have a staff introduction set.");
|
||||
|
||||
this.privateModAction(`${user.name} deleted the staffintro.`);
|
||||
this.modlog('DELETESTAFFINTRO');
|
||||
|
|
@ -1472,11 +1475,11 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
|
||||
const alias = toID(target);
|
||||
if (!alias.length) return this.errorReply("Only alphanumeric characters are valid in an alias.");
|
||||
if (!alias.length) throw new Chat.ErrorMessage("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.");
|
||||
throw new Chat.ErrorMessage("You cannot set an alias to an existing room or alias.");
|
||||
}
|
||||
if (room.settings.isPersonal) return this.errorReply("Personal rooms can't have aliases.");
|
||||
if (room.settings.isPersonal) throw new Chat.ErrorMessage("Personal rooms can't have aliases.");
|
||||
|
||||
Rooms.aliases.set(alias, room.roomid);
|
||||
this.privateModAction(`${user.name} added the room alias '${alias}'.`);
|
||||
|
|
@ -1497,7 +1500,7 @@ export const commands: Chat.ChatCommands = {
|
|||
unroomalias: 'removeroomalias',
|
||||
removeroomalias(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.settings.aliases) return this.errorReply("This room does not have any aliases.");
|
||||
if (!room.settings.aliases) throw new Chat.ErrorMessage("This room does not have any aliases.");
|
||||
this.checkCan('makeroom');
|
||||
if (target.includes(',')) {
|
||||
this.errorReply(`Invalid room alias: ${target.trim()}`);
|
||||
|
|
@ -1505,9 +1508,9 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
|
||||
const alias = toID(target);
|
||||
if (!alias || !Rooms.aliases.has(alias)) return this.errorReply("Please specify an existing alias.");
|
||||
if (!alias || !Rooms.aliases.has(alias)) throw new Chat.ErrorMessage("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.");
|
||||
throw new Chat.ErrorMessage("You may only remove an alias from the current room.");
|
||||
}
|
||||
|
||||
this.privateModAction(`${user.name} removed the room alias '${alias}'.`);
|
||||
|
|
|
|||
|
|
@ -836,15 +836,15 @@ export const commands: Chat.ChatCommands = {
|
|||
for (let k in args) {
|
||||
const vals = args[k];
|
||||
if (vals.length > 1) {
|
||||
return this.errorReply(`Too many values for ${k}`);
|
||||
throw new Chat.ErrorMessage(`Too many values for ${k}`);
|
||||
}
|
||||
k = k.toUpperCase().replace(/\s/g, '_');
|
||||
if (!(k in Artemis.RemoteClassifier.ATTRIBUTES)) {
|
||||
return this.errorReply(`Invalid attribute: ${k}`);
|
||||
throw new Chat.ErrorMessage(`Invalid attribute: ${k}`);
|
||||
}
|
||||
const val = parseFloat(vals[0]);
|
||||
if (isNaN(val)) {
|
||||
return this.errorReply(`Invalid value for ${k}: ${vals[0]}`);
|
||||
throw new Chat.ErrorMessage(`Invalid value for ${k}: ${vals[0]}`);
|
||||
}
|
||||
scores[k] = val;
|
||||
}
|
||||
|
|
@ -859,13 +859,13 @@ export const commands: Chat.ChatCommands = {
|
|||
toggle(target) {
|
||||
checkAccess(this);
|
||||
if (this.meansYes(target)) {
|
||||
if (!settings.disabled) return this.errorReply(`The abuse monitor is already enabled.`);
|
||||
if (!settings.disabled) throw new Chat.ErrorMessage(`The abuse monitor is already enabled.`);
|
||||
settings.disabled = false;
|
||||
} else if (this.meansNo(target)) {
|
||||
if (settings.disabled) return this.errorReply(`The abuse monitor is already disabled.`);
|
||||
if (settings.disabled) throw new Chat.ErrorMessage(`The abuse monitor is already disabled.`);
|
||||
settings.disabled = true;
|
||||
} else {
|
||||
return this.errorReply(`Invalid setting. Must be 'on' or 'off'.`);
|
||||
throw new Chat.ErrorMessage(`Invalid setting. Must be 'on' or 'off'.`);
|
||||
}
|
||||
saveSettings();
|
||||
this.refreshPage('abusemonitor-settings');
|
||||
|
|
@ -883,7 +883,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse(`/help abusemonitor`);
|
||||
}
|
||||
if (settings.threshold === num) {
|
||||
return this.errorReply(`The abuse monitor threshold is already ${num}.`);
|
||||
throw new Chat.ErrorMessage(`The abuse monitor threshold is already ${num}.`);
|
||||
}
|
||||
settings.threshold = num;
|
||||
saveSettings();
|
||||
|
|
@ -939,14 +939,14 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const roomMutes = muted.get(room);
|
||||
if (!roomMutes) {
|
||||
return this.errorReply(`No users have Artemis mutes in this room.`);
|
||||
throw new Chat.ErrorMessage(`No users have Artemis mutes in this room.`);
|
||||
}
|
||||
const targetUser = Users.get(target);
|
||||
if (!targetUser) {
|
||||
return this.errorReply(`User '${target}' not found.`);
|
||||
throw new Chat.ErrorMessage(`User '${target}' not found.`);
|
||||
}
|
||||
if (!roomMutes.has(targetUser)) {
|
||||
return this.errorReply(`That user does not have an Artemis mute in this room.`);
|
||||
throw new Chat.ErrorMessage(`That user does not have an Artemis mute in this room.`);
|
||||
}
|
||||
roomMutes.delete(targetUser);
|
||||
this.modlog(`ABUSEMONITOR UNMUTE`, targetUser);
|
||||
|
|
@ -959,7 +959,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!tarRoom) return this.popupReply(`The room "${roomid}" does not exist.`);
|
||||
const cmd = NOJOIN_COMMAND_WHITELIST[toID(type)];
|
||||
if (!cmd) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`Invalid punishment given. ` +
|
||||
`Must be one of ${Object.keys(NOJOIN_COMMAND_WHITELIST).join(', ')}.`
|
||||
);
|
||||
|
|
@ -1007,25 +1007,25 @@ export const commands: Chat.ChatCommands = {
|
|||
const examples = target.split(',').filter(Boolean);
|
||||
const type = examples.shift()?.toUpperCase().replace(/\s/g, '_') || "";
|
||||
if (!(type in Artemis.RemoteClassifier.ATTRIBUTES)) {
|
||||
return this.errorReply(`Invalid type: ${type}`);
|
||||
throw new Chat.ErrorMessage(`Invalid type: ${type}`);
|
||||
}
|
||||
if (examples.length < 3) {
|
||||
return this.errorReply(`At least 3 examples are needed.`);
|
||||
throw new Chat.ErrorMessage(`At least 3 examples are needed.`);
|
||||
}
|
||||
const scales = [];
|
||||
const oldScales = [];
|
||||
for (const chunk of examples) {
|
||||
const [message, rawNum] = chunk.split('|');
|
||||
if (!(message && rawNum)) {
|
||||
return this.errorReply(`Invalid example: "${chunk}". Must be in \`\`message|num\`\` format.`);
|
||||
throw new Chat.ErrorMessage(`Invalid example: "${chunk}". Must be in \`\`message|num\`\` format.`);
|
||||
}
|
||||
const num = parseFloat(rawNum);
|
||||
if (isNaN(num)) {
|
||||
return this.errorReply(`Invalid number in example '${chunk}'.`);
|
||||
throw new Chat.ErrorMessage(`Invalid number in example '${chunk}'.`);
|
||||
}
|
||||
const data = await classifier.classify(message);
|
||||
if (!data) {
|
||||
return this.errorReply(`No results found. Try again in a minute?`);
|
||||
throw new Chat.ErrorMessage(`No results found. Try again in a minute?`);
|
||||
}
|
||||
oldScales.push(num);
|
||||
scales.push(data[type]);
|
||||
|
|
@ -1070,16 +1070,15 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!targetId) return this.parse(`/help abusemonitor`);
|
||||
if (user.lastCommand !== `am userclear ${targetId}`) {
|
||||
user.lastCommand = `am userclear ${targetId}`;
|
||||
this.errorReply(`Are you sure you want to clear abuse monitor database records for ${targetId}?`);
|
||||
this.errorReply(`Retype the command if you're sure.`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage([`Are you sure you want to clear abuse monitor database records for ${targetId}?`,
|
||||
`Retype the command if you're sure.`]);
|
||||
}
|
||||
user.lastCommand = '';
|
||||
const results = await Chat.database.run(
|
||||
'DELETE FROM perspective_logs WHERE userid = ?', [targetId]
|
||||
);
|
||||
if (!results.changes) {
|
||||
return this.errorReply(`No logs for ${targetUsername} found.`);
|
||||
throw new Chat.ErrorMessage(`No logs for ${targetUsername} found.`);
|
||||
}
|
||||
this.sendReply(`${results.changes} log(s) cleared for ${targetId}.`);
|
||||
this.privateGlobalModAction(`${user.name} cleared abuse monitor logs for ${targetUsername}${rest ? ` (${rest})` : ""}.`);
|
||||
|
|
@ -1091,13 +1090,13 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse(`/help abusemonitor`);
|
||||
const num = parseInt(target);
|
||||
if (isNaN(num)) {
|
||||
return this.errorReply(`Invalid log number: ${target}`);
|
||||
throw new Chat.ErrorMessage(`Invalid log number: ${target}`);
|
||||
}
|
||||
const row = await Chat.database.get(
|
||||
'SELECT * FROM perspective_logs WHERE rowid = ?', [num]
|
||||
);
|
||||
if (!row) {
|
||||
return this.errorReply(`No log with ID ${num} found.`);
|
||||
throw new Chat.ErrorMessage(`No log with ID ${num} found.`);
|
||||
}
|
||||
await Chat.database.run( // my kingdom for RETURNING * in sqlite :(
|
||||
'DELETE FROM perspective_logs WHERE rowid = ?', [num]
|
||||
|
|
@ -1119,27 +1118,27 @@ export const commands: Chat.ChatCommands = {
|
|||
rawScore = toID(rawScore);
|
||||
const types = { ...Artemis.RemoteClassifier.ATTRIBUTES, "ALL": {} };
|
||||
if (!(type in types)) {
|
||||
return this.errorReply(`Invalid type: ${type}. Valid types: ${Object.keys(types).join(', ')}.`);
|
||||
throw new Chat.ErrorMessage(`Invalid type: ${type}. Valid types: ${Object.keys(types).join(', ')}.`);
|
||||
}
|
||||
const percent = parseFloat(rawPercent);
|
||||
if (isNaN(percent) || percent > 1 || percent < 0) {
|
||||
return this.errorReply(`Invalid percent: ${percent}. Must be between 0 and 1.`);
|
||||
throw new Chat.ErrorMessage(`Invalid percent: ${percent}. Must be between 0 and 1.`);
|
||||
}
|
||||
const score = parseInt(rawScore) || toID(rawScore).toUpperCase() as 'MAXIMUM';
|
||||
switch (typeof score) {
|
||||
case 'string':
|
||||
if (score !== 'MAXIMUM') {
|
||||
return this.errorReply(`Invalid score. Must be a number or "MAXIMUM".`);
|
||||
throw new Chat.ErrorMessage(`Invalid score. Must be a number or "MAXIMUM".`);
|
||||
}
|
||||
break;
|
||||
case 'number':
|
||||
if (isNaN(score) || score < 0) {
|
||||
return this.errorReply(`Invalid score. Must be a number or "MAXIMUM".`);
|
||||
throw new Chat.ErrorMessage(`Invalid score. Must be a number or "MAXIMUM".`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (settings.specials[type]?.[percent] && !this.cmd.includes('f')) {
|
||||
return this.errorReply(`That special case already exists. Use /am forceeditspecial to change it.`);
|
||||
throw new Chat.ErrorMessage(`That special case already exists. Use /am forceeditspecial to change it.`);
|
||||
}
|
||||
if (!settings.specials[type]) settings.specials[type] = {};
|
||||
// checked above to ensure it's a valid number or MAXIMUM
|
||||
|
|
@ -1157,14 +1156,14 @@ export const commands: Chat.ChatCommands = {
|
|||
const type = rawType.toUpperCase().replace(/\s/g, '_');
|
||||
const types = { ...Artemis.RemoteClassifier.ATTRIBUTES, "ALL": {} };
|
||||
if (!(type in types)) {
|
||||
return this.errorReply(`Invalid type: ${type}. Valid types: ${Object.keys(types).join(', ')}.`);
|
||||
throw new Chat.ErrorMessage(`Invalid type: ${type}. Valid types: ${Object.keys(types).join(', ')}.`);
|
||||
}
|
||||
const percent = parseFloat(rawPercent);
|
||||
if (isNaN(percent) || percent > 1 || percent < 0) {
|
||||
return this.errorReply(`Invalid percent: ${percent}. Must be between 0 and 1.`);
|
||||
throw new Chat.ErrorMessage(`Invalid percent: ${percent}. Must be between 0 and 1.`);
|
||||
}
|
||||
if (!settings.specials[type]?.[percent]) {
|
||||
return this.errorReply(`That special case does not exist.`);
|
||||
throw new Chat.ErrorMessage(`That special case does not exist.`);
|
||||
}
|
||||
delete settings.specials[type][percent];
|
||||
if (!Object.keys(settings.specials[type]).length) {
|
||||
|
|
@ -1181,7 +1180,7 @@ export const commands: Chat.ChatCommands = {
|
|||
checkAccess(this);
|
||||
const num = parseFloat(target);
|
||||
if (isNaN(num) || num < 0 || num > 1) {
|
||||
return this.errorReply(`Invalid minimum score: ${num}. Must be a positive integer.`);
|
||||
throw new Chat.ErrorMessage(`Invalid minimum score: ${num}. Must be a positive integer.`);
|
||||
}
|
||||
settings.minScore = num;
|
||||
saveSettings();
|
||||
|
|
@ -1195,11 +1194,11 @@ export const commands: Chat.ChatCommands = {
|
|||
checkAccess(this);
|
||||
const num = parseInt(target) - 1;
|
||||
if (isNaN(num)) {
|
||||
return this.errorReply(`Invalid punishment number: ${num + 1}.`);
|
||||
throw new Chat.ErrorMessage(`Invalid punishment number: ${num + 1}.`);
|
||||
}
|
||||
const punishment = settings.punishments[num];
|
||||
if (!punishment) {
|
||||
return this.errorReply(`Punishment ${num + 1} does not exist.`);
|
||||
throw new Chat.ErrorMessage(`Punishment ${num + 1} does not exist.`);
|
||||
}
|
||||
this.sendReply(
|
||||
`|html|Punishment ${num + 1}: <code>` +
|
||||
|
|
@ -1210,10 +1209,10 @@ export const commands: Chat.ChatCommands = {
|
|||
checkAccess(this);
|
||||
const [to, from] = target.split(',').map(f => toID(f));
|
||||
if (!(to && from)) {
|
||||
return this.errorReply(`Specify a type to change and a type to change to.`);
|
||||
throw new Chat.ErrorMessage(`Specify a type to change and a type to change to.`);
|
||||
}
|
||||
if (![to, from].every(f => punishmentHandlers[f])) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`Invalid types given. Valid types: ${Object.keys(punishmentHandlers).join(', ')}.`
|
||||
);
|
||||
}
|
||||
|
|
@ -1225,7 +1224,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
}
|
||||
if (!changed.length) {
|
||||
return this.errorReply(`No punishments of type '${to}' found.`);
|
||||
throw new Chat.ErrorMessage(`No punishments of type '${to}' found.`);
|
||||
}
|
||||
this.sendReply(`Updated punishment(s) ${changed.join(', ')}`);
|
||||
this.privateGlobalModAction(`${user.name} updated all abuse-monitor punishments of type ${to} to type ${from}`);
|
||||
|
|
@ -1268,31 +1267,31 @@ export const commands: Chat.ChatCommands = {
|
|||
switch (key) {
|
||||
case 'punishment': case 'p':
|
||||
if (punishment.punishment) {
|
||||
return this.errorReply(`Duplicate punishment values.`);
|
||||
throw new Chat.ErrorMessage(`Duplicate punishment values.`);
|
||||
}
|
||||
value = toID(value).toUpperCase();
|
||||
if (!PUNISHMENTS.includes(value)) {
|
||||
return this.errorReply(`Invalid punishment: ${value}. Valid punishments: ${PUNISHMENTS.join(', ')}.`);
|
||||
throw new Chat.ErrorMessage(`Invalid punishment: ${value}. Valid punishments: ${PUNISHMENTS.join(', ')}.`);
|
||||
}
|
||||
punishment.punishment = value;
|
||||
break;
|
||||
case 'count': case 'num': case 'c':
|
||||
if (punishment.count) {
|
||||
return this.errorReply(`Duplicate count values.`);
|
||||
throw new Chat.ErrorMessage(`Duplicate count values.`);
|
||||
}
|
||||
const num = parseInt(value);
|
||||
if (isNaN(num)) {
|
||||
return this.errorReply(`Invalid count '${value}'. Must be a number.`);
|
||||
throw new Chat.ErrorMessage(`Invalid count '${value}'. Must be a number.`);
|
||||
}
|
||||
punishment.count = num;
|
||||
break;
|
||||
case 'type': case 't':
|
||||
if (punishment.type) {
|
||||
return this.errorReply(`Duplicate type values.`);
|
||||
throw new Chat.ErrorMessage(`Duplicate type values.`);
|
||||
}
|
||||
value = value.replace(/\s/g, '_').toUpperCase();
|
||||
if (!Artemis.RemoteClassifier.ATTRIBUTES[value as keyof typeof Artemis.RemoteClassifier.ATTRIBUTES]) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`Invalid attribute: ${value}. ` +
|
||||
`Valid attributes: ${Object.keys(Artemis.RemoteClassifier.ATTRIBUTES).join(', ')}.`
|
||||
);
|
||||
|
|
@ -1301,11 +1300,11 @@ export const commands: Chat.ChatCommands = {
|
|||
break;
|
||||
case 'certainty': case 'ct':
|
||||
if (punishment.certainty) {
|
||||
return this.errorReply(`Duplicate certainty values.`);
|
||||
throw new Chat.ErrorMessage(`Duplicate certainty values.`);
|
||||
}
|
||||
const certainty = parseFloat(value);
|
||||
if (isNaN(certainty) || certainty > 1 || certainty < 0) {
|
||||
return this.errorReply(`Invalid certainty '${value}'. Must be a number above 0 and below 1.`);
|
||||
throw new Chat.ErrorMessage(`Invalid certainty '${value}'. Must be a number above 0 and below 1.`);
|
||||
}
|
||||
punishment.certainty = certainty;
|
||||
break;
|
||||
|
|
@ -1315,41 +1314,41 @@ export const commands: Chat.ChatCommands = {
|
|||
punishment.modlogActions = [];
|
||||
}
|
||||
if (punishment.modlogActions.includes(value)) {
|
||||
return this.errorReply(`Duplicate modlog action values - '${value}'.`);
|
||||
throw new Chat.ErrorMessage(`Duplicate modlog action values - '${value}'.`);
|
||||
}
|
||||
punishment.modlogActions.push(value);
|
||||
break;
|
||||
case 'mlc': case 'modlogcount':
|
||||
if (punishment.modlogCount) {
|
||||
return this.errorReply(`Duplicate modlog count values.`);
|
||||
throw new Chat.ErrorMessage(`Duplicate modlog count values.`);
|
||||
}
|
||||
const count = parseInt(value);
|
||||
if (isNaN(count)) {
|
||||
return this.errorReply(`Invalid modlog count.`);
|
||||
throw new Chat.ErrorMessage(`Invalid modlog count.`);
|
||||
}
|
||||
punishment.modlogCount = count;
|
||||
break;
|
||||
case 'st': case 's': case 'secondary':
|
||||
let [sType, sValue] = Utils.splitFirst(value, '|').map(f => f.trim());
|
||||
if (!sType || !sValue) {
|
||||
return this.errorReply(`Invalid secondary type/certainty.`);
|
||||
throw new Chat.ErrorMessage(`Invalid secondary type/certainty.`);
|
||||
}
|
||||
sType = sType.replace(/\s/g, '_').toUpperCase();
|
||||
if (!Artemis.RemoteClassifier.ATTRIBUTES[sType as keyof typeof Artemis.RemoteClassifier.ATTRIBUTES]) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`Invalid secondary attribute: ${sType}. ` +
|
||||
`Valid attributes: ${Object.keys(Artemis.RemoteClassifier.ATTRIBUTES).join(', ')}.`
|
||||
);
|
||||
}
|
||||
const sCertainty = parseFloat(sValue);
|
||||
if (isNaN(sCertainty) || sCertainty > 1 || sCertainty < 0) {
|
||||
return this.errorReply(`Invalid secondary certainty '${sValue}'. Must be a number above 0 and below 1.`);
|
||||
throw new Chat.ErrorMessage(`Invalid secondary certainty '${sValue}'. Must be a number above 0 and below 1.`);
|
||||
}
|
||||
if (!punishment.secondaryTypes) {
|
||||
punishment.secondaryTypes = {};
|
||||
}
|
||||
if (punishment.secondaryTypes[sType]) {
|
||||
return this.errorReply(`Duplicate secondary type.`);
|
||||
throw new Chat.ErrorMessage(`Duplicate secondary type.`);
|
||||
}
|
||||
punishment.secondaryTypes[sType] = sCertainty;
|
||||
break;
|
||||
|
|
@ -1362,7 +1361,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
}
|
||||
if (!punishment.punishment) {
|
||||
return this.errorReply(`A punishment type must be specified.`);
|
||||
throw new Chat.ErrorMessage(`A punishment type must be specified.`);
|
||||
}
|
||||
for (const [i, p] of settings.punishments.entries()) {
|
||||
let matches = 0;
|
||||
|
|
@ -1372,7 +1371,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (val && val === visualizePunishmentKey(p, key)) matches++;
|
||||
}
|
||||
if (matches === Object.keys(p).length) {
|
||||
return this.errorReply(`This punishment is already stored at ${i + 1}.`);
|
||||
throw new Chat.ErrorMessage(`This punishment is already stored at ${i + 1}.`);
|
||||
}
|
||||
}
|
||||
settings.punishments.push(punishment as PunishmentSettings);
|
||||
|
|
@ -1387,10 +1386,10 @@ export const commands: Chat.ChatCommands = {
|
|||
deletepunishment(target, room, user) {
|
||||
checkAccess(this);
|
||||
const idx = parseInt(target) - 1;
|
||||
if (isNaN(idx)) return this.errorReply(`Invalid number.`);
|
||||
if (isNaN(idx)) throw new Chat.ErrorMessage(`Invalid number.`);
|
||||
const punishment = settings.punishments[idx];
|
||||
if (!punishment) {
|
||||
return this.errorReply(`No punishments exist at index ${idx + 1}.`);
|
||||
throw new Chat.ErrorMessage(`No punishments exist at index ${idx + 1}.`);
|
||||
}
|
||||
settings.punishments.splice(idx, 1);
|
||||
saveSettings();
|
||||
|
|
@ -1418,15 +1417,15 @@ export const commands: Chat.ChatCommands = {
|
|||
const [rawTurns, rawIncrement, rawMin] = Utils.splitFirst(target, ',', 2).map(toID);
|
||||
const turns = parseInt(rawTurns);
|
||||
if (isNaN(turns) || turns < 0) {
|
||||
return this.errorReply(`Turns must be a number above 0.`);
|
||||
throw new Chat.ErrorMessage(`Turns must be a number above 0.`);
|
||||
}
|
||||
const increment = parseInt(rawIncrement);
|
||||
if (isNaN(increment) || increment < 0) {
|
||||
return this.errorReply(`The increment must be a number above 0.`);
|
||||
throw new Chat.ErrorMessage(`The increment must be a number above 0.`);
|
||||
}
|
||||
const min = parseInt(rawMin);
|
||||
if (rawMin && isNaN(min)) {
|
||||
return this.errorReply(`Invalid minimum (must be a number).`);
|
||||
throw new Chat.ErrorMessage(`Invalid minimum (must be a number).`);
|
||||
}
|
||||
settings.thresholdIncrement = { amount: increment, turns };
|
||||
if (min) {
|
||||
|
|
@ -1445,7 +1444,7 @@ export const commands: Chat.ChatCommands = {
|
|||
di: 'deleteincrement',
|
||||
deleteincrement(target, room, user) {
|
||||
checkAccess(this);
|
||||
if (!settings.thresholdIncrement) return this.errorReply(`The threshold increment is already disabled.`);
|
||||
if (!settings.thresholdIncrement) throw new Chat.ErrorMessage(`The threshold increment is already disabled.`);
|
||||
settings.thresholdIncrement = null;
|
||||
saveSettings();
|
||||
this.refreshPage('abusemonitor-settings');
|
||||
|
|
@ -1459,7 +1458,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const timeNum = new Date(target).getTime();
|
||||
if (isNaN(timeNum)) {
|
||||
return this.errorReply(`Invalid date.`);
|
||||
throw new Chat.ErrorMessage(`Invalid date.`);
|
||||
}
|
||||
let logs = await Chat.database.all(
|
||||
'SELECT * FROM perspective_stats WHERE result = 0 AND timestamp > ? AND timestamp < ?',
|
||||
|
|
@ -1469,7 +1468,7 @@ export const commands: Chat.ChatCommands = {
|
|||
Chat.toTimestamp(new Date(log.timestamp)).split(' ')[0] === target
|
||||
));
|
||||
if (!logs.length) {
|
||||
return this.errorReply(`No logs found for that date.`);
|
||||
throw new Chat.ErrorMessage(`No logs found for that date.`);
|
||||
}
|
||||
this.sendReplyBox(
|
||||
`<strong>${Chat.count(logs, 'logs')}</strong> found on the date ${target}:<hr />` +
|
||||
|
|
@ -1507,7 +1506,7 @@ export const commands: Chat.ChatCommands = {
|
|||
path = `artemis/${target.toLowerCase().replace(/\//g, '-')}`;
|
||||
}
|
||||
const backup = await FS(`config/chat-plugins/${path}.json`).readIfExists();
|
||||
if (!backup) return this.errorReply(`No backup settings saved.`);
|
||||
if (!backup) throw new Chat.ErrorMessage(`No backup settings saved.`);
|
||||
const backupSettings = JSON.parse(backup);
|
||||
Object.assign(settings, backupSettings);
|
||||
saveSettings();
|
||||
|
|
@ -1518,10 +1517,10 @@ export const commands: Chat.ChatCommands = {
|
|||
async deletebackup(target, room, user) {
|
||||
checkAccess(this);
|
||||
target = target.toLowerCase().replace(/\//g, '-');
|
||||
if (!target) return this.errorReply(`Specify a backup file.`);
|
||||
if (!target) throw new Chat.ErrorMessage(`Specify a backup file.`);
|
||||
const path = FS(`config/chat-plugins/artemis/${target}.json`);
|
||||
if (!(await path.exists())) {
|
||||
return this.errorReply(`Backup '${target}' not found.`);
|
||||
throw new Chat.ErrorMessage(`Backup '${target}' not found.`);
|
||||
}
|
||||
await path.unlinkIfExists();
|
||||
this.globalModlog(`ABUSEMONITOR DELETEBACKUP`, null, target);
|
||||
|
|
@ -1550,13 +1549,13 @@ export const commands: Chat.ChatCommands = {
|
|||
let message;
|
||||
if (this.meansYes(target)) {
|
||||
if (!settings.recommendOnly) {
|
||||
return this.errorReply(`Automatic punishments are already enabled.`);
|
||||
throw new Chat.ErrorMessage(`Automatic punishments are already enabled.`);
|
||||
}
|
||||
settings.recommendOnly = false;
|
||||
message = `${user.name} enabled automatic punishments for the Artemis battle monitor`;
|
||||
} else if (this.meansNo(target)) {
|
||||
if (settings.recommendOnly) {
|
||||
return this.errorReply(`Automatic punishments are already disabled.`);
|
||||
throw new Chat.ErrorMessage(`Automatic punishments are already disabled.`);
|
||||
}
|
||||
settings.recommendOnly = true;
|
||||
message = `${user.name} disabled automatic punishments for the Artemis battle monitor`;
|
||||
|
|
@ -1609,18 +1608,18 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse(`/help abusemonitor resolvereview`);
|
||||
}
|
||||
if (!reviews[userid]) {
|
||||
return this.errorReply(`No reviews found by that user.`);
|
||||
throw new Chat.ErrorMessage(`No reviews found by that user.`);
|
||||
}
|
||||
const review = reviews[userid].find(f => getBattleLinks(f.room).includes(roomid));
|
||||
if (!review) {
|
||||
return this.errorReply(`No reviews found by that user for that room.`);
|
||||
throw new Chat.ErrorMessage(`No reviews found by that user for that room.`);
|
||||
}
|
||||
const isAccurate = Number(accurate);
|
||||
if (isNaN(isAccurate) || isAccurate < 0 || isAccurate > 1) {
|
||||
return this.popupReply(`Invalid accuracy. Must be a number between 0 and 1.`);
|
||||
}
|
||||
if (review.resolved) {
|
||||
return this.errorReply(`That review has already been resolved.`);
|
||||
throw new Chat.ErrorMessage(`That review has already been resolved.`);
|
||||
}
|
||||
review.resolved = {
|
||||
by: user.id,
|
||||
|
|
@ -1636,10 +1635,10 @@ export const commands: Chat.ChatCommands = {
|
|||
checkAccess(this);
|
||||
if (!target) return this.parse(`/help am`);
|
||||
const [old, newWord] = target.split(',');
|
||||
if (!old || !newWord) return this.errorReply(`Invalid arguments - must be [oldWord], [newWord].`);
|
||||
if (toID(old) === toID(newWord)) return this.errorReply(`The old word and the new word are the same.`);
|
||||
if (!old || !newWord) throw new Chat.ErrorMessage(`Invalid arguments - must be [oldWord], [newWord].`);
|
||||
if (toID(old) === toID(newWord)) throw new Chat.ErrorMessage(`The old word and the new word are the same.`);
|
||||
if (settings.replacements[old]) {
|
||||
return this.errorReply(`The old word '${old}' is already in use (for '${settings.replacements[old]}').`);
|
||||
throw new Chat.ErrorMessage(`The old word '${old}' is already in use (for '${settings.replacements[old]}').`);
|
||||
}
|
||||
Chat.validateRegex(target);
|
||||
settings.replacements[old] = newWord;
|
||||
|
|
@ -1653,7 +1652,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse(`/help am`);
|
||||
const replaceTo = settings.replacements[target];
|
||||
if (!replaceTo) {
|
||||
return this.errorReply(`${target} is not a currently set replacement.`);
|
||||
throw new Chat.ErrorMessage(`${target} is not a currently set replacement.`);
|
||||
}
|
||||
delete settings.replacements[target];
|
||||
saveSettings();
|
||||
|
|
@ -1684,7 +1683,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const num = Number(target);
|
||||
if (isNaN(num)) {
|
||||
if (!/[0-9]{4}-[0-9]{2}-[0-9]{2}/.test(target)) {
|
||||
return this.errorReply(`Invalid date provided. Must be in YYYY-MM-DD format.`);
|
||||
throw new Chat.ErrorMessage(`Invalid date provided. Must be in YYYY-MM-DD format.`);
|
||||
}
|
||||
metadata.modlogIgnores[targetUser] = target;
|
||||
target = 'before and including ' + target;
|
||||
|
|
@ -1694,7 +1693,7 @@ export const commands: Chat.ChatCommands = {
|
|||
metadata.modlogIgnores[targetUser] = ignores = [];
|
||||
}
|
||||
if (ignores.includes(num)) {
|
||||
return this.errorReply(`That modlog entry is already ignored.`);
|
||||
throw new Chat.ErrorMessage(`That modlog entry is already ignored.`);
|
||||
}
|
||||
ignores.push(num);
|
||||
target = `entry #${target}`;
|
||||
|
|
@ -1715,18 +1714,18 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const entry = metadata.modlogIgnores?.[targetUser];
|
||||
if (!entry) {
|
||||
return this.errorReply(`That user has no ignored modlog entries registered.`);
|
||||
throw new Chat.ErrorMessage(`That user has no ignored modlog entries registered.`);
|
||||
}
|
||||
if (typeof entry === 'string') {
|
||||
rawNum = entry;
|
||||
delete metadata.modlogIgnores![targetUser];
|
||||
} else {
|
||||
if (isNaN(num)) {
|
||||
return this.errorReply(`Invalid modlog entry number: ${num}`);
|
||||
throw new Chat.ErrorMessage(`Invalid modlog entry number: ${num}`);
|
||||
}
|
||||
const idx = entry.indexOf(num);
|
||||
if (idx === -1) {
|
||||
return this.errorReply(`That modlog entry is not ignored for the user ${targetUser}.`);
|
||||
throw new Chat.ErrorMessage(`That modlog entry is not ignored for the user ${targetUser}.`);
|
||||
}
|
||||
entry.splice(idx, 1);
|
||||
if (!entry.length) {
|
||||
|
|
@ -1807,7 +1806,7 @@ export const pages: Chat.PageTable = {
|
|||
checkAccess(this, 'lock');
|
||||
const roomid = query.join('-') as RoomID;
|
||||
if (!toID(roomid)) {
|
||||
return this.errorReply(`You must specify a roomid to view abuse monitor data for.`);
|
||||
throw new Chat.ErrorMessage(`You must specify a roomid to view abuse monitor data for.`);
|
||||
}
|
||||
let buf = `<div class="pad">`;
|
||||
buf += `<button style="float:right;" class="button" name="send" value="/join ${this.pageid}">`;
|
||||
|
|
@ -1985,7 +1984,7 @@ export const pages: Chat.PageTable = {
|
|||
checkAccess(this);
|
||||
const dateString = (query.join('-') || Chat.toTimestamp(new Date())).slice(0, 7);
|
||||
if (!/^[0-9]{4}-[0-9]{2}$/.test(dateString)) {
|
||||
return this.errorReply(`Invalid date: ${dateString}`);
|
||||
throw new Chat.ErrorMessage(`Invalid date: ${dateString}`);
|
||||
}
|
||||
let buf = `<div class="pad">`;
|
||||
buf += `<button style="float:right;" class="button" name="send" value="/join ${this.pageid}">`;
|
||||
|
|
@ -2298,7 +2297,7 @@ export const pages: Chat.PageTable = {
|
|||
this.checkCan('lock');
|
||||
const targetUser = toID(query[0]);
|
||||
if (!targetUser) {
|
||||
return this.errorReply(`Specify a user.`);
|
||||
throw new Chat.ErrorMessage(`Specify a user.`);
|
||||
}
|
||||
this.title = `[Artemis History] ${targetUser}`;
|
||||
let buf = `<div class="pad"><h2>Artemis modlog handling for ${targetUser}</h2><hr />`;
|
||||
|
|
@ -2339,13 +2338,13 @@ export const pages: Chat.PageTable = {
|
|||
const [format, num, pw] = query.map(toID);
|
||||
this.checkCan('lock');
|
||||
if (!format || !num) {
|
||||
return this.errorReply(`Invalid battle link provided.`);
|
||||
throw new Chat.ErrorMessage(`Invalid battle link provided.`);
|
||||
}
|
||||
this.title = `[Battle Logs] ${format}-${num}`;
|
||||
const full = `battle-${format}-${num}${pw ? `-${pw}` : ""}`;
|
||||
const logData = await getBattleLog(full);
|
||||
if (!logData) {
|
||||
return this.errorReply(`No logs found for the battle <code>${full}</code>.`);
|
||||
throw new Chat.ErrorMessage(`No logs found for the battle <code>${full}</code>.`);
|
||||
}
|
||||
let log = logData.log;
|
||||
log = log.filter(l => l.startsWith('|c|'));
|
||||
|
|
|
|||
|
|
@ -76,10 +76,10 @@ export const commands: Chat.ChatCommands = {
|
|||
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.`);
|
||||
if (room.battle) throw new Chat.ErrorMessage(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.`);
|
||||
if (target !== text) throw new Chat.ErrorMessage(this.tr`You are not allowed to use filtered words in announcements.`);
|
||||
|
||||
const supportHTML = cmd === 'htmlcreate';
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ export const commands: Chat.ChatCommands = {
|
|||
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.`);
|
||||
throw new Chat.ErrorMessage(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);
|
||||
|
|
@ -108,7 +108,7 @@ export const commands: Chat.ChatCommands = {
|
|||
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.`);
|
||||
if (target !== text) throw new Chat.ErrorMessage(this.tr`You are not allowed to use filtered words in announcements.`);
|
||||
|
||||
const supportHTML = cmd === 'htmledit';
|
||||
|
||||
|
|
@ -134,12 +134,12 @@ export const commands: Chat.ChatCommands = {
|
|||
if (target) {
|
||||
this.checkCan('minigame', null, room);
|
||||
if (target === 'clear') {
|
||||
if (!announcement.endTimer()) return this.errorReply(this.tr`There is no timer to clear.`);
|
||||
if (!announcement.endTimer()) throw new Chat.ErrorMessage(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.`);
|
||||
throw new Chat.ErrorMessage(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)}.`);
|
||||
|
|
|
|||
|
|
@ -633,8 +633,8 @@ export class Auction extends Rooms.SimpleRoomGame {
|
|||
this.room.update();
|
||||
try {
|
||||
this.bid(user, parseCredits(message));
|
||||
} catch (e) {
|
||||
if (e instanceof Chat.ErrorMessage) {
|
||||
} catch (e: any) {
|
||||
if (e.name?.endsWith('ErrorMessage')) {
|
||||
user.sendTo(this.room, Utils.html`|raw|<span class="message-error">${e.message}</span>`);
|
||||
} else {
|
||||
user.sendTo(this.room, `|raw|<span class="message-error">An unexpected error occurred while placing your bid.</span>`);
|
||||
|
|
@ -752,14 +752,14 @@ export const commands: Chat.ChatCommands = {
|
|||
create(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('minigame', null, room);
|
||||
if (room.game) return this.errorReply(`There is already a game of ${room.game.title} in progress in this room.`);
|
||||
if (room.settings.auctionDisabled) return this.errorReply('Auctions are currently disabled in this room.');
|
||||
if (room.game) throw new Chat.ErrorMessage(`There is already a game of ${room.game.title} in progress in this room.`);
|
||||
if (room.settings.auctionDisabled) throw new Chat.ErrorMessage('Auctions are currently disabled in this room.');
|
||||
|
||||
let startingCredits;
|
||||
if (target) {
|
||||
startingCredits = parseCredits(target);
|
||||
if (startingCredits < 10000 || startingCredits > 10000000) {
|
||||
return this.errorReply(`Starting credits must be between 10,000 and 10,000,000.`);
|
||||
throw new Chat.ErrorMessage(`Starting credits must be between 10,000 and 10,000,000.`);
|
||||
}
|
||||
}
|
||||
const auction = new Auction(room, startingCredits);
|
||||
|
|
@ -915,13 +915,13 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
if (!target) return this.parse('/help auction importplayers');
|
||||
if (!/^https?:\/\/pastebin\.com\/[a-zA-Z0-9]+$/.test(target)) {
|
||||
return this.errorReply('Invalid pastebin URL.');
|
||||
throw new Chat.ErrorMessage('Invalid pastebin URL.');
|
||||
}
|
||||
let data = '';
|
||||
try {
|
||||
data = await Net(`https://pastebin.com/raw/${target.split('/').pop()}`).get();
|
||||
} catch {}
|
||||
if (!data) return this.errorReply('Error fetching data from pastebin.');
|
||||
if (!data) throw new Chat.ErrorMessage('Error fetching data from pastebin.');
|
||||
|
||||
auction.importPlayers(data);
|
||||
this.addModAction(`${user.name} imported the player list from ${target}.`);
|
||||
|
|
@ -1091,7 +1091,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('gamemanagement', null, room);
|
||||
if (room.settings.auctionDisabled) {
|
||||
return this.errorReply('Auctions are already disabled.');
|
||||
throw new Chat.ErrorMessage('Auctions are already disabled.');
|
||||
}
|
||||
room.settings.auctionDisabled = true;
|
||||
room.saveSettings();
|
||||
|
|
@ -1101,7 +1101,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('gamemanagement', null, room);
|
||||
if (!room.settings.auctionDisabled) {
|
||||
return this.errorReply('Auctions are already enabled.');
|
||||
throw new Chat.ErrorMessage('Auctions are already enabled.');
|
||||
}
|
||||
delete room.settings.auctionDisabled;
|
||||
room.saveSettings();
|
||||
|
|
@ -1161,7 +1161,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.parse(`/auction nominate ${target}`);
|
||||
},
|
||||
bid() {
|
||||
this.errorReply(`/bid is no longer supported. Send the amount by itself in the chat to place your bid.`);
|
||||
throw new Chat.ErrorMessage(`/bid is no longer supported. Send the amount by itself in the chat to place your bid.`);
|
||||
},
|
||||
overpay() {
|
||||
this.requireGame(Auction);
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ async function rustBattleSearch(
|
|||
const { connection, user } = context;
|
||||
const currentDayOfMonth = (new Date()).getDate();
|
||||
if (days < 1 || days > 15) {
|
||||
return context.errorReply(`Days must be between 1 and 15. To search longer ranges, use psbattletools manually on sim3.`);
|
||||
throw new Chat.ErrorMessage(`Days must be between 1 and 15. To search longer ranges, use psbattletools manually on sim3.`);
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -256,9 +256,7 @@ async function rustBattleSearch(
|
|||
env: { PATH: `${process.env.PATH}:${process.env.HOME}/.cargo/bin` },
|
||||
});
|
||||
} catch {
|
||||
return context.errorReply(
|
||||
`You must install <a href="https://crates.io/crates/psbattletools">psbattletools</a> to use the alternate battlesearch.`
|
||||
);
|
||||
throw new Chat.ErrorMessage(`You must install <a href="https://crates.io/crates/psbattletools">psbattletools</a> to use the alternate battlesearch.`);
|
||||
}
|
||||
if (user.lastCommand !== '/battlesearch' && [30, 31, 1].includes(currentDayOfMonth)) {
|
||||
const buf = [`Warning: Usage stats may be running currently.`];
|
||||
|
|
@ -266,7 +264,7 @@ async function rustBattleSearch(
|
|||
buf.push(`Please exercise caution.`);
|
||||
buf.push(`Type the command again to confirm.`);
|
||||
user.lastCommand = '/battlesearch';
|
||||
throw new Chat.ErrorMessage(buf.join('<br />'));
|
||||
throw new Chat.ErrorMessage(buf);
|
||||
}
|
||||
user.lastCommand = '';
|
||||
|
||||
|
|
@ -322,7 +320,7 @@ export const pages: Chat.PageTable = {
|
|||
if (!user.named) return Rooms.RETRY_AFTER_LOGIN;
|
||||
this.checkCan('forcewin');
|
||||
if (Config.nobattlesearch === true) {
|
||||
return this.errorReply(`Battlesearch has been temporarily disabled due to load issues.`);
|
||||
throw new Chat.ErrorMessage(`Battlesearch has been temporarily disabled due to load issues.`);
|
||||
}
|
||||
if (Config.nobattlesearch === 'psbattletools') {
|
||||
return rustBattleSearch(this, args[0], args[1], toID(args[2]));
|
||||
|
|
@ -423,7 +421,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (part.startsWith('limit=')) {
|
||||
const n = parseInt(part.slice('limit='.length).trim());
|
||||
if (isNaN(n)) {
|
||||
return this.errorReply(`Invalid limit: ${part.slice('limit='.length)}`);
|
||||
throw new Chat.ErrorMessage(`Invalid limit: ${part.slice('limit='.length)}`);
|
||||
}
|
||||
turnLimit = n;
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ export const commands: Chat.ChatCommands = {
|
|||
case 'octal': case 'oct': base = 8; break;
|
||||
case 'binary': case 'bin': base = 2; break;
|
||||
default:
|
||||
return this.errorReply(`Unrecognized base "${baseMatchResult[1]}". Valid options are binary or bin, octal or oct, decimal or dec, and hexadecimal or hex.`);
|
||||
throw new Chat.ErrorMessage(`Unrecognized base "${baseMatchResult[1]}". Valid options are binary or bin, octal or oct, decimal or dec, and hexadecimal or hex.`);
|
||||
}
|
||||
}
|
||||
const expression = target.replace(/\b(in|to)\s+([a-zA-Z]+)\b/g, '').trim();
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ export const pages: Chat.PageTable = {
|
|||
async cgtwinrates(query, user) {
|
||||
if (!user.named) return Rooms.RETRY_AFTER_LOGIN;
|
||||
if (!cgtDatabase) {
|
||||
return this.errorReply(`CGT win rates are not being tracked due to the server's SQL settings.`);
|
||||
throw new Chat.ErrorMessage(`CGT win rates are not being tracked due to the server's SQL settings.`);
|
||||
}
|
||||
query = query.join('-').split('--');
|
||||
const mode = query.shift();
|
||||
|
|
@ -97,7 +97,7 @@ export const pages: Chat.PageTable = {
|
|||
let buf = `<div class="pad"><h2>Winrates for [Gen 9] Computer Generated Teams</h2>`;
|
||||
const sorter = toID(query.shift() || 'alphabetical');
|
||||
if (!['alphabetical', 'level'].includes(sorter)) {
|
||||
return this.errorReply(`Invalid sorting method. Must be either 'alphabetical' or 'level'.`);
|
||||
throw new Chat.ErrorMessage(`Invalid sorting method. Must be either 'alphabetical' or 'level'.`);
|
||||
}
|
||||
const otherSort = sorter === 'alphabetical' ? 'Level' : 'Alphabetical';
|
||||
buf += `<a class="button" target="replace" href="/view-cgtwinrates-current--${toID(otherSort)}">`;
|
||||
|
|
|
|||
|
|
@ -625,11 +625,11 @@ export const commands: Chat.ChatCommands = {
|
|||
list = toID(list);
|
||||
|
||||
if (!list || !rest.length) {
|
||||
return this.errorReply(`Syntax: /filter add list ${separator} word ${separator} reason [${separator} optional public reason]`);
|
||||
throw new Chat.ErrorMessage(`Syntax: /filter add list ${separator} word ${separator} reason [${separator} optional public reason]`);
|
||||
}
|
||||
|
||||
if (!(list in filterWords)) {
|
||||
return this.errorReply(`Invalid list: ${list}. Possible options: ${Object.keys(filterWords).join(', ')}`);
|
||||
throw new Chat.ErrorMessage(`Invalid list: ${list}. Possible options: ${Object.keys(filterWords).join(', ')}`);
|
||||
}
|
||||
|
||||
const filterWord = { list, word: '' } as Partial<FilterWord> & { list: string, word: string };
|
||||
|
|
@ -638,7 +638,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (Chat.monitors[list].punishment === 'FILTERTO') {
|
||||
[filterWord.word, filterWord.replacement, filterWord.reason, filterWord.publicReason] = rest;
|
||||
if (!filterWord.replacement) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`Syntax for word filters: /filter add ${list} ${separator} regex ${separator} reason [${separator} optional public reason]`
|
||||
);
|
||||
}
|
||||
|
|
@ -648,7 +648,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
filterWord.word = filterWord.word.trim();
|
||||
if (!filterWord.word) {
|
||||
return this.errorReply(`Invalid word: '${filterWord.word}'.`);
|
||||
throw new Chat.ErrorMessage(`Invalid word: '${filterWord.word}'.`);
|
||||
}
|
||||
Filters.add(filterWord);
|
||||
const reason = filterWord.reason ? ` (${filterWord.reason})` : '';
|
||||
|
|
@ -667,15 +667,15 @@ export const commands: Chat.ChatCommands = {
|
|||
let [list, ...words] = target.split(target.includes('\n') ? '\n' : ',').map(param => param.trim());
|
||||
list = toID(list);
|
||||
|
||||
if (!list || !words.length) return this.errorReply("Syntax: /filter remove list, words");
|
||||
if (!list || !words.length) throw new Chat.ErrorMessage("Syntax: /filter remove list, words");
|
||||
|
||||
if (!(list in filterWords)) {
|
||||
return this.errorReply(`Invalid list: ${list}. Possible options: ${Object.keys(filterWords).join(', ')}`);
|
||||
throw new Chat.ErrorMessage(`Invalid list: ${list}. Possible options: ${Object.keys(filterWords).join(', ')}`);
|
||||
}
|
||||
|
||||
const notFound = words.filter(val => !filterWords[list].filter(entry => entry.word === val).length);
|
||||
if (notFound.length) {
|
||||
return this.errorReply(`${notFound.join(', ')} ${Chat.plural(notFound, "are", "is")} not on the ${list} list.`);
|
||||
throw new Chat.ErrorMessage(`${notFound.join(', ')} ${Chat.plural(notFound, "are", "is")} not on the ${list} list.`);
|
||||
}
|
||||
filterWords[list] = filterWords[list].filter(entry => !words.includes(entry.word));
|
||||
|
||||
|
|
@ -751,9 +751,9 @@ export const commands: Chat.ChatCommands = {
|
|||
allowname(target, room, user) {
|
||||
this.checkCan('forcerename');
|
||||
target = toID(target);
|
||||
if (!target) return this.errorReply(`Syntax: /allowname username`);
|
||||
if (!target) throw new Chat.ErrorMessage(`Syntax: /allowname username`);
|
||||
if (Punishments.namefilterwhitelist.has(target)) {
|
||||
return this.errorReply(`${target} is already allowed as a username.`);
|
||||
throw new Chat.ErrorMessage(`${target} is already allowed as a username.`);
|
||||
}
|
||||
|
||||
const msg = `${target} was allowed as a username by ${user.name}.`;
|
||||
|
|
|
|||
|
|
@ -875,25 +875,25 @@ export const pages: Chat.PageTable = {
|
|||
if (room) {
|
||||
this.checkCan('declare', null, room);
|
||||
} else {
|
||||
return this.errorReply(`Access denied.`);
|
||||
throw new Chat.ErrorMessage(`Access denied.`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!user.can('rangeban')) {
|
||||
// Some chatlogs can only be viewed by upper staff
|
||||
if (roomid.startsWith('spl') && roomid !== 'splatoon') {
|
||||
return this.errorReply("SPL team discussions are super secret.");
|
||||
throw new Chat.ErrorMessage("SPL team discussions are super secret.");
|
||||
}
|
||||
if (roomid.startsWith('wcop')) {
|
||||
return this.errorReply("WCOP team discussions are super secret.");
|
||||
throw new Chat.ErrorMessage("WCOP team discussions are super secret.");
|
||||
}
|
||||
if (UPPER_STAFF_ROOMS.includes(roomid) && !user.inRooms.has(roomid)) {
|
||||
return this.errorReply("Upper staff rooms are super secret.");
|
||||
throw new Chat.ErrorMessage("Upper staff rooms are super secret.");
|
||||
}
|
||||
}
|
||||
if (room) {
|
||||
if (!user.can('lock') || room.settings.isPrivate === 'hidden' && !room.checkModjoin(user)) {
|
||||
if (!room.persist) return this.errorReply(`Access denied.`);
|
||||
if (!room.persist) throw new Chat.ErrorMessage(`Access denied.`);
|
||||
this.checkCan('mute', null, room);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -914,7 +914,7 @@ export const pages: Chat.PageTable = {
|
|||
const validNonDateTerm = search ? validDateStrings.includes(date) : date === 'today';
|
||||
// this is apparently the best way to tell if a date is invalid
|
||||
if (isNaN(parsedDate.getTime()) && !validNonDateTerm) {
|
||||
return this.errorReply(`Invalid date.`);
|
||||
throw new Chat.ErrorMessage(`Invalid date.`);
|
||||
}
|
||||
|
||||
const isTime = opts?.startsWith('time-');
|
||||
|
|
@ -943,15 +943,15 @@ export const pages: Chat.PageTable = {
|
|||
this.checkCan('mute', null, room);
|
||||
} else {
|
||||
if (!user.can('bypassall')) {
|
||||
return this.errorReply(`You cannot view logs for rooms that no longer exist.`);
|
||||
throw new Chat.ErrorMessage(`You cannot view logs for rooms that no longer exist.`);
|
||||
}
|
||||
}
|
||||
const [, date, target] = Utils.splitFirst(args.join('-'), '--', 3).map(item => item.trim());
|
||||
if (isNaN(new Date(date).getTime())) {
|
||||
return this.errorReply(`Invalid date.`);
|
||||
throw new Chat.ErrorMessage(`Invalid date.`);
|
||||
}
|
||||
if (!LogReader.isMonth(date)) {
|
||||
return this.errorReply(`You must specify an exact month - both a year and a month.`);
|
||||
throw new Chat.ErrorMessage(`You must specify an exact month - both a year and a month.`);
|
||||
}
|
||||
this.title = `[Log Stats] ${date}`;
|
||||
return LogSearcher.runLinecountSearch(this, room ? room.roomid : args[0] as RoomID, date, toID(target));
|
||||
|
|
@ -960,7 +960,7 @@ export const pages: Chat.PageTable = {
|
|||
this.checkCan('rangeban');
|
||||
const type = toID(query.shift());
|
||||
if (type && !['chat', 'battle', 'all', 'battles'].includes(type)) {
|
||||
return this.errorReply(`Invalid log type.`);
|
||||
throw new Chat.ErrorMessage(`Invalid log type.`);
|
||||
}
|
||||
let title = '';
|
||||
switch (type) {
|
||||
|
|
@ -997,7 +997,7 @@ export const pages: Chat.PageTable = {
|
|||
const args = Utils.splitFirst(query.join('-'), '--', 2);
|
||||
const roomid = toID(args.shift()) as RoomID;
|
||||
if (!roomid) {
|
||||
return this.errorReply(`Specify a room.`);
|
||||
throw new Chat.ErrorMessage(`Specify a room.`);
|
||||
}
|
||||
const date = args.shift() || LogReader.getMonth();
|
||||
this.title = `[${roomid}] Activity Stats (${date})`;
|
||||
|
|
@ -1110,7 +1110,7 @@ export const commands: Chat.ChatCommands = {
|
|||
case 'room': case 'roomid':
|
||||
const tarRoom = Rooms.search(val);
|
||||
if (!tarRoom && !user.can('bypassall')) {
|
||||
return this.errorReply(`Room '${val}' not found.`);
|
||||
throw new Chat.ErrorMessage(`Room '${val}' not found.`);
|
||||
}
|
||||
search.roomid = (
|
||||
tarRoom?.roomid || val.toLowerCase().replace(/[^a-z0-9-]/g, '') as RoomID
|
||||
|
|
@ -1121,14 +1121,14 @@ export const commands: Chat.ChatCommands = {
|
|||
break;
|
||||
case 'date': case 'month': case 'time':
|
||||
if (!LogReader.isMonth(val)) {
|
||||
return this.errorReply(`Invalid date.`);
|
||||
throw new Chat.ErrorMessage(`Invalid date.`);
|
||||
}
|
||||
search.date = val;
|
||||
}
|
||||
}
|
||||
if (!search.roomid) {
|
||||
if (!room) {
|
||||
return this.errorReply(`If you're not specifying a room, you must use this command in a room.`);
|
||||
throw new Chat.ErrorMessage(`If you're not specifying a room, you must use this command in a room.`);
|
||||
}
|
||||
search.roomid = room.roomid;
|
||||
}
|
||||
|
|
@ -1155,7 +1155,7 @@ export const commands: Chat.ChatCommands = {
|
|||
battlelog(target, room, user) {
|
||||
this.checkCan('lock');
|
||||
target = target.trim();
|
||||
if (!target) return this.errorReply(`Specify a battle.`);
|
||||
if (!target) throw new Chat.ErrorMessage(`Specify a battle.`);
|
||||
if (target.startsWith('http://')) target = target.slice(7);
|
||||
if (target.startsWith('https://')) target = target.slice(8);
|
||||
if (target.startsWith(`${Config.routes.client}/`)) target = target.slice(Config.routes.client.length + 1);
|
||||
|
|
@ -1174,7 +1174,7 @@ export const commands: Chat.ChatCommands = {
|
|||
let [roomName, userName] = Utils.splitFirst(target, ',').map(f => f.trim());
|
||||
if (!roomName) {
|
||||
if (!room) {
|
||||
return this.errorReply(`If you are not specifying a room, use this command in a room.`);
|
||||
throw new Chat.ErrorMessage(`If you are not specifying a room, use this command in a room.`);
|
||||
}
|
||||
roomName = room.roomid;
|
||||
}
|
||||
|
|
@ -1194,8 +1194,8 @@ export const commands: Chat.ChatCommands = {
|
|||
const roomid = roomName.toLowerCase().replace(/[^a-z0-9-]+/g, '') as RoomID;
|
||||
if (!roomid) return this.parse('/help getbattlechat');
|
||||
const userid = toID(userName);
|
||||
if (userName && !userid) return this.errorReply(`Invalid username.`);
|
||||
if (!roomid.startsWith('battle-')) return this.errorReply(`You must specify a battle.`);
|
||||
if (userName && !userid) throw new Chat.ErrorMessage(`Invalid username.`);
|
||||
if (!roomid.startsWith('battle-')) throw new Chat.ErrorMessage(`You must specify a battle.`);
|
||||
const tarRoom = Rooms.get(roomid);
|
||||
|
||||
let log: string[];
|
||||
|
|
@ -1208,7 +1208,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const replayData = await Rooms.Replays.get(battleId);
|
||||
if (!replayData) {
|
||||
return this.errorReply(`No room or replay found for that battle.`);
|
||||
throw new Chat.ErrorMessage(`No room or replay found for that battle.`);
|
||||
}
|
||||
log = replayData.log.split('\n');
|
||||
} else {
|
||||
|
|
@ -1217,7 +1217,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const data = JSON.parse(raw);
|
||||
log = data.log ? data.log.split('\n') : [];
|
||||
} catch {
|
||||
return this.errorReply(`No room or replay found for that battle.`);
|
||||
throw new Chat.ErrorMessage(`No room or replay found for that battle.`);
|
||||
}
|
||||
}
|
||||
log = log.filter(l => l.startsWith('|c|'));
|
||||
|
|
@ -1266,7 +1266,7 @@ export const commands: Chat.ChatCommands = {
|
|||
target = target.toLowerCase().replace(/[^a-z0-9-]+/g, '');
|
||||
if (!target) return this.parse(`/help groupchatsearch`);
|
||||
if (target.length < 3) {
|
||||
return this.errorReply(`Too short of a search term.`);
|
||||
throw new Chat.ErrorMessage(`Too short of a search term.`);
|
||||
}
|
||||
const files = await Monitor.logPath(`chat`).readdir();
|
||||
const buffer = [];
|
||||
|
|
@ -1290,7 +1290,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('bypassall');
|
||||
const [id, date] = target.split(',').map(i => i.trim());
|
||||
if (id) room = Rooms.search(toID(id)) as Room | null;
|
||||
if (!room) return this.errorReply(`Either use this command in the target room or specify a room.`);
|
||||
if (!room) throw new Chat.ErrorMessage(`Either use this command in the target room or specify a room.`);
|
||||
return this.parse(`/join view-roominfo-${room}${date ? `--${date}` : ''}`);
|
||||
},
|
||||
roomactivityhelp: [
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ export const pages: Chat.PageTable = {
|
|||
query.shift(); // roomid
|
||||
const sortType = toID(query.shift());
|
||||
if (sortType && !['time', 'alphabet'].includes(sortType)) {
|
||||
return this.errorReply(`Invalid sorting type '${sortType}' - must be either 'time', 'alphabet', or not provided.`);
|
||||
throw new Chat.ErrorMessage(`Invalid sorting type '${sortType}' - must be either 'time', 'alphabet', or not provided.`);
|
||||
}
|
||||
|
||||
let buf = `<div class="pad ladder">`;
|
||||
|
|
@ -145,18 +145,18 @@ export const pages: Chat.PageTable = {
|
|||
export const commands: Chat.ChatCommands = {
|
||||
removedaily(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
let [key, rest] = target.split(',');
|
||||
key = toID(key);
|
||||
if (!key) return this.parse('/help daily');
|
||||
if (!spotlights[room.roomid][key]) return this.errorReply(`Cannot find a daily spotlight with name '${key}'`);
|
||||
if (!spotlights[room.roomid][key]) throw new Chat.ErrorMessage(`Cannot find a daily spotlight with name '${key}'`);
|
||||
|
||||
this.checkCan('announce', null, room);
|
||||
if (rest) {
|
||||
const queueNumber = parseInt(rest);
|
||||
if (isNaN(queueNumber) || queueNumber < 1) return this.errorReply("Invalid queue number");
|
||||
if (isNaN(queueNumber) || queueNumber < 1) throw new Chat.ErrorMessage("Invalid queue number");
|
||||
if (queueNumber >= spotlights[room.roomid][key].length) {
|
||||
return this.errorReply(`Queue number needs to be between 1 and ${spotlights[room.roomid][key].length - 1}`);
|
||||
throw new Chat.ErrorMessage(`Queue number needs to be between 1 and ${spotlights[room.roomid][key].length - 1}`);
|
||||
}
|
||||
spotlights[room.roomid][key].splice(queueNumber, 1);
|
||||
saveSpotlights();
|
||||
|
|
@ -179,21 +179,21 @@ export const commands: Chat.ChatCommands = {
|
|||
swapdailies: 'swapdaily',
|
||||
swapdaily(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!spotlights[room.roomid]) return this.errorReply("There are no dailies for this room.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
if (!spotlights[room.roomid]) throw new Chat.ErrorMessage("There are no dailies for this room.");
|
||||
this.checkCan('announce', null, room);
|
||||
|
||||
const [key, indexStringA, indexStringB] = target.split(',').map(index => toID(index));
|
||||
if (!indexStringB) return this.parse('/help daily');
|
||||
if (!spotlights[room.roomid][key]) return this.errorReply(`Cannot find a daily spotlight with name '${key}'`);
|
||||
if (!spotlights[room.roomid][key]) throw new Chat.ErrorMessage(`Cannot find a daily spotlight with name '${key}'`);
|
||||
if (!(NUMBER_REGEX.test(indexStringA) && NUMBER_REGEX.test(indexStringB))) {
|
||||
return this.errorReply("Queue numbers must be numbers.");
|
||||
throw new Chat.ErrorMessage("Queue numbers must be numbers.");
|
||||
}
|
||||
const indexA = parseInt(indexStringA);
|
||||
const indexB = parseInt(indexStringB);
|
||||
const queueLength = spotlights[room.roomid][key].length;
|
||||
if (indexA < 1 || indexB < 1 || indexA >= queueLength || indexB >= queueLength) {
|
||||
return this.errorReply(`Queue numbers must between 1 and the length of the queue (${queueLength}).`);
|
||||
throw new Chat.ErrorMessage(`Queue numbers must between 1 and the length of the queue (${queueLength}).`);
|
||||
}
|
||||
|
||||
const dailyA = spotlights[room.roomid][key][indexA];
|
||||
|
|
@ -212,7 +212,7 @@ export const commands: Chat.ChatCommands = {
|
|||
replacedaily: 'setdaily',
|
||||
async setdaily(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
let key, indexString, rest;
|
||||
if (cmd.endsWith('at') || cmd === 'replacedaily') {
|
||||
[key, indexString, ...rest] = target.split(',');
|
||||
|
|
@ -221,16 +221,16 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
key = toID(key);
|
||||
if (!key) return this.parse('/help daily');
|
||||
if (key.length > 20) return this.errorReply("Spotlight names can be a maximum of 20 characters long.");
|
||||
if (key.length > 20) throw new Chat.ErrorMessage("Spotlight names can be a maximum of 20 characters long.");
|
||||
if (key === 'constructor') return false;
|
||||
if (!spotlights[room.roomid]) spotlights[room.roomid] = {};
|
||||
const queueLength = spotlights[room.roomid][key]?.length || 0;
|
||||
|
||||
if (indexString && !NUMBER_REGEX.test(indexString)) return this.errorReply("The queue number must be a number.");
|
||||
if (indexString && !NUMBER_REGEX.test(indexString)) throw new Chat.ErrorMessage("The queue number must be a number.");
|
||||
|
||||
const index = (indexString ? parseInt(indexString) : queueLength);
|
||||
if (indexString && (index < 1 || index > queueLength)) {
|
||||
return this.errorReply(`Queue numbers must be between 1 and the length of the queue (${queueLength}).`);
|
||||
throw new Chat.ErrorMessage(`Queue numbers must be between 1 and the length of the queue (${queueLength}).`);
|
||||
}
|
||||
|
||||
this.checkCan('announce', null, room);
|
||||
|
|
@ -242,12 +242,12 @@ export const commands: Chat.ChatCommands = {
|
|||
try {
|
||||
[width, height] = await Chat.fitImage(img);
|
||||
} catch {
|
||||
return this.errorReply(`Invalid image url: ${img}`);
|
||||
throw new Chat.ErrorMessage(`Invalid image url: ${img}`);
|
||||
}
|
||||
}
|
||||
const desc = rest.join(',');
|
||||
if (Chat.stripFormatting(desc).length > 500) {
|
||||
return this.errorReply("Descriptions can be at most 500 characters long.");
|
||||
throw new Chat.ErrorMessage("Descriptions can be at most 500 characters long.");
|
||||
}
|
||||
if (img) img = [img, width, height] as StoredImage;
|
||||
const obj = { image: img, description: desc, time: Date.now() };
|
||||
|
|
@ -277,12 +277,12 @@ export const commands: Chat.ChatCommands = {
|
|||
},
|
||||
async daily(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
const key = toID(target);
|
||||
if (!key) return this.parse('/help daily');
|
||||
|
||||
if (!spotlights[room.roomid]?.[key]) {
|
||||
return this.errorReply(`Cannot find a daily spotlight with name '${key}'`);
|
||||
throw new Chat.ErrorMessage(`Cannot find a daily spotlight with name '${key}'`);
|
||||
}
|
||||
|
||||
if (!this.runBroadcast()) return;
|
||||
|
|
@ -301,7 +301,7 @@ export const commands: Chat.ChatCommands = {
|
|||
dailies: 'viewspotlights',
|
||||
viewspotlights(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
target = toID(target);
|
||||
return this.parse(`/join view-spotlights-${room.roomid}${target ? `-${target}` : ''}`);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ export const commands: Chat.ChatCommands = {
|
|||
async dexsearch(target, room, user, connection, cmd, message) {
|
||||
this.checkBroadcast();
|
||||
if (!target) return this.parse('/help dexsearch');
|
||||
if (target.length > 300) return this.errorReply('Dexsearch queries may not be longer than 300 characters.');
|
||||
if (target.length > 300) throw new Chat.ErrorMessage('Dexsearch queries may not be longer than 300 characters.');
|
||||
const targetGen = parseInt(cmd[cmd.length - 1]);
|
||||
if (targetGen) target += `, mod=gen${targetGen}`;
|
||||
const split = target.split(',').map(term => term.trim());
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ export const commands: Chat.ChatCommands = {
|
|||
viewlist(target, room, user) {
|
||||
Friends.checkCanUse(this);
|
||||
target = toID(target);
|
||||
if (!target) return this.errorReply(`Specify a user.`);
|
||||
if (!target) throw new Chat.ErrorMessage(`Specify a user.`);
|
||||
if (target === user.id) return this.parse(`/friends list`);
|
||||
return this.parse(`/j view-friends-viewuser-${target}`);
|
||||
},
|
||||
|
|
@ -261,7 +261,7 @@ export const commands: Chat.ChatCommands = {
|
|||
Friends.checkCanUse(this);
|
||||
target = toID(target);
|
||||
if (target.length > 18) {
|
||||
return this.errorReply(this.tr`That name is too long - choose a valid name.`);
|
||||
throw new Chat.ErrorMessage(this.tr`That name is too long - choose a valid name.`);
|
||||
}
|
||||
if (!target) return this.parse('/help friends');
|
||||
await Friends.request(user, target as ID);
|
||||
|
|
@ -292,7 +292,7 @@ export const commands: Chat.ChatCommands = {
|
|||
Friends.checkCanUse(this);
|
||||
target = toID(target);
|
||||
if (user.settings.blockFriendRequests) {
|
||||
return this.errorReply(this.tr`You are currently blocking friend requests, and so cannot accept your own.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are currently blocking friend requests, and so cannot accept your own.`);
|
||||
}
|
||||
if (!target) return this.parse('/help friends');
|
||||
await Friends.approveRequest(user.id, target as ID);
|
||||
|
|
@ -314,7 +314,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse('/help friends');
|
||||
const res = await Friends.removeRequest(user.id, target as ID);
|
||||
if (!res.changes) {
|
||||
return this.errorReply(`You do not have a friend request pending from '${target}'.`);
|
||||
throw new Chat.ErrorMessage(`You do not have a friend request pending from '${target}'.`);
|
||||
}
|
||||
this.refreshPage('friends-received');
|
||||
return sendPM(`You denied a friend request from '${target}'.`, user.id);
|
||||
|
|
@ -324,11 +324,11 @@ export const commands: Chat.ChatCommands = {
|
|||
const setting = user.settings.blockFriendRequests;
|
||||
target = target.trim();
|
||||
if (this.meansYes(target)) {
|
||||
if (!setting) return this.errorReply(this.tr`You already are allowing friend requests.`);
|
||||
if (!setting) throw new Chat.ErrorMessage(this.tr`You already are allowing friend requests.`);
|
||||
user.settings.blockFriendRequests = false;
|
||||
this.sendReply(this.tr`You are now allowing friend requests.`);
|
||||
} else if (this.meansNo(target)) {
|
||||
if (setting) return this.errorReply(this.tr`You already are blocking incoming friend requests.`);
|
||||
if (setting) throw new Chat.ErrorMessage(this.tr`You already are blocking incoming friend requests.`);
|
||||
user.settings.blockFriendRequests = true;
|
||||
this.sendReply(this.tr`You are now blocking incoming friend requests.`);
|
||||
} else {
|
||||
|
|
@ -355,11 +355,11 @@ export const commands: Chat.ChatCommands = {
|
|||
const setting = user.settings.allowFriendNotifications;
|
||||
target = target.trim();
|
||||
if (!cmd.includes('hide') || target && this.meansYes(target)) {
|
||||
if (setting) return this.errorReply(this.tr(`You are already allowing friend notifications.`));
|
||||
if (setting) throw new Chat.ErrorMessage(this.tr(`You are already allowing friend notifications.`));
|
||||
user.settings.allowFriendNotifications = true;
|
||||
this.sendReply(this.tr(`You will now receive friend notifications.`));
|
||||
} else if (cmd.includes('hide') || target && this.meansNo(target)) {
|
||||
if (!setting) return this.errorReply(this.tr`You are already not receiving friend notifications.`);
|
||||
if (!setting) throw new Chat.ErrorMessage(this.tr`You are already not receiving friend notifications.`);
|
||||
user.settings.allowFriendNotifications = false;
|
||||
this.sendReply(this.tr`You will not receive friend notifications.`);
|
||||
} else {
|
||||
|
|
@ -377,17 +377,17 @@ export const commands: Chat.ChatCommands = {
|
|||
Friends.checkCanUse(this);
|
||||
const setting = user.settings.hideLogins;
|
||||
if (cmd.includes('hide')) {
|
||||
if (setting) return this.errorReply(this.tr`You are already hiding your logins from friends.`);
|
||||
if (setting) throw new Chat.ErrorMessage(this.tr`You are already hiding your logins from friends.`);
|
||||
user.settings.hideLogins = true;
|
||||
await Chat.Friends.hideLoginData(user.id);
|
||||
this.sendReply(`You are now hiding your login times from your friends.`);
|
||||
} else if (cmd.includes('show')) {
|
||||
if (!setting) return this.errorReply(this.tr`You are already allowing friends to see your login times.`);
|
||||
if (!setting) throw new Chat.ErrorMessage(this.tr`You are already allowing friends to see your login times.`);
|
||||
user.settings.hideLogins = false;
|
||||
await Chat.Friends.allowLoginData(user.id);
|
||||
this.sendReply(`You are now allowing your friends to see your login times.`);
|
||||
} else {
|
||||
return this.errorReply(`Invalid setting.`);
|
||||
throw new Chat.ErrorMessage(`Invalid setting.`);
|
||||
}
|
||||
this.refreshPage('friends-settings');
|
||||
user.update();
|
||||
|
|
@ -398,14 +398,14 @@ export const commands: Chat.ChatCommands = {
|
|||
const { public_list: setting } = await Chat.Friends.getSettings(user.id);
|
||||
if (this.meansYes(target)) {
|
||||
if (setting) {
|
||||
return this.errorReply(this.tr`You are already allowing other people to view your friends list.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are already allowing other people to view your friends list.`);
|
||||
}
|
||||
await Chat.Friends.setHideList(user.id, true);
|
||||
this.refreshPage('friends-settings');
|
||||
return this.sendReply(this.tr`You are now allowing other people to view your friends list.`);
|
||||
} else if (this.meansNo(target)) {
|
||||
if (!setting) {
|
||||
return this.errorReply(this.tr`You are already hiding your friends list.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are already hiding your friends list.`);
|
||||
}
|
||||
await Chat.Friends.setHideList(user.id, false);
|
||||
this.refreshPage('friends-settings');
|
||||
|
|
@ -429,19 +429,19 @@ export const commands: Chat.ChatCommands = {
|
|||
target = toID(target);
|
||||
if (this.meansYes(target)) {
|
||||
if (user.settings.displayBattlesToFriends) {
|
||||
return this.errorReply(this.tr`You are already sharing your battles with friends.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are already sharing your battles with friends.`);
|
||||
}
|
||||
user.settings.displayBattlesToFriends = true;
|
||||
this.sendReply(`You are now allowing your friends to see your ongoing battles.`);
|
||||
} else if (this.meansNo(target)) {
|
||||
if (!user.settings.displayBattlesToFriends) {
|
||||
return this.errorReply(this.tr`You are already not sharing your battles with friends.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are already not sharing your battles with friends.`);
|
||||
}
|
||||
user.settings.displayBattlesToFriends = false;
|
||||
this.sendReply(`You are now hiding your ongoing battles from your friends.`);
|
||||
} else {
|
||||
if (!target) return this.parse('/help friends sharebattles');
|
||||
return this.errorReply(`Invalid setting '${target}'. Provide 'on' or 'off'.`);
|
||||
throw new Chat.ErrorMessage(`Invalid setting '${target}'. Provide 'on' or 'off'.`);
|
||||
}
|
||||
user.update();
|
||||
this.refreshPage('friends-settings');
|
||||
|
|
@ -521,12 +521,12 @@ export const pages: Chat.PageTable = {
|
|||
break;
|
||||
case 'viewuser':
|
||||
const target = toID(args.shift());
|
||||
if (!target) return this.errorReply(`Specify a user.`);
|
||||
if (!target) throw new Chat.ErrorMessage(`Specify a user.`);
|
||||
if (target === user.id) {
|
||||
return this.errorReply(`Use /friends list to view your own list.`);
|
||||
throw new Chat.ErrorMessage(`Use /friends list to view your own list.`);
|
||||
}
|
||||
const { public_list: isAllowing } = await Chat.Friends.getSettings(target);
|
||||
if (!isAllowing) return this.errorReply(`${target}'s friends list is not public or they do not have one.`);
|
||||
if (!isAllowing) throw new Chat.ErrorMessage(`${target}'s friends list is not public or they do not have one.`);
|
||||
this.title = `[Friends List] ${target}`;
|
||||
buf += await Friends.visualizePublicList(target);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -177,13 +177,13 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('mute', null, room);
|
||||
const [username, reason] = Utils.splitFirst(target, ',').map(u => u.trim());
|
||||
if (!toID(target)) return this.parse(`/help github`);
|
||||
if (!toID(username)) return this.errorReply("Provide a username.");
|
||||
if (!toID(username)) throw new Chat.ErrorMessage("Provide a username.");
|
||||
if (room.auth.has(toID(GitHub.getUsername(username)))) {
|
||||
return this.errorReply("That user is Dev roomauth. If you need to do this, demote them and try again.");
|
||||
throw new Chat.ErrorMessage("That user is Dev roomauth. If you need to do this, demote them and try again.");
|
||||
}
|
||||
if (!gitData.bans) gitData.bans = {};
|
||||
if (gitData.bans[toID(username)]) {
|
||||
return this.errorReply(`${username} is already gitbanned.`);
|
||||
throw new Chat.ErrorMessage(`${username} is already gitbanned.`);
|
||||
}
|
||||
gitData.bans[toID(username)] = reason || " "; // to ensure it's truthy
|
||||
GitHub.save();
|
||||
|
|
@ -195,7 +195,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('mute', null, room);
|
||||
target = toID(target);
|
||||
if (!target) return this.parse('/help github');
|
||||
if (!gitData.bans?.[target]) return this.errorReply("That user is not gitbanned.");
|
||||
if (!gitData.bans?.[target]) throw new Chat.ErrorMessage("That user is not gitbanned.");
|
||||
delete gitData.bans[target];
|
||||
if (!Object.keys(gitData.bans).length) delete gitData.bans;
|
||||
GitHub.save();
|
||||
|
|
@ -226,7 +226,7 @@ export const commands: Chat.ChatCommands = {
|
|||
target = toID(target);
|
||||
if (!target) return this.parse(`/help github`);
|
||||
const name = gitData.usernames?.[target];
|
||||
if (!name) return this.errorReply(`${target} is not a GitHub username on our list.`);
|
||||
if (!name) throw new Chat.ErrorMessage(`${target} is not a GitHub username on our list.`);
|
||||
delete gitData.usernames?.[target];
|
||||
if (!Object.keys(gitData.usernames || {}).length) delete gitData.usernames;
|
||||
GitHub.save();
|
||||
|
|
@ -251,9 +251,9 @@ export const pages: Chat.PageTable = {
|
|||
github: {
|
||||
bans(query, user) {
|
||||
const room = Rooms.get('development');
|
||||
if (!room) return this.errorReply("No Development room found.");
|
||||
if (!room) throw new Chat.ErrorMessage("No Development room found.");
|
||||
this.checkCan('mute', null, room);
|
||||
if (!gitData.bans) return this.errorReply("There are no gitbans at this time.");
|
||||
if (!gitData.bans) throw new Chat.ErrorMessage("There are no gitbans at this time.");
|
||||
let buf = `<div class="pad"><h2>Current Gitbans:</h2><hr /><ol>`;
|
||||
for (const [username, reason] of Object.entries(gitData.bans)) {
|
||||
buf += `<li><strong>${username}</strong> - ${reason.trim() || '(No reason found)'}</li>`;
|
||||
|
|
@ -262,7 +262,7 @@ export const pages: Chat.PageTable = {
|
|||
return buf;
|
||||
},
|
||||
names() {
|
||||
if (!gitData.usernames) return this.errorReply("There are no GitHub usernames in the list.");
|
||||
if (!gitData.usernames) throw new Chat.ErrorMessage("There are no GitHub usernames in the list.");
|
||||
let buf = `<div class="pad"><h2>Current GitHub username mappings:</h2><hr /><ol>`;
|
||||
for (const [username, name] of Object.entries(gitData.usernames)) {
|
||||
buf += `<li><strong>${username}</strong> - ${name}</li>`;
|
||||
|
|
|
|||
|
|
@ -323,15 +323,15 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
target = target.trim();
|
||||
const text = this.filter(target);
|
||||
if (target !== text) return this.errorReply("You are not allowed to use filtered words in hangmans.");
|
||||
if (target !== text) throw new Chat.ErrorMessage("You are not allowed to use filtered words in hangmans.");
|
||||
const params = text.split(',');
|
||||
|
||||
this.checkCan('minigame', null, room);
|
||||
if (room.settings.hangmanDisabled) return this.errorReply("Hangman is disabled for this room.");
|
||||
if (room.settings.hangmanDisabled) throw new Chat.ErrorMessage("Hangman is disabled for this room.");
|
||||
this.checkChat();
|
||||
if (room.game) return this.errorReply(`There is already a game of ${room.game.title} in progress in this room.`);
|
||||
if (room.game) throw new Chat.ErrorMessage(`There is already a game of ${room.game.title} in progress in this room.`);
|
||||
|
||||
if (!params) return this.errorReply("No word entered.");
|
||||
if (!params) throw new Chat.ErrorMessage("No word entered.");
|
||||
const { phrase, hint } = Hangman.validateParams(params);
|
||||
|
||||
const game = new Hangman(room, user, phrase, hint);
|
||||
|
|
@ -345,7 +345,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
guess(target, room, user) {
|
||||
const word = this.filter(target);
|
||||
if (word !== target) return this.errorReply(`You may not use filtered words in guesses.`);
|
||||
if (word !== target) throw new Chat.ErrorMessage(`You may not use filtered words in guesses.`);
|
||||
this.parse(`/choose ${target}`);
|
||||
},
|
||||
guesshelp: [
|
||||
|
|
@ -369,7 +369,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('gamemanagement', null, room);
|
||||
if (room.settings.hangmanDisabled) {
|
||||
return this.errorReply("Hangman is already disabled.");
|
||||
throw new Chat.ErrorMessage("Hangman is already disabled.");
|
||||
}
|
||||
room.settings.hangmanDisabled = true;
|
||||
room.saveSettings();
|
||||
|
|
@ -380,7 +380,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('gamemanagement', null, room);
|
||||
if (!room.settings.hangmanDisabled) {
|
||||
return this.errorReply("Hangman is already enabled.");
|
||||
throw new Chat.ErrorMessage("Hangman is already enabled.");
|
||||
}
|
||||
delete room.settings.hangmanDisabled;
|
||||
room.saveSettings();
|
||||
|
|
@ -440,7 +440,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const newID = hint.slice(5);
|
||||
const targetRoom = Rooms.search(newID);
|
||||
if (!targetRoom) {
|
||||
return this.errorReply(`Invalid room: ${newID}`);
|
||||
throw new Chat.ErrorMessage(`Invalid room: ${newID}`);
|
||||
}
|
||||
this.room = targetRoom;
|
||||
room = targetRoom;
|
||||
|
|
@ -448,13 +448,13 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
}
|
||||
if (!hangmanData[room.roomid]) {
|
||||
return this.errorReply("There are no hangman words for this room.");
|
||||
throw new Chat.ErrorMessage("There are no hangman words for this room.");
|
||||
}
|
||||
const roomKeys = Object.keys(hangmanData[room.roomid]);
|
||||
const roomKeyIDs = roomKeys.map(toID);
|
||||
const index = roomKeyIDs.indexOf(toID(word));
|
||||
if (index < 0) {
|
||||
return this.errorReply(`That word is not a saved hangman.`);
|
||||
throw new Chat.ErrorMessage(`That word is not a saved hangman.`);
|
||||
}
|
||||
word = roomKeys[index];
|
||||
hints = hints.map(toID);
|
||||
|
|
@ -488,7 +488,7 @@ export const commands: Chat.ChatCommands = {
|
|||
hangmanData[room.roomid] = {};
|
||||
}
|
||||
if (!hangmanData[room.roomid][term]) {
|
||||
return this.errorReply(`Term ${term} not found.`);
|
||||
throw new Chat.ErrorMessage(`Term ${term} not found.`);
|
||||
}
|
||||
if (!hangmanData[room.roomid][term].tags) hangmanData[room.roomid][term].tags = [];
|
||||
for (const [i, tag] of tags.entries()) {
|
||||
|
|
@ -519,13 +519,13 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse('/help hangman');
|
||||
}
|
||||
if (!hangmanData[room.roomid]) {
|
||||
return this.errorReply(`This room has no hangman terms.`);
|
||||
throw new Chat.ErrorMessage(`This room has no hangman terms.`);
|
||||
}
|
||||
if (!hangmanData[room.roomid][term]) {
|
||||
return this.errorReply(`That term was not found.`);
|
||||
throw new Chat.ErrorMessage(`That term was not found.`);
|
||||
}
|
||||
if (!hangmanData[room.roomid][term].tags) {
|
||||
return this.errorReply(`That term has no tags.`);
|
||||
throw new Chat.ErrorMessage(`That term has no tags.`);
|
||||
}
|
||||
if (tags.length) {
|
||||
this.privateModAction(`${user.name} removed ${Chat.count(tags, "tags")} from the hangman term ${term}`);
|
||||
|
|
@ -579,7 +579,7 @@ export const pages: Chat.PageTable = {
|
|||
buf += `<div class="pad"><h2>Hangman entries on ${room.title}</h2>`;
|
||||
const roomTerms = hangmanData[room.roomid];
|
||||
if (!roomTerms) {
|
||||
return this.errorReply(`No hangman terms found for ${room.title}.`);
|
||||
throw new Chat.ErrorMessage(`No hangman terms found for ${room.title}.`);
|
||||
}
|
||||
for (const t in roomTerms) {
|
||||
buf += `<div class="infobox">`;
|
||||
|
|
|
|||
|
|
@ -560,7 +560,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const types = list.map(f => f.toLowerCase().replace(/\s/g, '_'));
|
||||
for (const type of types) {
|
||||
if (!Artemis.LocalClassifier.ATTRIBUTES[type]) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`Invalid classifier type '${type}'. Valid types are ` +
|
||||
Object.keys(Artemis.LocalClassifier.ATTRIBUTES).join(', ')
|
||||
);
|
||||
|
|
@ -574,7 +574,7 @@ export const commands: Chat.ChatCommands = {
|
|||
case 'certainty': case 'c':
|
||||
const num = parseFloat(val);
|
||||
if (isNaN(num) || num < 0 || num > 1) {
|
||||
return this.errorReply(`Certainty must be a number below 1 and above 0.`);
|
||||
throw new Chat.ErrorMessage(`Certainty must be a number below 1 and above 0.`);
|
||||
}
|
||||
if (!punishment.severity) {
|
||||
punishment.severity = { certainty: 0, type: [] };
|
||||
|
|
@ -584,14 +584,14 @@ export const commands: Chat.ChatCommands = {
|
|||
case 'modlog': case 'm':
|
||||
const count = parseInt(val);
|
||||
if (isNaN(count) || count < 0) {
|
||||
return this.errorReply(`Modlog count must be a number above 0.`);
|
||||
throw new Chat.ErrorMessage(`Modlog count must be a number above 0.`);
|
||||
}
|
||||
punishment.modlogCount = count;
|
||||
break;
|
||||
case 'ticket': case 'tt': case 'tickettype':
|
||||
const type = toID(val);
|
||||
if (!(type in checkers)) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`The ticket type '${type}' does not exist or is not supported. ` +
|
||||
`Supported types are ${Object.keys(checkers).join(', ')}.`
|
||||
);
|
||||
|
|
@ -601,7 +601,7 @@ export const commands: Chat.ChatCommands = {
|
|||
case 'p': case 'punishment':
|
||||
const name = toID(val).toUpperCase();
|
||||
if (!ORDERED_PUNISHMENTS.includes(name)) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`Punishment '${name}' not supported. ` +
|
||||
`Supported punishments: ${ORDERED_PUNISHMENTS.join(', ')}`
|
||||
);
|
||||
|
|
@ -610,7 +610,7 @@ export const commands: Chat.ChatCommands = {
|
|||
break;
|
||||
case 'single': case 's':
|
||||
if (!this.meansYes(toID(val))) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`The 'single' value must always be 'on'. ` +
|
||||
`If you don't want it enabled, just do not use this argument type.`
|
||||
);
|
||||
|
|
@ -620,13 +620,13 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
}
|
||||
if (!punishment.ticketType) {
|
||||
return this.errorReply(`Must specify a ticket type to handle.`);
|
||||
throw new Chat.ErrorMessage(`Must specify a ticket type to handle.`);
|
||||
}
|
||||
if (!punishment.punishment) {
|
||||
return this.errorReply(`Must specify a punishment to apply.`);
|
||||
throw new Chat.ErrorMessage(`Must specify a punishment to apply.`);
|
||||
}
|
||||
if (!(punishment.severity?.certainty && punishment.severity?.type.length)) {
|
||||
return this.errorReply(`A severity to monitor for must be specified (certainty).`);
|
||||
throw new Chat.ErrorMessage(`A severity to monitor for must be specified (certainty).`);
|
||||
}
|
||||
for (const curP of settings.punishments) {
|
||||
let matches = 0;
|
||||
|
|
@ -636,7 +636,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
}
|
||||
if (matches === Object.keys(punishment).length) {
|
||||
return this.errorReply(`That punishment is already added.`);
|
||||
throw new Chat.ErrorMessage(`That punishment is already added.`);
|
||||
}
|
||||
}
|
||||
settings.punishments.push(punishment as AutoPunishment);
|
||||
|
|
@ -653,7 +653,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const num = parseInt(target) - 1;
|
||||
if (isNaN(num)) return this.parse(`/h autohelpticket`);
|
||||
const punishment = settings.punishments[num];
|
||||
if (!punishment) return this.errorReply(`There is no punishment at index ${num + 1}.`);
|
||||
if (!punishment) throw new Chat.ErrorMessage(`There is no punishment at index ${num + 1}.`);
|
||||
settings.punishments.splice(num, 1);
|
||||
this.privateGlobalModAction(
|
||||
`${user.name} removed the Artemis helpticket ${punishment.punishment} punishment indexed at ${num + 1}`
|
||||
|
|
@ -679,18 +679,18 @@ export const commands: Chat.ChatCommands = {
|
|||
let message;
|
||||
if (this.meansYes(target)) {
|
||||
if (settings.applyPunishments) {
|
||||
return this.errorReply(`Automatic punishments are already enabled.`);
|
||||
throw new Chat.ErrorMessage(`Automatic punishments are already enabled.`);
|
||||
}
|
||||
settings.applyPunishments = true;
|
||||
message = `${user.name} enabled automatic punishments for the Artemis ticket handler`;
|
||||
} else if (this.meansNo(target)) {
|
||||
if (!settings.applyPunishments) {
|
||||
return this.errorReply(`Automatic punishments are already disabled.`);
|
||||
throw new Chat.ErrorMessage(`Automatic punishments are already disabled.`);
|
||||
}
|
||||
settings.applyPunishments = false;
|
||||
message = `${user.name} disabled automatic punishments for the Artemis ticket handler`;
|
||||
} else {
|
||||
return this.errorReply(`Invalid setting. Must be 'on' or 'off'.`);
|
||||
throw new Chat.ErrorMessage(`Invalid setting. Must be 'on' or 'off'.`);
|
||||
}
|
||||
this.privateGlobalModAction(message);
|
||||
this.globalModlog(`AUTOHELPTICKET TOGGLE`, null, settings.applyPunishments ? 'on' : 'off');
|
||||
|
|
@ -739,7 +739,7 @@ export const pages: Chat.PageTable = {
|
|||
month = Chat.toTimestamp(new Date()).split(' ')[0].slice(0, -3);
|
||||
}
|
||||
if (!month) {
|
||||
return this.errorReply(`Invalid month. Must be in YYYY-MM format.`);
|
||||
throw new Chat.ErrorMessage(`Invalid month. Must be in YYYY-MM format.`);
|
||||
}
|
||||
|
||||
this.title = `[Artemis Ticket Stats] ${month}`;
|
||||
|
|
@ -821,7 +821,7 @@ export const pages: Chat.PageTable = {
|
|||
month = Chat.toTimestamp(new Date()).split(' ')[0].slice(0, -3);
|
||||
}
|
||||
if (!month) {
|
||||
return this.errorReply(`Invalid month. Must be in YYYY-MM format.`);
|
||||
throw new Chat.ErrorMessage(`Invalid month. Must be in YYYY-MM format.`);
|
||||
}
|
||||
this.title = `[Artemis Ticket Logs]`;
|
||||
let buf = `<div class="pad"><h3>Artemis ticket logs</h3><hr />`;
|
||||
|
|
|
|||
|
|
@ -1881,14 +1881,14 @@ export const pages: Chat.PageTable = {
|
|||
this.checkCan('lock');
|
||||
const userid = query.shift();
|
||||
if (!userid) {
|
||||
return this.errorReply(`Specify a userid to view the ticket for.`);
|
||||
throw new Chat.ErrorMessage(`Specify a userid to view the ticket for.`);
|
||||
}
|
||||
const ticket = tickets[toID(userid)];
|
||||
if (!ticket) {
|
||||
return this.errorReply(`Ticket not found.`);
|
||||
throw new Chat.ErrorMessage(`Ticket not found.`);
|
||||
}
|
||||
if (!ticket.text) {
|
||||
return this.errorReply(`That is either not a text ticket, or it has not yet been submitted.`);
|
||||
throw new Chat.ErrorMessage(`That is either not a text ticket, or it has not yet been submitted.`);
|
||||
}
|
||||
const ticketInfo = textTickets[HelpTicket.getTypeId(ticket.type)];
|
||||
this.title = `[Text Ticket] ${ticket.userid}`;
|
||||
|
|
@ -1968,12 +1968,12 @@ export const pages: Chat.PageTable = {
|
|||
this.checkCan('lock');
|
||||
const args = query.join('-').split('--');
|
||||
const userid = toID(args.shift());
|
||||
if (!userid) return this.errorReply(`Specify a userid to view ticket logs for.`);
|
||||
if (!userid) throw new Chat.ErrorMessage(`Specify a userid to view ticket logs for.`);
|
||||
const date = args.shift();
|
||||
if (date) {
|
||||
const parsed = new Date(date);
|
||||
if (!/[0-9]{4}-[0-9]{2}/.test(date) || isNaN(parsed.getTime())) {
|
||||
return this.errorReply(`Invalid date.`);
|
||||
throw new Chat.ErrorMessage(`Invalid date.`);
|
||||
}
|
||||
}
|
||||
const logs = await HelpTicket.getTextLogs(['userid', userid], date);
|
||||
|
|
@ -2254,7 +2254,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (user.can('lock')) {
|
||||
return this.parse('/join view-help-request'); // Globals automatically get the form for reference.
|
||||
}
|
||||
if (!user.named) return this.errorReply(this.tr`You need to choose a username before doing this.`);
|
||||
if (!user.named) throw new Chat.ErrorMessage(this.tr`You need to choose a username before doing this.`);
|
||||
return this.parse(`/join view-help-request${meta}`);
|
||||
},
|
||||
createhelp: [`/helpticket create - Creates a new ticket requesting help from global staff.`],
|
||||
|
|
@ -2573,11 +2573,11 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse(`/help helpticket addnote`);
|
||||
const [ticketName, note] = Utils.splitFirst(target, ',').map(i => i.trim());
|
||||
const ticketId = toID(ticketName);
|
||||
if (!ticketId) return this.errorReply(`Specify the userid that created the ticket you want to mark.`);
|
||||
if (!ticketId) throw new Chat.ErrorMessage(`Specify the userid that created the ticket you want to mark.`);
|
||||
const ticket = tickets[ticketId];
|
||||
if (!ticket) return this.errorReply(`${ticketId} does not have an active ticket.`);
|
||||
if (ticket.resolved) return this.errorReply(`${ticketId}'s ticket has already been resolved.`);
|
||||
if (!note) return this.errorReply(`You must specify a note to add.`);
|
||||
if (!ticket) throw new Chat.ErrorMessage(`${ticketId} does not have an active ticket.`);
|
||||
if (ticket.resolved) throw new Chat.ErrorMessage(`${ticketId}'s ticket has already been resolved.`);
|
||||
if (!note) throw new Chat.ErrorMessage(`You must specify a note to add.`);
|
||||
if (!ticket.notes) ticket.notes = {};
|
||||
ticket.notes[user.id] = note;
|
||||
writeTickets();
|
||||
|
|
@ -2596,14 +2596,16 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse(`/help helpticket removenote`);
|
||||
let [ticketName, staff] = Utils.splitFirst(target, ',').map(i => i.trim());
|
||||
const targetId = toID(ticketName);
|
||||
if (!targetId) return this.errorReply(`Specify the userid that created the ticket you want to remove a note from.`);
|
||||
if (!targetId) {
|
||||
throw new Chat.ErrorMessage(`Specify the userid that created the ticket you want to remove a note from.`);
|
||||
}
|
||||
const ticket = tickets[targetId];
|
||||
if (!ticket || ticket.resolved) return this.errorReply(`${targetId} does not have a pending ticket.`);
|
||||
if (!ticket || ticket.resolved) throw new Chat.ErrorMessage(`${targetId} does not have a pending ticket.`);
|
||||
staff = toID(staff) || user.id;
|
||||
if (!ticket.notes) return this.errorReply(`${targetId}'s ticket does not have any notes.`);
|
||||
if (!ticket.notes) throw new Chat.ErrorMessage(`${targetId}'s ticket does not have any notes.`);
|
||||
const note = ticket.notes[staff];
|
||||
if (!note) {
|
||||
return this.errorReply(`${staff === user.id ? 'you do' : `'${staff}' does`} not have a note on that ticket.`);
|
||||
throw new Chat.ErrorMessage(`${staff === user.id ? 'you do' : `'${staff}' does`} not have a note on that ticket.`);
|
||||
}
|
||||
if (!room || room.roomid !== 'staff') {
|
||||
this.sendReply(`You removed the note '${note}' (by ${staff}) on ${ticket.userid}'s ticket.`);
|
||||
|
|
@ -2633,15 +2635,15 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const typeId = HelpTicket.getTypeId(type);
|
||||
if (!(typeId in textTickets)) {
|
||||
this.errorReply(`'${type}' is not a valid text ticket type.`);
|
||||
return this.errorReply(`Valid types: ${Object.keys(textTickets).join(', ')}.`);
|
||||
throw new Chat.ErrorMessage([`'${type}' is not a valid text ticket type.`,
|
||||
`Valid types: ${Object.keys(textTickets).join(', ')}.`]);
|
||||
}
|
||||
if (!settings.responses[typeId]) {
|
||||
settings.responses[typeId] = {};
|
||||
}
|
||||
if (settings.responses[typeId][name] && !this.cmd.includes('f')) {
|
||||
this.errorReply(`That button already exists for that ticket type.`);
|
||||
return this.errorReply(`Use /ht forceaddresponse to override it if you're sure.`);
|
||||
throw new Chat.ErrorMessage([`That button already exists for that ticket type.`,
|
||||
`Use /ht forceaddresponse to override it if you're sure.`]);
|
||||
}
|
||||
settings.responses[typeId][name] = response;
|
||||
writeSettings();
|
||||
|
|
@ -2660,10 +2662,10 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!toID(type) || !toID(name)) return this.parse(`/help helpticket removeresponse`);
|
||||
const typeId = HelpTicket.getTypeId(type);
|
||||
if (!(type in textTickets)) {
|
||||
return this.errorReply(`'${type}' is not a valid text ticket type.`);
|
||||
throw new Chat.ErrorMessage(`'${type}' is not a valid text ticket type.`);
|
||||
}
|
||||
if (!settings.responses[typeId]?.[name]) {
|
||||
return this.errorReply(`'${name}' is not a response for the ${typeId} ticket type .`);
|
||||
throw new Chat.ErrorMessage(`'${name}' is not a response for the ${typeId} ticket type .`);
|
||||
}
|
||||
delete settings.responses[typeId][name];
|
||||
if (!Object.keys(settings.responses[typeId]).length) {
|
||||
|
|
@ -2684,7 +2686,7 @@ export const commands: Chat.ChatCommands = {
|
|||
let buf = `<strong>Help ticket response buttons `;
|
||||
target = toID(target);
|
||||
if (target && !(target in textTickets)) {
|
||||
return this.errorReply(`Invalid ticket type: ${target}.`);
|
||||
throw new Chat.ErrorMessage(`Invalid ticket type: ${target}.`);
|
||||
}
|
||||
buf += `${target ? `for the type ${target}:` : ""}</strong><hr />`;
|
||||
const table = target ? { [target]: settings.responses[target] } : settings.responses;
|
||||
|
|
@ -2716,7 +2718,7 @@ export const commands: Chat.ChatCommands = {
|
|||
let result = rest !== 'false';
|
||||
const ticket = tickets[toID(targetUsername)];
|
||||
if (!ticket?.open || (ticket.userid !== user.id && !user.can('lock'))) {
|
||||
return this.errorReply(this.tr`${targetUsername} does not have an open ticket.`);
|
||||
throw new Chat.ErrorMessage(this.tr`${targetUsername} does not have an open ticket.`);
|
||||
}
|
||||
if (typeof ticket.text !== 'undefined') {
|
||||
return this.parse(`/helpticket resolve ${target}`);
|
||||
|
|
@ -2747,10 +2749,10 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const punishment = Punishments.roomUserids.nestedGet('staff', toID(targetUsername));
|
||||
if (!targetUser && !Punishments.search(toID(targetUsername)).length) {
|
||||
return this.errorReply(this.tr`User '${targetUsername}' not found.`);
|
||||
throw new Chat.ErrorMessage(this.tr`User '${targetUsername}' not found.`);
|
||||
}
|
||||
if (reason.length > 300) {
|
||||
return this.errorReply(this.tr`The reason is too long. It cannot exceed 300 characters.`);
|
||||
throw new Chat.ErrorMessage(this.tr`The reason is too long. It cannot exceed 300 characters.`);
|
||||
}
|
||||
|
||||
let username;
|
||||
|
|
@ -2846,7 +2848,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const targetID: ID = Users.get(target)?.id || target as ID;
|
||||
const banned = Punishments.isTicketBanned(targetID);
|
||||
if (!banned) {
|
||||
return this.errorReply(this.tr`${target} is not ticket banned.`);
|
||||
throw new Chat.ErrorMessage(this.tr`${target} is not ticket banned.`);
|
||||
}
|
||||
|
||||
const affected = HelpTicket.unban(targetID);
|
||||
|
|
@ -2859,7 +2861,7 @@ export const commands: Chat.ChatCommands = {
|
|||
ignore(target, room, user) {
|
||||
this.checkCan('lock');
|
||||
if (user.settings.ignoreTickets) {
|
||||
return this.errorReply(this.tr`You are already ignoring help ticket notifications. Use /helpticket unignore to receive notifications again.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are already ignoring help ticket notifications. Use /helpticket unignore to receive notifications again.`);
|
||||
}
|
||||
user.settings.ignoreTickets = true;
|
||||
user.update();
|
||||
|
|
@ -2870,7 +2872,7 @@ export const commands: Chat.ChatCommands = {
|
|||
unignore(target, room, user) {
|
||||
this.checkCan('lock');
|
||||
if (!user.settings.ignoreTickets) {
|
||||
return this.errorReply(this.tr`You are not ignoring help ticket notifications. Use /helpticket ignore to stop receiving notifications.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are not ignoring help ticket notifications. Use /helpticket ignore to stop receiving notifications.`);
|
||||
}
|
||||
user.settings.ignoreTickets = false;
|
||||
user.update();
|
||||
|
|
@ -2883,7 +2885,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('makeroom');
|
||||
if (!target) return this.parse(`/help helpticket delete`);
|
||||
const ticket = tickets[toID(target)];
|
||||
if (!ticket) return this.errorReply(this.tr`${target} does not have a ticket.`);
|
||||
if (!ticket) throw new Chat.ErrorMessage(this.tr`${target} does not have a ticket.`);
|
||||
const targetRoom = Rooms.get(`help-${ticket.userid}`);
|
||||
if (targetRoom) {
|
||||
targetRoom.getGame(HelpTicket)!.deleteTicket(user);
|
||||
|
|
@ -2900,7 +2902,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('lock');
|
||||
const [targetString, dateString] = Utils.splitFirst(target, ',').map(i => i.trim());
|
||||
const id = toID(targetString);
|
||||
if (!id) return this.errorReply(`Specify a userid.`);
|
||||
if (!id) throw new Chat.ErrorMessage(`Specify a userid.`);
|
||||
return this.parse(`/j view-help-logs-${id}${dateString ? `--${dateString}` : ''}`);
|
||||
},
|
||||
logshelp: [
|
||||
|
|
@ -2916,11 +2918,11 @@ export const commands: Chat.ChatCommands = {
|
|||
const userid = toID(username);
|
||||
if (!userid) return this.parse(`/help helpticket`);
|
||||
if (!/[0-9]{4}-[0-9]{2}-[0-9]{2}/.test(date)) {
|
||||
return this.errorReply(`Invalid date (must be YYYY-MM-DD format).`);
|
||||
throw new Chat.ErrorMessage(`Invalid date (must be YYYY-MM-DD format).`);
|
||||
}
|
||||
const logPath = Monitor.logPath(`chat/help-${userid}/${date.slice(0, -3)}/${date}.txt`);
|
||||
if (!(await logPath.exists())) {
|
||||
return this.errorReply(`There are no logs for tickets from '${userid}' on the date '${date}'.`);
|
||||
throw new Chat.ErrorMessage(`There are no logs for tickets from '${userid}' on the date '${date}'.`);
|
||||
}
|
||||
if (!(await Monitor.logPath(`private/${userid}`).exists())) {
|
||||
await Monitor.logPath(`private/${userid}`).mkdirp();
|
||||
|
|
@ -2940,11 +2942,11 @@ export const commands: Chat.ChatCommands = {
|
|||
const userid = toID(username);
|
||||
if (!userid) return this.parse(`/help helpticket`);
|
||||
if (!/[0-9]{4}-[0-9]{2}-[0-9]{2}/.test(date)) {
|
||||
return this.errorReply(`Invalid date (must be YYYY-MM-DD format).`);
|
||||
throw new Chat.ErrorMessage(`Invalid date (must be YYYY-MM-DD format).`);
|
||||
}
|
||||
const logPath = Monitor.logPath(`private/${userid}/${date}.txt`);
|
||||
if (!(await logPath.exists())) {
|
||||
return this.errorReply(`There are no logs for tickets from '${userid}' on the date '${date}'.`);
|
||||
throw new Chat.ErrorMessage(`There are no logs for tickets from '${userid}' on the date '${date}'.`);
|
||||
}
|
||||
const monthPath = Monitor.logPath(`chat/help-${userid}/${date.slice(0, -3)}`);
|
||||
if (!(await monthPath.exists())) {
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const types = ['all', 'residential', 'res', 'mobile', 'proxy', 'openproxy'];
|
||||
const type = target ? toID(target) : 'all';
|
||||
if (!types.includes(type)) {
|
||||
return this.errorReply(`'${type}' isn't a valid host type. Specify one of ${types.join(', ')}.`);
|
||||
throw new Chat.ErrorMessage(`'${type}' isn't a valid host type. Specify one of ${types.join(', ')}.`);
|
||||
}
|
||||
return this.parse(`/join view-ranges-${type}`);
|
||||
},
|
||||
|
|
@ -245,11 +245,11 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const [typeString, stringRange, host] = target.split(',').map(part => part.trim());
|
||||
if (!host || !IPTools.hostRegex.test(host)) {
|
||||
return this.errorReply(`Invalid data: ${target}`);
|
||||
throw new Chat.ErrorMessage(`Invalid data: ${target}`);
|
||||
}
|
||||
const type = getHostType(typeString);
|
||||
const range = IPTools.stringToRange(stringRange);
|
||||
if (!range) return this.errorReply(`Couldn't parse IP range '${stringRange}'.`);
|
||||
if (!range) throw new Chat.ErrorMessage(`Couldn't parse IP range '${stringRange}'.`);
|
||||
range.host = `${IPTools.urlToHost(host)}?/${type}`;
|
||||
|
||||
IPTools.sortRanges();
|
||||
|
|
@ -257,7 +257,7 @@ export const commands: Chat.ChatCommands = {
|
|||
try {
|
||||
result = IPTools.checkRangeConflicts(range, IPTools.ranges, widen);
|
||||
} catch (e: any) {
|
||||
return this.errorReply(e.message);
|
||||
throw new Chat.ErrorMessage(e.message);
|
||||
}
|
||||
if (typeof result === 'number') {
|
||||
// Remove the range that is being widened
|
||||
|
|
@ -280,8 +280,8 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse('/help ipranges remove');
|
||||
|
||||
const range = IPTools.stringToRange(target);
|
||||
if (!range) return this.errorReply(`Couldn't parse the IP range '${target}'.`);
|
||||
if (!IPTools.getRange(range.minIP, range.maxIP)) return this.errorReply(`No IP range found at '${target}'.`);
|
||||
if (!range) throw new Chat.ErrorMessage(`Couldn't parse the IP range '${target}'.`);
|
||||
if (!IPTools.getRange(range.minIP, range.maxIP)) throw new Chat.ErrorMessage(`No IP range found at '${target}'.`);
|
||||
|
||||
void IPTools.removeRange(range.minIP, range.maxIP);
|
||||
|
||||
|
|
@ -301,9 +301,9 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse('/help ipranges rename');
|
||||
}
|
||||
const toRename = IPTools.stringToRange(rangeString);
|
||||
if (!toRename) return this.errorReply(`Couldn't parse IP range '${rangeString}'.`);
|
||||
if (!toRename) throw new Chat.ErrorMessage(`Couldn't parse IP range '${rangeString}'.`);
|
||||
const exists = IPTools.getRange(toRename.minIP, toRename.maxIP);
|
||||
if (!exists) return this.errorReply(`No IP range found at '${rangeString}'.`);
|
||||
if (!exists) throw new Chat.ErrorMessage(`No IP range found at '${rangeString}'.`);
|
||||
|
||||
const range = {
|
||||
minIP: toRename.minIP,
|
||||
|
|
@ -338,7 +338,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const types = ['all', 'residential', 'mobile', 'ranges'];
|
||||
const type = target ? toID(target) : 'all';
|
||||
if (!types.includes(type)) {
|
||||
return this.errorReply(`'${type}' isn't a valid host type. Specify one of ${types.join(', ')}.`);
|
||||
throw new Chat.ErrorMessage(`'${type}' isn't a valid host type. Specify one of ${types.join(', ')}.`);
|
||||
}
|
||||
return this.parse(`/join view-hosts-${type}`);
|
||||
},
|
||||
|
|
@ -362,9 +362,9 @@ export const commands: Chat.ChatCommands = {
|
|||
switch (type) {
|
||||
case 'openproxy':
|
||||
for (const host of hosts) {
|
||||
if (!IPTools.ipRegex.test(host)) return this.errorReply(`'${host}' is not a valid IP address.`);
|
||||
if (!IPTools.ipRegex.test(host)) throw new Chat.ErrorMessage(`'${host}' is not a valid IP address.`);
|
||||
if (removing !== IPTools.singleIPOpenProxies.has(host)) {
|
||||
return this.errorReply(`'${host}' is ${removing ? 'not' : 'already'} in the list of proxy IPs.`);
|
||||
throw new Chat.ErrorMessage(`'${host}' is ${removing ? 'not' : 'already'} in the list of proxy IPs.`);
|
||||
}
|
||||
}
|
||||
if (removing) {
|
||||
|
|
@ -375,9 +375,9 @@ export const commands: Chat.ChatCommands = {
|
|||
break;
|
||||
case 'proxy':
|
||||
for (const host of hosts) {
|
||||
if (!IPTools.hostRegex.test(host)) return this.errorReply(`'${host}' is not a valid host.`);
|
||||
if (!IPTools.hostRegex.test(host)) throw new Chat.ErrorMessage(`'${host}' is not a valid host.`);
|
||||
if (removing !== IPTools.proxyHosts.has(host)) {
|
||||
return this.errorReply(`'${host}' is ${removing ? 'not' : 'already'} in the list of proxy hosts.`);
|
||||
throw new Chat.ErrorMessage(`'${host}' is ${removing ? 'not' : 'already'} in the list of proxy hosts.`);
|
||||
}
|
||||
}
|
||||
if (removing) {
|
||||
|
|
@ -388,9 +388,9 @@ export const commands: Chat.ChatCommands = {
|
|||
break;
|
||||
case 'residential':
|
||||
for (const host of hosts) {
|
||||
if (!IPTools.hostRegex.test(host)) return this.errorReply(`'${host}' is not a valid host.`);
|
||||
if (!IPTools.hostRegex.test(host)) throw new Chat.ErrorMessage(`'${host}' is not a valid host.`);
|
||||
if (removing !== IPTools.residentialHosts.has(host)) {
|
||||
return this.errorReply(`'${host}' is ${removing ? 'not' : 'already'} in the list of residential hosts.`);
|
||||
throw new Chat.ErrorMessage(`'${host}' is ${removing ? 'not' : 'already'} in the list of residential hosts.`);
|
||||
}
|
||||
}
|
||||
if (removing) {
|
||||
|
|
@ -401,9 +401,9 @@ export const commands: Chat.ChatCommands = {
|
|||
break;
|
||||
case 'mobile':
|
||||
for (const host of hosts) {
|
||||
if (!IPTools.hostRegex.test(host)) return this.errorReply(`'${host}' is not a valid host.`);
|
||||
if (!IPTools.hostRegex.test(host)) throw new Chat.ErrorMessage(`'${host}' is not a valid host.`);
|
||||
if (removing !== IPTools.mobileHosts.has(host)) {
|
||||
return this.errorReply(`'${host}' is ${removing ? 'not' : 'already'} in the list of mobile hosts.`);
|
||||
throw new Chat.ErrorMessage(`'${host}' is ${removing ? 'not' : 'already'} in the list of mobile hosts.`);
|
||||
}
|
||||
}
|
||||
if (removing) {
|
||||
|
|
@ -413,7 +413,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
break;
|
||||
default:
|
||||
return this.errorReply(`'${type}' isn't one of 'openproxy', 'proxy', 'residential', or 'mobile'.`);
|
||||
throw new Chat.ErrorMessage(`'${type}' isn't one of 'openproxy', 'proxy', 'residential', or 'mobile'.`);
|
||||
}
|
||||
this.privateGlobalModAction(
|
||||
`${user.name} ${removing ? 'removed' : 'added'} ${hosts.length} hosts (${hosts.join(', ')}) ${removing ? 'from' : 'to'} the ${type} category`
|
||||
|
|
@ -441,23 +441,23 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!IPTools.ipRegex.test(ip)) {
|
||||
const pattern = IPTools.stringToRange(ip);
|
||||
if (!pattern) {
|
||||
return this.errorReply("Please enter a valid IP address.");
|
||||
throw new Chat.ErrorMessage("Please enter a valid IP address.");
|
||||
}
|
||||
if (!user.can('rangeban')) {
|
||||
return this.errorReply('Only upper staff can markshare ranges.');
|
||||
throw new Chat.ErrorMessage('Only upper staff can markshare ranges.');
|
||||
}
|
||||
for (const range of Punishments.sharedRanges.keys()) {
|
||||
if (IPTools.rangeIntersects(range, pattern)) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
`Range ${IPTools.rangeToString(pattern)} intersects with shared range ${IPTools.rangeToString(range)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Punishments.isSharedIp(ip)) return this.errorReply("This IP is already marked as shared.");
|
||||
if (Punishments.isSharedIp(ip)) throw new Chat.ErrorMessage("This IP is already marked as shared.");
|
||||
if (Punishments.isBlacklistedSharedIp(ip)) {
|
||||
return this.errorReply(`This IP is blacklisted from being marked as shared.`);
|
||||
throw new Chat.ErrorMessage(`This IP is blacklisted from being marked as shared.`);
|
||||
}
|
||||
if (!note) {
|
||||
this.errorReply(`You must specify who owns this shared IP.`);
|
||||
|
|
@ -479,9 +479,9 @@ export const commands: Chat.ChatCommands = {
|
|||
checkCanPerform(this, user, 'globalban');
|
||||
target = target.trim();
|
||||
const pattern = IPTools.stringToRange(target);
|
||||
if (!pattern) return this.errorReply("Please enter a valid IP address.");
|
||||
if (!pattern) throw new Chat.ErrorMessage("Please enter a valid IP address.");
|
||||
if (pattern.minIP !== pattern.maxIP && !user.can('rangeban')) {
|
||||
return this.errorReply(`Only administrators can unmarkshare ranges.`);
|
||||
throw new Chat.ErrorMessage(`Only administrators can unmarkshare ranges.`);
|
||||
}
|
||||
|
||||
let shared = false;
|
||||
|
|
@ -494,7 +494,7 @@ export const commands: Chat.ChatCommands = {
|
|||
shared = Punishments.sharedIps.has(target);
|
||||
}
|
||||
|
||||
if (!shared) return this.errorReply(`That IP/range isn't marked as shared.`);
|
||||
if (!shared) throw new Chat.ErrorMessage(`That IP/range isn't marked as shared.`);
|
||||
|
||||
Punishments.removeSharedIp(target);
|
||||
|
||||
|
|
@ -510,14 +510,14 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse(`/help nomarkshared`);
|
||||
checkCanPerform(this, user, 'globalban');
|
||||
const [ip, ...reasonArr] = target.split(',');
|
||||
if (!IPTools.ipRangeRegex.test(ip)) return this.errorReply(`Please enter a valid IP address or range.`);
|
||||
if (!IPTools.ipRangeRegex.test(ip)) throw new Chat.ErrorMessage(`Please enter a valid IP address or range.`);
|
||||
if (!reasonArr?.length) {
|
||||
this.errorReply(`A reason is required.`);
|
||||
this.parse(`/help nomarkshared`);
|
||||
return;
|
||||
}
|
||||
if (Punishments.isBlacklistedSharedIp(ip)) {
|
||||
return this.errorReply(`This IP is already blacklisted from being marked as shared.`);
|
||||
throw new Chat.ErrorMessage(`This IP is already blacklisted from being marked as shared.`);
|
||||
}
|
||||
// this works because we test ipRangeRegex above, which works for both ranges AND single ips.
|
||||
// so we know here this is one of the two.
|
||||
|
|
@ -526,15 +526,14 @@ export const commands: Chat.ChatCommands = {
|
|||
// if it doesn't end with *, it doesn't function as a range in IPTools#stringToRange, only as a single IP.
|
||||
// that's valid behavior, but it's detrimental here.
|
||||
if (!ip.endsWith('*')) {
|
||||
this.errorReply(`That looks like a range, but it is invalid.`);
|
||||
this.errorReply(`Append * to the end of the range and try again.`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage([`That looks like a range, but it is invalid.`,
|
||||
`Append * to the end of the range and try again.`]);
|
||||
}
|
||||
if (!user.can('bypassall')) {
|
||||
return this.errorReply(`Only Administrators can add ranges.`);
|
||||
throw new Chat.ErrorMessage(`Only Administrators can add ranges.`);
|
||||
}
|
||||
const range = IPTools.stringToRange(ip);
|
||||
if (!range) return this.errorReply(`Invalid IP range.`);
|
||||
if (!range) throw new Chat.ErrorMessage(`Invalid IP range.`);
|
||||
for (const sharedIp of Punishments.sharedIps.keys()) {
|
||||
const ipNum = IPTools.ipToNumber(sharedIp);
|
||||
if (IPTools.checkPattern([range], ipNum)) {
|
||||
|
|
@ -554,9 +553,9 @@ export const commands: Chat.ChatCommands = {
|
|||
remove(target, room, user) {
|
||||
if (!target) return this.parse(`/help nomarkshared`);
|
||||
checkCanPerform(this, user);
|
||||
if (!IPTools.ipRangeRegex.test(target)) return this.errorReply(`Please enter a valid IP address or range.`);
|
||||
if (!IPTools.ipRangeRegex.test(target)) throw new Chat.ErrorMessage(`Please enter a valid IP address or range.`);
|
||||
if (!Punishments.sharedIpBlacklist.has(target)) {
|
||||
return this.errorReply(`This IP is not blacklisted from being marked as shared.`);
|
||||
throw new Chat.ErrorMessage(`This IP is not blacklisted from being marked as shared.`);
|
||||
}
|
||||
|
||||
Punishments.removeBlacklistedSharedIp(target);
|
||||
|
|
|
|||
|
|
@ -2197,10 +2197,10 @@ export const commands: Chat.ChatCommands = {
|
|||
nexthost: 'host',
|
||||
host(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom();
|
||||
if (room.settings.mafiaDisabled) return this.errorReply(`Mafia is disabled for this room.`);
|
||||
if (room.settings.mafiaDisabled) throw new Chat.ErrorMessage(`Mafia is disabled for this room.`);
|
||||
this.checkChat();
|
||||
if (room.type !== 'chat') return this.errorReply(`This command is only meant to be used in chat rooms.`);
|
||||
if (room.game) return this.errorReply(`There is already a game of ${room.game.title} in progress in this room.`);
|
||||
if (room.type !== 'chat') throw new Chat.ErrorMessage(`This command is only meant to be used in chat rooms.`);
|
||||
if (room.game) throw new Chat.ErrorMessage(`There is already a game of ${room.game.title} in progress in this room.`);
|
||||
|
||||
const nextHost = room.roomid === 'mafia' && cmd === 'nexthost';
|
||||
if (nextHost || !room.auth.has(user.id)) this.checkCan('show', null, room);
|
||||
|
|
@ -2208,7 +2208,7 @@ export const commands: Chat.ChatCommands = {
|
|||
let targetUser!: User | null;
|
||||
let targetUsername!: string;
|
||||
if (nextHost) {
|
||||
if (!hostQueue.length) return this.errorReply(`Nobody is on the host queue.`);
|
||||
if (!hostQueue.length) throw new Chat.ErrorMessage(`Nobody is on the host queue.`);
|
||||
const skipped = [];
|
||||
let hostid;
|
||||
while ((hostid = hostQueue.shift())) {
|
||||
|
|
@ -2225,27 +2225,27 @@ export const commands: Chat.ChatCommands = {
|
|||
if (skipped.length) {
|
||||
this.sendReply(`${skipped.join(', ')} ${Chat.plural(skipped.length, 'were', 'was')} not online, not in the room, or are host banned and were removed from the host queue.`);
|
||||
}
|
||||
if (!targetUser) return this.errorReply(`Nobody on the host queue could be hosted.`);
|
||||
if (!targetUser) throw new Chat.ErrorMessage(`Nobody on the host queue could be hosted.`);
|
||||
} else {
|
||||
({ targetUser, targetUsername } = this.splitUser(target, { exactName: true }));
|
||||
if (room.roomid === 'mafia' && hostQueue.length && toID(targetUsername) !== hostQueue[0]) {
|
||||
if (!cmd.includes('force')) {
|
||||
return this.errorReply(`${targetUsername} isn't the next host on the queue. Use /mafia forcehost if you're sure.`);
|
||||
throw new Chat.ErrorMessage(`${targetUsername} isn't the next host on the queue. Use /mafia forcehost if you're sure.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetUser?.connected) {
|
||||
return this.errorReply(`The user "${targetUsername}" was not found.`);
|
||||
throw new Chat.ErrorMessage(`The user "${targetUsername}" was not found.`);
|
||||
}
|
||||
|
||||
if (!nextHost && targetUser.id !== user.id) this.checkCan('mute', null, room);
|
||||
|
||||
if (!room.users[targetUser.id]) {
|
||||
return this.errorReply(`${targetUsername} is not in this room, and cannot be hosted.`);
|
||||
throw new Chat.ErrorMessage(`${targetUsername} is not in this room, and cannot be hosted.`);
|
||||
}
|
||||
if (Mafia.isHostBanned(room, targetUser)) {
|
||||
return this.errorReply(`${targetUsername} is banned from hosting mafia games.`);
|
||||
throw new Chat.ErrorMessage(`${targetUsername} is banned from hosting mafia games.`);
|
||||
}
|
||||
|
||||
room.game = new Mafia(room, targetUser);
|
||||
|
|
@ -2268,7 +2268,7 @@ export const commands: Chat.ChatCommands = {
|
|||
q: 'queue',
|
||||
queue(target, room, user) {
|
||||
room = this.requireRoom('mafia' as RoomID);
|
||||
if (room.settings.mafiaDisabled) return this.errorReply(`Mafia is disabled for this room.`);
|
||||
if (room.settings.mafiaDisabled) throw new Chat.ErrorMessage(`Mafia is disabled for this room.`);
|
||||
const [command, targetUserID] = target.split(',').map(toID);
|
||||
|
||||
switch (command) {
|
||||
|
|
@ -2284,11 +2284,11 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!targetUserID) return this.parse(`/help mafia queue`);
|
||||
const targetUser = Users.get(targetUserID);
|
||||
if ((!targetUser?.connected) && !command.includes('force')) {
|
||||
return this.errorReply(`User ${targetUserID} not found. To forcefully add the user to the queue, use /mafia queue forceadd, ${targetUserID}`);
|
||||
throw new Chat.ErrorMessage(`User ${targetUserID} not found. To forcefully add the user to the queue, use /mafia queue forceadd, ${targetUserID}`);
|
||||
}
|
||||
if (hostQueue.includes(targetUserID)) return this.errorReply(`User ${targetUserID} is already on the host queue.`);
|
||||
if (hostQueue.includes(targetUserID)) throw new Chat.ErrorMessage(`User ${targetUserID} is already on the host queue.`);
|
||||
if (targetUser && Mafia.isHostBanned(room, targetUser)) {
|
||||
return this.errorReply(`User ${targetUserID} is banned from hosting mafia games.`);
|
||||
throw new Chat.ErrorMessage(`User ${targetUserID} is banned from hosting mafia games.`);
|
||||
}
|
||||
hostQueue.push(targetUserID);
|
||||
room.add(`User ${targetUserID} has been added to the host queue by ${user.name}.`).update();
|
||||
|
|
@ -2299,7 +2299,7 @@ export const commands: Chat.ChatCommands = {
|
|||
// anyone can self remove
|
||||
if (targetUserID !== user.id) this.checkCan('mute', null, room);
|
||||
const index = hostQueue.indexOf(targetUserID);
|
||||
if (index === -1) return this.errorReply(`User ${targetUserID} is not on the host queue.`);
|
||||
if (index === -1) throw new Chat.ErrorMessage(`User ${targetUserID} is not on the host queue.`);
|
||||
hostQueue.splice(index, 1);
|
||||
room.add(`User ${targetUserID} has been removed from the host queue by ${user.name}.`).update();
|
||||
break;
|
||||
|
|
@ -2352,13 +2352,13 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (game.phase !== 'signups') return this.errorReply(`Signups are already closed.`);
|
||||
if (game.phase !== 'signups') throw new Chat.ErrorMessage(`Signups are already closed.`);
|
||||
const num = parseInt(target);
|
||||
if (isNaN(num) || num > 50 || num < 2) return this.parse('/help mafia playercap');
|
||||
if (num < game.playerCount) {
|
||||
return this.errorReply(`Player cap has to be equal or more than the amount of players in game.`);
|
||||
throw new Chat.ErrorMessage(`Player cap has to be equal or more than the amount of players in game.`);
|
||||
}
|
||||
if (num === game.playerCap) return this.errorReply(`Player cap is already set at ${game.playerCap}.`);
|
||||
if (num === game.playerCap) throw new Chat.ErrorMessage(`Player cap is already set at ${game.playerCap}.`);
|
||||
game.playerCap = num;
|
||||
game.sendDeclare(`Player cap has been set to ${game.playerCap}`);
|
||||
game.logAction(user, `set playercap to ${num}`);
|
||||
|
|
@ -2371,8 +2371,8 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (game.phase !== 'signups') return this.errorReply(`Signups are already closed.`);
|
||||
if (game.playerCount < 2) return this.errorReply(`You need at least 2 players to start.`);
|
||||
if (game.phase !== 'signups') throw new Chat.ErrorMessage(`Signups are already closed.`);
|
||||
if (game.playerCount < 2) throw new Chat.ErrorMessage(`You need at least 2 players to start.`);
|
||||
game.phase = 'locked';
|
||||
game.sendHTML(game.roomWindow());
|
||||
game.updatePlayers();
|
||||
|
|
@ -2388,10 +2388,10 @@ export const commands: Chat.ChatCommands = {
|
|||
const action = toID(target);
|
||||
if (!['on', 'off'].includes(action)) return this.parse('/help mafia closedsetup');
|
||||
if (game.started) {
|
||||
return this.errorReply(`You can't ${action === 'on' ? 'enable' : 'disable'} closed setup because the game has already started.`);
|
||||
throw new Chat.ErrorMessage(`You can't ${action === 'on' ? 'enable' : 'disable'} closed setup because the game has already started.`);
|
||||
}
|
||||
if ((action === 'on' && game.closedSetup) || (action === 'off' && !game.closedSetup)) {
|
||||
return this.errorReply(`Closed setup is already ${game.closedSetup ? 'enabled' : 'disabled'}.`);
|
||||
throw new Chat.ErrorMessage(`Closed setup is already ${game.closedSetup ? 'enabled' : 'disabled'}.`);
|
||||
}
|
||||
game.closedSetup = action === 'on';
|
||||
game.sendDeclare(`The game is ${action === 'on' ? 'now' : 'no longer'} a closed setup.`);
|
||||
|
|
@ -2428,7 +2428,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const action = toID(target);
|
||||
if (!['on', 'off'].includes(action)) return this.parse('/help mafia takeidles');
|
||||
if ((action === 'off' && !game.takeIdles) || (action === 'on' && game.takeIdles)) {
|
||||
return this.errorReply(`Actions and idles are already ${game.takeIdles ? '' : 'not '}being accepted.`);
|
||||
throw new Chat.ErrorMessage(`Actions and idles are already ${game.takeIdles ? '' : 'not '}being accepted.`);
|
||||
}
|
||||
game.takeIdles = action === 'on';
|
||||
game.sendDeclare(`Actions and idles are ${game.takeIdles ? 'now' : 'no longer'} being accepted.`);
|
||||
|
|
@ -2445,10 +2445,12 @@ export const commands: Chat.ChatCommands = {
|
|||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
const reset = cmd.includes('reset');
|
||||
if (reset) {
|
||||
if (game.phase !== 'day' && game.phase !== 'night') return this.errorReply(`The game has not started yet.`);
|
||||
if (game.phase !== 'day' && game.phase !== 'night') throw new Chat.ErrorMessage(`The game has not started yet.`);
|
||||
} else {
|
||||
if (game.phase !== 'locked' && game.phase !== 'IDEAlocked') {
|
||||
return this.errorReply(game.phase === 'signups' ? `You need to close signups first.` : `The game has already started.`);
|
||||
throw new Chat.ErrorMessage(
|
||||
game.phase === 'signups' ? `You need to close signups first.` : `The game has already started.`
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!target) return this.parse('/help mafia setroles');
|
||||
|
|
@ -2469,8 +2471,8 @@ export const commands: Chat.ChatCommands = {
|
|||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (target) return this.parse('/help mafia resetgame');
|
||||
if (game.phase !== 'day' && game.phase !== 'night') return this.errorReply(`The game has not started yet.`);
|
||||
if (game.IDEA.data) return this.errorReply(`You cannot use this command in IDEA.`);
|
||||
if (game.phase !== 'day' && game.phase !== 'night') throw new Chat.ErrorMessage(`The game has not started yet.`);
|
||||
if (game.IDEA.data) throw new Chat.ErrorMessage(`You cannot use this command in IDEA.`);
|
||||
game.resetGame();
|
||||
game.logAction(user, 'reset the game state');
|
||||
},
|
||||
|
|
@ -2483,11 +2485,11 @@ export const commands: Chat.ChatCommands = {
|
|||
const game = this.requireGame(Mafia);
|
||||
this.checkCan('show', null, room);
|
||||
if (!user.can('mute', null, room) && game.hostid !== user.id && !game.cohostids.includes(user.id)) {
|
||||
return this.errorReply(`/mafia idea - Access denied.`);
|
||||
throw new Chat.ErrorMessage(`/mafia idea - Access denied.`);
|
||||
}
|
||||
if (game.started) return this.errorReply(`You cannot start an IDEA after the game has started.`);
|
||||
if (game.started) throw new Chat.ErrorMessage(`You cannot start an IDEA after the game has started.`);
|
||||
if (game.phase !== 'locked' && game.phase !== 'IDEAlocked') {
|
||||
return this.errorReply(`You need to close the signups first.`);
|
||||
throw new Chat.ErrorMessage(`You need to close the signups first.`);
|
||||
}
|
||||
game.ideaInit(user, toID(target));
|
||||
game.logAction(user, `started an IDEA`);
|
||||
|
|
@ -2503,17 +2505,17 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.started) return this.errorReply(`You cannot start an IDEA after the game has started.`);
|
||||
if (game.started) throw new Chat.ErrorMessage(`You cannot start an IDEA after the game has started.`);
|
||||
if (game.phase !== 'locked' && game.phase !== 'IDEAlocked') {
|
||||
return this.errorReply(`You need to close the signups first.`);
|
||||
throw new Chat.ErrorMessage(`You need to close the signups first.`);
|
||||
}
|
||||
const [options, roles] = Utils.splitFirst(target, '\n');
|
||||
if (!options || !roles) return this.parse('/help mafia idea');
|
||||
const [choicesStr, ...picks] = options.split(',').map(x => x.trim());
|
||||
const choices = parseInt(choicesStr);
|
||||
if (!choices || choices <= picks.length) return this.errorReply(`You need to have more choices than picks.`);
|
||||
if (!choices || choices <= picks.length) throw new Chat.ErrorMessage(`You need to have more choices than picks.`);
|
||||
if (picks.some((value, index, arr) => arr.indexOf(value, index + 1) > 0)) {
|
||||
return this.errorReply(`Your picks must be unique.`);
|
||||
throw new Chat.ErrorMessage(`Your picks must be unique.`);
|
||||
}
|
||||
game.customIdeaInit(user, choices, picks, roles);
|
||||
},
|
||||
|
|
@ -2532,7 +2534,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return user.sendTo(room, '|error|You are not a player in the game.');
|
||||
}
|
||||
if (game.phase !== 'IDEApicking') {
|
||||
return this.errorReply(`The game is not in the IDEA picking phase.`);
|
||||
throw new Chat.ErrorMessage(`The game is not in the IDEA picking phase.`);
|
||||
}
|
||||
game.ideaPick(user, args); // TODO use player object
|
||||
},
|
||||
|
|
@ -2550,14 +2552,14 @@ export const commands: Chat.ChatCommands = {
|
|||
ideadiscards(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (!game.IDEA.data) return this.errorReply(`There is no IDEA module in the mafia game.`);
|
||||
if (!game.IDEA.data) throw new Chat.ErrorMessage(`There is no IDEA module in the mafia game.`);
|
||||
if (target) {
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (this.meansNo(target)) {
|
||||
if (game.IDEA.discardsHidden) return this.errorReply(`IDEA discards are already hidden.`);
|
||||
if (game.IDEA.discardsHidden) throw new Chat.ErrorMessage(`IDEA discards are already hidden.`);
|
||||
game.IDEA.discardsHidden = true;
|
||||
} else if (this.meansYes(target)) {
|
||||
if (!game.IDEA.discardsHidden) return this.errorReply(`IDEA discards are already visible.`);
|
||||
if (!game.IDEA.discardsHidden) throw new Chat.ErrorMessage(`IDEA discards are already visible.`);
|
||||
game.IDEA.discardsHidden = false;
|
||||
} else {
|
||||
return this.parse('/help mafia ideadiscards');
|
||||
|
|
@ -2565,8 +2567,8 @@ export const commands: Chat.ChatCommands = {
|
|||
game.logAction(user, `${game.IDEA.discardsHidden ? 'hid' : 'unhid'} IDEA discards`);
|
||||
return this.sendReply(`IDEA discards are now ${game.IDEA.discardsHidden ? 'hidden' : 'visible'}.`);
|
||||
}
|
||||
if (game.IDEA.discardsHidden) return this.errorReply(`Discards are not visible.`);
|
||||
if (!game.IDEA.discardsHTML) return this.errorReply(`The IDEA module does not have finalised discards yet.`);
|
||||
if (game.IDEA.discardsHidden) throw new Chat.ErrorMessage(`Discards are not visible.`);
|
||||
if (!game.IDEA.discardsHTML) throw new Chat.ErrorMessage(`The IDEA module does not have finalised discards yet.`);
|
||||
if (!this.runBroadcast()) return;
|
||||
this.sendReplyBox(`<details><summary>IDEA discards:</summary>${game.IDEA.discardsHTML}</details>`);
|
||||
},
|
||||
|
|
@ -2649,7 +2651,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkChat(null, room);
|
||||
const player = game.getPlayer(user.id);
|
||||
if (!player || (player.isEliminated() && !player.isSpirit())) {
|
||||
return this.errorReply(`You are not in the game of ${game.title}.`);
|
||||
throw new Chat.ErrorMessage(`You are not in the game of ${game.title}.`);
|
||||
}
|
||||
game.vote(player, toID(target));
|
||||
},
|
||||
|
|
@ -2664,7 +2666,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkChat(null, room);
|
||||
const player = game.getPlayer(user.id);
|
||||
if (!player || (player.isEliminated() && !player.isSpirit())) {
|
||||
return this.errorReply(`You are not in the game of ${game.title}.`);
|
||||
throw new Chat.ErrorMessage(`You are not in the game of ${game.title}.`);
|
||||
}
|
||||
game.unvote(player);
|
||||
},
|
||||
|
|
@ -2706,12 +2708,12 @@ export const commands: Chat.ChatCommands = {
|
|||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (game.phase === 'IDEApicking') {
|
||||
return this.errorReply(`You cannot add or remove players while IDEA roles are being picked.`); // needs to be here since eliminate doesn't pass the user
|
||||
throw new Chat.ErrorMessage(`You cannot add or remove players while IDEA roles are being picked.`); // needs to be here since eliminate doesn't pass the user
|
||||
}
|
||||
if (!target) return this.parse('/help mafia kill');
|
||||
const player = game.getPlayer(toID(target));
|
||||
if (!player) {
|
||||
return this.errorReply(`${target.trim()} is not a player.`);
|
||||
throw new Chat.ErrorMessage(`${target.trim()} is not a player.`);
|
||||
}
|
||||
|
||||
let repeat, elimType;
|
||||
|
|
@ -2738,7 +2740,7 @@ export const commands: Chat.ChatCommands = {
|
|||
break;
|
||||
}
|
||||
|
||||
if (repeat) return this.errorReply(`${player.safeName} has already been ${cmd}ed.`);
|
||||
if (repeat) throw new Chat.ErrorMessage(`${player.safeName} has already been ${cmd}ed.`);
|
||||
|
||||
game.eliminate(player, elimType);
|
||||
game.logAction(user, `${cmd}ed ${player.safeName}`);
|
||||
|
|
@ -2794,16 +2796,16 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
const player = game.getPlayer(user.id);
|
||||
if (!player) return this.errorReply(`You are not in the game of ${game.title}.`);
|
||||
if (!player) throw new Chat.ErrorMessage(`You are not in the game of ${game.title}.`);
|
||||
|
||||
if (player.isEliminated()) {
|
||||
return this.errorReply(`You have been eliminated from the game and cannot take any actions.`);
|
||||
throw new Chat.ErrorMessage(`You have been eliminated from the game and cannot take any actions.`);
|
||||
}
|
||||
if (game.phase !== 'night') {
|
||||
return this.errorReply(`You can only submit an action or idle during the night phase.`);
|
||||
throw new Chat.ErrorMessage(`You can only submit an action or idle during the night phase.`);
|
||||
}
|
||||
if (!game.takeIdles) {
|
||||
return this.errorReply(`The host is not accepting idles through the script. Send your action or idle to the host.`);
|
||||
throw new Chat.ErrorMessage(`The host is not accepting idles through the script. Send your action or idle to the host.`);
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
|
|
@ -2900,7 +2902,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse(`/help mafia deadline`);
|
||||
}
|
||||
}
|
||||
if (num < 1 || num > 20) return this.errorReply(`The deadline must be between 1 and 20 minutes.`);
|
||||
if (num < 1 || num > 20) throw new Chat.ErrorMessage(`The deadline must be between 1 and 20 minutes.`);
|
||||
game.setDeadline(num);
|
||||
}
|
||||
game.logAction(user, `changed deadline`);
|
||||
|
|
@ -2914,7 +2916,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (!game.started) return this.errorReply(`The game has not started yet.`);
|
||||
if (!game.started) throw new Chat.ErrorMessage(`The game has not started yet.`);
|
||||
const [playerId, mod] = target.split(',');
|
||||
const player = game.getPlayer(toID(playerId));
|
||||
if (!player) {
|
||||
|
|
@ -2934,7 +2936,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (!game.started) return this.errorReply(`The game has not started yet.`);
|
||||
if (!game.started) throw new Chat.ErrorMessage(`The game has not started yet.`);
|
||||
if (cmd === 'clearhammermodifiers') {
|
||||
game.clearHammerModifiers(user);
|
||||
game.secretLogAction(user, `cleared hammer modifiers`);
|
||||
|
|
@ -2989,14 +2991,14 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (!game.started) return this.errorReply(`The game has not started yet.`);
|
||||
if (!game.started) throw new Chat.ErrorMessage(`The game has not started yet.`);
|
||||
|
||||
target = toID(target);
|
||||
const targetPlayer = game.getPlayer(target as ID);
|
||||
const silence = cmd === 'silence';
|
||||
if (!targetPlayer) return this.errorReply(`${target} is not in the game of mafia.`);
|
||||
if (!targetPlayer) throw new Chat.ErrorMessage(`${target} is not in the game of mafia.`);
|
||||
if (silence === targetPlayer.silenced) {
|
||||
return this.errorReply(`${targetPlayer.name} is already ${!silence ? 'not' : ''} silenced.`);
|
||||
throw new Chat.ErrorMessage(`${targetPlayer.name} is already ${!silence ? 'not' : ''} silenced.`);
|
||||
}
|
||||
targetPlayer.silenced = silence;
|
||||
this.sendReply(`${targetPlayer.name} has been ${!silence ? 'un' : ''}silenced.`);
|
||||
|
|
@ -3014,14 +3016,14 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (!game.started) return this.errorReply(`The game has not started yet.`);
|
||||
if (!game.started) throw new Chat.ErrorMessage(`The game has not started yet.`);
|
||||
|
||||
target = toID(target);
|
||||
const targetPlayer = game.getPlayer(target as ID);
|
||||
const nighttalk = !cmd.startsWith('un');
|
||||
if (!targetPlayer) return this.errorReply(`${target} is not in the game of mafia.`);
|
||||
if (!targetPlayer) throw new Chat.ErrorMessage(`${target} is not in the game of mafia.`);
|
||||
if (nighttalk === targetPlayer.nighttalk) {
|
||||
return this.errorReply(`${targetPlayer.name} is already ${!nighttalk ? 'not' : ''} able to talk during the night.`);
|
||||
throw new Chat.ErrorMessage(`${targetPlayer.name} is already ${!nighttalk ? 'not' : ''} able to talk during the night.`);
|
||||
}
|
||||
targetPlayer.nighttalk = nighttalk;
|
||||
this.sendReply(`${targetPlayer.name} can ${!nighttalk ? 'no longer' : 'now'} talk during the night.`);
|
||||
|
|
@ -3038,27 +3040,27 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (!game.started) return this.errorReply(`The game has not started yet.`);
|
||||
if (!game.started) throw new Chat.ErrorMessage(`The game has not started yet.`);
|
||||
|
||||
target = toID(target);
|
||||
const targetPlayer = game.getPlayer(target as ID);
|
||||
if (!targetPlayer) return this.errorReply(`${target} is not in the game of mafia.`);
|
||||
if (!targetPlayer) throw new Chat.ErrorMessage(`${target} is not in the game of mafia.`);
|
||||
|
||||
const actor = cmd.endsWith('actor');
|
||||
const remove = cmd.startsWith('un');
|
||||
if (remove) {
|
||||
if (targetPlayer.hammerRestriction === null) {
|
||||
return this.errorReply(`${targetPlayer.name} already has no voting restrictions.`);
|
||||
throw new Chat.ErrorMessage(`${targetPlayer.name} already has no voting restrictions.`);
|
||||
}
|
||||
if (actor !== targetPlayer.hammerRestriction) {
|
||||
return this.errorReply(`${targetPlayer.name} is ${targetPlayer.hammerRestriction ? 'an actor' : 'a priest'}.`);
|
||||
throw new Chat.ErrorMessage(`${targetPlayer.name} is ${targetPlayer.hammerRestriction ? 'an actor' : 'a priest'}.`);
|
||||
}
|
||||
targetPlayer.hammerRestriction = null;
|
||||
return this.sendReply(`${targetPlayer}'s hammer restriction was removed.`);
|
||||
}
|
||||
|
||||
if (actor === targetPlayer.hammerRestriction) {
|
||||
return this.errorReply(`${targetPlayer.name} is already ${targetPlayer.hammerRestriction ? 'an actor' : 'a priest'}.`);
|
||||
throw new Chat.ErrorMessage(`${targetPlayer.name} is already ${targetPlayer.hammerRestriction ? 'an actor' : 'a priest'}.`);
|
||||
}
|
||||
targetPlayer.hammerRestriction = actor;
|
||||
this.sendReply(`${targetPlayer.name} is now ${targetPlayer.hammerRestriction ? "an actor (can only hammer)" : "a priest (can't hammer)"}.`);
|
||||
|
|
@ -3079,10 +3081,10 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (!game.started) return this.errorReply(`The game has not started yet.`);
|
||||
if (!game.started) throw new Chat.ErrorMessage(`The game has not started yet.`);
|
||||
const hammer = parseInt(target);
|
||||
if (toID(cmd) !== `resethammer` && ((isNaN(hammer) && !this.meansNo(target)) || hammer < 1)) {
|
||||
return this.errorReply(`${target} is not a valid hammer count.`);
|
||||
throw new Chat.ErrorMessage(`${target} is not a valid hammer count.`);
|
||||
}
|
||||
switch (cmd.toLowerCase()) {
|
||||
case 'shifthammer':
|
||||
|
|
@ -3166,12 +3168,12 @@ export const commands: Chat.ChatCommands = {
|
|||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
target = toID(target);
|
||||
if (this.meansYes(target)) {
|
||||
if (game.forceVote) return this.errorReply(`Forcevoting is already enabled.`);
|
||||
if (game.forceVote) throw new Chat.ErrorMessage(`Forcevoting is already enabled.`);
|
||||
game.forceVote = true;
|
||||
if (game.started) game.resetHammer();
|
||||
game.sendDeclare(`Forcevoting has been enabled. Your vote will start on yourself, and you cannot unvote!`);
|
||||
} else if (this.meansNo(target)) {
|
||||
if (!game.forceVote) return this.errorReply(`Forcevoting is already disabled.`);
|
||||
if (!game.forceVote) throw new Chat.ErrorMessage(`Forcevoting is already disabled.`);
|
||||
game.forceVote = false;
|
||||
game.sendDeclare(`Forcevoting has been disabled. You can vote normally now!`);
|
||||
} else {
|
||||
|
|
@ -3186,7 +3188,7 @@ export const commands: Chat.ChatCommands = {
|
|||
votes(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (!game.started) return this.errorReply(`The game of mafia has not started yet.`);
|
||||
if (!game.started) throw new Chat.ErrorMessage(`The game of mafia has not started yet.`);
|
||||
|
||||
// hack to let hosts broadcast
|
||||
if (game.hostid === user.id || game.cohostids.includes(user.id)) {
|
||||
|
|
@ -3222,7 +3224,7 @@ export const commands: Chat.ChatCommands = {
|
|||
rolelist(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.closedSetup) return this.errorReply(`You cannot show roles in a closed setup.`);
|
||||
if (game.closedSetup) throw new Chat.ErrorMessage(`You cannot show roles in a closed setup.`);
|
||||
if (!this.runBroadcast()) return false;
|
||||
if (game.IDEA.data) {
|
||||
const buf = `<details><summary>IDEA roles:</summary>${game.IDEA.data.roles.join(`<br />`)}</details>`;
|
||||
|
|
@ -3240,9 +3242,9 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) {
|
||||
return this.errorReply(`Only the host can view roles.`);
|
||||
throw new Chat.ErrorMessage(`Only the host can view roles.`);
|
||||
}
|
||||
if (!game.started) return this.errorReply(`The game has not started.`);
|
||||
if (!game.started) throw new Chat.ErrorMessage(`The game has not started.`);
|
||||
this.sendReplyBox(game.players.map(
|
||||
p => `${p.safeName}: ${p.role ? (p.role.alignment === 'solo' ? 'Solo ' : '') + p.role.safeName : 'No role'}`
|
||||
).join('<br/>'));
|
||||
|
|
@ -3278,15 +3280,15 @@ export const commands: Chat.ChatCommands = {
|
|||
if (player) {
|
||||
// Check if they have requested to be subbed out.
|
||||
if (!game.requestedSub.includes(user.id)) {
|
||||
return this.errorReply(`You have not requested to be subbed out.`);
|
||||
throw new Chat.ErrorMessage(`You have not requested to be subbed out.`);
|
||||
}
|
||||
game.requestedSub.splice(game.requestedSub.indexOf(user.id), 1);
|
||||
this.errorReply(`You have cancelled your request to sub out.`);
|
||||
player.updateHtmlRoom();
|
||||
} else {
|
||||
this.checkChat(null, room);
|
||||
if (game.subs.includes(user.id)) return this.errorReply(`You are already on the sub list.`);
|
||||
if (game.played.includes(user.id)) return this.errorReply(`You cannot sub back into the game.`);
|
||||
if (game.subs.includes(user.id)) throw new Chat.ErrorMessage(`You are already on the sub list.`);
|
||||
if (game.played.includes(user.id)) throw new Chat.ErrorMessage(`You cannot sub back into the game.`);
|
||||
// Change this to game.canJoin(user, true, true) if you're trying to test something sub related locally.
|
||||
game.canJoin(user, true);
|
||||
game.subs.push(user.id);
|
||||
|
|
@ -3298,19 +3300,19 @@ export const commands: Chat.ChatCommands = {
|
|||
case 'out':
|
||||
if (player) {
|
||||
if (player.isEliminated()) {
|
||||
return this.errorReply(`You cannot request to be subbed out once eliminated.`);
|
||||
throw new Chat.ErrorMessage(`You cannot request to be subbed out once eliminated.`);
|
||||
}
|
||||
if (game.requestedSub.includes(user.id)) {
|
||||
return this.errorReply(`You have already requested to be subbed out.`);
|
||||
throw new Chat.ErrorMessage(`You have already requested to be subbed out.`);
|
||||
}
|
||||
game.requestedSub.push(user.id);
|
||||
player.updateHtmlRoom();
|
||||
game.nextSub();
|
||||
} else {
|
||||
if (game.hostid === user.id || game.cohostids.includes(user.id)) {
|
||||
return this.errorReply(`The host cannot sub out of the game.`);
|
||||
throw new Chat.ErrorMessage(`The host cannot sub out of the game.`);
|
||||
}
|
||||
if (!game.subs.includes(user.id)) return this.errorReply(`You are not on the sub list.`);
|
||||
if (!game.subs.includes(user.id)) throw new Chat.ErrorMessage(`You are not on the sub list.`);
|
||||
game.subs.splice(game.subs.indexOf(user.id), 1);
|
||||
// Update spectator's view
|
||||
this.parse(`/join view-mafia-${room.roomid}`);
|
||||
|
|
@ -3319,10 +3321,10 @@ export const commands: Chat.ChatCommands = {
|
|||
case 'next':
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
const toSub = args.shift();
|
||||
if (!game.getPlayer(toID(toSub))) return this.errorReply(`${toSub} is not in the game.`);
|
||||
if (!game.getPlayer(toID(toSub))) throw new Chat.ErrorMessage(`${toSub} is not in the game.`);
|
||||
if (!game.subs.length) {
|
||||
if (game.hostRequestedSub.includes(toID(toSub))) {
|
||||
return this.errorReply(`${toSub} is already on the list to be subbed out.`);
|
||||
throw new Chat.ErrorMessage(`${toSub} is already on the list to be subbed out.`);
|
||||
}
|
||||
user.sendTo(
|
||||
room,
|
||||
|
|
@ -3366,10 +3368,10 @@ export const commands: Chat.ChatCommands = {
|
|||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
const toSubOut = game.getPlayer(action);
|
||||
const toSubIn = toID(args.shift());
|
||||
if (!toSubOut) return this.errorReply(`${toSubOut} is not in the game.`);
|
||||
if (!toSubOut) throw new Chat.ErrorMessage(`${toSubOut} is not in the game.`);
|
||||
|
||||
const targetUser = Users.get(toSubIn);
|
||||
if (!targetUser) return this.errorReply(`The user "${toSubIn}" was not found.`);
|
||||
if (!targetUser) throw new Chat.ErrorMessage(`The user "${toSubIn}" was not found.`);
|
||||
game.canJoin(targetUser, false, cmd === 'forcesub');
|
||||
if (game.subs.includes(targetUser.id)) {
|
||||
game.subs.splice(game.subs.indexOf(targetUser.id), 1);
|
||||
|
|
@ -3399,12 +3401,12 @@ export const commands: Chat.ChatCommands = {
|
|||
const game = this.requireGame(Mafia);
|
||||
if (game.hostid !== user.id && !game.cohostids.includes(user.id)) this.checkCan('mute', null, room);
|
||||
if (this.meansYes(toID(target))) {
|
||||
if (game.autoSub) return this.errorReply(`Automatic subbing of players is already enabled.`);
|
||||
if (game.autoSub) throw new Chat.ErrorMessage(`Automatic subbing of players is already enabled.`);
|
||||
game.autoSub = true;
|
||||
user.sendTo(room, `Automatic subbing of players has been enabled.`);
|
||||
game.nextSub();
|
||||
} else if (this.meansNo(toID(target))) {
|
||||
if (!game.autoSub) return this.errorReply(`Automatic subbing of players is already disabled.`);
|
||||
if (!game.autoSub) throw new Chat.ErrorMessage(`Automatic subbing of players is already disabled.`);
|
||||
game.autoSub = false;
|
||||
user.sendTo(room, `Automatic subbing of players has been disabled.`);
|
||||
} else {
|
||||
|
|
@ -3424,12 +3426,14 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse(`/help mafia ${cmd}`);
|
||||
this.checkCan('mute', null, room);
|
||||
const { targetUser } = this.requireUser(target);
|
||||
if (!room.users[targetUser.id]) return this.errorReply(`${targetUser.name} is not in this room, and cannot be hosted.`);
|
||||
if (game.hostid === targetUser.id) return this.errorReply(`${targetUser.name} is already the host.`);
|
||||
if (game.cohostids.includes(targetUser.id)) return this.errorReply(`${targetUser.name} is already a cohost.`);
|
||||
if (!room.users[targetUser.id]) {
|
||||
throw new Chat.ErrorMessage(`${targetUser.name} is not in this room, and cannot be hosted.`);
|
||||
}
|
||||
if (game.hostid === targetUser.id) throw new Chat.ErrorMessage(`${targetUser.name} is already the host.`);
|
||||
if (game.cohostids.includes(targetUser.id)) throw new Chat.ErrorMessage(`${targetUser.name} is already a cohost.`);
|
||||
|
||||
if (game.getPlayer(targetUser.id)) {
|
||||
return this.errorReply(`${targetUser.name} cannot become a host because they are playing.`);
|
||||
throw new Chat.ErrorMessage(`${targetUser.name} cannot become a host because they are playing.`);
|
||||
}
|
||||
|
||||
if (game.subs.includes(targetUser.id)) game.subs.splice(game.subs.indexOf(targetUser.id), 1);
|
||||
|
|
@ -3474,9 +3478,9 @@ export const commands: Chat.ChatCommands = {
|
|||
const cohostIndex = game.cohostids.indexOf(targetID);
|
||||
if (cohostIndex < 0) {
|
||||
if (game.hostid === targetID) {
|
||||
return this.errorReply(`${target} is the host, not a cohost. Use /mafia subhost to replace them.`);
|
||||
throw new Chat.ErrorMessage(`${target} is the host, not a cohost. Use /mafia subhost to replace them.`);
|
||||
}
|
||||
return this.errorReply(`${target} is not a cohost.`);
|
||||
throw new Chat.ErrorMessage(`${target} is not a cohost.`);
|
||||
}
|
||||
game.cohostids.splice(cohostIndex, 1);
|
||||
game.sendDeclare(Utils.html`${target} was removed as a cohost by ${user.name}`);
|
||||
|
|
@ -3498,18 +3502,18 @@ export const commands: Chat.ChatCommands = {
|
|||
term: 'data',
|
||||
dt: 'data',
|
||||
data(target, room, user, connection, cmd) {
|
||||
if (room?.settings.mafiaDisabled) return this.errorReply(`Mafia is disabled for this room.`);
|
||||
if (room?.settings.mafiaDisabled) throw new Chat.ErrorMessage(`Mafia is disabled for this room.`);
|
||||
if (cmd === 'role' && !target && room) {
|
||||
// Support /mafia role showing your current role if you're in a game
|
||||
const game = room.getGame(Mafia);
|
||||
if (!game) {
|
||||
return this.errorReply(`There is no game of mafia running in this room. If you meant to display information about a role, use /mafia role [role name]`);
|
||||
throw new Chat.ErrorMessage(`There is no game of mafia running in this room. If you meant to display information about a role, use /mafia role [role name]`);
|
||||
}
|
||||
|
||||
const player = game.getPlayer(user.id);
|
||||
if (!player) return this.errorReply(`You are not in the game of ${game.title}.`);
|
||||
if (!player) throw new Chat.ErrorMessage(`You are not in the game of ${game.title}.`);
|
||||
const role = player.role;
|
||||
if (!role) return this.errorReply(`You do not have a role yet.`);
|
||||
if (!role) throw new Chat.ErrorMessage(`You do not have a role yet.`);
|
||||
return this.sendReplyBox(`Your role is: ${role.safeName}`);
|
||||
}
|
||||
|
||||
|
|
@ -3547,7 +3551,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!result) return this.errorReply(`"${target}" is not a valid mafia alignment, role, theme, or IDEA.`);
|
||||
if (!result) throw new Chat.ErrorMessage(`"${target}" is not a valid mafia alignment, role, theme, or IDEA.`);
|
||||
|
||||
// @ts-expect-error property access
|
||||
let buf = `<h3${result.color ? ` style="color: ${result.color}"` : ``}>${result.name}</h3><b>Type</b>: ${dataType}<br/>`;
|
||||
|
|
@ -3593,7 +3597,7 @@ export const commands: Chat.ChatCommands = {
|
|||
win(target, room, user, connection, cmd) {
|
||||
const isUnwin = cmd.startsWith('unwin');
|
||||
room = this.requireRoom('mafia' as RoomID);
|
||||
if (!room || room.settings.mafiaDisabled) return this.errorReply(`Mafia is disabled for this room.`);
|
||||
if (!room || room.settings.mafiaDisabled) throw new Chat.ErrorMessage(`Mafia is disabled for this room.`);
|
||||
this.checkCan('mute', null, room);
|
||||
const args = target.split(',');
|
||||
let points = parseInt(args[0]);
|
||||
|
|
@ -3607,7 +3611,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
} else {
|
||||
if (points > 100 || points < -100) {
|
||||
return this.errorReply(`You cannot give or take more than 100 points at a time.`);
|
||||
throw new Chat.ErrorMessage(`You cannot give or take more than 100 points at a time.`);
|
||||
}
|
||||
// shift out the point count
|
||||
args.shift();
|
||||
|
|
@ -3658,7 +3662,7 @@ export const commands: Chat.ChatCommands = {
|
|||
unmvp: 'mvp',
|
||||
mvp(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom('mafia' as RoomID);
|
||||
if (!room || room.settings.mafiaDisabled) return this.errorReply(`Mafia is disabled for this room.`);
|
||||
if (!room || room.settings.mafiaDisabled) throw new Chat.ErrorMessage(`Mafia is disabled for this room.`);
|
||||
this.checkCan('mute', null, room);
|
||||
const args = target.split(',');
|
||||
if (!args.length) return this.parse('/help mafia mvp');
|
||||
|
|
@ -3699,7 +3703,7 @@ export const commands: Chat.ChatCommands = {
|
|||
lb: 'leaderboard',
|
||||
leaderboard(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom('mafia' as RoomID);
|
||||
if (!room || room.settings.mafiaDisabled) return this.errorReply(`Mafia is disabled for this room.`);
|
||||
if (!room || room.settings.mafiaDisabled) throw new Chat.ErrorMessage(`Mafia is disabled for this room.`);
|
||||
if (['hostlogs', 'playlogs', 'leaverlogs'].includes(cmd)) {
|
||||
this.checkCan('mute', null, room);
|
||||
} else {
|
||||
|
|
@ -3737,14 +3741,14 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!duration) duration = 2;
|
||||
if (!reason) reason = '';
|
||||
if (reason.length > 300) {
|
||||
return this.errorReply("The reason is too long. It cannot exceed 300 characters.");
|
||||
throw new Chat.ErrorMessage("The reason is too long. It cannot exceed 300 characters.");
|
||||
}
|
||||
|
||||
const userid = toID(targetUser);
|
||||
if (Punishments.hasRoomPunishType(room, userid, `MAFIA${this.cmd.toUpperCase()}`)) {
|
||||
return this.errorReply(`User '${targetUser.name}' is already ${this.cmd}ned in this room.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' is already ${this.cmd}ned in this room.`);
|
||||
} else if (Punishments.hasRoomPunishType(room, userid, `MAFIAGAMEBAN`)) {
|
||||
return this.errorReply(`User '${targetUser.name}' is already gamebanned in this room, which also means they can't host.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' is already gamebanned in this room, which also means they can't host.`);
|
||||
} else if (Punishments.hasRoomPunishType(room, userid, `MAFIAHOSTBAN`)) {
|
||||
user.sendTo(room, `User '${targetUser.name}' is already hostbanned in this room, but they will now be gamebanned.`);
|
||||
this.parse(`/mafia unhostban ${targetUser.name}`);
|
||||
|
|
@ -3778,9 +3782,9 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const { targetUser } = this.requireUser(target, { allowOffline: true });
|
||||
if (!Mafia.isGameBanned(room, targetUser) && cmd === 'ungameban') {
|
||||
return this.errorReply(`User '${targetUser.name}' isn't banned from playing mafia games.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' isn't banned from playing mafia games.`);
|
||||
} else if (!Mafia.isHostBanned(room, targetUser) && cmd === 'unhostban') {
|
||||
return this.errorReply(`User '${targetUser.name}' isn't banned from hosting mafia games.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' isn't banned from hosting mafia games.`);
|
||||
}
|
||||
|
||||
if (cmd === 'unhostban') Mafia.unhostBan(room, targetUser);
|
||||
|
|
@ -3801,15 +3805,17 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
if (!id || !memo.length) return this.parse(`/help mafia addrole`);
|
||||
|
||||
if (alignment && !(alignment in MafiaData.alignments)) return this.errorReply(`${alignment} is not a valid alignment.`);
|
||||
if (image && !VALID_IMAGES.includes(image)) return this.errorReply(`${image} is not a valid image.`);
|
||||
if (alignment && !(alignment in MafiaData.alignments)) {
|
||||
throw new Chat.ErrorMessage(`${alignment} is not a valid alignment.`);
|
||||
}
|
||||
if (image && !VALID_IMAGES.includes(image)) throw new Chat.ErrorMessage(`${image} is not a valid image.`);
|
||||
|
||||
if (!overwrite && id in MafiaData.roles) {
|
||||
return this.errorReply(`${name} is already a role. Use /mafia overwriterole to overwrite.`);
|
||||
throw new Chat.ErrorMessage(`${name} is already a role. Use /mafia overwriterole to overwrite.`);
|
||||
}
|
||||
if (id in MafiaData.alignments) return this.errorReply(`${name} is already an alignment.`);
|
||||
if (id in MafiaData.alignments) throw new Chat.ErrorMessage(`${name} is already an alignment.`);
|
||||
if (id in MafiaData.aliases) {
|
||||
return this.errorReply(`${name} is already an alias (pointing to ${MafiaData.aliases[id]}).`);
|
||||
throw new Chat.ErrorMessage(`${name} is already an alias (pointing to ${MafiaData.aliases[id]}).`);
|
||||
}
|
||||
|
||||
const role: MafiaDataRole = { name, memo };
|
||||
|
|
@ -3836,14 +3842,14 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
if (!id || !plural || !memo.length) return this.parse(`/help mafia addalignment`);
|
||||
|
||||
if (image && !VALID_IMAGES.includes(image)) return this.errorReply(`${image} is not a valid image.`);
|
||||
if (image && !VALID_IMAGES.includes(image)) throw new Chat.ErrorMessage(`${image} is not a valid image.`);
|
||||
|
||||
if (!overwrite && id in MafiaData.alignments) {
|
||||
return this.errorReply(`${name} is already an alignment. Use /mafia overwritealignment to overwrite.`);
|
||||
throw new Chat.ErrorMessage(`${name} is already an alignment. Use /mafia overwritealignment to overwrite.`);
|
||||
}
|
||||
if (id in MafiaData.roles) return this.errorReply(`${name} is already a role.`);
|
||||
if (id in MafiaData.roles) throw new Chat.ErrorMessage(`${name} is already a role.`);
|
||||
if (id in MafiaData.aliases) {
|
||||
return this.errorReply(`${name} is already an alias (pointing to ${MafiaData.aliases[id]})`);
|
||||
throw new Chat.ErrorMessage(`${name} is already an alias (pointing to ${MafiaData.aliases[id]})`);
|
||||
}
|
||||
|
||||
const alignment: MafiaDataAlignment = { name, plural, memo };
|
||||
|
|
@ -3872,11 +3878,11 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!id || !desc || !rolelists.length) return this.parse(`/help mafia addtheme`);
|
||||
|
||||
if (!overwrite && id in MafiaData.themes) {
|
||||
return this.errorReply(`${name} is already a theme. Use /mafia overwritetheme to overwrite.`);
|
||||
throw new Chat.ErrorMessage(`${name} is already a theme. Use /mafia overwritetheme to overwrite.`);
|
||||
}
|
||||
if (id in MafiaData.IDEAs) return this.errorReply(`${name} is already an IDEA.`);
|
||||
if (id in MafiaData.IDEAs) throw new Chat.ErrorMessage(`${name} is already an IDEA.`);
|
||||
if (id in MafiaData.aliases) {
|
||||
return this.errorReply(`${name} is already an alias (pointing to ${MafiaData.aliases[id]})`);
|
||||
throw new Chat.ErrorMessage(`${name} is already an alias (pointing to ${MafiaData.aliases[id]})`);
|
||||
}
|
||||
|
||||
const rolelistsMap: { [players: number]: string } = {};
|
||||
|
|
@ -3896,7 +3902,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const parsedRole = Mafia.parseRole(role);
|
||||
if (parsedRole.problems.length) problems.push(...parsedRole.problems);
|
||||
}
|
||||
if (problems.length) return this.errorReply(`Problems found when parsing roles:\n${problems.join('\n')}`);
|
||||
if (problems.length) throw new Chat.ErrorMessage(`Problems found when parsing roles:\n${problems.join('\n')}`);
|
||||
|
||||
const theme: MafiaDataTheme = { name, desc, ...rolelistsMap };
|
||||
MafiaData.themes[id] = theme;
|
||||
|
|
@ -3922,14 +3928,14 @@ export const commands: Chat.ChatCommands = {
|
|||
const choices = parseInt(choicesStr);
|
||||
|
||||
if (!id || !choices || !picks.length) return this.parse(`/help mafia addidea`);
|
||||
if (choices <= picks.length) return this.errorReply(`You need to have more choices than picks.`);
|
||||
if (choices <= picks.length) throw new Chat.ErrorMessage(`You need to have more choices than picks.`);
|
||||
|
||||
if (!overwrite && id in MafiaData.IDEAs) {
|
||||
return this.errorReply(`${name} is already an IDEA. Use /mafia overwriteidea to overwrite.`);
|
||||
throw new Chat.ErrorMessage(`${name} is already an IDEA. Use /mafia overwriteidea to overwrite.`);
|
||||
}
|
||||
if (id in MafiaData.themes) return this.errorReply(`${name} is already a theme.`);
|
||||
if (id in MafiaData.themes) throw new Chat.ErrorMessage(`${name} is already a theme.`);
|
||||
if (id in MafiaData.aliases) {
|
||||
return this.errorReply(`${name} is already an alias (pointing to ${MafiaData.aliases[id]})`);
|
||||
throw new Chat.ErrorMessage(`${name} is already an alias (pointing to ${MafiaData.aliases[id]})`);
|
||||
}
|
||||
|
||||
const checkedRoles: string[] = [];
|
||||
|
|
@ -3940,7 +3946,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (parsedRole.problems.length) problems.push(...parsedRole.problems);
|
||||
checkedRoles.push(role);
|
||||
}
|
||||
if (problems.length) return this.errorReply(`Problems found when parsing roles:\n${problems.join('\n')}`);
|
||||
if (problems.length) throw new Chat.ErrorMessage(`Problems found when parsing roles:\n${problems.join('\n')}`);
|
||||
|
||||
const IDEA: MafiaDataIDEA = { name, choices, picks, roles };
|
||||
MafiaData.IDEAs[id] = IDEA;
|
||||
|
|
@ -3964,10 +3970,10 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!id || !memo.length) return this.parse(`/help mafia addterm`);
|
||||
|
||||
if (!overwrite && id in MafiaData.terms) {
|
||||
return this.errorReply(`${name} is already a term. Use /mafia overwriteterm to overwrite.`);
|
||||
throw new Chat.ErrorMessage(`${name} is already a term. Use /mafia overwriteterm to overwrite.`);
|
||||
}
|
||||
if (id in MafiaData.aliases) {
|
||||
return this.errorReply(`${name} is already an alias (pointing to ${MafiaData.aliases[id]})`);
|
||||
throw new Chat.ErrorMessage(`${name} is already an alias (pointing to ${MafiaData.aliases[id]})`);
|
||||
}
|
||||
|
||||
const term: MafiaDataTerm = { name, memo };
|
||||
|
|
@ -3987,15 +3993,15 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!from || !to) return this.parse(`/help mafia addalias`);
|
||||
|
||||
if (from in MafiaData.aliases) {
|
||||
return this.errorReply(`${from} is already an alias (pointing to ${MafiaData.aliases[from]})`);
|
||||
throw new Chat.ErrorMessage(`${from} is already an alias (pointing to ${MafiaData.aliases[from]})`);
|
||||
}
|
||||
let foundTarget = false;
|
||||
for (const entry of ['alignments', 'roles', 'themes', 'IDEAs', 'terms'] as (keyof MafiaData)[]) {
|
||||
const dataEntry = MafiaData[entry];
|
||||
if (from in dataEntry) return this.errorReply(`${from} is already a ${entry.slice(0, -1)}`);
|
||||
if (from in dataEntry) throw new Chat.ErrorMessage(`${from} is already a ${entry.slice(0, -1)}`);
|
||||
if (to in dataEntry) foundTarget = true;
|
||||
}
|
||||
if (!foundTarget) return this.errorReply(`No database entry exists with the key ${to}.`);
|
||||
if (!foundTarget) throw new Chat.ErrorMessage(`No database entry exists with the key ${to}.`);
|
||||
|
||||
MafiaData.aliases[from] = to;
|
||||
writeFile(DATA_FILE, MafiaData);
|
||||
|
|
@ -4013,15 +4019,15 @@ export const commands: Chat.ChatCommands = {
|
|||
let [source, entry] = target.split(',');
|
||||
entry = toID(entry);
|
||||
if (!(source in MafiaData)) {
|
||||
return this.errorReply(`Invalid source. Valid sources are ${Object.keys(MafiaData).join(', ')}`);
|
||||
throw new Chat.ErrorMessage(`Invalid source. Valid sources are ${Object.keys(MafiaData).join(', ')}`);
|
||||
}
|
||||
// @ts-expect-error checked above
|
||||
const dataSource = MafiaData[source];
|
||||
if (!(entry in dataSource)) return this.errorReply(`${entry} does not exist in ${source}.`);
|
||||
if (!(entry in dataSource)) throw new Chat.ErrorMessage(`${entry} does not exist in ${source}.`);
|
||||
|
||||
let buf = '';
|
||||
if (dataSource === MafiaData.alignments) {
|
||||
if (entry === 'solo' || entry === 'town') return this.errorReply(`You cannot delete the solo or town alignments.`);
|
||||
if (entry === 'solo' || entry === 'town') throw new Chat.ErrorMessage(`You cannot delete the solo or town alignments.`);
|
||||
|
||||
for (const key in MafiaData.roles) {
|
||||
if (MafiaData.roles[key].alignment === entry) {
|
||||
|
|
@ -4050,7 +4056,7 @@ export const commands: Chat.ChatCommands = {
|
|||
deletedatahelp: [`/mafia deletedata source,entry - Removes an entry from the database. Requires % @ # ~`],
|
||||
listdata(target, room, user) {
|
||||
if (!(target in MafiaData)) {
|
||||
return this.errorReply(`Invalid source. Valid sources are ${Object.keys(MafiaData).join(', ')}`);
|
||||
throw new Chat.ErrorMessage(`Invalid source. Valid sources are ${Object.keys(MafiaData).join(', ')}`);
|
||||
}
|
||||
const dataSource = MafiaData[target as keyof MafiaData];
|
||||
if (dataSource === MafiaData.aliases) {
|
||||
|
|
@ -4070,7 +4076,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('gamemanagement', null, room);
|
||||
if (room.settings.mafiaDisabled) {
|
||||
return this.errorReply("Mafia is already disabled.");
|
||||
throw new Chat.ErrorMessage("Mafia is already disabled.");
|
||||
}
|
||||
room.settings.mafiaDisabled = true;
|
||||
room.saveSettings();
|
||||
|
|
@ -4083,7 +4089,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('gamemanagement', null, room);
|
||||
if (!room.settings.mafiaDisabled) {
|
||||
return this.errorReply("Mafia is already enabled.");
|
||||
throw new Chat.ErrorMessage("Mafia is already enabled.");
|
||||
}
|
||||
room.settings.mafiaDisabled = false;
|
||||
room.saveSettings();
|
||||
|
|
|
|||
|
|
@ -286,11 +286,11 @@ export const commands: Chat.ChatCommands = {
|
|||
break;
|
||||
case 'lines': case 'maxlines':
|
||||
lines = parseInt(value);
|
||||
if (isNaN(lines) || lines < 1) return this.errorReply(`Invalid linecount: '${value}'.`);
|
||||
if (isNaN(lines) || lines < 1) throw new Chat.ErrorMessage(`Invalid linecount: '${value}'.`);
|
||||
break;
|
||||
default:
|
||||
this.errorReply(`Invalid modlog parameter: '${param}'.`);
|
||||
return this.errorReply(`Please specify 'room', 'note', 'user', 'ip', 'action', 'staff', or 'lines'.`);
|
||||
throw new Chat.ErrorMessage([`Invalid modlog parameter: '${param}'.`,
|
||||
`Please specify 'room', 'note', 'user', 'ip', 'action', 'staff', or 'lines'.`]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -303,7 +303,7 @@ export const commands: Chat.ChatCommands = {
|
|||
// default to global modlog for staff convenience
|
||||
roomid = 'global';
|
||||
} else {
|
||||
return this.errorReply(`Only global staff may view battle and groupchat modlogs.`);
|
||||
throw new Chat.ErrorMessage(`Only global staff may view battle and groupchat modlogs.`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +364,7 @@ export const pages: Chat.PageTable = {
|
|||
this.checkCan('lock');
|
||||
const target = toID(query.shift());
|
||||
if (!target || target.length > 18) {
|
||||
return this.errorReply(`Invalid userid - must be between 1 and 18 characters long.`);
|
||||
throw new Chat.ErrorMessage(`Invalid userid - must be between 1 and 18 characters long.`);
|
||||
}
|
||||
this.title = `[Modlog Stats] ${target}`;
|
||||
this.setHTML(`<div class="pad"><strong>Running modlog search...</strong></div>`);
|
||||
|
|
@ -375,7 +375,7 @@ export const pages: Chat.PageTable = {
|
|||
}], note: [], ip: [], action: [], actionTaker: [],
|
||||
}, 1000);
|
||||
if (!entries?.results.length) {
|
||||
return this.errorReply(`No data found.`);
|
||||
throw new Chat.ErrorMessage(`No data found.`);
|
||||
}
|
||||
const punishmentTable = new Utils.Multiset<string>();
|
||||
const punishmentsByIp = new Map<string, Utils.Multiset<string>>();
|
||||
|
|
|
|||
|
|
@ -513,7 +513,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!targetId) targetId = user.id;
|
||||
const mon = Dex.species.get(monName);
|
||||
if (!mon.exists) {
|
||||
return this.errorReply(`Species ${monName} does not exist.`);
|
||||
throw new Chat.ErrorMessage(`Species ${monName} does not exist.`);
|
||||
}
|
||||
Nominations.icons[targetId] = mon.name.toLowerCase();
|
||||
Nominations.save();
|
||||
|
|
@ -526,7 +526,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('rangeban');
|
||||
const targetID = toID(target);
|
||||
if (!Nominations.icons[targetID]) {
|
||||
return this.errorReply(`${targetID} does not have an icon set.`);
|
||||
throw new Chat.ErrorMessage(`${targetID} does not have an icon set.`);
|
||||
}
|
||||
delete Nominations.icons[targetID];
|
||||
Nominations.save();
|
||||
|
|
@ -550,9 +550,9 @@ export const pages: Chat.PageTable = {
|
|||
view(query, user) {
|
||||
this.checkCan('rangeban');
|
||||
const id = toID(query.shift());
|
||||
if (!id) return this.errorReply(`Invalid userid.`);
|
||||
if (!id) throw new Chat.ErrorMessage(`Invalid userid.`);
|
||||
const nom = Nominations.find(id);
|
||||
if (!nom) return this.errorReply(`No nomination found for '${id}'.`);
|
||||
if (!nom) throw new Chat.ErrorMessage(`No nomination found for '${id}'.`);
|
||||
this.title = `[Perma Nom] ${nom.primaryID}`;
|
||||
return Nominations.displayActionPage(nom);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -377,11 +377,11 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
if (!target) return this.parse('/help poll new');
|
||||
target = target.trim();
|
||||
if (target.length > 1024) return this.errorReply(this.tr`Poll too long.`);
|
||||
if (room.battle) return this.errorReply(this.tr`Battles do not support polls.`);
|
||||
if (target.length > 1024) throw new Chat.ErrorMessage(this.tr`Poll too long.`);
|
||||
if (room.battle) throw new Chat.ErrorMessage(this.tr`Battles do not support polls.`);
|
||||
|
||||
const text = this.filter(target);
|
||||
if (target !== text) return this.errorReply(this.tr`You are not allowed to use filtered words in polls.`);
|
||||
if (target !== text) throw new Chat.ErrorMessage(this.tr`You are not allowed to use filtered words in polls.`);
|
||||
|
||||
const supportHTML = cmd.includes('html');
|
||||
const multiPoll = cmd.includes('multi');
|
||||
|
|
@ -396,7 +396,7 @@ export const commands: Chat.ChatCommands = {
|
|||
} else if (text.includes(',')) {
|
||||
separator = ',';
|
||||
} else {
|
||||
return this.errorReply(this.tr`Not enough arguments for /poll new.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Not enough arguments for /poll new.`);
|
||||
}
|
||||
|
||||
let currentParam = "";
|
||||
|
|
@ -412,7 +412,7 @@ export const commands: Chat.ChatCommands = {
|
|||
currentParam += nextCharacter;
|
||||
i += 1;
|
||||
} else {
|
||||
return this.errorReply(this.tr`Extra escape character. To end a poll with '\\', enter it as '\\\\'`);
|
||||
throw new Chat.ErrorMessage(this.tr`Extra escape character. To end a poll with '\\', enter it as '\\\\'`);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
@ -436,21 +436,21 @@ export const commands: Chat.ChatCommands = {
|
|||
if (supportHTML) this.checkCan('declare', null, room);
|
||||
this.checkChat();
|
||||
if (room.minorActivity && !queue) {
|
||||
return this.errorReply(this.tr`There is already a poll or announcement in progress in this room.`);
|
||||
throw new Chat.ErrorMessage(this.tr`There is already a poll or announcement in progress in this room.`);
|
||||
}
|
||||
|
||||
if (params.length < 3) return this.errorReply(this.tr`Not enough arguments for /poll new.`);
|
||||
if (params.length < 3) throw new Chat.ErrorMessage(this.tr`Not enough arguments for /poll new.`);
|
||||
|
||||
// the function throws on failure, so no handling needs to be done anymore
|
||||
if (supportHTML) params = params.map(parameter => this.checkHTML(parameter));
|
||||
|
||||
const questions = params.splice(1);
|
||||
if (questions.length > MAX_QUESTIONS) {
|
||||
return this.errorReply(this.tr`Too many options for poll (maximum is ${MAX_QUESTIONS}).`);
|
||||
throw new Chat.ErrorMessage(this.tr`Too many options for poll (maximum is ${MAX_QUESTIONS}).`);
|
||||
}
|
||||
|
||||
if (new Set(questions).size !== questions.length) {
|
||||
return this.errorReply(this.tr`There are duplicate options in the poll.`);
|
||||
throw new Chat.ErrorMessage(this.tr`There are duplicate options in the poll.`);
|
||||
}
|
||||
|
||||
if (room.minorActivity) {
|
||||
|
|
@ -489,13 +489,13 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('mute', null, room);
|
||||
const queue = room.getMinorActivityQueue();
|
||||
if (!queue) {
|
||||
return this.errorReply(this.tr`The queue is already empty.`);
|
||||
throw new Chat.ErrorMessage(this.tr`The queue is already empty.`);
|
||||
}
|
||||
const slot = parseInt(target);
|
||||
if (isNaN(slot)) {
|
||||
return this.errorReply(this.tr`Can't delete poll at slot ${target} - "${target}" is not a number.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Can't delete poll at slot ${target} - "${target}" is not a number.`);
|
||||
}
|
||||
if (!queue[slot - 1]) return this.errorReply(this.tr`There is no poll in queue at slot ${slot}.`);
|
||||
if (!queue[slot - 1]) throw new Chat.ErrorMessage(this.tr`There is no poll in queue at slot ${slot}.`);
|
||||
|
||||
room.clearMinorActivityQueue(slot - 1);
|
||||
|
||||
|
|
@ -516,7 +516,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('mute', null, room);
|
||||
const queue = room.getMinorActivityQueue();
|
||||
if (!queue) {
|
||||
return this.errorReply(this.tr`The queue is already empty.`);
|
||||
throw new Chat.ErrorMessage(this.tr`The queue is already empty.`);
|
||||
}
|
||||
room.clearMinorActivityQueue();
|
||||
this.modlog('CLEARQUEUE');
|
||||
|
|
@ -534,7 +534,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!target) return this.parse('/help poll vote');
|
||||
|
||||
const parsed = parseInt(target);
|
||||
if (isNaN(parsed)) return this.errorReply(this.tr`To vote, specify the number of the option.`);
|
||||
if (isNaN(parsed)) throw new Chat.ErrorMessage(this.tr`To vote, specify the number of the option.`);
|
||||
|
||||
if (!poll.answers.has(parsed)) return this.sendReply(this.tr`Option not in poll.`);
|
||||
|
||||
|
|
@ -564,12 +564,12 @@ export const commands: Chat.ChatCommands = {
|
|||
if (target) {
|
||||
this.checkCan('minigame', null, room);
|
||||
if (target === 'clear') {
|
||||
if (!poll.endTimer()) return this.errorReply(this.tr("There is no timer to clear."));
|
||||
if (!poll.endTimer()) throw new Chat.ErrorMessage(this.tr("There is no timer to clear."));
|
||||
return this.add(this.tr`The poll 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.`);
|
||||
throw new Chat.ErrorMessage(this.tr`Time should be a number of minutes less than one week.`);
|
||||
}
|
||||
poll.setTimer({ timeoutMins });
|
||||
room.add(this.tr`The poll timer was turned on: the poll will end in ${Chat.toDurationString(timeoutMins * MINUTES)}.`);
|
||||
|
|
@ -638,10 +638,10 @@ export const commands: Chat.ChatCommands = {
|
|||
num = 0;
|
||||
}
|
||||
if (isNaN(num)) {
|
||||
return this.errorReply(`Invalid max vote cap: '${target}'`);
|
||||
throw new Chat.ErrorMessage(`Invalid max vote cap: '${target}'`);
|
||||
}
|
||||
if (poll.maxVotes === num) {
|
||||
return this.errorReply(`The poll's vote cap is already set to ${num}.`);
|
||||
throw new Chat.ErrorMessage(`The poll's vote cap is already set to ${num}.`);
|
||||
}
|
||||
poll.maxVotes = num;
|
||||
this.addModAction(`${user.name} set the poll's vote cap to ${num}.`);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export const commands: Chat.ChatCommands = {
|
|||
randquote(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const roomQuotes = quotes[room.roomid];
|
||||
if (!roomQuotes?.length) return this.errorReply(`This room has no quotes.`);
|
||||
if (!roomQuotes?.length) throw new Chat.ErrorMessage(`This room has no quotes.`);
|
||||
this.runBroadcast(true);
|
||||
const { quote, date, userid } = roomQuotes[Math.floor(Math.random() * roomQuotes.length)];
|
||||
const time = Chat.toTimestamp(new Date(date), { human: true });
|
||||
|
|
@ -45,7 +45,7 @@ export const commands: Chat.ChatCommands = {
|
|||
addquote(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) {
|
||||
return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
}
|
||||
target = target.trim();
|
||||
this.checkCan('mute', null, room);
|
||||
|
|
@ -56,16 +56,16 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const roomQuotes = quotes[room.roomid];
|
||||
if (this.filter(target) !== target) {
|
||||
return this.errorReply(`Invalid quote.`);
|
||||
throw new Chat.ErrorMessage(`Invalid quote.`);
|
||||
}
|
||||
if (roomQuotes.filter(item => item.quote === target).length) {
|
||||
return this.errorReply(`"${target}" is already quoted in this room.`);
|
||||
throw new Chat.ErrorMessage(`"${target}" is already quoted in this room.`);
|
||||
}
|
||||
if (target.length > 8192) {
|
||||
return this.errorReply(`Your quote cannot exceed 8192 characters.`);
|
||||
throw new Chat.ErrorMessage(`Your quote cannot exceed 8192 characters.`);
|
||||
}
|
||||
if (room.settings.isPrivate && roomQuotes.length >= MAX_QUOTES) {
|
||||
return this.errorReply(`This room already has ${MAX_QUOTES} quotes, which is the maximum for private rooms.`);
|
||||
throw new Chat.ErrorMessage(`This room already has ${MAX_QUOTES} quotes, which is the maximum for private rooms.`);
|
||||
}
|
||||
roomQuotes.push({ userid: user.id, quote: target, date: Date.now() });
|
||||
saveQuotes();
|
||||
|
|
@ -79,14 +79,14 @@ export const commands: Chat.ChatCommands = {
|
|||
removequote(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
if (!quotes[room.roomid]?.length) return this.errorReply(`This room has no quotes.`);
|
||||
if (!quotes[room.roomid]?.length) throw new Chat.ErrorMessage(`This room has no quotes.`);
|
||||
const roomQuotes = quotes[room.roomid];
|
||||
const index = toID(target) === 'last' ? roomQuotes.length - 1 : parseInt(toID(target)) - 1;
|
||||
if (isNaN(index)) {
|
||||
return this.errorReply(`Invalid index.`);
|
||||
throw new Chat.ErrorMessage(`Invalid index.`);
|
||||
}
|
||||
if (!roomQuotes[index]) {
|
||||
return this.errorReply(`Quote not found.`);
|
||||
throw new Chat.ErrorMessage(`Quote not found.`);
|
||||
}
|
||||
const [removed] = roomQuotes.splice(index, 1);
|
||||
const collapsedQuote = removed.quote.replace(/\n/g, ' ');
|
||||
|
|
@ -100,14 +100,14 @@ export const commands: Chat.ChatCommands = {
|
|||
viewquote(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const roomQuotes = quotes[room.roomid];
|
||||
if (!roomQuotes?.length) return this.errorReply(`This room has no quotes.`);
|
||||
if (!roomQuotes?.length) throw new Chat.ErrorMessage(`This room has no quotes.`);
|
||||
const [num, showAuthor] = Utils.splitFirst(target, ',');
|
||||
const index = num === 'last' ? roomQuotes.length - 1 : parseInt(num) - 1;
|
||||
if (isNaN(index)) {
|
||||
return this.errorReply(`Invalid index.`);
|
||||
throw new Chat.ErrorMessage(`Invalid index.`);
|
||||
}
|
||||
if (!roomQuotes[index]) {
|
||||
return this.errorReply(`Quote not found.`);
|
||||
throw new Chat.ErrorMessage(`Quote not found.`);
|
||||
}
|
||||
this.runBroadcast(true);
|
||||
const { quote, date, userid } = roomQuotes[index];
|
||||
|
|
@ -123,7 +123,7 @@ export const commands: Chat.ChatCommands = {
|
|||
viewquotes: 'quotes',
|
||||
quotes(target, room) {
|
||||
const targetRoom = target ? Rooms.search(target) : room;
|
||||
if (!targetRoom) return this.errorReply(`Invalid room.`);
|
||||
if (!targetRoom) throw new Chat.ErrorMessage(`Invalid room.`);
|
||||
this.parse(`/join view-quotes-${targetRoom.roomid}`);
|
||||
},
|
||||
quoteshelp: [`/quotes [room] - Shows all quotes for [room]. Defaults the room the command is used in.`],
|
||||
|
|
@ -147,7 +147,7 @@ export const pages: Chat.PageTable = {
|
|||
this.title = `[Quotes]`;
|
||||
// allow it for users if they can access the room
|
||||
if (!room.checkModjoin(user)) {
|
||||
return this.errorReply(`Access denied.`);
|
||||
throw new Chat.ErrorMessage(`Access denied.`);
|
||||
}
|
||||
let buffer = `<div class="pad">`;
|
||||
buffer += `<button style="float:right;" class="button" name="send" value="/join view-quotes-${room.roomid}"><i class="fa fa-refresh"></i> Refresh</button>`;
|
||||
|
|
|
|||
|
|
@ -493,8 +493,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const searchResults = dex.dataSearch(args[0], ['Pokedex']);
|
||||
|
||||
if (!searchResults?.length) {
|
||||
this.errorReply(`No Pok\u00e9mon named '${args[0]}' was found${Dex.gen > dex.gen ? ` in Gen ${dex.gen}` : ""}. (Check your spelling?)`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`No Pok\u00e9mon named '${args[0]}' was found${Dex.gen > dex.gen ? ` in Gen ${dex.gen}` : ""}. (Check your spelling?)`);
|
||||
}
|
||||
|
||||
let inexactMsg = '';
|
||||
|
|
@ -515,7 +514,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const rbyMoves = getRBYMoves(species);
|
||||
if (!rbyMoves) {
|
||||
this.sendReply(inexactMsg);
|
||||
return this.errorReply(`Error: ${species.name} has no Random Battle data in ${GEN_NAMES[toID(args[1])]}`);
|
||||
throw new Chat.ErrorMessage(`Error: ${species.name} has no Random Battle data in ${GEN_NAMES[toID(args[1])]}`);
|
||||
}
|
||||
movesets.push(`<span style="color:#999999;">Moves for ${species.name} in ${format.name}:</span>${rbyMoves}`);
|
||||
setCount = 1;
|
||||
|
|
@ -523,7 +522,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const lgpeMoves = getLetsGoMoves(species);
|
||||
if (!lgpeMoves) {
|
||||
this.sendReply(inexactMsg);
|
||||
return this.errorReply(`Error: ${species.name} has no Random Battle data in [Gen 7 Let's Go]`);
|
||||
throw new Chat.ErrorMessage(`Error: ${species.name} has no Random Battle data in [Gen 7 Let's Go]`);
|
||||
}
|
||||
movesets.push(`<span style="color:#999999;">Moves for ${species.name} in ${format.name}:</span><br />${lgpeMoves}`);
|
||||
setCount = 1;
|
||||
|
|
@ -582,7 +581,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
if (!movesets.length) {
|
||||
this.sendReply(inexactMsg);
|
||||
return this.errorReply(`Error: ${species.name} has no Random Battle data in ${format.name}`);
|
||||
throw new Chat.ErrorMessage(`Error: ${species.name} has no Random Battle data in ${format.name}`);
|
||||
}
|
||||
let buf = movesets.join('<hr/>');
|
||||
if (setCount <= 2) {
|
||||
|
|
@ -605,7 +604,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!args[0]) return this.parse(`/help battlefactory`);
|
||||
const species = Dex.species.get(args[0]);
|
||||
if (!species.exists) {
|
||||
return this.errorReply(`Error: Pok\u00e9mon '${args[0].trim()}' not found.`);
|
||||
throw new Chat.ErrorMessage(`Error: Pok\u00e9mon '${args[0].trim()}' not found.`);
|
||||
}
|
||||
let mod = 'gen9';
|
||||
if (args[1] && toID(args[1]) in Dex.dexes && Dex.dexes[toID(args[1])].gen >= 7) mod = toID(args[1]);
|
||||
|
|
@ -617,7 +616,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!args[0]) return this.parse(`/help battlefactory`);
|
||||
const species = Dex.species.get(args[0]);
|
||||
if (!species.exists) {
|
||||
return this.errorReply(`Error: Pok\u00e9mon '${args[0].trim()}' not found.`);
|
||||
throw new Chat.ErrorMessage(`Error: Pok\u00e9mon '${args[0].trim()}' not found.`);
|
||||
}
|
||||
let tier = '';
|
||||
if (args[1] && toID(args[1]) in TIERS) {
|
||||
|
|
@ -654,7 +653,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!this.runBroadcast()) return;
|
||||
if (!target) return this.parse(`/help cap1v1`);
|
||||
const species = Dex.species.get(target);
|
||||
if (!species.exists) return this.errorReply(`Error: Pok\u00e9mon '${target.trim()}' not found.`);
|
||||
if (!species.exists) throw new Chat.ErrorMessage(`Error: Pok\u00e9mon '${target.trim()}' not found.`);
|
||||
const cap1v1Set = CAP1v1Sets(species);
|
||||
if (!cap1v1Set) return this.parse(`/help cap1v1`);
|
||||
if (typeof cap1v1Set !== 'string') {
|
||||
|
|
|
|||
|
|
@ -216,11 +216,11 @@ export const commands: Chat.ChatCommands = {
|
|||
async removewinrates(target, room, user) {
|
||||
this.checkCan('rangeban');
|
||||
if (!/^[0-9]{4}-[0-9]{2}$/.test(target) || target === getMonth()) {
|
||||
return this.errorReply(`Invalid month: ${target}`);
|
||||
throw new Chat.ErrorMessage(`Invalid month: ${target}`);
|
||||
}
|
||||
const path = STATS_PATH.replace('{{MON}}', target);
|
||||
if (!(await FS(path).exists())) {
|
||||
return this.errorReply(`No stats for the month ${target}.`);
|
||||
throw new Chat.ErrorMessage(`No stats for the month ${target}.`);
|
||||
}
|
||||
await FS(path).unlinkIfExists();
|
||||
this.globalModlog('REMOVEWINRATES', null, target);
|
||||
|
|
@ -233,22 +233,22 @@ export const pages: Chat.PageTable = {
|
|||
if (!user.named) return Rooms.RETRY_AFTER_LOGIN;
|
||||
query = query.join('-').split('--');
|
||||
const format = toID(query.shift());
|
||||
if (!format) return this.errorReply(`Specify a format to view winrates for.`);
|
||||
if (!format) throw new Chat.ErrorMessage(`Specify a format to view winrates for.`);
|
||||
if (!stats.formats[format]) {
|
||||
return this.errorReply(`That format does not have winrates tracked.`);
|
||||
throw new Chat.ErrorMessage(`That format does not have winrates tracked.`);
|
||||
}
|
||||
checkRollover();
|
||||
const sorter = toID(query.shift() || 'zscore');
|
||||
if (!['zscore', 'raw'].includes(sorter)) {
|
||||
return this.errorReply(`Invalid sorting method. Must be either 'zscore' or 'raw'.`);
|
||||
throw new Chat.ErrorMessage(`Invalid sorting method. Must be either 'zscore' or 'raw'.`);
|
||||
}
|
||||
const month = query.shift() || getMonth();
|
||||
if (!/^[0-9]{4}-[0-9]{2}$/.test(month)) {
|
||||
return this.errorReply(`Invalid month: ${month}`);
|
||||
throw new Chat.ErrorMessage(`Invalid month: ${month}`);
|
||||
}
|
||||
const isOldMonth = month !== getMonth();
|
||||
if (isOldMonth && !(await FS(STATS_PATH.replace('{{MONTH}}', month)).exists())) {
|
||||
return this.errorReply(`There are no winrates for that month.`);
|
||||
throw new Chat.ErrorMessage(`There are no winrates for that month.`);
|
||||
}
|
||||
const formatTitle = Dex.formats.get(format).name;
|
||||
let buf = `<div class="pad"><h2>Winrates for ${formatTitle} (${month})</h2>`;
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const isHTML = cmd.includes('html');
|
||||
const isByMessages = cmd.includes('bymessages');
|
||||
room = this.requireRoom();
|
||||
if (room.settings.isPersonal) return this.errorReply(`Personal rooms do not support repeated messages.`);
|
||||
if (room.settings.isPersonal) throw new Chat.ErrorMessage(`Personal rooms do not support repeated messages.`);
|
||||
this.checkCan(isHTML ? 'addhtml' : 'mute', null, room);
|
||||
const [intervalString, name, ...messageArray] = target.split(',');
|
||||
const id = toID(name);
|
||||
|
|
@ -211,7 +211,7 @@ export const commands: Chat.ChatCommands = {
|
|||
repeatfaq(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
if (room.settings.isPersonal) return this.errorReply(`Personal rooms do not support repeated messages.`);
|
||||
if (room.settings.isPersonal) throw new Chat.ErrorMessage(`Personal rooms do not support repeated messages.`);
|
||||
const isByMessages = cmd.includes('bymessages');
|
||||
|
||||
let [intervalString, topic] = target.split(',');
|
||||
|
|
@ -257,11 +257,11 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
this.checkCan('mute', null, room);
|
||||
if (!room.settings.repeats?.length) {
|
||||
return this.errorReply(this.tr`There are no repeated phrases in this room.`);
|
||||
throw new Chat.ErrorMessage(this.tr`There are no repeated phrases in this room.`);
|
||||
}
|
||||
|
||||
if (!Repeats.hasRepeat(room, id)) {
|
||||
return this.errorReply(this.tr`The phrase labeled with "${id}" is not being repeated in this room.`);
|
||||
throw new Chat.ErrorMessage(this.tr`The phrase labeled with "${id}" is not being repeated in this room.`);
|
||||
}
|
||||
|
||||
Repeats.removeRepeat(room, id);
|
||||
|
|
@ -275,7 +275,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('declare', null, room);
|
||||
if (!room.settings.repeats?.length) {
|
||||
return this.errorReply(this.tr`There are no repeated phrases in this room.`);
|
||||
throw new Chat.ErrorMessage(this.tr`There are no repeated phrases in this room.`);
|
||||
}
|
||||
|
||||
for (const { id } of room.settings.repeats) {
|
||||
|
|
@ -289,7 +289,7 @@ export const commands: Chat.ChatCommands = {
|
|||
repeats: 'viewrepeats',
|
||||
viewrepeats(target, room, user) {
|
||||
const roomid = toID(target) || room?.roomid;
|
||||
if (!roomid) return this.errorReply(this.tr`You must specify a room when using this command in PMs.`);
|
||||
if (!roomid) throw new Chat.ErrorMessage(this.tr`You must specify a room when using this command in PMs.`);
|
||||
this.parse(`/j view-repeats-${roomid}`);
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ export const commands: Chat.ChatCommands = {
|
|||
question(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const responder = room.responder;
|
||||
if (!responder) return this.errorReply(`This room does not have an autoresponder configured.`);
|
||||
if (!responder) throw new Chat.ErrorMessage(`This room does not have an autoresponder configured.`);
|
||||
if (!target) return this.parse("/help question");
|
||||
const reply = responder.visualize(target, true);
|
||||
if (!reply) return this.sendReplyBox(`No answer found.`);
|
||||
|
|
@ -317,7 +317,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const responder = room.responder;
|
||||
if (!responder) {
|
||||
return this.errorReply(`This room has not configured an autoresponder.`);
|
||||
throw new Chat.ErrorMessage(`This room has not configured an autoresponder.`);
|
||||
}
|
||||
if (!target) {
|
||||
return this.parse('/help autoresponder');
|
||||
|
|
@ -337,15 +337,15 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
this.checkCan('ban', null, room);
|
||||
if (room.settings.isPrivate === true) {
|
||||
return this.errorReply(`Secret rooms cannot enable an autoresponder.`);
|
||||
throw new Chat.ErrorMessage(`Secret rooms cannot enable an autoresponder.`);
|
||||
}
|
||||
if (this.meansYes(target)) {
|
||||
if (room.responder) return this.errorReply(`The Autoresponder for this room is already enabled.`);
|
||||
if (room.responder) throw new Chat.ErrorMessage(`The Autoresponder for this room is already enabled.`);
|
||||
room.responder = new AutoResponder(room, answererData[room.roomid]);
|
||||
room.responder.writeState();
|
||||
}
|
||||
if (this.meansNo(target)) {
|
||||
if (!room.responder) return this.errorReply(`The Autoresponder for this room is already disabled.`);
|
||||
if (!room.responder) throw new Chat.ErrorMessage(`The Autoresponder for this room is already disabled.`);
|
||||
room.responder.destroy();
|
||||
}
|
||||
this.privateModAction(`${user.name} ${!room.responder ? 'disabled' : 'enabled'} the auto-response filter.`);
|
||||
|
|
@ -355,11 +355,11 @@ export const commands: Chat.ChatCommands = {
|
|||
add(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom();
|
||||
if (!room.responder) {
|
||||
return this.errorReply(`This room has not configured an auto-response filter.`);
|
||||
throw new Chat.ErrorMessage(`This room has not configured an auto-response filter.`);
|
||||
}
|
||||
const force = cmd === 'forceadd';
|
||||
if (force && !AutoResponder.canOverride(user, room)) {
|
||||
return this.errorReply(`You cannot use raw regex - use /autoresponder add instead.`);
|
||||
throw new Chat.ErrorMessage(`You cannot use raw regex - use /autoresponder add instead.`);
|
||||
}
|
||||
this.checkCan('ban', null, room);
|
||||
room.responder.tryAddRegex(target, force);
|
||||
|
|
@ -370,11 +370,11 @@ export const commands: Chat.ChatCommands = {
|
|||
const [faq, index] = target.split(',');
|
||||
room = this.requireRoom();
|
||||
if (!room.responder) {
|
||||
return this.errorReply(`${room.title} has not configured an auto-response filter.`);
|
||||
throw new Chat.ErrorMessage(`${room.title} has not configured an auto-response filter.`);
|
||||
}
|
||||
this.checkCan('ban', null, room);
|
||||
const num = parseInt(index);
|
||||
if (isNaN(num)) return this.errorReply("Invalid index.");
|
||||
if (isNaN(num)) throw new Chat.ErrorMessage("Invalid index.");
|
||||
room.responder.tryRemoveRegex(faq, num - 1);
|
||||
this.privateModAction(`${user.name} removed regex ${num} from the usable regexes for ${faq}.`);
|
||||
this.modlog('AUTOFILTER REMOVE', null, `removed regex ${index} for FAQ ${faq}`);
|
||||
|
|
@ -386,7 +386,7 @@ export const commands: Chat.ChatCommands = {
|
|||
ignore(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.responder) {
|
||||
return this.errorReply(`This room has not configured an auto-response filter.`);
|
||||
throw new Chat.ErrorMessage(`This room has not configured an auto-response filter.`);
|
||||
}
|
||||
this.checkCan('ban', null, room);
|
||||
if (!toID(target)) {
|
||||
|
|
@ -402,7 +402,7 @@ export const commands: Chat.ChatCommands = {
|
|||
unignore(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.responder) {
|
||||
return this.errorReply(`${room.title} has not configured an auto-response filter.`);
|
||||
throw new Chat.ErrorMessage(`${room.title} has not configured an auto-response filter.`);
|
||||
}
|
||||
this.checkCan('ban', null, room);
|
||||
if (!toID(target)) {
|
||||
|
|
@ -434,7 +434,7 @@ export const pages: Chat.PageTable = {
|
|||
async autoresponder(args, user) {
|
||||
const room = this.requireRoom();
|
||||
if (!room.responder) {
|
||||
return this.errorReply(`${room.title} does not have a configured autoresponder.`);
|
||||
throw new Chat.ErrorMessage(`${room.title} does not have a configured autoresponder.`);
|
||||
}
|
||||
args.shift();
|
||||
const roomData = answererData[room.roomid];
|
||||
|
|
@ -508,7 +508,7 @@ export const pages: Chat.PageTable = {
|
|||
this.title = `[${room.title} Autoresponder ignore list]`;
|
||||
buf = `<div class="pad"><h2>${room.title} responder terms to ignore:</h2>${back}${refresh('ignore')}<hr />`;
|
||||
if (!roomData.ignore) {
|
||||
return this.errorReply(`No terms on ignore list.`);
|
||||
throw new Chat.ErrorMessage(`No terms on ignore list.`);
|
||||
}
|
||||
for (const term of roomData.ignore) {
|
||||
buf += `- ${term} <button class="button" name="send"value="/msgroom ${room.roomid},/ar unignore ${term}">Remove</button><br />`;
|
||||
|
|
|
|||
|
|
@ -104,9 +104,9 @@ export const commands: Chat.ChatCommands = {
|
|||
roomevents: {
|
||||
''(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
if (!room.settings.events || !Object.keys(room.settings.events).length) {
|
||||
return this.errorReply("There are currently no planned upcoming events for this room.");
|
||||
throw new Chat.ErrorMessage("There are currently no planned upcoming events for this room.");
|
||||
}
|
||||
if (!this.runBroadcast()) return;
|
||||
convertAliasFormat(room);
|
||||
|
|
@ -131,7 +131,7 @@ export const commands: Chat.ChatCommands = {
|
|||
edit: 'add',
|
||||
add(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.checkCan('ban', null, room);
|
||||
if (!room.settings.events) room.settings.events = Object.create(null);
|
||||
convertAliasFormat(room);
|
||||
|
|
@ -139,21 +139,21 @@ export const commands: Chat.ChatCommands = {
|
|||
const [eventName, date, ...desc] = target.split(target.includes('|') ? '|' : ',');
|
||||
|
||||
if (!(eventName && date && desc)) {
|
||||
return this.errorReply("You're missing a command parameter - to see this command's syntax, use /help roomevents.");
|
||||
throw new Chat.ErrorMessage("You're missing a command parameter - to see this command's syntax, use /help roomevents.");
|
||||
}
|
||||
|
||||
const dateActual = date.trim();
|
||||
const descString = desc.join(target.includes('|') ? '|' : ',').trim();
|
||||
|
||||
if (eventName.trim().length > 50) return this.errorReply("Event names should not exceed 50 characters.");
|
||||
if (dateActual.length > 150) return this.errorReply("Event dates should not exceed 150 characters.");
|
||||
if (descString.length > 1000) return this.errorReply("Event descriptions should not exceed 1000 characters.");
|
||||
if (eventName.trim().length > 50) throw new Chat.ErrorMessage("Event names should not exceed 50 characters.");
|
||||
if (dateActual.length > 150) throw new Chat.ErrorMessage("Event dates should not exceed 150 characters.");
|
||||
if (descString.length > 1000) throw new Chat.ErrorMessage("Event descriptions should not exceed 1000 characters.");
|
||||
|
||||
const eventId = getEventID(eventName, room);
|
||||
if (!eventId) return this.errorReply("Event names must contain at least one alphanumerical character.");
|
||||
if (!eventId) throw new Chat.ErrorMessage("Event names must contain at least one alphanumerical character.");
|
||||
|
||||
const oldEvent = room.settings.events?.[eventId] as RoomEvent;
|
||||
if (oldEvent && 'events' in oldEvent) return this.errorReply(`"${eventId}" is already the name of a category.`);
|
||||
if (oldEvent && 'events' in oldEvent) throw new Chat.ErrorMessage(`"${eventId}" is already the name of a category.`);
|
||||
|
||||
const eventNameActual = (oldEvent ? oldEvent.eventName : eventName.trim());
|
||||
this.privateModAction(`${user.name} ${oldEvent ? "edited the" : "added a"} roomevent titled "${eventNameActual}".`);
|
||||
|
|
@ -169,24 +169,24 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
rename(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.checkCan('ban', null, room);
|
||||
let [oldName, newName] = target.split(target.includes('|') ? '|' : ',');
|
||||
if (!(oldName && newName)) return this.errorReply("Usage: /roomevents rename [old name], [new name]");
|
||||
if (!(oldName && newName)) throw new Chat.ErrorMessage("Usage: /roomevents rename [old name], [new name]");
|
||||
|
||||
convertAliasFormat(room);
|
||||
newName = newName.trim();
|
||||
const newID = toID(newName);
|
||||
const oldID = (getAliases(room).includes(toID(oldName)) ? getEventID(oldName, room) : toID(oldName));
|
||||
if (newID === oldID) return this.errorReply("The new name must be different from the old one.");
|
||||
if (!newID) return this.errorReply("Event names must contain at least one alphanumeric character.");
|
||||
if (newName.length > 50) return this.errorReply("Event names should not exceed 50 characters.");
|
||||
if (newID === oldID) throw new Chat.ErrorMessage("The new name must be different from the old one.");
|
||||
if (!newID) throw new Chat.ErrorMessage("Event names must contain at least one alphanumeric character.");
|
||||
if (newName.length > 50) throw new Chat.ErrorMessage("Event names should not exceed 50 characters.");
|
||||
|
||||
const events = room.settings.events!;
|
||||
const eventData = events?.[oldID];
|
||||
if (!(eventData && 'eventName' in eventData)) return this.errorReply(`There is no event titled "${oldName}".`);
|
||||
if (!(eventData && 'eventName' in eventData)) throw new Chat.ErrorMessage(`There is no event titled "${oldName}".`);
|
||||
if (events?.[newID]) {
|
||||
return this.errorReply(`"${newName}" is already an event, alias, or category.`);
|
||||
throw new Chat.ErrorMessage(`"${newName}" is already an event, alias, or category.`);
|
||||
}
|
||||
|
||||
const originalName = eventData.eventName;
|
||||
|
|
@ -202,19 +202,21 @@ export const commands: Chat.ChatCommands = {
|
|||
begin: 'start',
|
||||
start(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.checkCan('ban', null, room);
|
||||
if (!room.settings.events || !Object.keys(room.settings.events).length) {
|
||||
return this.errorReply("There are currently no planned upcoming events for this room to start.");
|
||||
throw new Chat.ErrorMessage("There are currently no planned upcoming events for this room to start.");
|
||||
}
|
||||
if (!target) return this.errorReply("Usage: /roomevents start [event name]");
|
||||
if (!target) throw new Chat.ErrorMessage("Usage: /roomevents start [event name]");
|
||||
convertAliasFormat(room);
|
||||
|
||||
target = toID(target);
|
||||
const event = room.settings.events[getEventID(target, room)];
|
||||
if (!(event && 'eventName' in event)) return this.errorReply(`There is no event titled '${target}'. Check spelling?`);
|
||||
if (!(event && 'eventName' in event)) {
|
||||
throw new Chat.ErrorMessage(`There is no event titled '${target}'. Check spelling?`);
|
||||
}
|
||||
if (event.started) {
|
||||
return this.errorReply(`The event ${event.eventName} has already started.`);
|
||||
throw new Chat.ErrorMessage(`The event ${event.eventName} has already started.`);
|
||||
}
|
||||
for (const u in room.users) {
|
||||
const activeUser = Users.get(u);
|
||||
|
|
@ -237,17 +239,17 @@ export const commands: Chat.ChatCommands = {
|
|||
delete: 'remove',
|
||||
remove(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.checkCan('ban', null, room);
|
||||
if (!room.settings.events || Object.keys(room.settings.events).length === 0) {
|
||||
return this.errorReply("There are currently no planned upcoming events for this room to remove.");
|
||||
throw new Chat.ErrorMessage("There are currently no planned upcoming events for this room to remove.");
|
||||
}
|
||||
if (!target) return this.errorReply("Usage: /roomevents remove [event name]");
|
||||
if (!target) throw new Chat.ErrorMessage("Usage: /roomevents remove [event name]");
|
||||
const eventID = toID(target);
|
||||
convertAliasFormat(room);
|
||||
if (getAliases(room).includes(eventID)) return this.errorReply("To delete aliases, use /roomevents removealias.");
|
||||
if (getAliases(room).includes(eventID)) throw new Chat.ErrorMessage("To delete aliases, use /roomevents removealias.");
|
||||
if (!(room.settings.events[eventID] && 'eventName' in room.settings.events[eventID])) {
|
||||
return this.errorReply(`There is no event titled '${target}'. Check spelling?`);
|
||||
throw new Chat.ErrorMessage(`There is no event titled '${target}'. Check spelling?`);
|
||||
}
|
||||
|
||||
delete room.settings.events[eventID];
|
||||
|
|
@ -265,12 +267,12 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
view(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
if (!room.settings.events || !Object.keys(room.settings.events).length) {
|
||||
return this.errorReply("There are currently no planned upcoming events for this room.");
|
||||
throw new Chat.ErrorMessage("There are currently no planned upcoming events for this room.");
|
||||
}
|
||||
|
||||
if (!target) return this.errorReply("Usage: /roomevents view [event name, alias, or category]");
|
||||
if (!target) throw new Chat.ErrorMessage("Usage: /roomevents view [event name, alias, or category]");
|
||||
convertAliasFormat(room);
|
||||
target = getEventID(target, room);
|
||||
|
||||
|
|
@ -288,7 +290,7 @@ export const commands: Chat.ChatCommands = {
|
|||
} else if (room.settings.events[target] && 'eventName' in room.settings.events[target]) {
|
||||
events.push(room.settings.events[target] as RoomEvent);
|
||||
} else {
|
||||
return this.errorReply(`There is no event or category titled '${target}'. Check spelling?`);
|
||||
throw new Chat.ErrorMessage(`There is no event or category titled '${target}'. Check spelling?`);
|
||||
}
|
||||
if (!this.runBroadcast()) return;
|
||||
let hasAliases = false;
|
||||
|
|
@ -325,19 +327,19 @@ export const commands: Chat.ChatCommands = {
|
|||
alias: 'addalias',
|
||||
addalias(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.checkCan('ban', null, room);
|
||||
const [alias, eventId] = target.split(target.includes('|') ? '|' : ',').map(argument => toID(argument));
|
||||
if (!(alias && eventId)) {
|
||||
return this.errorReply("Usage: /roomevents addalias [alias], [event name]. Aliases must contain at least one alphanumeric character.");
|
||||
throw new Chat.ErrorMessage("Usage: /roomevents addalias [alias], [event name]. Aliases must contain at least one alphanumeric character.");
|
||||
}
|
||||
if (!room.settings.events || Object.keys(room.settings.events).length === 0) {
|
||||
return this.errorReply(`There are currently no scheduled events.`);
|
||||
throw new Chat.ErrorMessage(`There are currently no scheduled events.`);
|
||||
}
|
||||
convertAliasFormat(room);
|
||||
const event = room.settings.events[eventId];
|
||||
if (!(event && 'eventName' in event)) return this.errorReply(`There is no event titled "${eventId}".`);
|
||||
if (room.settings.events[alias]) return this.errorReply(`"${alias}" is already an event, alias, or category.`);
|
||||
if (!(event && 'eventName' in event)) throw new Chat.ErrorMessage(`There is no event titled "${eventId}".`);
|
||||
if (room.settings.events[alias]) throw new Chat.ErrorMessage(`"${alias}" is already an event, alias, or category.`);
|
||||
|
||||
room.settings.events[alias] = { eventID: eventId };
|
||||
this.privateModAction(`${user.name} added an alias "${alias}" for the roomevent "${eventId}".`);
|
||||
|
|
@ -348,16 +350,16 @@ export const commands: Chat.ChatCommands = {
|
|||
deletealias: 'removealias',
|
||||
removealias(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.checkCan('ban', null, room);
|
||||
target = toID(target);
|
||||
if (!target) return this.errorReply("Usage: /roomevents removealias <alias>");
|
||||
if (!target) throw new Chat.ErrorMessage("Usage: /roomevents removealias <alias>");
|
||||
if (!room.settings.events || Object.keys(room.settings.events).length === 0) {
|
||||
return this.errorReply(`There are currently no scheduled events.`);
|
||||
throw new Chat.ErrorMessage(`There are currently no scheduled events.`);
|
||||
}
|
||||
convertAliasFormat(room);
|
||||
if (!(room.settings.events[target] && 'eventID' in room.settings.events[target])) {
|
||||
return this.errorReply(`${target} isn't an alias.`);
|
||||
throw new Chat.ErrorMessage(`${target} isn't an alias.`);
|
||||
}
|
||||
delete room.settings.events[target];
|
||||
|
||||
|
|
@ -368,25 +370,25 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
addtocategory(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.checkCan('ban', null, room);
|
||||
const [eventId, categoryId] = target.split(target.includes('|') ? '|' : ',').map(argument => toID(argument));
|
||||
if (!(eventId && categoryId)) return this.errorReply("Usage: /roomevents addtocategory [event name], [category].");
|
||||
if (!(eventId && categoryId)) throw new Chat.ErrorMessage("Usage: /roomevents addtocategory [event name], [category].");
|
||||
if (!room.settings.events || Object.keys(room.settings.events).length === 0) {
|
||||
return this.errorReply(`There are currently no scheduled events.`);
|
||||
throw new Chat.ErrorMessage(`There are currently no scheduled events.`);
|
||||
}
|
||||
convertAliasFormat(room);
|
||||
const event = room.settings.events[getEventID(eventId, room)];
|
||||
if (!(event && 'eventName' in event)) return this.errorReply(`There is no event or alias titled "${eventId}".`);
|
||||
if (!(event && 'eventName' in event)) throw new Chat.ErrorMessage(`There is no event or alias titled "${eventId}".`);
|
||||
const category = room.settings.events[categoryId];
|
||||
if (category && !('events' in category)) {
|
||||
return this.errorReply(`There is already an event or alias titled "${categoryId}".`);
|
||||
throw new Chat.ErrorMessage(`There is already an event or alias titled "${categoryId}".`);
|
||||
}
|
||||
if (!category) {
|
||||
return this.errorReply(`There is no category titled "${categoryId}". To create it, use /roomevents addcategory ${categoryId}.`);
|
||||
throw new Chat.ErrorMessage(`There is no category titled "${categoryId}". To create it, use /roomevents addcategory ${categoryId}.`);
|
||||
}
|
||||
if (category.events.includes(toID(event.eventName))) {
|
||||
return this.errorReply(`The event "${eventId}" is already in the "${categoryId}" category.`);
|
||||
throw new Chat.ErrorMessage(`The event "${eventId}" is already in the "${categoryId}" category.`);
|
||||
}
|
||||
category.events.push(toID(event.eventName));
|
||||
room.settings.events[categoryId] = category;
|
||||
|
|
@ -399,27 +401,27 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
removefromcategory(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.checkCan('ban', null, room);
|
||||
const [eventId, categoryId] = target.split(target.includes('|') ? '|' : ',').map(argument => toID(argument));
|
||||
if (!(eventId && categoryId)) {
|
||||
return this.errorReply("Usage: /roomevents removefromcategory [event name], [category].");
|
||||
throw new Chat.ErrorMessage("Usage: /roomevents removefromcategory [event name], [category].");
|
||||
}
|
||||
if (!room.settings.events || Object.keys(room.settings.events).length === 0) {
|
||||
return this.errorReply(`There are currently no scheduled events.`);
|
||||
throw new Chat.ErrorMessage(`There are currently no scheduled events.`);
|
||||
}
|
||||
convertAliasFormat(room);
|
||||
const event = room.settings.events[getEventID(eventId, room)];
|
||||
if (!(event && 'eventName' in event)) return this.errorReply(`There is no event or alias titled "${eventId}".`);
|
||||
if (!(event && 'eventName' in event)) throw new Chat.ErrorMessage(`There is no event or alias titled "${eventId}".`);
|
||||
|
||||
const category = room.settings.events[categoryId];
|
||||
if (category && !('events' in category)) {
|
||||
return this.errorReply(`There is already an event or alias titled "${categoryId}".`);
|
||||
throw new Chat.ErrorMessage(`There is already an event or alias titled "${categoryId}".`);
|
||||
}
|
||||
if (!category) return this.errorReply(`There is no category titled "${categoryId}".`);
|
||||
if (!category) throw new Chat.ErrorMessage(`There is no category titled "${categoryId}".`);
|
||||
|
||||
if (!category.events.includes(toID(event.eventName))) {
|
||||
return this.errorReply(`The event "${eventId}" isn't in the "${categoryId}" category.`);
|
||||
throw new Chat.ErrorMessage(`The event "${eventId}" isn't in the "${categoryId}" category.`);
|
||||
}
|
||||
category.events = category.events.filter(e => e !== eventId);
|
||||
room.settings.events[categoryId] = category;
|
||||
|
|
@ -433,15 +435,15 @@ export const commands: Chat.ChatCommands = {
|
|||
addcat: 'addcategory',
|
||||
addcategory(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.checkCan('ban', null, room);
|
||||
const categoryId = toID(target);
|
||||
if (!target) {
|
||||
return this.errorReply("Usage: /roomevents addcategory [category name]. Categories must contain at least one alphanumeric character.");
|
||||
throw new Chat.ErrorMessage("Usage: /roomevents addcategory [category name]. Categories must contain at least one alphanumeric character.");
|
||||
}
|
||||
convertAliasFormat(room);
|
||||
if (!room.settings.events) room.settings.events = Object.create(null);
|
||||
if (room.settings.events?.[categoryId]) return this.errorReply(`The category "${target}" already exists.`);
|
||||
if (room.settings.events?.[categoryId]) throw new Chat.ErrorMessage(`The category "${target}" already exists.`);
|
||||
|
||||
room.settings.events![categoryId] = { events: [] };
|
||||
|
||||
|
|
@ -457,13 +459,13 @@ export const commands: Chat.ChatCommands = {
|
|||
rmcat: 'removecategory',
|
||||
removecategory(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.checkCan('ban', null, room);
|
||||
const categoryId = toID(target);
|
||||
if (!target) return this.errorReply("Usage: /roomevents removecategory [category name].");
|
||||
if (!target) throw new Chat.ErrorMessage("Usage: /roomevents removecategory [category name].");
|
||||
convertAliasFormat(room);
|
||||
if (!room.settings.events) room.settings.events = Object.create(null);
|
||||
if (!room.settings.events?.[categoryId]) return this.errorReply(`The category "${target}" doesn't exist.`);
|
||||
if (!room.settings.events?.[categoryId]) throw new Chat.ErrorMessage(`The category "${target}" doesn't exist.`);
|
||||
|
||||
delete room.settings.events?.[categoryId];
|
||||
|
||||
|
|
@ -476,13 +478,13 @@ export const commands: Chat.ChatCommands = {
|
|||
viewcategories: 'categories',
|
||||
categories(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
this.runBroadcast();
|
||||
|
||||
const categoryButtons = getAllCategories(room).map(
|
||||
category => `<button class="button" name="send" value="/roomevents view ${category}">${category}</button>`
|
||||
);
|
||||
if (!categoryButtons.length) return this.errorReply(`There are no roomevent categories in ${room.title}.`);
|
||||
if (!categoryButtons.length) throw new Chat.ErrorMessage(`There are no roomevent categories in ${room.title}.`);
|
||||
this.sendReplyBox(`Roomevent categories in ${room.title}: ${categoryButtons.join(' ')}`);
|
||||
},
|
||||
|
||||
|
|
@ -493,9 +495,9 @@ export const commands: Chat.ChatCommands = {
|
|||
sortby(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
// preconditions
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
if (!room.settings.events || !Object.keys(room.settings.events).length) {
|
||||
return this.errorReply("There are currently no planned upcoming events for this room.");
|
||||
throw new Chat.ErrorMessage("There are currently no planned upcoming events for this room.");
|
||||
}
|
||||
this.checkCan('ban', null, room);
|
||||
|
||||
|
|
@ -545,7 +547,7 @@ export const commands: Chat.ChatCommands = {
|
|||
);
|
||||
break;
|
||||
default:
|
||||
return this.errorReply(`Invalid column name "${columnName}". Please use one of: date, desc, name.`);
|
||||
throw new Chat.ErrorMessage(`Invalid column name "${columnName}". Please use one of: date, desc, name.`);
|
||||
}
|
||||
|
||||
// rebuild the room.settings.events object
|
||||
|
|
|
|||
|
|
@ -61,26 +61,26 @@ export const commands: Chat.ChatCommands = {
|
|||
const useHTML = this.cmd.includes('html');
|
||||
this.checkCan('ban', null, room);
|
||||
if (useHTML && !user.can('addhtml', null, room, this.fullCmd)) {
|
||||
return this.errorReply(`You are not allowed to use raw HTML in roomfaqs.`);
|
||||
throw new Chat.ErrorMessage(`You are not allowed to use raw HTML in roomfaqs.`);
|
||||
}
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
if (!target) return this.parse('/help roomfaq');
|
||||
|
||||
target = target.trim();
|
||||
const input = this.filter(target);
|
||||
if (target !== input) return this.errorReply("You are not allowed to use fitered words in roomfaq entries.");
|
||||
if (target !== input) throw new Chat.ErrorMessage("You are not allowed to use fitered words in roomfaq entries.");
|
||||
let [topic, ...rest] = input.split(',');
|
||||
|
||||
topic = toID(topic);
|
||||
if (!(topic && rest.length)) return this.parse('/help roomfaq');
|
||||
let text = rest.join(',').trim();
|
||||
if (topic.length > 25) return this.errorReply("FAQ topics should not exceed 25 characters.");
|
||||
if (topic.length > 25) throw new Chat.ErrorMessage("FAQ topics should not exceed 25 characters.");
|
||||
|
||||
const lengthWithoutFormatting = Chat.stripFormatting(text).length;
|
||||
if (lengthWithoutFormatting > MAX_ROOMFAQ_LENGTH) {
|
||||
return this.errorReply(`FAQ entries must not exceed ${MAX_ROOMFAQ_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`FAQ entries must not exceed ${MAX_ROOMFAQ_LENGTH} characters.`);
|
||||
} else if (lengthWithoutFormatting < 1) {
|
||||
return this.errorReply(`FAQ entries must include at least one character.`);
|
||||
throw new Chat.ErrorMessage(`FAQ entries must include at least one character.`);
|
||||
}
|
||||
|
||||
if (!useHTML) {
|
||||
|
|
@ -108,7 +108,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const topic = toID(target);
|
||||
if (!topic) return this.parse('/help roomfaq');
|
||||
|
||||
if (!roomFaqs[room.roomid]?.[topic]) return this.errorReply("Invalid topic.");
|
||||
if (!roomFaqs[room.roomid]?.[topic]) throw new Chat.ErrorMessage("Invalid topic.");
|
||||
if (
|
||||
room.settings.repeats?.length &&
|
||||
room.settings.repeats.filter(x => x.faq && x.id === topic).length
|
||||
|
|
@ -131,21 +131,21 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkChat();
|
||||
this.checkCan('ban', null, room);
|
||||
if (!room.persist) return this.errorReply("This command is unavailable in temporary rooms.");
|
||||
if (!room.persist) throw new Chat.ErrorMessage("This command is unavailable in temporary rooms.");
|
||||
const [alias, topic] = target.split(',').map(val => toID(val));
|
||||
|
||||
if (!(alias && topic)) return this.parse('/help roomfaq');
|
||||
if (alias.length > 25) return this.errorReply("FAQ topics should not exceed 25 characters.");
|
||||
if (alias === topic) return this.errorReply("You cannot make the alias have the same name as the topic.");
|
||||
if (alias.length > 25) throw new Chat.ErrorMessage("FAQ topics should not exceed 25 characters.");
|
||||
if (alias === topic) throw new Chat.ErrorMessage("You cannot make the alias have the same name as the topic.");
|
||||
if (roomFaqs[room.roomid][alias] && !roomFaqs[room.roomid][alias].alias) {
|
||||
return this.errorReply("You cannot overwrite an existing topic with an alias; please delete the topic first.");
|
||||
throw new Chat.ErrorMessage("You cannot overwrite an existing topic with an alias; please delete the topic first.");
|
||||
}
|
||||
|
||||
if (!(roomFaqs[room.roomid] && topic in roomFaqs[room.roomid])) {
|
||||
return this.errorReply(`The topic ${topic} was not found in this room's faq list.`);
|
||||
throw new Chat.ErrorMessage(`The topic ${topic} was not found in this room's faq list.`);
|
||||
}
|
||||
if (getAlias(room.roomid, topic)) {
|
||||
return this.errorReply(`You cannot make an alias of an alias. Use /addalias ${alias}, ${getAlias(room.roomid, topic)} instead.`);
|
||||
throw new Chat.ErrorMessage(`You cannot make an alias of an alias. Use /addalias ${alias}, ${getAlias(room.roomid, topic)} instead.`);
|
||||
}
|
||||
roomFaqs[room.roomid][alias] = {
|
||||
alias: true,
|
||||
|
|
@ -159,13 +159,13 @@ export const commands: Chat.ChatCommands = {
|
|||
rfaq: 'roomfaq',
|
||||
roomfaq(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom();
|
||||
if (!roomFaqs[room.roomid]) return this.errorReply("This room has no FAQ topics.");
|
||||
if (!roomFaqs[room.roomid]) throw new Chat.ErrorMessage("This room has no FAQ topics.");
|
||||
let topic: string = toID(target);
|
||||
if (topic === 'constructor') return false;
|
||||
if (!topic) {
|
||||
return this.parse(`/join view-roomfaqs-${room.roomid}`);
|
||||
}
|
||||
if (!roomFaqs[room.roomid][topic]) return this.errorReply("Invalid topic.");
|
||||
if (!roomFaqs[room.roomid][topic]) throw new Chat.ErrorMessage("Invalid topic.");
|
||||
topic = getAlias(room.roomid, topic) || topic;
|
||||
|
||||
if (!this.runBroadcast()) return;
|
||||
|
|
|
|||
|
|
@ -1064,7 +1064,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
join(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply("There is no scavenger hunt currently running.");
|
||||
if (!game) throw new Chat.ErrorMessage("There is no scavenger hunt currently running.");
|
||||
this.checkChat();
|
||||
|
||||
game.joinGame(user);
|
||||
|
|
@ -1073,7 +1073,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
leave(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply("There is no scavenger hunt currently running.");
|
||||
if (!game) throw new Chat.ErrorMessage("There is no scavenger hunt currently running.");
|
||||
game.leaveGame(user);
|
||||
},
|
||||
|
||||
|
|
@ -1092,15 +1092,15 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
start(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
if (room.scavgame) return this.errorReply('There is already a scavenger game running.');
|
||||
if (room.scavgame) throw new Chat.ErrorMessage('There is already a scavenger game running.');
|
||||
if (room.getGame(ScavengerHunt)) {
|
||||
return this.errorReply('You cannot start a scavenger game where there is already a scavenger hunt in the room.');
|
||||
throw new Chat.ErrorMessage('You cannot start a scavenger game where there is already a scavenger hunt in the room.');
|
||||
}
|
||||
|
||||
target = toID(target);
|
||||
const game = ScavMods.LoadGame(room, target);
|
||||
|
||||
if (!game) return this.errorReply('Invalid game mode.');
|
||||
if (!game) throw new Chat.ErrorMessage('Invalid game mode.');
|
||||
|
||||
room.scavgame = game;
|
||||
|
||||
|
|
@ -1113,7 +1113,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
end(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
if (!room.scavgame) return this.errorReply(`There is no scavenger game currently running.`);
|
||||
if (!room.scavgame) throw new Chat.ErrorMessage(`There is no scavenger game currently running.`);
|
||||
|
||||
this.privateModAction(`The ${room.scavgame.name} has been forcibly ended by ${user.name}.`);
|
||||
this.modlog('SCAVENGER', null, 'ended the scavenger game');
|
||||
|
|
@ -1124,10 +1124,10 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
kick(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
if (!room.scavgame) return this.errorReply(`There is no scavenger game currently running.`);
|
||||
if (!room.scavgame) throw new Chat.ErrorMessage(`There is no scavenger game currently running.`);
|
||||
|
||||
const targetId = toID(target);
|
||||
if (targetId === 'constructor' || !targetId) return this.errorReply("Invalid player.");
|
||||
if (targetId === 'constructor' || !targetId) throw new Chat.ErrorMessage("Invalid player.");
|
||||
|
||||
const success = room.scavgame.eliminate(targetId);
|
||||
if (success) {
|
||||
|
|
@ -1138,7 +1138,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
game.eliminate(targetId); // remove player from current hunt as well.
|
||||
}
|
||||
} else {
|
||||
this.errorReply(`Unable to kick user '${targetId}'.`);
|
||||
throw new Chat.ErrorMessage(`Unable to kick user '${targetId}'.`);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -1147,8 +1147,8 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
scoreboard: 'leaderboard',
|
||||
async leaderboard(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.scavgame) return this.errorReply(`There is no scavenger game currently running.`);
|
||||
if (!room.scavgame.leaderboard) return this.errorReply("This scavenger game does not have a leaderboard.");
|
||||
if (!room.scavgame) throw new Chat.ErrorMessage(`There is no scavenger game currently running.`);
|
||||
if (!room.scavgame.leaderboard) throw new Chat.ErrorMessage("This scavenger game does not have a leaderboard.");
|
||||
if (!this.runBroadcast()) return false;
|
||||
|
||||
const html = await room.scavgame.leaderboard.htmlLadder();
|
||||
|
|
@ -1157,8 +1157,8 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
|
||||
async rank(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!room.scavgame) return this.errorReply(`There is no scavenger game currently running.`);
|
||||
if (!room.scavgame.leaderboard) return this.errorReply("This scavenger game does not have a leaderboard.");
|
||||
if (!room.scavgame) throw new Chat.ErrorMessage(`There is no scavenger game currently running.`);
|
||||
if (!room.scavgame.leaderboard) throw new Chat.ErrorMessage("This scavenger game does not have a leaderboard.");
|
||||
if (!this.runBroadcast()) return false;
|
||||
|
||||
const targetId = toID(target) || user.id;
|
||||
|
|
@ -1177,18 +1177,18 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
createteam(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
// if (room.getGame(ScavengerHunt)) return this.errorReply('Teams cannot be modified after the hunt starts.');
|
||||
// if (room.getGame(ScavengerHunt)) throw new Chat.ErrorMessage('Teams cannot be modified after the hunt starts.');
|
||||
|
||||
const game = room.scavgame;
|
||||
if (!game || game.id !== 'teamscavs') return this.errorReply('There is currently no game of Team Scavs going on.');
|
||||
if (!game || game.id !== 'teamscavs') throw new Chat.ErrorMessage('There is currently no game of Team Scavs going on.');
|
||||
|
||||
let [teamName, leader] = target.split(',');
|
||||
teamName = teamName.trim();
|
||||
if (game.teams[teamName]) return this.errorReply(`The team ${teamName} already exists.`);
|
||||
if (game.teams[teamName]) throw new Chat.ErrorMessage(`The team ${teamName} already exists.`);
|
||||
|
||||
const leaderUser = Users.get(leader);
|
||||
if (!leaderUser) return this.errorReply('The user you specified is currently not online');
|
||||
if (game.getPlayerTeam(leaderUser)) return this.errorReply('The user is already a member of another team.');
|
||||
if (!leaderUser) throw new Chat.ErrorMessage('The user you specified is currently not online');
|
||||
if (game.getPlayerTeam(leaderUser)) throw new Chat.ErrorMessage('The user is already a member of another team.');
|
||||
|
||||
game.teams[teamName] = { name: teamName, answers: [], players: [leaderUser.id], question: 1, completed: false };
|
||||
game.announce(Utils.html`A new team "${teamName}" has been created with ${leaderUser.name} as the leader.`);
|
||||
|
|
@ -1198,12 +1198,12 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
removeteam(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
// if (room.getGame(ScavengerHunt)) return this.errorReply('Teams cannot be modified after the hunt starts.');
|
||||
// if (room.getGame(ScavengerHunt)) throw new Chat.ErrorMessage('Teams cannot be modified after the hunt starts.');
|
||||
|
||||
const game = room.scavgame;
|
||||
if (!game || game.id !== 'teamscavs') return this.errorReply('There is currently no game of Team Scavs going on.');
|
||||
if (!game || game.id !== 'teamscavs') throw new Chat.ErrorMessage('There is currently no game of Team Scavs going on.');
|
||||
|
||||
if (!game.teams[target]) return this.errorReply(`The team ${target} does not exist.`);
|
||||
if (!game.teams[target]) throw new Chat.ErrorMessage(`The team ${target} does not exist.`);
|
||||
|
||||
delete game.teams[target];
|
||||
game.announce(Utils.html`The team "${target}" has been removed.`);
|
||||
|
|
@ -1212,8 +1212,8 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
addplayer(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.scavgame;
|
||||
if (!game || game.id !== 'teamscavs') return this.errorReply('There is currently no game of Team Scavs going on.');
|
||||
// if (room.getGame(ScavengerHunt)) return this.errorReply('Teams cannot be modified after the hunt starts.');
|
||||
if (!game || game.id !== 'teamscavs') throw new Chat.ErrorMessage('There is currently no game of Team Scavs going on.');
|
||||
// if (room.getGame(ScavengerHunt)) throw new Chat.ErrorMessage('Teams cannot be modified after the hunt starts.');
|
||||
|
||||
let userTeam;
|
||||
|
||||
|
|
@ -1224,10 +1224,10 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!userTeam) return this.errorReply('You must be the leader of a team to add people into the team.');
|
||||
if (!userTeam) throw new Chat.ErrorMessage('You must be the leader of a team to add people into the team.');
|
||||
|
||||
const targetUsers = target.split(',').map(id => Users.getExact(id)).filter(u => u?.connected) as User[];
|
||||
if (!targetUsers.length) return this.errorReply('Please select a user that is currently online.');
|
||||
if (!targetUsers.length) throw new Chat.ErrorMessage('Please select a user that is currently online.');
|
||||
|
||||
const errors = [];
|
||||
for (const targetUser of targetUsers) {
|
||||
|
|
@ -1247,9 +1247,9 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
editplayers(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.scavgame;
|
||||
if (!game || game.id !== 'teamscavs') return this.errorReply('There is currently no game of Team Scavs going on.');
|
||||
if (!game || game.id !== 'teamscavs') throw new Chat.ErrorMessage('There is currently no game of Team Scavs going on.');
|
||||
this.checkCan('mute', null, room);
|
||||
// if (room.getGame(ScavengerHunt)) return this.errorReply('Teams cannot be modified after the hunt starts.');
|
||||
// if (room.getGame(ScavengerHunt)) throw new Chat.ErrorMessage('Teams cannot be modified after the hunt starts.');
|
||||
|
||||
const parts = target.split(',');
|
||||
const teamName = parts[0].trim();
|
||||
|
|
@ -1257,7 +1257,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
|
||||
const team = game.teams[teamName];
|
||||
|
||||
if (!team) return this.errorReply('Invalid team.');
|
||||
if (!team) throw new Chat.ErrorMessage('Invalid team.');
|
||||
|
||||
for (const entry of playerchanges) {
|
||||
const userid = toID(entry);
|
||||
|
|
@ -1298,7 +1298,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
|
||||
const game = room.scavgame;
|
||||
if (!game || game.id !== 'teamscavs') return this.errorReply('There is currently no game of Team Scavs going on.');
|
||||
if (!game || game.id !== 'teamscavs') throw new Chat.ErrorMessage('There is currently no game of Team Scavs going on.');
|
||||
|
||||
const display = [];
|
||||
for (const teamID in game.teams) {
|
||||
|
|
@ -1312,10 +1312,10 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
guesses(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.scavgame;
|
||||
if (!game || game.id !== 'teamscavs') return this.errorReply('There is currently no game of Team Scavs going on.');
|
||||
if (!game || game.id !== 'teamscavs') throw new Chat.ErrorMessage('There is currently no game of Team Scavs going on.');
|
||||
|
||||
const team = game.getPlayerTeam(user);
|
||||
if (!team) return this.errorReply('You are not currently part of this Team Scavs game.');
|
||||
if (!team) throw new Chat.ErrorMessage('You are not currently part of this Team Scavs game.');
|
||||
|
||||
this.sendReplyBox(Utils.html`<strong>Question #${team.question} guesses:</strong> ${team.answers.sort().join(', ')}`);
|
||||
},
|
||||
|
|
@ -1324,12 +1324,12 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
note(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.scavgame;
|
||||
if (!game || game.id !== 'teamscavs') return this.errorReply('There is currently no game of Team Scavs going on.');
|
||||
if (!game || game.id !== 'teamscavs') throw new Chat.ErrorMessage('There is currently no game of Team Scavs going on.');
|
||||
|
||||
const team = game.getPlayerTeam(user);
|
||||
if (!team) return this.errorReply('You are not currently part of this Team Scavs game.');
|
||||
if (!team) throw new Chat.ErrorMessage('You are not currently part of this Team Scavs game.');
|
||||
|
||||
if (!target) return this.errorReply('Please include a message as the note.');
|
||||
if (!target) throw new Chat.ErrorMessage('Please include a message as the note.');
|
||||
|
||||
game.teamAnnounce(user, Utils.html`<strong> Note from ${user.name}:</strong> ${target}`);
|
||||
},
|
||||
|
|
@ -1376,10 +1376,10 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
create(target, room, user, connection, cmd) {
|
||||
room = this.requireRoom();
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("Scavenger hunts can only be created in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("Scavenger hunts can only be created in the scavengers room.");
|
||||
}
|
||||
this.checkCan('mute', null, room);
|
||||
if (room.game) return this.errorReply(`There is already a game in this room - ${room.game.title}.`);
|
||||
if (room.game) throw new Chat.ErrorMessage(`There is already a game in this room - ${room.game.title}.`);
|
||||
let gameType = 'regular' as GameTypes;
|
||||
if (cmd.includes('practice')) {
|
||||
gameType = 'practice';
|
||||
|
|
@ -1409,18 +1409,18 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
!cmd.includes('force') && ['regular', 'unrated', 'recycled'].includes(gameType) && !mod &&
|
||||
room.settings.scavQueue?.length && !room.scavgame
|
||||
) {
|
||||
return this.errorReply(`There are currently hunts in the queue! If you would like to start the hunt anyways, use /forcestart${gameType === 'regular' ? 'hunt' : gameType}.`);
|
||||
throw new Chat.ErrorMessage(`There are currently hunts in the queue! If you would like to start the hunt anyways, use /forcestart${gameType === 'regular' ? 'hunt' : gameType}.`);
|
||||
}
|
||||
|
||||
if (gameType === 'recycled') {
|
||||
if (ScavengerHuntDatabase.isEmpty()) {
|
||||
return this.errorReply("There are no hunts in the database.");
|
||||
throw new Chat.ErrorMessage("There are no hunts in the database.");
|
||||
}
|
||||
|
||||
let hunt;
|
||||
if (questions) {
|
||||
const huntNumber = parseInt(questions);
|
||||
if (!ScavengerHuntDatabase.hasHunt(huntNumber)) return this.errorReply("You specified an invalid hunt number.");
|
||||
if (!ScavengerHuntDatabase.hasHunt(huntNumber)) throw new Chat.ErrorMessage("You specified an invalid hunt number.");
|
||||
hunt = scavengersData.recycledHunts[huntNumber - 1];
|
||||
} else {
|
||||
hunt = ScavengerHuntDatabase.getRecycledHuntFromDatabase();
|
||||
|
|
@ -1440,11 +1440,11 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
gameType === 'official' || gameType === 'recycled'
|
||||
);
|
||||
if (!hosts.length) {
|
||||
return this.errorReply("The user(s) you specified as the host is not online, or is not in the room.");
|
||||
throw new Chat.ErrorMessage("The user(s) you specified as the host is not online, or is not in the room.");
|
||||
}
|
||||
|
||||
const res = ScavengerHunt.parseQuestions(params);
|
||||
if (res.err) return this.errorReply(res.err);
|
||||
if (res.err) throw new Chat.ErrorMessage(res.err);
|
||||
|
||||
room.game = new ScavengerHunt({
|
||||
room,
|
||||
|
|
@ -1463,7 +1463,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
status(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
|
||||
const elapsedMsg = Chat.toDurationString(Date.now() - game.startTime, { hhmmss: true });
|
||||
const gameTypeMsg = game.gameType ? `<em>${game.gameType}</em> ` : '';
|
||||
|
|
@ -1508,15 +1508,15 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
hint(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game.onSendQuestion(user, true)) this.errorReply("You are not currently participating in the hunt.");
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
if (!game.onSendQuestion(user, true)) throw new Chat.ErrorMessage("You are not currently participating in the hunt.");
|
||||
},
|
||||
|
||||
timer(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
|
||||
const minutes = (toID(target) === 'off' ? 0 : parseFloat(target));
|
||||
if (isNaN(minutes) || minutes < 0 || (minutes * 60 * 1000) > Chat.MAX_TIMEOUT_DURATION) {
|
||||
|
|
@ -1535,9 +1535,9 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
|
||||
if (game.staffHostId === user.id) return this.errorReply('You already have staff permissions for this hunt.');
|
||||
if (game.staffHostId === user.id) throw new Chat.ErrorMessage('You already have staff permissions for this hunt.');
|
||||
|
||||
game.staffHostId = `${user.id}`;
|
||||
game.staffHostName = `${user.name}`;
|
||||
|
|
@ -1554,7 +1554,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
|
||||
game.onEnd(true, user);
|
||||
this.privateModAction(`${user.name} has reset the scavenger hunt.`);
|
||||
|
|
@ -1565,7 +1565,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
|
||||
const hunt: QueuedHunt = {
|
||||
hosts: game.hosts,
|
||||
|
|
@ -1592,16 +1592,16 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
this.checkCan('mute', null, room);
|
||||
if (!room.game && room.scavgame) return this.parse('/scav games end');
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
|
||||
const completed = game.preCompleted ? game.preCompleted : game.completed;
|
||||
|
||||
if (!this.cmd.includes('force')) {
|
||||
if (!completed.length) {
|
||||
return this.errorReply('No one has finished the hunt yet. Use /forceendhunt if you want to end the hunt and reveal the answers.');
|
||||
throw new Chat.ErrorMessage('No one has finished the hunt yet. Use /forceendhunt if you want to end the hunt and reveal the answers.');
|
||||
}
|
||||
} else if (completed.length) {
|
||||
return this.errorReply(`This hunt has ${Chat.count(completed, "finishers")}; use /endhunt`);
|
||||
throw new Chat.ErrorMessage(`This hunt has ${Chat.count(completed, "finishers")}; use /endhunt`);
|
||||
}
|
||||
|
||||
game.onEnd(false, user);
|
||||
|
|
@ -1612,9 +1612,9 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
viewhunt(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
|
||||
if (!('onViewHunt' in game)) return this.errorReply('There is currently no hunt to be viewed.');
|
||||
if (!('onViewHunt' in game)) throw new Chat.ErrorMessage('There is currently no hunt to be viewed.');
|
||||
|
||||
game.onViewHunt(user);
|
||||
},
|
||||
|
|
@ -1622,12 +1622,12 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
edithunt(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
if (
|
||||
(!game.hosts.some(h => h.id === user.id) || !user.can('show', null, room)) &&
|
||||
game.staffHostId !== user.id
|
||||
) {
|
||||
return this.errorReply("You cannot edit the hints and answers if you are not the host.");
|
||||
throw new Chat.ErrorMessage("You cannot edit the hints and answers if you are not the host.");
|
||||
}
|
||||
|
||||
const [question, type, ...value] = target.split(',');
|
||||
|
|
@ -1640,19 +1640,19 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
spoiler(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
if (
|
||||
(!game.hosts.some(h => h.id === user.id) || !user.can('show', null, room)) &&
|
||||
game.staffHostId !== user.id
|
||||
) {
|
||||
return this.errorReply("You cannot add more hints if you are not the host.");
|
||||
throw new Chat.ErrorMessage("You cannot add more hints if you are not the host.");
|
||||
}
|
||||
const parts = target.split(',');
|
||||
const question = parseInt(parts[0]) - 1;
|
||||
const hint = parts.slice(1).join(',');
|
||||
|
||||
if (!game.questions[question]) return this.errorReply(`Invalid question number.`);
|
||||
if (!hint) return this.errorReply('The hint cannot be left empty.');
|
||||
if (!game.questions[question]) throw new Chat.ErrorMessage(`Invalid question number.`);
|
||||
if (!hint) throw new Chat.ErrorMessage('The hint cannot be left empty.');
|
||||
game.questions[question].spoilers.push(hint);
|
||||
|
||||
room.addByUser(user, `Question #${question + 1} hint - spoiler: ${hint}`);
|
||||
|
|
@ -1669,20 +1669,20 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
removehint(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
if (
|
||||
(!game.hosts.some(h => h.id === user.id) || !user.can('show', null, room)) &&
|
||||
game.staffHostId !== user.id
|
||||
) {
|
||||
return this.errorReply("You cannot remove hints if you are not the host.");
|
||||
throw new Chat.ErrorMessage("You cannot remove hints if you are not the host.");
|
||||
}
|
||||
|
||||
const parts = target.split(',');
|
||||
const question = parseInt(parts[0]) - 1;
|
||||
const hint = parseInt(parts[1]) - 1;
|
||||
|
||||
if (!game.questions[question]) return this.errorReply(`Invalid question number.`);
|
||||
if (!game.questions[question].spoilers[hint]) return this.errorReply('Invalid hint number.');
|
||||
if (!game.questions[question]) throw new Chat.ErrorMessage(`Invalid question number.`);
|
||||
if (!game.questions[question].spoilers[hint]) throw new Chat.ErrorMessage('Invalid hint number.');
|
||||
game.questions[question].spoilers.splice(hint, 1);
|
||||
|
||||
return this.sendReply("Hint has been removed.");
|
||||
|
|
@ -1692,12 +1692,12 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
edithint(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
if (
|
||||
(!game.hosts.some(h => h.id === user.id) || !user.can('show', null, room)) &&
|
||||
game.staffHostId !== user.id
|
||||
) {
|
||||
return this.errorReply("You cannot edit hints if you are not the host.");
|
||||
throw new Chat.ErrorMessage("You cannot edit hints if you are not the host.");
|
||||
}
|
||||
|
||||
const parts = target.split(',');
|
||||
|
|
@ -1705,9 +1705,9 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
const hint = parseInt(parts[1]) - 1;
|
||||
const value = parts.slice(2).join(',');
|
||||
|
||||
if (!game.questions[question]) return this.errorReply(`Invalid question number.`);
|
||||
if (!game.questions[question].spoilers[hint]) return this.errorReply('Invalid hint number.');
|
||||
if (!value) return this.errorReply('The hint cannot be left empty.');
|
||||
if (!game.questions[question]) throw new Chat.ErrorMessage(`Invalid question number.`);
|
||||
if (!game.questions[question].spoilers[hint]) throw new Chat.ErrorMessage('Invalid hint number.');
|
||||
if (!value) throw new Chat.ErrorMessage('The hint cannot be left empty.');
|
||||
game.questions[question].spoilers[hint] = value;
|
||||
|
||||
room.addByUser(user, `Question #${question + 1} hint - spoiler: ${value}`);
|
||||
|
|
@ -1724,17 +1724,17 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
kick(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const game = room.getGame(ScavengerHunt);
|
||||
if (!game) return this.errorReply(`There is no scavenger hunt currently running.`);
|
||||
if (!game) throw new Chat.ErrorMessage(`There is no scavenger hunt currently running.`);
|
||||
|
||||
const targetId = toID(target);
|
||||
if (targetId === 'constructor' || !targetId) return this.errorReply("Invalid player.");
|
||||
if (targetId === 'constructor' || !targetId) throw new Chat.ErrorMessage("Invalid player.");
|
||||
|
||||
const success = game.eliminate(targetId);
|
||||
if (success) {
|
||||
this.modlog('SCAV KICK', targetId);
|
||||
return this.privateModAction(`${user.name} has kicked '${targetId}' from the scavenger hunt.`);
|
||||
}
|
||||
this.errorReply(`Unable to kick '${targetId}' from the scavenger hunt.`);
|
||||
throw new Chat.ErrorMessage(`Unable to kick '${targetId}' from the scavenger hunt.`);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -1758,7 +1758,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
queue(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
if (!target && this.cmd !== 'queuerecycled') {
|
||||
if (this.cmd === 'queue') {
|
||||
|
|
@ -1776,7 +1776,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
|
||||
if (this.cmd === 'queuerecycled') {
|
||||
if (ScavengerHuntDatabase.isEmpty()) {
|
||||
return this.errorReply(`There are no hunts in the database.`);
|
||||
throw new Chat.ErrorMessage(`There are no hunts in the database.`);
|
||||
}
|
||||
if (!room.settings.scavQueue) {
|
||||
room.settings.scavQueue = [];
|
||||
|
|
@ -1785,7 +1785,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
let next;
|
||||
if (target) {
|
||||
const huntNumber = parseInt(target);
|
||||
if (!ScavengerHuntDatabase.hasHunt(huntNumber)) return this.errorReply("You specified an invalid hunt number.");
|
||||
if (!ScavengerHuntDatabase.hasHunt(huntNumber)) throw new Chat.ErrorMessage("You specified an invalid hunt number.");
|
||||
next = scavengersData.recycledHunts[huntNumber - 1];
|
||||
} else {
|
||||
next = ScavengerHuntDatabase.getRecycledHuntFromDatabase();
|
||||
|
|
@ -1803,11 +1803,11 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
const [hostsArray, ...params] = target.split('|');
|
||||
const hosts = ScavengerHunt.parseHosts(hostsArray.split(/[,;]/), room);
|
||||
if (!hosts.length) {
|
||||
return this.errorReply("The user(s) you specified as the host is not online, or is not in the room.");
|
||||
throw new Chat.ErrorMessage("The user(s) you specified as the host is not online, or is not in the room.");
|
||||
}
|
||||
|
||||
const results = ScavengerHunt.parseQuestions(params, this.cmd.includes('force'));
|
||||
if (results.err) return this.errorReply(results.err);
|
||||
if (results.err) throw new Chat.ErrorMessage(results.err);
|
||||
|
||||
if (!room.settings.scavQueue) room.settings.scavQueue = [];
|
||||
|
||||
|
|
@ -1828,7 +1828,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
dequeue(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
this.checkCan('mute', null, room);
|
||||
const id = parseInt(target);
|
||||
|
|
@ -1846,7 +1846,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
viewqueue(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
if (!this.runBroadcast()) return false;
|
||||
|
||||
|
|
@ -1856,14 +1856,14 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
next(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
this.checkCan('mute', null, room);
|
||||
|
||||
if (!room.settings.scavQueue?.length) {
|
||||
return this.errorReply("The scavenger hunt queue is currently empty.");
|
||||
throw new Chat.ErrorMessage("The scavenger hunt queue is currently empty.");
|
||||
}
|
||||
if (room.game) return this.errorReply(`There is already a game in this room - ${room.game.title}.`);
|
||||
if (room.game) throw new Chat.ErrorMessage(`There is already a game in this room - ${room.game.title}.`);
|
||||
|
||||
const huntId = parseInt(target) || 0;
|
||||
|
||||
|
|
@ -1892,14 +1892,14 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
disablequeue(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
this.checkCan('mute', null, room);
|
||||
|
||||
if (!room.settings.scavSettings) room.settings.scavSettings = {};
|
||||
const state = this.cmd === 'disablequeue';
|
||||
if ((room.settings.scavSettings.scavQueueDisabled || false) === state) {
|
||||
return this.errorReply(`The queue is already ${state ? 'disabled' : 'enabled'}.`);
|
||||
throw new Chat.ErrorMessage(`The queue is already ${state ? 'disabled' : 'enabled'}.`);
|
||||
}
|
||||
|
||||
room.settings.scavSettings.scavQueueDisabled = state;
|
||||
|
|
@ -1913,7 +1913,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
defaulttimer(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
this.checkCan('declare', null, room);
|
||||
|
||||
|
|
@ -1925,7 +1925,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
const duration = parseInt(target);
|
||||
|
||||
if (!duration || duration < 0) {
|
||||
return this.errorReply('The default timer must be an integer greater than zero, in minutes.');
|
||||
throw new Chat.ErrorMessage('The default timer must be an integer greater than zero, in minutes.');
|
||||
}
|
||||
|
||||
room.settings.scavSettings.defaultScavTimer = duration;
|
||||
|
|
@ -1945,8 +1945,10 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
const targetId = toID(parts[0]);
|
||||
const points = parseInt(parts[1]);
|
||||
|
||||
if (!targetId || targetId === 'constructor' || targetId.length > 18) return this.errorReply("Invalid username.");
|
||||
if (!points || points < 0 || points > 1000) return this.errorReply("Points must be an integer between 1 and 1000.");
|
||||
if (!targetId || targetId === 'constructor' || targetId.length > 18) throw new Chat.ErrorMessage("Invalid username.");
|
||||
if (!points || points < 0 || points > 1000) {
|
||||
throw new Chat.ErrorMessage("Points must be an integer between 1 and 1000.");
|
||||
}
|
||||
|
||||
Leaderboard.addPoints(targetId, 'points', points, true).write();
|
||||
|
||||
|
|
@ -1962,8 +1964,10 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
const targetId = toID(parts[0]);
|
||||
const points = parseInt(parts[1]);
|
||||
|
||||
if (!targetId || targetId === 'constructor' || targetId.length > 18) return this.errorReply("Invalid username.");
|
||||
if (!points || points < 0 || points > 1000) return this.errorReply("Points must be an integer between 1 and 1000.");
|
||||
if (!targetId || targetId === 'constructor' || targetId.length > 18) throw new Chat.ErrorMessage("Invalid username.");
|
||||
if (!points || points < 0 || points > 1000) {
|
||||
throw new Chat.ErrorMessage("Points must be an integer between 1 and 1000.");
|
||||
}
|
||||
|
||||
Leaderboard.addPoints(targetId, 'points', -points, true).write();
|
||||
|
||||
|
|
@ -1984,7 +1988,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
async ladder(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
if (!this.runBroadcast()) return false;
|
||||
|
||||
|
|
@ -2010,7 +2014,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
async rank(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
if (!this.runBroadcast()) return false;
|
||||
|
||||
|
|
@ -2031,7 +2035,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const scavsRoom = getScavsRoom(room);
|
||||
if (!scavsRoom) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
this.checkCan('mute', null, room); // perms for viewing only
|
||||
|
||||
|
|
@ -2050,10 +2054,10 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
const parts = target.split(',');
|
||||
const blitzPoints = parseInt(parts[1]);
|
||||
const gameType = toID(parts[0]) as GameTypes;
|
||||
if (!RATED_TYPES.includes(gameType)) return this.errorReply(`You cannot set blitz points for ${gameType} hunts.`);
|
||||
if (!RATED_TYPES.includes(gameType)) throw new Chat.ErrorMessage(`You cannot set blitz points for ${gameType} hunts.`);
|
||||
|
||||
if (isNaN(blitzPoints) || blitzPoints < 0 || blitzPoints > 1000) {
|
||||
return this.errorReply("The points value awarded for blitz must be an integer bewteen 0 and 1000.");
|
||||
throw new Chat.ErrorMessage("The points value awarded for blitz must be an integer bewteen 0 and 1000.");
|
||||
}
|
||||
if (!room.settings.scavSettings.blitzPoints) room.settings.scavSettings.blitzPoints = {};
|
||||
room.settings.scavSettings.blitzPoints[gameType] = blitzPoints;
|
||||
|
|
@ -2078,7 +2082,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const scavsRoom = getScavsRoom(room);
|
||||
if (!scavsRoom) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
this.checkCan('mute', null, room); // perms for viewing only
|
||||
if (!room.settings.scavSettings) room.settings.scavSettings = {};
|
||||
|
|
@ -2090,7 +2094,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
|
||||
this.checkCan('declare', null, room); // perms for editting
|
||||
const points = parseInt(target);
|
||||
if (isNaN(points)) return this.errorReply(`${target} is not a valid number of points.`);
|
||||
if (isNaN(points)) throw new Chat.ErrorMessage(`${target} is not a valid number of points.`);
|
||||
|
||||
room.settings.scavSettings.hostPoints = points;
|
||||
room.saveSettings();
|
||||
|
|
@ -2112,7 +2116,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const scavsRoom = getScavsRoom(room);
|
||||
if (!scavsRoom) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
this.checkCan('mute', null, room); // perms for viewing only
|
||||
if (!room.settings.scavSettings) room.settings.scavSettings = {};
|
||||
|
|
@ -2133,11 +2137,11 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
|
||||
let [type, ...pointsSet] = target.split(',');
|
||||
type = toID(type) as GameTypes;
|
||||
if (!RATED_TYPES.includes(type)) return this.errorReply(`You cannot set win points for ${type} hunts.`);
|
||||
if (!RATED_TYPES.includes(type)) throw new Chat.ErrorMessage(`You cannot set win points for ${type} hunts.`);
|
||||
const winPoints = pointsSet.map(p => parseInt(p));
|
||||
|
||||
if (winPoints.some(p => isNaN(p) || p < 0 || p > 1000) || !winPoints.length) {
|
||||
return this.errorReply("The points value awarded for winning a scavenger hunt must be an integer between 0 and 1000.");
|
||||
throw new Chat.ErrorMessage("The points value awarded for winning a scavenger hunt must be an integer between 0 and 1000.");
|
||||
}
|
||||
|
||||
if (!room.settings.scavSettings.winPoints) room.settings.scavSettings.winPoints = {};
|
||||
|
|
@ -2165,7 +2169,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const scavsRoom = getScavsRoom(room);
|
||||
if (!scavsRoom) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
if (this.cmd.includes('reset')) target = 'RESET';
|
||||
|
||||
|
|
@ -2179,7 +2183,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
room.settings.scavSettings.officialtwist = null;
|
||||
} else {
|
||||
const twist = toID(target);
|
||||
if (!ScavMods.twists[twist] || twist === 'constructor') return this.errorReply('Invalid twist.');
|
||||
if (!ScavMods.twists[twist] || twist === 'constructor') throw new Chat.ErrorMessage('Invalid twist.');
|
||||
|
||||
room.settings.scavSettings.officialtwist = twist;
|
||||
room.saveSettings();
|
||||
|
|
@ -2212,7 +2216,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
twists(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
this.checkCan('mute', null, room);
|
||||
if (!this.runBroadcast()) return false;
|
||||
|
|
@ -2335,7 +2339,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
this.checkCan('mute', null, room);
|
||||
|
||||
const targetId = toID(target);
|
||||
if (!targetId) return this.errorReply(`Please include the name of the user to ${this.cmd}.`);
|
||||
if (!targetId) throw new Chat.ErrorMessage(`Please include the name of the user to ${this.cmd}.`);
|
||||
const change = this.cmd === 'infract' ? 1 : -1;
|
||||
|
||||
PlayerLeaderboard.addPoints(targetId, 'infraction', change, true).write();
|
||||
|
|
@ -2393,7 +2397,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('mute', null, room);
|
||||
if (!getScavsRoom(room)) {
|
||||
return this.errorReply("Scavenger Hunts can only be added to the database in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("Scavenger Hunts can only be added to the database in the scavengers room.");
|
||||
}
|
||||
|
||||
let cmd;
|
||||
|
|
@ -2405,23 +2409,23 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
}
|
||||
|
||||
if (cmd === 'addhunt') {
|
||||
if (!target) return this.errorReply(`Usage: ${cmd} Hunt Text`);
|
||||
if (!target) throw new Chat.ErrorMessage(`Usage: ${cmd} Hunt Text`);
|
||||
|
||||
const [hostsArray, ...questions] = target.split('|');
|
||||
const hosts = ScavengerHunt.parseHosts(hostsArray.split(/[,;]/), room, true);
|
||||
if (!hosts.length) {
|
||||
return this.errorReply("You need to specify a host.");
|
||||
throw new Chat.ErrorMessage("You need to specify a host.");
|
||||
}
|
||||
|
||||
const result = ScavengerHunt.parseQuestions(questions);
|
||||
if (result.err) return this.errorReply(result.err);
|
||||
if (result.err) throw new Chat.ErrorMessage(result.err);
|
||||
|
||||
ScavengerHuntDatabase.addRecycledHuntToDatabase(hosts, result.result);
|
||||
return this.privateModAction(`A recycled hunt has been added to the database.`);
|
||||
}
|
||||
|
||||
// The rest of the commands depend on there already being hunts in the database.
|
||||
if (ScavengerHuntDatabase.isEmpty()) return this.errorReply("There are no hunts in the database.");
|
||||
if (ScavengerHuntDatabase.isEmpty()) throw new Chat.ErrorMessage("There are no hunts in the database.");
|
||||
|
||||
if (cmd === 'list') {
|
||||
return this.parse(`/join view-recycledHunts-${room}`);
|
||||
|
|
@ -2435,7 +2439,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
'removehint': 'Usage: removehint hunt number, question number, hint text',
|
||||
'autostart': 'Usage: autostart on/off',
|
||||
};
|
||||
if (!params) return this.errorReply(usageMessages[cmd]);
|
||||
if (!params) throw new Chat.ErrorMessage(usageMessages[cmd]);
|
||||
|
||||
const numberOfRequiredParameters: { [k: string]: number } = {
|
||||
'removehunt': 1,
|
||||
|
|
@ -2443,12 +2447,12 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
'removehint': 3,
|
||||
'autostart': 1,
|
||||
};
|
||||
if (params.length < numberOfRequiredParameters[cmd]) return this.errorReply(usageMessages[cmd]);
|
||||
if (params.length < numberOfRequiredParameters[cmd]) throw new Chat.ErrorMessage(usageMessages[cmd]);
|
||||
|
||||
const [huntNumber, questionNumber, hintNumber] = params.map(param => parseInt(param));
|
||||
const cmdsNeedingHuntNumber = ['removehunt', 'removehint', 'addhint'];
|
||||
if (cmdsNeedingHuntNumber.includes(cmd)) {
|
||||
if (!ScavengerHuntDatabase.hasHunt(huntNumber)) return this.errorReply("You specified an invalid hunt number.");
|
||||
if (!ScavengerHuntDatabase.hasHunt(huntNumber)) throw new Chat.ErrorMessage("You specified an invalid hunt number.");
|
||||
}
|
||||
|
||||
const cmdsNeedingQuestionNumber = ['addhint', 'removehint'];
|
||||
|
|
@ -2458,7 +2462,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
questionNumber <= 0 ||
|
||||
questionNumber > scavengersData.recycledHunts[huntNumber - 1].questions.length
|
||||
) {
|
||||
return this.errorReply("You specified an invalid question number.");
|
||||
throw new Chat.ErrorMessage("You specified an invalid question number.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2466,7 +2470,7 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
if (cmdsNeedingHintNumber.includes(cmd)) {
|
||||
const numQuestions = scavengersData.recycledHunts[huntNumber - 1].questions.length;
|
||||
if (isNaN(questionNumber) || questionNumber <= 0 || questionNumber > numQuestions) {
|
||||
return this.errorReply("You specified an invalid hint number.");
|
||||
throw new Chat.ErrorMessage("You specified an invalid hint number.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2482,9 +2486,9 @@ const ScavengerCommands: Chat.ChatCommands = {
|
|||
return this.privateModAction(`Hint #${hintNumber} was removed from Recycled hunt #${huntNumber} question #${questionNumber}.`);
|
||||
} else if (cmd === 'autostart') {
|
||||
if (!room.settings.scavSettings) room.settings.scavSettings = {};
|
||||
if (params[0] !== 'on' && params[0] !== 'off') return this.errorReply(usageMessages[cmd]);
|
||||
if (params[0] !== 'on' && params[0] !== 'off') throw new Chat.ErrorMessage(usageMessages[cmd]);
|
||||
if ((params[0] === 'on') === !!room.settings.scavSettings.addRecycledHuntsToQueueAutomatically) {
|
||||
return this.errorReply(`Autostarting recycled hunts is already ${room.settings.scavSettings.addRecycledHuntsToQueueAutomatically ? 'on' : 'off'}.`);
|
||||
throw new Chat.ErrorMessage(`Autostarting recycled hunts is already ${room.settings.scavSettings.addRecycledHuntsToQueueAutomatically ? 'on' : 'off'}.`);
|
||||
}
|
||||
room.settings.scavSettings.addRecycledHuntsToQueueAutomatically =
|
||||
!room.settings.scavSettings.addRecycledHuntsToQueueAutomatically;
|
||||
|
|
@ -2632,7 +2636,7 @@ export const commands: Chat.ChatCommands = {
|
|||
scavhelp: 'scavengershelp',
|
||||
scavengershelp(target, room, user) {
|
||||
if (!room || !getScavsRoom(room)) {
|
||||
return this.errorReply("This command can only be used in the scavengers room.");
|
||||
throw new Chat.ErrorMessage("This command can only be used in the scavengers room.");
|
||||
}
|
||||
if (!this.runBroadcast()) return false;
|
||||
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ export const pages: Chat.PageTable = {
|
|||
const format = toID(query.shift());
|
||||
const season = toID(query.shift()) || `${data.current.season}`;
|
||||
if (!data.badgeholders[season]) {
|
||||
return this.errorReply(`Season ${season} not found.`);
|
||||
throw new Chat.ErrorMessage(`Season ${season} not found.`);
|
||||
}
|
||||
this.title = `[Seasons]`;
|
||||
let buf = '<div class="pad">';
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const section = tours[sectionID];
|
||||
if (!section) {
|
||||
return this.errorReply(`Invalid section ID: "${sectionID}"`);
|
||||
return this.popupReply(`Invalid section ID: "${sectionID}"`);
|
||||
}
|
||||
if (!isEdit && section.tours.find(f => toID(title) === f.id)) {
|
||||
return this.popupReply(`A tour with that ID already exists. Please choose another.`);
|
||||
|
|
@ -152,7 +152,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (rawCredit || rawArtistName) { // if one exists, both should, as verified above
|
||||
const artistUrl = (Chat.linkRegex.exec(rawCredit))?.[0];
|
||||
if (!artistUrl) {
|
||||
return this.errorReply(`Invalid artist credit URL.`);
|
||||
return this.popupReply(`Invalid artist credit URL.`);
|
||||
}
|
||||
artistCredit = { url: artistUrl, name: rawArtistName.trim() };
|
||||
}
|
||||
|
|
@ -205,10 +205,10 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const section = tours[sectionID];
|
||||
if (!section) {
|
||||
return this.errorReply(`Invalid section ID: "${sectionID}". Valid IDs: ${Object.keys(tours).join(', ')}`);
|
||||
throw new Chat.ErrorMessage(`Invalid section ID: "${sectionID}". Valid IDs: ${Object.keys(tours).join(', ')}`);
|
||||
}
|
||||
if (section.whitelist?.includes(targetID)) {
|
||||
return this.errorReply(`That user is already whitelisted on that section.`);
|
||||
throw new Chat.ErrorMessage(`That user is already whitelisted on that section.`);
|
||||
}
|
||||
if (!section.whitelist) section.whitelist = [];
|
||||
section.whitelist.push(targetID);
|
||||
|
|
@ -226,11 +226,11 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const section = tours[sectionID];
|
||||
if (!section) {
|
||||
return this.errorReply(`Invalid section ID: "${sectionID}". Valid IDs: ${Object.keys(tours).join(', ')}`);
|
||||
throw new Chat.ErrorMessage(`Invalid section ID: "${sectionID}". Valid IDs: ${Object.keys(tours).join(', ')}`);
|
||||
}
|
||||
const idx = section.whitelist?.indexOf(targetID) ?? -1;
|
||||
if (!section.whitelist || idx < 0) {
|
||||
return this.errorReply(`${targetID} is not whitelisted in that section.`);
|
||||
throw new Chat.ErrorMessage(`${targetID} is not whitelisted in that section.`);
|
||||
}
|
||||
section.whitelist.splice(idx, 1);
|
||||
if (!section.whitelist.length) {
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const reqData: Record<string, number> = {};
|
||||
if (!reqs.length) {
|
||||
return this.errorReply("At least one requirement for qualifying must be provided.");
|
||||
throw new Chat.ErrorMessage("At least one requirement for qualifying must be provided.");
|
||||
}
|
||||
for (const req of reqs) {
|
||||
let [k, v] = req.split('=');
|
||||
|
|
@ -88,17 +88,17 @@ export const commands: Chat.ChatCommands = {
|
|||
continue;
|
||||
}
|
||||
if (!['elo', 'gxe', 'coil'].includes(k)) {
|
||||
return this.errorReply(`Invalid requirement type: ${k}. Must be 'coil', 'gxe', or 'elo'.`);
|
||||
throw new Chat.ErrorMessage(`Invalid requirement type: ${k}. Must be 'coil', 'gxe', or 'elo'.`);
|
||||
}
|
||||
if (k === 'coil' && !reqs.some(x => toID(x).startsWith('b'))) {
|
||||
throw new Chat.ErrorMessage("COIL reqs are specified, but you have not provided a B value (with the argument `b=num`)");
|
||||
}
|
||||
const val = Number(v);
|
||||
if (isNaN(val) || val < 0) {
|
||||
return this.errorReply(`Invalid value: ${v}`);
|
||||
throw new Chat.ErrorMessage(`Invalid value: ${v}`);
|
||||
}
|
||||
if (reqData[k]) {
|
||||
return this.errorReply(`Requirement type ${k} specified twice.`);
|
||||
throw new Chat.ErrorMessage(`Requirement type ${k} specified twice.`);
|
||||
}
|
||||
reqData[k] = val;
|
||||
}
|
||||
|
|
@ -131,7 +131,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const format = toID(target);
|
||||
const test = suspectTests.suspects[format];
|
||||
if (!test) return this.errorReply(`There is no suspect test for '${target}'. Check spelling?`);
|
||||
if (!test) throw new Chat.ErrorMessage(`There is no suspect test for '${target}'. Check spelling?`);
|
||||
|
||||
const [out, error] = await LoginServer.request('suspects/end', {
|
||||
format,
|
||||
|
|
|
|||
|
|
@ -458,7 +458,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const teamData = await TeamsHandler.get(teamid);
|
||||
if (!teamData) return this.popupReply(`Team not found.`);
|
||||
if (teamData.ownerid !== user.id && !user.can('rangeban')) {
|
||||
return this.errorReply("You cannot delete teams you do not own.");
|
||||
throw new Chat.ErrorMessage("You cannot delete teams you do not own.");
|
||||
}
|
||||
await TeamsHandler.delete(teamid);
|
||||
this.popupReply(`Team ${teamid} deleted.`);
|
||||
|
|
@ -598,11 +598,11 @@ export const pages: Chat.PageTable = {
|
|||
const team = await TeamsHandler.get(teamid);
|
||||
if (!team) {
|
||||
this.title = `[Invalid Team]`;
|
||||
return this.errorReply(`No team with the ID ${teamid} was found.`);
|
||||
throw new Chat.ErrorMessage(`No team with the ID ${teamid} was found.`);
|
||||
}
|
||||
if (team?.private && user.id !== team.ownerid && password !== team.private) {
|
||||
this.title = `[Private Team]`;
|
||||
return this.errorReply(`That team is private.`);
|
||||
throw new Chat.ErrorMessage(`That team is private.`);
|
||||
}
|
||||
this.title = `[Team] ${team.teamid}`;
|
||||
if (user.id !== team.ownerid && team.views >= 0) {
|
||||
|
|
@ -639,12 +639,12 @@ export const pages: Chat.PageTable = {
|
|||
TeamsHandler.validateAccess(connection);
|
||||
const teamID = toID(query.shift() || "");
|
||||
if (!teamID.length) {
|
||||
return this.errorReply(`Invalid team ID.`);
|
||||
throw new Chat.ErrorMessage(`Invalid team ID.`);
|
||||
}
|
||||
this.title = `[Edit Team] ${teamID}`;
|
||||
const data = await TeamsHandler.get(teamID);
|
||||
if (!data) {
|
||||
return this.errorReply(`Team ${teamID} not found.`);
|
||||
throw new Chat.ErrorMessage(`Team ${teamID} not found.`);
|
||||
}
|
||||
let buf = `<div class="ladder pad"><h2>Edit team ${teamID}</h2>${refresh(this)}<hr />`;
|
||||
// let [teamName, formatid, rawPrivacy, rawTeam] = Utils.splitFirst(target, ',', 4);
|
||||
|
|
@ -702,15 +702,15 @@ export const pages: Chat.PageTable = {
|
|||
const [rawOwner, rawFormat, rawPokemon, rawMoves, rawAbilities, rawGen] = query;
|
||||
const owner = toID(rawOwner);
|
||||
if (owner.length > 18) {
|
||||
return this.errorReply(`Invalid owner name. Names must be under 18 characters long.`);
|
||||
throw new Chat.ErrorMessage(`Invalid owner name. Names must be under 18 characters long.`);
|
||||
}
|
||||
const format = toID(rawFormat);
|
||||
if (format && !Dex.formats.get(format).exists) {
|
||||
return this.errorReply(`Format ${format} not found.`);
|
||||
throw new Chat.ErrorMessage(`Format ${format} not found.`);
|
||||
}
|
||||
const gen = Number(rawGen);
|
||||
if (rawGen && (isNaN(gen) || (gen < 1 || gen > Dex.gen))) {
|
||||
return this.errorReply(`Invalid generation: '${rawGen}'`);
|
||||
throw new Chat.ErrorMessage(`Invalid generation: '${rawGen}'`);
|
||||
}
|
||||
|
||||
const pokemon = rawPokemon?.split(',').map(toID).filter(Boolean);
|
||||
|
|
@ -764,7 +764,7 @@ export const pages: Chat.PageTable = {
|
|||
queryStr += ` ORDER BY date DESC`;
|
||||
break;
|
||||
default:
|
||||
return this.errorReply(`Invalid sort term '${sorter}'. Must be either 'views' or 'latest'.`);
|
||||
throw new Chat.ErrorMessage(`Invalid sort term '${sorter}'. Must be either 'views' or 'latest'.`);
|
||||
}
|
||||
queryStr += ` LIMIT ${count}`;
|
||||
let buf = `<div class="pad"><h2>Browse ${name} teams</h2>`;
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
async lastfm(target, room, user) {
|
||||
this.checkChat();
|
||||
if (!user.autoconfirmed) return this.errorReply(`You cannot use this command while not autoconfirmed.`);
|
||||
if (!user.autoconfirmed) throw new Chat.ErrorMessage(`You cannot use this command while not autoconfirmed.`);
|
||||
this.runBroadcast(true);
|
||||
const targetUsername = this.splitUser(target).targetUsername || (user.named ? user.name : '');
|
||||
const username = LastFM.getAccountName(targetUsername);
|
||||
|
|
@ -484,7 +484,7 @@ export const commands: Chat.ChatCommands = {
|
|||
async track(target, room, user) {
|
||||
if (!target) return this.parse('/help track');
|
||||
this.checkChat();
|
||||
if (!user.autoconfirmed) return this.errorReply(`You cannot use this command while not autoconfirmed.`);
|
||||
if (!user.autoconfirmed) throw new Chat.ErrorMessage(`You cannot use this command while not autoconfirmed.`);
|
||||
const [track, artist] = this.splitOne(target);
|
||||
if (!track) return this.parse('/help track');
|
||||
this.runBroadcast(true);
|
||||
|
|
@ -541,7 +541,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse('/help suggestrecommendation');
|
||||
}
|
||||
this.checkChat(target);
|
||||
if (!user.autoconfirmed) return this.errorReply(`You cannot use this command while not autoconfirmed.`);
|
||||
if (!user.autoconfirmed) throw new Chat.ErrorMessage(`You cannot use this command while not autoconfirmed.`);
|
||||
const [artist, title, url, description, ...tags] = target.split('|').map(x => x.trim());
|
||||
if (!(artist && title && url && description && tags?.length)) {
|
||||
return this.parse(`/help suggestrecommendation`);
|
||||
|
|
|
|||
|
|
@ -502,14 +502,12 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
|
||||
const handler = selectHandler(this.message);
|
||||
|
||||
if (!handler.room) return this.errorReply(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) return this.errorReply(`This command can only be used in ${handler.room.title}.`);
|
||||
if (!handler.room) throw new Chat.ErrorMessage(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) throw new Chat.ErrorMessage(`This command can only be used in ${handler.room.title}.`);
|
||||
this.checkCan('mute', null, room);
|
||||
|
||||
if (handler.voting) {
|
||||
return this.errorReply(
|
||||
`The nomination for the ${handler.name} of the ${handler.timeLabel} nomination is already in progress.`
|
||||
);
|
||||
throw new Chat.ErrorMessage(`The nomination for the ${handler.name} of the ${handler.timeLabel} nomination is already in progress.`);
|
||||
}
|
||||
handler.startVote();
|
||||
|
||||
|
|
@ -523,15 +521,15 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
|
||||
const handler = selectHandler(this.message);
|
||||
|
||||
if (!handler.room) return this.errorReply(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) return this.errorReply(`This command can only be used in ${handler.room.title}.`);
|
||||
if (!handler.room) throw new Chat.ErrorMessage(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) throw new Chat.ErrorMessage(`This command can only be used in ${handler.room.title}.`);
|
||||
this.checkCan('mute', null, room);
|
||||
|
||||
if (!handler.voting) {
|
||||
return this.errorReply(`There is no ${handler.name} of the ${handler.timeLabel} nomination in progress.`);
|
||||
throw new Chat.ErrorMessage(`There is no ${handler.name} of the ${handler.timeLabel} nomination in progress.`);
|
||||
}
|
||||
if (!handler.nominations.size) {
|
||||
return this.errorReply(`Can't select the ${handler.name} of the ${handler.timeLabel} without nominations.`);
|
||||
throw new Chat.ErrorMessage(`Can't select the ${handler.name} of the ${handler.timeLabel} without nominations.`);
|
||||
}
|
||||
handler.rollWinner();
|
||||
|
||||
|
|
@ -548,8 +546,8 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
|
||||
const handler = selectHandler(this.message);
|
||||
|
||||
if (!handler.room) return this.errorReply(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) return this.errorReply(`This command can only be used in ${handler.room.title}.`);
|
||||
if (!handler.room) throw new Chat.ErrorMessage(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) throw new Chat.ErrorMessage(`This command can only be used in ${handler.room.title}.`);
|
||||
|
||||
if (!toNominationId(target).length || target.length > 75) {
|
||||
return this.sendReply(`'${target}' is not a valid ${handler.name.toLowerCase()} name.`);
|
||||
|
|
@ -564,8 +562,8 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
|
||||
const handler = selectHandler(this.message);
|
||||
|
||||
if (!handler.room) return this.errorReply(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) return this.errorReply(`This command can only be used in ${handler.room.title}.`);
|
||||
if (!handler.room) throw new Chat.ErrorMessage(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) throw new Chat.ErrorMessage(`This command can only be used in ${handler.room.title}.`);
|
||||
|
||||
if (this.broadcasting) {
|
||||
selectHandler(this.message).display();
|
||||
|
|
@ -580,12 +578,12 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
|
||||
const handler = selectHandler(this.message);
|
||||
|
||||
if (!handler.room) return this.errorReply(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) return this.errorReply(`This command can only be used in ${handler.room.title}.`);
|
||||
if (!handler.room) throw new Chat.ErrorMessage(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) throw new Chat.ErrorMessage(`This command can only be used in ${handler.room.title}.`);
|
||||
this.checkCan('mute', null, room);
|
||||
|
||||
const userid = toID(target);
|
||||
if (!userid) return this.errorReply(`'${target}' is not a valid username.`);
|
||||
if (!userid) throw new Chat.ErrorMessage(`'${target}' is not a valid username.`);
|
||||
|
||||
if (handler.removeNomination(userid)) {
|
||||
this.privateModAction(`${user.name} removed ${target}'s nomination for the ${handler.name} of the ${handler.timeLabel}.`);
|
||||
|
|
@ -622,8 +620,8 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
|
||||
const handler = selectHandler(this.message);
|
||||
|
||||
if (!handler.room) return this.errorReply(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) return this.errorReply(`This command can only be used in ${handler.room.title}.`);
|
||||
if (!handler.room) throw new Chat.ErrorMessage(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) throw new Chat.ErrorMessage(`This command can only be used in ${handler.room.title}.`);
|
||||
this.checkCan('declare', null, room);
|
||||
|
||||
if (!toNominationId(target).length || target.length > 50) {
|
||||
|
|
@ -643,12 +641,12 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
|
||||
const handler = selectHandler(this.message);
|
||||
|
||||
if (!handler.room) return this.errorReply(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) return this.errorReply(`This command can only be used in ${handler.room.title}.`);
|
||||
if (!handler.room) throw new Chat.ErrorMessage(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) throw new Chat.ErrorMessage(`This command can only be used in ${handler.room.title}.`);
|
||||
this.checkCan('mute', null, room);
|
||||
|
||||
if (!(handler.voting && handler.timer)) {
|
||||
return this.errorReply(`There is no ${handler.name} of the ${handler.timeLabel} nomination to disable the timer for.`);
|
||||
throw new Chat.ErrorMessage(`There is no ${handler.name} of the ${handler.timeLabel} nomination to disable the timer for.`);
|
||||
}
|
||||
clearTimeout(handler.timer);
|
||||
|
||||
|
|
@ -663,8 +661,8 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
|
||||
const handler = selectHandler(this.message);
|
||||
|
||||
if (!handler.room) return this.errorReply(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) return this.errorReply(`This command can only be used in ${handler.room.title}.`);
|
||||
if (!handler.room) throw new Chat.ErrorMessage(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) throw new Chat.ErrorMessage(`This command can only be used in ${handler.room.title}.`);
|
||||
this.checkCan('mute', null, room);
|
||||
|
||||
const params = target.split(target.includes('|') ? '|' : ',').map(param => param.trim());
|
||||
|
|
@ -673,13 +671,13 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
|
||||
for (const param of params) {
|
||||
let [key, ...values] = param.split(':');
|
||||
if (!key || !values.length) return this.errorReply(`Syntax error in '${param}'`);
|
||||
if (!key || !values.length) throw new Chat.ErrorMessage(`Syntax error in '${param}'`);
|
||||
|
||||
key = key.trim();
|
||||
const value = values.join(':').trim();
|
||||
|
||||
if (!handler.keys.includes(key)) {
|
||||
return this.errorReply(`Invalid key: '${key}'. Valid keys: ${handler.keys.join(', ')}`);
|
||||
throw new Chat.ErrorMessage(`Invalid key: '${key}'. Valid keys: ${handler.keys.join(', ')}`);
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
|
|
@ -690,38 +688,38 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
case 'book':
|
||||
case 'author':
|
||||
case 'athlete':
|
||||
if (!toNominationId(value) || value.length > 50) return this.errorReply(`Please enter a valid ${key} name.`);
|
||||
if (!toNominationId(value) || value.length > 50) throw new Chat.ErrorMessage(`Please enter a valid ${key} name.`);
|
||||
break;
|
||||
case 'quote':
|
||||
case 'tagline':
|
||||
case 'match':
|
||||
case 'event':
|
||||
case 'videogame':
|
||||
if (!value.length || value.length > 150) return this.errorReply(`Please enter a valid ${key}.`);
|
||||
if (!value.length || value.length > 150) throw new Chat.ErrorMessage(`Please enter a valid ${key}.`);
|
||||
break;
|
||||
case 'sport':
|
||||
case 'team':
|
||||
case 'song':
|
||||
case 'country':
|
||||
if (!value.length || value.length > 50) return this.errorReply(`Please enter a valid ${key} name.`);
|
||||
if (!value.length || value.length > 50) throw new Chat.ErrorMessage(`Please enter a valid ${key} name.`);
|
||||
break;
|
||||
case 'link':
|
||||
case 'image':
|
||||
if (!/https?:\/\//.test(value)) {
|
||||
return this.errorReply(`Please enter a valid URL for the ${key} (starting with http:// or https://)`);
|
||||
throw new Chat.ErrorMessage(`Please enter a valid URL for the ${key} (starting with http:// or https://)`);
|
||||
}
|
||||
if (value.length > 200) return this.errorReply("URL too long.");
|
||||
if (value.length > 200) throw new Chat.ErrorMessage("URL too long.");
|
||||
break;
|
||||
case 'age':
|
||||
const num = parseInt(value);
|
||||
// let's assume someone isn't over 100 years old? Maybe we should for the memes
|
||||
// but i doubt there's any legit athlete over 100.
|
||||
if (isNaN(num) || num < 1 || num > 100) return this.errorReply('Please enter a valid number as an age');
|
||||
if (isNaN(num) || num < 1 || num > 100) throw new Chat.ErrorMessage('Please enter a valid number as an age');
|
||||
break;
|
||||
default:
|
||||
// another custom key w/o validation
|
||||
if (!toNominationId(value)) {
|
||||
return this.errorReply(`No value provided for key ${key}.`);
|
||||
throw new Chat.ErrorMessage(`No value provided for key ${key}.`);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -772,8 +770,8 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
|
||||
const handler = selectHandler(this.message);
|
||||
|
||||
if (!handler.room) return this.errorReply(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) return this.errorReply(`This command can only be used in ${handler.room.title}.`);
|
||||
if (!handler.room) throw new Chat.ErrorMessage(`The room for this -otd doesn't exist.`);
|
||||
if (room !== handler.room) throw new Chat.ErrorMessage(`This command can only be used in ${handler.room.title}.`);
|
||||
|
||||
return this.parse(`/join view-${handler.id}`);
|
||||
},
|
||||
|
|
@ -784,12 +782,12 @@ export const otdCommands: Chat.ChatCommands = {
|
|||
if (!this.runBroadcast()) return false;
|
||||
|
||||
const handler = selectHandler(this.message);
|
||||
if (!handler.room) return this.errorReply(`The room for this -otd doesn't exist.`);
|
||||
if (!handler.room) throw new Chat.ErrorMessage(`The room for this -otd doesn't exist.`);
|
||||
|
||||
if (room !== handler.room) return this.errorReply(`This command can only be used in ${handler.room.title}.`);
|
||||
if (room !== handler.room) throw new Chat.ErrorMessage(`This command can only be used in ${handler.room.title}.`);
|
||||
|
||||
const text = await handler.generateWinnerDisplay();
|
||||
if (!text) return this.errorReply("There is no winner yet.");
|
||||
if (!text) throw new Chat.ErrorMessage("There is no winner yet.");
|
||||
this.sendReplyBox(text);
|
||||
},
|
||||
};
|
||||
|
|
@ -800,11 +798,11 @@ export const commands: Chat.ChatCommands = {
|
|||
create(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (room.settings.isPrivate) {
|
||||
return this.errorReply(`This command is only available in public rooms`);
|
||||
throw new Chat.ErrorMessage(`This command is only available in public rooms`);
|
||||
}
|
||||
const count = [...otds.values()].filter(otd => otd.room.roomid === room.roomid).length;
|
||||
if (count > 3) {
|
||||
return this.errorReply(`This room already has 3+ -otd's.`);
|
||||
throw new Chat.ErrorMessage(`This room already has 3+ -otd's.`);
|
||||
}
|
||||
this.checkCan('rangeban');
|
||||
|
||||
|
|
@ -813,17 +811,19 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const [title, time, ...keyLabels] = target.split(',').map(i => i.trim());
|
||||
if (!toID(title)) {
|
||||
return this.errorReply(`Invalid title.`);
|
||||
throw new Chat.ErrorMessage(`Invalid title.`);
|
||||
}
|
||||
const timeLabel = toID(time);
|
||||
if (!['week', 'day'].includes(timeLabel)) {
|
||||
return this.errorReply("Invalid time label - use 'week' or 'month'");
|
||||
throw new Chat.ErrorMessage("Invalid time label - use 'week' or 'month'");
|
||||
}
|
||||
const id = `${title.charAt(0)}ot${timeLabel.charAt(0)}`;
|
||||
const existing = otds.get(id);
|
||||
if (existing) {
|
||||
this.errorReply(`That -OTD already exists (${existing.name} of the ${existing.timeLabel}, in ${existing.room.title})`);
|
||||
return this.errorReply(`Try picking a new title.`);
|
||||
throw new Chat.ErrorMessage([
|
||||
`That -OTD already exists (${existing.name} of the ${existing.timeLabel}, in ${existing.room.title})`,
|
||||
`Try picking a new title.`,
|
||||
]);
|
||||
}
|
||||
const titleIdx = keyLabels.map(toID).indexOf(toID(title));
|
||||
if (titleIdx > -1) {
|
||||
|
|
@ -833,16 +833,16 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const filteredKeys = keyLabels.map(toNominationId).filter(Boolean);
|
||||
if (!filteredKeys.length) {
|
||||
return this.errorReply(`No valid key labels given.`);
|
||||
throw new Chat.ErrorMessage(`No valid key labels given.`);
|
||||
}
|
||||
if (new Set(filteredKeys).size !== keyLabels.length) {
|
||||
return this.errorReply(`Invalid keys in set - do not use duplicate key labels.`);
|
||||
throw new Chat.ErrorMessage(`Invalid keys in set - do not use duplicate key labels.`);
|
||||
}
|
||||
if (filteredKeys.length < 3) {
|
||||
return this.errorReply(`Specify at least 3 key labels.`);
|
||||
throw new Chat.ErrorMessage(`Specify at least 3 key labels.`);
|
||||
}
|
||||
if (filteredKeys.some(k => k.length < 3 || k.length > 50)) {
|
||||
return this.errorReply(`All labels must be more than 3 characters and less than 50 characters long.`);
|
||||
throw new Chat.ErrorMessage(`All labels must be more than 3 characters and less than 50 characters long.`);
|
||||
}
|
||||
const otd = OtdHandler.create(room, {
|
||||
keyLabels, keys: filteredKeys, title, timeLabel, roomid: room.roomid,
|
||||
|
|
@ -860,11 +860,11 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const otd = otds.get(otdId);
|
||||
if (!otd) {
|
||||
return this.errorReply(`OTD ${otd} not found.`);
|
||||
throw new Chat.ErrorMessage(`OTD ${otd} not found.`);
|
||||
}
|
||||
const targetRoom = Rooms.get(roomid);
|
||||
if (!targetRoom) {
|
||||
return this.errorReply(`Room ${roomid} not found.`);
|
||||
throw new Chat.ErrorMessage(`Room ${roomid} not found.`);
|
||||
}
|
||||
const oldRoom = otd.settings.roomid.slice();
|
||||
otd.settings.roomid = targetRoom.roomid;
|
||||
|
|
@ -882,7 +882,7 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse(`/help otd`);
|
||||
}
|
||||
const otd = otds.get(target);
|
||||
if (!otd) return this.errorReply(`OTD ${target} not found.`);
|
||||
if (!otd) throw new Chat.ErrorMessage(`OTD ${target} not found.`);
|
||||
otd.destroy();
|
||||
this.globalModlog(`OTD DELETE`, null, target);
|
||||
this.privateGlobalModAction(`${user.name} deleted the OTD ${otd.name} of the ${otd.timeLabel}`);
|
||||
|
|
|
|||
|
|
@ -1520,11 +1520,11 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
this.checkCan('show', null, room);
|
||||
this.checkChat();
|
||||
if (room.game) {
|
||||
return this.errorReply(this.tr`There is already a game of ${room.game.title} in progress.`);
|
||||
throw new Chat.ErrorMessage(this.tr`There is already a game of ${room.game.title} in progress.`);
|
||||
}
|
||||
|
||||
const targets = (target ? target.split(',') : []);
|
||||
if (targets.length < 3) return this.errorReply("Usage: /trivia new [mode], [category], [length]");
|
||||
if (targets.length < 3) throw new Chat.ErrorMessage("Usage: /trivia new [mode], [category], [length]");
|
||||
|
||||
let mode: string = toID(targets[0]);
|
||||
if (['triforce', 'tri'].includes(mode)) mode = 'triumvirate';
|
||||
|
|
@ -1533,7 +1533,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
const acceptableModes = Object.keys(MODES).filter(curMode => curMode !== 'first');
|
||||
mode = Utils.shuffle(acceptableModes)[0];
|
||||
}
|
||||
if (!MODES[mode]) return this.errorReply(this.tr`"${mode}" is an invalid mode.`);
|
||||
if (!MODES[mode]) throw new Chat.ErrorMessage(this.tr`"${mode}" is an invalid mode.`);
|
||||
|
||||
let categories: ID[] | 'random' = targets[1]
|
||||
.split('+')
|
||||
|
|
@ -1551,23 +1551,23 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
let length: ID | number = toID(targets[2]);
|
||||
if (!LENGTHS[length]) {
|
||||
length = parseInt(length);
|
||||
if (isNaN(length) || length < 1) return this.errorReply(this.tr`"${length}" is an invalid game length.`);
|
||||
if (isNaN(length) || length < 1) throw new Chat.ErrorMessage(this.tr`"${length}" is an invalid game length.`);
|
||||
}
|
||||
|
||||
// Assume that infinite mode will last for at least 75 points
|
||||
const questionsNecessary = typeof length === 'string' ? (LENGTHS[length].cap || 75) / 5 : length;
|
||||
if (questions.length < questionsNecessary) {
|
||||
if (categories === 'random') {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
this.tr`There are not enough questions in the randomly chosen category to finish a trivia game.`
|
||||
);
|
||||
}
|
||||
if (categories.length === 1 && categories[0] === 'all') {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
this.tr`There are not enough questions in the trivia database to finish a trivia game.`
|
||||
);
|
||||
}
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
this.tr`There are not enough questions under the specified categories to finish a trivia game.`
|
||||
);
|
||||
}
|
||||
|
|
@ -1642,7 +1642,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
}
|
||||
|
||||
const answer = toID(target);
|
||||
if (!answer) return this.errorReply(this.tr`No valid answer was entered.`);
|
||||
if (!answer) throw new Chat.ErrorMessage(this.tr`No valid answer was entered.`);
|
||||
|
||||
if (room.game?.gameid === 'trivia' && !Object.keys(game.playerTable).includes(user.id)) {
|
||||
game.addTriviaPlayer(user);
|
||||
|
|
@ -1683,7 +1683,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
|
||||
const game = getTriviaGame(room);
|
||||
if (game.game.length !== 'infinite' && !user.can('editroom', null, room)) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
this.tr`Only Room Owners and higher can force a Trivia game to end with winners in a non-infinite length.`
|
||||
);
|
||||
}
|
||||
|
|
@ -1699,7 +1699,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
const game = getTriviaGame(room);
|
||||
|
||||
const targetUser = this.getUserOrSelf(target);
|
||||
if (!targetUser) return this.errorReply(this.tr`User ${target} does not exist.`);
|
||||
if (!targetUser) throw new Chat.ErrorMessage(this.tr`User ${target} does not exist.`);
|
||||
let buffer = `${game.isPaused ? this.tr`There is a paused trivia game` : this.tr`There is a trivia game in progress`}, ` +
|
||||
this.tr`and it is in its ${game.phase} phase.` + `<br />` +
|
||||
this.tr`Mode: ${game.game.mode} | Category: ${game.game.category} | Cap: ${game.getDisplayableCap()}`;
|
||||
|
|
@ -1710,7 +1710,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
buffer += `<br />${this.tr`Current score: ${player.points} | Correct Answers: ${player.correctAnswers}`}`;
|
||||
}
|
||||
} else if (targetUser.id !== user.id) {
|
||||
return this.errorReply(this.tr`User ${targetUser.name} is not a player in the current trivia game.`);
|
||||
throw new Chat.ErrorMessage(this.tr`User ${targetUser.name} is not a player in the current trivia game.`);
|
||||
}
|
||||
buffer += `<br />${this.tr`Players: ${game.formatPlayerList({ max: null, requirePoints: false })}`}`;
|
||||
|
||||
|
|
@ -1881,7 +1881,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
|
||||
const indicesLen = indices.length;
|
||||
if (!indicesLen) {
|
||||
return this.errorReply(
|
||||
throw new Chat.ErrorMessage(
|
||||
this.tr`'${target}' is not a valid set of submission index numbers.\n` +
|
||||
this.tr`View /trivia review and /trivia help for more information.`
|
||||
);
|
||||
|
|
@ -1899,7 +1899,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
return this.privateModAction(`${user.name} ${message} from the submission database.`);
|
||||
}
|
||||
|
||||
this.errorReply(this.tr`'${target}' is an invalid argument. View /trivia help questions for more information.`);
|
||||
throw new Chat.ErrorMessage(this.tr`'${target}' is an invalid argument. View /trivia help questions for more information.`);
|
||||
},
|
||||
accepthelp: [`/trivia accept [index1], [index2], ... [indexn] OR all - Add questions from the submission database to the question database using their index numbers or ranges of them. Requires: @ # ~`],
|
||||
rejecthelp: [`/trivia reject [index1], [index2], ... [indexn] OR all - Remove questions from the submission database using their index numbers or ranges of them. Requires: @ # ~`],
|
||||
|
|
@ -1914,7 +1914,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
|
||||
const question = Utils.escapeHTML(target).trim();
|
||||
if (!question) {
|
||||
return this.errorReply(this.tr`'${target}' is not a valid argument. View /trivia help questions for more information.`);
|
||||
throw new Chat.ErrorMessage(this.tr`'${target}' is not a valid argument. View /trivia help questions for more information.`);
|
||||
}
|
||||
|
||||
const { category } = await database.ensureQuestionExists(question);
|
||||
|
|
@ -2112,7 +2112,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
const category = CATEGORY_ALIASES[target] || target;
|
||||
if (category === 'random') return false;
|
||||
if (!ALL_CATEGORIES[category]) {
|
||||
return this.errorReply(this.tr`'${target}' is not a valid category. View /help trivia for more information.`);
|
||||
throw new Chat.ErrorMessage(this.tr`'${target}' is not a valid category. View /help trivia for more information.`);
|
||||
}
|
||||
|
||||
const list = await database.getQuestions([category], Number.MAX_SAFE_INTEGER, { order: 'oldestfirst' });
|
||||
|
|
@ -2158,7 +2158,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
type = target;
|
||||
} else {
|
||||
[type, ...query] = target.split(',');
|
||||
if (!target.includes(',')) return this.errorReply(this.tr`No valid search arguments entered.`);
|
||||
if (!target.includes(',')) throw new Chat.ErrorMessage(this.tr`No valid search arguments entered.`);
|
||||
}
|
||||
|
||||
type = toID(type);
|
||||
|
|
@ -2176,7 +2176,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
|
||||
let queryString = query.join(',');
|
||||
if (cmd !== 'doublespacesearch') queryString = queryString.trim();
|
||||
if (!queryString) return this.errorReply(this.tr`No valid search query was entered.`);
|
||||
if (!queryString) throw new Chat.ErrorMessage(this.tr`No valid search query was entered.`);
|
||||
|
||||
const results = await database.searchQuestions(queryString, options);
|
||||
if (!results.length) return this.sendReply(this.tr`No results found under the ${type} list.`);
|
||||
|
|
@ -2305,7 +2305,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
if (cmd.includes('score')) leaderboard = 'nonAlltime';
|
||||
|
||||
const ladder = (await cachedLadder.get(leaderboard))?.ladder;
|
||||
if (!ladder?.length) return this.errorReply(this.tr`No Trivia games have been played yet.`);
|
||||
if (!ladder?.length) throw new Chat.ErrorMessage(this.tr`No Trivia games have been played yet.`);
|
||||
|
||||
let buffer = "|raw|<div class=\"ladder\" style=\"overflow-y: scroll; max-height: 300px;\"><table>" +
|
||||
`<tr><th>${this.tr`Rank`}</th><th>${this.tr`User`}</th><th>${this.tr`Leaderboard score`}</th><th>${this.tr`Total game points`}</th><th>${this.tr`Total correct answers`}</th></tr>`;
|
||||
|
|
@ -2340,9 +2340,10 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
|
||||
if (user.lastCommand !== '/trivia resetcycleleaderboard') {
|
||||
user.lastCommand = '/trivia resetcycleleaderboard';
|
||||
this.errorReply(`Are you sure you want to reset the Trivia cycle-specific leaderboard? This action is IRREVERSIBLE.`);
|
||||
this.errorReply(`To confirm, retype the command.`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage([
|
||||
`Are you sure you want to reset the Trivia cycle-specific leaderboard? This action is IRREVERSIBLE.`,
|
||||
`To confirm, retype the command.`,
|
||||
]);
|
||||
}
|
||||
user.lastCommand = '';
|
||||
|
||||
|
|
@ -2364,10 +2365,10 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
this.modlog(`TRIVIA CATEGORY CLEAR`, null, SPECIAL_CATEGORIES[category]);
|
||||
return this.privateModAction(room.tr`${user.name} removed all questions of category '${category}'.`);
|
||||
} else {
|
||||
return this.errorReply(this.tr`You cannot clear the category '${ALL_CATEGORIES[category]}'.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You cannot clear the category '${ALL_CATEGORIES[category]}'.`);
|
||||
}
|
||||
} else {
|
||||
return this.errorReply(this.tr`'${category}' is an invalid category.`);
|
||||
throw new Chat.ErrorMessage(this.tr`'${category}' is an invalid category.`);
|
||||
}
|
||||
},
|
||||
clearqshelp: [`/trivia clearqs [category] - Remove all questions of the given category. Requires: # ~`],
|
||||
|
|
@ -2416,7 +2417,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
const [userid, pointString] = this.splitOne(target).map(toID);
|
||||
|
||||
const points = parseInt(pointString);
|
||||
if (isNaN(points)) return this.errorReply(`You must specify a number of points to add/remove.`);
|
||||
if (isNaN(points)) throw new Chat.ErrorMessage(`You must specify a number of points to add/remove.`);
|
||||
const isRemoval = cmd === 'removepoints';
|
||||
|
||||
const change = { score: isRemoval ? -points : points, totalPoints: 0, totalCorrectAnswers: 0 };
|
||||
|
|
@ -2447,7 +2448,7 @@ const triviaCommands: Chat.ChatCommands = {
|
|||
const userid = toID(target);
|
||||
if (!userid) return this.parse('/help trivia removeleaderboardentry');
|
||||
if (!(await database.getLeaderboardEntry(userid, 'alltime'))) {
|
||||
return this.errorReply(`The user '${userid}' has no Trivia leaderboard entry.`);
|
||||
throw new Chat.ErrorMessage(`The user '${userid}' has no Trivia leaderboard entry.`);
|
||||
}
|
||||
|
||||
const command = `/trivia removeleaderboardentry ${userid}`;
|
||||
|
|
@ -2581,7 +2582,7 @@ const mastermindCommands: Chat.ChatCommands = {
|
|||
|
||||
const finalists = parseInt(target);
|
||||
if (isNaN(finalists) || finalists < 2) {
|
||||
return this.errorReply(this.tr`You must specify a number that is at least 2 for finalists.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You must specify a number that is at least 2 for finalists.`);
|
||||
}
|
||||
|
||||
room.game = new Mastermind(room, finalists);
|
||||
|
|
@ -2601,17 +2602,17 @@ const mastermindCommands: Chat.ChatCommands = {
|
|||
|
||||
category = CATEGORY_ALIASES[category] || category;
|
||||
if (!(category in ALL_CATEGORIES)) {
|
||||
return this.errorReply(this.tr`${category} is not a valid category.`);
|
||||
throw new Chat.ErrorMessage(this.tr`${category} is not a valid category.`);
|
||||
}
|
||||
const categoryName = ALL_CATEGORIES[category];
|
||||
const timeout = parseInt(timeoutString);
|
||||
if (isNaN(timeout) || timeout < 1 || (timeout * 1000) > Chat.MAX_TIMEOUT_DURATION) {
|
||||
return this.errorReply(this.tr`You must specify a round length of at least 1 second.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You must specify a round length of at least 1 second.`);
|
||||
}
|
||||
|
||||
const questions = await getQuestions([category], 'random');
|
||||
if (!questions.length) {
|
||||
return this.errorReply(this.tr`There are no questions in the ${categoryName} category.`);
|
||||
throw new Chat.ErrorMessage(this.tr`There are no questions in the ${categoryName} category.`);
|
||||
}
|
||||
|
||||
game.startRound(player, category, questions, timeout);
|
||||
|
|
@ -2629,7 +2630,7 @@ const mastermindCommands: Chat.ChatCommands = {
|
|||
|
||||
const timeout = parseInt(target);
|
||||
if (isNaN(timeout) || timeout < 1 || (timeout * 1000) > Chat.MAX_TIMEOUT_DURATION) {
|
||||
return this.errorReply(this.tr`You must specify a length of at least 1 second.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You must specify a length of at least 1 second.`);
|
||||
}
|
||||
|
||||
await game.startFinals(timeout);
|
||||
|
|
@ -2652,9 +2653,9 @@ const mastermindCommands: Chat.ChatCommands = {
|
|||
pass(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
const round = getMastermindGame(room).currentRound;
|
||||
if (!round) return this.errorReply(this.tr`No round of Mastermind is currently being played.`);
|
||||
if (!round) throw new Chat.ErrorMessage(this.tr`No round of Mastermind is currently being played.`);
|
||||
if (!(user.id in round.playerTable)) {
|
||||
return this.errorReply(this.tr`You are not a player in the current round of Mastermind.`);
|
||||
throw new Chat.ErrorMessage(this.tr`You are not a player in the current round of Mastermind.`);
|
||||
}
|
||||
round.pass();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('lock');
|
||||
const targets = target.split(',').map(toID).filter(Boolean);
|
||||
if (!targets.length) {
|
||||
return this.errorReply(`Specify at least one term.`);
|
||||
throw new Chat.ErrorMessage(`Specify at least one term.`);
|
||||
}
|
||||
for (const [i, arg] of targets.entries()) {
|
||||
if (nameList.has(arg)) {
|
||||
|
|
@ -164,7 +164,7 @@ export const commands: Chat.ChatCommands = {
|
|||
}
|
||||
if (!targets.length) {
|
||||
// fuck you too, "mia added 0 term to the usersearch name list"
|
||||
return this.errorReply(`No terms could be added.`);
|
||||
throw new Chat.ErrorMessage(`No terms could be added.`);
|
||||
}
|
||||
const count = Chat.count(targets, 'terms');
|
||||
Rooms.get('staff')?.addByUser(
|
||||
|
|
@ -180,7 +180,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('lock');
|
||||
const targets = target.split(',').map(toID).filter(Boolean);
|
||||
if (!targets.length) {
|
||||
return this.errorReply(`Specify at least one term.`);
|
||||
throw new Chat.ErrorMessage(`Specify at least one term.`);
|
||||
}
|
||||
for (const [i, arg] of targets.entries()) {
|
||||
if (!nameList.has(arg)) {
|
||||
|
|
@ -191,7 +191,7 @@ export const commands: Chat.ChatCommands = {
|
|||
nameList.delete(arg);
|
||||
}
|
||||
if (!targets.length) {
|
||||
return this.errorReply(`No terms could be removed.`);
|
||||
throw new Chat.ErrorMessage(`No terms could be removed.`);
|
||||
}
|
||||
const count = Chat.count(targets, 'terms');
|
||||
Rooms.get('staff')?.addByUser(
|
||||
|
|
|
|||
|
|
@ -948,19 +948,21 @@ export const commands: Chat.ChatCommands = {
|
|||
param => param.trim()
|
||||
);
|
||||
if (!(giver && amountStr && summary && deposit && lookfor)) {
|
||||
return this.errorReply("Invalid arguments specified - /gts start giver | amount | summary | deposit | lookfor");
|
||||
throw new Chat.ErrorMessage("Invalid arguments specified - /gts start giver | amount | summary | deposit | lookfor");
|
||||
}
|
||||
const amount = parseInt(amountStr);
|
||||
if (!amount || amount < 20 || amount > 100) {
|
||||
return this.errorReply("Please enter a valid amount. For a GTS giveaway, you need to give away at least 20 mons, and no more than 100.");
|
||||
throw new Chat.ErrorMessage("Please enter a valid amount. For a GTS giveaway, you need to give away at least 20 mons, and no more than 100.");
|
||||
}
|
||||
const targetUser = Users.get(giver);
|
||||
if (!targetUser?.connected) return this.errorReply(`User '${giver}' is not online.`);
|
||||
if (!targetUser?.connected) throw new Chat.ErrorMessage(`User '${giver}' is not online.`);
|
||||
this.checkCan('warn', null, room);
|
||||
if (!targetUser.autoconfirmed) {
|
||||
return this.errorReply(`User '${targetUser.name}' needs to be autoconfirmed to host a giveaway.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' needs to be autoconfirmed to host a giveaway.`);
|
||||
}
|
||||
if (Giveaway.checkBanned(room, targetUser)) {
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' is giveaway banned.`);
|
||||
}
|
||||
if (Giveaway.checkBanned(room, targetUser)) return this.errorReply(`User '${targetUser.name}' is giveaway banned.`);
|
||||
|
||||
room.subGame = new GTS(room, targetUser, amount, summary, deposit, lookfor);
|
||||
|
||||
|
|
@ -981,8 +983,8 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.sendReply(output);
|
||||
}
|
||||
const newamount = parseInt(target);
|
||||
if (isNaN(newamount)) return this.errorReply("Please enter a valid amount.");
|
||||
if (newamount > game.left) return this.errorReply("The new amount must be lower than the old amount.");
|
||||
if (isNaN(newamount)) throw new Chat.ErrorMessage("Please enter a valid amount.");
|
||||
if (newamount > game.left) throw new Chat.ErrorMessage("The new amount must be lower than the old amount.");
|
||||
if (newamount < game.left - 1) {
|
||||
this.modlog(`GTS GIVEAWAY`, null, `set from ${game.left} to ${newamount} left`);
|
||||
}
|
||||
|
|
@ -993,10 +995,10 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom('wifi' as RoomID);
|
||||
const game = this.requireGame(GTS, true);
|
||||
if (!user.can('warn', null, room) && user !== game.giver) {
|
||||
return this.errorReply("Only the host or a staff member can update GTS giveaways.");
|
||||
throw new Chat.ErrorMessage("Only the host or a staff member can update GTS giveaways.");
|
||||
}
|
||||
|
||||
if (!target || target.length > 12) return this.errorReply("Please enter a valid IGN.");
|
||||
if (!target || target.length > 12) throw new Chat.ErrorMessage("Please enter a valid IGN.");
|
||||
|
||||
game.updateSent(target);
|
||||
},
|
||||
|
|
@ -1004,9 +1006,9 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom('wifi' as RoomID);
|
||||
const game = this.requireGame(GTS, true);
|
||||
if (!user.can('warn', null, room) && user !== game.giver) {
|
||||
return this.errorReply("Only the host or a staff member can update GTS giveaways.");
|
||||
throw new Chat.ErrorMessage("Only the host or a staff member can update GTS giveaways.");
|
||||
}
|
||||
if (game.noDeposits) return this.errorReply("The GTS giveaway was already set to not accept deposits.");
|
||||
if (game.noDeposits) throw new Chat.ErrorMessage("The GTS giveaway was already set to not accept deposits.");
|
||||
|
||||
game.stopDeposits();
|
||||
},
|
||||
|
|
@ -1016,7 +1018,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('warn', null, room);
|
||||
|
||||
if (target && target.length > 300) {
|
||||
return this.errorReply("The reason is too long. It cannot exceed 300 characters.");
|
||||
throw new Chat.ErrorMessage("The reason is too long. It cannot exceed 300 characters.");
|
||||
}
|
||||
const amount = game.end(true);
|
||||
if (target) target = `: ${target}`;
|
||||
|
|
@ -1095,10 +1097,10 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const { targetUser, rest: reason } = this.requireUser(target, { allowOffline: true });
|
||||
if (reason.length > 300) {
|
||||
return this.errorReply("The reason is too long. It cannot exceed 300 characters.");
|
||||
throw new Chat.ErrorMessage("The reason is too long. It cannot exceed 300 characters.");
|
||||
}
|
||||
if (Punishments.hasRoomPunishType(room, targetUser.name, 'GIVEAWAYBAN')) {
|
||||
return this.errorReply(`User '${targetUser.name}' is already giveawaybanned.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' is already giveawaybanned.`);
|
||||
}
|
||||
|
||||
const duration = cmd === 'monthban' ? 30 * DAY : cmd === 'permaban' ? 3650 * DAY : 7 * DAY;
|
||||
|
|
@ -1119,7 +1121,7 @@ export const commands: Chat.ChatCommands = {
|
|||
|
||||
const { targetUser } = this.requireUser(target, { allowOffline: true });
|
||||
if (!Giveaway.checkBanned(room, targetUser)) {
|
||||
return this.errorReply(`User '${targetUser.name}' isn't banned from entering giveaways.`);
|
||||
throw new Chat.ErrorMessage(`User '${targetUser.name}' isn't banned from entering giveaways.`);
|
||||
}
|
||||
|
||||
Giveaway.unban(room, targetUser);
|
||||
|
|
@ -1183,7 +1185,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (user.id !== game.host.id) this.checkCan('warn', null, room);
|
||||
|
||||
if (target && target.length > 300) {
|
||||
return this.errorReply("The reason is too long. It cannot exceed 300 characters.");
|
||||
throw new Chat.ErrorMessage("The reason is too long. It cannot exceed 300 characters.");
|
||||
}
|
||||
game.end(true);
|
||||
this.modlog('GIVEAWAY END', null, target);
|
||||
|
|
@ -1396,7 +1398,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (cmd.includes('un')) {
|
||||
const idx = wifiData.whitelist.indexOf(targetId);
|
||||
if (idx < 0) {
|
||||
return this.errorReply(`'${targetId}' is not whitelisted.`);
|
||||
throw new Chat.ErrorMessage(`'${targetId}' is not whitelisted.`);
|
||||
}
|
||||
wifiData.whitelist.splice(idx, 1);
|
||||
this.privateModAction(`${user.name} removed '${targetId}' from the giveaway whitelist.`);
|
||||
|
|
@ -1404,7 +1406,7 @@ export const commands: Chat.ChatCommands = {
|
|||
saveData();
|
||||
} else {
|
||||
if (wifiData.whitelist.includes(targetId)) {
|
||||
return this.errorReply(`'${targetId}' is already whitelisted.`);
|
||||
throw new Chat.ErrorMessage(`'${targetId}' is already whitelisted.`);
|
||||
}
|
||||
wifiData.whitelist.push(targetId);
|
||||
this.privateModAction(`${user.name} added ${targetId} to the giveaway whitelist.`);
|
||||
|
|
|
|||
|
|
@ -494,7 +494,7 @@ export function destroy() {
|
|||
export const commands: Chat.ChatCommands = {
|
||||
async randchannel(target, room, user) {
|
||||
room = this.requireRoom('internetexplorers' as RoomID);
|
||||
if (Object.keys(YouTube.data.channels).length < 1) return this.errorReply(`No channels in the database.`);
|
||||
if (Object.keys(YouTube.data.channels).length < 1) throw new Chat.ErrorMessage(`No channels in the database.`);
|
||||
target = toID(target);
|
||||
this.runBroadcast();
|
||||
const data = await YouTube.randChannel(target);
|
||||
|
|
@ -508,7 +508,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom('internetexplorers' as RoomID);
|
||||
this.checkCan('mute', null, room);
|
||||
const [id, name] = target.split(',').map(t => t.trim());
|
||||
if (!id) return this.errorReply('Specify a channel ID.');
|
||||
if (!id) throw new Chat.ErrorMessage('Specify a channel ID.');
|
||||
await YouTube.getChannelData(id, name);
|
||||
this.modlog('ADDCHANNEL', null, `${id} ${name ? `username: ${name}` : ''}`);
|
||||
return this.privateModAction(
|
||||
|
|
@ -521,7 +521,7 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom('internetexplorers' as RoomID);
|
||||
this.checkCan('mute', null, room);
|
||||
const id = YouTube.channelSearch(target);
|
||||
if (!id) return this.errorReply(`Channel with ID or name ${target} not found.`);
|
||||
if (!id) throw new Chat.ErrorMessage(`Channel with ID or name ${target} not found.`);
|
||||
delete YouTube.data.channels[id];
|
||||
YouTube.save();
|
||||
this.privateModAction(`${user.name} deleted channel with ID or name ${target}.`);
|
||||
|
|
@ -532,7 +532,7 @@ export const commands: Chat.ChatCommands = {
|
|||
async channel(target, room, user) {
|
||||
room = this.requireRoom('internetexplorers' as RoomID);
|
||||
const channel = YouTube.channelSearch(target);
|
||||
if (!channel) return this.errorReply(`No channels with ID or name ${target} found.`);
|
||||
if (!channel) throw new Chat.ErrorMessage(`No channels with ID or name ${target} found.`);
|
||||
const data = await YouTube.generateChannelDisplay(channel);
|
||||
this.runBroadcast();
|
||||
return this.sendReply(`|html|${data}`);
|
||||
|
|
@ -565,7 +565,7 @@ export const commands: Chat.ChatCommands = {
|
|||
this.checkCan('mute', null, room);
|
||||
const [channel, name] = target.split(',');
|
||||
const id = YouTube.channelSearch(channel);
|
||||
if (!id) return this.errorReply(`Channel ${channel} is not in the database.`);
|
||||
if (!id) throw new Chat.ErrorMessage(`Channel ${channel} is not in the database.`);
|
||||
YouTube.data.channels[id].username = name;
|
||||
this.modlog(`UPDATECHANNEL`, null, name);
|
||||
this.privateModAction(`${user.name} updated channel ${id}'s username to ${name}.`);
|
||||
|
|
@ -576,19 +576,19 @@ export const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom('internetexplorers' as RoomID);
|
||||
this.checkCan('declare', null, room);
|
||||
if (!target) {
|
||||
if (!YouTube.interval) return this.errorReply(`The YouTube plugin is not currently running an interval.`);
|
||||
if (!YouTube.interval) throw new Chat.ErrorMessage(`The YouTube plugin is not currently running an interval.`);
|
||||
return this.sendReply(`Interval is currently set to ${Chat.toDurationString(YouTube.intervalTime * 60 * 1000)}.`);
|
||||
}
|
||||
if (this.meansNo(target)) {
|
||||
if (!YouTube.interval) return this.errorReply(`The interval is not currently running`);
|
||||
if (!YouTube.interval) throw new Chat.ErrorMessage(`The interval is not currently running`);
|
||||
clearInterval(YouTube.interval);
|
||||
delete YouTube.data.intervalTime;
|
||||
YouTube.save();
|
||||
this.privateModAction(`${user.name} turned off the YouTube interval`);
|
||||
return this.modlog(`YOUTUBE INTERVAL`, null, 'OFF');
|
||||
}
|
||||
if (Object.keys(channelData).length < 1) return this.errorReply(`No channels in the database.`);
|
||||
if (isNaN(parseInt(target))) return this.errorReply(`Specify a number (in minutes) for the interval.`);
|
||||
if (Object.keys(channelData).length < 1) throw new Chat.ErrorMessage(`No channels in the database.`);
|
||||
if (isNaN(parseInt(target))) throw new Chat.ErrorMessage(`Specify a number (in minutes) for the interval.`);
|
||||
YouTube.runInterval(target);
|
||||
YouTube.save();
|
||||
this.privateModAction(`${user.name} set a randchannel interval to ${target} minutes`);
|
||||
|
|
@ -600,7 +600,7 @@ export const commands: Chat.ChatCommands = {
|
|||
const categoryID = toID(target);
|
||||
if (!categoryID) return this.parse(`/help youtube`);
|
||||
if (YouTube.data.categories.map(toID).includes(categoryID)) {
|
||||
return this.errorReply(`This category is already added. To change it, remove it and re-add it.`);
|
||||
throw new Chat.ErrorMessage(`This category is already added. To change it, remove it and re-add it.`);
|
||||
}
|
||||
YouTube.data.categories.push(target);
|
||||
this.modlog(`YOUTUBE ADDCATEGORY`, null, target);
|
||||
|
|
@ -614,7 +614,7 @@ export const commands: Chat.ChatCommands = {
|
|||
if (!categoryID) return this.parse(`/help youtube`);
|
||||
const index = YouTube.data.categories.indexOf(target);
|
||||
if (index < 0) {
|
||||
return this.errorReply(`${target} is not a valid category.`);
|
||||
throw new Chat.ErrorMessage(`${target} is not a valid category.`);
|
||||
}
|
||||
for (const id in YouTube.data.channels) {
|
||||
const channel = YouTube.data.channels[id];
|
||||
|
|
@ -633,10 +633,10 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse('/help youtube');
|
||||
}
|
||||
if (!YouTube.data.categories.includes(category)) {
|
||||
return this.errorReply(`Invalid category.`);
|
||||
throw new Chat.ErrorMessage(`Invalid category.`);
|
||||
}
|
||||
const name = YouTube.channelSearch(id);
|
||||
if (!name) return this.errorReply(`Invalid channel.`);
|
||||
if (!name) throw new Chat.ErrorMessage(`Invalid channel.`);
|
||||
const channel = YouTube.data.channels[name];
|
||||
YouTube.data.channels[name].category = category;
|
||||
YouTube.save();
|
||||
|
|
@ -651,10 +651,10 @@ export const commands: Chat.ChatCommands = {
|
|||
return this.parse('/help youtube');
|
||||
}
|
||||
const name = YouTube.channelSearch(target);
|
||||
if (!name) return this.errorReply(`Invalid channel.`);
|
||||
if (!name) throw new Chat.ErrorMessage(`Invalid channel.`);
|
||||
const channel = YouTube.data.channels[name];
|
||||
const category = channel.category;
|
||||
if (!category) return this.errorReply(`That channel does not have a category.`);
|
||||
if (!category) throw new Chat.ErrorMessage(`That channel does not have a category.`);
|
||||
delete channel.category;
|
||||
YouTube.save();
|
||||
this.modlog(`YOUTUBE DECATEGORIZE`, null, target);
|
||||
|
|
@ -681,11 +681,11 @@ export const commands: Chat.ChatCommands = {
|
|||
async create(target, room, user) {
|
||||
room = this.requireRoom();
|
||||
if (!GROUPWATCH_ROOMS.includes(room.roomid)) {
|
||||
return this.errorReply(`This room is not allowed to use the groupwatch function.`);
|
||||
throw new Chat.ErrorMessage(`This room is not allowed to use the groupwatch function.`);
|
||||
}
|
||||
this.checkCan('mute', null, room);
|
||||
const [url, title] = Utils.splitFirst(target, ',').map(p => p.trim());
|
||||
if (!url || !title) return this.errorReply(`You must specify a video to watch and a title for the group watch.`);
|
||||
if (!url || !title) throw new Chat.ErrorMessage(`You must specify a video to watch and a title for the group watch.`);
|
||||
const game = await YouTube.createGroupWatch(url, room, title);
|
||||
this.modlog(`YOUTUBE GROUPWATCH`, null, `${url} (${title})`);
|
||||
room.add(
|
||||
|
|
@ -735,9 +735,9 @@ export const commands: Chat.ChatCommands = {
|
|||
twitch: {
|
||||
async channel(target, room, user) {
|
||||
room = this.requireRoom('internetexplorers' as RoomID);
|
||||
if (!Config.twitchKey) return this.errorReply(`Twitch is not configured`);
|
||||
if (!Config.twitchKey) throw new Chat.ErrorMessage(`Twitch is not configured`);
|
||||
const data = await Twitch.getChannel(target);
|
||||
if (!data) return this.errorReply(`Channel not found`);
|
||||
if (!data) throw new Chat.ErrorMessage(`Channel not found`);
|
||||
const html = Twitch.visualizeChannel(data);
|
||||
this.runBroadcast();
|
||||
return this.sendReplyBox(html);
|
||||
|
|
@ -761,7 +761,7 @@ export const pages: Chat.PageTable = {
|
|||
switch (toID(type)) {
|
||||
case 'categories':
|
||||
if (!YouTube.data.categories.length) {
|
||||
return this.errorReply(`There are currently no categories in the Youtube channel database.`);
|
||||
throw new Chat.ErrorMessage(`There are currently no categories in the Youtube channel database.`);
|
||||
}
|
||||
const sorted: { [k: string]: string[] } = {};
|
||||
const channels = YouTube.data.channels;
|
||||
|
|
@ -802,7 +802,7 @@ export const pages: Chat.PageTable = {
|
|||
if (!user.named) return Rooms.RETRY_AFTER_LOGIN;
|
||||
const [roomid, num] = query;
|
||||
const watch = GroupWatch.groupwatches.get(`${roomid}-${num}`);
|
||||
if (!watch) return this.errorReply(`Groupwatch ${roomid}-${num} not found.`);
|
||||
if (!watch) throw new Chat.ErrorMessage(`Groupwatch ${roomid}-${num} not found.`);
|
||||
this.title = `[Groupwatch] ${watch.title}`;
|
||||
return watch.display();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -235,7 +235,8 @@ class PatternTester {
|
|||
* Outside of a command/page context, it would still cause a crash.
|
||||
*/
|
||||
export class ErrorMessage extends Error {
|
||||
constructor(message: string) {
|
||||
constructor(message: string | string[]) {
|
||||
if (Array.isArray(message)) message = message.join('\n');
|
||||
super(message);
|
||||
this.name = 'ErrorMessage';
|
||||
Error.captureStackTrace(this, ErrorMessage);
|
||||
|
|
@ -471,7 +472,7 @@ export class PageContext extends MessageContext {
|
|||
res = await handler.call(this, parts, this.user, this.connection);
|
||||
} catch (err: any) {
|
||||
if (err.name?.endsWith('ErrorMessage')) {
|
||||
if (err.message) this.errorReply(err.message);
|
||||
if (err.message) this.errorReply(err.message.replace(/\n/g, '<br />'));
|
||||
return;
|
||||
}
|
||||
if (err.name.endsWith('Interruption')) {
|
||||
|
|
@ -693,7 +694,7 @@ export class CommandContext extends MessageContext {
|
|||
!Users.globalAuth.atLeast(this.user, blockInvites as GroupSymbol)
|
||||
) {
|
||||
Chat.maybeNotifyBlocked(`invite`, this.pmTarget, this.user);
|
||||
return this.errorReply(`${this.pmTarget.name} is blocking room invites.`);
|
||||
throw new Chat.ErrorMessage(`${this.pmTarget.name} is blocking room invites.`);
|
||||
}
|
||||
}
|
||||
Chat.PrivateMessages.send(message, this.user, this.pmTarget);
|
||||
|
|
@ -707,9 +708,8 @@ export class CommandContext extends MessageContext {
|
|||
run(handler: string | AnnotatedChatHandler) {
|
||||
if (typeof handler === 'string') handler = Chat.commands[handler] as AnnotatedChatHandler;
|
||||
if (!handler.broadcastable && this.cmdToken === '!') {
|
||||
this.errorReply(`The command "${this.fullCmd}" can't be broadcast.`);
|
||||
this.errorReply(`Use /${this.fullCmd} instead.`);
|
||||
return false;
|
||||
throw new Chat.ErrorMessage([`The command "${this.fullCmd}" can't be broadcast.`,
|
||||
`Use /${this.fullCmd} instead.`]);
|
||||
}
|
||||
let result: any = handler.call(this, this.target, this.room, this.user, this.connection, this.cmd, this.message);
|
||||
if (result === undefined) result = false;
|
||||
|
|
@ -1024,9 +1024,7 @@ export class CommandContext extends MessageContext {
|
|||
}
|
||||
canUseConsole() {
|
||||
if (!this.user.hasConsoleAccess(this.connection)) {
|
||||
throw new Chat.ErrorMessage(
|
||||
(this.cmdToken + this.fullCmd).trim() + " - Requires console access, please set up `Config.consoleips`."
|
||||
);
|
||||
throw new Chat.ErrorMessage(`${(this.cmdToken + this.fullCmd).trim()} - Requires console access, please set up \`Config.consoleips\`.`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1039,20 +1037,20 @@ export class CommandContext extends MessageContext {
|
|||
}
|
||||
|
||||
if (this.user.locked && !(this.room?.roomid.startsWith('help-') || this.pmTarget?.can('lock'))) {
|
||||
this.errorReply(`You cannot broadcast this command's information while locked.`);
|
||||
throw new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);
|
||||
throw new Chat.ErrorMessage([`You cannot broadcast this command's information while locked.`,
|
||||
`To see it for yourself, use: /${this.message.slice(1)}`]);
|
||||
}
|
||||
|
||||
if (this.room && !this.user.can('show', null, this.room, this.cmd, this.cmdToken)) {
|
||||
const perm = this.room.settings.permissions?.[`!${this.cmd}`];
|
||||
const atLeast = perm ? `at least rank ${perm}` : 'voiced';
|
||||
this.errorReply(`You need to be ${atLeast} to broadcast this command's information.`);
|
||||
throw new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);
|
||||
throw new Chat.ErrorMessage([`You need to be ${atLeast} to broadcast this command's information.`,
|
||||
`To see it for yourself, use: /${this.message.slice(1)}`]);
|
||||
}
|
||||
|
||||
if (!this.room && !this.pmTarget) {
|
||||
this.errorReply(`Broadcasting a command with "!" in a PM or chatroom will show it that user or room.`);
|
||||
throw new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);
|
||||
throw new Chat.ErrorMessage([`Broadcasting a command with "!" in a PM or chatroom will show it that user or room.`,
|
||||
`To see it for yourself, use: /${this.message.slice(1)}`]);
|
||||
}
|
||||
|
||||
// broadcast cooldown
|
||||
|
|
@ -1388,24 +1386,22 @@ export class CommandContext extends MessageContext {
|
|||
|
||||
if (tagName === 'img') {
|
||||
if (!this.room || (this.room.settings.isPersonal && !this.user.can('lock'))) {
|
||||
throw new Chat.ErrorMessage(
|
||||
`This tag is not allowed: <${tagContent}>. Images are not allowed outside of chatrooms.`
|
||||
);
|
||||
throw new Chat.ErrorMessage(`This tag is not allowed: <${tagContent}>. Images are not allowed outside of chatrooms.`);
|
||||
}
|
||||
if (!/width ?= ?(?:[0-9]+|"[0-9]+")/i.test(tagContent) || !/height ?= ?(?:[0-9]+|"[0-9]+")/i.test(tagContent)) {
|
||||
// Width and height are required because most browsers insert the
|
||||
// <img> element before width and height are known, and when the
|
||||
// image is loaded, this changes the height of the chat area, which
|
||||
// messes up autoscrolling.
|
||||
this.errorReply(`This image is missing a width/height attribute: <${tagContent}>`);
|
||||
throw new Chat.ErrorMessage(`Images without predefined width/height cause problems with scrolling because loading them changes their height.`);
|
||||
throw new Chat.ErrorMessage([`This image is missing a width/height attribute: <${tagContent}>`,
|
||||
`Images without predefined width/height cause problems with scrolling because loading them changes their height.`]);
|
||||
}
|
||||
const srcMatch = / src ?= ?(?:"|')?([^ "']+)(?: ?(?:"|'))?/i.exec(tagContent);
|
||||
if (srcMatch) {
|
||||
this.checkEmbedURI(srcMatch[1]);
|
||||
} else {
|
||||
this.errorReply(`This image has a broken src attribute: <${tagContent}>`);
|
||||
throw new Chat.ErrorMessage(`The src attribute must exist and have no spaces in the URL`);
|
||||
throw new Chat.ErrorMessage([`This image has a broken src attribute: <${tagContent}>`,
|
||||
`The src attribute must exist and have no spaces in the URL`]);
|
||||
}
|
||||
}
|
||||
if (tagName === 'button') {
|
||||
|
|
@ -1418,16 +1414,18 @@ export class CommandContext extends MessageContext {
|
|||
const [pmTarget] = buttonValue.replace(msgCommandRegex, '').split(',');
|
||||
const auth = this.room ? this.room.auth : Users.globalAuth;
|
||||
if (auth.get(toID(pmTarget)) !== '*' && toID(pmTarget) !== this.user.id) {
|
||||
this.errorReply(`This button is not allowed: <${tagContent}>`);
|
||||
throw new Chat.ErrorMessage(`Your scripted button can't send PMs to ${pmTarget}, because that user is not a Room Bot.`);
|
||||
throw new Chat.ErrorMessage([`This button is not allowed: <${tagContent}>`,
|
||||
`Your scripted button can't send PMs to ${pmTarget}, because that user is not a Room Bot.`]);
|
||||
}
|
||||
} else if (buttonName === 'send' && buttonValue && botmsgCommandRegex.test(buttonValue)) {
|
||||
// no need to validate the bot being an actual bot; `/botmsg` will do it for us and is not abusable
|
||||
} else if (buttonName) {
|
||||
this.errorReply(`This button is not allowed: <${tagContent}>`);
|
||||
this.errorReply(`You do not have permission to use most buttons. Here are the two types you're allowed to use:`);
|
||||
this.errorReply(`1. Linking to a room: <a href="/roomid"><button>go to a place</button></a>`);
|
||||
throw new Chat.ErrorMessage(`2. Sending a message to a Bot: <button name="send" value="/msgroom BOT_ROOMID, /botmsg BOT_USERNAME, MESSAGE">send the thing</button>`);
|
||||
throw new Chat.ErrorMessage([
|
||||
`This button is not allowed: <${tagContent}>`,
|
||||
`You do not have permission to use most buttons. Here are the two types you're allowed to use:`,
|
||||
`1. Linking to a room: <a href="/roomid"><button>go to a place</button></a>`,
|
||||
`2. Sending a message to a Bot: <button name="send" value="/msgroom BOT_ROOMID, /botmsg BOT_USERNAME, MESSAGE">send the thing</button>`,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -424,8 +424,7 @@ export class Tournament extends Rooms.RoomGame<TournamentPlayer> {
|
|||
|
||||
const gameCount = user.games.size;
|
||||
if (gameCount > 4) {
|
||||
output.errorReply("Due to high load, you are limited to 4 games at the same time.");
|
||||
return;
|
||||
throw new Chat.ErrorMessage("Due to high load, you are limited to 4 games at the same time.");
|
||||
}
|
||||
|
||||
if (!Config.noipchecks) {
|
||||
|
|
@ -486,21 +485,17 @@ export class Tournament extends Rooms.RoomGame<TournamentPlayer> {
|
|||
return;
|
||||
}
|
||||
if (!(user.id in this.playerTable)) {
|
||||
output.errorReply(`${user.name} isn't in the tournament.`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`${user.name} isn't in the tournament.`);
|
||||
}
|
||||
if (!replacementUser.named) {
|
||||
output.errorReply(`${replacementUser.name} must be named to join the tournament.`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`${replacementUser.name} must be named to join the tournament.`);
|
||||
}
|
||||
if (replacementUser.id in this.playerTable) {
|
||||
output.errorReply(`${replacementUser.name} is already in the tournament.`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`${replacementUser.name} is already in the tournament.`);
|
||||
}
|
||||
if (Tournament.checkBanned(this.room, replacementUser) || Punishments.isBattleBanned(replacementUser) ||
|
||||
replacementUser.namelocked) {
|
||||
output.errorReply(`${replacementUser.name} is banned from joining tournaments.`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`${replacementUser.name} is banned from joining tournaments.`);
|
||||
}
|
||||
if ((this.room.settings.tournaments?.autoconfirmedOnly || this.autoconfirmedOnly) && !user.autoconfirmed) {
|
||||
user.popup("Signups for tournaments are only available for autoconfirmed users in this room.");
|
||||
|
|
@ -511,17 +506,14 @@ export class Tournament extends Rooms.RoomGame<TournamentPlayer> {
|
|||
for (const otherPlayer of this.players) {
|
||||
if (!otherPlayer) continue;
|
||||
const otherUser = Users.get(otherPlayer.id);
|
||||
if (otherUser &&
|
||||
otherUser.latestIp === replacementUser.latestIp &&
|
||||
if (otherUser && otherUser.latestIp === replacementUser.latestIp &&
|
||||
replacementUser.latestIp !== user.latestIp) {
|
||||
output.errorReply(`${replacementUser.name} already has an alt in the tournament.`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`${replacementUser.name} already has an alt in the tournament.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(replacementUser.id in this.room.users)) {
|
||||
output.errorReply(`${replacementUser.name} is not in this room (${this.room.title}).`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`${replacementUser.name} is not in this room (${this.room.title}).`);
|
||||
}
|
||||
const player = this.playerTable[user.id];
|
||||
if (player.pendingChallenge) {
|
||||
|
|
@ -1210,14 +1202,12 @@ function getGenerator(generator: string | undefined) {
|
|||
}
|
||||
|
||||
function createTournamentGenerator(
|
||||
generatorName: string | undefined, modifier: string | undefined, output: Chat.CommandContext
|
||||
generatorName: string | undefined, modifier: string | undefined
|
||||
) {
|
||||
const TourGenerator = getGenerator(generatorName);
|
||||
if (!TourGenerator) {
|
||||
output.errorReply(`${generatorName} is not a valid type.`);
|
||||
const generatorNames = Object.keys(TournamentGenerators).join(', ');
|
||||
output.errorReply(`Valid types: ${generatorNames}`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage([`${generatorName} is not a valid type.`, `Valid types: ${generatorNames}`]);
|
||||
}
|
||||
return new TourGenerator(modifier || '');
|
||||
}
|
||||
|
|
@ -1226,16 +1216,13 @@ function createTournament(
|
|||
isRated: boolean, generatorMod: string | undefined, name: string | undefined, output: Chat.CommandContext
|
||||
) {
|
||||
if (room.type !== 'chat') {
|
||||
output.errorReply("Tournaments can only be created in chat rooms.");
|
||||
return;
|
||||
throw new Chat.ErrorMessage("Tournaments can only be created in chat rooms.");
|
||||
}
|
||||
if (room.game) {
|
||||
output.errorReply(`You cannot have a tournament until the current room activity is over: ${room.game.title}`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`You cannot have a tournament until the current room activity is over: ${room.game.title}`);
|
||||
}
|
||||
if (Rooms.global.lockdown) {
|
||||
output.errorReply("The server is restarting soon, so a tournament cannot be created.");
|
||||
return;
|
||||
throw new Chat.ErrorMessage("The server is restarting soon, so a tournament cannot be created.");
|
||||
}
|
||||
const format = Dex.formats.get(formatId);
|
||||
if (format.effectType !== 'Format' || !format.tournamentShow) {
|
||||
|
|
@ -1247,19 +1234,15 @@ function createTournament(
|
|||
if (settings?.blockRecents && settings.recentTours && settings.recentToursLength) {
|
||||
const recentTours = settings.recentTours.map(x => x.baseFormat);
|
||||
if (recentTours.includes(format.id)) {
|
||||
output.errorReply(`A ${format.name} tournament was made too recently.`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage(`A ${format.name} tournament was made too recently.`);
|
||||
}
|
||||
}
|
||||
if (!getGenerator(generator)) {
|
||||
output.errorReply(`${generator} is not a valid type.`);
|
||||
const generators = Object.keys(TournamentGenerators).join(', ');
|
||||
output.errorReply(`Valid types: ${generators}`);
|
||||
return;
|
||||
throw new Chat.ErrorMessage([`${generator} is not a valid type.`, `Valid types: ${generators}`]);
|
||||
}
|
||||
if (playerCap && parseInt(playerCap) < 2) {
|
||||
output.errorReply("You cannot have a player cap that is less than 2.");
|
||||
return;
|
||||
throw new Chat.ErrorMessage("You cannot have a player cap that is less than 2.");
|
||||
}
|
||||
if (name?.trim().length) {
|
||||
if (output.checkChat(name) !== name) {
|
||||
|
|
@ -1272,7 +1255,7 @@ function createTournament(
|
|||
if (name.includes('|')) throw new Chat.ErrorMessage("The tournament's name cannot include the | symbol.");
|
||||
}
|
||||
const tour = room.game = new Tournament(
|
||||
room, format, createTournamentGenerator(generator, generatorMod, output)!, playerCap, isRated, name
|
||||
room, format, createTournamentGenerator(generator, generatorMod), playerCap, isRated, name
|
||||
);
|
||||
if (settings) {
|
||||
if (typeof settings.autostart === 'number') tour.setAutoStartTimeout(settings.autostart, output);
|
||||
|
|
@ -1353,14 +1336,18 @@ const commands: Chat.ChatCommands = {
|
|||
|
||||
const option = target.toLowerCase();
|
||||
if (this.meansYes(option)) {
|
||||
if (room.settings.tournaments?.announcements) return this.errorReply("Tournament announcements are already enabled.");
|
||||
if (room.settings.tournaments?.announcements) {
|
||||
throw new Chat.ErrorMessage("Tournament announcements are already enabled.");
|
||||
}
|
||||
if (!room.settings.tournaments) room.settings.tournaments = {};
|
||||
room.settings.tournaments.announcements = true;
|
||||
room.saveSettings();
|
||||
this.privateModAction(`Tournament announcements were enabled by ${user.name}`);
|
||||
this.modlog('TOUR ANNOUNCEMENTS', null, 'ON');
|
||||
} else if (this.meansNo(option)) {
|
||||
if (!room.settings.tournaments?.announcements) return this.errorReply("Tournament announcements are already disabled.");
|
||||
if (!room.settings.tournaments?.announcements) {
|
||||
throw new Chat.ErrorMessage("Tournament announcements are already disabled.");
|
||||
}
|
||||
if (!room.settings.tournaments) room.settings.tournaments = {};
|
||||
room.settings.tournaments.announcements = false;
|
||||
room.saveSettings();
|
||||
|
|
@ -1426,10 +1413,12 @@ const commands: Chat.ChatCommands = {
|
|||
const targetUserid = targetUser ? targetUser.id : toID(userid);
|
||||
if (!targetUser) return false;
|
||||
if (reason?.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
|
||||
if (Tournament.checkBanned(room, targetUser)) return this.errorReply("This user is already banned from tournaments.");
|
||||
if (Tournament.checkBanned(room, targetUser)) {
|
||||
throw new Chat.ErrorMessage("This user is already banned from tournaments.");
|
||||
}
|
||||
|
||||
const punishment = {
|
||||
type: 'TOURBAN',
|
||||
|
|
@ -1460,7 +1449,9 @@ const commands: Chat.ChatCommands = {
|
|||
|
||||
const targetUserid = toID(targetUser || toID(target));
|
||||
|
||||
if (!Tournament.checkBanned(room, targetUserid)) return this.errorReply("This user isn't banned from tournaments.");
|
||||
if (!Tournament.checkBanned(room, targetUserid)) {
|
||||
throw new Chat.ErrorMessage("This user isn't banned from tournaments.");
|
||||
}
|
||||
|
||||
if (targetUser) {
|
||||
Punishments.roomUnpunish(room, targetUserid, 'TOURBAN', false);
|
||||
|
|
@ -1484,7 +1475,7 @@ const commands: Chat.ChatCommands = {
|
|||
if (tournament.getRemainingPlayers().some(player => player.id === user.id)) {
|
||||
tournament.disqualifyUser(user.id, this, null, true);
|
||||
} else {
|
||||
this.errorReply("You have already been eliminated from this tournament.");
|
||||
throw new Chat.ErrorMessage("You have already been eliminated from this tournament.");
|
||||
}
|
||||
} else {
|
||||
tournament.removeUser(user.id, this);
|
||||
|
|
@ -1548,7 +1539,7 @@ const commands: Chat.ChatCommands = {
|
|||
const tournament = this.requireGame(Tournament);
|
||||
if (!this.runBroadcast()) return;
|
||||
if (tournament.customRules.length < 1) {
|
||||
return this.errorReply("The tournament does not have any custom rules.");
|
||||
throw new Chat.ErrorMessage("The tournament does not have any custom rules.");
|
||||
}
|
||||
this.sendReply(`|html|<div class='infobox infobox-limited'>This tournament includes:<br />${tournament.getCustomRules()}</div>`);
|
||||
},
|
||||
|
|
@ -1561,7 +1552,7 @@ const commands: Chat.ChatCommands = {
|
|||
}
|
||||
const [generatorType, cap, modifier] = target.split(',').map(item => item.trim());
|
||||
const playerCap = parseInt(cap);
|
||||
const generator = createTournamentGenerator(generatorType, modifier, this);
|
||||
const generator = createTournamentGenerator(generatorType, modifier);
|
||||
if (generator && tournament.setGenerator(generator, this)) {
|
||||
if (playerCap && playerCap >= 2) {
|
||||
tournament.playerCap = playerCap;
|
||||
|
|
@ -1595,11 +1586,11 @@ const commands: Chat.ChatCommands = {
|
|||
}
|
||||
}
|
||||
if (tournament.isTournamentStarted) {
|
||||
return this.errorReply("The player cap cannot be changed once the tournament has started.");
|
||||
throw new Chat.ErrorMessage("The player cap cannot be changed once the tournament has started.");
|
||||
}
|
||||
const option = target.toLowerCase();
|
||||
if (['0', 'infinity', 'off', 'false', 'stop', 'remove'].includes(option)) {
|
||||
if (!tournament.playerCap) return this.errorReply("The tournament does not have a player cap.");
|
||||
if (!tournament.playerCap) throw new Chat.ErrorMessage("The tournament does not have a player cap.");
|
||||
target = '0';
|
||||
}
|
||||
const playerCap = parseInt(target);
|
||||
|
|
@ -1610,10 +1601,10 @@ const commands: Chat.ChatCommands = {
|
|||
this.sendReply("Tournament cap removed.");
|
||||
} else {
|
||||
if (isNaN(playerCap) || playerCap < 2) {
|
||||
return this.errorReply("The tournament cannot have a player cap less than 2.");
|
||||
throw new Chat.ErrorMessage("The tournament cannot have a player cap less than 2.");
|
||||
}
|
||||
if (playerCap === tournament.playerCap) {
|
||||
return this.errorReply(`The tournament's player cap is already ${playerCap}.`);
|
||||
throw new Chat.ErrorMessage(`The tournament's player cap is already ${playerCap}.`);
|
||||
}
|
||||
tournament.playerCap = playerCap;
|
||||
if (Config.tourdefaultplayercap && tournament.playerCap > Config.tourdefaultplayercap) {
|
||||
|
|
@ -1642,7 +1633,7 @@ const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
const tournament = this.requireGame(Tournament);
|
||||
if (cmd === 'banlist') {
|
||||
return this.errorReply('The new syntax is: /tour rules -bannedthing, +un[banned|restricted]thing, *restrictedthing, !removedrule, addedrule');
|
||||
throw new Chat.ErrorMessage('The new syntax is: /tour rules -bannedthing, +un[banned|restricted]thing, *restrictedthing, !removedrule, addedrule');
|
||||
}
|
||||
if (!target) {
|
||||
this.sendReply("Usage: /tour rules <list of rules>");
|
||||
|
|
@ -1655,7 +1646,7 @@ const commands: Chat.ChatCommands = {
|
|||
}
|
||||
this.checkCan('tournaments', null, room);
|
||||
if (tournament.isTournamentStarted) {
|
||||
return this.errorReply("The custom rules cannot be changed once the tournament has started.");
|
||||
throw new Chat.ErrorMessage("The custom rules cannot be changed once the tournament has started.");
|
||||
}
|
||||
if (tournament.setCustomRules(target)) {
|
||||
room.addRaw(
|
||||
|
|
@ -1674,10 +1665,10 @@ const commands: Chat.ChatCommands = {
|
|||
this.checkCan('tournaments', null, room);
|
||||
const tournament = this.requireGame(Tournament);
|
||||
if (tournament.isTournamentStarted) {
|
||||
return this.errorReply("The custom rules cannot be changed once the tournament has started.");
|
||||
throw new Chat.ErrorMessage("The custom rules cannot be changed once the tournament has started.");
|
||||
}
|
||||
if (tournament.customRules.length < 1) {
|
||||
return this.errorReply("The tournament does not have any custom rules.");
|
||||
throw new Chat.ErrorMessage("The tournament does not have any custom rules.");
|
||||
}
|
||||
tournament.customRules = [];
|
||||
tournament.fullFormat = tournament.baseFormat;
|
||||
|
|
@ -1704,9 +1695,9 @@ const commands: Chat.ChatCommands = {
|
|||
if (!name || typeof name !== 'string') return;
|
||||
|
||||
if (name.length > MAX_CUSTOM_NAME_LENGTH) {
|
||||
return this.errorReply(`The tournament's name cannot exceed ${MAX_CUSTOM_NAME_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The tournament's name cannot exceed ${MAX_CUSTOM_NAME_LENGTH} characters.`);
|
||||
}
|
||||
if (name.includes('|')) return this.errorReply("The tournament's name cannot include the | symbol.");
|
||||
if (name.includes('|')) throw new Chat.ErrorMessage("The tournament's name cannot include the | symbol.");
|
||||
tournament.name = name;
|
||||
room.send(`|tournament|update|${JSON.stringify({ format: tournament.name })}`);
|
||||
this.privateModAction(`${user.name} set the tournament's name to ${tournament.name}.`);
|
||||
|
|
@ -1718,7 +1709,7 @@ const commands: Chat.ChatCommands = {
|
|||
room = this.requireRoom();
|
||||
this.checkCan('tournaments', null, room);
|
||||
const tournament = this.requireGame(Tournament);
|
||||
if (tournament.name === tournament.baseFormat) return this.errorReply("The tournament does not have a name.");
|
||||
if (tournament.name === tournament.baseFormat) throw new Chat.ErrorMessage("The tournament does not have a name.");
|
||||
tournament.name = tournament.baseFormat;
|
||||
room.send(`|tournament|update|${JSON.stringify({ format: tournament.name })}`);
|
||||
this.privateModAction(`${user.name} cleared the tournament's name.`);
|
||||
|
|
@ -1746,7 +1737,7 @@ const commands: Chat.ChatCommands = {
|
|||
const targetUser = Users.get(userid);
|
||||
const targetUserid = toID(targetUser || userid);
|
||||
if (reason?.length > MAX_REASON_LENGTH) {
|
||||
return this.errorReply(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
throw new Chat.ErrorMessage(`The reason is too long. It cannot exceed ${MAX_REASON_LENGTH} characters.`);
|
||||
}
|
||||
if (tournament.disqualifyUser(targetUserid, this, reason)) {
|
||||
this.privateModAction(`${(targetUser ? targetUser.name : targetUserid)} was disqualified from the tournament by ${user.name}${(reason ? ' (' + reason + ')' : '')}`);
|
||||
|
|
@ -1759,8 +1750,8 @@ const commands: Chat.ChatCommands = {
|
|||
this.checkCan('tournaments', null, room);
|
||||
const tournament = this.requireGame(Tournament);
|
||||
const [oldUser, newUser] = target.split(',').map(item => Users.get(item.trim()));
|
||||
if (!oldUser) return this.errorReply(`User ${oldUser} not found.`);
|
||||
if (!newUser) return this.errorReply(`User ${newUser} not found.`);
|
||||
if (!oldUser) throw new Chat.ErrorMessage(`User ${oldUser} not found.`);
|
||||
if (!newUser) throw new Chat.ErrorMessage(`User ${newUser} not found.`);
|
||||
|
||||
tournament.replaceUser(oldUser, newUser, this);
|
||||
},
|
||||
|
|
@ -1776,12 +1767,12 @@ const commands: Chat.ChatCommands = {
|
|||
const option = target.toLowerCase();
|
||||
if ((this.meansYes(option) && option !== '1') || option === 'start') {
|
||||
if (tournament.isTournamentStarted) {
|
||||
return this.errorReply("The tournament has already started.");
|
||||
throw new Chat.ErrorMessage("The tournament has already started.");
|
||||
} else if (!tournament.playerCap) {
|
||||
return this.errorReply("The tournament does not have a player cap set.");
|
||||
throw new Chat.ErrorMessage("The tournament does not have a player cap set.");
|
||||
} else {
|
||||
if (tournament.autostartcap) {
|
||||
return this.errorReply("The tournament is already set to autostart when the player cap is reached.");
|
||||
throw new Chat.ErrorMessage("The tournament is already set to autostart when the player cap is reached.");
|
||||
}
|
||||
tournament.setAutostartAtCap(true);
|
||||
this.privateModAction(`The tournament was set to autostart when the player cap is reached by ${user.name}`);
|
||||
|
|
@ -1790,14 +1781,14 @@ const commands: Chat.ChatCommands = {
|
|||
} else {
|
||||
if (option === '0' || option === 'infinity' || this.meansNo(option) || option === 'stop' || option === 'remove') {
|
||||
if (!tournament.autostartcap && tournament.autoStartTimeout === Infinity) {
|
||||
return this.errorReply("The automatic tournament start timer is already off.");
|
||||
throw new Chat.ErrorMessage("The automatic tournament start timer is already off.");
|
||||
}
|
||||
target = 'off';
|
||||
tournament.autostartcap = false;
|
||||
}
|
||||
const timeout = target.toLowerCase() === 'off' ? Infinity : Number(target) * 60 * 1000;
|
||||
if (timeout <= 0 || (timeout !== Infinity && timeout > Chat.MAX_TIMEOUT_DURATION)) {
|
||||
return this.errorReply(`The automatic tournament start timer must be set to a positive number.`);
|
||||
throw new Chat.ErrorMessage(`The automatic tournament start timer must be set to a positive number.`);
|
||||
}
|
||||
if (tournament.setAutoStartTimeout(timeout, this)) {
|
||||
this.privateModAction(`The tournament auto start timer was set to ${target} by ${user.name}`);
|
||||
|
|
@ -1821,10 +1812,10 @@ const commands: Chat.ChatCommands = {
|
|||
if (target.toLowerCase() === 'infinity' || target === '0') target = 'off';
|
||||
const timeout = target.toLowerCase() === 'off' ? Infinity : Number(target) * 60 * 1000;
|
||||
if (timeout <= 0 || (timeout !== Infinity && timeout > Chat.MAX_TIMEOUT_DURATION)) {
|
||||
return this.errorReply(`The automatic disqualification timer must be set to a positive number.`);
|
||||
throw new Chat.ErrorMessage(`The automatic disqualification timer must be set to a positive number.`);
|
||||
}
|
||||
if (timeout === tournament.autoDisqualifyTimeout) {
|
||||
return this.errorReply(`The automatic tournament disqualify timer is already set to ${target} minute(s).`);
|
||||
throw new Chat.ErrorMessage(`The automatic tournament disqualify timer is already set to ${target} minute(s).`);
|
||||
}
|
||||
if (tournament.setAutoDisqualifyTimeout(timeout, this)) {
|
||||
this.privateModAction(`The tournament auto disqualify timer was set to ${target} by ${user.name}`);
|
||||
|
|
@ -1836,7 +1827,7 @@ const commands: Chat.ChatCommands = {
|
|||
this.checkCan('tournaments', null, room);
|
||||
const tournament = this.requireGame(Tournament);
|
||||
if (tournament.autoDisqualifyTimeout === Infinity) {
|
||||
return this.errorReply("The automatic tournament disqualify timer is not set.");
|
||||
throw new Chat.ErrorMessage("The automatic tournament disqualify timer is not set.");
|
||||
}
|
||||
tournament.runAutoDisqualify(this);
|
||||
this.roomlog(`${user.name} used /tour runautodq`);
|
||||
|
|
@ -1859,12 +1850,12 @@ const commands: Chat.ChatCommands = {
|
|||
|
||||
const option = target.toLowerCase();
|
||||
if (this.meansYes(option) || option === 'allow' || option === 'allowed') {
|
||||
if (tournament.allowScouting) return this.errorReply("Scouting for this tournament is already set to allowed.");
|
||||
if (tournament.allowScouting) throw new Chat.ErrorMessage("Scouting for this tournament is already set to allowed.");
|
||||
tournament.setScouting(true);
|
||||
this.privateModAction(`The tournament was set to allow scouting by ${user.name}`);
|
||||
this.modlog('TOUR SCOUT', null, 'allow');
|
||||
} else if (this.meansNo(option) || option === 'disallow' || option === 'disallowed') {
|
||||
if (!tournament.allowScouting) return this.errorReply("Scouting for this tournament is already disabled.");
|
||||
if (!tournament.allowScouting) throw new Chat.ErrorMessage("Scouting for this tournament is already disabled.");
|
||||
tournament.setScouting(false);
|
||||
this.privateModAction(`The tournament was set to disallow scouting by ${user.name}`);
|
||||
this.modlog('TOUR SCOUT', null, 'disallow');
|
||||
|
|
@ -1888,12 +1879,12 @@ const commands: Chat.ChatCommands = {
|
|||
|
||||
const option = target.toLowerCase();
|
||||
if (this.meansYes(option) || option === 'allowed') {
|
||||
if (tournament.allowModjoin) return this.errorReply("Modjoining is already allowed for this tournament.");
|
||||
if (tournament.allowModjoin) throw new Chat.ErrorMessage("Modjoining is already allowed for this tournament.");
|
||||
tournament.setModjoin(true);
|
||||
this.privateModAction(`The tournament was set to allow modjoin by ${user.name}`);
|
||||
this.modlog('TOUR MODJOIN', null, option);
|
||||
} else if (this.meansNo(option) || option === 'disallowed') {
|
||||
if (!tournament.allowModjoin) return this.errorReply("Modjoining is already not allowed for this tournament.");
|
||||
if (!tournament.allowModjoin) throw new Chat.ErrorMessage("Modjoining is already not allowed for this tournament.");
|
||||
tournament.setModjoin(false);
|
||||
this.privateModAction(`The tournament was set to disallow modjoin by ${user.name}`);
|
||||
this.modlog('TOUR MODJOIN', null, option);
|
||||
|
|
@ -1920,7 +1911,7 @@ const commands: Chat.ChatCommands = {
|
|||
return this.parse(`/help tour`);
|
||||
}
|
||||
if (tournament.autoconfirmedOnly === value) {
|
||||
return this.errorReply(`This tournament is already set to ${value ? 'disallow' : 'allow'} non-autoconfirmed users.`);
|
||||
throw new Chat.ErrorMessage(`This tournament is already set to ${value ? 'disallow' : 'allow'} non-autoconfirmed users.`);
|
||||
}
|
||||
tournament.setAutoconfirmedOnly(value);
|
||||
this.privateModAction(`${user.name} set this tournament to ${value ? 'disallow' : 'allow'} non-autoconfirmed users.`);
|
||||
|
|
@ -2037,7 +2028,7 @@ const commands: Chat.ChatCommands = {
|
|||
const value = this.meansYes(target) ? true : this.meansNo(target) ? false : null;
|
||||
if (!target || value === null) return this.parse(`/help tour settings`);
|
||||
if (room.settings.tournaments.autoconfirmedOnly === value) {
|
||||
return this.errorReply(`All tournaments are already set to ${value ? 'disallow' : 'allow'} non-autoconfimed users.`);
|
||||
throw new Chat.ErrorMessage(`All tournaments are already set to ${value ? 'disallow' : 'allow'} non-autoconfimed users.`);
|
||||
}
|
||||
room.settings.tournaments.autoconfirmedOnly = value;
|
||||
room.saveSettings();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user