This is just a quick lsl scripting cheat sheet I put together for my own use. I’m hosting it here for ease of access and in the hope it maybe of use to the community. It is not intended as a full guide on how to script, just an aid for scripting but it might be helpful those still learning.
Scripting Limits
add next: https://wiki.secondlife.com/wiki/LSL_Script_Memory
- Height at which scripts reactivate on a no-script parcel - 50 m above terrain mesh. Scripted objects that take controls will keep running when you fly down or enter a no-script parcel. (If scripts are disabled in the region debug panel, they will not run at any height.)
- Maximum height where scripts can run - none, as long as the object remains rezzed or attached.
- Maximum script source code size - 65536 single byte characters (that's a viewer limit and can be changed in the config file 'panel_script_ed.xml').
- Maximum script memory size (LSO) - 16384 bytes.
- Maximum script memory size (Mono) - 65536 bytes (the maximum memory available to Mono scripts can be constrained via llSetMemoryLimit).
- Maximum active listeners per script - 65.
- Usable channel for each listener - min. -2147483648, max. 2147483647, including the following special channels: PUBLIC_CHANNEL and DEBUG_CHANNEL.
- Maximum number of scripts that can be rezzed at once – 1,000. (Refer to Tips, by Jeremy Linden.)
- For specific scripting limits, look up calls in the LSL Portal.
Random Channel
Method 1a
default
{
touch_start(integer total_number)
{
key id = llDetectedKey(0);
integer chan = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );
llRegionSayTo(id, 0, "Random Channel: "+(string)chan);
}
}
Method 1
default
{
touch_start(integer total_number)
{
key id = llDetectedKey(0);
integer chan = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );
llRegionSayTo(id, 0, "Random Channel: "+(string)chan);
}
}
iChannelLights = -1 - (integer)("0x" + llGetSubString( (string) kOwner, -7, -1) ) + 106;
Method 2
default
{
touch_start(integer total_number)
{
key id = llDetectedKey(0);
integer chan = 0x80000000 | (integer)llFrand(65536) | ((integer)llFrand(65536) << 16);
llRegionSayTo(id, 0, "Random Channel: "+(string)chan);
}
}
Method 3
default
{
touch_start(integer total_number)
{
key id = llDetectedKey(0);
integer chan = (integer)("0x" + (string)id) | 0xD0000000;
llRegionSayTo(id, 0, "Random Channel: "+(string)chan);
}
}Dchan = (integer)("0x" + (string)llGetOwner()) | 0xD0000000;
Memory Limit
Method 1
Sets the memory limit to 20kb
lllSetMemoryLimit(20000);
Method 2
Sets the memory limit to used memory + 5kb
lllSetMemoryLimit(llGetUsedMemory()+5000);
Method 3
Sets the memory limit to used memory + 4096 bytes. Hexadecimal number 0x1000 = 4096
llSetMemoryLimit(llGetUsedMemory()+0x1000);
Memory Free
llOwnerSay("\n::: "+llGetScriptName()+" :::\nFree Memory: "+(string)llGetFreeMemory());
llOwnerSay("\n::: "+llGetScriptName()+" :::\nFree Memory: "+(string)llGetFreeMemory()+" of "+(string)llGetMemoryLimit());
Owner Check
Touch
default
{
touch_start(integer num_detected)
{
key id = llDetectedKey(0);
//owner check (touch) prevents others from access this script.
if ( id != llGetOwner() ) {return;}
// send a message to the chat window of the avatar touching
llRegionSayTo(id, 0, "You touched this!");
}
}
Listen
default
{
listen(integer channel, string name, key id, string msg)
{
//owner check (listen)
if ( llGetOwner() != llGetOwnerKey(id) ){return;}
llOwnerSay(msg);
}
}
Listen
Basic Listener
integer chan;
default
{
state_entry()
{
chan = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );
llListen(chan, "", "", "");
}
listen(integer channel, string name, key id, string msg)
{
//owner check (listen)
if ( llGetOwner() != llGetOwnerKey(id) ){return;}
llOwnerSay(msg);
}
}
Global Listener
integer listener;
integer chan;
default
{
state_entry()
{
chan = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );
listener = llListen(chan, "", "", "");
}
listen(integer channel, string name, key id, string msg)
{
//owner check (listen)
if ( llGetOwner() != llGetOwnerKey(id) ){return;}
llOwnerSay(msg);
llListenRemove(listener);
}
}
Say
default
{
touch_start(integer num_detected)
{
key id = llDetectedKey(0);
// send a message to the chat window of the avatar touching
llRegionSayTo(id, 0, "You touched this!");
// send a message to the attachments of the avatar touching
// example channel: -12345
llRegionSayTo(id, -12345, "Hello there attachments!");
//full region range (note cannot be channel 0)
llRegionSay(25,"This is an incredibly useless program." );
//100 meter range
llShout(0, "I scream icecream!");
//20 meter range
llSay(0, "Hello, Avatar!");
//10 meter range
llWhisper(0, "This is an incredibly useless program.");
//gride wide
llInstantMessage( id, "Someone touched me!" );
//owner only
llOwnerSay("Ouch!");
}
}
Distance
Touch
-
default
{
touch_start(integer total_number)
{
key id = llDetectedKey(0);
//distance
vector pos = llDetectedPos(0);
float distance = llVecDist(pos, llGetPos() );
//range
float touchRange = 20;
if ( distance > touchRange ){return;}
llRegionSayTo(id, 0, "You touched this!");
}
}Listen
-
default
{
listen(integer channel, string name, key id, string msg)
{
//distance
vector pos = llList2Vector(llGetObjectDetails(id,[OBJECT_POS]),0);
float distance = llVecDist(pos, llGetPos() );
//range
float touchRange = 20;
if ( distance > touchRange ){return;}
llSay(0, msg);
}
}
Toggle
Method 1
This is the basic way to do it. toggles from false to true when touched. It works but it's more time consuming to code if you need more than one switch, and increases the likelyhood of bugs due to complexitity.
//ON-OFF Toggle
integer o;
default
{
state_entry()
{
llSetText("OFF",<1,1,1>,1);
}
touch_start(integer total_number)
{
if ( o == TRUE )//off
{
o = FALSE;
llSetText("OFF",<1,1,1>,1);
}
else//on
{
o = TRUE;
llSetText("ON",<1,1,1>,1);
}
}
}
Method 2
More advanced. I found this method looking at a script for a light switch. It toggles from -1 to 0 rather than false to true which makes it difficult to work with.
//ON-OFF Toggle
integer o = -1;
default
{
state_entry()
{
llSetText("OFF",<1,1,1>,1);
}
touch_start(integer total_number)
{
if(o = ~o)//off
{
llSetText("OFF",<1,1,1>,1);
}
else//on
{
llSetText("ON",<1,1,1>,1);
}
}
}
Method 3
As above but toggles from false to true. I use this for most scripts requring a toggle switch.
//ON-OFF Toggle
integer o;
default
{
state_entry()
{
llSetText("OFF",<1,1,1>,1);
}
touch_start(integer total_number)
{
if(o = !o)//on
{
llSetText("ON",<1,1,1>,1);
}
else//off
{
llSetText("OFF",<1,1,1>,1);
}
}
}Hold Touch
integer touched;
default
{
touch_start(integer num_detected)
{
touched = FALSE;
llResetTime();
}
touch(integer num_detected)
{
if (llGetTime() > 1.0 && touched == FALSE)
{
touched = TRUE;
llSay(0, "Held click.");
}
}
touch_end(integer num_detected)
{
if (llGetTime() <= 1.0)
{
llSay(0, "Normal click");
}
}
}-
list menuButtons(integer page, list buttons)
{
page--;
integer index = (page * 9);
list tokens = llList2List(buttons, index, index + 8 );
integer length = llGetListLength(tokens);
if ( length < 9 )
{
length = 9 - length;
//llSay(0,(string)length);
integer i;
for (i = 0; i < length; i++)
{
tokens += "-";
}
}
return tokens;
}
-
example list for testing scripts.
list greekLetters = ["Alpha","Beta","Gamma","Delta","Epsilon","Zeta","Eta","Theta","Iota","Kappa","Lambda","Mu","Nu","Xi","Omicron","Pi","Rho","Sigma","Tau","Upsilon","Phi","Chi","Psi","Omega"];
-
string str;
integer i;
integer length = llGetListLength(tokens);
for (i = 0; i < length; ++i)
{
str = llList2String(tokens,i);
llSay(0, (string)i+" - "+str);
}
loops
F
integer i;
integer end = llGetListLength(tokens);
for (i = 0; i < end; ++i)
For Loop
string str;
integer i;
integer end = llGetListLength(tokens);
for (i = 0; i < end; ++i)
{
str = llList2String(tokens,i);
llSay(0, (string)i+" - "+str);
}
while(i < end)
{
str = llList2String(tokens,i);
llSay(0, (string)i+" - "+str);
i++;
}
While
Do While
LSL Golf: Most efficient loop. (Not really my invention, but interesting)
integer i = -(lVar != []);
string elem;
// If lVar is guaranteed to never be empty, can drop the `if (i)` part
if (i) do {
elem = llList2String(lVar, i);
// do something with elem
} while(++i);
llSubStringIndex
default
{
touch_start(integer total_number)
{
string str;
string message = "Abi Wolfy";
if ( ~llSubStringIndex(message,"Wolfy") )
{
llSay(0, message);
}
}
}
Odd & Even
Odd or even number check
#1
integer num;
default
{
touch_start(integer num_detected)
{
num++;
string str;
if ( (num % 2) == 0 )
{
str = "even";
}
else
{
str = "odd";
}
llSay(0, (string)num+" is "+str);
}
}
meth 2
integer num;
default
{
touch_start(integer num_detected)
{
num++;
string str;
if ( num % 2 )
{
str = "odd";
}
else
{
str = "even";
}
llSay(0, (string)num+" is "+str);
}
}
bitwise
integer num;
default
{
touch_start(integer num_detected)
{
num++;
string str;
if (num & 1)
{
str = "odd";
}
else
{
str = "even";
}
llSay(0, (string)num+" is "+str);
}
}
Reverse Number
integer num = 7;
integer end = 8;
num = end - num;// 8 - 7 = 1
Colour
//Converting RGB colours in hexadecimal to LSL colour vectors
vector hex2lsl(string hex)
{
if ( llGetSubString(hex, 0, 0) == "#" ){hex = llDeleteSubString(hex, 0, 0);}
integer i = (integer)("0x" + hex);
return <(i >> 16) & 0xFF, (i >> 8) & 0xFF, (i & 0xFF)> / 255;
}
//Function made by me
string lsl2Hex( vector colour )
{
string str;
string hex = "0123456789abcdef";
integer i;
integer num;
//integer2Hex((integer)(255*colour.x))
num = (integer)(255*colour.x);
i = (num / 16);
num = (num % 16);
str += llGetSubString(hex, i, i)+llGetSubString(hex, num, num);
//integer2Hex((integer)(255*colour.y))
num = (integer)(255*colour.y);
i = (num / 16);
num = (num % 16);
str += llGetSubString(hex, i, i)+llGetSubString(hex, num, num);
//integer2Hex((integer)(255*colour.z)
num = (integer)(255*colour.z);
i = (num / 16);
num = (num % 16);
str += llGetSubString(hex, i, i)+llGetSubString(hex, num, num);
return "#"+str;
}
//The following functions will convert from an RGB color, with values from 0 to 255, to SL color, and back.
vector sl2rgb( vector sl )
{
sl *= 255; //Scale the SL color up by 255
return <(integer)sl.x, (integer)sl.y, (integer)sl.z>; //Make each part of it a whole number
}
vector rgb2sl( vector rgb )
{
return rgb / 255; //Scale the RGB color down by 255
}
//Converting RGB colours in hexadecimal to LSL colour vectors
vector hex2lsl(string hex)
{
integer i = (integer)("0x" + hex);
return <(i >> 16) & 0xFF, (i >> 8) & 0xFF, (i & 0xFF)> / 255;
}
percentage
integer percentageTest( integer total, integer value )
{
return (integer)((float)value / total * 100.0);
}
Lists
Tokens
list dataList = ["one","two","three"];
string data = llList2CSV(dataList);
list tokens = llParseString2List(data, [","], []);
string message = llToUpper(llList2String(tokens,0));
if ( message = "ONE" ){}
Notecard Reader
string gNotecard = ".notecard";
integer gNcLine;
key gNcQuery;
integer gRetry;
default
{
state_entry()
{
if (llGetInventoryType(gNotecard) != INVENTORY_NONE)
{
gNcQuery = llGetNumberOfNotecardLines(gNotecard);
}
}
dataserver( key query, string data )
{
if ( query == gNcQuery )
{
llResetTime();
integer end = (integer)data;
integer i = gNcLine;
for (; i <= end; ++i)
{
string line = llGetNotecardLineSync(gNotecard, i);
if ( line == NAK )
{
llOwnerSay("Cache interrupted on line "+(string)(i+1)+"! Retry attempt: "+(string)gRetry);
if ( gRetry++ < 3 )
{
gNcLine = i;
gNcQuery = llGetNumberOfNotecardLines(gNotecard);
}
return;
}
else if ( line == EOF || line == "END" )
{
llOwnerSay("Debug: EOF\nTime taken: "+(string)llGetTime());
gNcLine = 0;
gRetry = 0;
llSetText("--- EOF ---"+"\nTime: "+(string)llGetTime(),<1,1,1>,1);
return;
}
else if ( llGetSubString (line, 0, 0) != "#" && llGetSubString (line, 0, 1) != "\\\\" )
{
integer e = llSubStringIndex( line, "=" );
if (~e)
{
string name = llStringTrim(llToUpper(llGetSubString( line, 0, e-1 )), STRING_TRIM);
string value = llStringTrim(llGetSubString( line, e+1, -1 ), STRING_TRIM);
llOwnerSay("Name: '"+name+"'\nValue: '"+value+"'");
}
}
llSetText("Line: "+(string)(i+1)+ " of "+(string)end+"\nTime: "+(string)llGetTime(),<1,1,1>,1);
}
}
}
}