RATScript v2 / Complete Reference
Scripting Reference
The current RAT 5 event language: syntax, values, scopes, reusable functions, telnet capture, runtime limits, and built-ins.
Start here
RATScript is a small language for answering three questions: what happened, should RAT react, and what should RAT do. You can begin by editing a template; you do not need to memorize the language or the function list.
Names beginning with $, such as $player.name, are facts supplied by the current event.
Use if ... then to run actions only when a condition is true.
Functions such as log(...), discord_send(...), and gs_broadcast(...) do the work.
# This script runs when a new player joins.
log(format("Welcome, {0}!", $player.name))
Contents
- Start here
- Execution model and source layout
- Statements and control flow
- Values, operators, and conditions
- Variables, objects, and scopes
- Global runtime variables
- Event variables
- String interpolation
- Persistent shared state
- Reusable functions
- Telnet commands and capture
- Built-in functions
- Limits and failure behavior
- Complete examples
1. Execution model and source layout
rat5.v2 is the supported event-script version. RAT selects enabled definitions for an event, builds read-only event and runtime values, validates the script, and executes statements from top to bottom. Scripts can calculate values, branch, update definition-local persistent state, call reusable functions, and perform controlled side effects.
- Event and runtime values are fixed for the logical execution.
- Validation rejects unknown names, invalid object paths, malformed blocks, and incorrect argument counts.
- Only the first matching branch of an
ifblock executes. wait(...)suspends this execution without blocking other scripts.- Successful
global.*mutations are persisted for this definition.
Source layout
- Statements are separated by line breaks; semicolons are unnecessary.
#starts a comment outside a quoted string or telnet command.- Strings use double quotes and support
\",\\,\n,\r, and\t. - Keywords and function names are case-insensitive. Lowercase is used throughout this reference.
- Indentation is optional but recommended.
# A minimal chat command
set local.message = lower(trim($chat_content))
if local.message == "!hello" then
set global.hello_count = coalesce(global.hello_count, 0) + 1
gs_broadcast(format("Hello {0}! Use #{1}", $player.name, global.hello_count), "say")
end
2. Statements and control flow
set and unset
set assigns a local or persistent global value. Object paths are created as needed. unset removes the selected local or global path and its descendants.
set local.normalized = lower(trim($chat_content))
set global.last_player = $player.name
unset global.last_error
if, else if, else, and end
if $players_online == 0 then
log("Server is empty")
else if $players_online < $players_max then
log("Slots are available")
else
log("Server is full")
end
Calls, actions, and return
Value-returning calls may appear inside expressions. Action calls are complete statements. return is valid inside reusable functions and may return a value or stop with no value.
wait(milliseconds)
wait suspends the current logical execution and resumes from the following statement. Its limits and restart behavior are documented below.
3. Values, operators, and conditions
RATScript values are null, strings, numbers, booleans, and objects. Function results and variables retain their type; interpolation converts values to display text.
| Precedence | Operators | Purpose |
|---|---|---|
| 1 | () | Grouping and function calls |
| 2 | not, unary - | Boolean negation and numeric negation |
| 3 | *, /, % | Multiplication, division, remainder |
| 4 | +, - | Addition, concatenation, subtraction |
| 5 | <, <=, >, >= | Numeric or compatible ordered comparison |
| 6 | ==, != | Equality and inequality |
| 7 | and | Short-circuit conjunction |
| 8 | or | Short-circuit disjunction |
null, false, numeric zero, and an empty string are falsey; other values are truthy. Prefer explicit comparisons and exists(...) when optional data matters.
4. Variables, objects, and scopes
| Form | Lifetime | Writable | Use |
|---|---|---|---|
$name, $object.field | Current execution | No | Event-specific and runtime values supplied by RAT. |
local.name | Current call frame | Yes | Temporary calculations and structured values. |
global.name | Persistent per event definition | Yes | Counters, timestamps, modes, and other shared state. |
| Reusable-function parameter name | Current function call | No | Arguments declared by function name(parameter). |
Objects use dotted paths, for example $player.position.x, $discord.author.id, or local.embed.footer.text. Missing optional paths evaluate to null. Use exists(...) before relying on optional fields.
5. Global runtime variables
These values are supplied to event scripts and scheduled tasks. Catalog revision: 330738ea84ce.
| Name | Kind | Description | Example | Availability |
|---|---|---|---|---|
$backup
| object | Most recent backup operation result. rat5.v2 only | — | Required |
$config
| object | Current managed game server configuration. Sensitive password and token properties are never included. rat5.v2 only | — | Required |
$bm
| object | Current and upcoming blood moon timing when RAT knows it. rat5.v2 only | — | Required |
$game_server_name | string | Configured game server name when RAT knows it. | Initial RAT5 Server | Optional |
$players_online | string | Current number of players online. | 4 | Required |
$players_max | string | Configured maximum concurrent players when RAT knows it. | 16 | Optional |
$uptime | string | Elapsed time since the current game server process started. | 2d 4h 10m | Optional |
$day | string | Current in-game day when RAT knows it. | 7 | Optional |
$hour | string | Current in-game hour when RAT knows it. | 21 | Optional |
$minute | string | Current in-game minute when RAT knows it. | 30 | Optional |
$gametime | string | Current in-game day and time in Day N, HH:MM format when RAT knows it. | Day 710, 14:51 | Optional |
$current_time | string | Current UTC time at event execution in HH:MM:SS format. | 17:37:01 | Required |
$current_date | string | Current UTC date at event execution in YYYY-MM-DD format. | 2026-06-20 | Required |
$current_datetime | string | Current UTC datetime at event execution in RFC3339 format. | 2026-06-20T17:37:01Z | Required |
6. Event variables
Every event supplies only the tokens declared by its catalog entry, in addition to the runtime variables above. The compact index below lists top-level names; object fields, examples, nullability, deprecations, and templates are in the event catalog.
| Event type | Source | Top-level variables |
|---|---|---|
chat.global_messageChat Global Message | telnet.chat.global_message | $event_type, $event_key, $occurred_at_utc, $player.name, $chat_content, $channel_name, $platform_id, $entity_id, $player, $0, $1, $N-, $N+ |
chat.server_messageChat Server Message | telnet.chat.server_message | $event_type, $event_key, $occurred_at_utc, $speaker_name, $chat_content, $channel_name, $0, $1, $N-, $N+ |
discord.message_receivedDiscord Message | discord.message_received | $event_type, $event_key, $occurred_at_utc, $discord_guild_id, $discord_channel_id, $discord_channel_key, $discord_channel_name, $discord_message_id, $discord_message_timestamp, $discord_author_id, $discord_author_username, $discord_author_global_name, $discord_author_name, $discord_author_is_bot, $discord_mentions_everyone, $discord_mention_count, $discord_mentioned_user_ids, $discord_mentioned_role_ids, $discord_role_mention_count, $discord_attachment_count, $discord_embed_count, $discord_reaction_count, $discord_message_type, $discord_message_edited_at, $discord_message_pinned, $discord_message_tts, $discord_reply_message_id, $discord_reply_channel_id, $discord_reply_guild_id, $discord_reply_author_id, $discord_attachment_name, $discord_attachment_type, $discord_attachment_url, $discord_attachment_size, $discord_embed_title, $discord_embed_description, $discord_embed_url, $discord_embed_field_count, $discord_webhook_id, $discord_content_raw, $chat_content, $discord |
discord.message_updatedDiscord Message Updated | discord.message_updated | $event_type, $event_key, $occurred_at_utc, $discord_guild_id, $discord_channel_id, $discord_channel_key, $discord_channel_name, $discord_message_id, $discord_message_timestamp, $discord_message_edited_at, $discord_author_id, $discord_author_name, $discord_mentioned_user_ids, $discord_mentioned_role_ids, $discord_attachment_count, $discord_embed_count, $discord_reply_message_id, $discord_content_raw, $chat_content, $discord |
discord.message_deletedDiscord Message Deleted | discord.message_deleted | $event_type, $event_key, $occurred_at_utc, $discord_guild_id, $discord_channel_id, $discord_channel_key, $discord_channel_name, $discord_message_id, $discord_message_timestamp, $discord_message_edited_at, $discord_author_id, $discord_author_name, $discord_mentioned_user_ids, $discord_mentioned_role_ids, $discord_attachment_count, $discord_embed_count, $discord_reply_message_id, $discord_content_raw, $chat_content, $discord |
discord.reaction_addedDiscord Reaction Added | discord.reaction_added | $event_type, $event_key, $occurred_at_utc, $discord_guild_id, $discord_channel_id, $discord_channel_key, $discord_message_id, $discord_reaction_user_id, $discord_reaction_emoji, $discord_reaction_emoji_id |
discord.reaction_removedDiscord Reaction Removed | discord.reaction_removed | $event_type, $event_key, $occurred_at_utc, $discord_guild_id, $discord_channel_id, $discord_channel_key, $discord_message_id, $discord_reaction_user_id, $discord_reaction_emoji, $discord_reaction_emoji_id |
player.joinedPlayer Joined | telnet.player.joined | $event_type, $event_key, $occurred_at_utc, $player.name, $player |
player.leftPlayer Left | telnet.player.left | $event_type, $event_key, $occurred_at_utc, $player.name, $player |
entity.killedEntity Killed | telnet.entity.killed | $event_type, $event_key, $occurred_at_utc, $killed_entity_name, $killed_entity_id, $killed_player_name, $killed_player_id, $killed_platform_id, $killed_cross_platform_id, $killer_name, $killer_entity_id, $killer_player_name, $killer_player_id, $killer_platform_id, $killer_cross_platform_id |
server.unresponsiveServer Unresponsive | rat.telnet_health.unresponsive | $event_type, $event_key, $occurred_at_utc, $failure_count, $failure_reason, $failure_detail, $last_responsive_at_utc, $first_failure_at_utc, $unresponsive_since_utc, $probe_interval_seconds, $probe_timeout_seconds |
server.responsiveServer Responsive | rat.telnet_health.responsive | $event_type, $event_key, $occurred_at_utc, $responsive_at_utc, $unresponsive_since_utc, $first_failure_at_utc, $outage_duration_seconds, $failed_probe_count, $last_health_failure_reason |
text.matchText Match | | $event_type, $event_key, $occurred_at_utc, $raw_line |
backup.startedBackup Started | internal.backup.started | $event_type, $event_key, $occurred_at_utc, $backup_filename, $backup_destination, $backup_start_time, $backup_completion_time, $backup_duration, $backup_size, $backup_compression_type, $backup_error_message, $backup_retained_count |
backup.completedBackup Completed | internal.backup.completed | $event_type, $event_key, $occurred_at_utc, $backup_filename, $backup_destination, $backup_start_time, $backup_completion_time, $backup_duration, $backup_size, $backup_compression_type, $backup_error_message, $backup_retained_count |
backup.failedBackup Failed | internal.backup.failed | $event_type, $event_key, $occurred_at_utc, $backup_filename, $backup_destination, $backup_start_time, $backup_completion_time, $backup_duration, $backup_size, $backup_compression_type, $backup_error_message, $backup_retained_count |
server.readyServer Ready | internal.server.ready | $event_type, $event_key, $occurred_at_utc, $server_state, $server_process_id, $server_started_at, $server_ready_at, $server_stopped_at, $server_uptime, $server_restart_reason, $server_restart_delay |
server.restartingServer Restart | internal.server.restarting | $event_type, $event_key, $occurred_at_utc, $server_state, $server_process_id, $server_started_at, $server_ready_at, $server_stopped_at, $server_uptime, $server_restart_reason, $server_restart_delay |
server.startedServer Start | internal.server.started | $event_type, $event_key, $occurred_at_utc, $server_state, $server_process_id, $server_started_at, $server_ready_at, $server_stopped_at, $server_uptime, $server_restart_reason, $server_restart_delay |
server.stoppedServer Stop | internal.server.stopped | $event_type, $event_key, $occurred_at_utc, $server_state, $server_process_id, $server_started_at, $server_ready_at, $server_stopped_at, $server_uptime, $server_restart_reason, $server_restart_delay |
player.new_joinedNew Player Joined | internal.player.new_joined | $event_type, $event_key, $occurred_at_utc, $player.name, $player |
bloodmoon.startedBloodmoon Started | telnet.bloodmoon.started | $event_type, $event_key, $occurred_at_utc, $bloodmoon_day |
bloodmoon.endedBloodmoon Ended | telnet.bloodmoon.ended | $event_type, $event_key, $occurred_at_utc |
custom.backpack_locationPlayer Backpack Location | telnet.custom.backpack_location | $event_type, $event_key, $occurred_at_utc |
custom.preparing_quitPreparing Quit | telnet.custom.preparing_quit | $event_type, $event_key, $occurred_at_utc |
custom.server_statsGame Server Stats | telnet.custom.server_stats | $event_type, $event_key, $occurred_at_utc, $inf_time, $fps, $heap, $max, $chunks, $cgo, $ply, $zom, $ent, $items, $co, $rss |
custom.start_gameStart Game | telnet.custom.start_game | $event_type, $event_key, $occurred_at_utc |
player.connectedPlayer Connected | telnet.player.connected | $event_type, $event_key, $occurred_at_utc, $entityid, $name, $pltfmid, $crossid, $steam_owner, $ip, $player |
player.diedPlayer Died | telnet.player.died | $event_type, $event_key, $occurred_at_utc, $inf_gmsg, $player, $player_name |
player.disconnectedPlayer Disconnected | telnet.player.disconnected | $event_type, $event_key, $occurred_at_utc, $inf_player_disconnected, $pltfm_id, $cross_id, $owner_id, $player.name, $client_number, $player |
player.kickedPlayer Kicked | telnet.player.kicked | $event_type, $event_key, $occurred_at_utc, $kick_type, $kick_message, $entity_id, $pltfm_id, $cross_id, $owner_id, $player.name, $client_number, $player |
player.bannedPlayer Banned | telnet.player.banned | $event_type, $event_key, $occurred_at_utc, $ban_until, $ban_reason, $entity_id, $pltfm_id, $cross_id, $owner_id, $player.name, $client_number, $player |
player.spawned_in_worldPlayer Spawned in World | telnet.player.spawned_in_world | $event_type, $event_key, $occurred_at_utc, $reason, $position, $position_x, $position_y, $position_z, $entity_id, $pltfm_id, $cross_id, $owner_id, $player.name, $client_number, $player |
7. String interpolation
Quoted strings and telnet command text support {{expression}} interpolation. The expression may be a variable path or a supported expression. Use format(...) when numbered placeholders make a message easier to read.
log("Player {{$player.name}} triggered {{$event_type}}")
@say "Welcome {{$player.name}}"
discord_send("general", format("{0}: {1}", $player.name, $chat_content))
The complete shipped templates are maintained with their event entries in RAT 5 Events, preventing a second divergent copy in this page.
8. Persistent shared state
global.* is persisted per event definition. Two definitions using global.count do not share the same value. Values may be strings, numbers, booleans, or nested objects. Unset a path to remove it.
set global.uses = coalesce(global.uses, 0) + 1
set global.last.player = $player.name
set global.last.at = $current_datetime
if global.uses >= 100 then
unset global.uses
end
Preview reports proposed mutations without committing them. The Events screen in RAT 5 Client can inspect globals and remove a stored global when it is no longer needed.
9. Reusable functions
A reusable function is a separately stored, versioned rat5.v2 script containing one top-level function declaration. Names begin with a lowercase letter and contain lowercase letters, numbers, and underscores.
function announce(message)
log(message)
return upper(message)
end
Parameters are read-only call-frame values. Each call receives fresh locals, while event tokens and the calling definition's globals remain available when the function is context-dependent. Reusable functions may call enabled reusable functions and may suspend through wait(...). Direct and indirect recursion are rejected.
RAT tracks event and function dependencies. A referenced function cannot be deleted, and renames update stored references through the event store. Disabled functions cannot be called.
10. Telnet commands and response capture
A line beginning with @ sends one normalized telnet command. Carriage returns, line feeds, and NUL characters are rejected to prevent command injection.
@say "Maintenance begins in 10 minutes"
Capture is permitted only as the complete right-hand side of a set statement. Use @@command for the one-second response timeout or @@(duration)command to override it.
set local.server_time = @@(3s)gettime
log(local.server_time)
Capture waits up to five seconds for the command queue, treats 250 ms of idle output as completion, strips an echoed command, ignores transport noise, and captures at most 64 lines or 16 KiB. Empty responses, timeout, queue failure, unsafe commands, and limit overruns produce structured runtime errors.
11. Built-in functions
The server currently exposes 92 built-ins. User-defined reusable functions appear alongside these at runtime but are installation-specific.
Action
Write information to the RAT log or pause the current script. These are useful while learning and troubleshooting.
log(message)Writes an info-level event script message to the RAT server log.Example:log("Player {{$player.name}} said: {{$chat_content}}")debug(message)Writes a debug-level event script message to the RAT server log when debug logging is enabled.Example:debug("Matched {{$event_type}} at {{$current_datetime}}")wait(milliseconds)Suspends only the current script instance for up to 60000 ms, then resumes later from the next statement. Pending waits are kept in memory only, so restart or shutdown drops them.Example:wait(1500)credits_modify(player_ref, amount)Adds or subtracts credits for the resolved player. Amount must be an integer, and unresolved players are ignored.Example:credits_modify($player.name, 25)credits_set(player_ref, amount)Sets credits for the resolved player. Amount must be an integer, and unresolved players are ignored.Example:credits_set($player.name, 1000)
Conversion
Change a value into text, a number, or true/false so it can be compared or displayed safely.
to_string(value)Converts a value to a string using render-time rules.Example:to_string(global.help_count)to_number(value)Converts a value to a number or fails when conversion is not possible.Example:to_number(global.score)to_bool(value)Converts a value to a boolean using the script truthiness rules.Example:to_bool(global.enabled)
Discord
Send, reply to, edit, delete, react to, pin, or inspect Discord content. These require a working Discord integration.
discord_send(channel_key_or_id, message)Sends a Discord message to a configured channel mapping key or a raw reachable Discord channel ID.Example:discord_send("general", format("{0}: {1}", $discord_author_name, $chat_content))Returns:Sends `Trekkan: hello world` to the `general` channel mapping.`channel_key_or_id` accepts an enabled script-target mapping key or a numeric channel ID in the configured guild.`message` is limited to 2000 characters after trimming.Raw `<@...>`, `<@&...>`, `@everyone`, and `@here` text is displayed without notifying anyone. Use the Discord mention helpers to authorize notifications.Requires the bot to view the channel and send messages.discord_embed(channel_key_or_id, title, description, color?, url?, footer?, image_url?, thumbnail_url?)Sends a Discord embed to a configured channel mapping key or a raw reachable Discord channel ID. Sends the embed only; no separate plain-text message body is included. Description-only embeds are allowed, trailing optional arguments may be omitted, colors must use #RRGGBB, and URLs must be http/https.Example:discord_embed("general", "Server Alert", format("{0}: {1}", $event_type, $chat_content), "#ff8800")Returns:Sends one orange embed titled `Server Alert` with the rendered event text.Arguments after `description` are optional and must be supplied in signature order.`color` must be `#RRGGBB`; URL, image, and thumbnail values must use HTTP or HTTPS.Title is limited to 256 characters, description to 4096, footer to 2048, and total embed text to 6000.This legacy form sends no plain-text content and supports no fields, author, timestamp, or footer icon; use `discord_embed_send` for those features.Requires View Channel, Send Messages, and Embed Links.discord_embed_send(channel_key_or_id, embed_object)Sends a structured Discord embed object. Supports content, author, timestamp, footer icons, images, thumbnails, and deterministically ordered fields.Example:set local.embed.content = format("{0}", discord_mention_user($discord_author_id)) set local.embed.title = "Server Alert" set local.embed.description = $chat_content set local.embed.color = "#ff8800" set local.embed.timestamp = $occurred_at_utc set local.embed.author.name = "RAT" set local.embed.author.url = "https://example.com" set local.embed.author.icon_url = "https://example.com/rat.png" set local.embed.footer.text = "Automated" set local.embed.footer.icon_url = "https://example.com/footer.png" set local.embed.image_url = "https://example.com/image.png" set local.embed.thumbnail_url = "https://example.com/thumb.png" set local.embed.fields.field_01.name = "State" set local.embed.fields.field_01.value = "Online" set local.embed.fields.field_01.inline = true discord_embed_send("general", local.embed)Returns:Sends the structured embed and safely mentions only `$discord_author_id` in its plain-text content.Supported root properties: `content`, `title`, `description`, `color`, `url`, `timestamp`, `image_url`, and `thumbnail_url`.Author properties: `author.name`, `author.url`, and `author.icon_url`. URLs/icons require `author.name`.Footer properties: `footer.text` and `footer.icon_url`. The icon requires footer text.Fields are objects under `fields`; each requires `name` and `value`, with optional boolean `inline`. Field keys must be valid RatScript identifiers and are sorted alphabetically.Up to 25 fields are allowed. Field names are limited to 256 characters and values to 1024; aggregate embed text is limited to 6000.`timestamp` must be RFC3339. All URL properties must use HTTP or HTTPS.Only `content` can generate notifications, and only mention-helper values propagated through `format(...)` are authorized.discord_status(kind, text?)Updates the active Discord bot's scripted activity/custom status for the live session only. Supports clear, playing, watching, and custom. Repeating the same normalized request is a no-op, and clear removes the current scripted override without persisting anything across reconnects.Example:discord_status("playing", format("Watching {0} players", $player_count))Returns:Sets the bot activity to `Playing Watching 4 players` for the current Discord session.`kind` supports `playing`, `watching`, `custom`, and `clear`.`playing`, `watching`, and `custom` require non-empty text. `clear` accepts no text.Status changes are session-only and are not persisted across reconnects. Repeating the same normalized value is a no-op.discord_reply(channel_key_or_id, message_id, message, mention_replied_user?)Replies to a Discord message. The replied user is not notified unless the final argument is true.Example:discord_reply("general", $discord_message_id, "Acknowledged", false)Returns:Replies `Acknowledged` to `$discord_message_id` without notifying the original author.`message_id` must be a numeric Discord message ID in the target channel.`mention_replied_user` defaults to false. Set it to true only when the reply should notify the original author.Mentions inside `message` remain default-deny unless constructed with Discord mention helpers.Requires View Channel, Send Messages, and Read Message History.discord_edit(channel_key_or_id, message_id, message)Edits a message created by the Discord bot.Example:discord_edit("general", local.message_id, "Updated status")Returns:Replaces the bot message content with `Updated status`.The bot can edit only messages it created. `message_id` must be numeric and the replacement is limited to 2000 characters.Raw mention syntax does not notify; use Discord mention helpers for explicitly authorized mentions.discord_delete(channel_key_or_id, message_id)Deletes a Discord message when the bot has permission.Example:discord_delete("general", local.message_id)Returns:Deletes the selected Discord message.`message_id` must be numeric. Deleting another user's message requires Manage Messages.The target channel must be an enabled script target or a reachable channel in the configured guild.discord_react(channel_key_or_id, message_id, emoji)Adds a reaction to a Discord message.Example:discord_react("general", $discord_message_id, "👍")Returns:Adds 👍 to `$discord_message_id`.`emoji` accepts a Unicode emoji such as `👍` or Discord custom-emoji format such as `name:123456789012345678`.Requires Add Reactions and Read Message History; custom emoji may require Use External Emoji.discord_pin(channel_key_or_id, message_id)Pins a Discord message.Example:discord_pin("general", $discord_message_id)Returns:Pins `$discord_message_id` in the target channel.Requires Manage Messages. `message_id` must be numeric.discord_unpin(channel_key_or_id, message_id)Unpins a Discord message.Example:discord_unpin("general", $discord_message_id)Returns:Removes the pin from `$discord_message_id`.Requires Manage Messages. `message_id` must be numeric.discord_thread_start(channel_key_or_id, message_id, name, archive_minutes?)Starts a thread from a Discord message. Archive minutes may be 60, 1440, 4320, or 10080.Example:discord_thread_start("general", $discord_message_id, "Incident discussion", 1440)Returns:Creates `Incident discussion` from `$discord_message_id` and auto-archives it after 1440 minutes of inactivity.`name` is required and limited to 100 characters.`archive_minutes` defaults to 1440 and must be one of 60, 1440, 4320, or 10080. Availability depends on guild features.Requires Create Public Threads and Send Messages in Threads.discord_mention_user(user_id)Builds a user mention and authorizes only that user mention when the value is sent to Discord.Example:discord_mention_user($discord_author_id)Returns:<@456789012345678901>`user_id` must contain only digits.The returned value carries a whitelist for exactly that user. Preserve it with `format(...)` and pass the result directly to a Discord message, reply, edit, or structured embed `content`.discord_mention_role(role_id)Builds a role mention and authorizes only that role mention when the value is sent to Discord.Example:discord_mention_role("123456789012345678")Returns:<@&567890123456789012>`role_id` must contain only digits.The returned value carries a whitelist for exactly that role. Whether it notifies depends on Discord role mentionability and bot permissions.discord_mention_everyone()Builds an explicit @everyone mention. This is a high-impact notification and should be used sparingly.Example:discord_mention_everyone()Returns:@everyoneRequires `[discord.automation_options].allow_mass_mentions = true`; otherwise sending fails.This authorizes Discord's `everyone` mention type and therefore applies to `@everyone` or `@here` text in the same message.discord_mention_here()Builds an explicit @here mention. This is a high-impact notification and should be used sparingly.Example:discord_mention_here()Returns:@hereRequires `[discord.automation_options].allow_mass_mentions = true`; otherwise sending fails.This authorizes Discord's `everyone` mention type and therefore applies to `@everyone` or `@here` text in the same message.discord_user_has_role(user_id, role_id)Returns true when the user is a member of the configured Discord guild and currently has the specified role.Example:discord_user_has_role($discord.author.id, "567890123456789012")Returns:trueParameters:user_id(string);role_id(string)Return type:booleanBoth arguments must be numeric Discord IDs; role names are not accepted.Returns false when the user is not in the configured guild or does not have the role.Discord configuration or connection failures are reported as runtime errors.discord_user_in_guild(user_id)Returns true when the user is currently a member of the configured Discord guild.Example:discord_user_in_guild($discord.author.id)Returns:trueParameters:user_id(string)Return type:boolean`user_id` must be a numeric Discord ID.Returns false when Discord reports that the user is not a member of the configured guild.Discord configuration or connection failures are reported as runtime errors.discord_channel_exists(channel_key_or_id)Returns true when a configured channel mapping key or numeric channel ID resolves inside the configured Discord guild.Example:discord_channel_exists("general")Returns:trueParameters:channel_key_or_id(string)Return type:booleanAccepts a configured channel mapping key or a numeric Discord channel ID.Returns false when the channel does not exist or belongs to another guild.The mapping does not need to be enabled as a script target for this existence check.discord_role_exists(role_id)Returns true when the numeric role ID exists in the configured Discord guild.Example:discord_role_exists("567890123456789012")Returns:trueParameters:role_id(string)Return type:boolean`role_id` must be a numeric Discord ID; role names are not accepted.Returns false when the role is absent from the configured guild.Discord configuration or connection failures are reported as runtime errors.
Game Server
Broadcast messages and start, stop, restart, or inspect the managed game server. Review these carefully before enabling them.
gs_start()Starts the game server. Fire-and-forget; the script does not wait for the server to finish starting.Example:gs_start()gs_stop(reason?)Stops the game server. An optional reason string is logged. Fire-and-forget.Example:gs_stop("Scheduled maintenance")gs_restart(reason?)Restarts the game server. An optional reason string is logged. Fire-and-forget.Example:gs_restart("Nightly restart")gs_status()Returns the current server state as a string: "unknown", "stopped", "starting", "running", "stopping", "restarting", or "crashed".Example:gs_status()gs_broadcast(message, broadcast_type?, channel_key?)Broadcasts a message via one or more channels. broadcast_type: "say" (default), "discord", "discord_embed", "log", "all". channel_key is required for discord types.Example:gs_broadcast("Server restarting in 5 minutes.", "say")gs_countdown(seconds, action, reason?, interval?, broadcast_type?, channel_key?)Starts a countdown that executes action ("stop" or "restart") at zero. Fires milestone broadcasts automatically. A second call while a countdown is active is a no-op — call gs_countdown_cancel() first.Example:gs_countdown(300, "restart", "Nightly maintenance", 60, "say")gs_countdown_cancel(message?, broadcast_type?, channel_key?)Cancels the active countdown without executing the action. Silent by default; pass a message to broadcast the cancellation.Example:gs_countdown_cancel("Restart cancelled by admin.", "say")
Logic
Test whether values exist, are empty, match text, or meet common conditions.
empty(value)Returns true when the value is null or an empty string.Example:empty($chat_content)exists(value)Returns true when the value is not null.Example:exists(global.last_help_player)coalesce(a, b, ...)Returns the first non-null value.Example:coalesce(global.help_count, 0)
Lookup
Find structured information, such as a player record. Lookups can return null when no unique result exists.
player(name_or_id)Returns a structured player object for the matching current player name or stored identifier. Assign the result to a local before reading properties like local.pinfo.name.Example:SET local.pinfo = player($player.name)Parameters:name_or_id(string)Return type:object(nullable)return.id - Stable RAT player identifier.return.name - Current player display name.return.platform_id - Primary platform identifier reported by the game.return.cross_platform_id - Cross-platform identifier when available.return.steam_id - Steam user identifier when available.return.eos_id - Epic Online Services identifier when available.return.xbl_id - Xbox Live identifier when available.return.platform_family - Primary platform family.return.platform_user_id - User-id portion of the primary platform identifier.return.cross_platform_family - Cross-platform identifier family.return.cross_platform_user_id - User-id portion of the cross-platform identifier.return.entity_id - Current in-game entity identifier.return.online - True when RAT currently considers the player online.return.last_seen_at - Last known UTC observation time in RFC3339 format.return.ip_address - Most recently observed IP address.return.level - Current player level.return.health - Current health value.return.stamina - Current stamina value.return.score - Current score.return.ping - Current network latency in milliseconds.return.deaths - Recorded death count.return.zombie_kills - Recorded zombie kill count.return.player_kills - Recorded player kill count.return.total_play_time_seconds - Recorded total play time in seconds.return.credits - Current RAT credits balance.return.ban_active - True when the player has an active ban.return.ban_reason - Current ban reason when available.return.ban_until - Current ban expiration in UTC when available.return.group - Effective RAT player group.return.group.id - Effective group identifier.return.group.name - Effective group display name.return.group.max_teleport_destinations - Maximum saved teleport destinations.return.group.teleport_cooldown_seconds - Teleport cooldown in seconds.return.position - Last known player position.return.position.x - World X coordinate.return.position.y - World Y coordinate.return.position.z - World Z coordinate.
Math
Calculate, round, limit, or randomly select numeric values.
abs(value)Returns the absolute numeric value.Example:abs(-10)min(a, b, ...)Returns the smallest numeric value.Example:min(1, 2, 3)max(a, b, ...)Returns the largest numeric value.Example:max(1, 2, 3)round(value)Rounds a number to the nearest whole value.Example:round(12.5)floor(value)Rounds a number down.Example:floor(12.5)ceil(value)Rounds a number up.Example:ceil(12.5)clamp(value, min, max)Clamps a number into the provided range.Example:clamp(global.score, 0, 100)chance(percent)Returns true with the requested percentage probability from 0 through 100.Example:chance(25)Returns:true or falseParameters:percent(number)Return type:boolean`percent` may be fractional and must be between 0 and 100 inclusive.`chance(0)` is always false and `chance(100)` is always true.is_between(value, min, max)Returns true when a number is inclusively between the supplied minimum and maximum.Example:is_between($player.level, 10, 25)Returns:trueParameters:value(number);min(number);max(number)Return type:booleanBoth boundaries are inclusive.A minimum greater than the maximum is a runtime error.
Player
Read player status, groups, distances, balances, and leaderboard information.
player_has_group(player_ref, group_ref)Returns true when the uniquely resolved player's effective RAT group matches the supplied group ID or display name.Example:player_has_group($player.id, "VIP")Returns:trueParameters:player_ref(string);group_ref(string)Return type:boolean`player_ref` uses the same unique player resolution rules as `player(...)`.`group_ref` matches either the effective group ID or display name, case-insensitively.The default group counts as the player's effective group. Unresolved or ambiguous players return false.player_exists(player_ref)Returns true when the reference uniquely resolves to a stored player.Example:player_exists("Steam_76561197970441157")Returns:trueParameters:player_ref(string)Return type:booleanAccepts a RAT player ID, unique display name, platform ID, Steam ID, EOS ID, or Xbox ID.Returns false when there is no match or more than one player matches.player_online(player_ref)Returns true when RAT currently considers the uniquely resolved player online.Example:player_online($player.id)Returns:trueParameters:player_ref(string)Return type:booleanUses RAT's current stored online state for the uniquely resolved player.Unresolved or ambiguous players return false.player_banned(player_ref)Returns true when the uniquely resolved player has an active ban.Example:player_banned($player.id)Returns:falseParameters:player_ref(string)Return type:booleanReturns the active-ban state for the uniquely resolved player.Unresolved or ambiguous players return false.player_distance(player_a, player_b)Returns the unrounded three-dimensional distance between two players' latest known positions, or null when unavailable.Example:player_distance($player.id, "TargetPlayer")Returns:312.47Parameters:player_a(string);player_b(string)Return type:number(nullable)Calculates Euclidean distance using unrounded X, Y, and Z coordinates.Returns null when either player is unresolved, ambiguous, or lacks a complete known position.player_distance_from(player_ref, x, y, z)Returns the unrounded three-dimensional distance from a player's latest known position to the supplied coordinates, or null when unavailable.Example:player_distance_from($player.id, 1250, 70, -840)Returns:84.32Parameters:player_ref(string);x(number);y(number);z(number)Return type:number(nullable)Calculates Euclidean distance using the player's unrounded X, Y, and Z coordinates.Returns null when the player is unresolved, ambiguous, or lacks a complete known position.Coordinates must be finite numbers.player_leaderboard(metric, limit, row_template?, separator?)Returns a formatted leaderboard using current stored player data. The default row template is "{rank}. {player.name} - {formatted_value}".Example:player_leaderboard("zombie_kills", 10, "#{rank} {player.name}: {formatted_value}", "\n")Parameters:metric(string);limit(number);row_template(string, optional);separator(string, optional)Return type:stringAvailable metrics:deaths - Recorded death count.zombie_kills - Recorded zombie kill count.player_kills - Recorded player kill count.total_play_time_seconds - Recorded total play time.score - Current recorded score.level - Current recorded player level.credits - Current RAT credits balance.Available row-template fields:{rank} - One-based ordinal rank.{metric} - Canonical leaderboard metric key.{metric_label} - Human-readable metric label.{value} - Raw numeric metric value.{formatted_value} - Metric-aware display value.{player.id} - Stable RAT player identifier.{player.name} - Current player display name.{player.online} - Whether RAT currently considers the player online.{player.level} - Current player level, or blank when unavailable.{player.score} - Current score, or blank when unavailable.{player.deaths} - Recorded death count, or blank when unavailable.{player.zombie_kills} - Recorded zombie kill count, or blank when unavailable.{player.player_kills} - Recorded player kill count, or blank when unavailable.{player.total_play_time_seconds} - Recorded total play time in seconds, or blank when unavailable.{player.credits} - Current RAT credits balance.{player.last_seen_at} - Last known UTC observation time, or blank when unavailable.player_leaderboard_entry(metric, position)Returns one structured leaderboard entry, or null when that position has no eligible player. Assign the result to a local before reading its properties.Example:player_leaderboard_entry("zombie_kills", 1)Parameters:metric(string);position(number)Return type:object(nullable)return.rank - One-based ordinal rank.return.metric - Canonical leaderboard metric key.return.metric_label - Human-readable metric label.return.value - Raw numeric metric value.return.formatted_value - Metric-aware display value.return.player - Ranked player.return.player.id - Stable RAT player identifier.return.player.name - Current player display name.return.player.platform_id - Primary platform identifier reported by the game.return.player.cross_platform_id - Cross-platform identifier when available.return.player.steam_id - Steam user identifier when available.return.player.eos_id - Epic Online Services identifier when available.return.player.xbl_id - Xbox Live identifier when available.return.player.platform_family - Primary platform family.return.player.platform_user_id - User-id portion of the primary platform identifier.return.player.cross_platform_family - Cross-platform identifier family.return.player.cross_platform_user_id - User-id portion of the cross-platform identifier.return.player.entity_id - Current in-game entity identifier.return.player.online - True when RAT currently considers the player online.return.player.last_seen_at - Last known UTC observation time in RFC3339 format.return.player.ip_address - Most recently observed IP address.return.player.level - Current player level.return.player.health - Current health value.return.player.stamina - Current stamina value.return.player.score - Current score.return.player.ping - Current network latency in milliseconds.return.player.deaths - Recorded death count.return.player.zombie_kills - Recorded zombie kill count.return.player.player_kills - Recorded player kill count.return.player.total_play_time_seconds - Recorded total play time in seconds.return.player.credits - Current RAT credits balance.return.player.ban_active - True when the player has an active ban.return.player.ban_reason - Current ban reason when available.return.player.ban_until - Current ban expiration in UTC when available.return.player.group - Effective RAT player group.return.player.group.id - Effective group identifier.return.player.group.name - Effective group display name.return.player.group.max_teleport_destinations - Maximum saved teleport destinations.return.player.group.teleport_cooldown_seconds - Teleport cooldown in seconds.return.player.position - Last known player position.return.player.position.x - World X coordinate.return.player.position.y - World Y coordinate.return.player.position.z - World Z coordinate.credits_balance(player_ref)Returns the current credits balance for the resolved player, or null when no unique player match is found.Example:credits_balance($player.name)
String
Build, search, normalize, split, and format text.
format(template, value1, value2, ...)Formats a string with numbered placeholders like {0} and {1}.Example:format("Player {0} said {1}", $player.name, $chat_content)contains(value, search)Returns true when the plain-text search value appears within the source string.Example:contains(lower($chat_content), "!help")contains_any(value, search1, search2, ...)Returns true when any supplied plain-text search value appears within the source string.Example:contains_any(lower($chat_content), "help", "admin", "support")Returns:trueParameters:value(string);search1(string);search2...(string, optional)Return type:booleanSearches are plain text and case-sensitive; use `lower(...)` when case should be ignored.At least one search value is required. An empty search value matches every string.equals_ignore_case(a, b)Returns true when two rendered strings are equal without case sensitivity.Example:equals_ignore_case($chat_content, "!HELP")Returns:trueParameters:a(string);b(string)Return type:booleanRenders both values as strings and compares them with Unicode-aware case folding.matches(value, pattern)Returns true when the string matches a bounded RE2 regular expression.Example:matches($chat_content, "^![a-z_]+$")Returns:trueParameters:value(string);pattern(string)Return type:booleanUses Go's RE2 syntax, which does not support backreferences or look-around assertions.Input is limited to 8192 characters and the pattern to 512 characters.Invalid patterns and oversized values are runtime errors.starts_with(value, prefix)Returns true when the source string begins with the provided prefix.Example:starts_with($player.name, "[Admin]")ends_with(value, suffix)Returns true when the source string ends with the provided suffix.Example:ends_with($player.name, "_bot")lower(value)Converts a string to lowercase using culture-invariant rules.Example:lower($player.name)upper(value)Converts a string to uppercase using culture-invariant rules.Example:upper($player.name)trim(value)Trims leading and trailing whitespace.Example:trim($chat_content)trim_start(value)Trims leading whitespace.Example:trim_start($chat_content)trim_end(value)Trims trailing whitespace.Example:trim_end($chat_content)replace(value, from, to)Replaces the first plain-text match in a string.Example:replace($chat_content, " ", " ")replace_all(value, from, to)Replaces every plain-text match in a string.Example:replace_all($chat_content, " ", " ")substring(value, start, length?)Returns a substring from the provided start index, optionally limited by length.Example:substring($chat_content, 0, 24)length(value)Returns the rendered string length.Example:length($chat_content)concat(a, b, ...)Concatenates rendered values into a single string.Example:concat($player.name, ": ", $chat_content)left(value, count)Returns the leftmost count characters from a string.Example:left($player.name, 3)right(value, count)Returns the rightmost count characters from a string.Example:right($player.name, 3)pad_left(value, length, pad?)Pads a string on the left to the requested width.Example:pad_left($player.name, 12, ".")pad_right(value, length, pad?)Pads a string on the right to the requested width.Example:pad_right($player.name, 12, ".")index_of(value, search)Returns the first zero-based index of a substring or -1 when absent.Example:index_of($chat_content, "!")last_index_of(value, search)Returns the last zero-based index of a substring or -1 when absent.Example:last_index_of($chat_content, "!")pluralize(count, singular, plural?)Returns singular when count equals 1; otherwise returns the supplied plural or singular with s appended.Example:pluralize($players_online, "player", "players")Returns:playersParameters:count(number);singular(string);plural(string, optional)Return type:stringReturns `singular` only when count equals exactly 1.When `plural` is omitted, the default is `singular` with `s` appended.The function returns the selected word only; it does not include the count.
Teleport
Manage teleport destinations and move players. These functions perform live game actions.
tp_dc(player_ref)Returns the player's current teleport destination count. Unresolved players return 0.Example:tp_dc($player.name)tp_mdc(player_ref)Returns the player's maximum teleport destination count. Unresolved players return 0.Example:tp_mdc($player.name)tp_list(player_ref)Returns teleport destinations as newline-delimited text: name => (x, y, z[, dir]). Unresolved players return an empty string.Example:tp_list($player.name)tp_add(player_ref, destination, x, y, z, direction?)Adds or updates a saved teleport destination for the resolved player.Example:tp_add($player.name, "home", 10, 65, -2, "n")tp_remove(player_ref, destination)Removes a saved teleport destination for the resolved player.Example:tp_remove($player.name, "home")tp_go(player_ref, destination)Teleports the resolved player to a saved destination. Missing destinations are ignored.Example:tp_go($player.name, "home")tp_to(player_ref, x, y, z, direction?)Teleports the resolved player to explicit coordinates.Example:tp_to($player.name, 100, 70, -100, "e")tp_to_ground(player_ref, x, z, direction?)Teleports the resolved player to x/z using y=-1.Example:tp_to_ground($player.name, 100, -100, "s")tp_to_player(player_ref, target_player_ref)Teleports the resolved player to another player's current position.Example:tp_to_player($player.name, "TargetPlayer")tp_offset(player_ref, dx, dy, dz)Teleports the resolved player by an integer offset from their current position.Example:tp_offset($player.name, 0, 1, 0)
Time
Convert durations and compare stored timestamps with the current event time.
duration_seconds(value)Parses a non-negative duration such as 30s, 5m, or 2h and returns its length in seconds.Example:duration_seconds("5m")Returns:300Parameters:value(string)Return type:numberUses duration units such as `ms`, `s`, `m`, and `h`; units may be combined, as in `1h30m`.Negative and invalid durations are runtime errors. Fractional seconds are preserved.elapsed_seconds(datetime)Returns seconds elapsed between an RFC3339 timestamp and the current event time.Example:elapsed_seconds($player.last_seen_at)Returns:3600Parameters:datetime(string)Return type:number(nullable)`datetime` must use RFC3339. Null input returns null.Uses the event's `$current_datetime`, so previews are evaluated relative to their selected occurrence time.Future timestamps produce negative results.
12. Limits and failure behavior
- A single
wait(...)is limited to 60,000 ms. - One logical execution may live for at most 10 minutes and suspend at most 16 times.
- The process accepts at most 256 pending waits. Pending waits are not persisted across restart or shutdown.
- Telnet capture defaults to a one-second response timeout and is capped at 64 lines or 16 KiB.
- Reusable-function recursion is rejected during validation.
- A runtime error stops the current definition only. Other definitions for the event continue in order.
- Preview simulates side effects and persistent mutations; it does not send live commands or messages.
13. Complete examples
Persistent chat-command counter
Event type: chat.global_message
set local.message = lower(trim($chat_content))
if local.message == "!status" then
set global.status_uses = coalesce(global.status_uses, 0) + 1
gs_broadcast(
format("Server: {0}; players: {1}/{2}; uses: {3}",
gs_status(), $players_online, $players_max, global.status_uses),
"say"
)
end
Discord reply with a safe mention
Event type: discord.message_received
if equals_ignore_case(trim($chat_content), "!ack") then
discord_reply(
$discord_channel_id,
$discord_message_id,
format("{0} acknowledged", discord_mention_user($discord_author_id)),
false
)
end
Leaderboard announcement
set local.board = player_leaderboard("zombie_kills", 10)
discord_send("general", local.board)
Safe player lookup
set local.pinfo = player($player.name)
if exists(local.pinfo.id) then
debug(format("Resolved {0} as {1}", local.pinfo.name, local.pinfo.id))
else
debug(format("Could not uniquely resolve {0}", $player.name))
end