Chatbot: Difference between revisions
add llSetLocalRot llApplyImpulse llApplyRotationalImpulse to demo kicking a translucent, bouncing, spinning box |
teleport ~2m up the Z axis to demo verbose prefix arithmetic |
||
| Line 6: | Line 6: | ||
<pre> | <pre> | ||
/7 llSetColor(<0.3, 0.3, 0.3>, ALL_SIDES); | /7 llSetColor(<0.3, 0.3, 0.3>, ALL_SIDES); // darken | ||
/7 llSetColor(<1, 1, 1>, ALL_SIDES); | /7 llSetColor(<1, 1, 1>, ALL_SIDES); // lighten | ||
/7 llSetAlpha(0. | /7 llSetAlpha(0.7, ALL_SIDES); // make translucent | ||
</pre> | </pre> | ||
<pre> | <pre> | ||
/7 llSetText("look at me green", <0.0, 1.0, 0.0>, 1.0); | /7 llSetText("look at me green", <0.0, 1.0, 0.0>, 1.0); // label | ||
/7 llSetText("look at me black", <0.0, 0.0, 0.0>, 1.0); | /7 llSetText("look at me black", <0.0, 0.0, 0.0>, 1.0); // label differently | ||
/7 llSetText("", <0.0, 0.0, 0.0>, 1.0); | /7 llSetText("", <0.0, 0.0, 0.0>, 1.0); // do not label | ||
</pre> | </pre> | ||
<pre> | <pre> | ||
/7 llSetStatus(STATUS_PHYSICS, FALSE); | /7 llSetStatus(STATUS_PHYSICS, FALSE); | ||
/7 llSetLocalRot(llEuler2Rot(<0.0, 0.0, PI_BY_TWO>)); | /7 llSetPos("+"(llGetPos(), <0.0, 0.0, 2.1>)); // teleport up the Z axis | ||
/7 llSetLocalRot(llEuler2Rot(ZERO_ROTATION)); | /7 llSetLocalRot(llEuler2Rot(<0.0, 0.0, PI_BY_TWO>))); // face one way | ||
/7 llSetLocalRot(llEuler2Rot(ZERO_ROTATION)); // face another way | |||
/7 llSetStatus(STATUS_PHYSICS, TRUE); | /7 llSetStatus(STATUS_PHYSICS, TRUE); | ||
/7 llSetBuoyancy(0.9); | /7 llSetBuoyancy(0.9); // bounce well, without floating | ||
/7 llApplyImpulse(<0.0, 0.0, 1.0>, TRUE); // advance along the Z axis | /7 llApplyImpulse(<0.0, 0.0, 1.0>, TRUE); // advance along the Z axis | ||
/7 llApplyRotationalImpulse(<0.0, 0.0, 3.0>, TRUE); // yaw about the Z axis | /7 llApplyRotationalImpulse(<0.0, 0.0, 3.0>, TRUE); // yaw about the Z axis | ||
| Line 47: | Line 48: | ||
// | // | ||
// Compile and run the Lsl you type on a channel, | // Compile and run the Lsl you type on a channel, | ||
// faster than you can thru the 2007-08 SL GUI. | // faster than you can thru the 2007-08 SL GUI, | ||
// thus "chat with your 'bot" while it runs this script. | |||
// | // | ||
// Choose | // Choose one chat channel for hearing commands, echoing commands, and chatting results. | ||
integer theChannel = 7; | integer theChannel = 7; | ||
// Describe the language of an LSL expression without infix operators | // Chat back a copy of the meaningful or meaningless command, only on request. | ||
integer theEchoPlease = TRUE; | |||
// Describe the language of an LSL expression without infix operators. | |||
string escape = "\\"; | string escape = "\\"; | ||
string quote = "\""; | string quote = "\""; | ||
| Line 61: | Line 67: | ||
list spacers = [quote, escape, "(", ")", "/", "<", ">", "[", "]"]; | list spacers = [quote, escape, "(", ")", "/", "<", ">", "[", "]"]; | ||
// | // List some frequently useful code values. | ||
list theCodes = [ | list theCodes = [ | ||
| Line 84: | Line 90: | ||
0 | 0 | ||
]; | ]; | ||
// List the name of each code. | |||
list theCodenames = [ | list theCodenames = [ | ||
| Line 106: | Line 114: | ||
"0" | "0" | ||
]; | ]; | ||
// Evaluate any one parameter. | |||
list valueOf(string word) | list valueOf(string word) | ||
| Line 127: | Line 137: | ||
} | } | ||
} | } | ||
} | |||
// Add and return the sum. | |||
list sum(list values) | |||
{ | |||
if (llGetListEntryType(values, 0) == TYPE_VECTOR) | |||
{ | |||
return [llList2Vector(values, 0) + llList2Vector(values, 1)]; | |||
} | |||
return []; | |||
} | |||
// Subtract and return the difference. | |||
list difference(list values) | |||
{ | |||
if (llGetListEntryType(values, 0) == TYPE_VECTOR) | |||
{ | |||
return [llList2Vector(values, 0) - llList2Vector(values, 1)]; | |||
} | |||
return []; | |||
} | |||
// Multiply and return the product. | |||
list product(list values) | |||
{ | |||
if (llGetListEntryType(values, 0) == TYPE_ROTATION) | |||
{ | |||
return [llList2Rot(values, 0) * llList2Rot(values, 1)]; | |||
} | |||
return []; | |||
} | |||
// Divide and return the quotient. | |||
list quotient(list values) | |||
{ | |||
if (llGetListEntryType(values, 0) == TYPE_ROTATION) | |||
{ | |||
return [llList2Rot(values, 0) / llList2Rot(values, 1)]; | |||
} | |||
return []; | |||
} | |||
// Divide and return the remainder. | |||
list remainder(list values) | |||
{ | |||
return []; | |||
} | } | ||
// Pass the parameters to the named routine. | // Pass the parameters to the named routine. | ||
// Return no result, | // Return a list of results. | ||
// Return empty if no result, if empty list returned, or if callable meaningless. | |||
list resultOf(string callable, list parameters) | list resultOf(string callable, list parameters) | ||
{ | { | ||
if ("llApplyImpulse" == callable) // force, local | // Abbreviate the word "parameters" | ||
list ps = parameters; | |||
// Trace every call, even when the callable is meaningless | |||
if (theEchoPlease) | |||
{ | |||
llOwnerSay(callable + "(" + llList2CSV(ps) + ")"); | |||
} | |||
// Accept verbose prefix arithmetic such as { "+"(vec1, vec2) } | |||
if ("+" == callable) | |||
{ | |||
return sum(ps); | |||
} | |||
else if ("-" == callable) | |||
{ | |||
return difference(ps); | |||
} | |||
else if ("*" == callable) | |||
{ | |||
return product(ps); | |||
} | |||
else if ("/" == callable) | |||
{ | |||
return quotient(ps); | |||
} | |||
// else if ("%" == callable) | |||
// { | |||
// return remainder(ps); | |||
// } | |||
// Return a list of results to say callable meaningful and returns results | |||
// Or fall thru to say callable meaningful but returns no result | |||
if ("llApplyImpulse" == callable) // (force, local) | |||
{ | { | ||
llApplyImpulse(llList2Vector(ps, 0), llList2Integer(ps, 1)); | llApplyImpulse(llList2Vector(ps, 0), llList2Integer(ps, 1)); | ||
} | } | ||
else if ("llApplyRotationalImpulse" == callable) // force, local | else if ("llApplyRotationalImpulse" == callable) // (force, local) | ||
{ | { | ||
llApplyRotationalImpulse(llList2Vector(ps, 0), llList2Integer(ps, 1)); | llApplyRotationalImpulse(llList2Vector(ps, 0), llList2Integer(ps, 1)); | ||
} | } | ||
else if ("llEuler2Rot" == callable) // v | else if ("llEuler2Rot" == callable) // (v) | ||
{ | { | ||
return [llEuler2Rot(llList2Vector(ps, 0))]; | return [llEuler2Rot(llList2Vector(ps, 0))]; | ||
} | } | ||
else if ("llGetAgentSize" == callable) // id | else if ("llGetAgentSize" == callable) // (id) | ||
{ | { | ||
return [llGetAgentSize(llList2Key(ps, 0))]; | return [llGetAgentSize(llList2Key(ps, 0))]; | ||
} | } | ||
else if ("llGetLinkKey" == callable) // linknum | else if ("llGetLinkKey" == callable) // (linknum) | ||
{ | { | ||
return [llGetLinkKey(llList2Integer(ps, 0))]; | return [llGetLinkKey(llList2Integer(ps, 0))]; | ||
} | } | ||
else if ("llGetNumberOfPrims" == callable) // | else if ("llGetNumberOfPrims" == callable) // () | ||
{ | { | ||
return [llGetNumberOfPrims()]; | return [llGetNumberOfPrims()]; | ||
} | } | ||
else if ("llRot2Euler" == callable) // q | else if ("llGetPos" == callable) // () | ||
{ | |||
return [llGetPos()]; | |||
} | |||
else if ("llGetLocalRot" == callable) // () | |||
{ | |||
return [llGetLocalRot()]; | |||
} | |||
else if ("llGetlRot" == callable) // () | |||
{ | |||
return [llGetRot()]; | |||
} | |||
else if ("llRot2Euler" == callable) // (q) | |||
{ | { | ||
return [llRot2Euler(llList2Rot(ps, 0))]; | return [llRot2Euler(llList2Rot(ps, 0))]; | ||
} | } | ||
else if ("llSetAlpha" == callable) // alpha, face | else if ("llSetAlpha" == callable) // (alpha, face) | ||
{ | { | ||
llSetAlpha(llList2Float(ps, 0), llList2Integer(ps, 1)); | llSetAlpha(llList2Float(ps, 0), llList2Integer(ps, 1)); | ||
} | } | ||
else if ("llSetBuoyancy" == callable) // buoyancy | else if ("llSetBuoyancy" == callable) // (buoyancy) | ||
{ | { | ||
llSetBuoyancy(llList2Float(ps, 0)); | llSetBuoyancy(llList2Float(ps, 0)); | ||
} | } | ||
else if ("llSetColor" == callable) // color, face | else if ("llSetColor" == callable) // (color, face) | ||
{ | { | ||
llSetColor(llList2Vector(ps, 0), llList2Integer(ps, 1)); | llSetColor(llList2Vector(ps, 0), llList2Integer(ps, 1)); | ||
} | } | ||
else if ("llSetLocalRot" == callable) // rot | else if ("llSetLocalRot" == callable) // (rot) | ||
{ | { | ||
llSetLocalRot(llList2Rot(ps, 0)); | llSetLocalRot(llList2Rot(ps, 0)); | ||
} | } | ||
else if ("llSetPos" == callable) // pos | else if ("llSetPos" == callable) // (pos) | ||
{ | { | ||
llSetPos(llList2Vector(ps, 0)); | llSetPos(llList2Vector(ps, 0)); | ||
} | } | ||
else if ("llSetRot" == callable) // rot | else if ("llSetRot" == callable) // (rot) | ||
{ | { | ||
llSetRot(llList2Rot(ps, 0)); | llSetRot(llList2Rot(ps, 0)); | ||
} | } | ||
else if ("llSetStatus" == callable) // status, value | else if ("llSetStatus" == callable) // (status, value) | ||
{ | { | ||
llSetStatus(llList2Integer(ps, 0), llList2Integer(ps, 1)); | llSetStatus(llList2Integer(ps, 0), llList2Integer(ps, 1)); | ||
} | } | ||
else if ("llSetText" == callable) // text, color, alpha | else if ("llSetText" == callable) // (text, color, alpha) | ||
{ | { | ||
llSetText(llList2String(ps, 0), llList2Vector(ps, 1), llList2Float(ps, 2)); | llSetText(llList2String(ps, 0), llList2Vector(ps, 1), llList2Float(ps, 2)); | ||
} | } | ||
// Return | // Return an empty result if callable meaningless or returns no result | ||
return []; | return []; | ||
} | } | ||
// | // Interpret one list of words. | ||
list callEach(list words) | list callEach(list words) | ||
| Line 230: | Line 329: | ||
{ | { | ||
string word = llList2String(words, index); | string word = llList2String(words, index); | ||
// Count results of "( ... )" or of "< ... >" | // Count results of "( ... )" or of "< ... >" | ||
| Line 236: | Line 334: | ||
if ((word == "(") || (word == "<")) | if ((word == "(") || (word == "<")) | ||
{ | { | ||
integer beyond = llGetListLength(results); | |||
depths += [beyond]; // push the depth | depths += [beyond]; // push the depth | ||
} | } | ||
| Line 249: | Line 348: | ||
// Pop the parameters | // Pop the parameters | ||
integer beyond = llGetListLength(results); | |||
integer last = beyond - 1; | integer last = beyond - 1; | ||
list parameters = []; | list parameters = []; | ||
| Line 311: | Line 411: | ||
else | else | ||
{ | { | ||
results += | results += llList2List(words, index, index); | ||
} | } | ||
} | } | ||
| Line 318: | Line 418: | ||
// Succeed | // Succeed | ||
if (llGetListLength(results) <= 1) | |||
{ | |||
return []; | |||
} | |||
return llList2List(results, 1, -1); // pop the head (only if head is not tail) | return llList2List(results, 1, -1); // pop the head (only if head is not tail) | ||
} | } | ||
| Line 398: | Line 502: | ||
// Divide a string into words, | // Divide a string into words, | ||
// by returning each of the spacers as a word | // by returning each of the spacers as a word | ||
// and | // and return as a word each run of chars between words. | ||
list separateEach(string source, list spacers) | list separateEach(string source, list spacers) | ||
| Line 431: | Line 535: | ||
} | } | ||
// Hear and obey the chat of the owner at the channel. | // Hear and echo and obey the chat of the owner at the channel. | ||
default | default | ||
| Line 441: | Line 545: | ||
listen(integer channel, string name, key id, string message) | listen(integer channel, string name, key id, string message) | ||
{ | { | ||
llOwnerSay(message); | |||
// Compile and run | |||
// llOwnerSay(message); | |||
list words = separateEach(message, separators + spacers); | list words = separateEach(message, separators + spacers); | ||
// llOwnerSay(llList2CSV(words)); | // llOwnerSay((string) llGetListLength(words) + ": " + llList2CSV(words)); | ||
list values = valueEach(words); | list values = valueEach(words); | ||
// llOwnerSay(llList2CSV(values)); | // llOwnerSay((string) llGetListLength(values) + ": " + llList2CSV(values)); | ||
list results = callEach(values); | list results = callEach(values); | ||
// llOwnerSay((string) llGetListLength(results) + ": " + llList2CSV(results)); | |||
// Chat back the results, if not empty | |||
if (results != []) | if (results != []) | ||
{ | { | ||
Revision as of 07:03, 6 September 2007
Compile and run the LSL you chat on a channel, faster than you can compile and run it thru the 2007-08 SL GUI.
Created by Ppaatt Lynagh. "Allow anyone to copy", "next owner can copy & modify", and "mark item for sale price L$0", are the rights on my copies of this script in SL, as of 2007-09-04.
The LSL commands you can chat to this script include the following demo of kicking a translucent, bouncing, spinning box:
/7 llSetColor(<0.3, 0.3, 0.3>, ALL_SIDES); // darken /7 llSetColor(<1, 1, 1>, ALL_SIDES); // lighten /7 llSetAlpha(0.7, ALL_SIDES); // make translucent
/7 llSetText("look at me green", <0.0, 1.0, 0.0>, 1.0); // label
/7 llSetText("look at me black", <0.0, 0.0, 0.0>, 1.0); // label differently
/7 llSetText("", <0.0, 0.0, 0.0>, 1.0); // do not label
/7 llSetStatus(STATUS_PHYSICS, FALSE);
/7 llSetPos("+"(llGetPos(), <0.0, 0.0, 2.1>)); // teleport up the Z axis
/7 llSetLocalRot(llEuler2Rot(<0.0, 0.0, PI_BY_TWO>))); // face one way
/7 llSetLocalRot(llEuler2Rot(ZERO_ROTATION)); // face another way
/7 llSetStatus(STATUS_PHYSICS, TRUE);
/7 llSetBuoyancy(0.9); // bounce well, without floating
/7 llApplyImpulse(<0.0, 0.0, 1.0>, TRUE); // advance along the Z axis
/7 llApplyRotationalImpulse(<0.0, 0.0, 3.0>, TRUE); // yaw about the Z axis
/7 llSetStatus(STATUS_PHYSICS, FALSE); llSetStatus(STATUS_PHYSICS, TRUE); // zero rot inertia
/7 ZERO_VECTOR /7 llGetAgentSize(llGetLinkKey(llGetNumberOfPrims())) // often not ZERO_VECTOR while avatar sits
The commands shown above work well in the order shown with a 0.5 x 0.5 x 0.5 wood box such as the default object of the SL GUI. Sending these commands to other objects will show you how the effects of some commands that require STATUS_PHYICS TRUE do vary greatly with the mass of the object.
To keep this sample script conveniently short, this script understands only a few library function names, a few code constant names, a few punctuation marks, and a few data types. I hope you find it easy to add the library function names and code constant names that interest you, even prefix (not infix) function names like the "*" multiply operator. Adding the list data type as a possible parameter type might require real work: LSL doesn't understand lists of lists yet.
See the discussion tab for talk of more example command lines that we could/ should soon add.
Enjoy,
P.S. The code of the sample script follows:
// http://wiki.secondlife.com/wiki/Chatbot
//
// Compile and run the Lsl you type on a channel,
// faster than you can thru the 2007-08 SL GUI,
// thus "chat with your 'bot" while it runs this script.
//
// Choose one chat channel for hearing commands, echoing commands, and chatting results.
integer theChannel = 7;
// Chat back a copy of the meaningful or meaningless command, only on request.
integer theEchoPlease = TRUE;
// Describe the language of an LSL expression without infix operators.
string escape = "\\";
string quote = "\"";
list separators = ["\t", " ", ",", ";"];
list spacers = [quote, escape, "(", ")", "/", "<", ">", "[", "]"];
// List some frequently useful code values.
list theCodes = [
TRUE, FALSE,
PI,
TWO_PI,
PI_BY_TWO,
DEG_TO_RAD,
RAD_TO_DEG,
SQRT2,
NULL_KEY,
ALL_SIDES,
EOF,
ZERO_VECTOR,
ZERO_ROTATION,
STATUS_PHYSICS,
0
];
// List the name of each code.
list theCodenames = [
"TRUE", "FALSE",
"PI",
"TWO_PI",
"PI_BY_TWO",
"DEG_TO_RAD",
"RAD_TO_DEG",
"SQRT2",
"NULL_KEY",
"ALL_SIDES",
"EOF",
"ZERO_VECTOR",
"ZERO_ROTATION",
"STATUS_PHYSICS",
"0"
];
// Evaluate any one parameter.
list valueOf(string word)
{
if (0 <= llSubStringIndex(word, "."))
{
return [(float) word];
}
else if (0 <= llSubStringIndex("0123456789", llGetSubString(word, 0, 0)))
{
return [(integer) word];
}
else
{
integer index = llListFindList(theCodenames, [word]);
if (0 <= index)
{
return llList2List(theCodes, index, index);
} else {
return [word]; // unevaluated
}
}
}
// Add and return the sum.
list sum(list values)
{
if (llGetListEntryType(values, 0) == TYPE_VECTOR)
{
return [llList2Vector(values, 0) + llList2Vector(values, 1)];
}
return [];
}
// Subtract and return the difference.
list difference(list values)
{
if (llGetListEntryType(values, 0) == TYPE_VECTOR)
{
return [llList2Vector(values, 0) - llList2Vector(values, 1)];
}
return [];
}
// Multiply and return the product.
list product(list values)
{
if (llGetListEntryType(values, 0) == TYPE_ROTATION)
{
return [llList2Rot(values, 0) * llList2Rot(values, 1)];
}
return [];
}
// Divide and return the quotient.
list quotient(list values)
{
if (llGetListEntryType(values, 0) == TYPE_ROTATION)
{
return [llList2Rot(values, 0) / llList2Rot(values, 1)];
}
return [];
}
// Divide and return the remainder.
list remainder(list values)
{
return [];
}
// Pass the parameters to the named routine.
// Return a list of results.
// Return empty if no result, if empty list returned, or if callable meaningless.
list resultOf(string callable, list parameters)
{
// Abbreviate the word "parameters"
list ps = parameters;
// Trace every call, even when the callable is meaningless
if (theEchoPlease)
{
llOwnerSay(callable + "(" + llList2CSV(ps) + ")");
}
// Accept verbose prefix arithmetic such as { "+"(vec1, vec2) }
if ("+" == callable)
{
return sum(ps);
}
else if ("-" == callable)
{
return difference(ps);
}
else if ("*" == callable)
{
return product(ps);
}
else if ("/" == callable)
{
return quotient(ps);
}
// else if ("%" == callable)
// {
// return remainder(ps);
// }
// Return a list of results to say callable meaningful and returns results
// Or fall thru to say callable meaningful but returns no result
if ("llApplyImpulse" == callable) // (force, local)
{
llApplyImpulse(llList2Vector(ps, 0), llList2Integer(ps, 1));
}
else if ("llApplyRotationalImpulse" == callable) // (force, local)
{
llApplyRotationalImpulse(llList2Vector(ps, 0), llList2Integer(ps, 1));
}
else if ("llEuler2Rot" == callable) // (v)
{
return [llEuler2Rot(llList2Vector(ps, 0))];
}
else if ("llGetAgentSize" == callable) // (id)
{
return [llGetAgentSize(llList2Key(ps, 0))];
}
else if ("llGetLinkKey" == callable) // (linknum)
{
return [llGetLinkKey(llList2Integer(ps, 0))];
}
else if ("llGetNumberOfPrims" == callable) // ()
{
return [llGetNumberOfPrims()];
}
else if ("llGetPos" == callable) // ()
{
return [llGetPos()];
}
else if ("llGetLocalRot" == callable) // ()
{
return [llGetLocalRot()];
}
else if ("llGetlRot" == callable) // ()
{
return [llGetRot()];
}
else if ("llRot2Euler" == callable) // (q)
{
return [llRot2Euler(llList2Rot(ps, 0))];
}
else if ("llSetAlpha" == callable) // (alpha, face)
{
llSetAlpha(llList2Float(ps, 0), llList2Integer(ps, 1));
}
else if ("llSetBuoyancy" == callable) // (buoyancy)
{
llSetBuoyancy(llList2Float(ps, 0));
}
else if ("llSetColor" == callable) // (color, face)
{
llSetColor(llList2Vector(ps, 0), llList2Integer(ps, 1));
}
else if ("llSetLocalRot" == callable) // (rot)
{
llSetLocalRot(llList2Rot(ps, 0));
}
else if ("llSetPos" == callable) // (pos)
{
llSetPos(llList2Vector(ps, 0));
}
else if ("llSetRot" == callable) // (rot)
{
llSetRot(llList2Rot(ps, 0));
}
else if ("llSetStatus" == callable) // (status, value)
{
llSetStatus(llList2Integer(ps, 0), llList2Integer(ps, 1));
}
else if ("llSetText" == callable) // (text, color, alpha)
{
llSetText(llList2String(ps, 0), llList2Vector(ps, 1), llList2Float(ps, 2));
}
// Return an empty result if callable meaningless or returns no result
return [];
}
// Interpret one list of words.
list callEach(list words)
{
// Begin with almost nothing
list results = [""];
list depths = [0];
// Take each action in order
integer lenWords = llGetListLength(words);
integer index;
for (index = 0; index < lenWords; ++index)
{
string word = llList2String(words, index);
// Count results of "( ... )" or of "< ... >"
if ((word == "(") || (word == "<"))
{
integer beyond = llGetListLength(results);
depths += [beyond]; // push the depth
}
else if ((word == ")") || (word == ">"))
{
// Pop the depth
integer first = llList2Integer(depths, -1);
depths = llList2List(depths, 0, -2); // pop the tail
// Pop the parameters
integer beyond = llGetListLength(results);
integer last = beyond - 1;
list parameters = [];
if (first <= last)
{
parameters = llList2List(results, first, last);
results = llList2List(results, 0, first - 1);
}
// Join together the components of a vector
if (word == ">")
{
integer depth = llGetListLength(parameters);
if (depth == 3)
{
vector vec;
vec.x = llList2Float(parameters, 0);
vec.y = llList2Float(parameters, 1);
vec.z = llList2Float(parameters, 2);
results += [vec];
}
// Join together the components of a rotation
if (depth == 4)
{
rotation rot;
rot.x = llList2Float(parameters, 0);
rot.y = llList2Float(parameters, 1);
rot.z = llList2Float(parameters, 2);
rot.s = llList2Float(parameters, 2);
results += [rot];
}
}
// Call with a list of parameters (of non-list types)
else if (word == ")")
{
string callable = llList2String(results, -1);
results = llList2List(results, 0, -2); // pop the tail
results += resultOf(callable, parameters);
}
}
// Push any other word as a parameter
else
{
if (llGetSubString(word, 0, 0) == quote)
{
if (word == (quote + quote))
{
results += "";
}
else
{
results += llGetSubString(word, 1, -2);
}
}
else
{
results += llList2List(words, index, index);
}
}
}
// Succeed
if (llGetListLength(results) <= 1)
{
return [];
}
return llList2List(results, 1, -1); // pop the head (only if head is not tail)
}
// Divide the command into words.
// Take care to join together the words of each quotation.
// Return a list of the words of the command.
list valueEach(list words)
{
// Begin with nothing
list values = [];
// Divide the command into words, but also shatter quotations
integer lenWords = llGetListLength(words);
// Consider each word or word of a quotation
integer index = 0;
while (index < lenWords)
{
string word = llList2String(words, index++);
// Join together the words of a quotation
if (word == quote)
{
string value = "";
do
{
word = llList2String(words, index++);
if (word != quote)
{
value += word;
}
} while ((word != quote) && (index < lenWords));
// Quote the quotation simply, so the quotation is never found in spacers
values += quote + value + quote;
}
// Discard slash slash commentary
else if ((word == "/") && (llList2String(words, index) == "/"))
{
return values;
}
// Discard separators
else if ((0 <= llListFindList(separators, [word])) || (word == ""))
{
;
}
// Keep spacers
else if (0 <= llListFindList(spacers, [word]))
{
values += word;
}
// Evaluate other words
else
{
values += valueOf(word);
}
}
// Succeed
return values;
}
// Divide a string into words,
// by returning each of the spacers as a word
// and return as a word each run of chars between words.
list separateEach(string source, list spacers)
{
list outputs = [source];
// Pass never more than 8 spacers to llParseString2List
integer lenSpacers = llGetListLength(spacers);
integer ss;
for (ss = 0; ss < lenSpacers; ss += 8)
{
list someSpacers = llList2List(spacers, ss, ss + 7);
// Call llParseString2List again for each result so far
list inputs = outputs;
outputs = [];
integer lenInputs = llGetListLength(inputs);
integer ii;
for (ii = 0; ii < lenInputs; ++ii)
{
string input = llList2String(inputs, ii);
outputs += llParseString2List(input, [], someSpacers);
}
}
// Succeed
return outputs;
}
// Hear and echo and obey the chat of the owner at the channel.
default
{
state_entry()
{
llListen(theChannel, "", llGetOwner(), "");
}
listen(integer channel, string name, key id, string message)
{
// Compile and run
// llOwnerSay(message);
list words = separateEach(message, separators + spacers);
// llOwnerSay((string) llGetListLength(words) + ": " + llList2CSV(words));
list values = valueEach(words);
// llOwnerSay((string) llGetListLength(values) + ": " + llList2CSV(values));
list results = callEach(values);
// llOwnerSay((string) llGetListLength(results) + ": " + llList2CSV(results));
// Chat back the results, if not empty
if (results != [])
{
llOwnerSay(llList2CSV(results));
}
}
}