-
Notifications
You must be signed in to change notification settings - Fork 1
Scripting Reference
The complete .cmd scripting language as Genie 5 implements it. New to scripting? Read Scripting first — this page is the full reference. The language is the Genie 4 Wizard-derived dialect, ported faithfully; the original Genie 4 documentation remains an authoritative reference for the language itself, while this page focuses on Genie 5's behavior and timing.
A script is a flat list of statements parsed from one or more .cmd files. A running script is always in one of three states:
- Running — ready to execute the next statement.
- Blocked — paused on a timer, prompt, match, evaluation, or the roundtime gate.
- Finished — removed from the active list.
Scripts do not run on their own thread. They are advanced off three game events plus a timer for pure pauses, and the engine yields between statements so a long or looping script can't freeze the app. A per-tick statement budget means even a tight goto loop won't monopolize the UI — it simply resumes on the next tick.
The three driving events:
| Event | Unblocks |
|---|---|
| A line of game text |
matchwait, waitfor / waitforre, actions |
| A game prompt |
wait, type-ahead accounting, roundtime re-check |
| A room change |
move, nextroom
|
When a script loads, it's transformed in a few passes: include foo is expanded recursively (cycles detected; a missing include becomes an echo, not a crash); inline conditionals (if X then put Y) are normalized to block form; labels are indexed for O(1) goto/gosub; and if/else/while jump tables are pre-computed so conditionals don't scan for their matching brace at runtime.
| Statement | Notes |
|---|---|
goto label |
Jump to label:. An unknown label stops the script. |
gosub label [args] |
Push a return point and a fresh $0..$9 arg frame, then jump. gosub clear wipes the stacks without jumping. |
return |
Pop back to the caller; with no caller, the script ends. |
exit |
Stop immediately. |
if X then … / … { } elseif … else { }
|
Inline form is normalized to block form; uses pre-built jump tables. |
while X { … } |
Tests on entry; the closing brace loops back to re-test. |
shift |
Shift %1..%9 left by one. |
| Statement | Notes |
|---|---|
put text / send text
|
Send a command to the server. ;-chained commands drain one per tick. |
put #cmd |
A meta-command (#var, #echo, …) — handled by Genie, not sent to the server. |
put .script args |
Launch script.cmd as a sub-script (doesn't consume type-ahead). |
move text |
Send text, then block until a new room arrives (or a movement-failure line unblocks it). |
nextroom |
Block for the next room change without sending anything. |
| Statement | Blocks until | Roundtime-aware? |
|---|---|---|
pause N |
N seconds elapse | Yes — checks roundtime before the next statement |
wait |
The next prompt | Yes |
delay N |
N seconds elapse | No — deliberately bypasses the RT gate (e.g. webbed/stunned sleeps) |
move / nextroom
|
A new room arrives | n/a |
waitpause |
The current roundtime expires | Yes (that's its purpose) |
| Statement | Notes |
|---|---|
match label literal / matchre label regex
|
Register a pattern; matchwait [N] then blocks until a line matches (first match wins), with optional N-second timeout. |
waitfor text / waitforre regex
|
Block until a line contains the substring / matches the regex (single-shot). |
waiteval expr |
Block until an expression evaluates true; re-checked each tick, so changing state (vitals, indicators) unblocks it. |
Regex captures from matchre / waitforre / actions land in the current $0..$9 frame.
| Statement | Notes |
|---|---|
var name value |
Set %name (value is substituted before storage). Synonyms: setvariable, setvar. |
unvar name |
Remove %name. |
math var op N |
In-place add / subtract / multiply / divide / set. |
eval var expr / evalmath var expr
|
Evaluate an expression; evalmath coerces to numeric. |
random low high |
Uniform random into %r. |
timer start / stop / clear
|
Per-script stopwatch; %timer reads live elapsed seconds. |
save N value |
Genie 4 %s storage. |
| Statement | Notes |
|---|---|
action body when pattern / whenre pattern
|
Register a reaction; on a matching line, run body (captures land in a pushed $-frame). |
action body when eval expr |
Fires on the rising edge of expr becoming true. |
action (label) on / off / remove; action on / off / clear
|
Enable/disable/drop actions by label or globally. |
| Statement | Notes |
|---|---|
echo text |
Print to the echo channel (main window + Scripts panel). |
debug N |
Per-script trace verbosity (1 = goto/gosub/return … 10 = every line). |
js … / plugin …
|
Parsed for Genie 4 parity; JavaScript execution is a 🚧 roadmap item (see below). |
Two namespaces, distinguished by prefix:
| Prefix | Namespace | Lifetime | Set by |
|---|---|---|---|
%name |
per-script locals | the script |
var / math / eval…; %0..%9 seeded with script args |
$name |
engine-wide globals | the session | live game state and #var / #tvar
|
$0..$9 |
the top $-frame |
a gosub call or the latest regex match |
gosub args, matchre, waitforre, action firing |
% reads locals only. $ reads the top frame for $0..$9, then falls back to globals. Name resolution, %%name / $$name double-evaluation, and %name(N) pipe-array indexing all follow Genie 4 rules.
These live game-state globals are mirrored as events arrive (a non-exhaustive list):
| Global | Source |
|---|---|
$health, $mana, $spirit, $stamina/$fatigue, $concentration, $encumbrance
|
progress bars |
$roundtime, $casttime
|
live seconds remaining |
$righthand / $righthandnoun / $righthandid (and left*) |
held items |
$preparedspell, $stance
|
prepared spell, stance |
$standing, $kneeling, $prone, $sitting, $stunned, $hidden, $invisible, $dead, $webbed, $joined, $bleeding, $poisoned, $diseased
|
status indicators (1/0) |
$north, $northeast, … $up, $down, $out
|
compass exits (1/0) |
$roomname, $roomdesc, $roomexits, $roomobjs, $roomplayers, $gameroomid
|
room info |
$charactername, $game, $connected
|
session |
Because globals are mirrored at event time (not on access), use timer start / %timer for wall-clock waits rather than diffing $roundtime between prompts. Type #vars at the command bar for the live list.
DragonRealms' server does not send a prompt when roundtime expires — it only prompts in response to commands. So a roundtime-gated script has nothing in the natural event flow to wake it. The engine handles this by scheduling a one-shot timer for the remaining roundtime (read live from the game state) and re-checking when it fires. Roundtime is computed from the absolute timestamp the parser captured, so it's correct regardless of whether the roundtime or the prompt arrived first.
Commands you put to the game contribute to an in-flight counter that's decremented on each prompt. A shared, auto-calibrating cap limits how many commands can be outstanding, and tightens itself if the server replies "Sorry, you may only type ahead N commands." Keeping the cap tight means your script sees a full server response (including any roundtime) before its next game-bound command is considered.
-
Per-script tracing —
debug 5traces a script's reactions;debug 10traces every line. Output goes to the echo channel. -
Scripts panel — script output (
[script],[dbg:N], in-script#echo) is forked to its own panel with separate scrollback.
-
Undefined
$varaborts the script with a clear reason instead of silently expanding to empty. Useif def(name)to guard. - Per-character script folders (see Application Folders).
-
gosubfor reusable routines — jumping into a nested/indented label isn't reliable. -
Comment rule —
#is a comment only before whitespace/end-of-line;#put northis a meta-command.
- 🚧 JavaScript
.jsarray scripts — some community scripts use Genie 4's.jsengine. Genie 5 currently runs only.cmd;.jssupport is planned (with no host access by default, for safety).
- Scripting — the friendly tour.
- Configuration & Rules — triggers, variables, and classes scripts build on.
- Architecture — where the script engine sits in the pipeline.
Genie 5 — a cross-platform DragonRealms client · Repository · Discord · GPL-3.0
Alpha software. Pages describe current behavior; 🚧 marks roadmap items that aren't shipped yet.
🐤 Start here
🚶 Everyday use
- Connecting & Profiles
- The Interface
- Configuration & Rules
- Scripting
- The Mapper
- Updating Maps & Scripts
- Lich 5 Integration
🏃 Going deeper
- Scripting Reference
- Cross-Zone Travel
- Plugins
- Keeping Up to Date
- AI Advisor (planned)
- Policy Compliance
- Architecture
- Building from Source
- Troubleshooting & FAQ