The jokes have been extracted from Taivo Pungas' joke-dataset GitHub repository and filtered to fit Second Life limits (such as maximal group message length).
The script can be used as it is provided by manually adding jokes or it can be shunted with the provided jokes database.
To shunt the database with the jokes extracted from Tavio's repository, check out the corrade-lsl-templates/eggdrop Subversion respository using an SVN client and locate the corrade-eggdrop-joke.sql
file.
Next, import the jokes database into the group database, for instance, by using the command-line sqlite3
SQLite client:
sqlite3 e269893f-a570-0087-930e-6ba2a0b77f9c.sqlite < corrade-eggdrop-joke.sql
where:
e269893f-a570-0087-930e-6ba2a0b77f9c.sqlite
is a group database located under the Corrade folder at Databases/e269893f-a570-0087-930e-6ba2a0b77f9c.sqlite
.
Finally, the database must be modified in order to change the group name since it is by default set to [Wizardry and Steamworks]:Support
. Open up the database using the command-line SQLite client:
sqlite3 e269893f-a570-0087-930e-6ba2a0b77f9c.sqlite
and issue:
UPDATE "corrade-eggdrop-joke" SET name='YOUR_GROUP_NAME';
where:
YOUR_GROUP_NAME
should be replaced by the group name that the joke module runs for.When the script starts, an attempt is made to create the database if it does not already exist and then jokes are counted in order to speed up retrieval. Jokes can then be requested by typing in group chat:
@joke
which will make the script display a joke along with the avatar name that added the joke and the joke id
.
What do you call a substance that makes people attracted to both genders? A bi-product! [Ectogram Resident/2541]
The joke id
can then be used to remove a joke, for instance, by issuing:
@joke remove 2541
Conversely, new jokes can be added by issuing:
@joke add Why did the chicken cross the road? To get to the other side.
which will return a message indicating the joke ID that can then be used for other operations.
Furthermore, the module allows querying a joke by joke ID, simply by specifying the ID in group chat:
@joke 44532
which will return the joke with ID 44532
.
/////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2018 - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// // // A database-based joke module for Corrade Eggdrop. // /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueGet(string k, string data) { if(llStringLength(data) == 0) return ""; if(llStringLength(k) == 0) return ""; list a = llParseStringKeepNulls(data, ["&", "="], []); integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]); if(i != -1) return llList2String(a, 2*i+1); return ""; } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// string wasKeyValueEncode(list data) { list k = llList2ListStrided(data, 0, -1, 2); list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); data = []; do { data += llList2String(k, 0) + "=" + llList2String(v, 0); k = llDeleteSubList(k, 0, 0); v = llDeleteSubList(v, 0, 0); } while(llGetListLength(k) != 0); return llDumpList2String(data, "&"); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// // http://was.fm/secondlife/wanderer vector wasCirclePoint(float radius) { float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2); if(llPow(x,2) + llPow(y,2) <= llPow(radius,2)) return <x, y, 0>; return wasCirclePoint(radius); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// // escapes a string in conformance with RFC1738 string wasURLEscape(string i) { string o = ""; do { string c = llGetSubString(i, 0, 0); i = llDeleteSubString(i, 0, 0); if(c == "") jump continue; if(c == " ") { o += "+"; jump continue; } if(c == "\n") { o += "%0D" + llEscapeURL(c); jump continue; } o += llEscapeURL(c); @continue; } while(i != ""); return o; } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// list wasCSVToList(string csv) { list l = []; list s = []; string m = ""; do { string a = llGetSubString(csv, 0, 0); csv = llDeleteSubString(csv, 0, 0); if(a == ",") { if(llList2String(s, -1) != "\"") { l += m; m = ""; jump continue; } m += a; jump continue; } if(a == "\"" && llGetSubString(csv, 0, 0) == a) { m += a; csv = llDeleteSubString(csv, 0, 0); jump continue; } if(a == "\"") { if(llList2String(s, -1) != a) { s += a; jump continue; } s = llDeleteSubList(s, -1, -1); jump continue; } m += a; @continue; } while(csv != ""); // postcondition: length(s) = 0 return l + m; } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// string wasListToCSV(list l) { list v = []; do { string a = llDumpList2String( llParseStringKeepNulls( llList2String( l, 0 ), ["\""], [] ), "\"\"" ); if(llParseStringKeepNulls( a, [" ", ",", "\n", "\""], [] ) != (list) a ) a = "\"" + a + "\""; v += a; l = llDeleteSubList(l, 0, 0); } while(l != []); return llDumpList2String(v, ","); } /////////////////////////////////////////////////////////////////////////// // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // /////////////////////////////////////////////////////////////////////////// // unescapes a string in conformance with RFC1738 string wasURLUnescape(string i) { return llUnescapeURL( llDumpList2String( llParseString2List( llDumpList2String( llParseString2List( i, ["+"], [] ), " " ), ["%0D%0A"], [] ), "\n" ) ); } // configuration data string configuration = ""; // store message over state. string firstname = ""; string lastname = ""; string group = ""; string data = ""; string action = ""; string statement = ""; string parameters = ""; default { state_entry() { llOwnerSay("[Joke] Starting module..."); llSetTimerEvent(10); } link_message(integer sender, integer num, string message, key id) { if(id != "configuration") return; llOwnerSay("[Joke] Got configuration..."); configuration = message; action = "create_database"; state trampoline; } timer() { llOwnerSay("[Joke] Requesting configuration..."); llMessageLinked(LINK_THIS, 0, "configuration", NULL_KEY); } on_rez(integer num) { llResetScript(); } changed(integer change) { if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) { llResetScript(); } } state_exit() { llSetTimerEvent(0); } } state trampoline { state_entry() { if(action == "create_database") { statement = wasURLEscape("CREATE TABLE IF NOT EXISTS \"" + wasKeyValueGet("joke table", configuration) + "\" (data text(1023), name text(35), firstname text(31), lastname text(31), id integer NOT NULL PRIMARY KEY)"); state query; } if(action == "random") { statement = wasURLEscape("SELECT * FROM \"" + wasKeyValueGet("joke table", configuration) + "\" WHERE name=:group ORDER BY RANDOM() LIMIT 1"); parameters = wasURLEscape( wasListToCSV( [ "group", wasURLEscape( wasKeyValueGet( "group", configuration ) ) ] ) ); state query; } if(action == "id") { statement = wasURLEscape("SELECT * FROM \"" + wasKeyValueGet("joke table", configuration) + "\" WHERE name=:group AND id=:id"); parameters = wasURLEscape( wasListToCSV( [ "group", wasURLEscape( wasKeyValueGet( "group", configuration ) ), "id", data ] ) ); state query; } if(action == "search") { statement = wasURLEscape("SELECT * FROM \"" + wasKeyValueGet("joke table", configuration) + "\" WHERE name=:group AND data LIKE :data COLLATE NOCASE ORDER BY RANDOM() LIMIT 1"); parameters = wasURLEscape( wasListToCSV( [ "group", wasURLEscape( wasKeyValueGet( "group", configuration ) ), "data", wasURLEscape("%" + llDumpList2String(llParseString2List(data, [" "], []), "%") + "%") ] ) ); state query; } if(action == "remove") { statement = wasURLEscape("DELETE FROM \"" + wasKeyValueGet("joke table", configuration) + "\" WHERE name=:name AND id=:id"); parameters = wasURLEscape( wasListToCSV( [ "name", wasURLEscape( wasKeyValueGet( "group", configuration ) ), "id", data ] ) ); state query; } if(action == "add") { statement = wasURLEscape("INSERT INTO \"" + wasKeyValueGet("joke table", configuration) + "\" (name, data, firstname, lastname) VALUES (:name, :data, :firstname, :lastname)"); parameters = wasURLEscape( wasListToCSV( [ "name", wasURLEscape( wasKeyValueGet( "group", configuration ) ), "data", wasURLEscape(data), "firstname", wasURLEscape(firstname), "lastname", wasURLEscape(lastname) ] ) ); state query; } if(action == "get_joke_id") { statement = wasURLEscape("SELECT MAX(id) AS LAST FROM \"" + wasKeyValueGet("joke table", configuration) + "\""); state query; } if(action == "by") { statement = wasURLEscape("SELECT * FROM \"" + wasKeyValueGet("joke table", configuration) + "\" WHERE name=:group AND firstname=:firstname AND lastname=:lastname ORDER BY RANDOM() LIMIT 1"); parameters = wasURLEscape( wasListToCSV( [ "group", wasURLEscape( wasKeyValueGet( "group", configuration ) ), "firstname", wasURLEscape(firstname), "lastname", wasURLEscape(lastname) ] ) ); state query; } // DEBUG llOwnerSay("[Joke] Jump table corrupted, please contact creator..."); llResetScript(); } on_rez(integer num) { llResetScript(); } changed(integer change) { if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) { llResetScript(); } } } state query { state_entry() { // Check messge length. string message = wasKeyValueEncode( [ "command", "database", "group", wasURLEscape( wasKeyValueGet( "group", configuration ) ), "password", wasURLEscape( wasKeyValueGet( "password", configuration ) ), "SQL", statement, "data", parameters, "callback", wasURLEscape( wasKeyValueGet( "URL", configuration ) ) ] ); // GC - none of these are needed anymore. statement = ""; parameters = ""; // Message length check. if(llStringLength(message) > 1023) { data = "Message length exceeded 1023 characters."; state tell; } // DEBUG llOwnerSay("[Joke] Executing action: " + action); llInstantMessage( wasKeyValueGet( "corrade", configuration ), message ); // GC message = ""; llSetTimerEvent(60); } link_message(integer sender, integer num, string body, key id) { // Only process callbacks for the database command. if(id != "callback" || wasKeyValueGet("command", body) != "database") return; if(wasKeyValueGet("success", body) != "True") { // DEBUG llOwnerSay("[Joke] Unable query database: " + wasURLUnescape( wasKeyValueGet("error", body) ) ); state listen_group; } if(action == "create_database") { llOwnerSay("[Joke] Database created!"); state listen_group; } if(action == "random" || action == "id" || action == "search" || action == "by") { list result = wasCSVToList( wasURLUnescape( wasKeyValueGet("data", body) ) ); if(llGetListLength(result) != 10) { data = "No joke found. . ."; state tell; } data = llList2String( result, llListFindList(result, ["data"]) + 1 ); firstname = llList2String( result, llListFindList(result, ["firstname"]) + 1 ); lastname = llList2String( result, llListFindList(result, ["lastname"]) + 1 ); string id = llList2String( result, llListFindList(result, ["id"]) + 1 ); // Build data to be sent. data += " " + "[" + firstname + " " + lastname + "/" + id + "]"; state tell; } if(action == "remove") { data = "Joke " + data + " has been removed."; state tell; } if(action == "add") { action = "get_joke_id"; data = body; state trampoline; } if(action == "get_joke_id") { list result = wasCSVToList( wasURLUnescape( wasKeyValueGet("data", body) ) ); data = llList2String( result, llListFindList(result, ["LAST"]) + 1 ); data = "Joke " + data + " has been stored."; state tell; } // DEBUG llOwnerSay("[Joke] Jump table corrupted, please contact creator..."); state listen_group; } timer() { state listen_group; } on_rez(integer num) { llResetScript(); } changed(integer change) { if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) { llResetScript(); } } state_exit() { llSetTimerEvent(0); } } state listen_group { state_entry() { // DEBUG llOwnerSay("[Joke] Waiting for group messages."); } link_message(integer sender, integer num, string message, key id) { // We only care about notifications now. if(id != "notification") return; // This script only processes group notifications. if(wasKeyValueGet("type", message) != "group" || (wasKeyValueGet("type", message) == "group" && wasURLUnescape(wasKeyValueGet("group", message)) != wasKeyValueGet("group", configuration))) return; // Get the message sender. firstname = wasURLUnescape( wasKeyValueGet( "firstname", message ) ); lastname = wasURLUnescape( wasKeyValueGet( "lastname", message ) ); // Get the sent message. data = wasURLUnescape( wasKeyValueGet( "message", message ) ); // Check if this is an eggdrop command. if(llGetSubString(data, 0, 0) != wasKeyValueGet("command", configuration)) return; // Check if the command matches the current module. list command = llParseString2List(data, [" "], []); if(llList2String(command, 0) != wasKeyValueGet("command", configuration) + "joke") return; // Remove command. command = llDeleteSubList(command, 0, 0); // Remove action. action = llList2String(command, 0); // Jump to the "add" state for adding if(action == "add") { command = llDeleteSubList(command, 0, 0); data = llDumpList2String(command, " "); if(data == "") { data = "The joke's too short to be funny."; state tell; } action = "add"; state trampoline; } // Jump to the "remove" state for removing if(action == "remove") { command = llDeleteSubList(command, 0, 0); data = llDumpList2String(command, " "); if((integer)data == 0) { data = "Which one though? Please provide a joke id."; state tell; } action = "remove"; state trampoline; } if(action == "by") { command = llDeleteSubList(command, 0, 0); firstname = llList2String(command, 0); command = llDeleteSubList(command, 0, 0); lastname = llList2String(command, 0); command = llDeleteSubList(command, 0, 0); data = llDumpList2String(command, " "); if(llStringLength(firstname) == 0 || llStringLength(lastname) == 0) { data = "First and Last name is required."; state tell; } action = "by"; state trampoline; } string index = llList2String(command, 0); command = llDeleteSubList(command, 0, 0); data = llDumpList2String(command, " "); if(index == "search") { action = "search"; state trampoline; } if((integer)index <= 0) { action = "random"; state trampoline; } data = index; action = "id"; state trampoline; } on_rez(integer num) { llResetScript(); } changed(integer change) { if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) { llResetScript(); } } } state tell { state_entry() { // DEBUG llOwnerSay("[Joke] Sending to group."); llInstantMessage( wasKeyValueGet( "corrade", configuration ), wasKeyValueEncode( [ "command", "tell", "group", wasURLEscape( wasKeyValueGet( "group", configuration ) ), "password", wasURLEscape( wasKeyValueGet( "password", configuration ) ), "entity", "group", "message", wasURLEscape(data) ] ) ); state listen_group; } }