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:
- First visit:
recallreturns null, so we setnto 0, then increment to 1, store it, and say "visitor number 1." - Second visit:
recallreturns 1, we increment to 2, store it. - And so on.
The null value
null is the "no value" value. It appears when:
recallreads a slot that was never stored.- A block has an empty body.
- A command like
dothat has no meaningful return value.
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
store entity 'slot' valuewrites persistent state.recall entity 'slot'reads it back (null if unset).forget entity 'slot'deletes it.- Local variables (
let) reset each invocation;store/recallpersist across invocations. - Store on
$selffor mob-private state, on$actorfor player state that other scripts can check.