Variables
A variable is a named binding holding a value. Variables live
in the variable namespace, read with the $ sigil, and are distinct
from the command namespace (Declarations and scope).
They are also distinct from persistent entity state, which is not a
variable at all and is reached only through store / recall (below).
What a variable can be
A variable holds a single value of any type (Types).
All variables are lexical: read with $name (or ${name}) and
resolved to the nearest enclosing binding of that name. Bindings come
from block parameters, let/const locals, handler-injected names, and
top-level const; the full resolution rules are in
Declarations and scope.
Reading a variable
$name (or ${name}) evaluates to the value of the nearest binding of
name in the lexical chain.
$actor # the creature that triggered the current handler
$self # the script's owner
${count} # braced form, identical meaning
$room # a let/const local or a block parameter
A name with no binding anywhere in the chain is a compile-time error
("undefined variable $name"). A handler-injected name whose event does
not provide it (e.g. $actor for a tick) is unbound, and reading it is a
run-time error.
Declaring and mutating locals — let and set
let name value # introduce a new local in the current scope
set name value # mutate an existing binding, searching outward
let name valuecreates a fresh mutable binding in the current scope, shadowing any outer binding of the same name. Declaring a name already bound in the same scope is a compile-time error.set name valuerewrites an existing binding found up the chain. It never creates a binding. Targeting a name that is not bound, or an immutable binding (aconst), is a compile-time error.
let counter 0
set counter [+ $counter 1] # mutates the let above
The name in let/set/const is written without the $ sigil — the
sigil appears only when reading.
Because set searches outward, an inner block can mutate a binding owned
by an enclosing scope — the basis of the closure-counter idiom
(Declarations and scope).
Locals do not persist across invocations
Locals are fresh per invocation; cross-invocation state belongs in persistent entity state. See Scope lifetime.
Persistent entity state — store and recall
Persistent state is a set of string-keyed values (slots) attached to a
game entity (mobile, object, or room). It is not part of the variable
namespace and is never found by $name lookup.
store entity slot value # write a slot
recall entity slot # read a slot (null if never stored)
forget entity slot # delete a slot (recall returns null again)
entitymust evaluate to a creature, object, or room (Types); any other type is a run-time error. Inside a handler,$selfis the owner, so$selfis the usual entity argument.slotmust be a string.storewrites the slot; the value may be of any type and survives as long as the entity does.recallreturns the stored value, or null if the slot was never written.
store $self 'state' 'gossip'
require [eq [recall $self 'state'] 'gossip']
store/recall is how scripts keep state between invocations
(Locals do not persist across invocations).
store/recall operate only on
these script-defined slots; they do not touch the creature's actual game
attributes (hp, position, vnum, weight, …), which are exposed read-only
through builtins (Built-in functions). A
store $target "hp" 50 writes a slot named hp unrelated to the
creature's actual hit points.
A companion forget $entity slot deletes a slot; a subsequent recall
returns null again. The tag/untag/hastag builtins
(Built-in functions) are independent of
store/recall.