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"); + } } };