Getting started
Build one small, observable behavior first. The goal is to understand which event starts a script, who owns it, and which state survives after it stops.
src/dgscript/dg_triggers.c. Execution: src/dgscript/dg_scripts.c. Editing: src/dgscript/dg_olc.c.The runtime in one pass
A trigger prototype has a VNUM, name, intended owner type, event flags, Numeric Arg, Arguments string, and command list. Attaching that prototype gives an entity a runnable trigger instance. When a matching hook fires, the driver substitutes %variables% and sends non-control commands to the interpreter for the owner type.
A trigger is not a polling script
Most triggers run only because a specific game hook calls them. Random and Time triggers are the periodic exceptions, and their Global flag changes whether empty-zone checks are allowed.
1. Choose the owner that receives the event
Ownership is structural, not cosmetic. It selects the available trigger types, the meaning of %self%, and the command interpreter used after control commands are handled.
| Owner | Use it when | Commands | Typical events |
|---|---|---|---|
| Mobile | An NPC acts, fights, speaks, remembers, receives, or reacts as a character. | m* plus normal character commands | Greet, Speech, Fight, Bribe, Damage |
| Object | The behavior belongs to a carried, worn, room, timed, or consumed object. | o* | Get, Give, Wear, Timer, Consume |
| Room | The location observes entrants, speech, doors, drops, login, or zone reset. | w* | Enter, Command, Zone Reset, Login |
Do not choose a room owner merely because an effect happens in a room. Choose it when the room receives the relevant hook. The trigger matrix shows every owner/event combination.
2. Rebuild a small live trigger
The Dollhouse room trigger below reacts only when someone enters from the west. It is useful as a first exercise because the trigger has one event variable, short waits, and visible output.
- VNUM
- Use a free VNUM in your assigned zone
- Name
Hiding girl beckons- Intended for
- Rooms
- Trigger type
- Enter
- Numeric Arg
100(100 percent chance)- Arguments
- Empty
if %direction% == west
wait 1 s
%send% %actor% You hear a shuffling sound from under the bed.
wait 1 s
%send% %actor% A child's voice whispers: Quick, crawl in here!
end- Enter
trigedit <vnum>and fill the fields above. - Open the Commands editor, enter the body, save, and quit.
- Open REDIT for a test room, choose
S, then attach the trigger by VNUM. - Save the room, leave it, and enter from west and from a different direction.
%send% is an owner-neutral pseudo-command. On a room owner it resolves to the room implementation of send; the command guide explains the mapping.
3. Know where values come from
The Enter hook creates actor and direction for this run. %actor% substitutes the actor's internal UID where a command needs an entity target; %actor.name% reads a field. Trigger-local variables created with set disappear when the run finishes.
set clue redLocal to this trigger run.global clueMoves that local value into the owner's script-global state, under the current context.remote clue %actor.id%Copies the local value to the actor's script-global state.rdelete clue %actor.id%Deletes that remote global value.
UID rule
Pass event-supplied UIDs directly to entity commands. Use an entity's .id only where a command explicitly asks for a numeric script ID, such as remote or rdelete. Use makeuid when a marked UID must be built from an ID or nearby name; never construct or guess its prefix.
4. Attach, reload, and test both paths
Permanent attachments are edited from the S scripts menu in MEDIT, OEDIT, or REDIT and written as T <trigger-vnum> records in world files. The staff attach command affects a runtime instance and is best used for controlled inspection.
- Save both the trigger and its owning prototype or room.
- Load a fresh mobile or object instance after changing attachments.
- Exercise the matching case and at least one non-matching case.
- Check visible output, owner state, player state, and logs.
- Run
python3 scripts/world/wtool.py validate --zone <zone>.
See Testing and debugging for a repeatable verification sequence and runtime limits.
Common first-script mistakes
| Symptom | Likely cause | Correction |
|---|---|---|
| Never fires | Wrong owner/event pairing, no attachment, failed chance roll, or zone is empty for a periodic trigger. | Use tstat, inspect the owner, and temporarily make the condition observable. |
| Intercepts too much | Command prefix or wildcard is broad, and the body does not reject unrelated commands. | Compare %cmd.mudcommand% and %arg%; use return 0 on the non-match path. |
| State vanishes | set created only a local variable. | Use global for owner state or remote for target state. |
| Wrong command family | An m*, o*, or w* command was used on another owner. | Use the matching family or an owner-neutral pseudo-command. |
| Old behavior remains | A live owner still has an older attachment set, aggregate event flags, or owner-global state. | Save both editors, reload the owner, and retest from a clean state. |
Return values are hook-specific
return N sets an integer result, but only event hooks that read that result give it gameplay meaning. Receive can veto a transfer, and Damage uses the returned value as replacement damage. Do not assume every trigger type consumes it.