Difference between revisions of "User talk:Prajna Vella"

From Second Life Wiki
Jump to navigation Jump to search
 
Line 1: Line 1:
''[Moved here to work on. It was proposed for the LSL 101, but this is a wiki...]''
Sorry about the mess; I'm just practising my wiki editing.
 
Here is the simplest possible valid LSL script.  It doesn't actually ask the computer to do anything but all scripts have, at minimum, this structure:


<lsl>
<lsl>
default {
// Give object contents in a folder to AV on touch - by Prajna Vella
    state_entry() {
//
    }
// This script can be put in a 'giver' object along with the items you want to give to
}
// anyone who touches the object.  If you want to add an item, just add it to the
</lsl>
// object's contents; the script will notice the change and update the list.
//
// The script will not give any no-transfer items (because it can't, just as you can't)
// nor will it add no-copy items because llGiveInventoryList() doesn't allow it.


In order to explain even this short piece of code we need to introduce you to some terms that will probably be new to you.
string version = "1.0"; // the script version number
string folder = "Ephemera Gifts"; // the name of the folder we will give to the AV that touches the object
string title = "Gifts"; // the floating title for the giver object
list contents; // the list of items we will put in the folder


LSL scripts use two concepts called ''states'' and ''events''.
// check we can give the item and if so add it to the list
// this could have been included in the getList() function but the script is
// much more readable if it is done here.
addItem(string itemName) {
// get the permissions the object owner has for this item
integer ownerPerms = llGetInventoryPermMask(itemName, MASK_OWNER);
// only add items the owner has permission to copy and transfer
if ((ownerPerms & (PERM_COPY | PERM_TRANSFER)) == (PERM_COPY | PERM_TRANSFER))
// add the item to the list
contents += itemName;
else
llOwnerSay("Couldn't add '" + itemName + "' because you must have transfer and copy permissions.");
}


'''States'''
// get the list of the items we will give
 
getList() {
''State'' is actually a very good name for what states do in LSL. If you think of a car, it can either be moving or stopped. We can say its state is moving (when it is moving) and its state is stopped (when it is stopped).  Another example is your own state of being: you can be awake, asleep, active, sitting, standing, hungry, bored, confused, etc.
// empty the current list of items
 
contents = [];
All LSL scripts have at least one state: the ''default'' state. This is the state when no other states are active.  You can see in the code above the word ''default'' is used to tell the script about what happens in the default state.
// how many items are there in the contents?
 
integer items = llGetInventoryNumber(INVENTORY_ALL);
Here is an example with two states:
// we find out the name of this script here so we only have to do it once
 
string thisScript = llGetScriptName();
<lsl>
// this efficiently refers to the current item and will loop until we have reached item 0
default {
while (items) {
    state_entry() {
// this line gets the item name but first decrements the item counter
        llOwnerSay("Switching to the hungry state...");
// it is very efficient and takes care of the fact items are numbered starting with 0
        state hungry;
string thisItem = llGetInventoryName(INVENTORY_ALL, --items);
    }
// we need to check we don't give a copy of this script
if (thisItem != thisScript)
addItem(thisItem);
}
}
}


state hungry {
// we do this as a user defined function so it can be called from both state_entry() and changed() events
    state_entry() {
config() {
        llOwnerSay("I am very hungry! Does anyone have any spam?");
// tell the owner what is happening and get the list of items to give
    }
llOwnerSay("Version " + version);
llOwnerSay("Configuring...");
getList();
llOwnerSay("Ready to give folder " + folder);
llOwnerSay("Containing: " + llList2CSV(contents));
// set the floating text on the giver
llSetText(title, <1.0,1.0,1.0>, 1.0);
}
}
</lsl>


The first thing to notice is that the hungry state needs the word ''state'', so that the script knows this describes a state rather than something else.  The default state does not need to be proceeded by the word state.
default
{
// when the script starts running
state_entry() {
config();
}


Next, notice the curly braces '{' and '}'.  These tell the script which lines are part of the default state, which are part of the hungry state, and which belong to the state_entry() event handler, which we describe next.
// when someone touches the object
touch_start(integer count) {
// count is how many people touched the object
while (count) {
// we find out the UUID key of the AV that touched
key id = llDetectedKey(--count);
// and give them the folder
llGiveInventoryList(id, folder, contents);
}
}


'''Events'''
// when the contents of the object is changed
 
changed(integer change) {
When something happens we can say an ''event'' has happened.  LSL knows about many kinds of events and can respond to them depending on what kind of event happened.
if (change && CHANGED_INVENTORY)
 
// we get the list of items again
LSL scripts don't run on your PC, they run on the server where the sim you are in is running. The server takes care of seeing when something changes - an avatar moves, you click something, the clock ticks, someone types something in text chat, you create an object, save a notecard, give someone a landmark, etc. - and it passes on information about those changes to the viewer running on your PC, which then displays those changes or shows a dialog or whatever is needed.  The server also passes those events on to any scripts that have asked to know about that particular kind of event.
config();
 
}
Your script can tell the server to inform it of events by including an event handler.  In the example above we have added event handlers called ''state_entry()'', which requires the server to tell it when the script enters that particular state.  When the script receives the state_entry() event it runs the instructions inside the curly braces belonging to the state_entry() event handler.
 
Some events also pass other information from the server; for instance the ''listen()'' event receives a channel number (to indicate which channel the chat was heard on), the name of the avatar or object that sent the chat, their (or its) UUID key, and the text of the message that was typed or sent.  The listen() event handler is declared like this:
 
<lsl>
listen(integer channel, string name, key id, string message) {
    // some actions to take when something is heard in text chat
}
}
</lsl>
</lsl>
We will discuss more about events but before we do, and in order to explain the code above, we need to introduce another concept: variables.
'''Variables'''
We said that the server can pass information about events and in our example above you can see that we refer to the different pieces of information by giving them different names: channel, name, id, message.  Not only are these separate pieces of information, they are different ''types'' of information: channel is a number, name is text, id is a special kind of number called a UUID key, message is text.
Variables, then, are declared by giving their type and their name. But variables would not be very useful if they did not also have a ''value''.  When we give a value to a variable it can be said we ''defined'' the variable.
Before you use a variable in LSL you ''must'' declare it and usually you will want to define it as well.  These can both be done on separate lines or on the same line of code. Here are two examples:
<lsl>
string myName;
myName = "An Avatar";
// or
string myName = "An Avatar";
</lsl>
So what different types of variables does LSL know about?
'''integer'''
Integers are numbers, but only a limited set of numbers.  Integers in LSL are any numbers between −2,147,483,648 and +2,147,483,647, so long as they are 'whole' numbers (that is, they don't have a decimal point, like 1.5).
integers are declared and defined like this
<lsl>
integer myNumber = 42;
</lsl>
You are used to using the decimal number system (called ''base 10''), where numbers are counted using the digits 0 to 9, but you should also know there are other number systems that can be used with LSL, such as hexadecimal (''base 16''), which uses digits 0 to 9 and letters A to F.  You don't need to know about the hexadecimal system to write scripts but you may well come across hexadecimal numbers if you are modifying scripts someone else has written and you may later find that there are some places where it makes sense to use hexadecimal numbers instead of decimals.
Hexadecimal numbers are written as in this example (which does exactly the same as the example above):
<lsl>
integer myNumber = 0x2a;
</lsl>
''2a in hexidecimal = 42 [(2 * 16) + 10 is the same as (4 * 10) + 2]''
A note to those who have used other programming languages before: LSL does not have a binary variable type.  TRUE and FALSE are stored using integers with TRUE having a value of 1 and FALSE having a value of 0. We will discuss this in more detail later.
'''float'''

Latest revision as of 16:11, 6 May 2009

Sorry about the mess; I'm just practising my wiki editing.

<lsl> // Give object contents in a folder to AV on touch - by Prajna Vella // // This script can be put in a 'giver' object along with the items you want to give to // anyone who touches the object. If you want to add an item, just add it to the // object's contents; the script will notice the change and update the list. // // The script will not give any no-transfer items (because it can't, just as you can't) // nor will it add no-copy items because llGiveInventoryList() doesn't allow it.

string version = "1.0"; // the script version number string folder = "Ephemera Gifts"; // the name of the folder we will give to the AV that touches the object string title = "Gifts"; // the floating title for the giver object list contents; // the list of items we will put in the folder

// check we can give the item and if so add it to the list // this could have been included in the getList() function but the script is // much more readable if it is done here. addItem(string itemName) { // get the permissions the object owner has for this item integer ownerPerms = llGetInventoryPermMask(itemName, MASK_OWNER); // only add items the owner has permission to copy and transfer if ((ownerPerms & (PERM_COPY | PERM_TRANSFER)) == (PERM_COPY | PERM_TRANSFER)) // add the item to the list contents += itemName; else llOwnerSay("Couldn't add '" + itemName + "' because you must have transfer and copy permissions."); }

// get the list of the items we will give getList() { // empty the current list of items contents = []; // how many items are there in the contents? integer items = llGetInventoryNumber(INVENTORY_ALL); // we find out the name of this script here so we only have to do it once string thisScript = llGetScriptName(); // this efficiently refers to the current item and will loop until we have reached item 0 while (items) { // this line gets the item name but first decrements the item counter // it is very efficient and takes care of the fact items are numbered starting with 0 string thisItem = llGetInventoryName(INVENTORY_ALL, --items); // we need to check we don't give a copy of this script if (thisItem != thisScript) addItem(thisItem); } }

// we do this as a user defined function so it can be called from both state_entry() and changed() events config() { // tell the owner what is happening and get the list of items to give llOwnerSay("Version " + version); llOwnerSay("Configuring..."); getList(); llOwnerSay("Ready to give folder " + folder); llOwnerSay("Containing: " + llList2CSV(contents)); // set the floating text on the giver llSetText(title, <1.0,1.0,1.0>, 1.0); }

default { // when the script starts running state_entry() { config(); }

// when someone touches the object touch_start(integer count) { // count is how many people touched the object while (count) { // we find out the UUID key of the AV that touched key id = llDetectedKey(--count); // and give them the folder llGiveInventoryList(id, folder, contents); } }

// when the contents of the object is changed changed(integer change) { if (change && CHANGED_INVENTORY) // we get the list of items again config(); } } </lsl>