Chapter 3: Variables and control flow

Scripts can declare local variables, do arithmetic, and branch based on conditions. This chapter covers let, set, if, and each.

Local variables with let and set

let creates a new variable. set changes one that already exists.

after command (say) {
  require [keyword $args count]
  let n [count [people [room $self]]]
  do "say There are $n people in this room."
}

Breaking it down:

Note that let and set write the variable name without the $ sigil. The $ is only used when reading a variable.

let x 10          # create x with value 10
set x [+ $x 1]   # change x to x + 1 (now 11)

Arithmetic

Math uses prefix notation inside [...]:

[+ 3 4]           # 7
[- 10 3]          # 7
[* 2 5]           # 10
[/ 20 4]          # 5
[% 17 5]          # 2  (remainder)

Combine them by nesting:

let damage [+ [* 2 $strength] $weapon_bonus]

Comparisons

Comparisons also use prefix notation and return booleans:

[eq $x $y]        # equal (works for any type)
[ne $x $y]        # not equal
[gt $x $y]        # greater than (integers only)
[lt $x $y]        # less than
[ge $x $y]        # greater or equal
[le $x $y]        # less or equal

Conditional execution with if

after command (say) {
  require [keyword $args time]
  let h [hour]
  if [lt $h 6] {
    do "say It is still night."
  } elif [lt $h 12] {
    do "say Good morning."
  } elif [lt $h 18] {
    do "say Good afternoon."
  } else {
    do "say Good evening."
  }
}

The condition must be a boolean (true or false). Integers and strings are not automatically treated as booleans — you need a comparison like [gt $x 0], not just $x.

Looping with each

each iterates over a collection:

after command (say) {
  require [keyword $args roll-call]
  each [people [room $self]] { <person>
    do "say I see [name $person]."
  }
}

You can iterate over words in a string:

after command (say) {
  each [words $arg] { <word>
    do "say Word: $word"
  }
}

If the player types say one two three, the mob says each word separately.

Combining conditions

Use and, or, and not:

if [and [gt $level 10] [lt $level 20]] {
  do "say You are mid-level."
}

if [or [eq $class 'Warrior'] [eq $class 'Knight']] {
  do "say A fighting type!"
}

if [not [isplayer $actor]] {
  do "say You are not a player."
}

All operands must be booleans. [and] and [or] take two or more arguments.

Example: a level-checking guard

after command (say) {
  require [keyword $args pass enter]
  let lvl [level $actor]
  if [lt $lvl 10] {
    do "say You are too inexperienced, [name $actor]. Come back when you are stronger."
  } else {
    do "say You may pass, [name $actor]."
    do "emote steps aside."
  }
}

Example: counting objects

after command (say) {
  require [keyword $args inventory]
  let n [count [objects $actor]]
  do "say You carry $n items, [name $actor]."
}

Key points

Next: Chapter 4: Persistent state