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 2014 - License: GNU GPLv3 // 2 // Copyright (C) Wizardry and Steamworks 2014 - License: CC BY 2.0 //
3 /////////////////////////////////////////////////////////////////////////// 3 ///////////////////////////////////////////////////////////////////////////
4 // 4 //
5 // This is an automatic teleporter, and patrol script for the Corrade 5 // This is an automatic teleporter, and patrol script for the Corrade
6 // Second Life / OpenSim bot. You can find more details about the bot 6 // Second Life / OpenSim bot. You can find more details about the bot
7 // by following the URL: http://was.fm/secondlife/scripted_agents/corrade 7 // by following the URL: http://was.fm/secondlife/scripted_agents/corrade
8 // 8 //
9 // The purpose of this script is to demonstrate patroling with Corrade and 9 // The purpose of this script is to demonstrate patroling with Corrade and
10 // you are free to use, change, and commercialize it under the GNU/GPLv3 10 // you are free to use, change, and commercialize it under the CC BY 2.0
11 // license which can be found at: http://www.gnu.org/licenses/gpl.html 11 // license which can be found at: https://creativecommons.org/licenses/by/2.0
12 // 12 //
13 /////////////////////////////////////////////////////////////////////////// 13 ///////////////////////////////////////////////////////////////////////////
14   14  
15 /////////////////////////////////////////////////////////////////////////// 15 ///////////////////////////////////////////////////////////////////////////
16 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 16 // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 //
17 /////////////////////////////////////////////////////////////////////////// 17 ///////////////////////////////////////////////////////////////////////////
18 string wasKeyValueGet(string k, string data) { 18 string wasKeyValueGet(string k, string data) {
19 if(llStringLength(data) == 0) return ""; 19 if(llStringLength(data) == 0) return "";
20 if(llStringLength(k) == 0) return ""; 20 if(llStringLength(k) == 0) return "";
21 list a = llParseString2List(data, ["&", "="], []); 21 list a = llParseString2List(data, ["&", "="], []);
22 integer i = llListFindList(a, [ k ]); 22 integer i = llListFindList(a, [ k ]);
23 if(i != -1) return llList2String(a, i+1); 23 if(i != -1) return llList2String(a, i+1);
24 return ""; 24 return "";
25 } 25 }
26 26
27 /////////////////////////////////////////////////////////////////////////// 27 ///////////////////////////////////////////////////////////////////////////
28 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // 28 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
29 /////////////////////////////////////////////////////////////////////////// 29 ///////////////////////////////////////////////////////////////////////////
30 string wasKeyValueEncode(list data) { 30 string wasKeyValueEncode(list data) {
31 list k = llList2ListStrided(data, 0, -1, 2); 31 list k = llList2ListStrided(data, 0, -1, 2);
32 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); 32 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
33 data = []; 33 data = [];
34 do { 34 do {
35 data += llList2String(k, 0) + "=" + llList2String(v, 0); 35 data += llList2String(k, 0) + "=" + llList2String(v, 0);
36 k = llDeleteSubList(k, 0, 0); 36 k = llDeleteSubList(k, 0, 0);
37 v = llDeleteSubList(v, 0, 0); 37 v = llDeleteSubList(v, 0, 0);
38 } while(llGetListLength(k) != 0); 38 } while(llGetListLength(k) != 0);
39 return llDumpList2String(data, "&"); 39 return llDumpList2String(data, "&");
40 } 40 }
41   41  
42 /////////////////////////////////////////////////////////////////////////// 42 ///////////////////////////////////////////////////////////////////////////
43 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // 43 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
44 /////////////////////////////////////////////////////////////////////////// 44 ///////////////////////////////////////////////////////////////////////////
45 list wasDualQuicksort(list a, list b) { 45 list wasDualQuicksort(list a, list b) {
46 if(llGetListLength(a) <= 1) return a+b; 46 if(llGetListLength(a) <= 1) return a+b;
47 47
48 float pivot_a = llList2Float(a, 0); 48 float pivot_a = llList2Float(a, 0);
49 a = llDeleteSubList(a, 0, 0); 49 a = llDeleteSubList(a, 0, 0);
50 vector pivot_b = llList2Vector(b, 0); 50 vector pivot_b = llList2Vector(b, 0);
51 b = llDeleteSubList(b, 0, 0); 51 b = llDeleteSubList(b, 0, 0);
52 52
53 list less = []; 53 list less = [];
54 list less_b = []; 54 list less_b = [];
55 list more = []; 55 list more = [];
56 list more_b = []; 56 list more_b = [];
57 57
58 do { 58 do {
59 if(llList2Float(a, 0) > pivot_a) { 59 if(llList2Float(a, 0) > pivot_a) {
60 less += llList2List(a, 0, 0); 60 less += llList2List(a, 0, 0);
61 less_b += llList2List(b, 0, 0); 61 less_b += llList2List(b, 0, 0);
62 jump continue; 62 jump continue;
63 } 63 }
64 more += llList2List(a, 0, 0); 64 more += llList2List(a, 0, 0);
65 more_b += llList2List(b, 0, 0); 65 more_b += llList2List(b, 0, 0);
66 @continue; 66 @continue;
67 a = llDeleteSubList(a, 0, 0); 67 a = llDeleteSubList(a, 0, 0);
68 b = llDeleteSubList(b, 0, 0); 68 b = llDeleteSubList(b, 0, 0);
69 } while(llGetListLength(a)); 69 } while(llGetListLength(a));
70 return wasDualQuicksort(less, less_b) + [ pivot_a ] + [ pivot_b ] + wasDualQuicksort(more, more_b); 70 return wasDualQuicksort(less, less_b) + [ pivot_a ] + [ pivot_b ] + wasDualQuicksort(more, more_b);
71 } 71 }
72 72
73 /////////////////////////////////////////////////////////////////////////// 73 ///////////////////////////////////////////////////////////////////////////
74 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // 74 // Copyright (C) 2014 Wizardry and Steamworks - License: CC BY 2.0 //
75 /////////////////////////////////////////////////////////////////////////// 75 ///////////////////////////////////////////////////////////////////////////
76 // determines whether the segment AB intersects the segment CD 76 // determines whether the segment AB intersects the segment CD
77 integer wasSegmentIntersect(vector A, vector B, vector C, vector D) { 77 integer wasSegmentIntersect(vector A, vector B, vector C, vector D) {
78 vector s1 = <B.x - A.x, B.y - A.y, B.z - A.z>; 78 vector s1 = <B.x - A.x, B.y - A.y, B.z - A.z>;
79 vector s2 = <D.x - C.x, D.y - C.y, D.y - C.z>; 79 vector s2 = <D.x - C.x, D.y - C.y, D.y - C.z>;
80 80
81 float d = (s1.x * s2.y -s2.x * s1.y); 81 float d = (s1.x * s2.y -s2.x * s1.y);
82 82
83 if(d == 0) return FALSE; 83 if(d == 0) return FALSE;
84 84
85 float s = (s1.x * (A.y - C.y) - s1.y * (A.x - C.x)) / d; 85 float s = (s1.x * (A.y - C.y) - s1.y * (A.x - C.x)) / d;
86 float t = (s2.x * (A.y - C.y) - s2.y * (A.x - C.x)) / d; 86 float t = (s2.x * (A.y - C.y) - s2.y * (A.x - C.x)) / d;
87 87
88 // intersection at <A.x + (t * s1.x), A.y + (t * s1.y), A.z + (t * s1.z)>; 88 // intersection at <A.x + (t * s1.x), A.y + (t * s1.y), A.z + (t * s1.z)>;
89 return (integer)(s >= 0 && s <= 1 && t >= 0 && t <= 1 && 89 return (integer)(s >= 0 && s <= 1 && t >= 0 && t <= 1 &&
90 A.z + t*(B.z - A.z) == C.z + s*(D.z - C.z)); 90 A.z + t*(B.z - A.z) == C.z + s*(D.z - C.z));
91 } 91 }
92 92
93 /////////////////////////////////////////////////////////////////////////// 93 ///////////////////////////////////////////////////////////////////////////
94 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // 94 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
95 // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // 95 // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html //
96 /////////////////////////////////////////////////////////////////////////// 96 ///////////////////////////////////////////////////////////////////////////
97 integer wasPointInPolygon(vector p, list polygon) { 97 integer wasPointInPolygon(vector p, list polygon) {
98 integer inside = FALSE; 98 integer inside = FALSE;
99 integer i = 0; 99 integer i = 0;
100 integer nvert = llGetListLength(polygon); 100 integer nvert = llGetListLength(polygon);
101 integer j = nvert-1; 101 integer j = nvert-1;
102 do { 102 do {
103 vector pi = llList2Vector(polygon, i); 103 vector pi = llList2Vector(polygon, i);
104 vector pj = llList2Vector(polygon, j); 104 vector pj = llList2Vector(polygon, j);
105 if ((pi.y > p.y) != (pj.y > p.y)) 105 if ((pi.y > p.y) != (pj.y > p.y))
106 if(p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x) 106 if(p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x)
107 inside = !inside; 107 inside = !inside;
108 j = i++; 108 j = i++;
109 } while(i<nvert); 109 } while(i<nvert);
110 return inside; 110 return inside;
111 } 111 }
112 112
113 /////////////////////////////////////////////////////////////////////////// 113 ///////////////////////////////////////////////////////////////////////////
114 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // 114 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
115 // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // 115 // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html //
116 /////////////////////////////////////////////////////////////////////////// 116 ///////////////////////////////////////////////////////////////////////////
117 list wasPointToPolygon(list polygon, vector point) { 117 list wasPointToPolygon(list polygon, vector point) {
118 integer i = llGetListLength(polygon)-1; 118 integer i = llGetListLength(polygon)-1;
119 list l = []; 119 list l = [];
120 do { 120 do {
121 l = llListInsertList(l, (list)llVecDist(point, llList2Vector(polygon, i)), 0); 121 l = llListInsertList(l, (list)llVecDist(point, llList2Vector(polygon, i)), 0);
122 } while(--i>-1); 122 } while(--i>-1);
123 l = wasDualQuicksort(l, polygon); 123 l = wasDualQuicksort(l, polygon);
124 return [llList2Float(l, 0), llList2Vector(l, 1)]; 124 return [llList2Float(l, 0), llList2Vector(l, 1)];
125 125
126 } 126 }
127 127
128 /////////////////////////////////////////////////////////////////////////// 128 ///////////////////////////////////////////////////////////////////////////
129 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // 129 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
130 // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html // 130 // www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html //
131 /////////////////////////////////////////////////////////////////////////// 131 ///////////////////////////////////////////////////////////////////////////
132 vector wasPolygonCentroid(list polygon, vector start, float tollerance, integer power) { 132 vector wasPolygonCentroid(list polygon, vector start, float tollerance, integer power) {
133 // calculate the distance to the point farthest away from the start. 133 // calculate the distance to the point farthest away from the start.
134 list wpf = wasPointToPolygon(polygon, start); 134 list wpf = wasPointToPolygon(polygon, start);
135 float dist = llList2Float(wpf, 0); 135 float dist = llList2Float(wpf, 0);
136 vector next = llList2Vector(wpf, 1); 136 vector next = llList2Vector(wpf, 1);
137 137
138 // now calculate the next jump point 138 // now calculate the next jump point
139 next = start + ((dist/power)/dist) * (next-start); 139 next = start + ((dist/power)/dist) * (next-start);
140 140
141 // if it falls withing the tollerance range, return it; 141 // if it falls withing the tollerance range, return it;
142 if(llVecMag(start-next) < tollerance) return next; 142 if(llVecMag(start-next) < tollerance) return next;
143 return wasPolygonCentroid(polygon, next, tollerance, power*power); 143 return wasPolygonCentroid(polygon, next, tollerance, power*power);
144 } 144 }
145 145
146 /////////////////////////////////////////////////////////////////////////// 146 ///////////////////////////////////////////////////////////////////////////
147 // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 // 147 // Copyright (C) 2011 Wizardry and Steamworks - License: CC BY 2.0 //
148 /////////////////////////////////////////////////////////////////////////// 148 ///////////////////////////////////////////////////////////////////////////
149 vector wasCirclePoint(float radius) { 149 vector wasCirclePoint(float radius) {
150 float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); 150 float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
151 float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); 151 float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
152 if(llPow(x,2) + llPow(y,2) <= llPow(radius,2)) 152 if(llPow(x,2) + llPow(y,2) <= llPow(radius,2))
153 return <x, y, 0>; 153 return <x, y, 0>;
154 return wasCirclePoint(radius); 154 return wasCirclePoint(radius);
155 } 155 }
156 156
157 /////////////////////////////////////////////////////////////////////////// 157 ///////////////////////////////////////////////////////////////////////////
158 // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 // 158 // Copyright (C) 2011 Wizardry and Steamworks - License: CC BY 2.0 //
159 /////////////////////////////////////////////////////////////////////////// 159 ///////////////////////////////////////////////////////////////////////////
160 vector wasPolygonPoint(list polygon) { 160 vector wasPolygonPoint(list polygon) {
161 vector c = wasPolygonCentroid(polygon, llList2Vector(polygon, 0), 0.05, 2); 161 vector c = wasPolygonCentroid(polygon, llList2Vector(polygon, 0), 0.05, 2);
162 float r = llList2Float(wasPointToPolygon(polygon, c), 0); 162 float r = llList2Float(wasPointToPolygon(polygon, c), 0);
163 vector d; 163 vector d;
164 do { 164 do {
165 d = c + wasCirclePoint(r); 165 d = c + wasCirclePoint(r);
166 } while(wasPointInPolygon(d, polygon) == FALSE); 166 } while(wasPointInPolygon(d, polygon) == FALSE);
167 return d; 167 return d;
168 } 168 }
169 169
170 /////////////////////////////////////////////////////////////////////////// 170 ///////////////////////////////////////////////////////////////////////////
171 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 171 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
172 /////////////////////////////////////////////////////////////////////////// 172 ///////////////////////////////////////////////////////////////////////////
173 // determines whether the path between the current positon m and the 173 // determines whether the path between the current positon m and the
174 // computed next position d will intersect any two sides of the polygon 174 // computed next position d will intersect any two sides of the polygon
175 vector wasPolygonPath(vector m, list polygon) { 175 vector wasPolygonPath(vector m, list polygon) {
176 integer c = llGetListLength(polygon) - 1; 176 integer c = llGetListLength(polygon) - 1;
177 vector d = wasPolygonPoint(polygon); 177 vector d = wasPolygonPoint(polygon);
178 integer i = 0; 178 integer i = 0;
179 do { 179 do {
180 vector s = llList2Vector(polygon, c); 180 vector s = llList2Vector(polygon, c);
181 vector p = llList2Vector(polygon, c-1); 181 vector p = llList2Vector(polygon, c-1);
182 // project in plane 182 // project in plane
183 if(wasSegmentIntersect( 183 if(wasSegmentIntersect(
184 <m.x, m.y, 0>, 184 <m.x, m.y, 0>,
185 <d.x, d.y, 0>, 185 <d.x, d.y, 0>,
186 <s.x, s.y, 0>, 186 <s.x, s.y, 0>,
187 <p.x, p.y, 0>)) 187 <p.x, p.y, 0>))
188 ++i; 188 ++i;
189 } while(--c > 0); 189 } while(--c > 0);
190 if(i > 1) return wasPolygonPath(m, polygon); 190 if(i > 1) return wasPolygonPath(m, polygon);
191 return d; 191 return d;
192 } 192 }
193   193  
194 /////////////////////////////////////////////////////////////////////////// 194 ///////////////////////////////////////////////////////////////////////////
195 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 195 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
196 /////////////////////////////////////////////////////////////////////////// 196 ///////////////////////////////////////////////////////////////////////////
197 // escapes a string in conformance with RFC1738 197 // escapes a string in conformance with RFC1738
198 string wasURLEscape(string i) { 198 string wasURLEscape(string i) {
199 string o = ""; 199 string o = "";
200 do { 200 do {
201 string c = llGetSubString(i, 0, 0); 201 string c = llGetSubString(i, 0, 0);
202 i = llDeleteSubString(i, 0, 0); 202 i = llDeleteSubString(i, 0, 0);
203 if(c == "") jump continue; 203 if(c == "") jump continue;
204 if(c == " ") { 204 if(c == " ") {
205 o += "+"; 205 o += "+";
206 jump continue; 206 jump continue;
207 } 207 }
208 if(c == "\n") { 208 if(c == "\n") {
209 o += "%0D" + llEscapeURL(c); 209 o += "%0D" + llEscapeURL(c);
210 jump continue; 210 jump continue;
211 } 211 }
212 o += llEscapeURL(c); 212 o += llEscapeURL(c);
213 @continue; 213 @continue;
214 } while(i != ""); 214 } while(i != "");
215 return o; 215 return o;
216 } 216 }
217   217  
218 // corrade data 218 // corrade data
219 string CORRADE = ""; 219 string CORRADE = "";
220 string GROUP = ""; 220 string GROUP = "";
221 string PASSWORD = ""; 221 string PASSWORD = "";
222 float RADIUS = 0; 222 float RADIUS = 0;
223 float WAIT = 0; 223 float WAIT = 0;
224 list POLYGON = []; 224 list POLYGON = [];
225   225  
226 // for holding Corrade's current location 226 // for holding Corrade's current location
227 vector location = ZERO_VECTOR; 227 vector location = ZERO_VECTOR;
228   228  
229 // for holding the callback URL 229 // for holding the callback URL
230 string callback = ""; 230 string callback = "";
231   231  
232 // for notecard reading 232 // for notecard reading
233 integer line = 0; 233 integer line = 0;
234   234  
235 // key-value data will be read into this list 235 // key-value data will be read into this list
236 list tuples = []; 236 list tuples = [];
237 237
238 default { 238 default {
239 state_entry() { 239 state_entry() {
240 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { 240 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
241 llOwnerSay("Sorry, could not find an inventory notecard."); 241 llOwnerSay("Sorry, could not find an inventory notecard.");
242 return; 242 return;
243 } 243 }
244 // DEBUG 244 // DEBUG
245 llOwnerSay("Reading configuration file..."); 245 llOwnerSay("Reading configuration file...");
246 llGetNotecardLine("configuration", line); 246 llGetNotecardLine("configuration", line);
247 } 247 }
248 dataserver(key id, string data) { 248 dataserver(key id, string data) {
249 if(data == EOF) { 249 if(data == EOF) {
250 // invariant, length(tuples) % 2 == 0 250 // invariant, length(tuples) % 2 == 0
251 if(llGetListLength(tuples) % 2 != 0) { 251 if(llGetListLength(tuples) % 2 != 0) {
252 llOwnerSay("Error in configuration notecard."); 252 llOwnerSay("Error in configuration notecard.");
253 return; 253 return;
254 } 254 }
255 CORRADE = llList2String( 255 CORRADE = llList2String(
256 tuples, 256 tuples,
257 llListFindList( 257 llListFindList(
258 tuples, 258 tuples,
259 [ 259 [
260 "corrade" 260 "corrade"
261 ] 261 ]
262 ) 262 )
263 +1); 263 +1);
264 if(CORRADE == "") { 264 if(CORRADE == "") {
265 llOwnerSay("Error in configuration notecard: corrade"); 265 llOwnerSay("Error in configuration notecard: corrade");
266 return; 266 return;
267 } 267 }
268 GROUP = llList2String( 268 GROUP = llList2String(
269 tuples, 269 tuples,
270 llListFindList( 270 llListFindList(
271 tuples, 271 tuples,
272 [ 272 [
273 "group" 273 "group"
274 ] 274 ]
275 ) 275 )
276 +1); 276 +1);
277 if(GROUP == "") { 277 if(GROUP == "") {
278 llOwnerSay("Error in configuration notecard: group"); 278 llOwnerSay("Error in configuration notecard: group");
279 return; 279 return;
280 } 280 }
281 PASSWORD = llList2String( 281 PASSWORD = llList2String(
282 tuples, 282 tuples,
283 llListFindList( 283 llListFindList(
284 tuples, 284 tuples,
285 [ 285 [
286 "password" 286 "password"
287 ] 287 ]
288 ) 288 )
289 +1); 289 +1);
290 if(PASSWORD == "") { 290 if(PASSWORD == "") {
291 llOwnerSay("Error in configuration notecard: password"); 291 llOwnerSay("Error in configuration notecard: password");
292 return; 292 return;
293 } 293 }
294 294
295 // BEGIN POLYGON 295 // BEGIN POLYGON
296 integer i = llGetListLength(tuples)-1; 296 integer i = llGetListLength(tuples)-1;
297 do { 297 do {
298 string n = llList2String(tuples, i); 298 string n = llList2String(tuples, i);
299 if(llSubStringIndex(n, "point_") != -1) { 299 if(llSubStringIndex(n, "point_") != -1) {
300 list l = llParseString2List(n, ["_"], []); 300 list l = llParseString2List(n, ["_"], []);
301 if(llList2String(l, 0) == "point") { 301 if(llList2String(l, 0) == "point") {
302 integer x = llList2Integer( 302 integer x = llList2Integer(
303 l, 303 l,
304 1 304 1
305 )-1; 305 )-1;
306 // extend the polygon to the number of points 306 // extend the polygon to the number of points
307 while(llGetListLength(POLYGON) < x) 307 while(llGetListLength(POLYGON) < x)
308 POLYGON += ""; 308 POLYGON += "";
309 // and insert the point at the location 309 // and insert the point at the location
310 POLYGON = llListReplaceList( 310 POLYGON = llListReplaceList(
311 POLYGON, 311 POLYGON,
312 (list)( 312 (list)(
313 (vector)( 313 (vector)(
314 "<" + llList2CSV( 314 "<" + llList2CSV(
315 llParseString2List( 315 llParseString2List(
316 llList2String( 316 llList2String(
317 tuples, 317 tuples,
318 llListFindList( 318 llListFindList(
319 tuples, 319 tuples,
320 (list)n 320 (list)n
321 ) 321 )
322 +1 322 +1
323 ), 323 ),
324 ["<", ",", ">"], 324 ["<", ",", ">"],
325 [] 325 []
326 ) 326 )
327 ) + ">") 327 ) + ">")
328 ), 328 ),
329 x, 329 x,
330 x 330 x
331 ); 331 );
332 } 332 }
333 } 333 }
334 } while(--i>-1); 334 } while(--i>-1);
335 // now clean up any empty slots 335 // now clean up any empty slots
336 i = llGetListLength(POLYGON)-1; 336 i = llGetListLength(POLYGON)-1;
337 do { 337 do {
338 if(llList2String(POLYGON, i) == "") 338 if(llList2String(POLYGON, i) == "")
339 POLYGON = llDeleteSubList(POLYGON, i, i); 339 POLYGON = llDeleteSubList(POLYGON, i, i);
340 } while(--i > -1); 340 } while(--i > -1);
341 // END POLYGON 341 // END POLYGON
342 342
343 WAIT = llList2Float( 343 WAIT = llList2Float(
344 tuples, 344 tuples,
345 llListFindList( 345 llListFindList(
346 tuples, 346 tuples,
347 [ 347 [
348 "wait" 348 "wait"
349 ] 349 ]
350 ) 350 )
351 +1); 351 +1);
352 if(WAIT == 0) { 352 if(WAIT == 0) {
353 llOwnerSay("Error in configuration notecard: wait"); 353 llOwnerSay("Error in configuration notecard: wait");
354 return; 354 return;
355 } 355 }
356 // DEBUG 356 // DEBUG
357 llOwnerSay("Read configuration file..."); 357 llOwnerSay("Read configuration file...");
358 state url; 358 state url;
359 } 359 }
360 if(data == "") jump continue; 360 if(data == "") jump continue;
361 integer i = llSubStringIndex(data, "#"); 361 integer i = llSubStringIndex(data, "#");
362 if(i != -1) data = llDeleteSubString(data, i, -1); 362 if(i != -1) data = llDeleteSubString(data, i, -1);
363 list o = llParseString2List(data, ["="], []); 363 list o = llParseString2List(data, ["="], []);
364 // get rid of starting and ending quotes 364 // get rid of starting and ending quotes
365 string k = llDumpList2String( 365 string k = llDumpList2String(
366 llParseString2List( 366 llParseString2List(
367 llStringTrim( 367 llStringTrim(
368 llList2String( 368 llList2String(
369 o, 369 o,
370 0 370 0
371 ), 371 ),
372 STRING_TRIM), 372 STRING_TRIM),
373 ["\""], [] 373 ["\""], []
374 ), "\""); 374 ), "\"");
375 string v = llDumpList2String( 375 string v = llDumpList2String(
376 llParseString2List( 376 llParseString2List(
377 llStringTrim( 377 llStringTrim(
378 llList2String( 378 llList2String(
379 o, 379 o,
380 1 380 1
381 ), 381 ),
382 STRING_TRIM), 382 STRING_TRIM),
383 ["\""], [] 383 ["\""], []
384 ), "\""); 384 ), "\"");
385 if(k == "" || v == "") jump continue; 385 if(k == "" || v == "") jump continue;
386 tuples += k; 386 tuples += k;
387 tuples += v; 387 tuples += v;
388 @continue; 388 @continue;
389 llGetNotecardLine("configuration", ++line); 389 llGetNotecardLine("configuration", ++line);
390 } 390 }
391 on_rez(integer num) { 391 on_rez(integer num) {
392 llResetScript(); 392 llResetScript();
393 } 393 }
394 changed(integer change) { 394 changed(integer change) {
395 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 395 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
396 llResetScript(); 396 llResetScript();
397 } 397 }
398 } 398 }
399 } 399 }
400 400
401 state url { 401 state url {
402 state_entry() { 402 state_entry() {
403 // DEBUG 403 // DEBUG
404 llOwnerSay("Requesting URL..."); 404 llOwnerSay("Requesting URL...");
405 llRequestURL(); 405 llRequestURL();
406 } 406 }
407 http_request(key id, string method, string body) { 407 http_request(key id, string method, string body) {
408 if(method != URL_REQUEST_GRANTED) return; 408 if(method != URL_REQUEST_GRANTED) return;
409 callback = body; 409 callback = body;
410 // DEBUG 410 // DEBUG
411 llOwnerSay("Got URL..."); 411 llOwnerSay("Got URL...");
412 state detect; 412 state detect;
413 } 413 }
414 on_rez(integer num) { 414 on_rez(integer num) {
415 llResetScript(); 415 llResetScript();
416 } 416 }
417 changed(integer change) { 417 changed(integer change) {
418 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 418 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
419 llResetScript(); 419 llResetScript();
420 } 420 }
421 } 421 }
422 } 422 }
423 423
424 state detect { 424 state detect {
425 state_entry() { 425 state_entry() {
426 // DEBUG 426 // DEBUG
427 llOwnerSay("Detecting if Corrade is online..."); 427 llOwnerSay("Detecting if Corrade is online...");
428 llSetTimerEvent(5); 428 llSetTimerEvent(5);
429 } 429 }
430 timer() { 430 timer() {
431 llRequestAgentData((key)CORRADE, DATA_ONLINE); 431 llRequestAgentData((key)CORRADE, DATA_ONLINE);
432 } 432 }
433 dataserver(key id, string data) { 433 dataserver(key id, string data) {
434 if(data != "1") { 434 if(data != "1") {
435 // DEBUG 435 // DEBUG
436 llOwnerSay("Corrade is not online, sleeping..."); 436 llOwnerSay("Corrade is not online, sleeping...");
437 llSetTimerEvent(30); 437 llSetTimerEvent(30);
438 return; 438 return;
439 } 439 }
440 llSensor("", (key)CORRADE, AGENT, 10, TWO_PI); 440 llSensor("", (key)CORRADE, AGENT, 10, TWO_PI);
441 } 441 }
442 no_sensor() { 442 no_sensor() {
443 // DEBUG 443 // DEBUG
444 llOwnerSay("Teleporting Corrade..."); 444 llOwnerSay("Teleporting Corrade...");
445 llInstantMessage((key)CORRADE, 445 llInstantMessage((key)CORRADE,
446 wasKeyValueEncode( 446 wasKeyValueEncode(
447 [ 447 [
448 "command", "teleport", 448 "command", "teleport",
449 "group", wasURLEscape(GROUP), 449 "group", wasURLEscape(GROUP),
450 "password", wasURLEscape(PASSWORD), 450 "password", wasURLEscape(PASSWORD),
451 "entity", "region", 451 "entity", "region",
452 "region", wasURLEscape(llGetRegionName()), 452 "region", wasURLEscape(llGetRegionName()),
453 "position", wasURLEscape( 453 "position", wasURLEscape(
454 (string)( 454 (string)(
455 llGetPos() + wasCirclePoint(RADIUS) 455 llGetPos() + wasCirclePoint(RADIUS)
456 ) 456 )
457 ), 457 ),
458 "callback", callback 458 "callback", callback
459 ] 459 ]
460 ) 460 )
461 ); 461 );
462 llSensorRepeat("", (key)CORRADE, AGENT, 10, TWO_PI, 60); 462 llSensorRepeat("", (key)CORRADE, AGENT, 10, TWO_PI, 60);
463 } 463 }
464 sensor(integer num) { 464 sensor(integer num) {
465 llSetTimerEvent(0); 465 llSetTimerEvent(0);
466 state wander; 466 state wander;
467 } 467 }
468 http_request(key id, string method, string body) { 468 http_request(key id, string method, string body) {
469 llHTTPResponse(id, 200, "OK"); 469 llHTTPResponse(id, 200, "OK");
470 if(wasKeyValueGet("command", body) != "teleport" || 470 if(wasKeyValueGet("command", body) != "teleport" ||
471 wasKeyValueGet("success", body) != "True") { 471 wasKeyValueGet("success", body) != "True") {
472 // DEBUG 472 // DEBUG
473 llOwnerSay("Teleport failed..."); 473 llOwnerSay("Teleport failed...");
474 return; 474 return;
475 } 475 }
476 llSetTimerEvent(0); 476 llSetTimerEvent(0);
477 state wander; 477 state wander;
478 } 478 }
479 on_rez(integer num) { 479 on_rez(integer num) {
480 llResetScript(); 480 llResetScript();
481 } 481 }
482 changed(integer change) { 482 changed(integer change) {
483 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 483 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
484 llResetScript(); 484 llResetScript();
485 } 485 }
486 } 486 }
487 } 487 }
488   488  
489 state wander { 489 state wander {
490 state_entry() { 490 state_entry() {
491 // DEBUG 491 // DEBUG
492 llOwnerSay("Wandering ready..."); 492 llOwnerSay("Wandering ready...");
493 // initialize location from current location 493 // initialize location from current location
494 location = llGetPos(); 494 location = llGetPos();
495 llSetTimerEvent(1 + llFrand(WAIT)); 495 llSetTimerEvent(1 + llFrand(WAIT));
496 } 496 }
497 timer() { 497 timer() {
498 llRequestAgentData((key)CORRADE, DATA_ONLINE); 498 llRequestAgentData((key)CORRADE, DATA_ONLINE);
499 } 499 }
500 dataserver(key id, string data) { 500 dataserver(key id, string data) {
501 if(data != "1") { 501 if(data != "1") {
502 // DEBUG 502 // DEBUG
503 llOwnerSay("Corrade is not online, sleeping..."); 503 llOwnerSay("Corrade is not online, sleeping...");
504 llResetScript(); 504 llResetScript();
505 return; 505 return;
506 } 506 }
507 // DEBUG 507 // DEBUG
508 //llOwnerSay("Sending stop..."); 508 //llOwnerSay("Sending stop...");
509 llInstantMessage(CORRADE, 509 llInstantMessage(CORRADE,
510 wasKeyValueEncode( 510 wasKeyValueEncode(
511 [ 511 [
512 "command", "autopilot", 512 "command", "autopilot",
513 "group", wasURLEscape(GROUP), 513 "group", wasURLEscape(GROUP),
514 "password", wasURLEscape(PASSWORD), 514 "password", wasURLEscape(PASSWORD),
515 "action", "stop", 515 "action", "stop",
516 "callback", wasURLEscape(callback) 516 "callback", wasURLEscape(callback)
517 ] 517 ]
518 ) 518 )
519 ); 519 );
520 } 520 }
521 http_request(key id, string method, string body) { 521 http_request(key id, string method, string body) {
522 llHTTPResponse(id, 200, "OK"); 522 llHTTPResponse(id, 200, "OK");
523 if(wasKeyValueGet("command", body) != "autopilot" || 523 if(wasKeyValueGet("command", body) != "autopilot" ||
524 wasKeyValueGet("success", body) != "True") { 524 wasKeyValueGet("success", body) != "True") {
525 // DEBUG 525 // DEBUG
526 llOwnerSay("Could not get Corrade to stop, restarting script..."); 526 llOwnerSay("Could not get Corrade to stop, restarting script...");
527 llResetScript(); 527 llResetScript();
528 } 528 }
529 // DEBUG 529 // DEBUG
530 llOwnerSay("Sending next move..."); 530 llOwnerSay("Sending next move...");
531 // get the next location 531 // get the next location
532 location = wasPolygonPath(location, POLYGON); 532 location = wasPolygonPath(location, POLYGON);
533 vector pos = llGetPos(); 533 vector pos = llGetPos();
534 llInstantMessage(CORRADE, 534 llInstantMessage(CORRADE,
535 wasKeyValueEncode( 535 wasKeyValueEncode(
536 [ 536 [
537 "command", "autopilot", 537 "command", "autopilot",
538 "group", wasURLEscape(GROUP), 538 "group", wasURLEscape(GROUP),
539 "password", wasURLEscape(PASSWORD), 539 "password", wasURLEscape(PASSWORD),
540 "position", wasURLEscape( 540 "position", wasURLEscape(
541 (string)(<location.x, location.y, pos.z>) 541 (string)(<location.x, location.y, pos.z>)
542 ), 542 ),
543 "action", "start" 543 "action", "start"
544 ] 544 ]
545 ) 545 )
546 ); 546 );
547 llSetTimerEvent(1 + llFrand(WAIT)); 547 llSetTimerEvent(1 + llFrand(WAIT));
548 } 548 }
549 on_rez(integer num) { 549 on_rez(integer num) {
550 llResetScript(); 550 llResetScript();
551 } 551 }
552 changed(integer change) { 552 changed(integer change) {
553 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 553 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
554 llResetScript(); 554 llResetScript();
555 } 555 }
556 } 556 }
557 } 557 }
558   558