Control flow

How a script chooses what to run and how it stops. Control flow is not special syntax — if, return, break, continue, and the rest are ordinary command calls that take block arguments or direct execution.

if / elif / else

if [cond] { body }
if [cond] { body } elif [cond] { body } else { body }

Conditions are tested top to bottom; the first one that is true runs its branch, and the rest are skipped. elif may appear any number of times; else, at most once and last. The condition must be a bool — a non-bool raises a type error, because there is no truthiness (see Values).

after command (say) {
  if [ge [level $actor] 10] {
    do "say welcome, veteran"
  } else {
    do "say you have much to learn"
  }
}

For an inverted test, use if [not [cond]] { … }.

if is also an expression: it yields the value of the branch that runs (with no match and no else, it yields null). The branch's value is its last statement's value, so that statement must be a value-producing call:

let label [if [ge [level $actor] 10] { [upper "veteran"] } else { [upper "novice"] }]
do "say you are a $label"

Against a level-26 actor $label is VETERAN. Note the branch bodies use [upper "veteran"], a command call — a bare "veteran" in statement position would be read as a command and fail.

return

return value exits the enclosing block, def, or handler, yielding value. Bare return yields null. A return inside a loop unwinds out of the loop.

def classify { <c>
  if [ge [level $c] 20] { return [upper "elite"] }
  return [upper "common"]
}

break and continue

Inside a loop body (each, select, every, some):

after command (say) {
  each [words "1 2 3 4 5"] { <n>
    if [streqi $n '3'] { continue }
    if [streqi $n '5'] { break }
    do "say n is $n"
  }
}

It reports n is 1, n is 2, n is 4, then stops. (Compare the words as strings — '3' — since words yields strings, not ints.)

break and continue affect only the nearest enclosing loop; they do not jump out of an outer loop. To escape several levels, set a flag with set and test it. A break/continue with no enclosing loop propagates out and stops the script.

halt

halt stops the current execution immediately. Nothing after it in the handler runs.

after command (say) {
  do "say first"
  halt
  do "say never reached"     # not executed
}

Only "first" is said.

pause

pause n suspends the script for n ticks, then resumes right where it left off with its locals intact — the one way a script spans game ticks.

after enter {
  do "bow $actor"
  pause 3
  do "emote points to a sign."
}

nuke

nuke cancels every other script currently running on the same owner — the running script that calls nuke keeps going, but any sibling scripts on the same creature/object/room are terminated, including ones suspended on a pause or queued to run later. Use it when a script needs to take sole control of its owner and stop competing handlers (e.g. an aggressive sequence that should override a paused idle routine).

handle command {
  require [streqi $arg "stop"]
  nuke
  do "say everything else is cancelled."
}

See also