corrade-lsl-templates – Blame information for rev 29

Subversion Repositories:
Rev:
Rev Author Line No. Line
2 office 1 ///////////////////////////////////////////////////////////////////////////
29 office 2 // Copyright (C) Wizardry and Steamworks 2016 - License: CC BY 2.0 //
2 office 3 ///////////////////////////////////////////////////////////////////////////
4 //
5 // This script is used to make Corrade sit on a primitive. The script first
6 // uses a Corrade command to scan the surrounding area for primitives and
7 // then sends a command to make Corrade sit on that primitive.
8 //
9 // For more information on Corrade, please see:
10 // http://grimore.org/secondlife/scripted_agents/corrade
11 //
12 ///////////////////////////////////////////////////////////////////////////
13  
14 ///////////////////////////////////////////////////////////////////////////
29 office 15 // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 //
2 office 16 ///////////////////////////////////////////////////////////////////////////
17 string wasKeyValueGet(string k, string data) {
18 if(llStringLength(data) == 0) return "";
19 if(llStringLength(k) == 0) return "";
20 list a = llParseString2List(data, ["&", "="], []);
21 integer i = llListFindList(a, [ k ]);
22 if(i != -1) return llList2String(a, i+1);
23 return "";
24 }
25  
26 ///////////////////////////////////////////////////////////////////////////
29 office 27 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
2 office 28 ///////////////////////////////////////////////////////////////////////////
29 string wasKeyValueEncode(list data) {
30 list k = llList2ListStrided(data, 0, -1, 2);
31 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
32 data = [];
33 do {
34 data += llList2String(k, 0) + "=" + llList2String(v, 0);
35 k = llDeleteSubList(k, 0, 0);
36 v = llDeleteSubList(v, 0, 0);
37 } while(llGetListLength(k) != 0);
38 return llDumpList2String(data, "&");
39 }
40  
41 ///////////////////////////////////////////////////////////////////////////
29 office 42 // Copyright (C) 2011 Wizardry and Steamworks - License: CC BY 2.0 //
2 office 43 ///////////////////////////////////////////////////////////////////////////
44 // http://was.fm/secondlife/wanderer
45 vector wasCirclePoint(float radius) {
46 float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
47 float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
48 if(llPow(x,2) + llPow(y,2) <= llPow(radius,2))
49 return <x, y, 0>;
50 return wasCirclePoint(radius);
51 }
52  
53 ///////////////////////////////////////////////////////////////////////////
29 office 54 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
2 office 55 ///////////////////////////////////////////////////////////////////////////
56 // escapes a string in conformance with RFC1738
57 string wasURLEscape(string i) {
58 string o = "";
59 do {
60 string c = llGetSubString(i, 0, 0);
61 i = llDeleteSubString(i, 0, 0);
62 if(c == "") jump continue;
63 if(c == " ") {
64 o += "+";
65 jump continue;
66 }
67 if(c == "\n") {
68 o += "%0D" + llEscapeURL(c);
69 jump continue;
70 }
71 o += llEscapeURL(c);
72 @continue;
73 } while(i != "");
74 return o;
75 }
76  
77 ///////////////////////////////////////////////////////////////////////////
29 office 78 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
2 office 79 ///////////////////////////////////////////////////////////////////////////
80 list wasCSVToList(string csv) {
81 list l = [];
82 list s = [];
83 string m = "";
84 do {
85 string a = llGetSubString(csv, 0, 0);
86 csv = llDeleteSubString(csv, 0, 0);
87 if(a == ",") {
88 if(llList2String(s, -1) != "\"") {
89 l += m;
90 m = "";
91 jump continue;
92 }
93 m += a;
94 jump continue;
95 }
96 if(a == "\"" && llGetSubString(csv, 0, 0) == a) {
97 m += a;
98 csv = llDeleteSubString(csv, 0, 0);
99 jump continue;
100 }
101 if(a == "\"") {
102 if(llList2String(s, -1) != a) {
103 s += a;
104 jump continue;
105 }
106 s = llDeleteSubList(s, -1, -1);
107 jump continue;
108 }
109 m += a;
110 @continue;
111 } while(csv != "");
112 // postcondition: length(s) = 0
113 return l + m;
114 }
115  
116 ///////////////////////////////////////////////////////////////////////////
29 office 117 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
2 office 118 ///////////////////////////////////////////////////////////////////////////
119 string wasListToCSV(list l) {
120 list v = [];
121 do {
122 string a = llDumpList2String(
123 llParseStringKeepNulls(
124 llList2String(
125 l,
126  
127 ),
128 ["\""],
129 []
130 ),
131 "\"\""
132 );
133 if(llParseStringKeepNulls(
134 a,
135 [" ", ",", "\n", "\""], []
136 ) !=
137 (list) a
138 ) a = "\"" + a + "\"";
139 v += a;
140 l = llDeleteSubList(l, 0, 0);
141 } while(l != []);
142 return llDumpList2String(v, ",");
143 }
144  
145 ///////////////////////////////////////////////////////////////////////////
29 office 146 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
2 office 147 ///////////////////////////////////////////////////////////////////////////
148 // unescapes a string in conformance with RFC1738
149 string wasURLUnescape(string i) {
150 return llUnescapeURL(
151 llDumpList2String(
152 llParseString2List(
153 llDumpList2String(
154 llParseString2List(
155 i,
156 ["+"],
157 []
158 ),
159 " "
160 ),
161 ["%0D%0A"],
162 []
163 ),
164 "\n"
165 )
166 );
167 }
168  
169 ///////////////////////////////////////////////////////////////////////////
29 office 170 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
2 office 171 ///////////////////////////////////////////////////////////////////////////
172 integer wasMenuIndex = 0;
173 list wasDialogMenu(list input, list actions, string direction) {
174 integer cut = 11-wasListCountExclude(actions, [""]);
175 if(direction == ">" && (wasMenuIndex+1)*cut+wasMenuIndex+1 < llGetListLength(input)) {
176 ++wasMenuIndex;
177 jump slice;
178 }
179 if(direction == "<" && wasMenuIndex-1 >= 0) {
180 --wasMenuIndex;
181 jump slice;
182 }
183 @slice;
184 integer multiple = wasMenuIndex*cut;
185 input = llList2List(input, multiple+wasMenuIndex, multiple+cut+wasMenuIndex);
186 input = wasListMerge(input, actions, "");
187 return input;
188 }
189  
190 ///////////////////////////////////////////////////////////////////////////
29 office 191 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
2 office 192 ///////////////////////////////////////////////////////////////////////////
193 integer wasListCountExclude(list input, list exclude) {
194 if(llGetListLength(input) == 0) return 0;
195 if(llListFindList(exclude, (list)llList2String(input, 0)) == -1)
196 return 1 + wasListCountExclude(llDeleteSubList(input, 0, 0), exclude);
197 return wasListCountExclude(llDeleteSubList(input, 0, 0), exclude);
198 }
199  
200 ///////////////////////////////////////////////////////////////////////////
29 office 201 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
2 office 202 ///////////////////////////////////////////////////////////////////////////
203 list wasListMerge(list l, list m, string merge) {
204 if(llGetListLength(l) == 0 && llGetListLength(m) == 0) return [];
205 string a = llList2String(m, 0);
206 if(a != merge) return [ a ] + wasListMerge(l, llDeleteSubList(m, 0, 0), merge);
207 return [ llList2String(l, 0) ] + wasListMerge(llDeleteSubList(l, 0, 0), llDeleteSubList(m, 0, 0), merge);
208 }
209  
210 // configuration data
211 string configuration = "";
212 // callback URL
213 string callback = "";
214 // scanned primitives
215 list names = [];
216 list UUIDs = [];
217 // temporary list for button name normalization
218 list menu = [];
219 integer select = -1;
220  
221 default {
222 state_entry() {
223 llSetTimerEvent(1);
224 }
225 link_message(integer sender, integer num, string message, key id) {
226 if(sender != 1 || id != "configuration") return;
227 configuration = message;
228 state off;
229 }
230 timer() {
231 llMessageLinked(LINK_ROOT, 0, "configuration", NULL_KEY);
232 }
233 attach(key id) {
234 llResetScript();
235 }
236 on_rez(integer num) {
237 llResetScript();
238 }
239 changed(integer change) {
240 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
241 llResetScript();
242 }
243 }
244 state_exit() {
245 llSetTimerEvent(0);
246 }
247 }
248  
249 state off {
250 state_entry() {
251 llSetColor(<.5,0,0>, ALL_SIDES);
252 }
253 touch_end(integer num) {
254 state on;
255 }
256 attach(key id) {
257 llResetScript();
258 }
259 on_rez(integer num) {
260 llResetScript();
261 }
262 changed(integer change) {
263 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
264 llResetScript();
265 }
266 }
267 }
268  
269 state on {
270 state_entry() {
271 llSetColor(<0,.5,0>, ALL_SIDES);
272 state url;
273 }
274 attach(key id) {
275 llResetScript();
276 }
277 on_rez(integer num) {
278 llResetScript();
279 }
280 changed(integer change) {
281 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
282 llResetScript();
283 }
284 }
285 }
286  
287 state url {
288 state_entry() {
289 // DEBUG
290 llOwnerSay("Requesting URL...");
291 llRequestURL();
292 }
293 touch_end(integer num) {
294 llSetColor(<.5,0,0>, ALL_SIDES);
295 llResetScript();
296 }
297 http_request(key id, string method, string body) {
298 if(method != URL_REQUEST_GRANTED) return;
299 callback = body;
300 // DEBUG
301 llOwnerSay("Got URL...");
302 state scan;
303 }
304 attach(key id) {
305 llResetScript();
306 }
307 on_rez(integer num) {
308 llResetScript();
309 }
310 changed(integer change) {
311 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
312 llResetScript();
313 }
314 }
315 }
316  
317 state scan {
318 state_entry() {
319 // DEBUG
320 llOwnerSay("Getting objects...");
321 llInstantMessage(
322 wasKeyValueGet(
323 "corrade",
324 configuration
325 ),
326 wasKeyValueEncode(
327 [
328 "command", "getobjectsdata",
329 "group", wasURLEscape(
330 wasKeyValueGet(
331 "group",
332 configuration
333 )
334 ),
335 "password", wasURLEscape(
336 wasKeyValueGet(
337 "password",
338 configuration
339 )
340 ),
341 "entity", "world",
342 "range", wasURLEscape(
343 wasKeyValueGet(
344 "radar",
345 configuration
346 )
347 ),
348 "data", wasListToCSV(
349 [
350 "Properties.Name",
351 "ID"
352 ]
353 ),
354 "sift", wasListToCSV(
355 [
356 "take", 32
357 ]
358 ),
359 "callback", wasURLEscape(callback)
360 ]
361 )
362 );
363 }
364 touch_end(integer num) {
365 llSetColor(<.5,0,0>, ALL_SIDES);
366 llResetScript();
367 }
368 http_request(key id, string method, string body) {
369 llHTTPResponse(id, 200, "OK");
370 if(wasKeyValueGet("command", body) != "getobjectsdata" ||
371 wasKeyValueGet("success", body) != "True") {
372 // DEBUG
373 llOwnerSay("Error querying primitives: " + wasKeyValueGet("error", body));
374 llResetScript();
375 }
376 string dataKey = wasURLUnescape(
377 wasKeyValueGet(
378 "data",
379 body
380 )
381 );
382 if(dataKey == "") {
383 // DEBUG
384 llOwnerSay("No data for scanned primitives...");
385 llResetScript();
386 }
387 list data = wasCSVToList(dataKey);
388 // Copy the names and UUIDs of the primitives.
389 names = [];
390 UUIDs = [];
391 do {
392 string v = llList2String(data, -1);
393 data = llDeleteSubList(data, -1, -1);
394 string k = llList2String(data, -1);
395 data = llDeleteSubList(data, -1, -1);
396 if(k == "Properties.Name") {
397 names += v;
398 jump continue;
399 }
400 UUIDs += (key)v;
401 @continue;
402 } while(llGetListLength(data));
403 state choose;
404 }
405 attach(key id) {
406 llResetScript();
407 }
408 on_rez(integer num) {
409 llResetScript();
410 }
411 changed(integer change) {
412 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
413 llResetScript();
414 }
415 }
416 state_exit() {
417 llSetTimerEvent(0);
418 }
419 }
420  
421 state choose {
422 state_entry() {
423 // DEBUG
424 llOwnerSay("Sending menu...");
425 menu = [];
426 integer i = 0;
427 do {
428 menu += llGetSubString(llList2String(names, i), 0, 23);
429 } while(++i < llGetListLength(names));
430 llListen(-10, "", llGetOwner(), "");
431 llDialog(llGetOwner(), "\nPlease choose a primitive for Corrade to sit on from the list below:\n", wasDialogMenu(menu, ["⟵ Back", "", "Next ⟶"], ""), -10);
432 llSetTimerEvent(60);
433 }
434 touch_end(integer num) {
435 llSetColor(<.5,0,0>, ALL_SIDES);
436 llResetScript();
437 }
438 listen(integer channel, string name, key id, string message) {
439 if(message == "⟵ Back") {
440 llDialog(id, "\nPlease choose a primitive for Corrade to sit on from the list below:\n", wasDialogMenu(menu, ["⟵ Back", "", "Next ⟶"], "<"), -10);
441 return;
442 }
443 if(message == "Next ⟶") {
444 llDialog(id, "\nPlease choose a primitive for Corrade to sit on from the list below:\n", wasDialogMenu(menu, ["⟵ Back", "", "Next ⟶"], ">"), -10);
445 return;
446 }
447 integer i = llGetListLength(menu) - 1;
448 do {
449 string v = llList2String(menu, i);
450 if(llSubStringIndex(v, message) != -1)
451 jump sit;
452 } while(--i > -1);
453 // GC
454 menu = [];
455 // DEBUG
456 llOwnerSay("Invalid menu item selected...");
457 llResetScript();
458 @sit;
459 // GC
460 menu = [];
461 select = i;
462 // Got a menu item so bind to permission notifications and sit.
463 state notify;
464  
465 }
466 timer() {
467 // DEBUG
468 llOwnerSay("Dialog menu timeout...");
469 llResetScript();
470 }
471 attach(key id) {
472 llResetScript();
473 }
474 on_rez(integer num) {
475 llResetScript();
476 }
477 changed(integer change) {
478 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
479 llResetScript();
480 }
481 }
482 state_exit() {
483 llSetTimerEvent(0);
484 }
485 }
486  
487 state notify {
488 state_entry() {
489 // DEBUG
490 llOwnerSay("Binding to the permission Corrade notification...");
491 llInstantMessage(
492 (key)wasKeyValueGet(
493 "corrade",
494 configuration
495 ),
496 wasKeyValueEncode(
497 [
498 "command", "notify",
499 "group", wasURLEscape(
500 wasKeyValueGet(
501 "group",
502 configuration
503 )
504 ),
505 "password", wasURLEscape(
506 wasKeyValueGet(
507 "password",
508 configuration
509 )
510 ),
511 "action", "add",
512 "type", "permission",
513 "URL", wasURLEscape(callback),
514 "callback", wasURLEscape(callback)
515 ]
516 )
517 );
518 llSetTimerEvent(60);
519 }
520 touch_end(integer num) {
521 llSetColor(<.5,0,0>, ALL_SIDES);
522 llResetScript();
523 }
524 http_request(key id, string method, string body) {
525 llHTTPResponse(id, 200, "OK");
526 if(wasKeyValueGet("command", body) != "notify" ||
527 wasKeyValueGet("success", body) != "True") {
528 // DEBUG
529 llOwnerSay("Failed to bind to the permission notification...");
530 llResetScript();
531 }
532 // DEBUG
533 llOwnerSay("Permission notification installed...");
534 state sit;
535 }
536 timer() {
537 // DEBUG
538 llOwnerSay("Timeout binding to permission notification...");
539 llResetScript();
540 }
541 attach(key id) {
542 llResetScript();
543 }
544 on_rez(integer num) {
545 llResetScript();
546 }
547 changed(integer change) {
548 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
549 llResetScript();
550 }
551 }
552 state_exit() {
553 llSetTimerEvent(0);
554 }
555 }
556  
557 state sit {
558 state_entry() {
559 // DEBUG
560 llOwnerSay("Sitting on: " +
561 llList2String(names, select) +
562 " UUID: " +
563 llList2String(UUIDs, select)
564 );
565 llInstantMessage(
566 (key)wasKeyValueGet(
567 "corrade",
568 configuration
569 ),
570 wasKeyValueEncode(
571 [
572 "command", "sit",
573 "group", wasURLEscape(
574 wasKeyValueGet(
575 "group",
576 configuration
577 )
578 ),
579 "password", wasURLEscape(
580 wasKeyValueGet(
581 "password",
582 configuration
583 )
584 ),
585 "item", wasURLEscape(
586 llList2String(UUIDs, select)
587 ),
588 "range", wasURLEscape(
589 wasKeyValueGet(
590 "radar",
591 configuration
592 )
593 ),
594 "callback", wasURLEscape(callback)
595 ]
596 )
597 );
598 llSetTimerEvent(60);
599 }
600 touch_end(integer num) {
601 state unbind;
602 }
603 http_request(key id, string method, string body) {
604 llHTTPResponse(id, 200, "OK");
605 llSetTimerEvent(5);
606 if(wasKeyValueGet("type", body) != "permission" ||
607 wasKeyValueGet("permissions", body) != "TriggerAnimation") return;
608 llSetTimerEvent(10);
609 // DEBUG
610 llOwnerSay("Corrade received the permission request to trigger an animation, replying...");
611 llInstantMessage(
612 (key)wasKeyValueGet(
613 "corrade",
614 configuration
615 ),
616 wasKeyValueEncode(
617 [
618 "command", "replytoscriptpermissionrequest",
619 "group", wasKeyValueGet(
620 "group",
621 configuration
622 ),
623 "password", wasKeyValueGet(
624 "password",
625 configuration
626 ),
627 "item", wasKeyValueGet(
628 "item",
629 body
630 ),
631 "task", wasKeyValueGet(
632 "task",
633 body
634 ),
635 "region", wasKeyValueGet(
636 "region",
637 body
638 ),
639 "permissions", "TriggerAnimation",
640 "callback", wasURLEscape(callback)
641 ]
642 )
643 );
644 llResetScript();
645 }
646 timer() {
647 state unbind;
648 }
649 attach(key id) {
650 llResetScript();
651 }
652 on_rez(integer num) {
653 llResetScript();
654 }
655 changed(integer change) {
656 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
657 llResetScript();
658 }
659 }
660 state_exit() {
661 llSetTimerEvent(0);
662 }
663 }
664  
665 state unbind {
666 state_entry() {
667 // DEBUG
668 llOwnerSay("Unbinding from the permission Corrade notification...");
669 llInstantMessage(
670 (key)wasKeyValueGet(
671 "corrade",
672 configuration
673 ),
674 wasKeyValueEncode(
675 [
676 "command", "notify",
677 "group", wasURLEscape(
678 wasKeyValueGet(
679 "group",
680 configuration
681 )
682 ),
683 "password", wasURLEscape(
684 wasKeyValueGet(
685 "password",
686 configuration
687 )
688 ),
689 "action", "remove",
690 "type", "permission",
691 "URL", wasURLEscape(callback),
692 "callback", wasURLEscape(callback)
693 ]
694 )
695 );
696 llSetTimerEvent(60);
697 }
698 http_request(key id, string method, string body) {
699 llHTTPResponse(id, 200, "OK");
700 if(wasKeyValueGet("command", body) != "notify" ||
701 wasKeyValueGet("success", body) != "True") {
702 // DEBUG
703 llOwnerSay("Failed to unbind from the permission notification...");
704 llResetScript();
705 }
706 // DEBUG
707 llOwnerSay("Permission notification uninstalled...");
708 llResetScript();
709 }
710 timer() {
711 // DEBUG
712 llOwnerSay("Timeout unbinding from the permission notification...");
713 llResetScript();
714 }
715 attach(key id) {
716 llResetScript();
717 }
718 on_rez(integer num) {
719 llResetScript();
720 }
721 changed(integer change) {
722 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
723 llResetScript();
724 }
725 }
726 state_exit() {
727 llSetTimerEvent(0);
728 }
729 }