User:Fred Gandt/Tuition

From Second Life Wiki
< User:Fred Gandt
Revision as of 17:24, 26 February 2010 by Fred Gandt (talk | contribs) (Started new section about order in scripting.)
Jump to navigation Jump to search
FG jpg.jpg

Some Complete Scripts for Use and Abuse

Free Scripts (content constantly updating)

Terms Used in Scripting

Parentheses = ()

Brackets = []

Braces = {}

Angle brackets = <>

Various Scripting Examples for Tuition

Over time I will be creating a full course starting here to teach the basics of LSL scripting. I will be accompanying the posted examples with text explanation, videos and in-world tuition. The course will take quite some time to produce fully since I enjoy scripting for my own amusement most of the time I am logged in so, unless I can invent an LSL powered time machine I will be creating this course in between projects.

User Created Functions

LSL allows us to create functions to run by calling those functions within the script runtime. They are an extremely useful way to help organize a script, keep the memory use down and simplify code. Some simple ways to create and use this ability are shown below...

THIS IS NOT A SINGLE SCRIPT.

<lsl>// This first example shows the most basic syntax used to create a function.

Function() // This is the name we choose for our function. We use the name to call its use. {

   ;

}

default {

   state_entry()
   {
       Function(); // This is how we call for the function to run.
   }
   touch_start(integer nd)
   {
       Function(); // From anywhere the function can be called.
   }

}

// So we add the actions we desire within the function braces.

Function() {

   llOwnerSay("I worked!!");

}

default {

   state_entry()
   {
       Function();
   }
   touch_start(integer nd)
   {
       Function();
   }

}

// We can add conditions inside the function and pass to it any type of information.

Function(integer i) // Now the function carries information to be processed. {

   if(i) // We can check the information as the function runs.
   llOwnerSay("I worked!!");
   else
   llOwnerSay("I still worked!!");

}

default {

   state_entry()
   {
       Function(TRUE); // Now when we call the function we MUST provide the information the function NEEDS to run
   }                                              // (even if the function doesn't always use it).
   touch_start(integer nd)
   {
       Function(FALSE);
   }

}

// We can give the function a type and have it return the result dependent on what we feed it.

string Function(integer i, integer q) {

   integer r = (i + q);
   return ((string)r); // This style MUST return the same type of info as the function type.

}

default {

   state_entry()
   {  // Now the function can be used in-line as it returns the type of info we want to use directly to where it is called.
       llOwnerSay(Function(5, 5));
   }
   touch_start(integer nd)
   {
       integer i = 5;
       integer q = (i*5);
       llOwnerSay(Function(i, q));
   }

}</lsl>

Scopes and Variables

This is to demonstrate where a variable may and may not be referenced within a script. It also demonstrates a basic view of what dictates a scope. A scope is an area within a script that is a parent and/or a child of another area. There will be more in-depth explanation as time goes on.

<lsl>integer global_variable = TRUE; // This variable can be referenced throughout the script (in any state).

default { // No variable can be created to exist throughout the state (use a global variable).

   state_entry()
   {
       integer event_variable = TRUE; // Events can have local variables.
       if(global_variable) // A global variable can be referenced in any child scope in the script.
       if(event_variable) // The event variable can be referenced anywhere within the event it is created in.
       {
           integer conditional_variable_1 = TRUE; // If the event has child scopes new local variables can be created for them.
           if(global_variable)
           if(event_variable)
           if(conditional_variable_1)
           {
               integer conditional_variable_2 = TRUE; // Each local scope can have its own unique variables.
               if(global_variable)
               if(event_variable)
               if(conditional_variable_1)
               if(conditional_variable_2)
               {
                   integer conditional_variable_3 = TRUE;
                   if(global_variable)
                   if(event_variable)
                   if(conditional_variable_1)
                   if(conditional_variable_2)
                   if(conditional_variable_3)
                   {
                       integer conditional_variable_4 = TRUE;
                       if(global_variable)
                       if(event_variable)
                       if(conditional_variable_1)
                       if(conditional_variable_2)
                       if(conditional_variable_3)
                       if(conditional_variable_4)
                       llOwnerSay("Yikes!"); // We made it through!!
                   }
               }
           }
       } // No variable can be referenced outside the scope it was created in.
   }

}</lsl>

Notes on order of operations in scripts

As a script runs it uses information we give it and information it gets for us. If we instruct the script to get information that we want to use immediately we can use the requesting function in-line like this -<lsl>llSetText(llKey2Name(llGetOwner()), <1.0,1.0,1.0>, 1.0);</lsl>However, some requested information is not acquired at the calling of the function but during the triggering of an associated event. These events include -<lsl>dataserver

http_response

run_time_permissions</lsl>amongst others. When using this type of data requesting function and event setup we need to be careful how we structure our script.

The following is an example of a typical mistake made in scripts (I have fixed scripts sold with this error in them).<lsl>// This script compiles without error but is badly written. It attempts to animate the owner of the script... // ...when the object it is in is touched. But written this way it will fail.

integer perms; // Used to store the boolean value TRUE (1) or FALSE (0). // If the script has been granted permissions the value of perms will be 1. Else it will be zero. key owner; // Used to store the UUID (key) of the owner of the script.

string anim = "Dance"; // The name of the anim we want to use.

default // Create a default state. {

   state_entry() // On entering the state...
   {
       owner = llGetOwner(); // Establish the owners UUID and store it.
   }
   touch_start(integer nd) // When touched...
   {
       if(llDetectedKey(0) == owner) // Check if the person who touched us is the owner by comparing the UUIDs.
       {
           llRequestPermissions(owner, PERMISSION_TRIGGER_ANIMATION); // Request permission to animate the owner.
           if(perms) // If we have permission...
           llStartAnimation(anim); // Start the animation.
       }
   } // So what is all this stuff for?
   run_time_permissions(integer perm) // This event is triggered as a result of requesting permissions.
   { // We can use a condition like this to check that we have the perms we asked for.
       if(perm & PERMISSION_TRIGGER_ANIMATION)
       perms = TRUE; // Then we can store the condition of the permissions to a global variable (for checks).
   }

}// So if asking for permissions triggers run_time_permissions with the result we need to wait... // ...until run_time_permissions is triggered before we can know one way or another... // ...if our request for perms was granted. The problem with this script then is that we attempt to start the animation... // during the run time of the triggered touch_start event and while that is running the triggering of... // ...run_time_permissions has to wait. So the value of perms cannot be established until after the last code in... // ...the touch_start event has run.

// The lesson is that llRequestPermissions does what it says. It requests the perms. It doesn't always get them. // run_time_permissions is where we check what perms we have got and act accordingly.</lsl>So what we need to do is change the order of the function calls and events to something like this -<lsl>integer perms;

key owner;

string anim = "Dance";

default {

   state_entry()
   {
       owner = llGetOwner();
       llRequestPermissions(owner, PERMISSION_TRIGGER_ANIMATION);
   }
   touch_start(integer nd)
   {
       if(llDetectedKey(0) == owner)
       {
           if(perms)
           llStartAnimation(anim);
       }
   }
   run_time_permissions(integer perm)
   {
       if(perm & PERMISSION_TRIGGER_ANIMATION)
       perms = TRUE;
   }

}</lsl>Or this -<lsl>integer perms;

key owner;

string anim = "Dance";

default {

   state_entry()
   {
       owner = llGetOwner();
   }
   touch_start(integer nd)
   {
       if(llDetectedKey(0) == owner)
       {
           llRequestPermissions(owner, PERMISSION_TRIGGER_ANIMATION);
       }
   }
   run_time_permissions(integer perm)
   {
       if(perm & PERMISSION_TRIGGER_ANIMATION)
       {
           perms = TRUE;
           llStartAnimation(anim);
       }
   }

}</lsl>Getting things in the right order is extremely important. I hope this helps