====== 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: [[immortal:scriptlaw|Script Law]]. Build first: [[immortal:creationlaw:mobiles|Creation Law — Mobiles]]. ===== Why attach after the prototype exists ===== ''@npc proc '' 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. ===== Step-by-step: first mobile script ===== **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] ''. 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 ([[immortal:creationlaw:mobiles|Mobiles]], [[immortal:creationlaw:items|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. ===== STATE branches you will write constantly ===== ^ 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;''. ===== Mobile shell APIs (illustrative) ===== 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 '' on a live world proc before inventing new calls — only ''MobileShell'' / script subclass methods are legal. ===== CPU filter caveat (read once) ===== 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. ===== Worked example: ''babybunny'' (chatter + slap) ===== > @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. ===== Worked example: ''thanksgiving'' (quest give) ===== 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 ([[immortal:creationlaw:objects|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 ===== Worked example: ''quest_cursor'' (follow / sayto) ===== 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. ===== Hard-coded Java specials ===== 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 ([[immortal:creationlaw:mobiles|Mobiles]]). ===== Bind overview (mobile ''var'') ===== * ''STATE'', ''state'', ''mobile'', ''victim'', ''victims'', ''item'', ''items'', ''command'', ''args'' * Scratch: ''m'', ''it'', ''rm'', ''s'', ''n'' * ''util'' — ''ScriptTool'' helpers ===== Editing safety ===== * ''@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 ===== Common mistakes ===== * ''@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'' ===== Related ===== * [[immortal:creationlaw:mobiles|Creation mobiles]] — descr/stats/npc + zone place * [[immortal:scriptlaw:items|Script items]] — ''vid'' / ''purge'' primitives quests use * [[immortal:scriptlaw:zones|Script zones]] — resets load scripted mobiles; zones have no proc table * [[immortal:scriptlaw|Script Law]] — hub