corrade-lsl-templates

Subversion Repositories:
Compare Path: Rev
With Path: Rev
?path1? @ 7  →  ?path2? @ 8
/source/eggdrop/Fortune.txt
@@ -0,0 +1,83 @@
A closed mouth gathers no feet.
A journey of a thousand miles begins with a cash advance.
A king's castle is his home.
A penny saved is ridiculous.
All that glitters has a high refractive index.
Ambition a poor excuse for not having enough sense to be lazy.
Anarchy is better that no government at all.
Any small object when dropped will hide under a larger object.
As you read the scroll, it vanishes...
Automobile - A mechanical device that runs up hills and down people.
Be moderate where pleasure is concerned, avoid fatigue.
Of the choice of two evils, I pick the one I've never tried before.
Brain -- the apparatus with which we think that we think.
BATCH - A group, kinda like a herd.
Computer hackers do it all night long.
Computer modelers simulate it first.
Computer programmers don't byte, they nybble a bit.
Computer programmers know how to use their hardware.
Computers are not intelligent. They only think they are.
Courage is your greatest present need.
CLEARASOL - Effective sunspot remover.
Death is life's way of telling you you've been fired.
Death is Nature's way of saying 'slow down'.
Do something unusual today. Accomplish work on the computer.
Documentation is like sex: When it's good, it's fantastic, when it's bad...
Don't force it, get a larger hammer.
Don't hate yourself in the morning -- sleep till noon.
Drive defensively -- buy a tank.
Earn cash in your spare time -- blackmail friends.
Entropy isn't what it used to be.
Fairy tales: horror stories for children to get them use to reality.
Familiarity breeds children.
God didn't create the world in 7 days. He pulled an all-nighter on the 6th.
Going the speed of light is bad for your age.
GAY ABANDON - Homosexual repellent perfume.
He who hesitates is sometimes saved.
Health is merely the slowest possible rate at which one can die.
Help support helpless victims of computer error.
Herblock's Law: if it is good, they will stop making it.
History does not repeat itself, -- historians merely repeat each other.
I'm defending her honor, which is more than she ever did.
If you don't change your direction, you may end up where you were headed.
If you're not part of the solution, be part of the problem!
In the field of observation, chance favors only the prepared minds.
It is a miracle that curiosity survives formal education. Albert Einstein
It works better if you plug it in.
It's not hard to meet expenses, they're everywhere.
Jury -- Twelve people who determine which client has the better lawyer.
KODACLONE - duplicating film.
Let not the sands of time get in your lunch.
Life is what happens to you while you are planning to do something else.
Life's a bitch, then you die.
Lynch's Law: When the going gets tough, everyone leaves.
Mediocrity thrives on standardization.
MOP AND GLOW - Floor wax used by Three Mile Island cleanup team.
Never lick a gift horse in the mouth.
Old MacDonald had an agricultural real estate tax abatement.
Quoting one is plagiarism. Quoting many is research.
QUARKBAR - the candy with flavour and charm.
QUASIMOTO - 4 wheeled hard-top moped made in France.
Reality's the only obstacle to happiness.
Screw up your life, you've screwed everything else up.
Silver's law: If Murphy's law can go wrong it will.
Some grow with responsibility, others just swell.
SQWERTY - Computer keyboard sized down for use by children.
SYSTEM GOING DOWN AT 4:45 THIS AFTERNOON FOR DISK CRASHING.
The attention span of a computer is as long as its electrical cord.
The only difference between a rut and a grave is the depth.
The only way to get rid of temptation is to yield to it.
The road to to success is always under construction.
Those who can't write, write help files.
To be, or not to be, those are the parameters.
To err is human, to really foul things up requires a computer.
Today is the last day of your life so far.
TRAPEZOID - A device for catching zoids.
Wasting time is an important part of life.
When all else fails, read the instructions.
When in doubt, don't bother.
Xerox does it again and again and again and...
XMODEM - A spot-marking transfer protocol.
YTERM - A terminal program for queries.
When in doubt, ignore it.
I'd insult you, but you're not bright enough to notice.
/source/eggdrop/Joke.txt
@@ -0,0 +1,67 @@
Can a kangaroo jump higher than a house? Of course, a house doesn’t jump at all.
Doctor: "I'm sorry but you suffer from a terminal illness and have only 10 to live." Patient: "What do you mean, 10? 10 what? Months? Weeks?!" Doctor: "Nine."
A man asks a farmer near a field, “Sorry sir, would you mind if I crossed your field instead of going around it? You see, I have to catch the 4:23 train.” The farmer says, “Sure, go right ahead. And if my bull sees you, you’ll even catch the 4:11 one.”
Anton, do you think I’m a bad mother? My name is Paul.
My dog used to chase people on a bike a lot. It got so bad, finally I had to take his bike away.
What is the difference between a snowman and a snowwoman? Snowballs.
"Mom, where do tampons go?" / "Where the babies come from, darling." / "In the stork?"
Police officer: "Can you identify yourself, sir?" / Driver pulls out his mirror and says: "Yes, it's me."
Some nice Chinese couple gave me a very good camera down by the Washington Monument. I didn’t really understand what they were saying, but it was very nice of them.
Dentist: "You need a crown." / Patient: "Finally someone who understands me"
Two flies are sitting on a pile of dog poop. One suggests to the other: “Do you want to hear a really good joke?” The other fly replies: “But nothing disgusting like last time, I’m trying to eat here!”
Coco Chanel once said that you should put perfume on places where you want to be kissed by a man. But hell does that burn!
Me and my wife decided that we don't want to have children anymore. So anybody who wants one can leave us their phone number and address and we will bring you one.
It is so cold outside I saw a politician with his hands in his own pockets.
In a boomerang shop: "I'd like to buy a new boomerang please. Also, can you tell me how to throw the old one away?"
Patient: Oh doctor, I’m just so nervous. This is my first operation. Doctor: Don't worry. Mine too.
Why is women’s soccer so rare? It’s quite hard to find enough women willing to wear the same outfit.
Guest at a restaurant: “I refuse to eat this roastbeef. Please call the manager!“ Waiter: “That’s no use. He won’t eat it either.”
“You are so kind, funny and beautiful.” / “Oh come on. You just want to get me to bed.” / “And smart, too!”
Why haven’t you ever seen any elephants hiding up trees? Because they’re really, really good at it.
Two elephants meet a totally naked guy. After a while one elephant says to the other: “I really don’t get how he can feed himself with that thing!”
"Grandpa, why don't you have any life insurance?" / "So you can all be really sad when I die."
A wife is like a hand grenade. Take off the ring and say good bye to your house.
I’m certain there are female hormones in beer. When I drink too much, I talk nonsense and I cannot control my car.
Man: Hi, do you want to dance? / Woman: Yeah, sure! / Man: Great, go and dance, I want to talk to your pretty friend!
Waiter, I am outraged. There is one hair in my soup. And what do you expect for this price? A whole wig?!
I got another letter from this lawyer today. It said “Final Notice”. Good that he will not bother me anymore.
Yes, money cannot buy you happiness, but I’d still feel a lot more comfortable crying in a new BMW than on a bike.
Meanwhile in a parallel universe: “Oh for God’s sake! Where are all these extra single socks coming from?!”
I have a bumper sticker saying, "Honk if you think I'm sexy". Some days I just stand at a green light till I’m feeling good about myself.
I met two guys wearing matching clothing. So I asked them if they were gay. They promptly arrested me.
Did anyone notice that the “&”symbol looks like a dog dragging his butt across the floor?
My car horn now sounds like gunshots. People move out of the way much faster recently.
Police officer to a driver: “OK, driver’s license, vehicle license, first aid kit and warning triangle.” / Driver: “Nah, I’ve already got all that. But how much for that funny Captain’s cap?“
Not every badly unkempt guy is homeless. It could well be that he lives with 3 females and only 1 bathroom.
Do not go to the bathroom in a dream. It’s a trap!
aw a poster today, somebody was asking “Have you seen my cat?” So I called the number and said that I didn’t. - I like to help where I can.
I read the mass chicken farms pump chickens full of antibiotics. Well, that would at least explain why chicken soup is so good when you have a cold.
What do you call the soft tissue between a shark's teeth? The slow swimmer.
I called the hospital but the line was dead.
I fear my neighbor may be stalking me, she's been googling my name last night on her computer. I saw it clearly through my binoculars.
You know you’re old when your friends start having kids on purpose.
Why do people never eat clocks? Because it’s really time consuming.
Backing rapidly at a tree significantly reduces your trunk space.
If you step on someone’s foot, they open their mouth – just like a garbage bin.
My head is very slowly 3D printing my hair.
Sweater is a pretty disgusting name for a piece of clothing.
Bill Gates and I have a combined fortune of approximately 80 billion dollars.
It would be very nice if the car navigation voice would get more and more excited as you'd get closer to your destination.
Are those who sneeze the most blessed?
I wonder what dirty talk looks like in sign language.
When a pregnant woman takes a bath, she’s become a human submarine.
The first parents ever to have identical twins must have been really confused.
The Titanic’s sinking was a true miracle to the lobsters in the kitchens.
If every person on Earth blinked at the same time, nobody would ever find out.
When you clap, you hit yourself repeatedly because you like it.
I’d love to know how the phrase “when the shit hits the fan” came into being – with dates, names and pictures.
Chances are, good looking nurses and doctors never get accurate blood pressure level readings from their patients of the opposite gender.
The next generation kids will be able to look up their parents on the internet and see their whole lives documented, no excuses.
Tissues in a box should have different colors so you’d be warned that you’re approaching the last tissue.
What is white and flies up? A retarded snowflake
Why are pigs not allowed to ride bikes? Because they lack the thumbs to ring the bell.
At work: Excuse me, may I disturb you shortly? / Of course, what is it? / Nothing, I just wanted to disturb you.
Andy has 150 candy bars. He eats 125. What does Andy have now? Andy has diabetes now.
What is yellow and cannot swim? An excavator! And why? Because it only has one arm.
Why do bees hum? They don't remember the text!
What do you get when you cross a dog and an antenna? A Golden Receiver.
/source/eggdrop/ban.lsl
@@ -0,0 +1,584 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// A module that bans group members using fuzzy name matching.
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, 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"
)
);
}
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
list wasSetIntersect(list a, list b) {
if(llGetListLength(a) == 0) return [];
string i = llList2String(a, 0);
a = llDeleteSubList(a, 0, 0);
if(llListFindList(b, (list)i) == -1)
return wasSetIntersect(a, b);
return i + wasSetIntersect(a, b);
}
 
// configuration data
string configuration = "";
// callback URL
string URL = "";
// store message over state.
string data = "";
// banee
string firstname = "";
string lastname = "";
 
default {
state_entry() {
llOwnerSay("[Ban] Starting...");
llSetTimerEvent(10);
}
link_message(integer sender, integer num, string message, key id) {
if(id != "configuration") return;
llOwnerSay("[Ban] Got configuration...");
configuration = message;
state listen_group;
}
timer() {
llOwnerSay("[Ban] 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 listen_group {
state_entry() {
// DEBUG
llOwnerSay("[Ban] 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")
return;
// Get the sent message.
data = wasURLUnescape(
wasKeyValueGet(
"message",
message
)
);
if(llGetSubString(data, 0, 0) !=
wasKeyValueGet("command", configuration))
return;
list command = llParseString2List(data, ["@", " "], []);
if(llList2String(command, 0) != "ban")
return;
firstname = wasKeyValueGet("firstname", message);
lastname = wasKeyValueGet("lastname", message);
if(firstname == "" || lastname == "") {
data = "And who would yarr be?";
state tell;
}
// Remove command.
command = llDeleteSubList(command, 0, 0);
// Dump the rest of the message.
data = llDumpList2String(command, " ");
// Get an URL.
state url;
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
}
 
state url {
state_entry() {
// DEBUG
llOwnerSay("[Ban] Requesting URL...");
llRequestURL();
}
http_request(key id, string method, string body) {
if(method != URL_REQUEST_GRANTED) return;
URL = body;
// DEBUG
llOwnerSay("[Ban] Got URL...");
state get_caller_roles;
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
}
 
state get_caller_roles {
state_entry() {
// DEBUG
llOwnerSay("[Ban] Searching for caller...");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "getmemberroles",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"firstname", firstname,
"lastname", lastname,
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "getmemberroles" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Ban] Unable to get member roles: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
llReleaseURL(URL);
state listen_group;
}
// Dump the roles to a list.
list roles = wasCSVToList(
wasURLUnescape(
wasKeyValueGet("data", body)
)
);
if(llGetListLength(
wasSetIntersect(roles,
wasCSVToList(
wasKeyValueGet(
"admin roles", configuration
)
)
)
) == 0) {
data = "You ain't got the cojones!";
llReleaseURL(URL);
state tell;
}
list banee = llParseString2List(data, [" "], []);
firstname = llList2String(banee, 0);
lastname = llList2String(banee, 1);
if(firstname == "" || lastname == "") {
data = "Full name required.";
state tell;
}
// GC
banee = [];
state get_banee_roles;
}
timer() {
llReleaseURL(URL);
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 get_banee_roles {
state_entry() {
// DEBUG
llOwnerSay("[Ban] Searching for banee...");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "getmemberroles",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"firstname", firstname,
"lastname", lastname,
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "getmemberroles" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Ban] Unable to get member roles: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
llReleaseURL(URL);
state listen_group;
}
string result = wasURLUnescape(
wasKeyValueGet("data", body)
);
if(result != "" && llListFindList(wasCSVToList(result), (list)"Owners") != -1) {
data = "Ejectee is an owner. I'm not gonna open the pod bay doors.";
llReleaseURL(URL);
state tell;
}
state ban;
}
timer() {
llReleaseURL(URL);
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 ban {
state_entry() {
// DEBUG
llOwnerSay("[Ban] Banning...");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "ban",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"action", "ban",
"avatars", wasURLEscape(
wasListToCSV(
[
firstname + " " + lastname
]
)
),
"eject", "True",
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
llReleaseURL(URL);
if(wasKeyValueGet("command", body) != "ban" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Ban] Unable to ban member: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
state listen_group;
}
data = "Hasta la vista, baby!";
state tell;
}
timer() {
llReleaseURL(URL);
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 tell {
state_entry() {
// DEBUG
llOwnerSay("[Ban] 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;
}
}
/source/eggdrop/configuration.txt
@@ -0,0 +1,39 @@
########################## START CONFIGURATION ############################
 
# This is a configuration notecard based on the key-value data Wizardry and
# Steamworks reader. Everything following the "#" character is ignored
# along with blank lines. Values can be set for various parameters in a
# simple and understandable format with the following syntax:
# KEY = "VALUE"
# Every time you change this configuration notecard, the script will reset
# itself and the new configuration will be read from this notecard.
 
# The "corrade", "group" and "password" settings must correspond to your
# settings in Corrade.ini otherwise the script will not work at all.
 
# Set this to the UUID of the Corrade bot.
# Corrade Resident
corrade = "2783a9d0-7e5d-4598-b127-d88ebdf1091d"
 
# The name of the group - it can also be the UUID of the group.
group = "My Group"
 
# The password for the group.
password = "mypassword"
 
# The version that this HUD is compatible with.
version = 9.163
 
# The marker to be used with all commands.
command = @
 
# The range for the dice rolling command (inclusive).
roll range = 3,64
 
# The roles that are eligible for administrative group functions.
admin roles = Owners,Officers,Ecto
 
# Restrict wiki operations to admin roles.
restricted wiki = True
 
########################### END CONFIGURATION #############################
/source/eggdrop/control.lsl
@@ -0,0 +1,510 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// An eggdrop-like group bot using Corrade.
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(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) 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 //
///////////////////////////////////////////////////////////////////////////
// unescapes a string in conformance with RFC1738
string wasURLUnescape(string i) {
return llUnescapeURL(
llDumpList2String(
llParseString2List(
llDumpList2String(
llParseString2List(
i,
["+"],
[]
),
" "
),
["%0D%0A"],
[]
),
"\n"
)
);
}
 
///////////////////////////////////////////////////////////////////////////
// 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, ",");
}
 
// for notecard reading
integer line = 0;
// key-value data will be read into this list
list tuples = [];
string configuration = "";
// Corrade's online status.
integer online = FALSE;
integer compatible = FALSE;
string URL = "";
 
// The notifications to bind to.
list notifications = [ "group", "notice" ];
// The tag that this script uses for notifications.
string EGG_TAG = "147d8bf1-4fbc-4c31-b0ea-1d2a72a41041";
 
default {
state_entry() {
if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
llOwnerSay("[Control] Sorry, could not find a configuration inventory notecard.");
return;
}
// DEBUG
llOwnerSay("[Control] Reading configuration file...");
llGetNotecardLine("configuration", line);
}
dataserver(key id, string data) {
if(data == EOF) {
// invariant, length(tuples) % 2 == 0
if(llGetListLength(tuples) % 2 != 0) {
llOwnerSay("[Control] Error in configuration notecard.");
return;
}
key CORRADE = llList2Key(
tuples,
llListFindList(
tuples,
[
"corrade"
]
)
+1);
if(CORRADE == NULL_KEY) {
llOwnerSay("[Control] Error in configuration notecard: corrade");
return;
}
string GROUP = llList2String(
tuples,
llListFindList(
tuples,
[
"group"
]
)
+1);
if(GROUP == "") {
llOwnerSay("[Control] Error in configuration notecard: group");
return;
}
string PASSWORD = llList2String(
tuples,
llListFindList(
tuples,
[
"password"
]
)
+1);
if(PASSWORD == "") {
llOwnerSay("[Control] Error in configuration notecard: password");
return;
}
string VERSION = llList2String(
tuples,
llListFindList(
tuples,
[
"version"
]
)
+1);
if(VERSION == "") {
llOwnerSay("[Control] Error in configuration notecard: version");
return;
}
// DEBUG
llOwnerSay("[Control] Read configuration notecard...");
configuration = wasKeyValueEncode(tuples);
// GC
tuples = [];
state request_url_notifications;
}
if(data == "") jump continue;
integer i = llSubStringIndex(data, "#");
if(i != -1) data = llDeleteSubString(data, i, -1);
list o = llParseString2List(data, ["="], []);
// get rid of starting and ending quotes
string k = llDumpList2String(
llParseString2List(
llStringTrim(
llList2String(
o,
0
),
STRING_TRIM),
["\""], []
), "\"");
string v = llDumpList2String(
llParseString2List(
llStringTrim(
llList2String(
o,
1
),
STRING_TRIM),
["\""], []
), "\"");
if(k == "" || v == "") jump continue;
tuples += k;
tuples += v;
@continue;
llGetNotecardLine("configuration", ++line);
}
attach(key id) {
llResetScript();
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
llResetScript();
}
}
}
 
state request_url_notifications {
state_entry() {
// DEBUG
llOwnerSay("[Control] Requesting URL...");
llRequestURL();
}
http_request(key id, string method, string body) {
if(method != URL_REQUEST_GRANTED) return;
URL = body;
// DEBUG
llOwnerSay("[Control] Got URL...");
state unbind_notifications;
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
}
 
state unbind_notifications {
state_entry() {
// DEBUG
llOwnerSay("[Control] Releasing notifications...");
llInstantMessage(
(key)wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "notify",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"action", "remove",
"tag", wasURLEscape(EGG_TAG),
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "notify" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Control] Unable to release tag: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
llResetScript();
}
state bind_notifications;
}
timer() {
llOwnerSay("[Control] Timeout releasing notifications");
llResetScript();
}
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 bind_notifications {
state_entry() {
// DEBUG
llOwnerSay("[Control] Binding to notifications...");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "notify",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"action", "add",
"type", wasURLEscape(
wasListToCSV(
notifications
)
),
"URL", wasURLEscape(URL),
"tag", wasURLEscape(EGG_TAG),
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "notify" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Control] Unable to bind notifications: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
llResetScript();
}
state serve_configuration;
}
timer() {
llOwnerSay("[Control] Timeout binding notifications");
llResetScript();
}
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 serve_configuration {
state_entry() {
// DEBUG
llOwnerSay("[Control] Checking version...");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "version",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
llSetTimerEvent(0);
if(wasKeyValueGet("command", body) != "version") {
llMessageLinked(LINK_THIS, 0, body, "notification");
return;
}
if(wasKeyValueGet("success", body) != "True") {
llOwnerSay("[Control] Version check failed...");
return;
}
list v = llParseString2List(
wasKeyValueGet(
"data",
body
),
["."],
[]
);
integer receivedVersion = (integer)(llList2String(v, 0) + llList2String(v, 1));
v = llParseString2List(
wasKeyValueGet(
"version",
configuration
),
["."],
[]
);
integer notecardVersion = (integer)(llList2String(v, 0) + llList2String(v, 1));
if(receivedVersion < notecardVersion) {
llOwnerSay("[Control] Version is incompatible! You need a Corrade of at least version: " +
wasKeyValueGet(
"version",
configuration
) +
" for this HUD."
);
compatible = FALSE;
//llReleaseURL(URL);
return;
}
// DEBUG
llOwnerSay("[Control] Version is compatible!");
compatible = TRUE;
//llReleaseURL(URL);
return;
}
link_message(integer sender, integer num, string message, key id) {
if(message != "configuration") return;
llMessageLinked(LINK_THIS, 0, configuration, "configuration");
}
timer() {
llOwnerSay("[Control] Timeout checking version...");
llResetScript();
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
state_exit() {
llSetTimerEvent(0);
}
}
/source/eggdrop/dice.lsl
@@ -0,0 +1,301 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// A dice roll with a configurable range.
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, 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 = "";
// callback URL
string URL = "";
// store message over state.
string data = "";
 
default {
state_entry() {
llOwnerSay("[Dice] Starting module...");
llSetTimerEvent(10);
}
link_message(integer sender, integer num, string message, key id) {
if(id != "configuration") return;
llOwnerSay("[Dice] Got configuration...");
configuration = message;
state listen_group;
}
timer() {
llOwnerSay("[Dice] 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 listen_group {
state_entry() {
// DEBUG
llOwnerSay("[Dice] 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")
return;
// Get the sent message.
data = wasURLUnescape(
wasKeyValueGet(
"message",
message
)
);
if(llGetSubString(data, 0, 0) !=
wasKeyValueGet("command", configuration))
return;
list command = llParseString2List(data, ["@", " "], []);
if(llList2String(command, 0) != "roll")
return;
list range = wasCSVToList(
wasKeyValueGet("roll range", configuration)
);
integer roll = llList2Integer(command, 1);
if(roll < llList2Integer(range, 0) || roll > llList2Integer(range, 1)) {
data = "Value should be within bounds [" +
llList2String(range, 0) +
"," +
llList2String(range, 1) +
"].";
state tell;
}
data = wasKeyValueGet(
"firstname",
message
) +
" " +
wasKeyValueGet(
"lastname",
message
) + " rolls a " +
(string)((integer)(llFrand(roll + 1)));
state tell;
}
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("[Dice] 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;
}
}
/source/eggdrop/eval.lsl
@@ -0,0 +1,459 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// A module that evaluates a mathematical expression for Corrade Eggdrop.
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, 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"
)
);
}
 
//////////////////////////////////////////////////////////
// Returns a reversed list.
//////////////////////////////////////////////////////////
list wasListReverse(list lst) {
if(llGetListLength(lst)<=1) return lst;
return wasListReverse(llList2List(lst, 1, llGetListLength(lst))) + llList2List(lst,0,0);
}
//////////////////////////////////////////////////////////
// Deletes elements delete from list input.
//////////////////////////////////////////////////////////
list wasSubtractSubList(list input, list delete) {
do {
string tok = llList2String(delete, 0);
list clean = input;
do {
if(llList2String(clean, 0) == tok) {
integer idx = llListFindList(input, (list)tok);
input = llDeleteSubList(input, idx, idx);
}
} while(clean = llDeleteSubList(clean, 0, 0));
} while(delete = llDeleteSubList(delete, 0, 0));
return input;
}
//////////////////////////////////////////////////////////
// Returns a list of operators and operands.
//////////////////////////////////////////////////////////
list wasInfixTokenize(string input) {
list op = [ "+", "-", "(", ")", "%", "*", "/", "^", "sin", "asin", "cos", "acos", "tan", "sqrt", "ln" ];
list result = llParseString2List(input, [], op);
return wasSubtractSubList(result, [" "]);
}
//////////////////////////////////////////////////////////
// Transforms an infix expression to a postfix expression.
//////////////////////////////////////////////////////////
list wasInfixToPostfix(list infix) {
list op = [ "+", "-", "%", "*", "/", "^", "sin", "asin", "cos", "acos", "tan", "sqrt", "ln" ];
list opStack = [];
list result = [];
do {
string t = llList2String(infix, 0);
infix = llDeleteSubList(infix, 0, 0);
if(t == "(") {
opStack += "(";
jump continue;
}
if(t == ")") {
while(llGetListLength(opStack) != 0) {
string topa = llList2String(opStack, llGetListLength(opStack)-1);
opStack = llDeleteSubList(opStack, llGetListLength(opStack)-1, llGetListLength(opStack)-1);
if(topa != "(" && topa != ")") result += topa;
}
opStack = llDeleteSubList(opStack, llGetListLength(opStack)-1, llGetListLength(opStack)-1);
jump continue;
}
integer idx = llListFindList(op, (list)t);
if(idx == -1) {
result += t;
jump continue;
}
@repeat;
string topb = llList2String(opStack, llGetListLength(opStack)-1);
integer odx = llListFindList(op, (list)topb);
if(odx >= idx) {
opStack = llDeleteSubList(opStack, llGetListLength(opStack)-1, llGetListLength(opStack)-1);
result += topb;
if(llGetListLength(opStack) != 0) jump repeat;
}
opStack += t;
@continue;
} while(llGetListLength(infix) != 0);
result += wasListReverse(opStack);
return result;
}
//////////////////////////////////////////////////////////
// Evaluate a postfix expression.
//////////////////////////////////////////////////////////
float wasPostfixEval(list postfix) {
list op = [ "+", "-", "%", "*", "/", "^", "sin", "asin", "cos", "acos", "tan", "sqrt", "ln" ];
list orStack = [];
do {
string t = llList2String(postfix, 0);
postfix = llDeleteSubList(postfix, 0, 0);
integer idx = llListFindList(op, (list)t);
if(idx == -1) {
orStack += t;
jump continue;
}
float a = llList2Float(orStack, llGetListLength(orStack)-1);
orStack = llDeleteSubList(orStack, llGetListLength(orStack)-1, llGetListLength(orStack)-1);
float b = llList2Float(orStack, llGetListLength(orStack)-1);
float r = 0;
if(t == "+") {
orStack = llDeleteSubList(orStack, llGetListLength(orStack)-1, llGetListLength(orStack)-1);
r = b + a;
jump push;
}
if(t == "-") {
orStack = llDeleteSubList(orStack, llGetListLength(orStack)-1, llGetListLength(orStack)-1);
r = b - a;
jump push;
}
if(t == "*") {
orStack = llDeleteSubList(orStack, llGetListLength(orStack)-1, llGetListLength(orStack)-1);
r = b * a;
jump push;
}
if(t == "/") {
orStack = llDeleteSubList(orStack, llGetListLength(orStack)-1, llGetListLength(orStack)-1);
if(a == 0) {
r = (float)"NaN";
jump push;
}
r = b / a;
jump push;
}
if(t == "^") {
orStack = llDeleteSubList(orStack, llGetListLength(orStack)-1, llGetListLength(orStack)-1);
r = llPow(b,a);
jump push;
}
if(t == "%") {
orStack = llDeleteSubList(orStack, llGetListLength(orStack)-1, llGetListLength(orStack)-1);
r = (integer)b % (integer)a;
jump push;
}
if(t == "sin") {
r = llSin(a * DEG_TO_RAD);
jump push;
}
if(t == "asin") {
r = llAsin(a * DEG_TO_RAD);
jump push;
}
if(t == "cos") {
r = llCos(a * DEG_TO_RAD);
jump push;
}
if(t == "acos") {
r = llAcos(a * DEG_TO_RAD);
jump push;
}
if(t == "tan") {
r = llTan(a * DEG_TO_RAD);
jump push;
}
if(t == "ln") {
r = llLog(a);
jump push;
}
if(t == "sqrt") {
r = llSqrt(a);
}
@push;
orStack += r;
@continue;
} while(llGetListLength(postfix) != 0);
return llList2Float(orStack, 0);
}
 
// configuration data
string configuration = "";
// callback URL
string URL = "";
// store message over state.
string data = "";
 
// Notecard reading.
key nQuery = NULL_KEY;
integer nLine = 0;
list nList = [];
 
default {
state_entry() {
llOwnerSay("[Eval] Starting module...");
llSetTimerEvent(10);
}
link_message(integer sender, integer num, string message, key id) {
if(id != "configuration") return;
llOwnerSay("[Eval] Got configuration...");
configuration = message;
state listen_group;
}
timer() {
llOwnerSay("[Eval] 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 listen_group {
state_entry() {
// DEBUG
llOwnerSay("[Eval] 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")
return;
// Get the sent message.
data = wasURLUnescape(
wasKeyValueGet(
"message",
message
)
);
if(llGetSubString(data, 0, 0) !=
wasKeyValueGet("command", configuration))
return;
list command = llParseString2List(data, ["@", " "], []);
if(llList2String(command, 0) != "eval")
return;
// Remove command.
command = llDeleteSubList(command, 0, 0);
// Dump the rest of the message.
data = (string)wasPostfixEval(
wasInfixToPostfix(
wasInfixTokenize(
llDumpList2String(
command,
" "
)
)
)
);
state tell;
}
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("[Eval] 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;
}
}
/source/eggdrop/fortune.lsl
@@ -0,0 +1,327 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// A fortune module for Corrade Eggdrop.
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, 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 = "";
// callback URL
string URL = "";
// store message over state.
string data = "";
 
// Notecard reading.
key nQuery = NULL_KEY;
integer nLine = 0;
list nList = [];
 
default {
state_entry() {
llOwnerSay("[Fortune] Starting module...");
llSetTimerEvent(10);
}
link_message(integer sender, integer num, string message, key id) {
if(id != "configuration") return;
llOwnerSay("[Fortune] Got configuration...");
configuration = message;
state read_fortunes;
}
timer() {
llOwnerSay("[Fortune] 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 read_fortunes {
state_entry() {
// DEBUG
llOwnerSay("[Fortune] Reading fortunes...");
if(llGetInventoryType("Fortune") != INVENTORY_NOTECARD) {
llOwnerSay("[Fortune] Failed to find a notecard named fortune in the primitive's inventory.");
return;
}
nQuery = llGetNotecardLine("Fortune", nLine);
}
dataserver(key id, string data) {
if(id != nQuery) return;
if(data == EOF) {
// DEBUG
llOwnerSay("[Fortune] Read fortunes...");
state listen_group;
}
if(data == "") jump continue;
nList += data;
@continue;
nQuery = llGetNotecardLine("Fortune", ++nLine);
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
}
 
state listen_group {
state_entry() {
// DEBUG
llOwnerSay("[Fortune] 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")
return;
// Get the sent message.
data = wasURLUnescape(
wasKeyValueGet(
"message",
message
)
);
if(llGetSubString(data, 0, 0) !=
wasKeyValueGet("command", configuration))
return;
list command = llParseString2List(data, ["@", " "], []);
if(llList2String(command, 0) != "fortune")
return;
list range = wasCSVToList(
wasKeyValueGet("roll range", configuration)
);
data = llList2String(
nList,
(integer)
llFrand(
llGetListLength(nList)
)
);
state tell;
}
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("[Fortune] 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;
}
}
/source/eggdrop/help.lsl
@@ -0,0 +1,293 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// Help message for Corrade eggdrop.
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, 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 = "";
// callback URL
string URL = "";
// store message over state.
string data = "";
 
default {
state_entry() {
llOwnerSay("[Help] Starting module...");
llSetTimerEvent(10);
}
link_message(integer sender, integer num, string message, key id) {
if(id != "configuration") return;
llOwnerSay("[Help] Got configuration...");
configuration = message;
state listen_group;
}
timer() {
llOwnerSay("[Help] 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 listen_group {
state_entry() {
// DEBUG
llOwnerSay("[Help] 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")
return;
// Get the sent message.
data = wasURLUnescape(
wasKeyValueGet(
"message",
message
)
);
if(llGetSubString(data, 0, 0) !=
wasKeyValueGet("command", configuration))
return;
list command = llParseString2List(data, ["@", " "], []);
if(llList2String(command, 0) != "help")
return;
 
data ="
 
~~~~~~~~~ Corrade Eggdrop ~~~~~~~~~
Syntax: @<command> [OPTIONS]
\t@roll <number>\t- Roll a dice with <number> sides.
\t@spank <name>\t- Spank a group member.
\t@wiki <get|set|dir>\t- Wiki commands.
\t@fortune\t\t- Get a random fortune cookie.
\t@joke\t\t- Get a random joke.
\t@eval <expression>\t- Evaluate a mathematical expression.
\t@ban <first> <last>\t- Ban a group member by name.
\t@invite <first> <last>\t- Invite agent to group by name.
 
\t@help\t- This help message.
~~~~~~~~~ Corrade Eggdrop ~~~~~~~~~
";
 
state tell;
}
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("[Help] 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;
}
}
/source/eggdrop/invite.lsl
@@ -0,0 +1,489 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// A module that invites people to the group members.
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, 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 = "";
// callback URL
string URL = "";
// store message over state.
string data = "";
string firstname = "";
string lastname = "";
 
default {
state_entry() {
llOwnerSay("[Invite] Starting...");
llSetTimerEvent(10);
}
link_message(integer sender, integer num, string message, key id) {
if(id != "configuration") return;
llOwnerSay("[Invite] Got configuration...");
configuration = message;
state listen_group;
}
timer() {
llOwnerSay("[Invite] 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 listen_group {
state_entry() {
// DEBUG
llOwnerSay("[Invite] 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")
return;
// Get the sent message.
data = wasURLUnescape(
wasKeyValueGet(
"message",
message
)
);
if(llGetSubString(data, 0, 0) !=
wasKeyValueGet("command", configuration))
return;
list command = llParseString2List(data, ["@", " "], []);
if(llList2String(command, 0) != "invite")
return;
// Remove command.
command = llDeleteSubList(command, 0, 0);
// Dump the rest of the message.
data = llDumpList2String(command, " ");
// Get an URL.
state url;
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
}
 
state url {
state_entry() {
// DEBUG
llOwnerSay("[Invite] Requesting URL...");
llRequestURL();
}
http_request(key id, string method, string body) {
if(method != URL_REQUEST_GRANTED) return;
URL = body;
// DEBUG
llOwnerSay("[Invite] Got URL...");
state search;
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
}
 
state search {
state_entry() {
// DEBUG
llOwnerSay("[Invite] Searching for agent.");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "directorysearch",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"type", "people",
"name", wasURLEscape(data),
/*"sift", wasURLEscape(
wasListToCSV(
[
"match",
wasURLEscape("(?i),?([^,$]*" + data +"[^,$]*),?")
]
)
),*/
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
if(wasKeyValueGet("command", body) != "directorysearch" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Invite] Unable to search for agent: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
llReleaseURL(URL);
state listen_group;
}
list first_last = llParseString2List(data, [" "], []);
firstname = llList2String(first_last, 0);
lastname = llList2String(first_last, 1);
list found_agent = wasCSVToList(
wasURLUnescape(
wasKeyValueGet("data", body)
)
);
if(llToUpper(
llList2String(
found_agent,
llListFindList(
found_agent,
(list)"FirstName"
) + 1
)
) != llToUpper(firstname) ||
llToUpper(
llList2String(
found_agent,
llListFindList(
found_agent,
(list)"LastName"
) + 1
)
) != llToUpper(lastname)) {
data = "Agent not found.";
llReleaseURL(URL);
state tell;
}
state invite;
}
timer() {
llReleaseURL(URL);
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 invite {
state_entry() {
// DEBUG
llOwnerSay("[Invite] inviting...");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "invite",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"firstname", firstname,
"lastname", lastname,
"soft", "True",
"verify", "False",
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
llReleaseURL(URL);
if(wasKeyValueGet("command", body) != "invite" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Eject] Unable to invite agent: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
state listen_group;
}
data = "Butters (Jym) was sent to pick them up!";
state tell;
}
timer() {
llReleaseURL(URL);
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 tell {
state_entry() {
// DEBUG
llOwnerSay("[Invite] 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;
}
}
/source/eggdrop/joke.lsl
@@ -0,0 +1,327 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// A joke module for Corrade Eggdrop.
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, 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 = "";
// callback URL
string URL = "";
// store message over state.
string data = "";
 
// Notecard reading.
key nQuery = NULL_KEY;
integer nLine = 0;
list nList = [];
 
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;
state read_jokes;
}
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 read_jokes {
state_entry() {
// DEBUG
llOwnerSay("[Joke] Reading jokes...");
if(llGetInventoryType("Joke") != INVENTORY_NOTECARD) {
llOwnerSay("[Joke] Failed to find a notecard named Joke in the primitive's inventory.");
return;
}
nQuery = llGetNotecardLine("Joke", nLine);
}
dataserver(key id, string data) {
if(id != nQuery) return;
if(data == EOF) {
// DEBUG
llOwnerSay("[Joke] Read jokes...");
state listen_group;
}
if(data == "") jump continue;
nList += data;
@continue;
nQuery = llGetNotecardLine("Joke", ++nLine);
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
}
 
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")
return;
// Get the sent message.
data = wasURLUnescape(
wasKeyValueGet(
"message",
message
)
);
if(llGetSubString(data, 0, 0) !=
wasKeyValueGet("command", configuration))
return;
list command = llParseString2List(data, ["@", " "], []);
if(llList2String(command, 0) != "joke")
return;
list range = wasCSVToList(
wasKeyValueGet("roll range", configuration)
);
data = llList2String(
nList,
(integer)
llFrand(
llGetListLength(nList)
)
);
state tell;
}
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;
}
}
/source/eggdrop/spank.lsl
@@ -0,0 +1,399 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// A module that spanks group members using fuzzy name matching. . .
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, 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 = "";
// callback URL
string URL = "";
// store message over state.
string data = "";
 
default {
state_entry() {
llOwnerSay("[Spank] Starting...");
llSetTimerEvent(10);
}
link_message(integer sender, integer num, string message, key id) {
if(id != "configuration") return;
llOwnerSay("[Spank] Got configuration...");
configuration = message;
state listen_group;
}
timer() {
llOwnerSay("[Spank] 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 listen_group {
state_entry() {
// DEBUG
llOwnerSay("[Spank] 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")
return;
// Get the sent message.
data = wasURLUnescape(
wasKeyValueGet(
"message",
message
)
);
if(llGetSubString(data, 0, 0) !=
wasKeyValueGet("command", configuration))
return;
list command = llParseString2List(data, ["@", " "], []);
if(llList2String(command, 0) != "spank")
return;
// Remove command.
command = llDeleteSubList(command, 0, 0);
// Dump the rest of the message.
data = llDumpList2String(command, " ");
// Get an URL.
state url;
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
}
 
state url {
state_entry() {
// DEBUG
llOwnerSay("[Spank] Requesting URL...");
llRequestURL();
}
http_request(key id, string method, string body) {
if(method != URL_REQUEST_GRANTED) return;
URL = body;
// DEBUG
llOwnerSay("[Spank] Got URL...");
state search;
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
}
 
state search {
state_entry() {
// DEBUG
llOwnerSay("[Spank] Searching for agent.");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "getmembers",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"sift", wasURLEscape(
wasListToCSV(
[
"match",
wasURLEscape("(?i),?([^,$]*" + data +"[^,$]*),?")
]
)
),
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
llReleaseURL(URL);
if(wasKeyValueGet("command", body) != "getmembers" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Spank] Unable to get members: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
state listen_group;
}
// Dump the members to a list.
data = llList2CSV(
wasCSVToList(
wasURLUnescape(
wasKeyValueGet("data", body)
)
)
);
if(data == "") {
data = "I could not find anyone to spank (story of my life).";
state tell;
}
llOwnerSay("Spanking: " + data);
data = "/me spanks " + data;
state tell;
}
timer() {
llReleaseURL(URL);
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 tell {
state_entry() {
// DEBUG
llOwnerSay("[Spank] 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;
}
}
/source/eggdrop/wiki.lsl
@@ -0,0 +1,781 @@
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
//
// A wiki module that can memorize strings and recall them by path.
//
///////////////////////////////////////////////////////////////////////////
 
///////////////////////////////////////////////////////////////////////////
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
integer wasIsAlNum(string a) {
if(a == "") return FALSE;
integer x = llBase64ToInteger("AAAA" +
llStringToBase64(llGetSubString(a, 0, 0)));
return (x >= 65 && x <= 90) || (x >= 97 && x <= 122) ||
(x >= 48 && x <= 57);
}
///////////////////////////////////////////////////////////////////////////
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
///////////////////////////////////////////////////////////////////////////
string wasKeyValueGet(string k, string data) {
if(llStringLength(data) == 0) return "";
if(llStringLength(k) == 0) return "";
list a = llParseString2List(data, ["&", "="], []);
integer i = llListFindList(a, [ k ]);
if(i != -1) return llList2String(a, 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 = "";
// callback URL
string URL = "";
// store message over state.
string data = "";
string path = "";
string jump_state = "";
 
default {
state_entry() {
llOwnerSay("[Wiki] Starting...");
llSetTimerEvent(10);
}
link_message(integer sender, integer num, string message, key id) {
if(id != "configuration") return;
llOwnerSay("[Wiki] Got configuration...");
configuration = message;
jump_state = "create_database";
state url;
}
timer() {
llOwnerSay("[Wiki] 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 url {
state_entry() {
// DEBUG
llOwnerSay("[Wiki] Requesting URL...");
llRequestURL();
}
http_request(key id, string method, string body) {
if(method != URL_REQUEST_GRANTED) return;
URL = body;
// DEBUG
llOwnerSay("[Wiki] Got URL...");
if(jump_state == "create_database")
state create_database;
if(jump_state == "get")
state get;
if(jump_state == "set")
state set;
if(jump_state == "dir")
state dir;
if(jump_state == "listen_group")
state listen_group;
// DEBUG
llOwnerSay("[Wiki] 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 create_database {
state_entry() {
// DEBUG
llOwnerSay("[Wiki] Creating database.");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"SQL", wasURLEscape("CREATE TABLE IF NOT EXISTS corradeeggdrop (path text unique collate nocase, data text)"),
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
llReleaseURL(URL);
if(wasKeyValueGet("command", body) != "database" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Wiki] Unable modify database: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
state listen_group;
}
llOwnerSay("[Wiki] Database created!");
state listen_group;
}
timer() {
llReleaseURL(URL);
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("[Wiki] 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")
return;
// Get the sent message.
data = wasURLUnescape(
wasKeyValueGet(
"message",
message
)
);
if(llGetSubString(data, 0, 0) !=
wasKeyValueGet("command", configuration))
return;
list command = llParseString2List(data, ["@", " "], []);
if(llList2String(command, 0) != "wiki")
return;
// Remove command.
command = llDeleteSubList(command, 0, 0);
// Check for supported sub-commands.
if(llList2String(command, 0) != "set" &&
llList2String(command, 0) != "get" &&
llList2String(command, 0) != "dir") {
data = "Subcommands are: get, set, dir";
state tell;
}
// Get the sub-command and store it as a jump state.
jump_state = llList2String(command, 0);
// Remove sub-command.
command = llDeleteSubList(command, 0, 0);
// Get the path parts.
list path_parts = llParseString2List(
llList2String(command, 0), ["/"], []
);
// Dump the path and store it over states.
path = llStringTrim(
llDumpList2String(
path_parts,
"/"
),
STRING_TRIM
);
if(path != "") {
integer i = llStringLength(path) - 1;
do {
string c = llGetSubString(path, i, i);
if(c != "/" && !wasIsAlNum(c)) {
data = "Only alpha-numerics accepted in the path string.";
state tell;
}
} while(--i > -1);
}
path = "/" + path;
// Remove path.
command = llDeleteSubList(command, 0, 0);
// Dump the rest of the message.
data = llDumpList2String(command, " ");
// Get an URL.
state url;
}
on_rez(integer num) {
llResetScript();
}
changed(integer change) {
if((change & CHANGED_INVENTORY) ||
(change & CHANGED_REGION_START) ||
(change & CHANGED_OWNER)) {
llResetScript();
}
}
}
 
state set {
state_entry() {
if(data == "") {
// DEBUG
llOwnerSay("[Wiki] Removing from database.");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"SQL", wasURLEscape("DELETE FROM corradeeggdrop WHERE path=:path"),
"data", wasListToCSV(
[
"path",
wasURLEscape("path")
]
),
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
return;
}
// DEBUG
llOwnerSay("[Wiki] Adding to database.");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"SQL", wasURLEscape("REPLACE INTO corradeeggdrop (path, data) VALUES (:path, :data)"),
"data", wasListToCSV(
[
"path",
wasURLEscape("path"),
"data",
wasURLEscape("data")
]
),
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
llReleaseURL(URL);
if(wasKeyValueGet("command", body) != "database" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Wiki] Unable modify database: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
state listen_group;
}
if(data == "") {
data = "Deleted from " + path;
state tell;
}
data = "Stored into " + path;
state tell;
}
timer() {
llReleaseURL(URL);
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 get {
state_entry() {
// DEBUG
llOwnerSay("[Wiki] Retrieving from database.");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"SQL", wasURLEscape("SELECT data FROM corradeeggdrop WHERE path=:path"),
"data", wasListToCSV(
[
"path",
wasURLEscape(path)
]
),
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
llReleaseURL(URL);
if(wasKeyValueGet("command", body) != "database" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Wiki] Unable retrieve from database: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
state listen_group;
}
data = llDumpList2String(
llDeleteSubList(
wasCSVToList(
wasURLUnescape(
wasKeyValueGet("data", body)
)
),
0,
0
),
""
);
if(data == "") {
data = "Sorry, that path contains no data.";
state tell;
}
data = path + ": " + data;
state tell;
}
timer() {
llReleaseURL(URL);
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 dir {
state_entry() {
// DEBUG
llOwnerSay("[Wiki] Listing paths from database.");
llInstantMessage(
wasKeyValueGet(
"corrade",
configuration
),
wasKeyValueEncode(
[
"command", "database",
"group", wasURLEscape(
wasKeyValueGet(
"group",
configuration
)
),
"password", wasURLEscape(
wasKeyValueGet(
"password",
configuration
)
),
"SQL", wasURLEscape("SELECT path FROM corradeeggdrop WHERE path like :path"),
"data", wasListToCSV(
[
"path",
wasURLEscape(path + "%")
]
),
"callback", wasURLEscape(URL)
]
)
);
llSetTimerEvent(60);
}
http_request(key id, string method, string body) {
llHTTPResponse(id, 200, "OK");
llReleaseURL(URL);
if(wasKeyValueGet("command", body) != "database" ||
wasKeyValueGet("success", body) != "True") {
// DEBUG
llOwnerSay("[Wiki] Unable retrieve from database: " +
wasURLUnescape(
wasKeyValueGet("error", body)
)
);
state listen_group;
}
list paths = llList2ListStrided(
llDeleteSubList(
wasCSVToList(
wasURLUnescape(
wasKeyValueGet("data", body)
)
),
0,
0
),
0,
-1,
2
);
if(llGetListLength(paths) == 0) {
data = "Sorry, that path contains no sub-paths.";
state tell;
}
// Eliminate path component.
if(path == "/")
path = "";
list sibling = [];
do {
// Get the path part.
string part = llList2String(paths, 0);
// Remove the path component.
string child = llStringTrim(
llDumpList2String(
llParseString2List(
part,
[path, "/"],
[]
),
"/"
),
STRING_TRIM
);
integer i = llSubStringIndex(child, "/");
if(i == -1) {
sibling += path + "/" + child;
jump continue;
}
child = path + "/" + llDeleteSubString(child, i, -1) + "/";
if(llListFindList(sibling, (list)child) == -1)
sibling += child;
@continue;
paths = llDeleteSubList(paths, 0, 0);
} while(llGetListLength(paths) != 0);
data = llList2CSV(sibling);
// GC
sibling = [];
state tell;
}
timer() {
llReleaseURL(URL);
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 tell {
state_entry() {
// DEBUG
llOwnerSay("[Wiki] 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;
}
}