immortal:scriptlaw:mobiles

Script Law — Mobiles

Full mobile SpecProc onboarding. You may know Diku mobile specials or dg_scripts — Neo uses Beanshell on named SpecProcs, attached with @npc proc after the mobile prototype exists.

Hub: Script Law. Build first: Creation Law — Mobiles.

@npc proc <name> only stores a string name on the prototype. The Beanshell lives in the SpecProc table. Create the proc, write the script, verify with examine / index, then load the npc workspace, set proc, @examine, @save. Reversing that order is the top beginner mistake.

1. Create the named proc

> @proc npc new quiet_stretch
Okay.
> @proc npc script quiet_stretch
(writer opens — paste the stub below, finish writer)
> @proc npc examine quiet_stretch
> @proc npc matrix quiet_stretch 0.0
Okay.
> index proc_npc quiet
>

Pattern: @proc npc [delete|examine|new|matrix|rename|script] <name>. Names: lowercase, alphabetic/underscore, length 3–16.

2. Minimal starter stub (periodic flavor only — safe default):

if (var.STATE == var.STATE_SCRIPT) {
  // occasional flavor only
  if (util.chance(100)) {
    var.mobile.echoRoom("You stretch.", "$n stretches.");
    return true;
  }
}
return false;

3. Attach on the mobile prototype

> @load npc 1210
Okay.
> @npc proc quiet_stretch
Okay.
> @examine npc
> @save npc
Okay.
> create npc 1210
> zone reset
>

If create is refused, fix ranges / maximum (Mobiles, Items create-vs-load notes). If the script never fires, confirm the proc name on @examine npc and that you saved.

4. Personal writer alternative

> script mobile list
Listing the mobile script for Silk:
…
> script mobile write
Writing a new mobile script for Silk.
(writer opens)
>

script (mobile|item|room) (list|write) [player] — non-implementors edit their own name only.

Need Branch
Ambient chatter / pulse var.STATE == 0 or var.STATE_SCRIPT
After give / say / social STATE_POST_INTERPRETER (-3)
During command interpret STATE_INTERPRETER (-1)
Combat tick STATE_COMBAT (-2)

Return Boolean.TRUE to block the triggering command on interpreter-style calls (see SpecProcMobile.func javadoc). Otherwise return false;.

Real mobile scripts use patterns such as:

  • var.mobile.echoRoom(…), cechoRoom(…), cechonRoom(…), say(…), social(…), interpretSocial(…)
  • var.mobile.follow(…), teleportHome(), teleportToNC(…), createItem(…), createNPC(…), purge(), oldScript(String[] cmds)
  • var.item.purge(), var.item.vid() when an item is in context
  • util.roll(n), util.chance(die)

Prefer @proc npc examine <name> on a live world proc before inventing new calls — only MobileShell / script subclass methods are legal.

Authors historically embed the literal tokens STATE_SCRIPT, STATE_INTERPRETER, … in script text so SpecProc.script() can set CPU filter flags. In current SpecProcMobile.func that early-return filter is commented out, so mobile scripts still run for every call until the optimization is re-enabled. Keep scripts cheap, and still write correct STATE branches for when the filter returns.

> @proc npc examine babybunny

Pattern from the live world dump: on STATE_SCRIPT (0), roll and echoRoom; on STATE_POST_INTERPRETER (-3), react to slap. Always end with return false; unless you intend to block. Study the full text in-game — this handbook only teaches the shape.

On pulse (STATE == 0) the hen speaks via oldScript. On post-interpret, if var.command is give and var.item.vid() matches the quest item, thank the player, purge the item, and createItem a reward into the victim's inventory. Returning true consumes the interaction.

Teaching checklist when you copy this pattern:

  • [ ] Quest item prototype VID is stable (Objects)
  • [ ] Mobile has the proc attached and saved
  • [ ] You test with a real give of that VID, not only pulse chatter
  • [ ] You purge reward leftovers between tests

Branches on var.STATE_POST_INTERPRETER for sayto orders (follow, make indian, …) and on STATE_SCRIPT to teleport home or stay with the master. Uses named constants (var.STATE_POST_INTERPRETER / var.STATE_SCRIPT) rather than raw integers — prefer that style in new scripts.

Not every interesting mobile is a Beanshell row. MobileSimpleScript dispatches compiled methods by VID for a large legacy set. Classes such as MobileMayor, MobileJanitor implement SpecProc* in Java. Attach those through SpecNPC on @npc_stats attrs when the special is enum-backed compiled code rather than a free-form script name (Mobiles).

  • STATE, state, mobile, victim, victims, item, items, command, args
  • Scratch: m, it, rm, s, n
  • utilScriptTool helpers
  • @proc npc delete removes the DB row — clear @npc proc on prototypes first when you care about clean refs
  • Eval errors echo to the owning immortal when the proc name matches a player CID
  • No separate reload verb: save script text, keep prototype pointed at the name; boot reloads from H2
  • Shared Interpreter — no leftover globals
  • @npc proc before @proc npc new/script
  • Forgetting @save npc
  • Testing with an old instance (purge / zone reset)
  • Heavy work on every STATE because the CPU filter is currently off
  • Returning true and accidentally eating player commands
  • Inventing shell methods not on MobileShell
  • immortal/scriptlaw/mobiles.txt
  • Last modified: 2026/09/23 22:22
  • by 127.0.0.1
  • Currently locked by: 216.73.216.245