diff --git a/config/commands.js b/chat-plugins/info.js
similarity index 80%
rename from config/commands.js
rename to chat-plugins/info.js
index 300778c7c4..2986598cb0 100644
--- a/config/commands.js
+++ b/chat-plugins/info.js
@@ -1,9 +1,9 @@
/**
- * Commands
+ * Informational Commands
* Pokemon Showdown - https://pokemonshowdown.com/
*
- * These are commands. For instance, you can define the command 'whois'
- * here, then use it by typing /whois into Pokemon Showdown.
+ * These are informational commands. For instance, you can define the command
+ * 'whois' here, then use it by typing /whois into Pokemon Showdown.
*
* For the API, see chat-plugins/COMMANDS.md
*
@@ -145,7 +145,7 @@ var commands = exports.commands = {
},
/*********************************************************
- * Informational commands
+ * Data Search Tools
*********************************************************/
pstats: 'data',
@@ -1152,6 +1152,10 @@ var commands = exports.commands = {
this.sendReplyBox("" + atkName + " is " + factor + "x effective against " + defName + ".");
},
+ /*********************************************************
+ * Informational commands
+ *********************************************************/
+
uptime: function (target, room, user) {
if (!this.canBroadcast()) return;
var uptime = process.uptime();
@@ -1694,6 +1698,11 @@ var commands = exports.commands = {
}
},
+ register: function () {
+ if (!this.canBroadcast()) return;
+ this.sendReplyBox('You will be prompted to register upon winning a rated battle. Alternatively, there is a register button in the menu in the upper right.');
+ },
+
/*********************************************************
* Miscellaneous commands
*********************************************************/
@@ -1780,24 +1789,6 @@ var commands = exports.commands = {
return this.sendReplyBox('We randomly picked: ' + Tools.escapeHTML(options.sample().trim()));
},
- register: function () {
- if (!this.canBroadcast()) return;
- this.sendReplyBox('You will be prompted to register upon winning a rated battle. Alternatively, there is a register button in the menu in the upper right.');
- },
-
- lobbychat: function (target, room, user, connection) {
- if (!Rooms.lobby) return this.popupReply("This server doesn't have a lobby.");
- target = toId(target);
- if (target === 'off') {
- user.leaveRoom(Rooms.lobby, connection.socket);
- connection.send('|users|');
- this.sendReply("You are now blocking lobby chat.");
- } else {
- user.joinRoom(Rooms.lobby, connection);
- this.sendReply("You are now receiving lobby chat.");
- }
- },
-
showimage: function (target, room, user) {
if (!target) return this.parse('/help showimage');
if (!this.can('declare', null, room)) return false;
@@ -1826,363 +1817,33 @@ var commands = exports.commands = {
this.sendReplyBox(target);
},
- a: function (target, room, user) {
- if (!this.can('rawpacket')) return false;
- // secret sysop command
- room.add(target);
+ bofrocket: function (target, room, user) {
+ if (room.id !== 'bof') return this.sendReply("The command '/bofrocket' was unrecognized. To send a message starting with '/bofrocket', type '//bofrocket'.");
+ if (!this.can('modchat', null, room)) return;
+ target = this.splitTarget(target);
+ if (!this.targetUser) return this.sendReply("User not found");
+ if (!room.users[this.targetUser.userid]) return this.sendReply("Not in bof");
+ this.targetUser.avatar = '#bofrocket';
+ room.add("" + user.name + " applied bofrocket to " + this.targetUser.name);
},
- /*********************************************************
- * Help commands
- *********************************************************/
+ showtan: function (target, room, user) {
+ if (room.id !== 'showderp') return this.sendReply("The command '/showtan' was unrecognized. To send a message starting with '/showtan', type '//showtan'.");
+ if (!this.can('modchat', null, room)) return;
+ target = this.splitTarget(target);
+ if (!this.targetUser) return this.sendReply("User not found");
+ if (!room.users[this.targetUser.userid]) return this.sendReply("Not a showderper");
+ this.targetUser.avatar = '#showtan';
+ room.add("" + user.name + " applied showtan to affected area of " + this.targetUser.name);
+ },
- commands: 'help',
- h: 'help',
- '?': 'help',
- help: function (target, room, user) {
- target = target.toLowerCase();
- var matched = false;
- if (target === 'msg' || target === 'pm' || target === 'whisper' || target === 'w') {
- matched = true;
- this.sendReply("/msg OR /whisper OR /w [username], [message] - Send a private message.");
- }
- if (target === 'r' || target === 'reply') {
- matched = true;
- this.sendReply("/reply OR /r [message] - Send a private message to the last person you received a message from, or sent a message to.");
- }
- if (target === 'avatar') {
- matched = true;
- this.sendReply("/avatar [new avatar number] - Change your trainer sprite.");
- }
- if (target === 'whois' || target === 'alts' || target === 'ip' || target === 'rooms') {
- matched = true;
- this.sendReply("/whois - Get details on yourself: alts, group, IP address, and rooms.");
- this.sendReply("/whois [username] - Get details on a username: alts (Requires: % @ & ~), group, IP address (Requires: @ & ~), and rooms.");
- }
- if (target === 'data') {
- matched = true;
- this.sendReply("/data [pokemon/item/move/ability] - Get details on this pokemon/item/move/ability/nature.");
- this.sendReply("!data [pokemon/item/move/ability] - Show everyone these details. Requires: + % @ & ~");
- }
- if (target === 'details' || target === 'dt') {
- matched = true;
- this.sendReply("/details [pokemon] - Get additional details on this pokemon/item/move/ability/nature.");
- this.sendReply("!details [pokemon] - Show everyone these details. Requires: + % @ & ~");
- }
- if (target === 'analysis') {
- matched = true;
- this.sendReply("/analysis [pokemon], [generation] - Links to the Smogon University analysis for this Pokemon in the given generation.");
- this.sendReply("!analysis [pokemon], [generation] - Shows everyone this link. Requires: + % @ & ~");
- }
- if (target === 'groups') {
- matched = true;
- this.sendReply("/groups - Explains what the + % @ & next to people's names mean.");
- this.sendReply("!groups - Show everyone that information. Requires: + % @ & ~");
- }
- if (target === 'opensource') {
- matched = true;
- this.sendReply("/opensource - Links to PS's source code repository.");
- this.sendReply("!opensource - Show everyone that information. Requires: + % @ & ~");
- }
- if (target === 'avatars') {
- matched = true;
- this.sendReply("/avatars - Explains how to change avatars.");
- this.sendReply("!avatars - Show everyone that information. Requires: + % @ & ~");
- }
- if (target === 'intro') {
- matched = true;
- this.sendReply("/intro - Provides an introduction to competitive pokemon.");
- this.sendReply("!intro - Show everyone that information. Requires: + % @ & ~");
- }
- if (target === 'cap') {
- matched = true;
- this.sendReply("/cap - Provides an introduction to the Create-A-Pokemon project.");
- this.sendReply("!cap - Show everyone that information. Requires: + % @ & ~");
- }
- if (target === 'om') {
- matched = true;
- this.sendReply("/om - Provides links to information on the Other Metagames.");
- this.sendReply("!om - Show everyone that information. Requires: + % @ & ~");
- }
- if (target === 'learn' || target === 'learnset' || target === 'learnall') {
- matched = true;
- this.sendReply("/learn [pokemon], [move, move, ...] - Displays how a Pokemon can learn the given moves, if it can at all.");
- this.sendReply("!learn [pokemon], [move, move, ...] - Show everyone that information. Requires: + % @ & ~");
- }
- if (target === 'calc' || target === 'calculator') {
- matched = true;
- this.sendReply("/calc - Provides a link to a damage calculator");
- this.sendReply("!calc - Shows everyone a link to a damage calculator. Requires: + % @ & ~");
- }
- if (target === 'away' || target === 'idle') {
- matched = true;
- this.sendReply("/away - Blocks challenges and private messages. Unblock them with /back.");
- }
- if (target === 'blockchallenges') {
- matched = true;
- this.sendReply("/blockchallenges - Blocks challenges so no one can challenge you. Unblock them with /unblockchallenges.");
- }
- if (target === 'blockpms' || target === 'ignorepms') {
- matched = true;
- this.sendReply("/blockpms - Blocks private messages. Unblock them with /unignorepms.");
- }
- if (target === 'back') {
- matched = true;
- this.sendReply("/back - Unblocks challenges and/or private messages, if either are blocked.");
- }
- if (target === 'unblockchallenges' || target === 'allowchallenges') {
- matched = true;
- this.sendReply("/unblockchallenges - Unblocks challenges so you can be challenged again. Block them with /blockchallenges.");
- }
- if (target === 'unblockpms' || target === 'unignorepms') {
- matched = true;
- this.sendReply("/unblockpms - Unblocks private messages. Block them with /blockpms.");
- }
- if (target === 'faq') {
- matched = true;
- this.sendReply("/faq [theme] - Provides a link to the FAQ. Add deviation, doubles, randomcap, restart, or staff for a link to these questions. Add all for all of them.");
- this.sendReply("!faq [theme] - Shows everyone a link to the FAQ. Add deviation, doubles, randomcap, restart, or staff for a link to these questions. Add all for all of them. Requires: + % @ & ~");
- }
- if (target === 'effectiveness' || target === 'matchup' || target === 'eff' || target === 'type') {
- matched = true;
- this.sendReply("/effectiveness [attack], [defender] - Provides the effectiveness of a move or type on another type or a Pokémon.");
- this.sendReply("!effectiveness [attack], [defender] - Shows everyone the effectiveness of a move or type on another type or a Pokémon.");
- }
- if (target === 'weakness' || target === 'weaknesses' || target === 'weak' || target === 'resist') {
- matched = true;
- this.sendReply("/weakness [pokemon] - Provides a Pokemon's resistances, weaknesses, and immunities, ignoring abilities.");
- this.sendReply("/weakness [type 1]/[type 2] - Provides a type or type combination's resistances, weaknesses, and immunities, ignoring abilities.");
- this.sendReply("!weakness [pokemon] - Shows everyone a Pokemon's resistances, weaknesses, and immunities, ignoring abilities. Requires: + % @ & ~");
- this.sendReply("!weakness [type 1]/[type 2] - Shows everyone a type or type combination's resistances, weaknesses, and immunities, ignoring abilities. Requires: + % @ & ~");
- }
- if (target === 'dexsearch' || target === 'dsearch' || target === 'ds') {
- matched = true;
- this.sendReply("/dexsearch [type], [move], [move], ... - Searches for Pokemon that fulfill the selected criteria.");
- this.sendReply("Search categories are: type, tier, color, moves, ability, gen.");
- this.sendReply("Valid colors are: green, red, blue, white, brown, yellow, purple, pink, gray and black.");
- this.sendReply("Valid tiers are: Uber/OU/BL/UU/BL2/RU/BL3/NU/PU/NFE/LC/CAP.");
- this.sendReply("Types must be followed by ' type', e.g., 'dragon type'.");
- this.sendReply("Parameters can be excluded through the use of '!', e.g., '!water type' excludes all water types.");
- this.sendReply("The parameter 'mega' can be added to search for Mega Evolutions only, and the parameters 'FE' or 'NFE' can be added to search fully or not-fully evolved Pokemon only.");
- this.sendReply("The order of the parameters does not matter.");
- }
- if (target === 'movesearch' || target === 'msearch' || target === 'ms') {
- matched = true;
- this.sendReply("/movesearch [parameter], [parameter], [parameter], ... - Searches for moves that fulfill the selected criteria.");
- this.sendReply("Search categories are: type, category, flag, status inflicted, type boosted, and numeric range for base power, pp, and accuracy.");
- this.sendReply("Types must be followed by ' type', e.g., 'dragon type'.");
- this.sendReply("Stat boosts must be preceded with 'boosts ', e.g., 'boosts attack' searches for moves that boost the attack stat.");
- this.sendReply("Inequality ranges use the characters '>' and '<' though they behave as '≥' and '≤', e.g., 'bp > 100' searches for all moves equal to and greater than 100 base power.");
- this.sendReply("Parameters can be excluded through the use of '!', e.g., !water type' excludes all water type moves.");
- this.sendReply("The order of the parameters does not matter.");
- }
- if (target === 'dice' || target === 'roll') {
- matched = true;
- this.sendReply("/dice [optional max number] - Randomly picks a number between 1 and 6, or between 1 and the number you choose.");
- this.sendReply("/dice [number of dice]d[number of sides] - Simulates rolling a number of dice, e.g., /dice 2d4 simulates rolling two 4-sided dice.");
- }
- if (target === 'pick' || target === 'pickrandom') {
- matched = true;
- this.sendReply("/pick [option], [option], ... - Randomly selects an item from a list containing 2 or more elements.");
- }
- if (target === 'invite') {
- matched = true;
- this.sendReply("/invite [username], [roomname] - Invites the player [username] to join the room [roomname].");
- }
- if (target === 'addplayer') {
- matched = true;
- this.sendReply("/addplayer [username] - Allow the specified user to join the battle as a player.");
- }
-
- // driver commands
- if (target === 'lock' || target === 'l') {
- matched = true;
- this.sendReply("/lock OR /l [username], [reason] - Locks the user from talking in all chats. Requires: % @ & ~");
- }
- if (target === 'unlock') {
- matched = true;
- this.sendReply("/unlock [username] - Unlocks the user. Requires: % @ & ~");
- }
- if (target === 'redirect' || target === 'redir') {
- matched = true;
- this.sendReply("/redirect OR /redir [username], [roomname] - Attempts to redirect the user [username] to the room [roomname]. Requires: % @ & ~");
- }
- if (target === 'modnote') {
- matched = true;
- this.sendReply("/modnote [note] - Adds a moderator note that can be read through modlog. Requires: % @ & ~");
- }
- if (target === 'forcerename' || target === 'fr') {
- matched = true;
- this.sendReply("/forcerename OR /fr [username], [reason] - Forcibly change a user's name and shows them the [reason]. Requires: % @ & ~");
- }
- if (target === 'kickbattle') {
- matched = true;
- this.sendReply("/kickbattle [username], [reason] - Kicks a user from a battle with reason. Requires: % @ & ~");
- }
- if (target === 'warn' || target === 'k') {
- matched = true;
- this.sendReply("/warn OR /k [username], [reason] - Warns a user showing them the Pokemon Showdown Rules and [reason] in an overlay. Requires: % @ & ~");
- }
- if (target === 'modlog') {
- matched = true;
- this.sendReply("/modlog [roomid|all], [n] - Roomid defaults to current room. If n is a number or omitted, display the last n lines of the moderator log. Defaults to 15. If n is not a number, search the moderator log for 'n' on room's log [roomid]. If you set [all] as [roomid], searches for 'n' on all rooms's logs. Requires: % @ & ~");
- }
- if (target === 'mute' || target === 'm') {
- matched = true;
- this.sendReply("/mute OR /m [username], [reason] - Mutes a user with reason for 7 minutes. Requires: % @ & ~");
- }
- if (target === 'hourmute' || target === 'hm') {
- matched = true;
- this.sendReply("/hourmute OR /hm [username], [reason] - Mutes a user with reason for an hour. Requires: % @ & ~");
- }
- if (target === 'unmute' || target === 'um') {
- matched = true;
- this.sendReply("/unmute [username] - Removes mute from user. Requires: % @ & ~");
- }
-
- // mod commands
- if (target === 'roomban' || target === 'rb') {
- matched = true;
- this.sendReply("/roomban [username] - Bans the user from the room you are in. Requires: @ & ~");
- }
- if (target === 'roomunban') {
- matched = true;
- this.sendReply("/roomunban [username] - Unbans the user from the room you are in. Requires: @ & ~");
- }
- if (target === 'ban' || target === 'b') {
- matched = true;
- this.sendReply("/ban OR /b [username], [reason] - Kick user from all rooms and ban user's IP address with reason. Requires: @ & ~");
- }
- if (target === 'unban') {
- matched = true;
- this.sendReply("/unban [username] - Unban a user. Requires: @ & ~");
- }
-
- // RO commands
- if (target === 'showimage') {
- matched = true;
- this.sendReply("/showimage [url], [width], [height] - Show an image. Requires: # & ~");
- }
- if (target === 'roompromote') {
- matched = true;
- this.sendReply("/roompromote [username], [group] - Promotes the user to the specified group or next ranked group. Requires: @ # & ~");
- }
- if (target === 'roomdemote') {
- matched = true;
- this.sendReply("/roomdemote [username], [group] - Demotes the user to the specified group or previous ranked group. Requires: @ # & ~");
- }
-
- // leader commands
- if (target === 'banip') {
- matched = true;
- this.sendReply("/banip [ip] - Kick users on this IP or IP range from all rooms and bans it. Accepts wildcards to ban ranges. Requires: & ~");
- }
- if (target === 'unbanip') {
- matched = true;
- this.sendReply("/unbanip [ip] - Kick users on this IP or IP range from all rooms and bans it. Accepts wildcards to ban ranges. Requires: & ~");
- }
- if (target === 'unbanall') {
- matched = true;
- this.sendReply("/unbanall - Unban all IP addresses. Requires: & ~");
- }
- if (target === 'promote') {
- matched = true;
- this.sendReply("/promote [username], [group] - Promotes the user to the specified group or next ranked group. Requires: & ~");
- }
- if (target === 'demote') {
- matched = true;
- this.sendReply("/demote [username], [group] - Demotes the user to the specified group or previous ranked group. Requires: & ~");
- }
- if (target === 'forcetie') {
- matched = true;
- this.sendReply("/forcetie - Forces the current match to tie. Requires: & ~");
- }
- if (target === 'declare') {
- matched = true;
- this.sendReply("/declare [message] - Anonymously announces a message. Requires: & ~");
- }
-
- // admin commands
- if (target === 'chatdeclare' || target === 'cdeclare') {
- matched = true;
- this.sendReply("/cdeclare [message] - Anonymously announces a message to all chatrooms on the server. Requires: ~");
- }
- if (target === 'globaldeclare' || target === 'gdeclare') {
- matched = true;
- this.sendReply("/globaldeclare [message] - Anonymously announces a message to every room on the server. Requires: ~");
- }
- if (target === 'htmlbox') {
- matched = true;
- this.sendReply("/htmlbox [message] - Displays a message, parsing HTML code contained. Requires: ~ # with global authority");
- }
- if (target === 'announce' || target === 'wall') {
- matched = true;
- this.sendReply("/announce OR /wall [message] - Makes an announcement. Requires: % @ & ~");
- }
- if (target === 'modchat') {
- matched = true;
- this.sendReply("/modchat [off/autoconfirmed/+/%/@/&/~] - Set the level of moderated chat. Requires: @ for off/autoconfirmed/+ options, & ~ for all the options");
- }
- if (target === 'hotpatch') {
- matched = true;
- this.sendReply("Hot-patching the game engine allows you to update parts of Showdown without interrupting currently-running battles. Requires: ~");
- this.sendReply("Hot-patching has greater memory requirements than restarting.");
- this.sendReply("/hotpatch chat - reload chat-commands.js");
- this.sendReply("/hotpatch battles - spawn new simulator processes");
- this.sendReply("/hotpatch formats - reload the tools.js tree, rebuild and rebroad the formats list, and also spawn new simulator processes");
- }
- if (target === 'lockdown') {
- matched = true;
- this.sendReply("/lockdown - locks down the server, which prevents new battles from starting so that the server can eventually be restarted. Requires: ~");
- }
- if (target === 'kill') {
- matched = true;
- this.sendReply("/kill - kills the server. Can't be done unless the server is in lockdown state. Requires: ~");
- }
- if (target === 'loadbanlist') {
- matched = true;
- this.sendReply("/loadbanlist - Loads the bans located at ipbans.txt. The command is executed automatically at startup. Requires: ~");
- }
- if (target === 'makechatroom') {
- matched = true;
- this.sendReply("/makechatroom [roomname] - Creates a new room named [roomname]. Requires: ~");
- }
- if (target === 'deregisterchatroom') {
- matched = true;
- this.sendReply("/deregisterchatroom [roomname] - Deletes room [roomname] after the next server restart. Requires: ~");
- }
- if (target === 'roomowner') {
- matched = true;
- this.sendReply("/roomowner [username] - Appoints [username] as a room owner. Removes official status. Requires: ~");
- }
- if (target === 'roomdeowner') {
- matched = true;
- this.sendReply("/roomdeowner [username] - Removes [username]'s status as a room owner. Requires: ~");
- }
- if (target === 'privateroom' || target === 'hiddenroom') {
- matched = true;
- this.sendReply("/privateroom [on/off] - Makes or unmakes a room private. Requires: ~");
- this.sendReply("/hiddenroom [on/off] - Makes or unmakes a room hidden. Hidden rooms will maintain global ranks of users. Requires: \u2605 ~");
- }
-
- // overall
- if (target === 'help' || target === 'h' || target === '?' || target === 'commands') {
- matched = true;
- this.sendReply("/help OR /h OR /? - Gives you help.");
- }
- if (!target) {
- this.sendReply("COMMANDS: /nick, /avatar, /rating, /whois, /msg, /reply, /ignore, /away, /back, /timestamps, /highlight");
- this.sendReply("INFORMATIONAL COMMANDS: /data, /dexsearch, /movesearch, /groups, /opensource, /avatars, /faq, /rules, /intro, /tiers, /othermetas, /learn, /analysis, /calc (replace / with ! to broadcast. Broadcasting requires: + % @ & ~)");
- if (user.group !== Config.groupsranking[0]) {
- this.sendReply("DRIVER COMMANDS: /warn, /mute, /unmute, /alts, /forcerename, /modlog, /lock, /unlock, /announce, /redirect");
- this.sendReply("MODERATOR COMMANDS: /ban, /unban, /ip");
- this.sendReply("LEADER COMMANDS: /declare, /forcetie, /forcewin, /promote, /demote, /banip, /unbanall");
- }
- this.sendReply("For an overview of room commands, use /roomhelp");
- this.sendReply("For details of a specific command, use something like: /help data");
- } else if (!matched) {
- this.sendReply("Help for the command '" + target + "' was not found. Try /help for general help");
- }
+ cpgtan: function (target, room, user) {
+ if (room.id !== 'cpg') return this.sendReply("The command '/cpgtan' was unrecognized. To send a message starting with '/cpgtan', type '//cpgtan'.");
+ if (!this.can('modchat', null, room)) return;
+ target = this.splitTarget(target);
+ if (!this.targetUser) return this.sendReply("User not found");
+ if (!room.users[this.targetUser.userid]) return this.sendReply("Not a cpger");
+ this.targetUser.avatar = '#cpgtan';
+ room.add("" + user.name + " applied cpgtan to affected area of " + this.targetUser.name);
}
-
};
diff --git a/command-parser.js b/command-parser.js
index f209bcfddd..9ea3b7d940 100644
--- a/command-parser.js
+++ b/command-parser.js
@@ -7,9 +7,9 @@
*
* Individual commands are put in:
* commands.js - "core" commands that shouldn't be modified
- * config/commands.js - other commands that can be safely modified
+ * chat-plugins/ - other commands that can be safely modified
*
- * The command API is (mostly) documented in config/commands.js
+ * The command API is (mostly) documented in chat-plugins/COMMANDS.md
*
* @license MIT license
*/
@@ -38,11 +38,6 @@ var fs = require('fs');
var commands = exports.commands = require('./commands.js').commands;
-var customCommands = require('./config/commands.js');
-if (customCommands && customCommands.commands) {
- Object.merge(commands, customCommands.commands);
-}
-
// Install plug-in commands
fs.readdirSync('./chat-plugins').forEach(function (file) {
diff --git a/commands.js b/commands.js
index 1a6f32b11a..36fcd67c5a 100644
--- a/commands.js
+++ b/commands.js
@@ -2069,6 +2069,365 @@ var commands = exports.commands = {
}
}
user.rename(targetName, targetToken, targetAuth, connection);
+ },
+
+ a: function (target, room, user) {
+ if (!this.can('rawpacket')) return false;
+ // secret sysop command
+ room.add(target);
+ },
+
+ /*********************************************************
+ * Help commands
+ *********************************************************/
+
+ commands: 'help',
+ h: 'help',
+ '?': 'help',
+ help: function (target, room, user) {
+ target = target.toLowerCase();
+ var matched = false;
+ if (target === 'msg' || target === 'pm' || target === 'whisper' || target === 'w') {
+ matched = true;
+ this.sendReply("/msg OR /whisper OR /w [username], [message] - Send a private message.");
+ }
+ if (target === 'r' || target === 'reply') {
+ matched = true;
+ this.sendReply("/reply OR /r [message] - Send a private message to the last person you received a message from, or sent a message to.");
+ }
+ if (target === 'avatar') {
+ matched = true;
+ this.sendReply("/avatar [new avatar number] - Change your trainer sprite.");
+ }
+ if (target === 'whois' || target === 'alts' || target === 'ip' || target === 'rooms') {
+ matched = true;
+ this.sendReply("/whois - Get details on yourself: alts, group, IP address, and rooms.");
+ this.sendReply("/whois [username] - Get details on a username: alts (Requires: % @ & ~), group, IP address (Requires: @ & ~), and rooms.");
+ }
+ if (target === 'data') {
+ matched = true;
+ this.sendReply("/data [pokemon/item/move/ability] - Get details on this pokemon/item/move/ability/nature.");
+ this.sendReply("!data [pokemon/item/move/ability] - Show everyone these details. Requires: + % @ & ~");
+ }
+ if (target === 'details' || target === 'dt') {
+ matched = true;
+ this.sendReply("/details [pokemon] - Get additional details on this pokemon/item/move/ability/nature.");
+ this.sendReply("!details [pokemon] - Show everyone these details. Requires: + % @ & ~");
+ }
+ if (target === 'analysis') {
+ matched = true;
+ this.sendReply("/analysis [pokemon], [generation] - Links to the Smogon University analysis for this Pokemon in the given generation.");
+ this.sendReply("!analysis [pokemon], [generation] - Shows everyone this link. Requires: + % @ & ~");
+ }
+ if (target === 'groups') {
+ matched = true;
+ this.sendReply("/groups - Explains what the + % @ & next to people's names mean.");
+ this.sendReply("!groups - Show everyone that information. Requires: + % @ & ~");
+ }
+ if (target === 'opensource') {
+ matched = true;
+ this.sendReply("/opensource - Links to PS's source code repository.");
+ this.sendReply("!opensource - Show everyone that information. Requires: + % @ & ~");
+ }
+ if (target === 'avatars') {
+ matched = true;
+ this.sendReply("/avatars - Explains how to change avatars.");
+ this.sendReply("!avatars - Show everyone that information. Requires: + % @ & ~");
+ }
+ if (target === 'intro') {
+ matched = true;
+ this.sendReply("/intro - Provides an introduction to competitive pokemon.");
+ this.sendReply("!intro - Show everyone that information. Requires: + % @ & ~");
+ }
+ if (target === 'cap') {
+ matched = true;
+ this.sendReply("/cap - Provides an introduction to the Create-A-Pokemon project.");
+ this.sendReply("!cap - Show everyone that information. Requires: + % @ & ~");
+ }
+ if (target === 'om') {
+ matched = true;
+ this.sendReply("/om - Provides links to information on the Other Metagames.");
+ this.sendReply("!om - Show everyone that information. Requires: + % @ & ~");
+ }
+ if (target === 'learn' || target === 'learnset' || target === 'learnall') {
+ matched = true;
+ this.sendReply("/learn [pokemon], [move, move, ...] - Displays how a Pokemon can learn the given moves, if it can at all.");
+ this.sendReply("!learn [pokemon], [move, move, ...] - Show everyone that information. Requires: + % @ & ~");
+ }
+ if (target === 'calc' || target === 'calculator') {
+ matched = true;
+ this.sendReply("/calc - Provides a link to a damage calculator");
+ this.sendReply("!calc - Shows everyone a link to a damage calculator. Requires: + % @ & ~");
+ }
+ if (target === 'away' || target === 'idle') {
+ matched = true;
+ this.sendReply("/away - Blocks challenges and private messages. Unblock them with /back.");
+ }
+ if (target === 'blockchallenges') {
+ matched = true;
+ this.sendReply("/blockchallenges - Blocks challenges so no one can challenge you. Unblock them with /unblockchallenges.");
+ }
+ if (target === 'blockpms' || target === 'ignorepms') {
+ matched = true;
+ this.sendReply("/blockpms - Blocks private messages. Unblock them with /unignorepms.");
+ }
+ if (target === 'back') {
+ matched = true;
+ this.sendReply("/back - Unblocks challenges and/or private messages, if either are blocked.");
+ }
+ if (target === 'unblockchallenges' || target === 'allowchallenges') {
+ matched = true;
+ this.sendReply("/unblockchallenges - Unblocks challenges so you can be challenged again. Block them with /blockchallenges.");
+ }
+ if (target === 'unblockpms' || target === 'unignorepms') {
+ matched = true;
+ this.sendReply("/unblockpms - Unblocks private messages. Block them with /blockpms.");
+ }
+ if (target === 'faq') {
+ matched = true;
+ this.sendReply("/faq [theme] - Provides a link to the FAQ. Add deviation, doubles, randomcap, restart, or staff for a link to these questions. Add all for all of them.");
+ this.sendReply("!faq [theme] - Shows everyone a link to the FAQ. Add deviation, doubles, randomcap, restart, or staff for a link to these questions. Add all for all of them. Requires: + % @ & ~");
+ }
+ if (target === 'effectiveness' || target === 'matchup' || target === 'eff' || target === 'type') {
+ matched = true;
+ this.sendReply("/effectiveness [attack], [defender] - Provides the effectiveness of a move or type on another type or a Pokémon.");
+ this.sendReply("!effectiveness [attack], [defender] - Shows everyone the effectiveness of a move or type on another type or a Pokémon.");
+ }
+ if (target === 'weakness' || target === 'weaknesses' || target === 'weak' || target === 'resist') {
+ matched = true;
+ this.sendReply("/weakness [pokemon] - Provides a Pokemon's resistances, weaknesses, and immunities, ignoring abilities.");
+ this.sendReply("/weakness [type 1]/[type 2] - Provides a type or type combination's resistances, weaknesses, and immunities, ignoring abilities.");
+ this.sendReply("!weakness [pokemon] - Shows everyone a Pokemon's resistances, weaknesses, and immunities, ignoring abilities. Requires: + % @ & ~");
+ this.sendReply("!weakness [type 1]/[type 2] - Shows everyone a type or type combination's resistances, weaknesses, and immunities, ignoring abilities. Requires: + % @ & ~");
+ }
+ if (target === 'dexsearch' || target === 'dsearch' || target === 'ds') {
+ matched = true;
+ this.sendReply("/dexsearch [type], [move], [move], ... - Searches for Pokemon that fulfill the selected criteria.");
+ this.sendReply("Search categories are: type, tier, color, moves, ability, gen.");
+ this.sendReply("Valid colors are: green, red, blue, white, brown, yellow, purple, pink, gray and black.");
+ this.sendReply("Valid tiers are: Uber/OU/BL/UU/BL2/RU/BL3/NU/PU/NFE/LC/CAP.");
+ this.sendReply("Types must be followed by ' type', e.g., 'dragon type'.");
+ this.sendReply("Parameters can be excluded through the use of '!', e.g., '!water type' excludes all water types.");
+ this.sendReply("The parameter 'mega' can be added to search for Mega Evolutions only, and the parameters 'FE' or 'NFE' can be added to search fully or not-fully evolved Pokemon only.");
+ this.sendReply("The order of the parameters does not matter.");
+ }
+ if (target === 'movesearch' || target === 'msearch' || target === 'ms') {
+ matched = true;
+ this.sendReply("/movesearch [parameter], [parameter], [parameter], ... - Searches for moves that fulfill the selected criteria.");
+ this.sendReply("Search categories are: type, category, flag, status inflicted, type boosted, and numeric range for base power, pp, and accuracy.");
+ this.sendReply("Types must be followed by ' type', e.g., 'dragon type'.");
+ this.sendReply("Stat boosts must be preceded with 'boosts ', e.g., 'boosts attack' searches for moves that boost the attack stat.");
+ this.sendReply("Inequality ranges use the characters '>' and '<' though they behave as '≥' and '≤', e.g., 'bp > 100' searches for all moves equal to and greater than 100 base power.");
+ this.sendReply("Parameters can be excluded through the use of '!', e.g., !water type' excludes all water type moves.");
+ this.sendReply("The order of the parameters does not matter.");
+ }
+ if (target === 'dice' || target === 'roll') {
+ matched = true;
+ this.sendReply("/dice [optional max number] - Randomly picks a number between 1 and 6, or between 1 and the number you choose.");
+ this.sendReply("/dice [number of dice]d[number of sides] - Simulates rolling a number of dice, e.g., /dice 2d4 simulates rolling two 4-sided dice.");
+ }
+ if (target === 'pick' || target === 'pickrandom') {
+ matched = true;
+ this.sendReply("/pick [option], [option], ... - Randomly selects an item from a list containing 2 or more elements.");
+ }
+ if (target === 'invite') {
+ matched = true;
+ this.sendReply("/invite [username], [roomname] - Invites the player [username] to join the room [roomname].");
+ }
+ if (target === 'addplayer') {
+ matched = true;
+ this.sendReply("/addplayer [username] - Allow the specified user to join the battle as a player.");
+ }
+
+ // driver commands
+ if (target === 'lock' || target === 'l') {
+ matched = true;
+ this.sendReply("/lock OR /l [username], [reason] - Locks the user from talking in all chats. Requires: % @ & ~");
+ }
+ if (target === 'unlock') {
+ matched = true;
+ this.sendReply("/unlock [username] - Unlocks the user. Requires: % @ & ~");
+ }
+ if (target === 'redirect' || target === 'redir') {
+ matched = true;
+ this.sendReply("/redirect OR /redir [username], [roomname] - Attempts to redirect the user [username] to the room [roomname]. Requires: % @ & ~");
+ }
+ if (target === 'modnote') {
+ matched = true;
+ this.sendReply("/modnote [note] - Adds a moderator note that can be read through modlog. Requires: % @ & ~");
+ }
+ if (target === 'forcerename' || target === 'fr') {
+ matched = true;
+ this.sendReply("/forcerename OR /fr [username], [reason] - Forcibly change a user's name and shows them the [reason]. Requires: % @ & ~");
+ }
+ if (target === 'kickbattle') {
+ matched = true;
+ this.sendReply("/kickbattle [username], [reason] - Kicks a user from a battle with reason. Requires: % @ & ~");
+ }
+ if (target === 'warn' || target === 'k') {
+ matched = true;
+ this.sendReply("/warn OR /k [username], [reason] - Warns a user showing them the Pokemon Showdown Rules and [reason] in an overlay. Requires: % @ & ~");
+ }
+ if (target === 'modlog') {
+ matched = true;
+ this.sendReply("/modlog [roomid|all], [n] - Roomid defaults to current room. If n is a number or omitted, display the last n lines of the moderator log. Defaults to 15. If n is not a number, search the moderator log for 'n' on room's log [roomid]. If you set [all] as [roomid], searches for 'n' on all rooms's logs. Requires: % @ & ~");
+ }
+ if (target === 'mute' || target === 'm') {
+ matched = true;
+ this.sendReply("/mute OR /m [username], [reason] - Mutes a user with reason for 7 minutes. Requires: % @ & ~");
+ }
+ if (target === 'hourmute' || target === 'hm') {
+ matched = true;
+ this.sendReply("/hourmute OR /hm [username], [reason] - Mutes a user with reason for an hour. Requires: % @ & ~");
+ }
+ if (target === 'unmute' || target === 'um') {
+ matched = true;
+ this.sendReply("/unmute [username] - Removes mute from user. Requires: % @ & ~");
+ }
+
+ // mod commands
+ if (target === 'roomban' || target === 'rb') {
+ matched = true;
+ this.sendReply("/roomban [username] - Bans the user from the room you are in. Requires: @ & ~");
+ }
+ if (target === 'roomunban') {
+ matched = true;
+ this.sendReply("/roomunban [username] - Unbans the user from the room you are in. Requires: @ & ~");
+ }
+ if (target === 'ban' || target === 'b') {
+ matched = true;
+ this.sendReply("/ban OR /b [username], [reason] - Kick user from all rooms and ban user's IP address with reason. Requires: @ & ~");
+ }
+ if (target === 'unban') {
+ matched = true;
+ this.sendReply("/unban [username] - Unban a user. Requires: @ & ~");
+ }
+
+ // RO commands
+ if (target === 'showimage') {
+ matched = true;
+ this.sendReply("/showimage [url], [width], [height] - Show an image. Requires: # & ~");
+ }
+ if (target === 'roompromote') {
+ matched = true;
+ this.sendReply("/roompromote [username], [group] - Promotes the user to the specified group or next ranked group. Requires: @ # & ~");
+ }
+ if (target === 'roomdemote') {
+ matched = true;
+ this.sendReply("/roomdemote [username], [group] - Demotes the user to the specified group or previous ranked group. Requires: @ # & ~");
+ }
+
+ // leader commands
+ if (target === 'banip') {
+ matched = true;
+ this.sendReply("/banip [ip] - Kick users on this IP or IP range from all rooms and bans it. Accepts wildcards to ban ranges. Requires: & ~");
+ }
+ if (target === 'unbanip') {
+ matched = true;
+ this.sendReply("/unbanip [ip] - Kick users on this IP or IP range from all rooms and bans it. Accepts wildcards to ban ranges. Requires: & ~");
+ }
+ if (target === 'unbanall') {
+ matched = true;
+ this.sendReply("/unbanall - Unban all IP addresses. Requires: & ~");
+ }
+ if (target === 'promote') {
+ matched = true;
+ this.sendReply("/promote [username], [group] - Promotes the user to the specified group or next ranked group. Requires: & ~");
+ }
+ if (target === 'demote') {
+ matched = true;
+ this.sendReply("/demote [username], [group] - Demotes the user to the specified group or previous ranked group. Requires: & ~");
+ }
+ if (target === 'forcetie') {
+ matched = true;
+ this.sendReply("/forcetie - Forces the current match to tie. Requires: & ~");
+ }
+ if (target === 'declare') {
+ matched = true;
+ this.sendReply("/declare [message] - Anonymously announces a message. Requires: & ~");
+ }
+
+ // admin commands
+ if (target === 'chatdeclare' || target === 'cdeclare') {
+ matched = true;
+ this.sendReply("/cdeclare [message] - Anonymously announces a message to all chatrooms on the server. Requires: ~");
+ }
+ if (target === 'globaldeclare' || target === 'gdeclare') {
+ matched = true;
+ this.sendReply("/globaldeclare [message] - Anonymously announces a message to every room on the server. Requires: ~");
+ }
+ if (target === 'htmlbox') {
+ matched = true;
+ this.sendReply("/htmlbox [message] - Displays a message, parsing HTML code contained. Requires: ~ # with global authority");
+ }
+ if (target === 'announce' || target === 'wall') {
+ matched = true;
+ this.sendReply("/announce OR /wall [message] - Makes an announcement. Requires: % @ & ~");
+ }
+ if (target === 'modchat') {
+ matched = true;
+ this.sendReply("/modchat [off/autoconfirmed/+/%/@/&/~] - Set the level of moderated chat. Requires: @ for off/autoconfirmed/+ options, & ~ for all the options");
+ }
+ if (target === 'hotpatch') {
+ matched = true;
+ this.sendReply("Hot-patching the game engine allows you to update parts of Showdown without interrupting currently-running battles. Requires: ~");
+ this.sendReply("Hot-patching has greater memory requirements than restarting.");
+ this.sendReply("/hotpatch chat - reload chat-commands.js");
+ this.sendReply("/hotpatch battles - spawn new simulator processes");
+ this.sendReply("/hotpatch formats - reload the tools.js tree, rebuild and rebroad the formats list, and also spawn new simulator processes");
+ }
+ if (target === 'lockdown') {
+ matched = true;
+ this.sendReply("/lockdown - locks down the server, which prevents new battles from starting so that the server can eventually be restarted. Requires: ~");
+ }
+ if (target === 'kill') {
+ matched = true;
+ this.sendReply("/kill - kills the server. Can't be done unless the server is in lockdown state. Requires: ~");
+ }
+ if (target === 'loadbanlist') {
+ matched = true;
+ this.sendReply("/loadbanlist - Loads the bans located at ipbans.txt. The command is executed automatically at startup. Requires: ~");
+ }
+ if (target === 'makechatroom') {
+ matched = true;
+ this.sendReply("/makechatroom [roomname] - Creates a new room named [roomname]. Requires: ~");
+ }
+ if (target === 'deregisterchatroom') {
+ matched = true;
+ this.sendReply("/deregisterchatroom [roomname] - Deletes room [roomname] after the next server restart. Requires: ~");
+ }
+ if (target === 'roomowner') {
+ matched = true;
+ this.sendReply("/roomowner [username] - Appoints [username] as a room owner. Removes official status. Requires: ~");
+ }
+ if (target === 'roomdeowner') {
+ matched = true;
+ this.sendReply("/roomdeowner [username] - Removes [username]'s status as a room owner. Requires: ~");
+ }
+ if (target === 'privateroom' || target === 'hiddenroom') {
+ matched = true;
+ this.sendReply("/privateroom [on/off] - Makes or unmakes a room private. Requires: ~");
+ this.sendReply("/hiddenroom [on/off] - Makes or unmakes a room hidden. Hidden rooms will maintain global ranks of users. Requires: \u2605 ~");
+ }
+
+ // overall
+ if (target === 'help' || target === 'h' || target === '?' || target === 'commands') {
+ matched = true;
+ this.sendReply("/help OR /h OR /? - Gives you help.");
+ }
+ if (!target) {
+ this.sendReply("COMMANDS: /nick, /avatar, /rating, /whois, /msg, /reply, /ignore, /away, /back, /timestamps, /highlight");
+ this.sendReply("INFORMATIONAL COMMANDS: /data, /dexsearch, /movesearch, /groups, /opensource, /avatars, /faq, /rules, /intro, /tiers, /othermetas, /learn, /analysis, /calc (replace / with ! to broadcast. Broadcasting requires: + % @ & ~)");
+ if (user.group !== Config.groupsranking[0]) {
+ this.sendReply("DRIVER COMMANDS: /warn, /mute, /unmute, /alts, /forcerename, /modlog, /lock, /unlock, /announce, /redirect");
+ this.sendReply("MODERATOR COMMANDS: /ban, /unban, /ip");
+ this.sendReply("LEADER COMMANDS: /declare, /forcetie, /forcewin, /promote, /demote, /banip, /unbanall");
+ }
+ this.sendReply("For an overview of room commands, use /roomhelp");
+ this.sendReply("For details of a specific command, use something like: /help data");
+ } else if (!matched) {
+ this.sendReply("Help for the command '" + target + "' was not found. Try /help for general help");
+ }
}
};