corrade-lsl-templates – Diff between revs 29 and 37

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 29 Rev 37
1 /////////////////////////////////////////////////////////////////////////// 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2014 - License: CC BY 2.0 // 2 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
3 /////////////////////////////////////////////////////////////////////////// 3 ///////////////////////////////////////////////////////////////////////////
4 // 4 //
5 // This is a puppeteer script for the Corrade Second Life / OpenSim bot 5 // This is a puppeteer script for the Corrade Second Life / OpenSim bot
6 // that, given a set of local coordinates, will make the bot traverse a 6 // that, given a set of local coordinates, will make the bot traverse a
7 // path while also minding collisions with object. You can find more 7 // path while also minding collisions with object. You can find more
8 // details about the Corrade bot and how to get it to work on your machine 8 // details about the Corrade bot and how to get it to work on your machine
9 // by following the URL: http://grimore.org/secondlife/scripted_agents/corrade 9 // by following the URL: http://was.fm/secondlife/scripted_agents/corrade
10 // 10 //
11 // This script works together with a "configuration" notecard that must 11 // This script works together with a "configuration" notecard that must
12 // be placed in the same primitive as this script. The purpose of this 12 // be placed in the same primitive as this script. The purpose of this
13 // script is to demonstrate how Corrade can be made to walk on a path and 13 // script is to demonstrate how Corrade can be made to walk on a path and
14 // you are free to use, change, and commercialize it under the CC BY 2.0 14 // you are free to use, change, and commercialize it under the GNU/GPLv3
15 // license at: https://creativecommons.org/licenses/by/2.0 15 // license at: http://www.gnu.org/licenses/gpl.html
16 // 16 //
17 /////////////////////////////////////////////////////////////////////////// 17 ///////////////////////////////////////////////////////////////////////////
18   18  
19 /////////////////////////////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////////////////////////////
20 // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 // 20 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
21 /////////////////////////////////////////////////////////////////////////// 21 ///////////////////////////////////////////////////////////////////////////
22 string wasKeyValueGet(string k, string data) { 22 string wasKeyValueGet(string var, string kvp) {
-   23 list dVars = llParseString2List(kvp, ["&"], []);
-   24 do {
-   25 list data = llParseString2List(llList2String(dVars, 0), ["="], []);
23 if(llStringLength(data) == 0) return ""; 26 string k = llList2String(data, 0);
24 if(llStringLength(k) == 0) return ""; 27 if(k != var) jump continue;
25 list a = llParseString2List(data, ["&", "="], []); 28 return llList2String(data, 1);
-   29 @continue;
26 integer i = llListFindList(a, [ k ]); 30 dVars = llDeleteSubList(dVars, 0, 0);
27 if(i != -1) return llList2String(a, i+1); 31 } while(llGetListLength(dVars));
28 return ""; 32 return "";
29 } 33 }
30 34  
31 /////////////////////////////////////////////////////////////////////////// 35 ///////////////////////////////////////////////////////////////////////////
32 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 // 36 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
33 /////////////////////////////////////////////////////////////////////////// 37 ///////////////////////////////////////////////////////////////////////////
34 string wasKeyValueEncode(list data) { 38 string wasKeyValueEncode(list kvp) {
35 list k = llList2ListStrided(data, 0, -1, 2); 39 if(llGetListLength(kvp) < 2) return "";
36 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); 40 string k = llList2String(kvp, 0);
37 data = []; -  
38 do { -  
39 data += llList2String(k, 0) + "=" + llList2String(v, 0); 41 kvp = llDeleteSubList(kvp, 0, 0);
40 k = llDeleteSubList(k, 0, 0); 42 string v = llList2String(kvp, 0);
41 v = llDeleteSubList(v, 0, 0); 43 kvp = llDeleteSubList(kvp, 0, 0);
42 } while(llGetListLength(k) != 0); 44 if(llGetListLength(kvp) < 2) return k + "=" + v;
43 return llDumpList2String(data, "&"); 45 return k + "=" + v + "&" + wasKeyValueEncode(kvp);
44 } 46 }
-   47  
45   48  
46 /////////////////////////////////////////////////////////////////////////// 49 ///////////////////////////////////////////////////////////////////////////
47 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // 50 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
48 /////////////////////////////////////////////////////////////////////////// 51 ///////////////////////////////////////////////////////////////////////////
49 // escapes a string in conformance with RFC1738 52 // escapes a string in conformance with RFC1738
50 string wasURLEscape(string i) { 53 string wasURLEscape(string i) {
51 string o = ""; 54 string o = "";
52 do { 55 do {
53 string c = llGetSubString(i, 0, 0); 56 string c = llGetSubString(i, 0, 0);
54 i = llDeleteSubString(i, 0, 0); 57 i = llDeleteSubString(i, 0, 0);
55 if(c == "") jump continue; 58 if(c == "") jump continue;
56 if(c == " ") { 59 if(c == " ") {
57 o += "+"; 60 o += "+";
58 jump continue; 61 jump continue;
59 } 62 }
60 if(c == "\n") { 63 if(c == "\n") {
61 o += "%0D" + llEscapeURL(c); 64 o += "%0D" + llEscapeURL(c);
62 jump continue; 65 jump continue;
63 } 66 }
64 o += llEscapeURL(c); 67 o += llEscapeURL(c);
65 @continue; 68 @continue;
66 } while(i != ""); 69 } while(i != "");
67 return o; 70 return o;
68 } 71 }
69   72  
70 /////////////////////////////////////////////////////////////////////////// 73 ///////////////////////////////////////////////////////////////////////////
71 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // 74 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
72 /////////////////////////////////////////////////////////////////////////// 75 ///////////////////////////////////////////////////////////////////////////
73 // unescapes a string in conformance with RFC1738 76 // unescapes a string in conformance with RFC1738
74 string wasURLUnescape(string i) { 77 string wasURLUnescape(string i) {
75 return llUnescapeURL( 78 return llUnescapeURL(
76 llDumpList2String( 79 llDumpList2String(
77 llParseString2List( 80 llParseString2List(
78 llDumpList2String( 81 llDumpList2String(
79 llParseString2List( 82 llParseString2List(
80 i, 83 i,
81 ["+"], 84 ["+"],
82 [] 85 []
83 ), 86 ),
84 " " 87 " "
85 ), 88 ),
86 ["%0D%0A"], 89 ["%0D%0A"],
87 [] 90 []
88 ), 91 ),
89 "\n" 92 "\n"
90 ) 93 )
91 ); 94 );
92 } 95 }
93   -  
94 /////////////////////////////////////////////////////////////////////////// 96 ///////////////////////////////////////////////////////////////////////////
95 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // 97 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
96 /////////////////////////////////////////////////////////////////////////// 98 ///////////////////////////////////////////////////////////////////////////
97 list wasCSVToList(string csv) { 99 list wasCSVToList(string csv) {
98 list l = []; 100 list l = [];
99 list s = []; 101 list s = [];
100 string m = ""; 102 string m = "";
101 do { 103 do {
102 string a = llGetSubString(csv, 0, 0); 104 string a = llGetSubString(csv, 0, 0);
103 csv = llDeleteSubString(csv, 0, 0); 105 csv = llDeleteSubString(csv, 0, 0);
104 if(a == ",") { 106 if(a == ",") {
105 if(llList2String(s, -1) != "\"") { 107 if(llList2String(s, -1) != "\"") {
106 l += m; 108 l += m;
107 m = ""; 109 m = "";
108 jump continue; 110 jump continue;
109 } 111 }
110 m += a; 112 m += a;
111 jump continue; 113 jump continue;
112 } 114 }
113 if(a == "\"" && llGetSubString(csv, 0, 0) == a) { 115 if(a == "\"" && llGetSubString(csv, 0, 0) == a) {
114 m += a; 116 m += a;
115 csv = llDeleteSubString(csv, 0, 0); 117 csv = llDeleteSubString(csv, 0, 0);
116 jump continue; 118 jump continue;
117 } 119 }
118 if(a == "\"") { 120 if(a == "\"") {
119 if(llList2String(s, -1) != a) { 121 if(llList2String(s, -1) != a) {
120 s += a; 122 s += a;
121 jump continue; 123 jump continue;
122 } 124 }
123 s = llDeleteSubList(s, -1, -1); 125 s = llDeleteSubList(s, -1, -1);
124 jump continue; 126 jump continue;
125 } 127 }
126 m += a; 128 m += a;
127 @continue; 129 @continue;
128 } while(csv != ""); 130 } while(csv != "");
129 // postcondition: length(s) = 0 131 // postcondition: length(s) = 0
130 return l + m; 132 return l + m;
131 } 133 }
132   134  
133 // corrade data 135 // corrade data
134 key CORRADE = NULL_KEY; 136 key CORRADE = NULL_KEY;
135 string GROUP = ""; 137 string GROUP = "";
136 string PASSWORD = ""; 138 string PASSWORD = "";
137 list PATH = []; 139 list PATH = [];
138 float PAUSE = 0; 140 float PAUSE = 0;
139 integer RANDOMIZE = FALSE; 141 integer RANDOMIZE = FALSE;
140   142  
141 // for holding the callback URL 143 // for holding the callback URL
142 string callback = ""; 144 string callback = "";
143   145  
144 // for notecard reading 146 // for notecard reading
145 integer line = 0; 147 integer line = 0;
146 148
147 // key-value data will be read into this list 149 // key-value data will be read into this list
148 list tuples = []; 150 list tuples = [];
149 // stores COrrade's current position 151 // stores COrrade's current position
150 vector origin = ZERO_VECTOR; 152 vector origin = ZERO_VECTOR;
151   153  
152 default { 154 default {
153 state_entry() { 155 state_entry() {
154 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { 156 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
155 llOwnerSay("Sorry, could not find a configuration inventory notecard."); 157 llOwnerSay("Sorry, could not find a configuration inventory notecard.");
156 return; 158 return;
157 } 159 }
158 // DEBUG 160 // DEBUG
159 llOwnerSay("Reading configuration file..."); 161 llOwnerSay("Reading configuration file...");
160 llGetNotecardLine("configuration", line); 162 llGetNotecardLine("configuration", line);
161 } 163 }
162 dataserver(key id, string data) { 164 dataserver(key id, string data) {
163 if(data == EOF) { 165 if(data == EOF) {
164 // invariant, length(tuples) % 2 == 0 166 // invariant, length(tuples) % 2 == 0
165 if(llGetListLength(tuples) % 2 != 0) { 167 if(llGetListLength(tuples) % 2 != 0) {
166 llOwnerSay("Error in configuration notecard."); 168 llOwnerSay("Error in configuration notecard.");
167 return; 169 return;
168 } 170 }
169 CORRADE = llList2Key( 171 CORRADE = llList2Key(
170 tuples, 172 tuples,
171 llListFindList( 173 llListFindList(
172 tuples, 174 tuples,
173 [ 175 [
174 "corrade" 176 "corrade"
175 ] 177 ]
176 ) 178 )
177 +1); 179 +1);
178 if(CORRADE == NULL_KEY) { 180 if(CORRADE == NULL_KEY) {
179 llOwnerSay("Error in configuration notecard: corrade"); 181 llOwnerSay("Error in configuration notecard: corrade");
180 return; 182 return;
181 } 183 }
182 GROUP = llList2String( 184 GROUP = llList2String(
183 tuples, 185 tuples,
184 llListFindList( 186 llListFindList(
185 tuples, 187 tuples,
186 [ 188 [
187 "group" 189 "group"
188 ] 190 ]
189 ) 191 )
190 +1); 192 +1);
191 if(GROUP == "") { 193 if(GROUP == "") {
192 llOwnerSay("Error in configuration notecard: group"); 194 llOwnerSay("Error in configuration notecard: group");
193 return; 195 return;
194 } 196 }
195 PASSWORD = llList2String( 197 PASSWORD = llList2String(
196 tuples, 198 tuples,
197 llListFindList( 199 llListFindList(
198 tuples, 200 tuples,
199 [ 201 [
200 "password" 202 "password"
201 ] 203 ]
202 ) 204 )
203 +1); 205 +1);
204 if(PASSWORD == "") { 206 if(PASSWORD == "") {
205 llOwnerSay("Error in configuration notecard: password"); 207 llOwnerSay("Error in configuration notecard: password");
206 return; 208 return;
207 } 209 }
208 PATH = llCSV2List( 210 PATH = llCSV2List(
209 llList2String( 211 llList2String(
210 tuples, 212 tuples,
211 llListFindList( 213 llListFindList(
212 tuples, 214 tuples,
213 [ 215 [
214 "path" 216 "path"
215 ] 217 ]
216 ) 218 )
217 +1) 219 +1)
218 ); 220 );
219 if(PATH == []) { 221 if(PATH == []) {
220 llOwnerSay("Error in configuration notecard: points"); 222 llOwnerSay("Error in configuration notecard: points");
221 return; 223 return;
222 } 224 }
223 PAUSE = llList2Float( 225 PAUSE = llList2Float(
224 tuples, 226 tuples,
225 llListFindList( 227 llListFindList(
226 tuples, 228 tuples,
227 [ 229 [
228 "pause" 230 "pause"
229 ] 231 ]
230 ) 232 )
231 +1); 233 +1);
232 if(PAUSE == 0) { 234 if(PAUSE == 0) {
233 llOwnerSay("Error in configuration notecard: pause"); 235 llOwnerSay("Error in configuration notecard: pause");
234 return; 236 return;
235 } 237 }
236 string boolean = llList2String( 238 string boolean = llList2String(
237 tuples, 239 tuples,
238 llListFindList( 240 llListFindList(
239 tuples, 241 tuples,
240 [ 242 [
241 "randomize" 243 "randomize"
242 ] 244 ]
243 ) 245 )
244 +1); 246 +1);
245 if(llToLower(boolean) == "true") RANDOMIZE = TRUE; 247 if(llToLower(boolean) == "true") RANDOMIZE = TRUE;
246 // DEBUG 248 // DEBUG
247 llOwnerSay("Read configuration notecard..."); 249 llOwnerSay("Read configuration notecard...");
248 state url; 250 state url;
249 } 251 }
250 if(data == "") jump continue; 252 if(data == "") jump continue;
251 integer i = llSubStringIndex(data, "#"); 253 integer i = llSubStringIndex(data, "#");
252 if(i != -1) data = llDeleteSubString(data, i, -1); 254 if(i != -1) data = llDeleteSubString(data, i, -1);
253 list o = llParseString2List(data, ["="], []); 255 list o = llParseString2List(data, ["="], []);
254 // get rid of starting and ending quotes 256 // get rid of starting and ending quotes
255 string k = llDumpList2String( 257 string k = llDumpList2String(
256 llParseString2List( 258 llParseString2List(
257 llStringTrim( 259 llStringTrim(
258 llList2String( 260 llList2String(
259 o, 261 o,
260 0 262 0
261 ), 263 ),
262 STRING_TRIM), 264 STRING_TRIM),
263 ["\""], [] 265 ["\""], []
264 ), "\""); 266 ), "\"");
265 string v = llDumpList2String( 267 string v = llDumpList2String(
266 llParseString2List( 268 llParseString2List(
267 llStringTrim( 269 llStringTrim(
268 llList2String( 270 llList2String(
269 o, 271 o,
270 1 272 1
271 ), 273 ),
272 STRING_TRIM), 274 STRING_TRIM),
273 ["\""], [] 275 ["\""], []
274 ), "\""); 276 ), "\"");
275 if(k == "" || v == "") jump continue; 277 if(k == "" || v == "") jump continue;
276 tuples += k; 278 tuples += k;
277 tuples += v; 279 tuples += v;
278 @continue; 280 @continue;
279 llGetNotecardLine("configuration", ++line); 281 llGetNotecardLine("configuration", ++line);
280 } 282 }
281 on_rez(integer num) { 283 on_rez(integer num) {
282 llResetScript(); 284 llResetScript();
283 } 285 }
284 changed(integer change) { 286 changed(integer change) {
285 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 287 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
286 llResetScript(); 288 llResetScript();
287 } 289 }
288 } 290 }
289 } 291 }
290   292  
291 state url { 293 state url {
292 state_entry() { 294 state_entry() {
293 // DEBUG 295 // DEBUG
294 llOwnerSay("Requesting URL..."); 296 llOwnerSay("Requesting URL...");
295 llRequestURL(); 297 llRequestURL();
296 } 298 }
297 http_request(key id, string method, string body) { 299 http_request(key id, string method, string body) {
298 if(method != URL_REQUEST_GRANTED) return; 300 if(method != URL_REQUEST_GRANTED) return;
299 callback = body; 301 callback = body;
300 // DEBUG 302 // DEBUG
301 llOwnerSay("Got URL..."); 303 llOwnerSay("Got URL...");
302 state detect; 304 state detect;
303 } 305 }
304 on_rez(integer num) { 306 on_rez(integer num) {
305 llResetScript(); 307 llResetScript();
306 } 308 }
307 changed(integer change) { 309 changed(integer change) {
308 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 310 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
309 llResetScript(); 311 llResetScript();
310 } 312 }
311 } 313 }
312 } 314 }
313 315
314 state detect { 316 state detect {
315 state_entry() { 317 state_entry() {
316 // DEBUG 318 // DEBUG
317 llOwnerSay("Detecting if Corrade is online..."); 319 llOwnerSay("Detecting if Corrade is online...");
318 llSetTimerEvent(5); 320 llSetTimerEvent(5);
319 } 321 }
320 timer() { 322 timer() {
321 llRequestAgentData((key)CORRADE, DATA_ONLINE); 323 llRequestAgentData((key)CORRADE, DATA_ONLINE);
322 } 324 }
323 dataserver(key id, string data) { 325 dataserver(key id, string data) {
324 if(data != "1") { 326 if(data != "1") {
325 // DEBUG 327 // DEBUG
326 llOwnerSay("Corrade is not online, sleeping..."); 328 llOwnerSay("Corrade is not online, sleeping...");
327 llSetTimerEvent(30); 329 llSetTimerEvent(30);
328 return; 330 return;
329 } 331 }
330 state notify; 332 state notify;
331 } 333 }
332 on_rez(integer num) { 334 on_rez(integer num) {
333 llResetScript(); 335 llResetScript();
334 } 336 }
335 changed(integer change) { 337 changed(integer change) {
336 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 338 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
337 llResetScript(); 339 llResetScript();
338 } 340 }
339 } 341 }
340 } 342 }
341   343  
342 state notify { 344 state notify {
343 state_entry() { 345 state_entry() {
344 // DEBUG 346 // DEBUG
345 llOwnerSay("Binding to the collision notification..."); 347 llOwnerSay("Binding to the collision notification...");
346 llInstantMessage( 348 llInstantMessage(
347 (key)CORRADE, 349 CORRADE,
348 wasKeyValueEncode( 350 wasKeyValueEncode(
349 [ 351 [
350 "command", "notify", 352 "command", "notify",
351 "group", wasURLEscape(GROUP), 353 "group", wasURLEscape(GROUP),
352 "password", wasURLEscape(PASSWORD), 354 "password", wasURLEscape(PASSWORD),
353 "action", "set", 355 "action", "set",
354 "type", "collision", 356 "type", "collision",
355 "URL", wasURLEscape(callback), 357 "URL", wasURLEscape(callback),
356 "callback", wasURLEscape(callback) 358 "callback", wasURLEscape(callback)
357 ] 359 ]
358 ) 360 )
359 ); 361 );
360 } 362 }
361 http_request(key id, string method, string body) { 363 http_request(key id, string method, string body) {
362 llHTTPResponse(id, 200, "OK"); 364 llHTTPResponse(id, 200, "OK");
363 if(wasKeyValueGet("command", body) != "notify" || 365 if(wasKeyValueGet("command", body) != "notify" ||
364 wasKeyValueGet("success", body) != "True") { 366 wasKeyValueGet("success", body) != "True") {
365 // DEBUG 367 // DEBUG
366 llOwnerSay("Failed to bind to the collisioin notification..."); 368 llOwnerSay("Failed to bind to the collisioin notification...");
367 state detect; 369 state detect;
368 } 370 }
369 // DEBUG 371 // DEBUG
370 llOwnerSay("Collision notification installed..."); 372 llOwnerSay("Collision notification installed...");
371 state pause; 373 state pause;
372 } 374 }
373 on_rez(integer num) { 375 on_rez(integer num) {
374 llResetScript(); 376 llResetScript();
375 } 377 }
376 changed(integer change) { 378 changed(integer change) {
377 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 379 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
378 llResetScript(); 380 llResetScript();
379 } 381 }
380 } 382 }
381 } 383 }
382   384  
383 state pause { 385 state pause {
384 state_entry() { 386 state_entry() {
385 //DEBUG 387 //DEBUG
386 llOwnerSay("Pausing..."); 388 llOwnerSay("Pausing...");
387 // Check whether Corrade is still online first. 389 // Check whether Corrade is still online first.
388 llRequestAgentData((key)CORRADE, DATA_ONLINE); 390 llRequestAgentData((key)CORRADE, DATA_ONLINE);
389 } 391 }
390 dataserver(key id, string data) { 392 dataserver(key id, string data) {
391 if(data != "1") { 393 if(data != "1") {
392 // DEBUG 394 // DEBUG
393 llOwnerSay("Corrade is not online, sleeping..."); 395 llOwnerSay("Corrade is not online, sleeping...");
394 llSetTimerEvent(30); 396 llSetTimerEvent(30);
395 return; 397 return;
396 } 398 }
397 // Corrade is online, so schedule the next walk. 399 // Corrade is online, so schedule the next walk.
398 if(RANDOMIZE) { 400 if(RANDOMIZE) {
399 // The minimal trigger time for a timer event is ~0.045s 401 // The minimal trigger time for a timer event is ~0.045s
400 // This ensures we do not end up stuck in the pause state. 402 // This ensures we do not end up stuck in the pause state.
401 llSetTimerEvent(0.045 + llFrand(PAUSE - 0.045)); 403 llSetTimerEvent(0.045 + llFrand(PAUSE - 0.045));
402 return; 404 return;
403 } 405 }
404 llSetTimerEvent(PAUSE); 406 llSetTimerEvent(PAUSE);
405 } 407 }
406 timer() { 408 timer() {
407 llSetTimerEvent(0); 409 llSetTimerEvent(0);
408 state find; 410 state find;
409 } 411 }
410 } 412 }
411   413  
412 state find { 414 state find {
413 state_entry() { 415 state_entry() {
414 // We now query Corrade for its current position. 416 // We now query Corrade for its current position.
415 llInstantMessage(CORRADE, 417 llInstantMessage(CORRADE,
416 wasKeyValueEncode( 418 wasKeyValueEncode(
417 [ 419 [
418 "command", "getselfdata", 420 "command", "getselfdata",
419 "group", wasURLEscape(GROUP), 421 "group", wasURLEscape(GROUP),
420 "password", wasURLEscape(PASSWORD), 422 "password", wasURLEscape(PASSWORD),
421 "data", "SimPosition", 423 "data", "SimPosition",
422 "callback", wasURLEscape(callback) 424 "callback", wasURLEscape(callback)
423 ] 425 ]
424 ) 426 )
425 ); 427 );
426 // alarm 60 for Corrade not responding 428 // alarm 60 for Corrade not responding
427 llSetTimerEvent(60); 429 llSetTimerEvent(60);
428 } 430 }
429 timer() { 431 timer() {
430 llSetTimerEvent(0); 432 llSetTimerEvent(0);
431 // DEBUG 433 // DEBUG
432 llOwnerSay("Corrade not responding to data query..."); 434 llOwnerSay("Corrade not responding to data query...");
433 state pause; 435 state pause;
434 } 436 }
435 http_request(key id, string method, string body) { 437 http_request(key id, string method, string body) {
436 llHTTPResponse(id, 200, "OK"); 438 llHTTPResponse(id, 200, "OK");
437 list data = wasCSVToList( 439 list data = wasCSVToList(
438 wasKeyValueGet( 440 wasKeyValueGet(
439 "data", 441 "data",
440 wasURLUnescape(body) 442 wasURLUnescape(body)
441 ) 443 )
442 ); 444 );
443 origin= (vector)llList2String( 445 origin= (vector)llList2String(
444 data, 446 data,
445 llListFindList( 447 llListFindList(
446 data, 448 data,
447 (list)"SimPosition" 449 (list)"SimPosition"
448 )+1 450 )+1
449 ); 451 );
450 state walk; 452 state walk;
451 } 453 }
452 on_rez(integer num) { 454 on_rez(integer num) {
453 llResetScript(); 455 llResetScript();
454 } 456 }
455 changed(integer change) { 457 changed(integer change) {
456 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 458 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
457 llResetScript(); 459 llResetScript();
458 } 460 }
459 } 461 }
460 } 462 }
461   463  
462 state walk { 464 state walk {
463 state_entry() { 465 state_entry() {
464 // DEBUG 466 // DEBUG
465 llOwnerSay("Walking..."); 467 llOwnerSay("Walking...");
466 468
467 // extract next destination and permute the set 469 // extract next destination and permute the set
468 vector next = (vector)llList2String(PATH, 0); 470 vector next = (vector)llList2String(PATH, 0);
469 PATH = llDeleteSubList(PATH, 0, 0); 471 PATH = llDeleteSubList(PATH, 0, 0);
470 PATH += next; 472 PATH += next;
471 -  
472 llInstantMessage(CORRADE, -  
473 wasKeyValueEncode( -  
474 [ -  
475 "command", "autopilot", -  
476 "group", wasURLEscape(GROUP), -  
477 "password", wasURLEscape(PASSWORD), -  
478 "position", next, -  
479 "action", "start" -  
480 ] -  
481 ) -  
482 ); 473
483 // We now determine the waiting time for Corrade to reach 474 // We now determine the waiting time for Corrade to reach
484 // its next destination by extracting time as a function 475 // its next destination by extracting time as a function
485 // of the distance it has to walk and the speed of travel: 476 // of the distance it has to walk and the speed of travel:
486 // t = s / v 477 // t = s / v
487 // This, of course, is prone to error since the distance 478 // This, of course, is prone to error since the distance
488 // is calculated on the shortest direct path. Nevertheless, 479 // is calculated on the shortest direct path. Nevertheless,
489 // it is a pretty good appoximation for terrain that is 480 // it is a pretty good appoximation for terrain that is
490 // mostly flat and without too many curvatures. 481 // mostly flat and without too many curvatures.
491 // NB. 3.20 m/s is the walking speed of an avatar. 482 // NB. 3.20 m/s is the walking speed of an avatar.
-   483 llInstantMessage(CORRADE,
-   484 wasKeyValueEncode(
-   485 [
-   486 "command", "walkto",
-   487 "group", wasURLEscape(GROUP),
-   488 "password", wasURLEscape(PASSWORD),
-   489 "position", next,
-   490 "vicinity", "1",
-   491 "timeout", llVecDist(origin, next)/3.20
-   492 ]
-   493 )
-   494 );
-   495  
492 llSetTimerEvent(llVecDist(origin, next)/3.20); 496 llSetTimerEvent(llVecDist(origin, next)/3.20);
493 } 497 }
494 http_request(key id, string method, string body) { 498 http_request(key id, string method, string body) {
495 // since we have bound to the collision notification, 499 // since we have bound to the collision notification,
496 // this region of code deals with Corrade colliding 500 // this region of code deals with Corrade colliding
497 // with in-world assets; in which case, we stop 501 // with in-world assets; in which case, we stop
498 // moving to not seem awkward 502 // moving to not seem awkward
499 503
500 // DEBUG 504 // DEBUG
501 llOwnerSay("Collided..."); 505 llOwnerSay("Collided...");
502 506
503 llHTTPResponse(id, 200, "OK"); 507 llHTTPResponse(id, 200, "OK");
504 508  
505 llInstantMessage(CORRADE, -  
506 wasKeyValueEncode( -  
507 [ -  
508 "command", "autopilot", -  
509 "group", wasURLEscape(GROUP), -  
510 "password", wasURLEscape(PASSWORD), -  
511 "action", "stop" -  
512 ] -  
513 ) -  
514 ); -  
515 // We did not reach our destination since we collided with 509 // We did not reach our destination since we collided with
516 // something on our path, so switch directly to waiting and 510 // something on our path, so switch directly to waiting and
517 // attempt to reach the next destination on our path. 511 // attempt to reach the next destination on our path.
518 state pause; 512 state pause;
519 } 513 }
520 timer() { 514 timer() {
521 // We most likely reached our destination, so switch to pause. 515 // We most likely reached our destination, so switch to pause.
522 llSetTimerEvent(0); 516 llSetTimerEvent(0);
523 state pause; 517 state pause;
524 } 518 }
525 on_rez(integer num) { 519 on_rez(integer num) {
526 llResetScript(); 520 llResetScript();
527 } 521 }
528 changed(integer change) { 522 changed(integer change) {
529 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 523 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
530 llResetScript(); 524 llResetScript();
531 } 525 }
532 } 526 }
533 } 527 }
534   528  
535   529