Chapter 7: Advanced handlers
This chapter covers the three handler phases, how multiple handlers chain together, how to intercept the default action, and more event types.
The three phases
Every event has three phases:
before— runs before the default action. You can announce or prepare, but you cannot prevent the action.handle— runs alongside the default action. This is the phase that can intercept (suppress) the default action.after— runs after the default action completes. Most handlers use this phase.
before command (drop) {
do "say Are you sure you want to drop something?"
}
after command (drop) {
do "say You dropped it!"
}
The before handler fires before the item is dropped. The after
handler fires after. In both cases, the drop still happens normally.
Intercepting with handle
A handle handler can suppress the default action. If the handler
body executes a successful action command (like do, oload,
trans, etc.), the default action is suppressed:
handle command (north) {
do "say You shall not pass!"
}
When a player types north, the mob says the line and the do
counts as a successful action — so the actual movement north is
suppressed. The player stays in the room.
Compare this with after:
after command (north) {
do "say Safe travels!"
}
Here the player moves north normally, and the mob speaks after.
What counts as an action
Commands like do, force, oload, mload, trans, damage,
spell, tag, echo, emit are action commands. If they succeed,
they suppress the default.
Commands that only affect variables or flow control (let, set,
store, recall, require) do not count as actions and do not
suppress anything.
Multiple handlers and chaining
You can have several handlers for the same phase and event. They are tried in source order. A handler that runs to completion stops the chain — later handlers are not reached.
The chain advances to the next handler only when:
- A filter does not match, or
- A
requireguard fails, or - An
unlessguard succeeds.
after command (say) {
require [keyword $args quest]
do "say Let me tell you about the quest."
}
after command (say) {
require [keyword $args shop]
do "say The shop is to the east."
}
after command (say) {
do "say I don't understand. Try 'quest' or 'shop'."
}
If the player says "quest", the first handler matches and runs — the
others are skipped. If the player says "shop", the first handler's
require fails, advancing to the second, which matches. If the player
says anything else, both require guards fail, and the third handler
(the fallback) runs.
This pattern gives you an if/elif/else chain across handlers.
The unless guard
unless is the inverse of require:
after enter {
unless [isplayer $actor]
do "say A mortal approaches."
}
Wait — that is backwards. unless advances to the next handler if
the condition is true. So this says: "unless the actor is a player,
skip to the next handler." The mob only speaks when $actor is not
a player.
That means unless [isplayer $actor] is equivalent to
require [not [isplayer $actor]]. Use whichever reads more naturally.
Event types
Beyond command and enter, here are the other events:
tick
Fires periodically on the mob. No $actor is available.
after tick {
if [random 20] {
do "say Anyone need a drink?"
}
}
[random 20] is true 20% of the time. Tick handlers are great for
ambient behavior.
fight
Fires when someone initiates combat with the mob.
after fight {
do "say You dare challenge me, [name $actor]?"
}
combat
Fires each combat round while the mob is fighting. No $actor.
after combat {
if [random 30] {
do "say Feel my wrath!"
}
}
death
Fires when a creature dies. $actor is the deceased, $killer is
the killer (may be null).
before death {
require [eq $actor $self]
do "say I'll be back..."
}
after death {
require [not [eq $actor $self]]
do "emote bows solemnly."
}
The first handler fires when the mob itself dies. The second fires when someone else dies in the room.
A handle death can even prevent the death — if it performs a
successful action:
handle death {
require [eq $actor $self]
damage $self -100
do "emote's wounds knit shut!"
}
This heals the mob and suppresses the death.
give
Fires when someone gives an object to the mob. $object is the item.
after give {
do "say Thank you for the [name $object], [name $actor]."
}
load
Fires once when the mob is first loaded into the world. No $actor.
after load {
do "emote stretches and looks around."
}
idle
Fires when the mob has nothing else to do. No $actor.
after idle {
randomly { do "yawn" } or { do "stretch" } or { do "look" }
}
spell
Fires when a spell is cast. $actor is the caster, $spell is the
spell number. Filters take spell numbers:
after spell (42) {
do "say Impressive magic, [name $actor]!"
}
Object and room events
Scripts can also be attached to objects and rooms:
Objects:
olc oedit <vnum>, thenolc oset script. Object events includeget,drop,wear,remove,put,getfrom,wield,eat,drink,sacrifice,search.$selfis the object;$actoris the creature acting on it.Rooms:
olc redit(edits the current room), thenolc rset script. Room events includecommand,enter,leave,tick, and others.$selfis the room.
The randomly form
randomly picks one branch at random:
after tick {
randomly {
do "say What a lovely day."
} or {
do "say I wonder what's for dinner."
} or {
do "yawn"
}
}
Each branch has an equal chance. The or keyword separates branches.
The pause command
pause suspends the script for a number of game ticks, then resumes:
after enter {
do "say Welcome."
pause 3
do "say Make yourself at home."
}
The mob says "Welcome," waits 3 ticks, then says the second line. Local variables survive across the pause.
Self-suppression
A mob does not trigger its own command, enter, leave, or spell
handlers. This prevents infinite loops — a do "say ..." in a
command (say) handler will not re-trigger the handler.
Key points
- Three phases:
before(advisory),handle(can intercept),after(most common). - Interception: a successful action in
handlesuppresses the default. - Handler chaining: handlers try in source order;
require/unlessfailures advance to the next. randomly { } or { } or { }for random behavior.pause Nsuspends and resumes after N ticks.- Self-suppression prevents a mob from triggering its own handlers.
Next: Chapter 8: Debugging