The PatternCog offers a way of creating custom message filters of moderate complexity without needing to make code changes in the bot and redeploy it. A guild can have any number of custom patterns. The commands are:
$rb_pattern add <name> <statement> - Add a new named pattern$rb_pattern remove <name> - Remove a named pattern$rb_pattern list - List all named patternsThe pattern <name> can be anything. If it contains spaces, enclose it in double quotes, e.g. "my filter".
A statement consists of one or more actions to take on a message followed by an expression defining the criteria for which messages match. For example:
reply "You can't say that word!", delete if message contains "heck"
This statement has two actions: replying, then deleting the original message. It will match any word that contains the word “heck”.
The list of actions and the matching expression are separated by the word “if”, which must be present in every statement.
One or more actions can be added to the statement. If there is more than one, they are separated with commas. Example:
delete, kick, modwarn
Available actions:
ban - Bans the user. The “reason” in the audit log will reference the pattern name.delete - Deletes the message.kick - Kicks the user. The “reason” in the audit log will reference the pattern name.modwarn - Tags the mods in a warning message. The message will offer quick actions to manually delete the message, kick the user, and ban the user (assuming the other actions didn’t already do one or more of these things)reply "message" - Makes Rocketbot automatically reply to their message with the given text.The simplest expression just consists of a message field, a comparison operator, and a value to compare it to. For example:
content contains "forbidden"
The message will match if its content contains the word "forbidden".
The available operators and type of value depends on the field being accessed.
content - The text of the message. Note this is in raw Discord markdown, so it may contain underscores, emote names, and mention codes. Available operators: ==, !=, contains, !contains, matches, !matches. Comparison value must be a quoted string.author - Who sent the message. Available operators: ==, !=. Comparison value must be a user mention (an @ that Discord will tab-complete for you).author.id - The numeric ID of the user who sent the message. Available operators: ==, !=. Comparison value must be a numeric user ID.author.name - The username of the author. Available operators: ==, !=, contains, !contains, matches, !matches. Comparison value must be a quoted string.author.joinage - How much time has elapsed from when the author joined and when the message was sent. If the user has joined and left multiple times this is the most recent join time. Available operators: ==, !=, <, >, <=, >=. Comparison value must be a timespan (see below)== - The values are equal!= - The values are not equal< - The field is less than the given value> - The field is greater than the given value<= - The field is less than or equal to the given value>= - The field is greater than or equal to the given valuecontains - The value is contained somewhere in the field value!contains - The value is not contained anywhere in the field valuematches - The given regular expression matches the field value!matches - The given regular expression does not match the field valueText values must be enclosed in double quote (") characters.
Timespans consist of one or more pairs of a number and a unit letter (“d” for days, “h” for hours, “m” for minutes, “s” for seconds). Examples:
30d - 30 days1h30m - 1 hour, 30 minutes99d9h9m9s - 99 days, 9 hours, 9 minutes, 9 secondsMultiple expressions can be combined with “and” or “or”. For example:
content contains "alpha" and content contains "bravo"
This will only match messages that contain both “alpha” and “bravo” somewhere in the text.
More complex expressions can use parentheses to clarify the order of interpretation. For example:
(content contains "foo" and author.joinage < 30m) or (content contains "bar" and author.joinage > 30m)
A message will match if it contains “foo” and the user joined in the last half hour, OR it will match if the message contains “bar” and the author joined more than a half hour ago.
Lastly, expressions can be inverted by prefixing a !. For example:
!(content contains "me" and content contains "you")
This will only match messages that do not contain both “me” and “you”. If it contains just “me” or just “you” or neither word then it will match. If both are present it will not match.
Here are examples of add commands:
Automatically delete a banned word:
$rb_pattern add "bad word" delete if content contains "darn"
Ban anyone who posts a URL within the first 30 minutes of joining the server.
$rb_pattern add "url spam" ban if author.joinage < 30m and (content contains "http://" or content contains "https://")
Automatically reply to anyone asking when lunch is.
$rb_pattern add "lunch" reply "Lunch is at noon." if content == "When is lunch?"
<statement> ::= <actions> “ if ” <expression>
<actions> ::= <action> | <action> “ ” <actions>
<action> ::= “ban” | “delete” | “kick” | “modwarn” | “reply ” <quoted_string>
<quoted_string> ::= ‘“’ <any> ‘“’
<expression> ::= <simple_expr> | <not_expr> | <paren_expr> | <compound_expr>
<simple_expr> ::= <field_name> “ ” <op> “ ” <value>
<not_expr> ::= “!” <expression>
<paren_expr> ::= “(” <expression> “)”
<compound_expr> ::= <and_expr> | <or_expr>
<and_expr> ::= <expression> “ and ” <expression>
<or_expr> ::= <expression> “ or ” <expression>
<field_name> ::= “content” | “author” | “author.id” | “author.name” | “author.joinage”
<op> ::= “==” | “!=” | “<” | “>” | “<=” | “>=” | “contains” | “!contains” | “matches” | “!matches”
<value> ::= <int> | <float> | <quoted_string> | <timespan> | <mention>
<timespan> ::= <timespan_component> | <timespan_component> <timespan>
<timespan_component> ::= <int> <timespan_unit>
<timespan_unit> ::= “d” | “h” | “m” | “s”
<mention> ::= “<@!” <int> “>”