Migrating from Other Clients
Rune has no in-client command language: scripting is Lua. Aliases, triggers,
and timers live in ~/.config/rune/init.lua (auto-loaded at startup), and the
edit loop is: change the file, /reload, keep playing. /lua <code> runs
one-liners without touching a file.
A trigger you’d write like this in TinTin++:
#action {%1 attacks you} {flee}looks like this in init.lua:
rune.trigger.regex("(\\w+) attacks you", "flee")From TinTin++
Section titled “From TinTin++”| TinTin++ | Rune equivalent |
|---|---|
#alias {k} {kill} |
rune.alias.exact("k", "kill"); typed args are appended, so k rat sends kill rat |
#alias {gr %1} {get %1;wear %1} |
rune.alias.regex("^gr (.+)$", "get %1;wear %1") |
#action {%1 attacks you} {flee} |
rune.trigger.regex("(\\w+) attacks you", "flee") |
#gag {spam line} |
rune.trigger.contains("spam line", nil, { gag = true }) |
#highlight {gold} {yellow} |
rune.trigger.contains("gold", function(m, ctx) return rune.style.yellow(ctx.line:clean()) end) |
#substitute |
a trigger action returning the rewritten string |
#tick / #ticker |
rune.timer.every(60, "save", { name = "tick" }) |
#delay {5} {stand} |
rune.timer.after(5, "stand") |
#var |
plain Lua variables (rune.session/rune.store for state that must survive /reload/restarts) |
#if, #math, #loop |
Lua (if, arithmetic, for) |
#showme |
rune.echo(text) |
#split |
a native rune.ui.layout({ type = "row", children = ... }) row/column tree |
#session x host port |
/connect host port, /world add for bookmarks |
#read file.tin |
/load file.lua |
#write |
your scripts are already files |
#3 north |
works as-is; repeat an alias or use a Lua loop for command sequences, not {...} blocks |
; separator |
works as-is: kill rat;loot |
From Mudlet
Section titled “From Mudlet”The scripting language is the same; the API names differ:
| Mudlet | Rune equivalent |
|---|---|
send("kill rat") |
rune.send("kill rat") |
echo("text") / cecho(...) |
rune.echo(text), colored via rune.style.* |
matches[2] (first capture) |
matches[1]; there is no whole-match slot |
tempTimer(5, code) |
rune.timer.after(5, action) |
tempRegexTrigger(pattern, code) |
rune.trigger.regex(pattern, action) |
| prompt trigger | rune.trigger.regex(pattern, action, { on = "prompt" }) |
| script editor window | your $EDITOR; Ctrl+E edits the input line in it too |
From MUSHclient
Section titled “From MUSHclient”The scripting language is the same; the API names differ. If you’re using MUSHclient’s XML syntax for creating triggers, aliases, and timers, you’ll need to convert those to Lua first.
| MUSHclient | Rune equivalent |
|---|---|
Send("kill rat") |
rune.send_raw("kill rat") |
Execute("kill rat") |
rune.send("kill rat") |
Note("text") |
rune.echo(text) |
wildcards[1] |
matches[1] |
DoAfter(5, "drink") |
rune.timer.after(5, "drink") |
tempRegexTrigger(pattern, code) |
rune.trigger.regex(pattern, action) |
EnableTrigger("tname",false) |
rune.trigger.disable("tname") |
SetVariable("varname","value") |
rune.store.set("varname","value") |
OnPluginPartialLine |
See Prompt triggers |
Some functions, such as ColourNote, have no direct equivalent. A small Lua
wrapper around rune.style.* can replace them.
Prompt triggers
Section titled “Prompt triggers”Clients expose prompt handling under different names. Rune uses
on = "prompt" as an option on an ordinary trigger:
| Client concept | Rune equivalent |
|---|---|
TinTin++ #prompt / RECEIVED PROMPT event |
trigger with { on = "prompt" } |
| zMUD/CMUD Trigger on Prompt | trigger with { on = "prompt" } |
Blightmud trigger with prompt = true |
trigger with { on = "prompt" } |
| Mudlet prompt trigger | trigger with { on = "prompt" } |
MUSHclient OnPluginPartialLine |
prompt trigger to match text, or the prompt hook to observe every update |
Prompt triggers see the partial line and prompts confirmed by Telnet GA/EOR. Complete lines go through output triggers. See the Triggers guide for the full model.
Capture references
Section titled “Capture references”Regex aliases and triggers substitute %1, %2, and so on from captures
in string actions, so most one-liners port verbatim. Function actions
receive (matches, ctx) when you need logic:
rune.trigger.regex("^(\\w+) tells you '(.+)'$", function(matches) rune.echo(rune.style.cyan("TELL from " .. matches[1]))end)What carries over unchanged
Section titled “What carries over unchanged”; chaining, #N repeats, /commands, up-arrow history,
Ctrl+R history search, and tab completion all behave the way
terminal-client muscle memory expects.
Where things live
Section titled “Where things live”Everything lives under ~/.config/rune/; the full path table is in
Installation. Your
scripts go in init.lua; bookmarks and durable state in store.json.
Full signatures for every rune.* namespace:
API reference.
Triggers is where most ports start: match modes, captures, gagging, and rewriting in rune’s terms.