Testing and debugging
Separate structural validation, prototype inspection, event execution, and persistent-state verification. Each layer catches a different class of failure.
scripts/world/wtool.py. Runtime diagnostics and limits: src/dgscript/dg_scripts.c.Test in five layers
- Validate the world records and references.
- Confirm the saved trigger type, Numeric Arg, Arguments, and body.
- Confirm the right trigger is attached to the right owner type.
- Cause the exact game event under controlled conditions.
- Inspect local effects, owner globals, player globals, and repeat behavior.
Static world validation
python3 scripts/world/wtool.py validate --zone 118Use --zone <number> for one or more zones, --paths for selected files, --mini for the mini world, or --all for the full indexed world. Add --strict when warnings must fail the run.
The validator can catch malformed flat-file records, bad flags, and indexed reference problems. It does not execute DG command bodies or prove that a command-trigger condition is reachable.
Read-only lookup is useful before boot
wtool show trigger <vnum> displays a normalized trigger record, and wtool refs trigger <vnum> can help trace incoming and outgoing world references supported by the tool.
Prepare a clean runtime test
- Save TRIGEDIT and the owning MEDIT, OEDIT, or REDIT session.
- Use
tstat <vnum>to read back the prototype. - Load or reset a fresh mobile/object instance when attachments or load behavior changed.
- Inspect the live owner and verify the trigger is attached once and has the correct intended type.
- Use a test character whose quest variables and inventory state are known.
- Keep a second observer present for
echoaround, room messages, and visibility-sensitive events.
For command triggers, test the full command, abbreviations that the Arguments prefix accepts, a different command with the same prefix, empty arguments, wrong targets, and a valid target. Confirm whether the command falls through or is consumed.
Event-specific test matrix
| Event family | Positive case | Negative and boundary cases |
|---|---|---|
| Chance | Temporarily test at 100 when safe, then restore the designed value. | Zero, repeated rolls, empty zone, and Global behavior. |
| Command | Exact canonical command and intended argument. | Abbreviation, unrelated prefix match, empty arg, hidden command token, return 0 path. |
| Speech / Act | Expected word, phrase, or substring. | Case changes, embedded substring, multiple phrases, actor visibility. |
| Enter / Greet / Leave | Each intended direction with a valid actor. | Wrong direction, teleport arrival, staff target rules, movement veto. |
| Object action | Get, drop, give, wear, remove, or consume normally. | Owner purges itself, return false, wrong inventory/equipment/room mask. |
| Combat | Start combat and cross configured threshold. | Damage replacement of 0, negative, and expected positive values; actor/victim roles. |
| Timer / Time | Fresh object timer expiry or exact in-game hour. | Object extracted early, timer reset, hour wrap, duplicate instances. |
| Zone Reset / Login / Load | Cause a real hook with a clean instance. | Repeated reset/load, recursion chain, and state already present. |
Verify state, waits, and interruption
A successful message does not prove the state machine. After every state-changing path, inspect the player or owner and then retest:
- Before the first run, confirm the variable is absent or has the intended starting value.
- After
global, confirm the value lives on the owner and survives a new trigger run. - After
remote, confirm the target's numeric ID, variable name, value, and context. - After
rdeleteorvdelete, confirm only the intended state was removed. - Disconnect and reconnect when testing player-persisted variables.
For a waiting trigger, test the normal resume, owner extraction during the wait, actor movement, target disappearance, and overlapping attempts to fire the same trigger while it is already running. A trigger with nonzero depth is not started again by the normal trigger check.
Reset deliberately
Do not use broad variable deletion as a casual test reset. Record the exact variables a flow owns, remove only those, and restore any inventory or room population prerequisites.
Runtime limits and scheduling
- DG pulse
PULSE_DG_SCRIPTis13 RL_SEC, intentionally offset from the mobile pulse.- Recursion
MAX_SCRIPT_DEPTHis 10; exceeding it logs the chain and extracts the owner's script.- Loop yield
- At 30 loop iterations, the driver inserts
wait 1and resumes later. - Loop stop
- At 100 total iterations, the driver logs the runaway loop and breaks.
- Editor/body buffer
MAX_CMD_LENGTHis 16384 bytes.- Substituted line buffer
MAX_INPUT_LENGTHis 512 bytes for each runtime command line.
These guards prevent one trigger from monopolizing the game loop, but hitting one is still a script defect unless the yield is explicitly part of a bounded design.
Diagnose by symptom
| Symptom | Evidence to collect | Likely direction |
|---|---|---|
| No output | tstat, owner attachment, event variables, chance and direction. | Wrong hook, owner mismatch, no fresh instance, empty-zone periodic check. |
| Unknown command | Owner type and substituted command line. | Wrong m*/o*/w* family or malformed pseudo-command arguments. |
| Condition always true/false | Actual substituted values, missing names, text versus numeric comparison. | Empty substitution, broad contains/prefix match, field typo. |
| Stops after wait | Owner still exists, resume target, script log. | Owner extracted, target stale, invalid wait format. |
| Quest cannot repeat | Player globals and inventory before entry. | Completion/start variable not cleared or wrong namespace. |
| Duplicates or loops | Attachment count, load chain, hidden-command path, log recursion warning. | Repeated trigger attachment, recursive load/force, unbounded while. |
| Movement corrupts iteration | Loop body around teleport/purge. | Next pointer was read after moving the current character. |
Script errors are reported through script_log(), including malformed blocks, invalid UIDs, bad wait syntax, missing variables for global/remote, unknown affect properties, recursion, and runaway loops. Search by trigger VNUM first.