Skip to content
DG Scripts

The Dollhouse

Zone 118 turns a compact world into a stateful narrative system. These public excerpts come directly from its live trigger file and are presented as engineering patterns, not starter boilerplate.

Public source setlib/world/trg/118.trg, with attachments in zone 118 mobile, object, and room files. Authored by Detta, Zusuk, Fizban, and Havamal.

Zone ledger

Name
The Dollhouse
VNUM range
11800-11899
Rooms
99
Mobiles
50
Objects
79
Shops
2
Triggers
95 prototypes
Quest
1 zone quest
Lifespan
8 minutes
Level range
5-10

The zone uses a consistent zn118_ player-variable namespace for start, quest, done, and clue state. Scripts split responsibility across owners: rooms detect place events, mobiles deliver character behavior, objects carry commands and timers, and player globals connect the episodes.

11802
shop
11804
girl
11822
gateway
11870
bedroom
11871
under bed
11896
focus

Pattern 1: stage dialogue with local state

Trigger 11800 is a mobile Greet trigger with a 100 percent Numeric Arg. It derives one local word, then spaces dialogue across real-time waits.

Trigger 11800 / exact command body
set gender one
if %actor.sex% == male
set gender lad
elseif %actor.sex% == female
set gender lady
end
wait 2 s
emote looks up and peers at you keenly as she smiles in greeting.
wait 2 s
say Why hello little %gender%.
wait 2 s
say Have a look around if it pleases you.
wait 2 s
say I hope you find what you are looking for.
wait 2 s
emote smiles strangely at you as she turns back to her work.
Owner
Mobile; normal say and emote reach the character interpreter.
State
gender is local and needs no cleanup.
Timing
Each wait 2 s resumes the same trigger instance.
Tradeoff
A long greeting cannot start that same instance again while it has nonzero depth.

The script's indentation is historical, but its block boundaries are explicit. New scripts should indent branch bodies for review clarity.

Pattern 2: make a guarded gateway

Trigger 11805 is an object Command trigger. Numeric Arg 3 enables the worn and inventory command locations; Arguments o catches an open-command prefix. The body then resolves the canonical command, checks the object keyword, clears prior cycle state, and moves the player and followers.

Trigger 11805 / exact command body
set eye 'eye
if %cmd.mudcommand% == open && %eye.contains('%arg%)% && %arg%
  if %actor.varexists(zn118_knifestart)%
    rdelete zn118_knifestart %actor.id%
  end
  if %actor.varexists(zn118_gravedone)%
    rdelete zn118_gravedone %actor.id%
  end
  %teleport% %actor% 11822
  set room %actor.room%
  set people %room.people%
  while %people%
    set next %people.next_in_room%
    if %people.master% == %actor%
      %teleport% %people% %actor%
    end
    set people %next%
  done
  %send% %actor% You open the eye.
  wait 1 s
  %send% %actor% A hazy mist swirls up and around you, blurring your vision for a second before clearing away.
  wait 1 s
  %force% %actor% look
  wait 1 s
  %send% %actor% The voice of a young girl whispers: Please recover what I left there.
  wait 1 s
  %load% obj 11807
  %send% %actor% A leather-strapped journal suddenly materializes on the ground.
  wait 1 s
  %send% %actor% The voice of a young girl whispers: Give the journal to the ones you meet there, they will know what to do with it.
  %purge% self
else
  return 0
end
Design moveWhy it works
Canonical command guard%cmd.mudcommand% distinguishes open from unrelated input caught by a short prefix.
Keyword contains testThe local eye text validates the player's target wording.
Explicit cycle resetOnly the variables that would corrupt a new run are deleted.
Cache next_in_roomTeleporting a follower mutates the room list; caching prevents traversal corruption.
False fallthroughreturn 0 gives irrelevant commands back to normal command handling.
Self-purge at the endThe gateway object is single-use after all timed narrative and loading finishes.

Pattern 3: hand work from a room to a mobile

Trigger 11808 is a room Enter trigger. It loads a mobile, then forces the entering actor to issue a private token. Trigger 11807, attached to that mobile, catches the token as a mobile Command trigger.

Trigger 11808 / exact command body
wait 1 s
%load% mob 11804
%force% %actor% xx118xx
Trigger 11807 / exact command body
eval room %self.room%
if (%room.vnum% == 11804)
  if !(%actor.varexists(zn118_a)%)
    emote walks into the room and peers at you.
    wait 2 s
    say You cant talk to the shadow-ones, they're not real...
    wait 2 s
    say at least not any more.
    wait 2 s
    say The others here aren't real either...
    wait 2 s
    say but then they never were.
    wait 1 s
    emote giggles as she runs off.
    set zn118_a 1
    remote zn118_a %actor.id%
  end
end
drop journal
%purge% %self%

This is a message-passing pattern: the room owns entry detection, while the mobile owns dialogue and normal character commands. The private token is coupling, so it must remain uncommon, documented, and consistent on both sides.

Guard every hidden command

The mobile verifies its room and the player's prior state before narrating. A token alone should never be sufficient authorization for a quest transition.

Pattern 4: choose from a local variable table

Trigger 11843 is a room Command trigger that assigns 21 local values, rolls a 1-based index, builds the selected variable name with escaped percent signs, then evaluates that reference.

Trigger 11843 / abridged; table entries 3-20 omitted
if %cmd.mudcommand% == examine
  if walls /= %arg%
    eval max %random.21%
    set txt[1] PATRIS
    set txt[2] PRODITIO
    * txt[3] through txt[20] use the same local-table pattern
    set txt[21] RAPIO
    set word %%txt[%max%]%%
    eval word %word%
    %send% %actor% Your eyes scan the glowing walls and alight upon the word %word%.
    if !%actor.varexists(zn118_blinddone)%
      set zn118_blindquest %word%
      remote zn118_blindquest %actor.id%
    end
  else
    return 0
  end
end

%random.21% returns 1 through 21, so every possible index has a value. The doubled percent signs preserve the selected reference for the later eval pass. The state write is conditional: completed players can still see a word without replacing their quest clue.

Abridgment note

The displayed message has its in-game color controls removed, and the middle table entries are omitted for teaching. The control flow and variable mechanism follow trigger 11843.

Pattern 5: turn a command into spatial movement

A room Enter trigger advertises an affordance only from the west. A paired room Command trigger makes crawl a bidirectional connection between rooms 11870 and 11871.

Trigger 11868 / exact command body
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
Trigger 11869 / exact command body
if %self.vnum% == 11870
  %send% %actor% You drop to your knees and crawl under the bed.
  %echoaround% %actor% %actor.name% drops to %actor.hisher% knees and crawls under the bed.
  wait 1 s
  %at% 11871 %echo% %actor.name% crawls under the bed.
  %teleport% %actor% 11871
elseif %self.vnum% == 11871
  %send% %actor% You crawl awkwardly out from under the bed.
  %echoaround% %actor% %actor.name% crawls awkwardly out from under the bed.
  %at% 11870 %echo% %actor.name% crawls out from under the bed.
  wait 1 s
  %teleport% %actor% 11870
end
%force% %actor% look

The same prototype works on both rooms by branching on %self.vnum%. %at% announces arrival at the destination before teleport, while %echoaround% excludes the actor from the departure message. The final forced look restores orientation.

Pattern 6: initialize, expire, and purge an object

Object Load trigger 11897 assigns different timer lengths by object VNUM. Object Timer trigger 11865 supplies the terminal world message and purges the expired object.

Trigger 11897 / exact command body
wait 2 s
if %self.vnum% == 11862
  otimer 3
elseif %self.vnum% == 11865
  otimer 1
elseif %self.vnum% == 11833
  otimer 1
end
Trigger 11865 / exact command body
if %self.vnum% == 11870
%echo% %self.shortdesc% decays away, a few traces of dust blowing in the wind.
else
%echo% A quivering horde of maggots consumes %self.shortdesc%.
end
%purge% self
PhaseOwner eventResponsibility
InitializationObject LoadWait until placement is settled, then set the object timer.
LifetimeObject runtimeThe core object timer counts down.
ExpiryObject TimerDescribe decay from the object's location and purge self.

Pattern 7: render progress instead of duplicating objects

Object Command trigger 11891 turns one journal into a progress view. Each section checks a completion variable, plus late-cycle overrides, and prints either revealed text or a placeholder.

Trigger 11891 / shortened structural excerpt
if %self.name% /= %arg%
  if %actor.varexists(zn118_crayondone)% || %actor.varexists(zn118_gravedone)% || %actor.varexists(zn118_gravequest)%
    %send% %actor% .  I drew you the pictures, if only you'd see,
    %send% %actor% .  crayons instead of a voice.
  else
    %send% %actor% .  - - - - - - - - - - - - - - - - - - - - - - -
  end

  * Additional sections repeat this reveal-or-placeholder structure.

  if %actor.varexists(zn118_gravedone)%
    %send% %actor% .  The ghosts shall be buried, I choose to forget,
    %send% %actor% .  and learn to forgive myself.
  else
    %send% %actor% .  - - - - - - - - - - - - - - - - - - - - - - -
  end
else
  return 0
end

This keeps the journal object stateless and makes the player globals the projection source. The three-way OR also lets a current quest phase or completed cycle reveal material consistently.

Abridgment note

Trigger 11891 contains many more reveal sections. This excerpt preserves two representative branches and marks the omitted repetition explicitly.

What to carry into a new zone

Namespace player state

zn118_ makes ownership and cleanup discoverable.

Put events on natural owners

Rooms detect place, mobiles perform character behavior, objects own use and time.

Guard broad command triggers

Resolve canonical command and target, then return false for unrelated input.

Cache mutable traversals

Save the next pointer before teleporting or purging from a linked list.

Separate start and completion

Distinct variables make interruption, repetition, and recovery testable.

Make progress visible

The journal projects state into content the player can re-read.

What not to copy blindly

  • Do not reuse the zn118_ namespace or Dollhouse VNUMs outside this zone.
  • Do not copy hidden tokens without both endpoints and all owner/location guards.
  • Do not assume historical indentation or naming is the preferred style for new work.
  • Do not extract one trigger from a cooperative flow without tracing its attachments and remote state.
  • Do not treat a static validator pass as proof that the narrative state machine is reachable.