diff options
Diffstat (limited to 'NPC_menu.lsl')
| -rw-r--r-- | NPC_menu.lsl | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/NPC_menu.lsl b/NPC_menu.lsl new file mode 100644 index 0000000..0b67c55 --- /dev/null +++ b/NPC_menu.lsl | |||
| @@ -0,0 +1,481 @@ | |||
| 1 | // Onefang's NPC menu version 1.0. | ||
| 2 | // Requires NPC tool, and onefang's utilities scripts. | ||
| 3 | |||
| 4 | // Copyright (C) 2013 David Seikel (onefang rejected). | ||
| 5 | // | ||
| 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 7 | // of this software and associated documentation files (the "Software"), to | ||
| 8 | // deal in the Software without restriction, including without limitation the | ||
| 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
| 10 | // sell copies of the Software, and to permit persons to whom the Software is | ||
| 11 | // furnished to do so, subject to the following conditions: | ||
| 12 | // | ||
| 13 | // The above copyright notice and this permission notice shall be included in | ||
| 14 | // all copies of the Software and its Copyright notices. In addition publicly | ||
| 15 | // documented acknowledgment must be given that this software has been used if no | ||
| 16 | // source code of this software is made available publicly. This includes | ||
| 17 | // acknowledgments in either Copyright notices, Manuals, Publicity and Marketing | ||
| 18 | // documents or any documentation provided with any product containing this | ||
| 19 | // software. This License does not apply to any software that links to the | ||
| 20 | // libraries provided by this software (statically or dynamically), but only to | ||
| 21 | // the software provided. | ||
| 22 | // | ||
| 23 | // Please see the COPYING-PLAIN for a plain-english explanation of this notice | ||
| 24 | // and it's intent. | ||
| 25 | // | ||
| 26 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 27 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 28 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
| 29 | // THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
| 30 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 31 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 32 | |||
| 33 | list chatters = []; // npc key, relay channel. | ||
| 34 | integer CHAT_KEY = 0; | ||
| 35 | integer CHAT_CHANNEL = 1; | ||
| 36 | integer CHAT_STRIDE = 2; | ||
| 37 | |||
| 38 | list sensorRequests = []; // name to search for, type of search, range, command, user key, npc key, title for menu, agents flag, every flag | ||
| 39 | integer sensorInFlight = FALSE; | ||
| 40 | |||
| 41 | // NPC commands. | ||
| 42 | string NPC_ANIMATE = "animate"; // NPC name, animation name | ||
| 43 | string NPC_ATTENTION= "attention"; // NPC name. | ||
| 44 | string NPC_CHANGE = "change"; // NPC name, NPC (notecard) name. | ||
| 45 | string NPC_CLONE = "clone"; // Avatar's name. | ||
| 46 | string NPC_COME = "come"; // NPC name. | ||
| 47 | string NPC_COMPLETE = "complete"; // NPC name. | ||
| 48 | string NPC_CREATE = "create"; // NPC (notecard) name, (optional) position vector. | ||
| 49 | string NPC_DELETE = "delete"; // NPC name. | ||
| 50 | string NPC_DISMISSED= "dismissed"; // NPC name. | ||
| 51 | string NPC_FOLLOW = "follow"; // NPC name, (optional) distance (float or vector). | ||
| 52 | string NPC_FLY = "fly"; // NPC name, position vector or object/agent name/key. | ||
| 53 | string NPC_GO = "go"; // NPC name, position vector or object/agent name/key. | ||
| 54 | string NPC_LAND = "land"; // NPC name, position vector or object/agent name/key. | ||
| 55 | string NPC_LINK = "link"; // Link number, number, string, (optional) key | ||
| 56 | string NPC_LISTEN = "listen"; // new command channel | ||
| 57 | string NPC_LOCATE = "locate"; // NPC name | ||
| 58 | string NPC_NUKE = "nuke"; // No arguments. | ||
| 59 | string NPC_ROTATE = "rotate"; // NPC name, Z rotation in degrees. | ||
| 60 | string NPC_SAY = "say"; // NPC name, thing to say, or relay channel. | ||
| 61 | string NPC_SCRIPT = "script"; // Script notecard name. | ||
| 62 | string NPC_SHOUT = "shout"; // NPC name, thing to shout, or relay channel. | ||
| 63 | string NPC_SIT = "sit"; // NPC name, object to sit on. | ||
| 64 | string NPC_SLEEP = "sleep"; // Seconds. | ||
| 65 | string NPC_STALK = "stalk"; // NPC name, avatar name, (optional) distance (float or vector). | ||
| 66 | string NPC_STAND = "stand"; // NPC name. | ||
| 67 | string NPC_STOP = "stop"; // NPC name. | ||
| 68 | string NPC_STOPANIM = "stopanim"; // NPC name, animation name | ||
| 69 | string NPC_TOUCH = "touch"; // NPC name, object to touch. | ||
| 70 | string NPC_WHISPER = "whisper"; // NPC name, thing to whisper, or relay channel. | ||
| 71 | |||
| 72 | string NPC_MAIN = "Main"; // TODO - does not really matter what this is I think, so use it as the registered menu button. | ||
| 73 | string NPC_PICK = "Pick"; | ||
| 74 | string NPC_NPC = "NPC"; | ||
| 75 | string NPC_RELAY = "Relay"; | ||
| 76 | |||
| 77 | string NPC_NPC_EXT = ".avatar"; | ||
| 78 | string NPC_SCRIPT_EXT = ".npc"; | ||
| 79 | string NPC_BACKUP_CARD = "Restore"; | ||
| 80 | string NPC_RECORD_CARD = "Recorded"; | ||
| 81 | |||
| 82 | integer NPC_RECORD = -100; | ||
| 83 | integer NPC_RECORD_STOP = -101; | ||
| 84 | integer NPC_NEW_NPC = -102; | ||
| 85 | integer NPC_ADD_CHATTER = -103; | ||
| 86 | integer NPC_DEL_CHATTER = -104; | ||
| 87 | |||
| 88 | |||
| 89 | // Stuff for onefangs common utilities. | ||
| 90 | key NPCscriptKey; | ||
| 91 | key scriptKey; | ||
| 92 | |||
| 93 | string UTILITIES_SCRIPT_NAME = "onefang's utilities"; | ||
| 94 | string LIST_SEP = "$!#"; // Used to seperate lists when sending them as strings. | ||
| 95 | integer UTILITIES_RESET = -1; | ||
| 96 | integer UTILITIES_RESET_DONE = -2; | ||
| 97 | integer UTILITIES_READ = -3; | ||
| 98 | integer UTILITIES_READ_DONE = -4; | ||
| 99 | integer UTILITIES_SUBSTITUTE = -5; | ||
| 100 | integer UTILITIES_SUBSTITUTE_DONE = -6; | ||
| 101 | integer UTILITIES_NEXT_WORD = -7; | ||
| 102 | integer UTILITIES_NEXT_WORD_DONE = -8; | ||
| 103 | integer UTILITIES_PAYMENT_MADE = -9; | ||
| 104 | integer UTILITIES_PAYMENT_MADE_DONE = -10; | ||
| 105 | integer UTILITIES_MENU = -11; | ||
| 106 | integer UTILITIES_MENU_DONE = -12; | ||
| 107 | integer UTILITIES_WARP = -13; | ||
| 108 | integer UTILITIES_WARP_DONE = -14; | ||
| 109 | integer UTILITIES_AVATAR_KEY = -15; | ||
| 110 | integer UTILITIES_AVATAR_KEY_DONE = -16; | ||
| 111 | integer UTILITIES_CHAT = -17; | ||
| 112 | integer UTILITIES_CHAT_DONE = -18; | ||
| 113 | integer UTILITIES_CHAT_FAKE = -19; | ||
| 114 | integer UTILITIES_CHAT_FAKE_DONE = -20; | ||
| 115 | |||
| 116 | |||
| 117 | showMenu(key id, string type, string title, list buttons, string extra) | ||
| 118 | { | ||
| 119 | llMessageLinked(LINK_SET, UTILITIES_MENU, llDumpList2String([id, type, title] + buttons, LIST_SEP), (key) scriptKey + "|" + extra); | ||
| 120 | } | ||
| 121 | |||
| 122 | NPCmenu(key id, key npc) | ||
| 123 | { | ||
| 124 | string name = llKey2Name(npc); | ||
| 125 | |||
| 126 | if ((0 == osIsUUID(npc)) || (npc == NULL_KEY) || ("" == name)) | ||
| 127 | { | ||
| 128 | showMenu(id, (string) INVENTORY_NONE, "Main NPC menu.", | ||
| 129 | [ | ||
| 130 | "clone avatar..", "create NPC..", "run script..", | ||
| 131 | "nearby NPCs..", "local NPCs..", "NPCs in sim..", | ||
| 132 | "backup NPCs", "nuke NPCs", "restore NPCs", | ||
| 133 | "start recording", "stop recording" | ||
| 134 | ], NPC_MAIN); | ||
| 135 | } | ||
| 136 | else | ||
| 137 | { | ||
| 138 | integer found = llListFindList(chatters, [npc]); | ||
| 139 | string chat = ""; | ||
| 140 | |||
| 141 | if (0 <= found) | ||
| 142 | chat = "\nUse /" + llList2String(chatters, found + CHAT_CHANNEL) + " to relay chat to " + llKey2Name(npc); | ||
| 143 | showMenu(id, (string) INVENTORY_NONE, "Play with " + llKey2Name(npc) + " :" + chat, | ||
| 144 | [ | ||
| 145 | "change..", "chat relay..", "come here", | ||
| 146 | "go to..", "fly to..", "land at..", | ||
| 147 | "follow me", "stalk them..", "stop moving", | ||
| 148 | "sit..", NPC_STAND, | ||
| 149 | NPC_LOCATE, "take controls", "touch..", | ||
| 150 | "start animation..", "stop animation..", | ||
| 151 | NPC_DELETE | ||
| 152 | ], NPC_NPC + "|" + npc); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | startSensor(key user, key npc, string name, integer type, float range, | ||
| 157 | string command, string title, integer agents, integer everything) | ||
| 158 | { | ||
| 159 | if ((AGENT == type) && (range > 9999.9999)) // Assumes we are only looking for NPCs. | ||
| 160 | { | ||
| 161 | integer i; | ||
| 162 | list menu = []; | ||
| 163 | list avatars = osGetAvatarList(); // Strided list, UUID, position, name. | ||
| 164 | integer length = llGetListLength(avatars); | ||
| 165 | |||
| 166 | for (i = 0; i < length; i++) | ||
| 167 | { | ||
| 168 | key this = (key) llList2String(avatars, i * 3); | ||
| 169 | |||
| 170 | if (osIsNpc(this)) | ||
| 171 | menu += [llKey2Name(this) + "|" + (string) this]; | ||
| 172 | } | ||
| 173 | if (llGetListLength(menu) > 0) | ||
| 174 | showMenu(user, (string) INVENTORY_NONE, "Choose NPC :", menu, NPC_PICK); | ||
| 175 | } | ||
| 176 | else | ||
| 177 | { | ||
| 178 | sensorRequests += [name, type, range, command, user, npc, title, agents, everything]; | ||
| 179 | nextSensor(); | ||
| 180 | } | ||
| 181 | } | ||
| 182 | |||
| 183 | nextSensor() | ||
| 184 | { | ||
| 185 | if (sensorInFlight) | ||
| 186 | return; | ||
| 187 | if (0 < llGetListLength(sensorRequests)) | ||
| 188 | { | ||
| 189 | string name = llList2String(sensorRequests, 0); | ||
| 190 | integer type = llList2Integer(sensorRequests, 1); | ||
| 191 | float range = llList2Float(sensorRequests, 2); | ||
| 192 | string command = llList2String(sensorRequests, 3); | ||
| 193 | key user = llList2String(sensorRequests, 4); | ||
| 194 | key npc = llList2String(sensorRequests, 5); | ||
| 195 | string title = llList2String(sensorRequests, 6); | ||
| 196 | integer agents = llList2Integer(sensorRequests, 7); | ||
| 197 | integer every = llList2Integer(sensorRequests, 8); | ||
| 198 | |||
| 199 | sensorInFlight = TRUE; | ||
| 200 | llSensor(name, "", type, range, TWO_PI); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | |||
| 204 | sendCommand(key user, string command) | ||
| 205 | { | ||
| 206 | // Work around the other script getting reset later, with a fresh key | ||
| 207 | NPCscriptKey = llGetInventoryKey("NPC tool"); | ||
| 208 | llMessageLinked(LINK_SET, UTILITIES_CHAT_FAKE, llDumpList2String([0, llKey2Name(user), user, command], LIST_SEP), NPCscriptKey); | ||
| 209 | } | ||
| 210 | |||
| 211 | init() | ||
| 212 | { | ||
| 213 | scriptKey = llGetInventoryKey(llGetScriptName()); | ||
| 214 | // Register our interest in touch menus. | ||
| 215 | llMessageLinked(LINK_SET, UTILITIES_MENU, llDumpList2String([NULL_KEY, INVENTORY_NONE, "NPC tool|" + llGetScriptName()], LIST_SEP), (key) scriptKey); | ||
| 216 | } | ||
| 217 | |||
| 218 | |||
| 219 | default | ||
| 220 | { | ||
| 221 | state_entry() | ||
| 222 | { | ||
| 223 | init(); | ||
| 224 | } | ||
| 225 | |||
| 226 | on_rez(integer param) | ||
| 227 | { | ||
| 228 | init(); | ||
| 229 | } | ||
| 230 | |||
| 231 | attach(key attached) | ||
| 232 | { | ||
| 233 | init(); | ||
| 234 | } | ||
| 235 | |||
| 236 | link_message(integer sender_num, integer num, string value, key id) | ||
| 237 | { | ||
| 238 | list keys = llParseStringKeepNulls((string) id, ["|"], []); | ||
| 239 | string extra = llList2String(keys, 1); | ||
| 240 | |||
| 241 | id = (key) llList2String(keys, 0); | ||
| 242 | // Work around the other script getting reset later, with a fresh key | ||
| 243 | NPCscriptKey = llGetInventoryKey("NPC tool"); | ||
| 244 | //llSay(0, "id = " + (string) id + " extra = " + extra + " VALUE " + value); | ||
| 245 | if (UTILITIES_RESET_DONE == num) | ||
| 246 | init(); | ||
| 247 | else if ((NPC_NEW_NPC == num) && (NPCscriptKey == id)) | ||
| 248 | { | ||
| 249 | list args = llParseString2List(value, ["|"], []); | ||
| 250 | |||
| 251 | NPCmenu(llList2String(args, 0), llList2String(args, 1)); | ||
| 252 | } | ||
| 253 | else if ((NPC_ADD_CHATTER == num) && (NPCscriptKey == id)) | ||
| 254 | { | ||
| 255 | list args = llParseString2List(value, ["|"], []); | ||
| 256 | key npc = llList2String(args, 0); | ||
| 257 | integer channel = llList2Integer(args, 1); | ||
| 258 | integer found = llListFindList(chatters, [npc]); | ||
| 259 | |||
| 260 | if (0 <= found) | ||
| 261 | chatters = llDeleteSubList(chatters, found, found + CHAT_STRIDE - 1); | ||
| 262 | chatters += [npc, channel]; | ||
| 263 | } | ||
| 264 | else if ((NPC_DEL_CHATTER == num) && (NPCscriptKey == id)) | ||
| 265 | { | ||
| 266 | integer found = llListFindList(chatters, [value]); | ||
| 267 | |||
| 268 | if (0 <= found) | ||
| 269 | chatters = llDeleteSubList(chatters, found, found + CHAT_STRIDE - 1); | ||
| 270 | } | ||
| 271 | else if ((UTILITIES_CHAT_DONE == num) && (NPCscriptKey == id)) | ||
| 272 | { | ||
| 273 | // incoming channel | incoming name | incoming key | incoming message | prefix | command | list of arguments | rest of message | ||
| 274 | list result = llParseStringKeepNulls(value, [LIST_SEP], []); | ||
| 275 | //integer inchannel = llList2Integer(result, 0); | ||
| 276 | //string inName = llList2String (result, 1); | ||
| 277 | key user = llList2Key (result, 2); | ||
| 278 | //string inMessage = llList2String (result, 3); | ||
| 279 | //string prefix = llList2String (result, 4); | ||
| 280 | string command = llList2String (result, 5); | ||
| 281 | list arguments = llList2List (result, 6, -1); // Includes "rest of message" as the last one. | ||
| 282 | |||
| 283 | if (NPC_NUKE == command) | ||
| 284 | { | ||
| 285 | chatters = []; | ||
| 286 | sensorRequests = []; | ||
| 287 | sensorInFlight = FALSE; | ||
| 288 | } | ||
| 289 | } | ||
| 290 | else if ((UTILITIES_MENU_DONE == num) && (scriptKey == id)) // Big menu button pushed | ||
| 291 | { | ||
| 292 | list input = llParseStringKeepNulls(value, [LIST_SEP], []); | ||
| 293 | key user = (key) llList2String(input, 0); | ||
| 294 | string selection = llList2String(input, 1); | ||
| 295 | list parts = llParseString2List(selection, ["|"], []); | ||
| 296 | key uuid = (key) llList2String(parts, 1); | ||
| 297 | key npc = (key) llList2String(keys, 2); | ||
| 298 | list details = llGetObjectDetails(uuid, [OBJECT_POS]); | ||
| 299 | string menu = extra; | ||
| 300 | //llSay(0, extra + " MENU " + value + " KEYS " + llDumpList2String(keys, " ")); | ||
| 301 | |||
| 302 | // See if it was our top level menu requested via touch registration. | ||
| 303 | if ("" == selection) | ||
| 304 | { | ||
| 305 | NPCmenu(user, NULL_KEY); | ||
| 306 | return; | ||
| 307 | } | ||
| 308 | |||
| 309 | // Figure out what the user picked. | ||
| 310 | if ((NPC_MAIN == extra) || (NPC_NPC == extra)) | ||
| 311 | menu = selection; | ||
| 312 | // Make sure main menu items don't return to an NPC menu, by setting npc to null. | ||
| 313 | if (NPC_MAIN == extra) | ||
| 314 | npc = NULL_KEY; | ||
| 315 | |||
| 316 | // Check if the NPC still exists. | ||
| 317 | if (NPC_NPC == extra) | ||
| 318 | { | ||
| 319 | list npcDetails = llGetObjectDetails(npc, [OBJECT_POS]); | ||
| 320 | |||
| 321 | if (llGetListLength(npcDetails) == 0) | ||
| 322 | { | ||
| 323 | // Bail out if the NPC went AWOL. | ||
| 324 | npc = NULL_KEY; | ||
| 325 | selection = "Exit"; | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | if ("Exit" == selection) | ||
| 330 | { | ||
| 331 | if (NPC_NPC == extra) npc = NULL_KEY; | ||
| 332 | if (NPC_MAIN == extra) return; | ||
| 333 | } | ||
| 334 | // Commands. | ||
| 335 | else if (NPC_ANIMATE == menu) sendCommand(user, NPC_ANIMATE + " " + npc + " " + selection); | ||
| 336 | else if (NPC_CHANGE == menu) sendCommand(user, NPC_CHANGE + " " + npc + " " + selection); | ||
| 337 | else if (NPC_CLONE == menu) sendCommand(user, NPC_CLONE + " " + uuid); | ||
| 338 | else if (NPC_FLY == menu) sendCommand(user, NPC_FLY + " " + npc + " " + llList2String(details, 0)); | ||
| 339 | else if (NPC_GO == menu) sendCommand(user, NPC_GO + " " + npc + " " + llList2String(details, 0)); | ||
| 340 | else if (NPC_LAND == menu) sendCommand(user, NPC_LAND + " " + npc + " " + llList2String(details, 0)); | ||
| 341 | else if (NPC_LOCATE == menu) sendCommand(user, NPC_LOCATE + " " + npc); | ||
| 342 | else if (NPC_RELAY == menu) sendCommand(user, NPC_SAY + " " + npc + " " + selection); | ||
| 343 | else if (NPC_SCRIPT == menu) sendCommand(user, NPC_SCRIPT + " " + selection); | ||
| 344 | else if (NPC_SIT == menu) sendCommand(user, NPC_SIT + " " + npc + " " + uuid); | ||
| 345 | else if (NPC_STALK == menu) sendCommand(user, NPC_STALK + " " + npc + " " + uuid); | ||
| 346 | else if (NPC_STAND == menu) sendCommand(user, NPC_STAND + " " + npc); | ||
| 347 | else if (NPC_STOPANIM == menu) sendCommand(user, NPC_STOPANIM + " " + npc + " " + selection); | ||
| 348 | else if (NPC_TOUCH == menu) sendCommand(user, NPC_TOUCH + " " + npc + " " + uuid); | ||
| 349 | else if ("come here" == menu) sendCommand(user, NPC_COME + " " + npc); | ||
| 350 | else if ("follow me" == menu) sendCommand(user, NPC_FOLLOW + " " + npc); | ||
| 351 | else if ("nuke NPCs" == menu) sendCommand(user, NPC_NUKE); | ||
| 352 | else if ("restore NPCs" == menu) sendCommand(user, NPC_SCRIPT + " " + NPC_BACKUP_CARD + NPC_SCRIPT_EXT); | ||
| 353 | else if ("stop moving" == menu) sendCommand(user, NPC_STOP + " " + npc); | ||
| 354 | |||
| 355 | // Menus. | ||
| 356 | else if ("change.." == menu) showMenu(user, ((string) INVENTORY_NOTECARD) + "|.+\\" + NPC_NPC_EXT, | ||
| 357 | "Choose an NPC to change to :", [], NPC_CHANGE + "|" + npc); | ||
| 358 | else if ("chat relay.." == menu) showMenu(user, (string) INVENTORY_NONE, | ||
| 359 | "Choose a channel to relay chat from :", ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"], NPC_RELAY + "|" + npc); | ||
| 360 | else if ("create NPC.." == menu) showMenu(user, ((string) INVENTORY_NOTECARD) + "|.+\\" + NPC_NPC_EXT, | ||
| 361 | "Choose an NPC to create :", [], NPC_CREATE); | ||
| 362 | else if ("run script.." == menu) showMenu(user, ((string) INVENTORY_NOTECARD) + "|.+\\" + NPC_SCRIPT_EXT, | ||
| 363 | "Choose a script to run :", [], NPC_SCRIPT); | ||
| 364 | else if ("start animation.." == menu) showMenu(user, (string) INVENTORY_ANIMATION, | ||
| 365 | "Choose an animation to start :", [], NPC_ANIMATE + "|" + npc); | ||
| 366 | else if ("stop animation.." == menu) showMenu(user, (string) INVENTORY_ANIMATION, | ||
| 367 | "Choose an animation to stop :", [], NPC_STOPANIM + "|" + npc); | ||
| 368 | |||
| 369 | // Sensor menus. | ||
| 370 | else if ("clone avatar.." == menu) startSensor(user, "", "", AGENT, 256.0, NPC_CLONE, "Choose person to clone :", TRUE, TRUE); | ||
| 371 | else if ("fly to.." == menu) startSensor(user, npc, "", ACTIVE | PASSIVE, 1024.0, NPC_FLY, "Choose thing to fly to :", FALSE, TRUE); | ||
| 372 | else if ("go to.." == menu) startSensor(user, npc, "", ACTIVE | PASSIVE, 1024.0, NPC_GO, "Choose thing to go to :", FALSE, TRUE); | ||
| 373 | else if ("land at.." == menu) startSensor(user, npc, "", ACTIVE | PASSIVE, 1024.0, NPC_LAND, "Choose thing to land at :", FALSE, TRUE); | ||
| 374 | else if ("local NPCs.." == menu) startSensor(user, "", "", AGENT, 256.0, NPC_PICK, "Choose NPC :", FALSE, FALSE); | ||
| 375 | else if ("nearby NPCs.." == menu) startSensor(user, "", "", AGENT, 20.0, NPC_PICK, "Choose NPC :", FALSE, FALSE); | ||
| 376 | else if ("NPCs in sim.." == menu) startSensor(user, "", "", AGENT, 16384.0, NPC_PICK, "Choose NPC :", FALSE, FALSE); | ||
| 377 | else if ("sit.." == menu) startSensor(user, npc, "", ACTIVE | SCRIPTED, 1024.0, NPC_SIT, "Choose thing to sit on :", FALSE, TRUE); | ||
| 378 | else if ("stalk them.." == menu) startSensor(user, npc, "", AGENT, 1024.0, NPC_STALK, "Choose person to stalk :", TRUE, TRUE); | ||
| 379 | else if ("touch.." == menu) startSensor(user, npc, "", ACTIVE | SCRIPTED, 1024.0, NPC_TOUCH, "Choose thing to touch :", FALSE, TRUE); | ||
| 380 | |||
| 381 | // Misc. | ||
| 382 | else if (NPC_PICK == menu) npc = uuid; | ||
| 383 | else if ("start recording" == menu) llMessageLinked(LINK_SET, NPC_RECORD, "", NPCscriptKey); | ||
| 384 | else if ("stop recording" == menu) llMessageLinked(LINK_SET, NPC_RECORD_STOP, "", NPCscriptKey); | ||
| 385 | else if (NPC_CREATE == menu) | ||
| 386 | { | ||
| 387 | sendCommand(user, NPC_CREATE + " " + selection); | ||
| 388 | // Avoid the NPCmenu() below. An odd one out, coz the NPC wont exist yet, but we want their menu when they do exist. | ||
| 389 | return; | ||
| 390 | } | ||
| 391 | else if (NPC_DELETE == menu) | ||
| 392 | { | ||
| 393 | sendCommand(user, NPC_DELETE + " " + npc); | ||
| 394 | // An odd one out, the NPC wont exist, so return to the main menu. | ||
| 395 | npc = NULL_KEY; | ||
| 396 | } | ||
| 397 | else if ("backup NPCs" == menu) | ||
| 398 | { | ||
| 399 | list avatars = osGetAvatarList(); // Strided list, UUID, position, name. | ||
| 400 | list delete = []; | ||
| 401 | list backup = []; | ||
| 402 | integer length = llGetListLength(avatars); | ||
| 403 | integer i; | ||
| 404 | |||
| 405 | llRemoveInventory(NPC_BACKUP_CARD + NPC_SCRIPT_EXT); | ||
| 406 | for (i = 0; i < length; i++) | ||
| 407 | { | ||
| 408 | key this = (key) llList2String(avatars, i * 3); | ||
| 409 | |||
| 410 | if (osIsNpc(this)) | ||
| 411 | { | ||
| 412 | string aName = llKey2Name(this); | ||
| 413 | |||
| 414 | osAgentSaveAppearance(this, aName + NPC_NPC_EXT); | ||
| 415 | delete += [NPC_DELETE + " " + aName]; | ||
| 416 | backup += [NPC_CREATE + " " + aName + " " + llList2String(avatars, (i * 3) + 1)]; | ||
| 417 | } | ||
| 418 | } | ||
| 419 | osMakeNotecard(NPC_BACKUP_CARD + NPC_SCRIPT_EXT, | ||
| 420 | ["script " + NPC_BACKUP_CARD + ".before" + NPC_SCRIPT_EXT] | ||
| 421 | + delete + backup | ||
| 422 | + ["script " + NPC_BACKUP_CARD + ".after" + NPC_SCRIPT_EXT]); | ||
| 423 | } | ||
| 424 | |||
| 425 | // If the menu name ends in "..", then it's expected that we are waiting on another menu, so don't show one now. | ||
| 426 | if (0 == osRegexIsMatch(menu, ".+\\.\\.$")) | ||
| 427 | NPCmenu(user, npc); | ||
| 428 | } // End of menu block. | ||
| 429 | } | ||
| 430 | |||
| 431 | no_sensor() | ||
| 432 | { | ||
| 433 | sensorInFlight = FALSE; | ||
| 434 | if (llGetListLength(sensorRequests)) | ||
| 435 | { | ||
| 436 | sensorRequests = llDeleteSubList(sensorRequests, 0, 8); | ||
| 437 | nextSensor(); | ||
| 438 | } | ||
| 439 | } | ||
| 440 | |||
| 441 | sensor(integer numberDetected) | ||
| 442 | { | ||
| 443 | sensorInFlight = FALSE; | ||
| 444 | if (llGetListLength(sensorRequests)) | ||
| 445 | { | ||
| 446 | string name = llList2String(sensorRequests, 0); | ||
| 447 | integer type = llList2Integer(sensorRequests, 1); | ||
| 448 | float range = llList2Float(sensorRequests, 2); | ||
| 449 | string command = llList2String(sensorRequests, 3); | ||
| 450 | key user = llList2String(sensorRequests, 4); | ||
| 451 | key npc = llList2String(sensorRequests, 5); | ||
| 452 | string title = llList2String(sensorRequests, 6); | ||
| 453 | integer agents = llList2Integer(sensorRequests, 7); | ||
| 454 | integer every = llList2Integer(sensorRequests, 8); | ||
| 455 | |||
| 456 | sensorRequests = llDeleteSubList(sensorRequests, 0, 8); | ||
| 457 | if ("" == title) | ||
| 458 | sendCommand(user, command + " " + npc + " " + llDetectedKey(0)); | ||
| 459 | else | ||
| 460 | { | ||
| 461 | integer i; | ||
| 462 | list menu = []; | ||
| 463 | |||
| 464 | if (agents) | ||
| 465 | menu += ["you|" + (string) user]; | ||
| 466 | for (i = 0; i < numberDetected; i++) | ||
| 467 | { | ||
| 468 | key this = llDetectedKey(i); | ||
| 469 | |||
| 470 | if (!(agents && (this == user))) | ||
| 471 | if (every || osIsNpc(this)) | ||
| 472 | menu += [llDetectedName(i) + "|" + (string) this]; | ||
| 473 | } | ||
| 474 | if (llGetListLength(menu) > 0) | ||
| 475 | showMenu(user, (string) INVENTORY_NONE, title, menu, command + "|" + npc); | ||
| 476 | } | ||
| 477 | nextSensor(); | ||
| 478 | } | ||
| 479 | } | ||
| 480 | |||
| 481 | } \ No newline at end of file | ||
