Chat Commands
Before this: Admin Gates, Taking Text Apart, Safe Text
Next steps: Every Player
A chat command is a word typed into chat after a /, like /roll. A circuit
can add its own, read what the player typed after it, and answer them. This
lesson builds a dice roll, a lamp set from chat, a private message, and a
nickname announcement.
Needs admin to load: every command uses Chat Command Event. /pm also
uses Find Player by Name, and /nick Broadcast Chat Message.
Contents
Code
on ChatCommand("roll", "Roll a six-sided die") -> (who, arguments) {
let n = Random(1, 6)
who.ShowChatMessage("You rolled ${n}")
}
on ChatCommand("roll", ...)adds/rollto chat. The second text is the help line the game shows for it.Random(1, 6)picks a whole number from 1 to 6, different each time.-> (who, arguments)names what the event gives:whois the player who typed it, andargumentsis the rest of the line after/roll.who.ShowChatMessageanswers only that player.
A player types /roll. Who sees the result? Another types /roll 20. Do
they get a twenty-sided die?
Run
- Compile the chip and paste it in-game. Nothing needs wiring: the command is the input.
- Type
/rollin chat. You get a number from 1 to 6, and nobody else sees it. - Type
/roll 20. Still 1 to 6: the chip ignoresarguments.
Under the Hood
Open the chip. Chat Command Event has the command name and help text in its settings and no inputs. Its outputs are Exec Out, Player State (the player) and Arguments. The chain runs through Random and Show Chat Message, with a Format String building the text.
Arguments are always text, even when they look like a number.
Taking Text Apart covers reading them. Here /roll 20 asks for
a bigger die, and anything that is not a number gives the usual six:
on ChatCommand("roll", "Roll a die: /roll or /roll 20") -> (who, arguments) {
let asked = arguments.Trim().ParseInt()
let sides = if asked.Success && asked.Value >= 2 then asked.Value else 6
let n = Random(1, sides)
who.ShowChatMessage("You rolled ${n} on a d${sides}")
}
A setting and a number
/lamp brightness 20 sets one setting of a lamp. Split(" ") cuts the
arguments at the first space: the setting name on the left, the number on the
right. Anything that does not match gets the usage line back.
const MAX_BRIGHTNESS = 100.0
const MAX_RADIUS = 2000.0
const USAGE = "Usage: /lamp brightness 0 to 100, or /lamp radius 0 to 2000"
var level: float = 10.0
var reach: float = 500.0
@right out brightness = level.Value
@right out radius = reach.Value
on ChatCommand("lamp", "Set the lamp: /lamp brightness 20") -> (who, arguments) {
let parts = arguments.Trim().Split(" ")
let setting = parts.Left.ToLower()
let number = parts.Right.Trim().ParseNumber()
if !parts.Found || !number.Success || number.Value < 0.0 {
who.ShowChatMessage(USAGE)
} else if setting == "brightness" && number.Value <= MAX_BRIGHTNESS {
level = number.Value
who.ShowChatMessage("Brightness is now ${number.Value}")
} else if setting == "radius" && number.Value <= MAX_RADIUS {
reach = number.Value
who.ShowChatMessage("Radius is now ${number.Value}")
} else {
who.ShowChatMessage(USAGE)
}
}
Wire brightness and radius to a Point Light’s Brightness and
Radius. ToLower() lets /lamp Brightness 20 work too.
One player, or everyone
/pm name message whispers to another player. FindPlayer looks a player up
by name or user id. It is admin too, and Every Player
shows another way to search.
import { escape, sanitize } from "sanitize"
const MAX_LEN = 200
on ChatCommand("pm", "Whisper to one player: /pm name message") -> (who, arguments) {
let parts = arguments.Trim().Split(" ")
if !parts.Found {
who.ShowChatMessage("Usage: /pm name message")
return
}
let to = FindPlayer(parts.Left)
if to == null {
who.ShowChatMessage("Nobody is called ${sanitize(parts.Left)}")
return
}
let text = sanitize(parts.Right, MAX_LEN)
to.ShowChatMessage("[from ${escape(who.GetDisplayName())}] ${text}")
who.ShowChatMessage("[to ${escape(to.GetDisplayName())}] ${text}")
}
When nobody matches, to is empty, and to == null is the check
(Object References). return ends the handler there, so nothing after it runs.
Every piece of text a player typed goes through sanitize before it is shown, and every name through escape, as in
Safe Text. A message is text another player chose,
and it is shown to someone else.
/nick name tells the whole server, with BroadcastChatMessage:
import { escape, sanitize } from "sanitize"
on ChatCommand("nick", "Announce a nickname: /nick name") -> (who, arguments) {
let nick = sanitize(arguments)
if nick == "" {
who.ShowChatMessage("Usage: /nick name")
return
}
BroadcastChatMessage("${escape(who.GetDisplayName())} is now known as ${nick}")
}
Modify
- Add
/flip: answer “Heads” or “Tails” withRandom(0, 1). - Add
/roll2: roll two dice, and answer with both rolls and the total. Let/roll2 20set the sides of both, as/roll 20does. - Make
/pmtell the receiver how to answer: add “(reply with /pm name message)” after the text, with the sender’s name filled in.
Make
Make a /vote yes and /vote no poll. A sign shows the two tallies, and
/vote reset clears the poll. Anything else after /vote gets a usage line
back. Then add a /vote close that stops counting until the next reset.
chip sign -> decal Text
Good to Know
- A command fires for whoever types it, anywhere in the world. Check the player yourself if only some should be able to use it. Moderation shows how.
argumentsis the rest of the line as the player typed it: extra spaces, any case, any symbols. Trim it, and escape it before showing it.
See ChatCommand and FindPlayer in the reference.
Next: Every Player.