MUD on Urbit

Scripted Room Hooks

design

Status: Implemented Date: 2026-03-29

Hooks are scripted triggers attached to rooms. When a player performs an action in a room (entering, looking, killing a mob), hooks fire automatically, checking conditions and executing actions. They enable one-time discoveries, conditional messages, rewards, traps, and dynamic world events without writing Hoon.

Structure

Each hook has three parts:

{
  "trigger": "on-enter",
  "conditions": [ ... ],
  "actions": [ ... ]
}

A room can have up to 20 hooks. Each hook can have up to 5 conditions and 10 actions. Conditions are AND’d together – all must pass for actions to fire.

Triggers

TriggerFires when…
on-enterPlayer moves into the room (any direction, recall)
on-lookPlayer types look with no arguments
on-killPlayer kills a mob in the room
on-use(reserved, not yet wired)
on-talk(reserved, not yet wired)

Conditions

All conditions must be true for the hook to fire. If a hook has no conditions, it always fires.

TypeFieldsDescription
flagflag, opCheck if a player flag is set or not-set
has-itemitem-idPlayer has an item with this template ID
level-gtevaluePlayer level >= value
level-ltevaluePlayer level <= value
kills-gtevaluePlayer total kills >= value
randomchanceRandom chance out of 100 (e.g. 25 = 25%)
room-flagflagA room flag matches (e.g. dark, safe)

Player Flags

Flags are per-player, per-session strings stored in a set. They persist for the session and reset on disconnect. Use them for one-time events:

{
  "conditions": [{"type": "flag", "flag": "saw-ghost", "op": "not-set"}],
  "actions": [
    {"type": "message", "text": "A spectral figure materializes before you..."},
    {"type": "set-flag", "flag": "saw-ghost"}
  ]
}

The player sees the ghost once. On subsequent visits, the saw-ghost flag is set, so the hook doesn’t fire.

Actions

Actions execute in order when all conditions pass.

TypeFieldsDescription
messagetextSend a system message to the triggering player
broadcasttextSend a message to everyone in the room
set-flagflagSet a player flag
clear-flagflagRemove a player flag
give-goldamountGive gold to the player
take-goldamountRemove gold (floors at 0)
give-xpamountAward XP
give-itemitem-idCreate an item instance and add to inventory
take-itemitem-idRemove first item matching template ID
teleportroomMove the player to a different room
spawn-mobmob-id, roomSpawn a mob (room 0 = current room)
healhp, mana, movesRestore vitals (capped at max)
damageamountDeal damage (floors at 1 HP)
add-effectname, durationApply a named status effect to the player (e.g. “wet”, “burning”). Duration is in regen ticks.
transform-itemseffectTransform inventory items that have a matching transforms entry on their template for this effect

Examples

One-time discovery with gold reward

{
  "trigger": "on-enter",
  "conditions": [
    {"type": "flag", "flag": "crypt-looted", "op": "not-set"}
  ],
  "actions": [
    {"type": "message", "text": "Beneath a loose stone you find a pouch of coins."},
    {"type": "give-gold", "amount": 50},
    {"type": "set-flag", "flag": "crypt-looted"}
  ]
}

Level-gated area message

{
  "trigger": "on-enter",
  "conditions": [
    {"type": "level-gte", "value": 10}
  ],
  "actions": [
    {"type": "message", "text": "The runes on the archway glow, acknowledging your power."}
  ]
}

Random ambush on entry

{
  "trigger": "on-enter",
  "conditions": [
    {"type": "random", "chance": 30}
  ],
  "actions": [
    {"type": "broadcast", "text": "Shadows coalesce into a dark figure!"},
    {"type": "spawn-mob", "mob-id": 15, "room": 0}
  ]
}

Kill reward with item

{
  "trigger": "on-kill",
  "conditions": [
    {"type": "kills-gte", "value": 5},
    {"type": "flag", "flag": "wolf-hunter", "op": "not-set"}
  ],
  "actions": [
    {"type": "message", "text": "The wolves fear you now. You find a fang amulet among the remains."},
    {"type": "give-item", "item-id": 42},
    {"type": "set-flag", "flag": "wolf-hunter"}
  ]
}

Trap room with healing fountain

[
  {
    "trigger": "on-enter",
    "conditions": [],
    "actions": [
      {"type": "damage", "amount": 10},
      {"type": "message", "text": "Poison gas seeps from the walls! You take damage."}
    ]
  },
  {
    "trigger": "on-look",
    "conditions": [{"type": "flag", "flag": "found-fountain", "op": "not-set"}],
    "actions": [
      {"type": "message", "text": "You notice a small fountain of clear water hidden in an alcove."},
      {"type": "heal", "hp": 30, "mana": 20, "moves": 0},
      {"type": "set-flag", "flag": "found-fountain"}
    ]
  }
]

Environmental effect with item transformation

A waterfall room that makes the player wet and transforms items:

{
  "trigger": "on-enter",
  "conditions": [],
  "actions": [
    {"type": "message", "text": "You pass through the cascading waterfall. You're soaked to the bone."},
    {"type": "add-effect", "name": "wet", "duration": 10},
    {"type": "transform-items", "effect": "wet"}
  ]
}

This requires item templates to have a transforms field. For example, crackers (template 42) with "transforms": {"wet": 43} become soggy crackers (template 43) when the player walks through the waterfall. The “wet” effect lasts 10 regen ticks. Items without a “wet” transform entry are unaffected.

The item templates would look like:

{"id": 42, "name": "Crackers", "transforms": {"wet": 43}, ...}
{"id": 43, "name": "Soggy Crackers", ...}

Burning hallway with damage-over-time effect

{
  "trigger": "on-enter",
  "conditions": [],
  "actions": [
    {"type": "message", "text": "Flames lick at you from vents in the walls!"},
    {"type": "damage", "amount": 15},
    {"type": "add-effect", "name": "burning", "duration": 3}
  ]
}

Adding Hooks to Rooms

Hooks are defined in the hooks array on each room in the JSON area file:

{
  "id": 6,
  "name": "Dead Garden",
  "description": "Withered plants and cracked soil...",
  "sector": "field",
  "exits": {"south": 1},
  "flags": [],
  "hooks": [
    {
      "trigger": "on-enter",
      "conditions": [{"type": "flag", "flag": "garden-visited", "op": "not-set"}],
      "actions": [
        {"type": "message", "text": "The dead vines shudder as you enter..."},
        {"type": "set-flag", "flag": "garden-visited"}
      ]
    }
  ]
}

Rooms without hooks use an empty array: "hooks": []

Hooks can also be edited via the level editor’s admin API (/mud/api/admin/save-room).