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

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 5 Rev 29
1 /////////////////////////////////////////////////////////////////////////// 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 // 2 // Copyright (C) Wizardry and Steamworks 2016 - License: CC BY 2.0 //
3 /////////////////////////////////////////////////////////////////////////// 3 ///////////////////////////////////////////////////////////////////////////
4 // 4 //
5 // This project makes Corrade, the Second Life / OpenSim bot evade region 5 // This project makes Corrade, the Second Life / OpenSim bot evade region
6 // restarts by teleporting to other regions. More details about Corrade 6 // restarts by teleporting to other regions. More details about Corrade
7 // can be found at the URL: 7 // can be found at the URL:
8 // 8 //
9 // http://grimore.org/secondlife/scripted_agents/corrade 9 // http://grimore.org/secondlife/scripted_agents/corrade
10 // 10 //
11 // The script works in combination with a "configuration" notecard that 11 // The script works in combination with a "configuration" notecard that
12 // must be placed in the same primitive as this script. The purpose of this 12 // must be placed in the same primitive as this script. The purpose of this
13 // script is to illustrate how region restarts can be evaded with Corrade 13 // script is to illustrate how region restarts can be evaded with Corrade
14 // and you are free to use, change, and commercialize it under the terms 14 // and you are free to use, change, and commercialize it under the terms
15 // of the GNU/GPLv3 license at: http://www.gnu.org/licenses/gpl.html 15 // of the CC BY 2.0 license at: https://creativecommons.org/licenses/by/2.0
16 // 16 //
17 /////////////////////////////////////////////////////////////////////////// 17 ///////////////////////////////////////////////////////////////////////////
18   18  
19 /////////////////////////////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////////////////////////////
20 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 20 // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 //
21 /////////////////////////////////////////////////////////////////////////// 21 ///////////////////////////////////////////////////////////////////////////
22 string wasKeyValueGet(string k, string data) { 22 string wasKeyValueGet(string k, string data) {
23 if(llStringLength(data) == 0) return ""; 23 if(llStringLength(data) == 0) return "";
24 if(llStringLength(k) == 0) return ""; 24 if(llStringLength(k) == 0) return "";
25 list a = llParseString2List(data, ["&", "="], []); 25 list a = llParseString2List(data, ["&", "="], []);
26 integer i = llListFindList(a, [ k ]); 26 integer i = llListFindList(a, [ k ]);
27 if(i != -1) return llList2String(a, i+1); 27 if(i != -1) return llList2String(a, i+1);
28 return ""; 28 return "";
29 } 29 }
30 30
31 /////////////////////////////////////////////////////////////////////////// 31 ///////////////////////////////////////////////////////////////////////////
32 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // 32 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
33 /////////////////////////////////////////////////////////////////////////// 33 ///////////////////////////////////////////////////////////////////////////
34 string wasKeyValueEncode(list data) { 34 string wasKeyValueEncode(list data) {
35 list k = llList2ListStrided(data, 0, -1, 2); 35 list k = llList2ListStrided(data, 0, -1, 2);
36 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); 36 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
37 data = []; 37 data = [];
38 do { 38 do {
39 data += llList2String(k, 0) + "=" + llList2String(v, 0); 39 data += llList2String(k, 0) + "=" + llList2String(v, 0);
40 k = llDeleteSubList(k, 0, 0); 40 k = llDeleteSubList(k, 0, 0);
41 v = llDeleteSubList(v, 0, 0); 41 v = llDeleteSubList(v, 0, 0);
42 } while(llGetListLength(k) != 0); 42 } while(llGetListLength(k) != 0);
43 return llDumpList2String(data, "&"); 43 return llDumpList2String(data, "&");
44 } 44 }
45   45  
46 /////////////////////////////////////////////////////////////////////////// 46 ///////////////////////////////////////////////////////////////////////////
47 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 47 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
48 /////////////////////////////////////////////////////////////////////////// 48 ///////////////////////////////////////////////////////////////////////////
49 // escapes a string in conformance with RFC1738 49 // escapes a string in conformance with RFC1738
50 string wasURLEscape(string i) { 50 string wasURLEscape(string i) {
51 string o = ""; 51 string o = "";
52 do { 52 do {
53 string c = llGetSubString(i, 0, 0); 53 string c = llGetSubString(i, 0, 0);
54 i = llDeleteSubString(i, 0, 0); 54 i = llDeleteSubString(i, 0, 0);
55 if(c == "") jump continue; 55 if(c == "") jump continue;
56 if(c == " ") { 56 if(c == " ") {
57 o += "+"; 57 o += "+";
58 jump continue; 58 jump continue;
59 } 59 }
60 if(c == "\n") { 60 if(c == "\n") {
61 o += "%0D" + llEscapeURL(c); 61 o += "%0D" + llEscapeURL(c);
62 jump continue; 62 jump continue;
63 } 63 }
64 o += llEscapeURL(c); 64 o += llEscapeURL(c);
65 @continue; 65 @continue;
66 } while(i != ""); 66 } while(i != "");
67 return o; 67 return o;
68 } 68 }
69   69  
70 /////////////////////////////////////////////////////////////////////////// 70 ///////////////////////////////////////////////////////////////////////////
71 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 71 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
72 /////////////////////////////////////////////////////////////////////////// 72 ///////////////////////////////////////////////////////////////////////////
73 // unescapes a string in conformance with RFC1738 73 // unescapes a string in conformance with RFC1738
74 string wasURLUnescape(string i) { 74 string wasURLUnescape(string i) {
75 return llUnescapeURL( 75 return llUnescapeURL(
76 llDumpList2String( 76 llDumpList2String(
77 llParseString2List( 77 llParseString2List(
78 llDumpList2String( 78 llDumpList2String(
79 llParseString2List( 79 llParseString2List(
80 i, 80 i,
81 ["+"], 81 ["+"],
82 [] 82 []
83 ), 83 ),
84 " " 84 " "
85 ), 85 ),
86 ["%0D%0A"], 86 ["%0D%0A"],
87 [] 87 []
88 ), 88 ),
89 "\n" 89 "\n"
90 ) 90 )
91 ); 91 );
92 } 92 }
93   93  
94 /////////////////////////////////////////////////////////////////////////// 94 ///////////////////////////////////////////////////////////////////////////
95 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 95 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
96 /////////////////////////////////////////////////////////////////////////// 96 ///////////////////////////////////////////////////////////////////////////
97 list wasCSVToList(string csv) { 97 list wasCSVToList(string csv) {
98 list l = []; 98 list l = [];
99 list s = []; 99 list s = [];
100 string m = ""; 100 string m = "";
101 do { 101 do {
102 string a = llGetSubString(csv, 0, 0); 102 string a = llGetSubString(csv, 0, 0);
103 csv = llDeleteSubString(csv, 0, 0); 103 csv = llDeleteSubString(csv, 0, 0);
104 if(a == ",") { 104 if(a == ",") {
105 if(llList2String(s, -1) != "\"") { 105 if(llList2String(s, -1) != "\"") {
106 l += m; 106 l += m;
107 m = ""; 107 m = "";
108 jump continue; 108 jump continue;
109 } 109 }
110 m += a; 110 m += a;
111 jump continue; 111 jump continue;
112 } 112 }
113 if(a == "\"" && llGetSubString(csv, 0, 0) == a) { 113 if(a == "\"" && llGetSubString(csv, 0, 0) == a) {
114 m += a; 114 m += a;
115 csv = llDeleteSubString(csv, 0, 0); 115 csv = llDeleteSubString(csv, 0, 0);
116 jump continue; 116 jump continue;
117 } 117 }
118 if(a == "\"") { 118 if(a == "\"") {
119 if(llList2String(s, -1) != a) { 119 if(llList2String(s, -1) != a) {
120 s += a; 120 s += a;
121 jump continue; 121 jump continue;
122 } 122 }
123 s = llDeleteSubList(s, -1, -1); 123 s = llDeleteSubList(s, -1, -1);
124 jump continue; 124 jump continue;
125 } 125 }
126 m += a; 126 m += a;
127 @continue; 127 @continue;
128 } while(csv != ""); 128 } while(csv != "");
129 // postcondition: length(s) = 0 129 // postcondition: length(s) = 0
130 return l + m; 130 return l + m;
131 } 131 }
132   132  
133 // corrade data 133 // corrade data
134 key CORRADE = NULL_KEY; 134 key CORRADE = NULL_KEY;
135 string GROUP = ""; 135 string GROUP = "";
136 string PASSWORD = ""; 136 string PASSWORD = "";
137   137  
138 // hold all the escape regions 138 // hold all the escape regions
139 list REGIONS = []; 139 list REGIONS = [];
140 // the home region name 140 // the home region name
141 string HOME_REGION = ""; 141 string HOME_REGION = "";
142 vector HOME_POSITION = ZERO_VECTOR; 142 vector HOME_POSITION = ZERO_VECTOR;
143 // holds the restat delay dynamically 143 // holds the restat delay dynamically
144 integer RESTART_DELAY = 0; 144 integer RESTART_DELAY = 0;
145   145  
146 // for holding the callback URL 146 // for holding the callback URL
147 string callback = ""; 147 string callback = "";
148   148  
149 // for notecard reading 149 // for notecard reading
150 integer line = 0; 150 integer line = 0;
151 151
152 // key-value data will be read into this list 152 // key-value data will be read into this list
153 list tuples = []; 153 list tuples = [];
154   154  
155 // jump label 155 // jump label
156 string setjmp = ""; 156 string setjmp = "";
157   157  
158 default { 158 default {
159 state_entry() { 159 state_entry() {
160 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { 160 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
161 llOwnerSay("Sorry, could not find a configuration inventory notecard."); 161 llOwnerSay("Sorry, could not find a configuration inventory notecard.");
162 return; 162 return;
163 } 163 }
164 // DEBUG 164 // DEBUG
165 llOwnerSay("Reading configuration file..."); 165 llOwnerSay("Reading configuration file...");
166 llGetNotecardLine("configuration", line); 166 llGetNotecardLine("configuration", line);
167 } 167 }
168 dataserver(key id, string data) { 168 dataserver(key id, string data) {
169 if(data == EOF) { 169 if(data == EOF) {
170 // invariant, length(tuples) % 2 == 0 170 // invariant, length(tuples) % 2 == 0
171 if(llGetListLength(tuples) % 2 != 0) { 171 if(llGetListLength(tuples) % 2 != 0) {
172 llOwnerSay("Error in configuration notecard."); 172 llOwnerSay("Error in configuration notecard.");
173 return; 173 return;
174 } 174 }
175 CORRADE = llList2Key( 175 CORRADE = llList2Key(
176 tuples, 176 tuples,
177 llListFindList( 177 llListFindList(
178 tuples, 178 tuples,
179 [ 179 [
180 "corrade" 180 "corrade"
181 ] 181 ]
182 ) 182 )
183 +1 183 +1
184 ); 184 );
185 if(CORRADE == NULL_KEY) { 185 if(CORRADE == NULL_KEY) {
186 llOwnerSay("Error in configuration notecard: corrade"); 186 llOwnerSay("Error in configuration notecard: corrade");
187 return; 187 return;
188 } 188 }
189 GROUP = llList2String( 189 GROUP = llList2String(
190 tuples, 190 tuples,
191 llListFindList( 191 llListFindList(
192 tuples, 192 tuples,
193 [ 193 [
194 "group" 194 "group"
195 ] 195 ]
196 ) 196 )
197 +1 197 +1
198 ); 198 );
199 if(GROUP == "") { 199 if(GROUP == "") {
200 llOwnerSay("Error in configuration notecard: group"); 200 llOwnerSay("Error in configuration notecard: group");
201 return; 201 return;
202 } 202 }
203 PASSWORD = llList2String( 203 PASSWORD = llList2String(
204 tuples, 204 tuples,
205 llListFindList( 205 llListFindList(
206 tuples, 206 tuples,
207 [ 207 [
208 "password" 208 "password"
209 ] 209 ]
210 ) 210 )
211 +1 211 +1
212 ); 212 );
213 if(PASSWORD == "") { 213 if(PASSWORD == "") {
214 llOwnerSay("Error in configuration notecard: password"); 214 llOwnerSay("Error in configuration notecard: password");
215 return; 215 return;
216 } 216 }
217 REGIONS = wasCSVToList( 217 REGIONS = wasCSVToList(
218 llList2String( 218 llList2String(
219 tuples, 219 tuples,
220 llListFindList( 220 llListFindList(
221 tuples, 221 tuples,
222 [ 222 [
223 "regions" 223 "regions"
224 ] 224 ]
225 ) 225 )
226 +1 226 +1
227 ) 227 )
228 ); 228 );
229 if(REGIONS == []) { 229 if(REGIONS == []) {
230 llOwnerSay("Error in configuration notecard: regions"); 230 llOwnerSay("Error in configuration notecard: regions");
231 return; 231 return;
232 } 232 }
233 HOME_REGION = llList2String( 233 HOME_REGION = llList2String(
234 tuples, 234 tuples,
235 llListFindList( 235 llListFindList(
236 tuples, 236 tuples,
237 [ 237 [
238 "home" 238 "home"
239 ] 239 ]
240 ) 240 )
241 +1 241 +1
242 ); 242 );
243 if(HOME_REGION == "") { 243 if(HOME_REGION == "") {
244 llOwnerSay("Error in configuration notecard: home"); 244 llOwnerSay("Error in configuration notecard: home");
245 return; 245 return;
246 } 246 }
247 HOME_POSITION = (vector)llList2String( 247 HOME_POSITION = (vector)llList2String(
248 tuples, 248 tuples,
249 llListFindList( 249 llListFindList(
250 tuples, 250 tuples,
251 [ 251 [
252 "position" 252 "position"
253 ] 253 ]
254 ) 254 )
255 +1 255 +1
256 ); 256 );
257 if(HOME_POSITION == ZERO_VECTOR) { 257 if(HOME_POSITION == ZERO_VECTOR) {
258 llOwnerSay("Error in configuration notecard: position"); 258 llOwnerSay("Error in configuration notecard: position");
259 return; 259 return;
260 } 260 }
261 // DEBUG 261 // DEBUG
262 llOwnerSay("Read configuration notecard..."); 262 llOwnerSay("Read configuration notecard...");
263 263
264 // The notecard has been read, so get and URL and switch into detect. 264 // The notecard has been read, so get and URL and switch into detect.
265 setjmp = "detect"; 265 setjmp = "detect";
266 state url; 266 state url;
267 } 267 }
268 if(data == "") jump continue; 268 if(data == "") jump continue;
269 integer i = llSubStringIndex(data, "#"); 269 integer i = llSubStringIndex(data, "#");
270 if(i != -1) data = llDeleteSubString(data, i, -1); 270 if(i != -1) data = llDeleteSubString(data, i, -1);
271 list o = llParseString2List(data, ["="], []); 271 list o = llParseString2List(data, ["="], []);
272 // get rid of starting and ending quotes 272 // get rid of starting and ending quotes
273 string k = llDumpList2String( 273 string k = llDumpList2String(
274 llParseString2List( 274 llParseString2List(
275 llStringTrim( 275 llStringTrim(
276 llList2String( 276 llList2String(
277 o, 277 o,
278 0 278 0
279 ), 279 ),
280 STRING_TRIM), 280 STRING_TRIM),
281 ["\""], [] 281 ["\""], []
282 ), "\""); 282 ), "\"");
283 string v = llDumpList2String( 283 string v = llDumpList2String(
284 llParseString2List( 284 llParseString2List(
285 llStringTrim( 285 llStringTrim(
286 llList2String( 286 llList2String(
287 o, 287 o,
288 1 288 1
289 ), 289 ),
290 STRING_TRIM), 290 STRING_TRIM),
291 ["\""], [] 291 ["\""], []
292 ), "\""); 292 ), "\"");
293 if(k == "" || v == "") jump continue; 293 if(k == "" || v == "") jump continue;
294 tuples += k; 294 tuples += k;
295 tuples += v; 295 tuples += v;
296 @continue; 296 @continue;
297 llGetNotecardLine("configuration", ++line); 297 llGetNotecardLine("configuration", ++line);
298 } 298 }
299 on_rez(integer num) { 299 on_rez(integer num) {
300 llResetScript(); 300 llResetScript();
301 } 301 }
302 changed(integer change) { 302 changed(integer change) {
303 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 303 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
304 llResetScript(); 304 llResetScript();
305 } 305 }
306 } 306 }
307 } 307 }
308   308  
309 state url { 309 state url {
310 state_entry() { 310 state_entry() {
311 // DEBUG 311 // DEBUG
312 llOwnerSay("Requesting URL..."); 312 llOwnerSay("Requesting URL...");
313 llRequestURL(); 313 llRequestURL();
314 } 314 }
315 http_request(key id, string method, string body) { 315 http_request(key id, string method, string body) {
316 if(method != URL_REQUEST_GRANTED) return; 316 if(method != URL_REQUEST_GRANTED) return;
317 callback = body; 317 callback = body;
318 318
319 // DEBUG 319 // DEBUG
320 llOwnerSay("Got URL..."); 320 llOwnerSay("Got URL...");
321 321
322 // Jump table 322 // Jump table
323 if(setjmp == "detect") state detect; 323 if(setjmp == "detect") state detect;
324 if(setjmp == "recall") state recall; 324 if(setjmp == "recall") state recall;
325 325
326 // Here be HALT. 326 // Here be HALT.
327 llResetScript(); 327 llResetScript();
328 } 328 }
329 on_rez(integer num) { 329 on_rez(integer num) {
330 llResetScript(); 330 llResetScript();
331 } 331 }
332 changed(integer change) { 332 changed(integer change) {
333 if((change & CHANGED_INVENTORY)) { 333 if((change & CHANGED_INVENTORY)) {
334 llResetScript(); 334 llResetScript();
335 } 335 }
336 } 336 }
337 } 337 }
338 338
339 state detect { 339 state detect {
340 state_entry() { 340 state_entry() {
341 // DEBUG 341 // DEBUG
342 llOwnerSay("Detecting if Corrade is online..."); 342 llOwnerSay("Detecting if Corrade is online...");
343 llSetTimerEvent(5); 343 llSetTimerEvent(5);
344 } 344 }
345 timer() { 345 timer() {
346 llRequestAgentData((key)CORRADE, DATA_ONLINE); 346 llRequestAgentData((key)CORRADE, DATA_ONLINE);
347 } 347 }
348 dataserver(key id, string data) { 348 dataserver(key id, string data) {
349 if(data != "1") { 349 if(data != "1") {
350 // DEBUG 350 // DEBUG
351 llOwnerSay("Corrade is not online, sleeping..."); 351 llOwnerSay("Corrade is not online, sleeping...");
352 llSetTimerEvent(30); 352 llSetTimerEvent(30);
353 return; 353 return;
354 } 354 }
355 state notify; 355 state notify;
356 } 356 }
357 on_rez(integer num) { 357 on_rez(integer num) {
358 llResetScript(); 358 llResetScript();
359 } 359 }
360 changed(integer change) { 360 changed(integer change) {
361 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 361 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
362 llResetScript(); 362 llResetScript();
363 } 363 }
364 } 364 }
365 } 365 }
366 366
367 state notify { 367 state notify {
368 state_entry() { 368 state_entry() {
369 // DEBUG 369 // DEBUG
370 llOwnerSay("Binding to the alert notification..."); 370 llOwnerSay("Binding to the alert notification...");
371 llInstantMessage( 371 llInstantMessage(
372 (key)CORRADE, 372 (key)CORRADE,
373 wasKeyValueEncode( 373 wasKeyValueEncode(
374 [ 374 [
375 "command", "notify", 375 "command", "notify",
376 "group", wasURLEscape(GROUP), 376 "group", wasURLEscape(GROUP),
377 "password", wasURLEscape(PASSWORD), 377 "password", wasURLEscape(PASSWORD),
378 "action", "set", 378 "action", "set",
379 "type", "alert", 379 "type", "alert",
380 "URL", wasURLEscape(callback), 380 "URL", wasURLEscape(callback),
381 "callback", wasURLEscape(callback) 381 "callback", wasURLEscape(callback)
382 ] 382 ]
383 ) 383 )
384 ); 384 );
385 } 385 }
386 http_request(key id, string method, string body) { 386 http_request(key id, string method, string body) {
387 llHTTPResponse(id, 200, "OK"); 387 llHTTPResponse(id, 200, "OK");
388 if(wasKeyValueGet("command", body) != "notify") return; 388 if(wasKeyValueGet("command", body) != "notify") return;
389 if(wasKeyValueGet("success", body) != "True") { 389 if(wasKeyValueGet("success", body) != "True") {
390 // DEBUG 390 // DEBUG
391 llOwnerSay("Failed to bind to the alert notification..."); 391 llOwnerSay("Failed to bind to the alert notification...");
392 state sense; 392 state sense;
393 } 393 }
394 // DEBUG 394 // DEBUG
395 llOwnerSay("Alert notification installed..."); 395 llOwnerSay("Alert notification installed...");
396 state sense; 396 state sense;
397 } 397 }
398 on_rez(integer num) { 398 on_rez(integer num) {
399 llResetScript(); 399 llResetScript();
400 } 400 }
401 changed(integer change) { 401 changed(integer change) {
402 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 402 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
403 llResetScript(); 403 llResetScript();
404 } 404 }
405 } 405 }
406 } 406 }
407   407  
408 state sense { 408 state sense {
409 state_entry() { 409 state_entry() {
410 // DEBUG 410 // DEBUG
411 llOwnerSay("Waiting for alert messages for region restarts..."); 411 llOwnerSay("Waiting for alert messages for region restarts...");
412 } 412 }
413 timer() { 413 timer() {
414 llRequestAgentData((key)CORRADE, DATA_ONLINE); 414 llRequestAgentData((key)CORRADE, DATA_ONLINE);
415 } 415 }
416 dataserver(key id, string data) { 416 dataserver(key id, string data) {
417 if(data == "1") return; 417 if(data == "1") return;
418 // DEBUG 418 // DEBUG
419 llOwnerSay("Corrade is not online, sleeping..."); 419 llOwnerSay("Corrade is not online, sleeping...");
420 // Switch to detect loop and wait there for Corrade to come online. 420 // Switch to detect loop and wait there for Corrade to come online.
421 state detect; 421 state detect;
422 } 422 }
423 http_request(key id, string method, string body) { 423 http_request(key id, string method, string body) {
424 llHTTPResponse(id, 200, "OK"); 424 llHTTPResponse(id, 200, "OK");
425 // Get the number of minutes after which the region will go down. 425 // Get the number of minutes after which the region will go down.
426 RESTART_DELAY = llList2Integer( 426 RESTART_DELAY = llList2Integer(
427 llParseString2List( 427 llParseString2List(
428 wasURLUnescape( 428 wasURLUnescape(
429 wasKeyValueGet( 429 wasKeyValueGet(
430 "message", 430 "message",
431 body 431 body
432 ) 432 )
433 ), 433 ),
434 [ 434 [
435 " will restart in ", 435 " will restart in ",
436 " minutes." 436 " minutes."
437 ], 437 ],
438 [] 438 []
439 ), 439 ),
440 1 440 1
441 ); 441 );
442 442
443 if(RESTART_DELAY == 0) return; 443 if(RESTART_DELAY == 0) return;
444   444  
445 // DEBUG 445 // DEBUG
446 llOwnerSay("Attempting to evade region restart..."); 446 llOwnerSay("Attempting to evade region restart...");
447   447  
448 // Evade! 448 // Evade!
449 state evade; 449 state evade;
450 } 450 }
451 on_rez(integer num) { 451 on_rez(integer num) {
452 llResetScript(); 452 llResetScript();
453 } 453 }
454 changed(integer change) { 454 changed(integer change) {
455 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 455 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
456 llResetScript(); 456 llResetScript();
457 } 457 }
458 } 458 }
459 } 459 }
460   460  
461 state evade_trampoline { 461 state evade_trampoline {
462 state_entry() { 462 state_entry() {
463 state evade; 463 state evade;
464 } 464 }
465 } 465 }
466   466  
467 state evade { 467 state evade {
468 state_entry() { 468 state_entry() {
469 // DEBUG 469 // DEBUG
470 llOwnerSay("Teleporting Corrade out of the region..."); 470 llOwnerSay("Teleporting Corrade out of the region...");
471 // Alarm 60 471 // Alarm 60
472 llSetTimerEvent(60); 472 llSetTimerEvent(60);
473 // Shuffle regions. 473 // Shuffle regions.
474 string region = llList2String(REGIONS, 0); 474 string region = llList2String(REGIONS, 0);
475 REGIONS = llDeleteSubList(REGIONS, 0, 0); 475 REGIONS = llDeleteSubList(REGIONS, 0, 0);
476 REGIONS += region; 476 REGIONS += region;
477 llInstantMessage( 477 llInstantMessage(
478 (key)CORRADE, wasKeyValueEncode( 478 (key)CORRADE, wasKeyValueEncode(
479 [ 479 [
480 "command", "teleport", 480 "command", "teleport",
481 "group", wasURLEscape(GROUP), 481 "group", wasURLEscape(GROUP),
482 "password", wasURLEscape(PASSWORD), 482 "password", wasURLEscape(PASSWORD),
483 "entity", "region", 483 "entity", "region",
484 "region", wasURLEscape(region), 484 "region", wasURLEscape(region),
485 "callback", wasURLEscape(callback) 485 "callback", wasURLEscape(callback)
486 ] 486 ]
487 ) 487 )
488 ); 488 );
489 } 489 }
490 timer() { 490 timer() {
491 state evade_trampoline; 491 state evade_trampoline;
492 } 492 }
493 http_request(key id, string method, string body) { 493 http_request(key id, string method, string body) {
494 llHTTPResponse(id, 200, "OK"); 494 llHTTPResponse(id, 200, "OK");
495 // This message was most likely not for us. 495 // This message was most likely not for us.
496 if(wasKeyValueGet("command", body) 496 if(wasKeyValueGet("command", body)
497 != "teleport") return; 497 != "teleport") return;
498 if(wasKeyValueGet("success", body) != "True") { 498 if(wasKeyValueGet("success", body) != "True") {
499 // DEBUG 499 // DEBUG
500 llOwnerSay("Failed teleport, retrying..."); 500 llOwnerSay("Failed teleport, retrying...");
501 state evade_trampoline; 501 state evade_trampoline;
502 } 502 }
503 503
504 // DEBUG 504 // DEBUG
505 llOwnerSay("Corrade evaded region restart..."); 505 llOwnerSay("Corrade evaded region restart...");
506 506
507 state confront; 507 state confront;
508 } 508 }
509 on_rez(integer num) { 509 on_rez(integer num) {
510 llResetScript(); 510 llResetScript();
511 } 511 }
512 changed(integer change) { 512 changed(integer change) {
513 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 513 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
514 llResetScript(); 514 llResetScript();
515 } 515 }
516 } 516 }
517 state_exit() { 517 state_exit() {
518 llSetTimerEvent(0); 518 llSetTimerEvent(0);
519 } 519 }
520 } 520 }
521   521  
522 /* 522 /*
523 * This state is suspended for the duration of the simulator downtime. 523 * This state is suspended for the duration of the simulator downtime.
524 * Effects: 524 * Effects:
525 * - callback URL is lost 525 * - callback URL is lost
526 * - timer is resumed 526 * - timer is resumed
527 * - CHANGED_REGION_RESTART raised 527 * - CHANGED_REGION_RESTART raised
528 */ 528 */
529 state confront { 529 state confront {
530 state_entry() { 530 state_entry() {
531 // Marty! The future is in the past. 531 // Marty! The future is in the past.
532 // The past is in the future! - Doc Brown, Back To The Future 532 // The past is in the future! - Doc Brown, Back To The Future
533 // 533 //
534 // Schedule an event after the scheduled restart delay 534 // Schedule an event after the scheduled restart delay
535 // sent to the region plus some convenience offset (60s). 535 // sent to the region plus some convenience offset (60s).
536 // 536 //
537 // Even if the region is not back up after the restart 537 // Even if the region is not back up after the restart
538 // delay and the convenience offset, the script will not 538 // delay and the convenience offset, the script will not
539 // be running anyway since the sim will be offline and 539 // be running anyway since the sim will be offline and
540 // will be suspended. 540 // will be suspended.
541 // 541 //
542 // Instead, when the region is back up, the timer will 542 // Instead, when the region is back up, the timer will
543 // resume and the script will eventually raise the event. 543 // resume and the script will eventually raise the event.
544 llSetTimerEvent(RESTART_DELAY * 60 + 60); 544 llSetTimerEvent(RESTART_DELAY * 60 + 60);
545 } 545 }
546 timer() { 546 timer() {
547 // Ok, either the region has restarted or the event was raised. 547 // Ok, either the region has restarted or the event was raised.
548 // 548 //
549 // Refresh the URL and then recall. 549 // Refresh the URL and then recall.
550 setjmp = "recall"; 550 setjmp = "recall";
551 state url; 551 state url;
552 } 552 }
553 on_rez(integer num) { 553 on_rez(integer num) {
554 llResetScript(); 554 llResetScript();
555 } 555 }
556 changed(integer change) { 556 changed(integer change) {
557 if(change & CHANGED_INVENTORY) { 557 if(change & CHANGED_INVENTORY) {
558 llResetScript(); 558 llResetScript();
559 } 559 }
560 } 560 }
561 state_exit() { 561 state_exit() {
562 llSetTimerEvent(0); 562 llSetTimerEvent(0);
563 } 563 }
564 } 564 }
565   565  
566 state recall_trampoline { 566 state recall_trampoline {
567 state_entry() { 567 state_entry() {
568 state recall; 568 state recall;
569 } 569 }
570 } 570 }
571   571  
572 state recall { 572 state recall {
573 state_entry() { 573 state_entry() {
574 // DEBUG 574 // DEBUG
575 llOwnerSay("Teleporting Corrade back to the home region..."); 575 llOwnerSay("Teleporting Corrade back to the home region...");
576 // Alarm 60 576 // Alarm 60
577 llSetTimerEvent(60); 577 llSetTimerEvent(60);
578 llInstantMessage( 578 llInstantMessage(
579 (key)CORRADE, wasKeyValueEncode( 579 (key)CORRADE, wasKeyValueEncode(
580 [ 580 [
581 "command", "teleport", 581 "command", "teleport",
582 "group", wasURLEscape(GROUP), 582 "group", wasURLEscape(GROUP),
583 "password", wasURLEscape(PASSWORD), 583 "password", wasURLEscape(PASSWORD),
584 "entity", "region", 584 "entity", "region",
585 "region", wasURLEscape(HOME_REGION), 585 "region", wasURLEscape(HOME_REGION),
586 "position", wasURLEscape((string)HOME_POSITION), 586 "position", wasURLEscape((string)HOME_POSITION),
587 "callback", wasURLEscape(callback) 587 "callback", wasURLEscape(callback)
588 ] 588 ]
589 ) 589 )
590 ); 590 );
591 } 591 }
592 timer() { 592 timer() {
593 state recall_trampoline; 593 state recall_trampoline;
594 } 594 }
595 http_request(key id, string method, string body) { 595 http_request(key id, string method, string body) {
596 llHTTPResponse(id, 200, "OK"); 596 llHTTPResponse(id, 200, "OK");
597 // This message was most likely not for us. 597 // This message was most likely not for us.
598 if(wasKeyValueGet("command", body) 598 if(wasKeyValueGet("command", body)
599 != "teleport") return; 599 != "teleport") return;
600 if(wasKeyValueGet("success", body) != "True") { 600 if(wasKeyValueGet("success", body) != "True") {
601 // DEBUG 601 // DEBUG
602 llOwnerSay("Failed teleport, retrying..."); 602 llOwnerSay("Failed teleport, retrying...");
603 state recall_trampoline; 603 state recall_trampoline;
604 } 604 }
605 605
606 // DEBUG 606 // DEBUG
607 llOwnerSay("Corrade teleported to home region..."); 607 llOwnerSay("Corrade teleported to home region...");
608 608
609 // We are back to the home region now. 609 // We are back to the home region now.
610 state detect; 610 state detect;
611 } 611 }
612 on_rez(integer num) { 612 on_rez(integer num) {
613 llResetScript(); 613 llResetScript();
614 } 614 }
615 changed(integer change) { 615 changed(integer change) {
616 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 616 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
617 llResetScript(); 617 llResetScript();
618 } 618 }
619 } 619 }
620 state_exit() { 620 state_exit() {
621 llSetTimerEvent(0); 621 llSetTimerEvent(0);
622 } 622 }
623 } 623 }
624   624