Appearance
Chat & private messages
Mytharyn has two kinds of player text:
- Chat is the bubble above a player's head, seen by everyone in the same level. Scripts can read it, set it and react to it. A chat starting with
/is a local command instead: it's never shown and never leaves the client. - Private messages (PMs) go from one account to another, across servers. They're handled by the Login Server's global PM system. Game-server scripts can send system PMs and learn that a PM arrived, but can't read PM text.
Chat bubbles
A player's chat is one string. Setting it shows a bubble to everyone in their level, and '' clears it. The bubble fades 5 seconds after its owner moves. Text is trimmed to 200 characters and control characters become spaces. Players who enter the level later still see an existing bubble.
| Side | Read | Write |
|---|---|---|
| Server | player.chat (live) | player.chat = 'text': applies immediately, shown to everyone in the level including the player |
| Client | player.chat (local player) | player.chat = 'text': batched, shown locally and sent to the server like typed chat |
ts
// Server: make a player say something.
player.chat = `*gulp* ${potionName}`Reacting to chat on the client: onPlayerChats
Clientside weapons (and clientside NPC scripts) export onPlayerChats(player, chat):
ts
function onPlayerChats(who: ChatPlayer, chat: string) {
if (who.id !== player.id) return // only react to yourself
if (chat === '/where') echo(`${player.level} ${player.x},${player.y}`)
}It fires when any player in the level changes their chat, you included. That covers typed chat, chat set by a clientside script, and chat set by a server script. chat is '' when a bubble was cleared. The first argument is a frozen ChatPlayer snapshot: id, name (account), nick, x, y, dir, and chat as it was at that moment.
Only actual changes fire it. Setting the same text again is silent, so a handler that reacts by writing player.chat can't loop on itself. It does not fire when a bubble expires, or for bubbles that already existed when their owner entered your level.
Slash commands
Chat that starts with / is a command:
- no bubble is shown, and nothing is sent to the server or other players;
- it's delivered to
onPlayerChatson this client only, withwhobeing the local player andchatthe full command text.
That's all you need to build chat commands. Parse the text, and call triggerServer for anything the server must do:
ts
// weapons/commands.client.ts
function onPlayerChats(who: ChatPlayer, chat: string) {
if (who.id !== player.id || !chat.startsWith('/')) return
const [cmd, ...args] = chat.slice(1).split(' ')
switch (cmd) {
case 'ani': setAni(args[0]); break // purely local
case 'home': triggerServer('weapon', this.name, 'home'); break // needs the server
}
}Every loaded weapon receives every command. Ignore ones that aren't yours, and pick distinctive command names. The Login Server's -pm weapon also hears your / commands on every server (that's how /pm <account> <text> and /r <text> work everywhere), so avoid those two names.
Built-in commands
The client handles a few commands itself, without a slash: setnick <name> (bare setnick resets to your account name), sethead <image>, setbody <image>, setcolor <slot> r,g,b (slot 0–4 or skin/coat/sleeves/shoes/belt) and showname. The first four still show as normal chat. showname is consumed.
Commands you want other players to see (say, an :additem command) can use any other prefix. They're then ordinary chat, broadcast as a bubble and delivered to everyone's onPlayerChats.
Reacting to chat on the server
Plain server scripts and weapon server halves have no chat event. Two ways to react to chat serverside:
- Forward from a clientside weapon. Catch it in
onPlayerChatsandtriggerServerit. This is the usual way for commands, and it works for/commands, which never reach the server otherwise. - Level NPCs. A serverside NPC script's
onPlayerChats(player, chat)fires for chat typed by players in its level. Script-set chat and/commandsdon't trigger it. A shopkeeper can open its shop when someone says "shop" nearby. See NPCs.
Private messages
PMs are global. The Login Server's persistent -pm weapon (F8) keeps the friends list, holds received messages and lets players read and send them on every server. For the privileged API behind it, see Login server scripting. Game-server scripts get two narrow hooks.
Sending a system PM: sendPM (server)
sendPM(target, text) sends a system PM from this server to a player on any server. target is an account name or a Player.
ts
sendPM(player, 'Welcome back!')
sendPM('SomeAccount', 'Your auction sold for 500 gold')- It needs no player context, so it's safe after an
awaitor in a timer. - It's delivered only if the player is online somewhere. Otherwise it's silently dropped.
- Text is limited to 200 characters. The call is batched.
- The recipient sees it as coming from your server:
{ account: <server name>, server: <server name>, system: true }.
Knowing a PM arrived: onPMReceived (client)
Clientside weapons and clientside NPC scripts can export onPMReceived(sender):
ts
function onPMReceived(sender: PMSender) {
if (!sender.system) echo(`New message from ${sender.account} (${sender.server})`)
}PMSender has account (the sender, or the sending server's name for system PMs), server (the server they're on, '' if unknown) and system (true for sendPM from a server script). The event is a notification only. The message text is never delivered to game-server scripts. Only the Login Server's privileged weapons can read it (with openPM), so a game server can't snoop on players' conversations. Game weapons also can't send player PMs or see the friends list.
Related
- Tutorial: Chat commands
- Players:
nick,chatand the other player properties. - Login server scripting: the full PM and friends API.