// Wolf NPC remote - wear it as a HUD (or rez it on your land) and control your own WolfNPCs on this region. // Uses the wolf-commands plugin through wolfCall: no region restart is ever needed for these commands. // Touch: pick one of your NPCs, then what it should do. Only NPCs you own (and may still run here) obey you. // Wolf Territories, 2026. Copy, change and share freely. integer CHANNEL; integer listener; list npcKeys; list npcNames; key chosen; string chosenName; // Every wolf-commands call answers with a list; an empty list means "refused", and wolfGetLastError() says why. integer tell(string what, list answer) { if (llGetListLength(answer) == 0) { llOwnerSay(what + ": " + wolfGetLastError()); return FALSE; } return TRUE; } listenFor(float seconds) { llListenRemove(listener); listener = llListen(CHANNEL, "", llGetOwner(), ""); llSetTimerEvent(seconds); } pickNpc() { // [count, key, name, rights, key, name, rights, ...] - rights is "edit", "control" or "none". list r = wolfCall("npc.list", []); if (!tell("Your NPCs", r)) return; npcKeys = []; npcNames = []; integer i; for (i = 1; i + 2 < llGetListLength(r) && llGetListLength(npcNames) < 12; i += 3) { if (llList2String(r, i + 2) != "none") { npcKeys += llList2Key(r, i); npcNames += llGetSubString(llList2String(r, i + 1), 0, 23); } } if (npcNames == []) { llOwnerSay("You have no NPCs you can control on this region."); return; } listenFor(60.0); llDialog(llGetOwner(), "Which NPC?", npcNames, CHANNEL); } pickAction() { listenFor(60.0); llDialog(llGetOwner(), chosenName + " - what should it do?", ["Come here", "Follow me", "Stop", "Go home", "Say hello", "Status", "Fire", "Ice"], CHANNEL); } default { state_entry() { CHANNEL = -1 - (integer)("0x" + llGetSubString((string)llGetKey(), 0, 6)); chosen = NULL_KEY; } touch_start(integer n) { if (llDetectedKey(0) == llGetOwner()) pickNpc(); } listen(integer ch, string name, key id, string msg) { integer i = llListFindList(npcNames, [msg]); if (chosen == NULL_KEY || i != -1) { if (i == -1) return; chosen = llList2Key(npcKeys, i); chosenName = msg; pickAction(); return; } list r; if (msg == "Come here") r = wolfCall("npc.goto", [chosen, llList2Vector(llGetObjectDetails(llGetOwner(), [OBJECT_POS]), 0)]); else if (msg == "Follow me") r = wolfCall("npc.follow", [chosen, llGetOwner()]); else if (msg == "Stop") r = wolfCall("npc.stop", [chosen]); else if (msg == "Go home") r = wolfCall("npc.home", [chosen]); else if (msg == "Say hello") r = wolfCall("npc.say", [chosen, "Hello, " + llKey2Name(llGetOwner()) + "!"]); else if (msg == "Fire" || msg == "Ice") r = wolfCall("npc.breath", [chosen, llToLower(msg), 3.0]); // dragons only else if (msg == "Status") { // "intention|awake or asleep|alive or dead|health/max" r = wolfCall("npc.info", [chosen]); if (tell(chosenName, r)) llOwnerSay(chosenName + ": " + llList2String(r, 0)); } if (msg != "Status") tell(chosenName, r); chosen = NULL_KEY; llListenRemove(listener); llSetTimerEvent(0.0); } timer() { llListenRemove(listener); llSetTimerEvent(0.0); chosen = NULL_KEY; } }