corrade-lsl-templates – Blame information for rev 35

Subversion Repositories:
Rev:
Rev Author Line No. Line
35 office 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2016 - License: CC BY 2.0 //
3 ///////////////////////////////////////////////////////////////////////////
4 //
5 // This script makes Corrade retrieve an item from the sim.
6 // For more information on Corrade, please see:
7 // http://grimore.org/secondlife/scripted_agents/corrade
8 //
9 ///////////////////////////////////////////////////////////////////////////
10  
11 ///////////////////////////////////////////////////////////////////////////
12 // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 //
13 ///////////////////////////////////////////////////////////////////////////
14 vector wasCirclePoint(float radius) {
15 float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
16 float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
17 if(llPow(x,2) + llPow(y,2) <= llPow(radius,2))
18 return <x, y, 0>;
19 return wasCirclePoint(radius);
20 }
21  
22 ///////////////////////////////////////////////////////////////////////////
23 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
24 ///////////////////////////////////////////////////////////////////////////
25 string wasKeyValueGet(string k, string data) {
26 if(llStringLength(data) == 0) return "";
27 if(llStringLength(k) == 0) return "";
28 list a = llParseString2List(data, ["&", "="], []);
29 integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
30 if(i != -1) return llList2String(a, 2*i+1);
31 return "";
32 }
33  
34 ///////////////////////////////////////////////////////////////////////////
35 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
36 ///////////////////////////////////////////////////////////////////////////
37 string wasKeyValueEncode(list data) {
38 list k = llList2ListStrided(data, 0, -1, 2);
39 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
40 data = [];
41 do {
42 data += llList2String(k, 0) + "=" + llList2String(v, 0);
43 k = llDeleteSubList(k, 0, 0);
44 v = llDeleteSubList(v, 0, 0);
45 } while(llGetListLength(k) != 0);
46 return llDumpList2String(data, "&");
47 }
48  
49 ///////////////////////////////////////////////////////////////////////////
50 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
51 ///////////////////////////////////////////////////////////////////////////
52 // escapes a string in conformance with RFC1738
53 string wasURLEscape(string i) {
54 string o = "";
55 do {
56 string c = llGetSubString(i, 0, 0);
57 i = llDeleteSubString(i, 0, 0);
58 if(c == "") jump continue;
59 if(c == " ") {
60 o += "+";
61 jump continue;
62 }
63 if(c == "\n") {
64 o += "%0D" + llEscapeURL(c);
65 jump continue;
66 }
67 o += llEscapeURL(c);
68 @continue;
69 } while(i != "");
70 return o;
71 }
72  
73 ///////////////////////////////////////////////////////////////////////////
74 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
75 ///////////////////////////////////////////////////////////////////////////
76 // unescapes a string in conformance with RFC1738
77 string wasURLUnescape(string i) {
78 return llUnescapeURL(
79 llDumpList2String(
80 llParseString2List(
81 llDumpList2String(
82 llParseString2List(
83 i,
84 ["+"],
85 []
86 ),
87 " "
88 ),
89 ["%0D%0A"],
90 []
91 ),
92 "\n"
93 )
94 );
95 }
96  
97 ///////////////////////////////////////////////////////////////////////////
98 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
99 ///////////////////////////////////////////////////////////////////////////
100 list wasCSVToList(string csv) {
101 list l = [];
102 list s = [];
103 string m = "";
104 do {
105 string a = llGetSubString(csv, 0, 0);
106 csv = llDeleteSubString(csv, 0, 0);
107 if(a == ",") {
108 if(llList2String(s, -1) != "\"") {
109 l += m;
110 m = "";
111 jump continue;
112 }
113 m += a;
114 jump continue;
115 }
116 if(a == "\"" && llGetSubString(csv, 0, 0) == a) {
117 m += a;
118 csv = llDeleteSubString(csv, 0, 0);
119 jump continue;
120 }
121 if(a == "\"") {
122 if(llList2String(s, -1) != a) {
123 s += a;
124 jump continue;
125 }
126 s = llDeleteSubList(s, -1, -1);
127 jump continue;
128 }
129 m += a;
130 @continue;
131 } while(csv != "");
132 // postcondition: length(s) = 0
133 return l + m;
134 }
135  
136 ///////////////////////////////////////////////////////////////////////////
137 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
138 ///////////////////////////////////////////////////////////////////////////
139 string wasListToCSV(list l) {
140 list v = [];
141 do {
142 string a = llDumpList2String(
143 llParseStringKeepNulls(
144 llList2String(
145 l,
146  
147 ),
148 ["\""],
149 []
150 ),
151 "\"\""
152 );
153 if(llParseStringKeepNulls(
154 a,
155 [" ", ",", "\n", "\""], []
156 ) !=
157 (list) a
158 ) a = "\"" + a + "\"";
159 v += a;
160 l = llDeleteSubList(l, 0, 0);
161 } while(l != []);
162 return llDumpList2String(v, ",");
163 }
164  
165 ///////////////////////////////////////////////////////////////////////////
166 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
167 ///////////////////////////////////////////////////////////////////////////
168 integer wasMenuIndex = 0;
169 list wasDialogMenu(list input, list actions, string direction) {
170 integer cut = 11-wasListCountExclude(actions, [""]);
171 if(direction == ">" && (wasMenuIndex+1)*cut+wasMenuIndex+1 < llGetListLength(input)) {
172 ++wasMenuIndex;
173 jump slice;
174 }
175 if(direction == "<" && wasMenuIndex-1 >= 0) {
176 --wasMenuIndex;
177 jump slice;
178 }
179 @slice;
180 integer multiple = wasMenuIndex*cut;
181 input = llList2List(input, multiple+wasMenuIndex, multiple+cut+wasMenuIndex);
182 input = wasListMerge(input, actions, "");
183 return input;
184 }
185  
186 ///////////////////////////////////////////////////////////////////////////
187 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
188 ///////////////////////////////////////////////////////////////////////////
189 integer wasListCountExclude(list input, list exclude) {
190 if(llGetListLength(input) == 0) return 0;
191 if(llListFindList(exclude, (list)llList2String(input, 0)) == -1)
192 return 1 + wasListCountExclude(llDeleteSubList(input, 0, 0), exclude);
193 return wasListCountExclude(llDeleteSubList(input, 0, 0), exclude);
194 }
195  
196 ///////////////////////////////////////////////////////////////////////////
197 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
198 ///////////////////////////////////////////////////////////////////////////
199 list wasListMerge(list l, list m, string merge) {
200 if(llGetListLength(l) == 0 && llGetListLength(m) == 0) return [];
201 string a = llList2String(m, 0);
202 if(a != merge) return [ a ] + wasListMerge(l, llDeleteSubList(m, 0, 0), merge);
203 return [ llList2String(l, 0) ] + wasListMerge(llDeleteSubList(l, 0, 0), llDeleteSubList(m, 0, 0), merge);
204 }
205  
206 // for notecard reading
207 integer line = 0;
208  
209 // key-value data will be read into this list
210 list tuples = [];
211 string configuration = "";
212  
213 // URL
214 string callback = "";
215  
216 // dialog variables
217 list names = [];
218 list UUIDs = [];
219 list local = [];
220 list menu = [];
221 integer listenHandle = 0;
222  
223 // jump table
224 string autopilot_jump_state = "";
225  
226 // utility variables
227 key itemUUID = NULL_KEY;
228 vector autoPilotTarget = ZERO_VECTOR;
229  
230 // position of the cliking avatar
231 key avatarTouch = NULL_KEY;
232  
233 default {
234 state_entry() {
235 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
236 llOwnerSay("Sorry, could not find a configuration inventory notecard.");
237 return;
238 }
239 // DEBUG
240 llOwnerSay("Reading configuration file...");
241 llGetNotecardLine("configuration", line);
242 }
243 dataserver(key id, string data) {
244 if(data == EOF) {
245 // invariant, length(tuples) % 2 == 0
246 if(llGetListLength(tuples) % 2 != 0) {
247 llOwnerSay("Error in configuration notecard.");
248 return;
249 }
250 key CORRADE = llList2Key(
251 tuples,
252 llListFindList(
253 tuples,
254 [
255 "corrade"
256 ]
257 )
258 +1);
259 if(CORRADE == NULL_KEY) {
260 llOwnerSay("Error in configuration notecard: corrade");
261 return;
262 }
263 string GROUP = llList2String(
264 tuples,
265 llListFindList(
266 tuples,
267 [
268 "group"
269 ]
270 )
271 +1);
272 if(GROUP == "") {
273 llOwnerSay("Error in configuration notecard: group");
274 return;
275 }
276 string PASSWORD = llList2String(
277 tuples,
278 llListFindList(
279 tuples,
280 [
281 "password"
282 ]
283 )
284 +1);
285 if(PASSWORD == "") {
286 llOwnerSay("Error in configuration notecard: password");
287 return;
288 }
289 string VERSION = llList2String(
290 tuples,
291 llListFindList(
292 tuples,
293 [
294 "version"
295 ]
296 )
297 +1);
298 if(VERSION == "") {
299 llOwnerSay("Error in configuration notecard: version");
300 return;
301 }
302 // DEBUG
303 llOwnerSay("Read configuration notecard...");
304 configuration = wasKeyValueEncode(tuples);
305 // GC
306 tuples = [];
307  
308 autopilot_jump_state = "main";
309 state url;
310 }
311 if(data == "") jump continue;
312 integer i = llSubStringIndex(data, "#");
313 if(i != -1) data = llDeleteSubString(data, i, -1);
314 list o = llParseString2List(data, ["="], []);
315 // get rid of starting and ending quotes
316 string k = llDumpList2String(
317 llParseString2List(
318 llStringTrim(
319 llList2String(
320 o,
321  
322 ),
323 STRING_TRIM),
324 ["\""], []
325 ), "\"");
326 string v = llDumpList2String(
327 llParseString2List(
328 llStringTrim(
329 llList2String(
330 o,
331 1
332 ),
333 STRING_TRIM),
334 ["\""], []
335 ), "\"");
336 if(k == "" || v == "") jump continue;
337 tuples += k;
338 tuples += v;
339 @continue;
340 llGetNotecardLine("configuration", ++line);
341 }
342 attach(key id) {
343 llResetScript();
344 }
345 on_rez(integer num) {
346 llResetScript();
347 }
348 changed(integer change) {
349 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
350 llResetScript();
351 }
352 }
353 }
354  
355 state url {
356 state_entry() {
357 // DEBUG
358 llOwnerSay("Requesting URL...");
359 llReleaseURL(callback);
360 llRequestURL();
361 }
362 http_request(key id, string method, string body) {
363 if(method != URL_REQUEST_GRANTED) return;
364 callback = body;
365 // DEBUG
366 llOwnerSay("Got URL...");
367  
368 state main;
369 }
370 on_rez(integer num) {
371 llResetScript();
372 }
373 changed(integer change) {
374 llResetScript();
375 }
376 }
377  
378  
379 state main {
380 state_entry() {
381 llOwnerSay("Touch to select object...");
382 }
383 touch_start(integer num) {
384 // DEBUG
385 llOwnerSay("Getting objects...");
386  
387 // store the poition of the cliking avatar
388 avatarTouch = llDetectedKey(0);
389  
390 llInstantMessage(
391 wasKeyValueGet(
392 "corrade",
393 configuration
394 ),
395 wasKeyValueEncode(
396 [
397 "command", "getobjectsdata",
398 "group", wasURLEscape(
399 wasKeyValueGet(
400 "group",
401 configuration
402 )
403 ),
404 "password", wasURLEscape(
405 wasKeyValueGet(
406 "password",
407 configuration
408 )
409 ),
410 "entity", "world",
411 "range", wasURLEscape(
412 wasKeyValueGet(
413 "range",
414 configuration
415 )
416 ),
417 "data", wasListToCSV(
418 [
419 "Properties.Name",
420 "ID",
421 "Position"
422 ]
423 ),
424 "sift", wasListToCSV(
425 [
426 "take", 30
427 ]
428 ),
429 "callback", wasURLEscape(callback)
430 ]
431 )
432 );
433  
434 llSetTimerEvent(60);
435 }
436 timer() {
437 // DEBUG
438 llOwnerSay("Timeout retrieving object properties...");
439 llResetScript();
440 }
441 http_request(key id, string method, string body) {
442 llHTTPResponse(id, 200, "OK");
443  
444 // Only listen to getobjectsdata command.
445 if(wasKeyValueGet("command", body) != "getobjectsdata")
446 return;
447  
448 if(wasKeyValueGet("success", body) != "True") {
449 // DEBUG
450 llOwnerSay("Error querying primitives: " + wasKeyValueGet("error", body));
451 llResetScript();
452 }
453  
454 string dataKey = wasURLUnescape(
455 wasKeyValueGet(
456 "data",
457 body
458 )
459 );
460  
461 if(dataKey == "") {
462 // DEBUG
463 llOwnerSay("No data for scanned primitives. No primitives in range?");
464 llResetScript();
465 }
466  
467 list data = wasCSVToList(dataKey);
468 // Copy the names and UUIDs of the primitives.
469 names = [];
470 UUIDs = [];
471 local = [];
472 do {
473 string k = llList2String(data, 0);
474 data = llDeleteSubList(data, 0, 0);
475 string v = llList2String(data, 0);
476 data = llDeleteSubList(data, 0, 0);
477  
478 if(k == "Properties.Name") {
479 // Corrade may pass blank names due to SL
480 // objects not being yet discovered.
481 if(v == "") {
482 names += "Unknown";
483 jump continue;
484 }
485 names += v;
486 jump continue;
487 }
488  
489 if(k == "ID"){
490 if(v == "") {
491 UUIDs += NULL_KEY;
492 jump continue;
493 }
494 UUIDs += v;
495 jump continue;
496 }
497  
498 if(k == "Position") {
499 if(v == "") {
500 local += ZERO_VECTOR;
501 jump continue;
502 }
503 local += v;
504 jump continue;
505 }
506 @continue;
507 } while(llGetListLength(data));
508  
509 state pick;
510 }
511 on_rez(integer num) {
512 llResetScript();
513 }
514 changed(integer change) {
515 llResetScript();
516 }
517 state_exit() {
518 llSetTimerEvent(0);
519 }
520 }
521  
522 state pick {
523 state_entry() {
524 // DEBUG
525 llOwnerSay("Sending menu...");
526  
527 // trim the button labels down to 23 characters
528 menu = [];
529 integer i = 0;
530 do {
531 menu += llGetSubString(llList2String(names, i), 0, 23);
532 } while(++i < llGetListLength(names));
533  
534 // listen and send the dialog
535 integer comChannel = ((integer)("0x"+llGetSubString((string)avatarTouch,-8,-1)) & 0x3FFFFFFF) ^ 0xBFFFFFFF;
536 listenHandle = llListen(comChannel, "", avatarTouch, "");
537 llDialog(avatarTouch, "\nPlease choose a primitive for Corrade to sit on from the list below:\n", wasDialogMenu(menu, ["⟵ Back", "", "Next ⟶"], ""), comChannel);
538 llSetTimerEvent(60);
539 }
540 listen(integer channel, string name, key id, string message) {
541 if(message == "⟵ Back") {
542 llDialog(id, "\nPlease choose a primitive for Corrade to sit on from the list below:\n", wasDialogMenu(menu, ["⟵ Back", "", "Next ⟶"], "<"), channel);
543 return;
544 }
545 if(message == "Next ⟶") {
546 llDialog(id, "\nPlease choose a primitive for Corrade to sit on from the list below:\n", wasDialogMenu(menu, ["⟵ Back", "", "Next ⟶"], ">"), channel);
547 return;
548 }
549 integer i = llGetListLength(menu) - 1;
550 do {
551 string v = llList2String(menu, i);
552 if(llSubStringIndex(v, message) != -1)
553 jump selection;
554 } while(--i > -1);
555 // GC
556 menu = [];
557  
558 // DEBUG
559 llOwnerSay("Invalid menu item selected...");
560 llResetScript();
561 @selection;
562  
563 // DEBUG
564 llOwnerSay("Selected: " + llList2String(names, i) + "...");
565  
566 // Get the key of the object.
567 itemUUID = (key)llList2String(UUIDs, i);
568  
569 // Get the target.
570 autoPilotTarget = (vector)llList2String(local, i);
571  
572 // GC
573 menu = [];
574 names = [];
575 UUIDs = [];
576 local = [];
577  
578 // Got a menu item so bind to permission notifications and sit.
579 state bind;
580 }
581 timer() {
582 // DEBUG
583 llOwnerSay("Dialog menu timeout...");
584 llResetScript();
585 }
586 on_rez(integer num) {
587 llResetScript();
588 }
589 changed(integer change) {
590 llResetScript();
591 }
592 state_exit() {
593 llSetTimerEvent(0);
594 }
595 }
596  
597  
598 state bind {
599 state_entry() {
600 // DEBUG
601 llOwnerSay("Binding notifications...");
602  
603 llInstantMessage(
604 (key)wasKeyValueGet(
605 "corrade",
606 configuration
607 ),
608 wasKeyValueEncode(
609 [
610 "command", "notify",
611 "group", wasURLEscape(
612 wasKeyValueGet(
613 "group",
614 configuration
615 )
616 ),
617 "password", wasURLEscape(
618 wasKeyValueGet(
619 "password",
620 configuration
621 )
622 ),
623 "action", "set",
624 "type", wasListToCSV(
625 [
626 "inventory",
627 "location"
628 ]
629 ),
630 "tag", wasURLEscape(
631 wasKeyValueGet(
632 "tag",
633 configuration
634 )
635 ),
636 "URL", wasURLEscape(callback),
637 "callback", wasURLEscape(callback)
638 ]
639 )
640 );
641 llSetTimerEvent(60);
642 }
643 http_request(key id, string method, string body) {
644 llHTTPResponse(id, 200, "OK");
645  
646 if(wasKeyValueGet("command", body) != "notify")
647 return;
648  
649 if(wasKeyValueGet("success", body) != "True") {
650 // DEBUG
651 llOwnerSay("Failed to bind notifications...");
652 llResetScript();
653 }
654  
655 // DEBUG
656 llOwnerSay("Notifications installed, fetching...");
657  
658 autopilot_jump_state = "take";
659 state autopilot;
660 }
661 timer() {
662 // DEBUG
663 llOwnerSay("Timeout binding notifications...");
664 llResetScript();
665 }
666 on_rez(integer num) {
667 llResetScript();
668 }
669 changed(integer change) {
670 llResetScript();
671 }
672 state_exit() {
673 llSetTimerEvent(0);
674 }
675 }
676  
677 state autopilot {
678 state_entry() {
679 // DEBUG
680 llOwnerSay("Walking...");
681  
682 llInstantMessage(
683 (key)wasKeyValueGet(
684 "corrade",
685 configuration
686 ),
687 wasKeyValueEncode(
688 [
689 "command", "autopilot",
690 "group", wasURLEscape(
691 wasKeyValueGet(
692 "group",
693 configuration
694 )
695 ),
696 "password", wasURLEscape(
697 wasKeyValueGet(
698 "password",
699 configuration
700 )
701 ),
702 "position", autoPilotTarget + wasCirclePoint(1.1),
703 "action", "start"
704 ]
705 )
706 );
707  
708 llSetTimerEvent(60);
709 }
710 http_request(key id, string method, string body) {
711 llHTTPResponse(id, 200, "OK");
712  
713 // Wait for the location notification.
714 if(wasKeyValueGet("type", body) != "location")
715 return;
716  
717 // Compute the position beteen the bot and the target.
718 vector position = (vector)wasURLUnescape(
719 wasKeyValueGet(
720 "position",
721 body
722 )
723 );
724  
725 // Detect when Corrade is near.
726 if(llVecDist(position, autoPilotTarget) >
727 (float)wasURLEscape(wasKeyValueGet("scan", configuration)))
728 return;
729  
730 // DEBUG
731 llOwnerSay("Corrade has arrived...");
732  
733 // Jump table!
734 if(autopilot_jump_state == "drop")
735 state drop;
736  
737 if(autopilot_jump_state == "take")
738 state take;
739  
740 // DEBUG
741 llOwnerSay("Jump table corrupt, please contact vendor...");
742 }
743 timer() {
744 // DEBUG
745 llOwnerSay("Timeout fetching object...");
746 llResetScript();
747 }
748 on_rez(integer num) {
749 llResetScript();
750 }
751 changed(integer change) {
752 llResetScript();
753 }
754 state_exit() {
755 llSetTimerEvent(0);
756 }
757 }
758  
759 state take {
760 state_entry() {
761 // DEBUG
762 llOwnerSay("Taking to inventory...");
763  
764 llInstantMessage(
765 (key)wasKeyValueGet(
766 "corrade",
767 configuration
768 ),
769 wasKeyValueEncode(
770 [
771 "command", "derez",
772 "group", wasURLEscape(
773 wasKeyValueGet(
774 "group",
775 configuration
776 )
777 ),
778 "password", wasURLEscape(
779 wasKeyValueGet(
780 "password",
781 configuration
782 )
783 ),
784 "item", itemUUID,
785 "type", "AgentInventoryTake",
786 "range", "5"
787 ]
788 )
789 );
790  
791 llSetTimerEvent(60);
792 }
793 http_request(key id, string method, string body) {
794 llHTTPResponse(id, 200, "OK");
795  
796 // wait for inventory notification.
797 if(wasKeyValueGet("type", body) != "inventory")
798 return;
799  
800 // item taken to inventory implies the create action
801 if(wasKeyValueGet("action", body) != "created")
802 return;
803  
804 itemUUID = (key) wasURLUnescape(
805 wasKeyValueGet(
806 "inventory",
807 body
808 )
809 );
810  
811 // DEBUG
812 llOwnerSay("Retrieved object as inventory UUID: " + (string)itemUUID);
813  
814 state wear;
815 }
816 timer() {
817 // DEBUG
818 llOwnerSay("Timeout taking object to inventory...");
819 llResetScript();
820 }
821 on_rez(integer num) {
822 llResetScript();
823 }
824 changed(integer change) {
825 llResetScript();
826 }
827 state_exit() {
828 llSetTimerEvent(0);
829 }
830 }
831  
832 state wear {
833 state_entry() {
834 // DEBUG
835 llOwnerSay("Wearing...");
836  
837 llInstantMessage(
838 (key)wasKeyValueGet(
839 "corrade",
840 configuration
841 ),
842 wasKeyValueEncode(
843 [
844 "command", "attach",
845 "group", wasURLEscape(
846 wasKeyValueGet(
847 "group",
848 configuration
849 )
850 ),
851 "password", wasURLEscape(
852 wasKeyValueGet(
853 "password",
854 configuration
855 )
856 ),
857 "attachments", wasListToCSV(
858 [
859 wasURLEscape(
860 wasKeyValueGet(
861 "attachPoint",
862 configuration
863 )
864 ), itemUUID
865 ]
866 ),
867 "callback", wasURLEscape(callback)
868 ]
869 )
870 );
871  
872 llSetTimerEvent(60);
873 }
874 http_request(key id, string method, string body) {
875 llHTTPResponse(id, 200, "OK");
876  
877 if(wasKeyValueGet("command", body) != "attach")
878 return;
879  
880 if(wasKeyValueGet("success", body) != "True") {
881 // DEBUG
882 llOwnerSay("Unable to attach item: " + wasKeyValueGet("error", body));
883 llResetScript();
884 }
885  
886 // DEBUG
887 llOwnerSay("Item attached, returning...");
888  
889 // set the new target to the position of the avatar
890 autoPilotTarget = (vector)llList2String(
891 llGetObjectDetails(
892 avatarTouch,
893 [
894 OBJECT_POS
895 ]
896 ),
897  
898 );
899 autopilot_jump_state = "drop";
900 state autopilot;
901 }
902 timer() {
903 // DEBUG
904 llOwnerSay("Timeout taking object to inventory...");
905 llResetScript();
906 }
907 on_rez(integer num) {
908 llResetScript();
909 }
910 changed(integer change) {
911 llResetScript();
912 }
913 state_exit() {
914 llSetTimerEvent(0);
915 }
916 }
917  
918 state drop {
919 state_entry() {
920 // DEBUG
921 llOwnerSay("Dropping...");
922  
923 llInstantMessage(
924 (key)wasKeyValueGet(
925 "corrade",
926 configuration
927 ),
928 wasKeyValueEncode(
929 [
930 "command", "dropobject",
931 "group", wasURLEscape(
932 wasKeyValueGet(
933 "group",
934 configuration
935 )
936 ),
937 "password", wasURLEscape(
938 wasKeyValueGet(
939 "password",
940 configuration
941 )
942 ),
943 "type", "UUID",
944 "item", wasURLEscape(itemUUID),
945 "callback", wasURLEscape(callback)
946 ]
947 )
948 );
949  
950 llSetTimerEvent(60);
951 }
952 http_request(key id, string method, string body) {
953 llHTTPResponse(id, 200, "OK");
954  
955 if(wasKeyValueGet("command", body) != "dropobject")
956 return;
957  
958 if(wasKeyValueGet("success", body) != "True") {
959 // DEBUG
960 llOwnerSay("Could not drop object: " + wasURLUnescape(body));
961 llResetScript();
962 }
963  
964 // DEBUG
965 llOwnerSay("Item dropped...");
966  
967 state unbind;
968 }
969 timer() {
970 // DEBUG
971 llOwnerSay("Timeout dropping object...");
972 llResetScript();
973 }
974 on_rez(integer num) {
975 llResetScript();
976 }
977 changed(integer change) {
978 llResetScript();
979 }
980 state_exit() {
981 llSetTimerEvent(0);
982 }
983 }
984  
985 state unbind {
986 state_entry() {
987 // DEBUG
988 llOwnerSay("Unbinding notifications...");
989  
990 llInstantMessage(
991 (key)wasKeyValueGet(
992 "corrade",
993 configuration
994 ),
995 wasKeyValueEncode(
996 [
997 "command", "notify",
998 "group", wasURLEscape(
999 wasKeyValueGet(
1000 "group",
1001 configuration
1002 )
1003 ),
1004 "password", wasURLEscape(
1005 wasKeyValueGet(
1006 "password",
1007 configuration
1008 )
1009 ),
1010 "action", "remove",
1011 "tag", wasURLEscape(
1012 wasKeyValueGet(
1013 "tag",
1014 configuration
1015 )
1016 ),
1017 "URL", wasURLEscape(callback),
1018 "callback", wasURLEscape(callback)
1019 ]
1020 )
1021 );
1022  
1023 llSetTimerEvent(60);
1024 }
1025 http_request(key id, string method, string body) {
1026 llHTTPResponse(id, 200, "OK");
1027  
1028 if(wasKeyValueGet("command", body) != "notify")
1029 return;
1030  
1031 if(wasKeyValueGet("success", body) != "True") {
1032 // DEBUG
1033 llOwnerSay("Failed to unbind notifications...");
1034 llResetScript();
1035 }
1036  
1037 // DEBUG
1038 llOwnerSay("Notifications uninstalled...");
1039  
1040 llResetScript();
1041 }
1042 timer() {
1043 // DEBUG
1044 llOwnerSay("Timeout binding notifications...");
1045 llResetScript();
1046 }
1047 on_rez(integer num) {
1048 llResetScript();
1049 }
1050 changed(integer change) {
1051 llResetScript();
1052 }
1053 state_exit() {
1054 llSetTimerEvent(0);
1055 }
1056 }