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 script demonstrates the built-in local chat AIML talking feature of 5 // This script demonstrates the built-in local chat AIML talking feature of
6 // the Corrade Second Life / OpenSim bot. For more documentation on Corrade 6 // the Corrade Second Life / OpenSim bot. For more documentation on Corrade
7 // follow the URL: http://grimore.org/secondlife/scripted_agents/corrade 7 // follow the URL: http://grimore.org/secondlife/scripted_agents/corrade
8 // 8 //
9 // The script works in combination with a "configuration" notecard that 9 // The script works in combination with a "configuration" notecard that
10 // must be placed in the same primitive as this script. The purpose of this 10 // must be placed in the same primitive as this script. The purpose of this
11 // script is to demonstrate answering messages with Corrade's built-in AI 11 // script is to demonstrate answering messages with Corrade's built-in AI
12 // and you are free to use, change, and commercialize it under the terms 12 // and you are free to use, change, and commercialize it under the terms
13 // of the GNU/GPLv3 license at: http://www.gnu.org/licenses/gpl.html 13 // of the CC BY 2.0 license at: https://creativecommons.org/licenses/by/2.0
14 // 14 //
15 /////////////////////////////////////////////////////////////////////////// 15 ///////////////////////////////////////////////////////////////////////////
16   16  
17 /////////////////////////////////////////////////////////////////////////// 17 ///////////////////////////////////////////////////////////////////////////
18 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 18 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
19 /////////////////////////////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////////////////////////////
20 string wasKeyValueGet(string k, string data) { 20 string wasKeyValueGet(string k, string data) {
21 if(llStringLength(data) == 0) return ""; 21 if(llStringLength(data) == 0) return "";
22 if(llStringLength(k) == 0) return ""; 22 if(llStringLength(k) == 0) return "";
23 list a = llParseString2List(data, ["&", "="], []); 23 list a = llParseString2List(data, ["&", "="], []);
24 integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]); 24 integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
25 if(i != -1) return llList2String(a, 2*i+1); 25 if(i != -1) return llList2String(a, 2*i+1);
26 return ""; 26 return "";
27 } 27 }
28 28
29 /////////////////////////////////////////////////////////////////////////// 29 ///////////////////////////////////////////////////////////////////////////
30 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // 30 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
31 /////////////////////////////////////////////////////////////////////////// 31 ///////////////////////////////////////////////////////////////////////////
32 string wasKeyValueEncode(list data) { 32 string wasKeyValueEncode(list data) {
33 list k = llList2ListStrided(data, 0, -1, 2); 33 list k = llList2ListStrided(data, 0, -1, 2);
34 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); 34 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
35 data = []; 35 data = [];
36 do { 36 do {
37 data += llList2String(k, 0) + "=" + llList2String(v, 0); 37 data += llList2String(k, 0) + "=" + llList2String(v, 0);
38 k = llDeleteSubList(k, 0, 0); 38 k = llDeleteSubList(k, 0, 0);
39 v = llDeleteSubList(v, 0, 0); 39 v = llDeleteSubList(v, 0, 0);
40 } while(llGetListLength(k) != 0); 40 } while(llGetListLength(k) != 0);
41 return llDumpList2String(data, "&"); 41 return llDumpList2String(data, "&");
42 } 42 }
43   43  
44 /////////////////////////////////////////////////////////////////////////// 44 ///////////////////////////////////////////////////////////////////////////
45 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 45 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
46 /////////////////////////////////////////////////////////////////////////// 46 ///////////////////////////////////////////////////////////////////////////
47 // escapes a string in conformance with RFC1738 47 // escapes a string in conformance with RFC1738
48 string wasURLEscape(string i) { 48 string wasURLEscape(string i) {
49 string o = ""; 49 string o = "";
50 do { 50 do {
51 string c = llGetSubString(i, 0, 0); 51 string c = llGetSubString(i, 0, 0);
52 i = llDeleteSubString(i, 0, 0); 52 i = llDeleteSubString(i, 0, 0);
53 if(c == "") jump continue; 53 if(c == "") jump continue;
54 if(c == " ") { 54 if(c == " ") {
55 o += "+"; 55 o += "+";
56 jump continue; 56 jump continue;
57 } 57 }
58 if(c == "\n") { 58 if(c == "\n") {
59 o += "%0D" + llEscapeURL(c); 59 o += "%0D" + llEscapeURL(c);
60 jump continue; 60 jump continue;
61 } 61 }
62 o += llEscapeURL(c); 62 o += llEscapeURL(c);
63 @continue; 63 @continue;
64 } while(i != ""); 64 } while(i != "");
65 return o; 65 return o;
66 } 66 }
67   67  
68 /////////////////////////////////////////////////////////////////////////// 68 ///////////////////////////////////////////////////////////////////////////
69 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 69 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
70 /////////////////////////////////////////////////////////////////////////// 70 ///////////////////////////////////////////////////////////////////////////
71 // unescapes a string in conformance with RFC1738 71 // unescapes a string in conformance with RFC1738
72 string wasURLUnescape(string i) { 72 string wasURLUnescape(string i) {
73 return llUnescapeURL( 73 return llUnescapeURL(
74 llDumpList2String( 74 llDumpList2String(
75 llParseString2List( 75 llParseString2List(
76 llDumpList2String( 76 llDumpList2String(
77 llParseString2List( 77 llParseString2List(
78 i, 78 i,
79 ["+"], 79 ["+"],
80 [] 80 []
81 ), 81 ),
82 " " 82 " "
83 ), 83 ),
84 ["%0D%0A"], 84 ["%0D%0A"],
85 [] 85 []
86 ), 86 ),
87 "\n" 87 "\n"
88 ) 88 )
89 ); 89 );
90 } 90 }
91   91  
92 // corrade data 92 // corrade data
93 key CORRADE = NULL_KEY; 93 key CORRADE = NULL_KEY;
94 string GROUP = ""; 94 string GROUP = "";
95 string PASSWORD = ""; 95 string PASSWORD = "";
96   96  
97 // instance variables 97 // instance variables
98 string firstname = ""; 98 string firstname = "";
99 string lastname = ""; 99 string lastname = "";
100 string message = ""; 100 string message = "";
101   101  
102 // for holding the callback URL 102 // for holding the callback URL
103 string callback = ""; 103 string callback = "";
104   104  
105 // for notecard reading 105 // for notecard reading
106 integer line = 0; 106 integer line = 0;
107 107
108 // key-value data will be read into this list 108 // key-value data will be read into this list
109 list tuples = []; 109 list tuples = [];
110   110  
111 default { 111 default {
112 state_entry() { 112 state_entry() {
113 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { 113 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
114 llOwnerSay("Sorry, could not find a configuration inventory notecard."); 114 llOwnerSay("Sorry, could not find a configuration inventory notecard.");
115 return; 115 return;
116 } 116 }
117 // DEBUG 117 // DEBUG
118 llOwnerSay("Reading configuration file..."); 118 llOwnerSay("Reading configuration file...");
119 llGetNotecardLine("configuration", line); 119 llGetNotecardLine("configuration", line);
120 } 120 }
121 dataserver(key id, string data) { 121 dataserver(key id, string data) {
122 if(data == EOF) { 122 if(data == EOF) {
123 // invariant, length(tuples) % 2 == 0 123 // invariant, length(tuples) % 2 == 0
124 if(llGetListLength(tuples) % 2 != 0) { 124 if(llGetListLength(tuples) % 2 != 0) {
125 llOwnerSay("Error in configuration notecard."); 125 llOwnerSay("Error in configuration notecard.");
126 return; 126 return;
127 } 127 }
128 CORRADE = llList2Key( 128 CORRADE = llList2Key(
129 tuples, 129 tuples,
130 llListFindList( 130 llListFindList(
131 tuples, 131 tuples,
132 [ 132 [
133 "corrade" 133 "corrade"
134 ] 134 ]
135 ) 135 )
136 +1); 136 +1);
137 if(CORRADE == NULL_KEY) { 137 if(CORRADE == NULL_KEY) {
138 llOwnerSay("Error in configuration notecard: corrade"); 138 llOwnerSay("Error in configuration notecard: corrade");
139 return; 139 return;
140 } 140 }
141 GROUP = llList2String( 141 GROUP = llList2String(
142 tuples, 142 tuples,
143 llListFindList( 143 llListFindList(
144 tuples, 144 tuples,
145 [ 145 [
146 "group" 146 "group"
147 ] 147 ]
148 ) 148 )
149 +1); 149 +1);
150 if(GROUP == "") { 150 if(GROUP == "") {
151 llOwnerSay("Error in configuration notecard: group"); 151 llOwnerSay("Error in configuration notecard: group");
152 return; 152 return;
153 } 153 }
154 PASSWORD = llList2String( 154 PASSWORD = llList2String(
155 tuples, 155 tuples,
156 llListFindList( 156 llListFindList(
157 tuples, 157 tuples,
158 [ 158 [
159 "password" 159 "password"
160 ] 160 ]
161 ) 161 )
162 +1); 162 +1);
163 if(PASSWORD == "") { 163 if(PASSWORD == "") {
164 llOwnerSay("Error in configuration notecard: password"); 164 llOwnerSay("Error in configuration notecard: password");
165 return; 165 return;
166 } 166 }
167 // DEBUG 167 // DEBUG
168 llOwnerSay("Read configuration notecard..."); 168 llOwnerSay("Read configuration notecard...");
169 state url; 169 state url;
170 } 170 }
171 if(data == "") jump continue; 171 if(data == "") jump continue;
172 integer i = llSubStringIndex(data, "#"); 172 integer i = llSubStringIndex(data, "#");
173 if(i != -1) data = llDeleteSubString(data, i, -1); 173 if(i != -1) data = llDeleteSubString(data, i, -1);
174 list o = llParseString2List(data, ["="], []); 174 list o = llParseString2List(data, ["="], []);
175 // get rid of starting and ending quotes 175 // get rid of starting and ending quotes
176 string k = llDumpList2String( 176 string k = llDumpList2String(
177 llParseString2List( 177 llParseString2List(
178 llStringTrim( 178 llStringTrim(
179 llList2String( 179 llList2String(
180 o, 180 o,
181 0 181 0
182 ), 182 ),
183 STRING_TRIM), 183 STRING_TRIM),
184 ["\""], [] 184 ["\""], []
185 ), "\""); 185 ), "\"");
186 string v = llDumpList2String( 186 string v = llDumpList2String(
187 llParseString2List( 187 llParseString2List(
188 llStringTrim( 188 llStringTrim(
189 llList2String( 189 llList2String(
190 o, 190 o,
191 1 191 1
192 ), 192 ),
193 STRING_TRIM), 193 STRING_TRIM),
194 ["\""], [] 194 ["\""], []
195 ), "\""); 195 ), "\"");
196 if(k == "" || v == "") jump continue; 196 if(k == "" || v == "") jump continue;
197 tuples += k; 197 tuples += k;
198 tuples += v; 198 tuples += v;
199 @continue; 199 @continue;
200 llGetNotecardLine("configuration", ++line); 200 llGetNotecardLine("configuration", ++line);
201 } 201 }
202 on_rez(integer num) { 202 on_rez(integer num) {
203 llResetScript(); 203 llResetScript();
204 } 204 }
205 changed(integer change) { 205 changed(integer change) {
206 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 206 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
207 llResetScript(); 207 llResetScript();
208 } 208 }
209 } 209 }
210 } 210 }
211   211  
212 state url { 212 state url {
213 state_entry() { 213 state_entry() {
214 // DEBUG 214 // DEBUG
215 llOwnerSay("Requesting URL..."); 215 llOwnerSay("Requesting URL...");
216 llRequestURL(); 216 llRequestURL();
217 } 217 }
218 http_request(key id, string method, string body) { 218 http_request(key id, string method, string body) {
219 if(method != URL_REQUEST_GRANTED) return; 219 if(method != URL_REQUEST_GRANTED) return;
220 callback = body; 220 callback = body;
221 // DEBUG 221 // DEBUG
222 llOwnerSay("Got URL..."); 222 llOwnerSay("Got URL...");
223 state detect; 223 state detect;
224 } 224 }
225 on_rez(integer num) { 225 on_rez(integer num) {
226 llResetScript(); 226 llResetScript();
227 } 227 }
228 changed(integer change) { 228 changed(integer change) {
229 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 229 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
230 llResetScript(); 230 llResetScript();
231 } 231 }
232 } 232 }
233 } 233 }
234 234
235 state detect { 235 state detect {
236 state_entry() { 236 state_entry() {
237 // DEBUG 237 // DEBUG
238 llOwnerSay("Detecting if Corrade is online..."); 238 llOwnerSay("Detecting if Corrade is online...");
239 llSetTimerEvent(5); 239 llSetTimerEvent(5);
240 } 240 }
241 timer() { 241 timer() {
242 llRequestAgentData((key)CORRADE, DATA_ONLINE); 242 llRequestAgentData((key)CORRADE, DATA_ONLINE);
243 } 243 }
244 dataserver(key id, string data) { 244 dataserver(key id, string data) {
245 if(data != "1") { 245 if(data != "1") {
246 // DEBUG 246 // DEBUG
247 llOwnerSay("Corrade is not online, sleeping..."); 247 llOwnerSay("Corrade is not online, sleeping...");
248 llSetTimerEvent(30); 248 llSetTimerEvent(30);
249 return; 249 return;
250 } 250 }
251 state notify; 251 state notify;
252 } 252 }
253 on_rez(integer num) { 253 on_rez(integer num) {
254 llResetScript(); 254 llResetScript();
255 } 255 }
256 changed(integer change) { 256 changed(integer change) {
257 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 257 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
258 llResetScript(); 258 llResetScript();
259 } 259 }
260 } 260 }
261 } 261 }
262 262
263 state notify { 263 state notify {
264 state_entry() { 264 state_entry() {
265 // DEBUG 265 // DEBUG
266 llOwnerSay("Binding to the local message notification..."); 266 llOwnerSay("Binding to the local message notification...");
267 llInstantMessage( 267 llInstantMessage(
268 (key)CORRADE, 268 (key)CORRADE,
269 wasKeyValueEncode( 269 wasKeyValueEncode(
270 [ 270 [
271 "command", "notify", 271 "command", "notify",
272 "group", wasURLEscape(GROUP), 272 "group", wasURLEscape(GROUP),
273 "password", wasURLEscape(PASSWORD), 273 "password", wasURLEscape(PASSWORD),
274 "action", "set", 274 "action", "set",
275 "type", "local", 275 "type", "local",
276 "URL", wasURLEscape(callback), 276 "URL", wasURLEscape(callback),
277 "callback", wasURLEscape(callback) 277 "callback", wasURLEscape(callback)
278 ] 278 ]
279 ) 279 )
280 ); 280 );
281 } 281 }
282 http_request(key id, string method, string body) { 282 http_request(key id, string method, string body) {
283 llHTTPResponse(id, 200, "OK"); 283 llHTTPResponse(id, 200, "OK");
284 if(wasKeyValueGet("command", body) != "notify" || 284 if(wasKeyValueGet("command", body) != "notify" ||
285 wasKeyValueGet("success", body) != "True") { 285 wasKeyValueGet("success", body) != "True") {
286 // DEBUG 286 // DEBUG
287 llOwnerSay("Failed to bind to the local chat notification..."); 287 llOwnerSay("Failed to bind to the local chat notification...");
288 state detect; 288 state detect;
289 } 289 }
290 // DEBUG 290 // DEBUG
291 llOwnerSay("Local chat notification installed..."); 291 llOwnerSay("Local chat notification installed...");
292 state chat; 292 state chat;
293 } 293 }
294 on_rez(integer num) { 294 on_rez(integer num) {
295 llResetScript(); 295 llResetScript();
296 } 296 }
297 changed(integer change) { 297 changed(integer change) {
298 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 298 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
299 llResetScript(); 299 llResetScript();
300 } 300 }
301 } 301 }
302 } 302 }
303   303  
304 state chat { 304 state chat {
305 state_entry() { 305 state_entry() {
306 // DEBUG 306 // DEBUG
307 llOwnerSay("Waiting for local chat message..."); 307 llOwnerSay("Waiting for local chat message...");
308 llSetTimerEvent(5); 308 llSetTimerEvent(5);
309 } 309 }
310 timer() { 310 timer() {
311 llRequestAgentData((key)CORRADE, DATA_ONLINE); 311 llRequestAgentData((key)CORRADE, DATA_ONLINE);
312 } 312 }
313 dataserver(key id, string data) { 313 dataserver(key id, string data) {
314 if(data == "1") return; 314 if(data == "1") return;
315 // DEBUG 315 // DEBUG
316 llOwnerSay("Corrade is not online, sleeping..."); 316 llOwnerSay("Corrade is not online, sleeping...");
317 // Switch to detect loop and wait there for Corrade to come online. 317 // Switch to detect loop and wait there for Corrade to come online.
318 state detect; 318 state detect;
319 } 319 }
320 http_request(key id, string method, string body) { 320 http_request(key id, string method, string body) {
321 llHTTPResponse(id, 200, "OK"); 321 llHTTPResponse(id, 200, "OK");
322 firstname = wasURLUnescape(wasKeyValueGet("firstname", body)); 322 firstname = wasURLUnescape(wasKeyValueGet("firstname", body));
323 lastname = wasURLUnescape(wasKeyValueGet("lastname", body)); 323 lastname = wasURLUnescape(wasKeyValueGet("lastname", body));
324 // DEBUG 324 // DEBUG
325 message = wasKeyValueGet("message", body); 325 message = wasKeyValueGet("message", body);
326 if(message != "") { 326 if(message != "") {
327 llOwnerSay("Got local chat from: " + firstname + " " + lastname); 327 llOwnerSay("Got local chat from: " + firstname + " " + lastname);
328 state process; 328 state process;
329 } 329 }
330 } 330 }
331 on_rez(integer num) { 331 on_rez(integer num) {
332 llResetScript(); 332 llResetScript();
333 } 333 }
334 changed(integer change) { 334 changed(integer change) {
335 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 335 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
336 llResetScript(); 336 llResetScript();
337 } 337 }
338 } 338 }
339 } 339 }
340   340  
341 state process { 341 state process {
342 state_entry() { 342 state_entry() {
343 // DEBUG 343 // DEBUG
344 llOwnerSay("Sending message to Corrade's AI facility..."); 344 llOwnerSay("Sending message to Corrade's AI facility...");
345 llInstantMessage(CORRADE, 345 llInstantMessage(CORRADE,
346 wasKeyValueEncode( 346 wasKeyValueEncode(
347 [ 347 [
348 "command", "ai", 348 "command", "ai",
349 "group", wasURLEscape(GROUP), 349 "group", wasURLEscape(GROUP),
350 "password", wasURLEscape(PASSWORD), 350 "password", wasURLEscape(PASSWORD),
351 "action", "process", 351 "action", "process",
352 "message", wasURLEscape(message), 352 "message", wasURLEscape(message),
353 "callback", wasURLEscape(callback) 353 "callback", wasURLEscape(callback)
354 ] 354 ]
355 ) 355 )
356 ); 356 );
357 llSetTimerEvent(5); 357 llSetTimerEvent(5);
358 } 358 }
359 timer() { 359 timer() {
360 llRequestAgentData((key)CORRADE, DATA_ONLINE); 360 llRequestAgentData((key)CORRADE, DATA_ONLINE);
361 } 361 }
362 dataserver(key id, string data) { 362 dataserver(key id, string data) {
363 if(data == "1") return; 363 if(data == "1") return;
364 // DEBUG 364 // DEBUG
365 llOwnerSay("Corrade is not online, sleeping..."); 365 llOwnerSay("Corrade is not online, sleeping...");
366 // Switch to detect loop and wait there for Corrade to come online. 366 // Switch to detect loop and wait there for Corrade to come online.
367 state detect; 367 state detect;
368 } 368 }
369 http_request(key id, string method, string body) { 369 http_request(key id, string method, string body) {
370 llHTTPResponse(id, 200, "OK"); 370 llHTTPResponse(id, 200, "OK");
371 // DEBUG 371 // DEBUG
372 llOwnerSay("Sending answer to: " + firstname + " " + lastname); 372 llOwnerSay("Sending answer to: " + firstname + " " + lastname);
373 llInstantMessage(CORRADE, 373 llInstantMessage(CORRADE,
374 wasKeyValueEncode( 374 wasKeyValueEncode(
375 [ 375 [
376 "command", "tell", 376 "command", "tell",
377 "group", wasURLEscape(GROUP), 377 "group", wasURLEscape(GROUP),
378 "password", wasURLEscape(PASSWORD), 378 "password", wasURLEscape(PASSWORD),
379 "entity", "local", 379 "entity", "local",
380 "message", wasKeyValueGet("data", body) 380 "message", wasKeyValueGet("data", body)
381 ] 381 ]
382 ) 382 )
383 ); 383 );
384 state chat; 384 state chat;
385 } 385 }
386 on_rez(integer num) { 386 on_rez(integer num) {
387 llResetScript(); 387 llResetScript();
388 } 388 }
389 changed(integer change) { 389 changed(integer change) {
390 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 390 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
391 llResetScript(); 391 llResetScript();
392 } 392 }
393 } 393 }
394 } 394 }
395   395