diff options
Diffstat (limited to '')
-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 | ||