corrade-lsl-templates – Diff between revs 29 and 37
?pathlinks?
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 | |