File size: 9,644 Bytes
5c2ed06
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
Pokémon Showdown Command API
========================================================================

Defining a Command
------------------------------------------------------------------------

You can define the commands such as 'whois', then use them by typing
`/whois` into Pokémon Showdown.

A command can be in the form:

	ip: 'whois',

This is called an alias: it makes it so `/ip` does the same thing as
`/whois`.

But to actually define a command, it's a function:

	avatars(target, room, user) {
		if (!this.runBroadcast()) return;
		this.sendReplyBox(
			'You can <button name="avatars">change ' +
			'your avatar</button> by clicking on it in the <button ' +
			'name="openOptions"><i class="icon-cog"></i> Options' +
			'</button> menu in the upper right. Custom avatars are ' +
			'only obtainable by staff.'
		);
	}


Parameters
------------------------------------------------------------------------

Commands are actually passed six parameters:

	function (target, room, user, connection, cmd, message)

Most of the time, you only need the first three, though.

- `target` = the part of the message after the command
- `room` = the room object the message was sent to  
  (The room name is `room.roomid`)
- `user` = the user object that sent the message  
  (The user's name is `user.name`)
- `connection` = the connection that the message was sent from
- `cmd` = the name of the command
- `message` = the entire message sent by the user

For instance, if a user types in `/msg zarel, hello`,

	`target` = `"zarel, hello"`
	`cmd` = `"msg"`
	`message` = `"/msg zarel, hello"`

Commands return the message the user should say. If they don't
return anything or return something falsy, the user won't say
anything.


Help Entries
------------------------------------------------------------------------

A `/help` entry can be added for a command by adding a command in the
form `<command>help: ["<help text>"],`, where `<command>` is the primary function
name, followed by an array or function.

If the help entry is an array, each element of the array will be sent as a
new line. If the help entry is a function, the help command will execute
that function.

As an example:

	ip: 'whois',
	rooms: 'whois',
	whois(target, room, user) {
		<function body>
	},
	whoishelp:[
		"/whois - Get details on yourself: alts, group, IP address,
		and rooms.",
		"/whois [username] - Get details on a username: group and rooms.",
	],

`/help whois` will send the information in `whoishelp`.


Plines
------------------------------------------------------------------------

A lot of the functions refering "plines". A pline is a protocol line,
documented in [PROTOCOL.md][https://github.com/smogon/pokemon-showdown/blob/master/PROTOCOL.md]

Plines are the ones that usually start with `|MESSAGETYPE|`, but a pline
that doesn't start with `|` will be shown as text directly to the user.

Note that currently, most plines starting with `|` break horribly when
sent in PMs, so please be careful about that.


Functions
------------------------------------------------------------------------

Commands have access to the following functions:

`this.sendReply(pline)`
*	Sends a pline to the room/PM the user typed the command into.

`this.sendReplyBox(html)`
*	Same as sendReply, but shows it in a box, and you can put HTML in it.

`this.popupReply(message)`
*	Shows a popup in the window the user typed the command into.

`this.add(pline)`
*	Adds a pline to the room so that everyone can see it.
	This is like `this.sendReply`, except everyone in the room sees it,
	instead of just the user that typed the command.

`this.send(pline)`
*	Sends a pline to the room so that everyone can see it.
	This is like `this.add`, except it's not logged, and users who join the
	room later won't see it in the log, and if it's a battle, it won't show
	up in saved replays.
	You USUALLY want to use `this.add` instead.

`this.roomlog(pline)`
*	Log a pline to the room's log without sending it to anyone. This is
	like `this.add`, except no one will see it.

`this.addModAction(message)`
*	Like `this.add`, but the message is treated like a chat message from the
	user who used the command (notifying and potentially highlighting other
	users). This does not log anything into the modlog.

`this.modlog(action, user, note, options)`
*	Adds a log line into the room's modlog, similar to `this.globalModlog`.
	The arguments `user` (the targeted user), `note` (details), and `options`
	(no ip, no alts) are optional.

`this.checkCan(permission)`  
`this.checkCan(permission, targetUser)`
*	Checks if the user has the permission to do something, or if a
	targetUser is passed, check if the user has permission to do it to that
	user. Will automatically give the user an "Access denied" message, and
	stop the command there, if the user doesn't have permission: use
	`user.can()` if you don't want that message.

	Should usually be near the top of the command, like:

		this.checkCan('potd');

`this.runBroadcast()`
*	Signifies that a message can be broadcast, as long as the user has
	permission to. This will check to see if the user used `!command`
	instead of `/command`. If so, it will check to see if the user has
	permission to broadcast (by default, voice+ can), and return `false` if
	not. Otherwise, it will add the message to the room, and turn on the
	flag `this.broadcasting`, so that `this.sendReply` and `this.sendReplyBox`
	will broadcast to the room instead of just the user that used the
	command.

	Should usually be near the top of the command, like:

		this.checkBroadcast();

`this.runBroadcast(suppressMessage)`
*	Functionally the same as `this.canBroadcast()`. However, it will look as
	if the user had written the text `suppressMessage`.

`this.checkChat()`
*	Checks to see if the user can speak in the room. Returns false if the
	user can't speak (is muted, the room has modchat on, etc), or true
	otherwise.

	Should usually be near the top of the command, like:

		this.checkChat();

`this.checkChat(message, room)`
*	Checks to see if the user can say the message in the room.
	If a room is not specified, it will default to the current one.
	If it has a falsy value, the check won't be attached to any room.
	In addition to running the checks from `this.checkChat()`, it also checks
	to see if the message has any banned words, is too long, or was just
	sent by the user. Returns the filtered message, or a falsy value if the
	user can't speak.

	Should usually be near the top of the command, like:

		target = this.checkChat(target);
		if (!target) return false;

`this.parse(message, inNamespace)`
*	Runs the message as if the user had typed it in.

	Mostly useful for giving help messages, like for commands that require
	a target:

		if (!target) return this.parse('/help msg');

	If `inNamespace` is true, then the message is parsed in that
	corresponding namespace:

		// command msg is in namespace test. (ie. /test msg)
		this.parse('/help', true);
		// is parsed as if the user said '/test help'

	After 10 levels of recursion (calling `this.parse` from a command called
	by `this.parse` from a command called by `this.parse` etc) we will assume
	it's a bug in your command and error out.

`this.getUserOrSelf(target, exactName)`
*	If `target` is blank, returns the user that sent the message.
	Otherwise, returns the user with the username in target, or a falsy
	value if no user with that username exists.
	By default, this will track users across name changes. However, if
	`exactName` is true, it will enforce exact matches.

`this.splitUser(target, exactName)`
*	Splits a target in the form `<user>, <rest>` into its constituent parts;
	returning
	`{targetUser: User | null, targetUsername: string, inputUsername: string, rest: string}`.
	`inputUsername` will be exactly `<user>` and `rest` will be `<rest>`.

	If a user doesn't exist (because they are offline or otherwise),
	`targetUser` will be null but `targetUsername` will be `inputUsername`.
	If `targetUser` exists, `targetUsername` will be `targetUser.name`
	(fixing capitalization and following name changes if applicable).

	By default, this will track users across name changes. However, if
	`exactName` is true, it will enforce exact matches.

Unless otherwise specified, these functions will return undefined, so you
can `return this.sendReply` or something to send a reply and stop the command
there.


Namespace Commands
------------------------------------------------------------------------

A command can also be an object, in which case is treated like
a namespace:

	game: {
		play(target, room, user) {
			user.isPlaying = true;
			this.sendReply("Playing.");
		},
		stop(target, room, user) {
			user.isPlaying = false;
			this.sendReply("Stopped.");
		}
	}

These commands can be called by `/game play` and `/game stop`.

Namespaces help organise commands, and nest them under
one main command.

Note: Multiple namespaces can be nested, but the final (innermost)
command must be a function.

Namespace objects can have help entries and so can the internal
commands:

	game: {
		play(target, room, user) {
			user.isPlaying = true;
			this.sendReply("Playing.");
		},
		playhelp: ["Tells you if the user is playing."],
		stop(target, room, user) {
			user.isPlaying = false;
			this.sendReply("Stopped.");
		},
	},
	gamehelp: [
		"commands for /game are:",
		"/game play - Tells you if the user is playing.",
		"/game stop - Tells you if the user stopped playing.",
	],

The help entries are accessed with `/help game play` and `/help game`
respectively. If help for `/help game stop` doesn't exist, it will show
help for `/help game` instead.