Skip to content
DG Scripts

Testing and debugging

Separate structural validation, prototype inspection, event execution, and persistent-state verification. Each layer catches a different class of failure.

Implementation trailStatic world tooling: scripts/world/wtool.py. Runtime diagnostics and limits: src/dgscript/dg_scripts.c.

Test in five layers

Recordwtool validate
Prototypetlist + tstat
Attachmentowner stat
Eventpositive + negative
Stateglobals + reset
  1. Validate the world records and references.
  2. Confirm the saved trigger type, Numeric Arg, Arguments, and body.
  3. Confirm the right trigger is attached to the right owner type.
  4. Cause the exact game event under controlled conditions.
  5. Inspect local effects, owner globals, player globals, and repeat behavior.

Static world validation

Repository root
python3 scripts/world/wtool.py validate --zone 118

Use --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 familyPositive caseNegative and boundary cases
ChanceTemporarily test at 100 when safe, then restore the designed value.Zero, repeated rolls, empty zone, and Global behavior.
CommandExact canonical command and intended argument.Abbreviation, unrelated prefix match, empty arg, hidden command token, return 0 path.
Speech / ActExpected word, phrase, or substring.Case changes, embedded substring, multiple phrases, actor visibility.
Enter / Greet / LeaveEach intended direction with a valid actor.Wrong direction, teleport arrival, staff target rules, movement veto.
Object actionGet, drop, give, wear, remove, or consume normally.Owner purges itself, return false, wrong inventory/equipment/room mask.
CombatStart combat and cross configured threshold.Damage replacement of 0, negative, and expected positive values; actor/victim roles.
Timer / TimeFresh object timer expiry or exact in-game hour.Object extracted early, timer reset, hour wrap, duplicate instances.
Zone Reset / Login / LoadCause 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 rdelete or vdelete, 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_SCRIPT is 13 RL_SEC, intentionally offset from the mobile pulse.
Recursion
MAX_SCRIPT_DEPTH is 10; exceeding it logs the chain and extracts the owner's script.
Loop yield
At 30 loop iterations, the driver inserts wait 1 and resumes later.
Loop stop
At 100 total iterations, the driver logs the runaway loop and breaks.
Editor/body buffer
MAX_CMD_LENGTH is 16384 bytes.
Substituted line buffer
MAX_INPUT_LENGTH is 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

SymptomEvidence to collectLikely direction
No outputtstat, owner attachment, event variables, chance and direction.Wrong hook, owner mismatch, no fresh instance, empty-zone periodic check.
Unknown commandOwner type and substituted command line.Wrong m*/o*/w* family or malformed pseudo-command arguments.
Condition always true/falseActual substituted values, missing names, text versus numeric comparison.Empty substitution, broad contains/prefix match, field typo.
Stops after waitOwner still exists, resume target, script log.Owner extracted, target stale, invalid wait format.
Quest cannot repeatPlayer globals and inventory before entry.Completion/start variable not cleared or wrong namespace.
Duplicates or loopsAttachment count, load chain, hidden-command path, log recursion warning.Repeated trigger attachment, recursive load/force, unbounded while.
Movement corrupts iterationLoop 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.