Chapter 4: Persistent state

Local variables (from let) are fresh every time a handler runs — they do not survive between events. To make a mob remember something across invocations, use store and recall.

Storing and recalling values

store $self 'mood' 'happy'

This writes the value 'happy' into a slot called 'mood' on the mob ($self). The slot persists as long as the mob exists.

let mood [recall $self 'mood']

This reads the slot back. If the slot was never written, recall returns null.

Example: a mob that counts visitors

after enter {
  let n [recall $self 'visitor_count']
  if [eq $n null] {
    set n 0
  }
  set n [+ $n 1]
  store $self 'visitor_count' $n
  do "say You are visitor number $n!"
}

Walk in and out several times. The count increases with each visit.

Let's trace through what happens:

  1. First visit: recall returns null, so we set n to 0, then increment to 1, store it, and say "visitor number 1."
  2. Second visit: recall returns 1, we increment to 2, store it.
  3. And so on.

The null value

null is the "no value" value. It appears when:

Test for null with eq:

if [eq [recall $self 'quest_state'] null] {
  do "say I have no quest for you yet."
}

Or use exists to check if something is non-null:

if [exists [recall $self 'quest_state']] {
  do "say Your quest is in progress."
}

Example: a quest-giving NPC

This mob offers a quest, tracks whether the player accepted, and responds differently on return:

after command (say) {
  require [keyword $args quest job task]

  let state [recall $self 'quest_given']

  if [not [exists $state]] {
    do "say I need someone to clear the rats from the cellar."
    do "say Say 'accept' if you are willing."
    store $self 'quest_given' false
  } elif [eq $state false] {
    do "say Well? Will you accept the task?"
  } else {
    do "say Thank you, the quest is underway."
  }
}

after command (say) {
  require [keyword $args accept yes]
  require [eq [recall $self 'quest_given'] false]
  store $self 'quest_given' true
  do "say Excellent! Head down to the cellar."
}

Notice there are two after command (say) handlers. When the first handler's require passes and it runs to completion, the script stops — the second handler is not reached. The second handler only runs when the first handler's require fails (the player said "accept" instead of "quest"). More on this in Chapter 7.

Storing on other entities

store and recall work on any entity — not just $self. You can store state on the player:

after command (say) {
  require [keyword $args bless]
  store $actor 'blessed_by_priest' true
  do "say Go in peace, [name $actor]."
}

Another mob's script could then check this:

after enter {
  require [isplayer $actor]
  if [eq [recall $actor 'blessed_by_priest'] true] {
    do "say Ah, the priest has blessed you. You may pass."
  }
}

Forgetting stored values

forget removes a slot:

forget $self 'quest_given'

After this, recall $self 'quest_given' returns null again.

Slots are strings

The slot name must be a string. The value can be any type — integer, string, boolean, or even an entity reference. Choose descriptive slot names to avoid collisions with other scripts.

Key points

Next: Chapter 5: Working with entities