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

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 37 Rev 38
1 /////////////////////////////////////////////////////////////////////////// 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 2 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
3 /////////////////////////////////////////////////////////////////////////// 3 ///////////////////////////////////////////////////////////////////////////
4 // -  
5 // This is an automatic grid follower for the Corrade Second Life / OpenSim -  
6 // bot. You can find more details about the bot by following the URL: -  
7 // http://was.fm/secondlife/scripted_agents/corrade -  
8 // -  
9 // The follower script works together with a "configuration" notecard and -  
10 // that must be placed in the same primitive as this script. -  
11 // You are free to use, change, and commercialize it under the GNU/GPLv3 -  
12 // license at: http://www.gnu.org/licenses/gpl.html -  
13 // -  
14 /////////////////////////////////////////////////////////////////////////// -  
15   4  
16 /////////////////////////////////////////////////////////////////////////// 5 ///////////////////////////////////////////////////////////////////////////
17 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 6 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
18 /////////////////////////////////////////////////////////////////////////// 7 ///////////////////////////////////////////////////////////////////////////
19 string wasKeyValueGet(string k, string data) { 8 string wasKeyValueGet(string k, string data) {
20 if(llStringLength(data) == 0) return ""; 9 if(llStringLength(data) == 0) return "";
21 if(llStringLength(k) == 0) return ""; 10 if(llStringLength(k) == 0) return "";
22 list a = llParseString2List(data, ["&", "="], []); 11 list a = llParseStringKeepNulls(data, ["&", "="], []);
23 integer i = llListFindList(a, [ k ]); 12 integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
24 if(i != -1) return llList2String(a, i+1); 13 if(i != -1) return llList2String(a, 2*i+1);
25 return ""; 14 return "";
26 } 15 }
27 16  
28 /////////////////////////////////////////////////////////////////////////// 17 ///////////////////////////////////////////////////////////////////////////
29 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // 18 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
30 /////////////////////////////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////////////////////////////
31 string wasKeyValueEncode(list data) { 20 string wasKeyValueEncode(list data) {
32 list k = llList2ListStrided(data, 0, -1, 2); 21 list k = llList2ListStrided(data, 0, -1, 2);
33 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); 22 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
34 data = []; 23 data = [];
35 do { 24 do {
36 data += llList2String(k, 0) + "=" + llList2String(v, 0); 25 data += llList2String(k, 0) + "=" + llList2String(v, 0);
37 k = llDeleteSubList(k, 0, 0); 26 k = llDeleteSubList(k, 0, 0);
38 v = llDeleteSubList(v, 0, 0); 27 v = llDeleteSubList(v, 0, 0);
39 } while(llGetListLength(k) != 0); 28 } while(llGetListLength(k) != 0);
40 return llDumpList2String(data, "&"); 29 return llDumpList2String(data, "&");
41 } 30 }
42   31  
43 /////////////////////////////////////////////////////////////////////////// 32 ///////////////////////////////////////////////////////////////////////////
44 // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 // 33 // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 //
45 /////////////////////////////////////////////////////////////////////////// 34 ///////////////////////////////////////////////////////////////////////////
46 vector wasCirclePoint(float radius) { 35 vector wasCirclePoint(float radius) {
47 float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); 36 float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
48 float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); 37 float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
49 if(llPow(x,2) + llPow(y,2) <= llPow(radius,2)) 38 if(llPow(x,2) + llPow(y,2) <= llPow(radius,2))
50 return <x, y, 0>; 39 return <x, y, 0>;
51 return wasCirclePoint(radius); 40 return wasCirclePoint(radius);
52 } 41 }
53   42  
54 /////////////////////////////////////////////////////////////////////////// 43 ///////////////////////////////////////////////////////////////////////////
55 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 44 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
56 /////////////////////////////////////////////////////////////////////////// 45 ///////////////////////////////////////////////////////////////////////////
57 integer wasIsAvatarInSensorRange(key avatar) { 46 integer wasIsAvatarInSensorRange(key avatar) {
58 return llListFindList( 47 return llListFindList(
59 llGetAgentList( 48 llGetAgentList(
60 AGENT_LIST_REGION, 49 AGENT_LIST_REGION,
61 [] 50 []
62 ), 51 ),
63 (list)((key)avatar) 52 (list)((key)avatar)
64 ) != -1 && 53 ) != -1 &&
65 llVecDist( 54 llVecDist(
66 llGetPos(), 55 llGetPos(),
67 llList2Vector( 56 llList2Vector(
68 llGetObjectDetails( 57 llGetObjectDetails(
69 avatar, 58 avatar,
70 [OBJECT_POS] 59 [OBJECT_POS]
71 ), 60 ),
72 0 61 0
73 ) 62 )
74 ) <= 96; 63 ) <= 96;
75 } 64 }
76   65  
77 /////////////////////////////////////////////////////////////////////////// 66 ///////////////////////////////////////////////////////////////////////////
78 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 67 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
79 /////////////////////////////////////////////////////////////////////////// 68 ///////////////////////////////////////////////////////////////////////////
80 // escapes a string in conformance with RFC1738 69 // escapes a string in conformance with RFC1738
81 string wasURLEscape(string i) { 70 string wasURLEscape(string i) {
82 string o = ""; 71 string o = "";
83 do { 72 do {
84 string c = llGetSubString(i, 0, 0); 73 string c = llGetSubString(i, 0, 0);
85 i = llDeleteSubString(i, 0, 0); 74 i = llDeleteSubString(i, 0, 0);
86 if(c == "") jump continue; 75 if(c == "") jump continue;
87 if(c == " ") { 76 if(c == " ") {
88 o += "+"; 77 o += "+";
89 jump continue; 78 jump continue;
90 } 79 }
91 if(c == "\n") { 80 if(c == "\n") {
92 o += "%0D" + llEscapeURL(c); 81 o += "%0D" + llEscapeURL(c);
93 jump continue; 82 jump continue;
94 } 83 }
95 o += llEscapeURL(c); 84 o += llEscapeURL(c);
96 @continue; 85 @continue;
97 } while(i != ""); 86 } while(i != "");
98 return o; 87 return o;
99 } 88 }
100   89  
101 // corrade data 90 // corrade data
102 string CORRADE = ""; 91 string CORRADE = "";
103 string GROUP = ""; 92 string GROUP = "";
104 string PASSWORD = ""; 93 string PASSWORD = "";
105 string RANGE = ""; 94 integer RANGE = 5;
106   95  
107 // for holding the callback URL 96 // for holding the callback URL
108 string callback = ""; 97 string callback = "";
109   98  
110 // for notecard reading 99 // for notecard reading
111 integer line = 0; 100 integer line = 0;
112 101  
113 // key-value data will be read into this list 102 // key-value data will be read into this list
114 list tuples = []; 103 list tuples = [];
115 104  
116 default { 105 default {
117 state_entry() { 106 state_entry() {
118 // set color for button 107 // set color for button
119 llSetColor(<1,1,0>, ALL_SIDES); 108 llSetColor(<1,1,0>, ALL_SIDES);
120 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { 109 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
121 llOwnerSay("Sorry, could not find an inventory notecard."); 110 llOwnerSay("Sorry, could not find an inventory notecard.");
122 return; 111 return;
123 } 112 }
124 // DEBUG 113 // DEBUG
125 llOwnerSay("Reading configuration file..."); 114 llOwnerSay("Reading configuration file...");
126 llGetNotecardLine("configuration", line); 115 llGetNotecardLine("configuration", line);
127 } 116 }
128 dataserver(key id, string data) { 117 dataserver(key id, string data) {
129 if(data == EOF) { 118 if(data == EOF) {
130 // invariant, length(tuples) % 2 == 0 119 // invariant, length(tuples) % 2 == 0
131 if(llGetListLength(tuples) % 2 != 0) { 120 if(llGetListLength(tuples) % 2 != 0) {
132 llOwnerSay("Error in configuration notecard."); 121 llOwnerSay("Error in configuration notecard.");
133 return; 122 return;
134 } 123 }
135 CORRADE = llList2String( 124 CORRADE = llList2String(
136 tuples, 125 tuples,
137 llListFindList( 126 llListFindList(
138 tuples, 127 tuples,
139 [ 128 [
140 "corrade" 129 "corrade"
141 ] 130 ]
142 ) 131 )
143 +1); 132 +1);
144 if(CORRADE == "") { 133 if(CORRADE == "") {
145 llOwnerSay("Error in configuration notecard: corrade"); 134 llOwnerSay("Error in configuration notecard: corrade");
146 return; 135 return;
147 } 136 }
148 GROUP = llList2String( 137 GROUP = llList2String(
149 tuples, 138 tuples,
150 llListFindList( 139 llListFindList(
151 tuples, 140 tuples,
152 [ 141 [
153 "group" 142 "group"
154 ] 143 ]
155 ) 144 )
156 +1); 145 +1);
157 if(GROUP == "") { 146 if(GROUP == "") {
158 llOwnerSay("Error in configuration notecard: password"); 147 llOwnerSay("Error in configuration notecard: password");
159 return; 148 return;
160 } 149 }
161 PASSWORD = llList2String( 150 PASSWORD = llList2String(
162 tuples, 151 tuples,
163 llListFindList( 152 llListFindList(
164 tuples, 153 tuples,
165 [ 154 [
166 "password" 155 "password"
167 ] 156 ]
168 ) 157 )
169 +1); 158 +1);
170 if(GROUP == "") { 159 if(GROUP == "") {
171 llOwnerSay("Error in configuration notecard: group"); 160 llOwnerSay("Error in configuration notecard: group");
172 return; 161 return;
173 } 162 }
174 RANGE = llList2String( 163 RANGE = llList2Integer(
175 tuples, 164 tuples,
176 llListFindList( 165 llListFindList(
177 tuples, 166 tuples,
178 [ 167 [
179 "range" 168 "range"
180 ] 169 ]
181 ) 170 )
182 +1); 171 +1);
183 if(RANGE == "") { 172 if(RANGE == 0) {
184 llOwnerSay("Error in configuration notecard: range"); 173 llOwnerSay("Error in configuration notecard: range");
185 return; 174 return;
186 } 175 }
187 // DEBUG 176 // DEBUG
188 llOwnerSay("Read configuration file..."); 177 llOwnerSay("Read configuration file...");
189 state url; 178 state url;
190 } 179 }
191 if(data == "") jump continue; 180 if(data == "") jump continue;
192 integer i = llSubStringIndex(data, "#"); 181 integer i = llSubStringIndex(data, "#");
193 if(i != -1) data = llDeleteSubString(data, i, -1); 182 if(i != -1) data = llDeleteSubString(data, i, -1);
194 list o = llParseString2List(data, ["="], []); 183 list o = llParseString2List(data, ["="], []);
195 // get rid of starting and ending quotes 184 // get rid of starting and ending quotes
196 string k = llDumpList2String( 185 string k = llDumpList2String(
197 llParseString2List( 186 llParseString2List(
198 llStringTrim( 187 llStringTrim(
199 llList2String( 188 llList2String(
200 o, 189 o,
201 0 190 0
202 ), 191 ),
203 STRING_TRIM), 192 STRING_TRIM),
204 ["\""], [] 193 ["\""], []
205 ), "\""); 194 ), "\"");
206 string v = llDumpList2String( 195 string v = llDumpList2String(
207 llParseString2List( 196 llParseString2List(
208 llStringTrim( 197 llStringTrim(
209 llList2String( 198 llList2String(
210 o, 199 o,
211 1 200 1
212 ), 201 ),
213 STRING_TRIM), 202 STRING_TRIM),
214 ["\""], [] 203 ["\""], []
215 ), "\""); 204 ), "\"");
216 if(k == "" || v == "") jump continue; 205 if(k == "" || v == "") jump continue;
217 tuples += k; 206 tuples += k;
218 tuples += v; 207 tuples += v;
219 @continue; 208 @continue;
220 llGetNotecardLine("configuration", ++line); 209 llGetNotecardLine("configuration", ++line);
221 } 210 }
222 on_rez(integer num) { 211 on_rez(integer num) {
223 llResetScript(); 212 llResetScript();
224 } 213 }
225 changed(integer change) { 214 changed(integer change) {
226 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 215 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
227 llResetScript(); 216 llResetScript();
228 } 217 }
229 } 218 }
230 } 219 }
231 220  
232 state url { 221 state url {
233 state_entry() { 222 state_entry() {
234 // DEBUG 223 // DEBUG
235 llOwnerSay("Requesting URL..."); 224 llOwnerSay("Requesting URL...");
236 llRequestURL(); 225 llRequestURL();
237 } 226 }
238 http_request(key id, string method, string body) { 227 http_request(key id, string method, string body) {
239 if(method != URL_REQUEST_GRANTED) return; 228 if(method != URL_REQUEST_GRANTED) return;
240 callback = body; 229 callback = body;
241 // DEBUG 230 // DEBUG
242 llOwnerSay("Got URL..."); 231 llOwnerSay("Got URL...");
243 state off; 232 state off;
244 } 233 }
245 on_rez(integer num) { 234 on_rez(integer num) {
246 llResetScript(); 235 llResetScript();
247 } 236 }
248 changed(integer change) { 237 changed(integer change) {
249 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 238 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
250 llResetScript(); 239 llResetScript();
251 } 240 }
252 } 241 }
253 } 242 }
254   243  
255 state off { 244 state off {
256 state_entry() { 245 state_entry() {
257 // set color for button 246 // set color for button
258 llSetColor(<1,0,0>, ALL_SIDES); 247 llSetColor(<1,0,0>, ALL_SIDES);
259 } 248 }
260 touch_start(integer num) { 249 touch_start(integer num) {
261 state on; 250 state on;
262 } 251 }
263 on_rez(integer num) { 252 on_rez(integer num) {
264 llResetScript(); 253 llResetScript();
265 } 254 }
266 changed(integer change) { 255 changed(integer change) {
267 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 256 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
268 llResetScript(); 257 llResetScript();
269 } 258 }
270 } 259 }
271 } 260 }
272 261  
273 state on { 262 state on {
274 state_entry() { 263 state_entry() {
275 // set color for button 264 // set color for button
276 llSetColor(<0,1,0>, ALL_SIDES); 265 llSetColor(<0,1,0>, ALL_SIDES);
277 // if Corrade is in-range then just follow 266 // if Corrade is in-range then just follow
278 if(wasIsAvatarInSensorRange(CORRADE)) state follow; 267 if(wasIsAvatarInSensorRange(CORRADE)) {
-   268 state follow;
-   269 }
279 // DEBUG 270 // DEBUG
280 llOwnerSay("Detecting if Corrade is online..."); 271 llOwnerSay("Detecting if Corrade is online...");
281 llSetTimerEvent(5); 272 llSetTimerEvent(5);
282 } 273 }
283 timer() { 274 timer() {
284 llRequestAgentData((key)CORRADE, DATA_ONLINE); 275 llRequestAgentData(CORRADE, DATA_ONLINE);
285 } 276 }
286 dataserver(key id, string data) { 277 dataserver(key id, string data) {
287 if(data != "1") { 278 if(data != "1") {
288 // DEBUG 279 // DEBUG
289 llOwnerSay("Corrade is not online, sleeping..."); 280 llOwnerSay("Corrade is not online, sleeping...");
290 llSetTimerEvent(30); 281 llSetTimerEvent(30);
291 return; 282 return;
292 } 283 }
293 llSensorRepeat("", (key)CORRADE, AGENT, (integer)RANGE, TWO_PI, 5); 284 llSensorRepeat("", CORRADE, AGENT, RANGE, TWO_PI, 5);
294 } 285 }
295 no_sensor() { 286 no_sensor() {
296 // DEBUG 287 // DEBUG
297 llOwnerSay("Teleporting Corrade..."); 288 llOwnerSay("Teleporting Corrade...");
298 llInstantMessage((key)CORRADE, 289 llInstantMessage(CORRADE,
299 wasKeyValueEncode( 290 wasKeyValueEncode(
300 [ 291 [
301 "command", "teleport", 292 "command", "teleport",
302 "group", wasURLEscape(GROUP), 293 "group", wasURLEscape(GROUP),
303 "password", wasURLEscape(PASSWORD), 294 "password", wasURLEscape(PASSWORD),
304 "entity", "region", 295 "entity", "region",
305 "region", wasURLEscape(llGetRegionName()), 296 "region", wasURLEscape(llGetRegionName()),
306 "position", llGetPos() + wasCirclePoint((integer)RANGE), 297 "position", llGetPos() + wasCirclePoint((integer)RANGE),
307 "callback", callback 298 "callback", callback
308 ] 299 ]
309 ) 300 )
310 ); 301 );
311 } 302 }
312 sensor(integer num) { 303 sensor(integer num) {
313 llSetTimerEvent(0); -  
314 state follow; 304 state follow;
315 } 305 }
316 http_request(key id, string method, string body) { 306 http_request(key id, string method, string body) {
317 llHTTPResponse(id, 200, "OK"); 307 llHTTPResponse(id, 200, "OK");
318 if(wasKeyValueGet("command", body) != "teleport" || 308 if(wasKeyValueGet("command", body) == "teleport") {
319 wasKeyValueGet("success", body) != "True") { 309 integer success = wasKeyValueGet("success", body) == "True";
-   310 if(success) {
-   311 // DEBUG
-   312 llOwnerSay("Teleport succeeded...");
-   313 state follow;
-   314 }
320 // DEBUG 315 // DEBUG
321 llOwnerSay("Teleport failed..."); 316 llOwnerSay("Teleport failed...");
322 return; 317 return;
323 } 318 }
324 llSetTimerEvent(0); -  
325 state follow; -  
326 } 319 }
327 on_rez(integer num) { 320 on_rez(integer num) {
328 llResetScript(); 321 llResetScript();
329 } 322 }
330 changed(integer change) { 323 changed(integer change) {
331 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 324 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
332 llResetScript(); 325 llResetScript();
333 } 326 }
334 } 327 }
-   328 state_exit() {
-   329 llSetTimerEvent(0);
-   330 }
335 } 331 }
336 332  
337 state follow { 333 state follow {
338 state_entry() { 334 state_entry() {
339 // DEBUG 335 // DEBUG
340 llOwnerSay("In follow state..."); 336 llOwnerSay("In follow state...");
341 // check every second whether Corrade is online 337 // check every second whether Corrade is online
342 llRequestAgentData(CORRADE, DATA_ONLINE); 338 llRequestAgentData(CORRADE, DATA_ONLINE);
343 } 339 }
344 touch_start(integer num) { 340 touch_start(integer num) {
345 state off; 341 state off;
346 } 342 }
347 dataserver(key id, string data) { 343 dataserver(key id, string data) {
348 // if Corrade is not online 344 // if Corrade is not online
349 if(data != "1") state on; 345 if(data != "1") state on;
350 // Corrade is online, so attempt to dectect 346 // Corrade is online, so attempt to dectect
351 llSensorRepeat("", CORRADE, AGENT, (integer)RANGE, TWO_PI, 1); 347 llSensorRepeat("", CORRADE, AGENT, RANGE, TWO_PI, 1);
352 } 348 }
353 no_sensor() { 349 no_sensor() {
354 // check if Corrade is in range, and if not, start detecting 350 // check if Corrade is in range, and if not, start detecting
355 if(!wasIsAvatarInSensorRange(CORRADE)) state on; 351 if(!wasIsAvatarInSensorRange(CORRADE)) {
-   352 state on;
-   353 }
356 // Corrade is in sensor range, so execute move. 354 // Corrade is in sensor range, so execute move.
357 llInstantMessage(CORRADE, 355 llInstantMessage(CORRADE,
358 wasKeyValueEncode( 356 wasKeyValueEncode(
359 [ 357 [
360 "command", "walkto", 358 "command", "walkto",
361 "group", wasURLEscape(GROUP), 359 "group", wasURLEscape(GROUP),
362 "password", wasURLEscape(PASSWORD), 360 "password", wasURLEscape(PASSWORD),
363 // move in a radius around the current primitive. 361 // move in a radius around the current primitive.
364 "position", llGetPos() + wasCirclePoint((integer)RANGE), 362 "position", llGetPos() + wasCirclePoint((integer)RANGE),
365 "vicinity", 1, 363 "vicinity", 1,
366 "timeout", 2500 364 "timeout", 2500
367 ] 365 ]
368 ) 366 )
369 ); 367 );
370 llSensorRepeat("", CORRADE, AGENT, (integer)RANGE, TWO_PI, 1); 368 llSensorRepeat("", CORRADE, AGENT, (integer)RANGE, TWO_PI, 1);
371 llRequestAgentData(CORRADE, DATA_ONLINE); 369 llRequestAgentData(CORRADE, DATA_ONLINE);
372 } 370 }
373 on_rez(integer num) { 371 on_rez(integer num) {
374 llResetScript(); 372 llResetScript();
375 } 373 }
376 changed(integer change) { 374 changed(integer change) {
377 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 375 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
378 llResetScript(); 376 llResetScript();
379 } 377 }
380 } 378 }
381 } -  
382   379 }
-   380  
383
Generated by GNU Enscript 1.6.5.90.
-  
384   -  
385   -  
386   -