Krull Kitty's Scripting Course

Creating scripts
Post Reply
User avatar
Krull Kitty
Posts: 100
Joined: Thu Aug 06, 2020 1:25 pm
Has thanked: 39 times
Been thanked: 81 times

Krull Kitty's Scripting Course

Post by Krull Kitty »

###### PART 1 ######

LSL, Otherwise known as Linden Scripting Language, the primary language
used to create functionality in second life.

*********DATA TYPES***********
Some people may not realize that scripting is about finding, calling for, manipulating and returning
information. These are the most basic ideas behind why we need scripts to make things happen.

Making things move requires that we understand our in-world coordinate system and then tell
the object how to act within those coordinates. Scripting also requires that we understand the
"Type" of data, or information, we are using for our intended tasks.

Quick Segway:

An important resource to remember is the online scripting portal located at this web address:
http://wiki.secondlife.com/wiki/LSL_Portal

This page can be quickly accessed by going to the "Help" drop down menu above and selecting
the "Scripting Portal..." option from the menu, this will take you directly to the scripting reference.

The newer SL browsers do not have the scripting portal listed in the help menu drop down so you will
have to rely on good old cut and paste.

END of Segway!

Back to data types. Virtual scripting allows us to communicate with what would otherwise be
inanimate objects. Thats what makes scripting interesting. We can also make objects communicate
with each other and pass data between themselves automatically.

Objects can be told to scan the environment and act or react in a certain way if something or
someone is detected.

By understanding the "Types" of data we can manipulate and the information we can send and receive
from the environment, we can dream up, and imagine, some pretty cool effects and actions.

The environment uses a set number of data "Types":
Key - "a822ff2b-ff02-461d-b45d-dcd10a2de0c2"
Integer - Integers are whole numbers. Between -2,147,483,648 and +2,147,483,647
Float - 175.098267 --> If you want a decimal point in your number, then it is a float.

Rotation - <0.0, 0.0, 0.0, 1.0>
Quaternion -<0.0, 0.0, 0.0, 1.0> --> Quaternions and rotations are the same thing.
Vector - <105,12,55>

String - "I am a string."
List - ["List Item 1", "List Item 2", "List Item 3", "Etc...", "On and On", "And on..."]

These "Types" of data allow us to create virtual "Containers" that store numerical, alphanumerical
and text type data.

One of the more unique data types we find in virtual environments are called "Keys".
A key will look something like this: ec1f7d45-744c-427f-9987-a96d7b50d72b
A "Key" is also known as an object or avatar UUID.

A UUID is known as a "Universally Unique Identifier".

Every single thing in a virtual environment has a "Key" or "UUID" value. Everything!

*********FUNCTIONS***********

"Functions" are the programming codes we use to actually manipulate the Data "Types"
we are working with.

Functions are numerous, there are so many functions available that allow us to manipulate
our data and our objects that the list is much too long to go through, so we focus on small
numbers of relevant functions to get started and to develop an understanding of how
functions work in Virtual environments.

When looking at a function in the scripting portal, the header in the portal shows a function
listed as follows: Function: llSay( integer channel, string msg );

This listing essentially tells us what the Function is looking for in order for it to behave as
intended in our program.

Function: llSay( integer channel, string msg );

The first part "Function:" tells us that this page refers to a Function of course.

"llSay", the part before the bracket is the "Function" itself.

"( integer channel, string msg )", This tells us that this "Function" is looking for 2 values,
An "Integer" first which represents the channel to chat on,
and a "String", the actual message to chat out.

";", The semi colon is VERY important, 90% of all the lines in a program must have this
semi colon at the end. This tells the program that this line of code is finished and to
move onto the next line of code in the program.

Note that all "Functions" have 2 lower case Ls in front of them (ll), which stands for
Linden Language.

We are going to be working with functions regularly and quite often! A program will not do much
without "Functionality" ;)

The Scripting portal is the place to search for specific functions when you are looking to
achieve a certain effect or do something specific with data.

*********PROGRAM STRUCTURE***********

The server is the computer which reads, interprets and reacts to the scripts based on what we
program into them.

The server reads a script from left to right, top to bottom, just like we read books.
LSL scripts have 2 main sections, the "Declaration" section and the "Body".

The "Declaration" section is where we declare the variables, or data types, that we wish
to use in the script. When we declare variables in this section these variables will be
available throughout the entire script.

The "Body" of the script is where we begin constructing the logic of our program with
"Functions".

The "Body" of our script is where we first encounter something called an "Event" block.

An "Event" block is a block of code which tells the server to do something when this or that
takes place. There are many "Events" that can occur to an object or script.

default
{
state_entry()
{
llSay(0, "Hello, Avatar!");
}
}

The simple program above demonstrates the basic "Body" structure of code.
The "default" code above tells the server that this is where the script logic
begins.

This is also the default script you will see after creating a new script.

"state_entry()" is the code which specifies the first event encountered in any
script, and that is that the script has just entered into existence in-world.
Weather it be because you just rezzed the object with the script in it, just created
and compiled the script or just reset the script.

Whenever you bring a script into the environment one of the first "Events" that occurs
to the script is the "state_entry()" event!

The "state_entry()", "Code Block" is not required by the script, but it is helpful to know that
using this Code block means that the server will do whatever is in this "Event Block"
before it does anything else in your script.

This is useful if you need to load data into variables before the rest of the script can
be properly executed.

Notice that each code block is followed by curly braces, "{}", an open and closed curly
brace defines the scope, or length, of each block and the code within it.

default
{ }

default <<---NOTICE that code blocks do not require Semi Colons ";".
{
state_entry()
{
}
}

Notice how the Curly braces nest within each other. The main script is all contained
within the "default" code block, think of the "default" code block as the main container
for the rest of your script.

Some of the more common event code blocks which occur inside the main "default"
container are;

touch_start(integer total_number)
{
}
on_rez(integer start_param)
{
}
listen(integer channel, string name, key id, string message)
{
}
attach(key id)
{
}
changed(integer change)
{
}
sensor (integer numberDetected)
{
}
collision_start(integer num)
{
}
timer()
{
}
link_message(integer source, integer num, string str, key id)
{
}
state_exit()
{
}
at_target(integer tnum, vector targetpos, vector ourpos)
{
}
not_at_target()
{
}

Event Code Blocks are how we coordinate and manage what is happening
in the environment. Each Event Code Block "Listens" in a way for a specific
thing to happen, and when it happens it tells the server to execute the code
within it.

The nice thing about Event Code Blocks is that they can also be used by us
to trigger events as well, using the "timer()" code block for example allows
us to create a function which repeats over a certain time interval.

All of the available "Events" are also listed on the Scripting portal for you
to review and read about. When you dissect someone elses script, understanding
the event blocks will help you to gain a better understanding of what the script
is for.

*********VARIABLE ASSIGNMENTS***********

We looked at Data "Types" when we began, this is where we put the idea of Data "Types"
to use.

When we are creating a new script we will always be working with some sort of value.
Whether the value is a number or text or a combination of both, even a physical grid
position, we need to use that value according to what it is.

Assigning a value to a variable is really easy to do.

string MyVar = "Hello!";

This line of code tells the server to "Remember" that the variable "MyVar" retains or holds
the string value "Hello!".

the "string" part tells the server that this variable is going to be "Text".
The "MyVar" part is the name I chose to give my variable so I would remember it.
The "= 'Hello!';" part is telling the server that the variable I just created called "MyVar"
contains the value "Hello!".

When you declare a new variable, you do not have to assign a value, you can assign
a value to your new variable later in your script if you don't know what the value of
the variable will be.

Its generally a good idea to start declaring your variables above, and before, your "default"
code block. This makes the value of these variables available to all of the "Functions" and
"Events" in your script, even if they change dynamically.

*********LETS GET STARTED!***********

Let's create a script, a simple script, which demonstrates the use of some
basic concepts that we learned about above.

You have the choice of rezzing a prim on the ground and creating a new
script inside your new prim, or right clicking on any folder in your inventory
and selecting the "New Script" option.

Let's begin by declaring a new string variable called "MyText" in the upper
script area, 'Before' our 'default' code block; Ignore the stars they are placed
into this script to keep the stages separate.

***************************
string MyText = "Hello There!";
***************************

Now we add the 'default' code block with the opening and closing curly braces;
***************************
string MyText = "Hello There!";
default
{
}
***************************

Next, we add our first event, the 'state_entry()' event code block,
this tells the server to do this first as soon as the script starts;
***************************
string MyText = "Hello There!";
default
{
state_entry()
{
}
}
***************************

Finally, we add a "Function" inside our "state_entry()" code block since the
server will check here first for "Functions" to execute;
***************************
string MyText = "Hello There!";
default
{
state_entry()
{
llSay(0, MyText);
}
}
***************************

Now click the "Save" button at the bottom left hand corner of your script
screen and the script will be saved.

Discussion:
What will this script do.

Scripting 101.a
By: Krull Kitty
Krull Quar in Second Life
These users thanked the author Krull Kitty for the post (total 5):
Ilan TochnerAda RadiusFrank SquirrelHerderAlexina ProctorMichael Timeless
User avatar
Krull Kitty
Posts: 100
Joined: Thu Aug 06, 2020 1:25 pm
Has thanked: 39 times
Been thanked: 81 times

Re: Krull Kitty's Scripting Course

Post by Krull Kitty »

###### PART 2 ######

Stage 2 in our scripting class involves interacting with the environment
by harnessing the power of "Functions" in order to manipulate the world
around us.

*********FUNCTIONS & FUNCTIONALITY***********

"Functions" also allow us to extract information from the environment
and use that information to manipulate the environment in return.

Lets have a look at the scripting portals "Function" list:
http://wiki.secondlife.com/wiki/Category:LSL_Functions

As you look through the list of functions on this page some of them
should be obvious in terms of what they are used for.

See how many you can identify by default on your own. You can find out more
about a function by clicking on it in the list and it will take you to that function's
description page. The description page for a function sometimes has a sample
script listed below the details which demonstrate how the function is used.

This makes the scripting portal very useful in terms of learning functions.
And finding functions for specific projects and purposes.

Let's begin by manipulating an in world object. Create a simple cube
on the ground, while in edit mode go to the "Content" tab of the
edit window.

Click on the, "New Script" button on the top left side of the Content section.
A "New Script" will appear inside the content section of the cube.

Right click on the script to rename it to something more appropriate.
Let's call it "Scale". Double click on the script to open the scripting
window and you will see the default script.

Luckily we dont have to change the events inside the script it's self,
we can modify this script to suit our needs as is, since our new script
will contain both the state_entry and touch_start events.

For this example we will use the. llSetScale(<0, 0, 0>); , function to
change the size of the prim when someone touches it.

We are going to delete both functions inside the new script, not the event blocks
just the functions within the event blocks.

We will now insert the llSetScale(<5.0,5.0,1.0>); function into the touch_start
event of our script and click on the save button at the bottom left hand corner
of the script window.

default
{
state_entry()
{
}

touch_start(integer total_number)
{
llSetScale(<5.0, 5.0, 1.0>);
}
}

The llSetScale() Function accepts a Float "Vector" which has the following format "<0,0,0>" .
Where the vector in this case represents the <x, y, z> size of the object we are changing the scale of.

By clicking on the prim, it now changes the size of the prim "Programmatically" or, via scripted function.

But, we might want to shrink the prim back down after a certain amount of time so, we will add
more "Functionality" to our script.

default
{
state_entry()
{
}

touch_start(integer total_number)
{
llSetScale(<5.0, 5.0, 1.0>);
llSleep(5.0); <<<<---Added sleep function which makes the script pause for 5 seconds.
llSetScale(<0.5, 0.5, 0.5>); <<<<---Added new setscale function to shrink the prim back down after 5 sec.

}
}

Lets add even MORE functionality to our growing script!

In the state_entry event, which fires as soon as the script starts we will
change the color of the prim by using the llSetColor(<0,0,0>); color function.

default
{
state_entry()
{
llSetColor(<0,0,1>, ALL_SIDES); <<<<--- Where the color float vector represents <Red, Green, Blue> shades.
} <<<<--- and the integer or constant ALL_SIDES means change the color on all faces.
<<<<--- Or by replacing the Constant ALL_SIDES with a specific side number.
touch_start(integer total_number)
{
llSetScale(<5.0, 5.0, 1.0>);
llSleep(5.0); <<<<---Added sleep function which makes the script pause for 5 seconds.
llSetScale(<0.5, 0.5, 0.5>); <<<<---Added new setscale function to shrink the prim back down after 5 sec.

}
}

Lets add even more playful functionality to this script!

default
{
state_entry()
{
llSetColor(<0,0,1>, ALL_SIDES);
}

touch_start(integer total_number)
{
llSetScale(<5.0, 5.0, 1.0>);
llSetColor(<0,1,0>, ALL_SIDES); <<<<--- This will change the color of the prim to all Green when first touched.
llSleep(5.0);
llSetScale(<0.5, 0.5, 0.5>);
llSetColor(<1,0,0>, ALL_SIDES); <<<<--- After 5 seconds the prim will change to Red on all sides.

}
}

Let add a texture application function after an additional 5 seconds has passed below the last functions
in the touch_start event block. We are going to use the "llSetTexture( string texture, integer face );" function.

To acquire the UUID of any object or texture in your inventory simply right click on the object and select the
"Copy Asset UUID" option, this will copy the UUID of the object into your clipboard memory and can then
be pasted into your script, notecard etc...

default
{
state_entry()
{
llSetColor(<0,0,1>, ALL_SIDES);
}

touch_start(integer total_number)
{
llSetScale(<5.0, 5.0, 1.0>);
llSetColor(<0,1,0>, ALL_SIDES);
llSleep(5.0);
llSetScale(<0.5, 0.5, 0.5>);
llSetColor(<1,0,0>, ALL_SIDES);
llSleep(5.0); <<<<--- Added another sleep call function.

llSetColor(<1,1,1>, ALL_SIDES); <<<<--- Change the color of the prim back to white before new texture.

???--- Added this new function which will paste the new texture on all sides of the prim.
llSetTexture("016f11b3-da03-be29-41fc-6f12f217d51e", ALL_SIDES);
}
}

Notice that in the settexture function I have pasted the UUID of the texture itself into the function
by placing it in quotes since the function is expecting a "String". If I tried to just put the UUID there
without quotes the script would throw an error.

Anything placed between quotes in a script is treated and recognized as a "String" by the server
when it executes your script. So if a function calls for a specific type of data in it's description be
sure to feed it the proper variables or the script will fail to operate.

There are literally hundreds of functions you can use to interact with the world around us.
Some are very complex in how they work, others are simple and easy to use.

Lets GET some information from our environment, we have been telling an object WHAT to do, now
lets get some information FROM the object we are working with!

default
{
state_entry()
{
llSetColor(<0,0,1>, ALL_SIDES);
}

touch_start(integer total_number)
{
llSetScale(<5.0, 5.0, 1.0>);
llSetColor(<0,1,0>, ALL_SIDES);
llSleep(5.0);
llSetScale(<0.5, 0.5, 0.5>);
llSetColor(<1,0,0>, ALL_SIDES);
llSleep(5.0);
llSetColor(<1,1,1>, ALL_SIDES);
llSetTexture("016f11b3-da03-be29-41fc-6f12f217d51e", ALL_SIDES);

llSleep(5.0); <<<<--- Added yet another sleep pause.

????---Added this function to grab the UUID code of the texture on face 0 of the prim.
string texture = llGetTexture(0); <<<<---Stored the UUID of the texture INTO a new "String" variable I created.

????--- Now I will chat out the UUID code of the texture on face 0 using the chat function!
llSay(0, "The UUID of the texture on face 0 is: " + texture);
}
}

Lets add a more personal touch to our script by grabbing the users name after they
touch the prim and chatting it back out to them with a custom message using the;
llDetectedKey( integer number );
llKey2Name( key id );

key userid; <<<<??--- We start by declaring two global variables userid and usersname
string usersname;

default
{
state_entry()
{
llSetColor(<0,0,1>, ALL_SIDES);
}

touch_start(integer total_number)
{
????--- We store the users key into the userid key variable.
userid = llDetectedKey(0);

????--- We store the users Name into the usersname string variable using their key.
usersname = llKey2Name(userid);

????--- We insert a new chat function with our message and the new string.
llSay(0, "Thank you for clicking on me: " + usersname);

llSetScale(<5.0, 5.0, 1.0>);
llSetColor(<0,1,0>, ALL_SIDES);
llSleep(5.0);
llSetScale(<0.5, 0.5, 0.5>);
llSetColor(<1,0,0>, ALL_SIDES);
llSleep(5.0);
llSetColor(<1,1,1>, ALL_SIDES);
llSetTexture("016f11b3-da03-be29-41fc-6f12f217d51e", ALL_SIDES);
llSleep(5.0);
string texture = llGetTexture(0);
llSay(0, "The UUID of the texture on face 0 is: " + texture);
}
}

*********SCRIPT ERRORS***********

There is nothing more rewarding than finishing a script and seeing the:
Compile successful!
Save complete.
Message after finishing your script and saving it with the "Save" button.

BUT, things do go wrong, and when they do...

Let's deliberately cause an error and see what happens!

key userid;
string usersname;
default
{
state_entry()
{
llSetColor(<0,0,1>, ALL_SIDES);
}

touch_start(integer total_number)
{
userid = llDetectedKey(0);
usersname = llKey2Name(userid);
llSay(0, "Thank you for clicking on me: " + usersname);
llSetScale(<5.0, 5.0, 1.0>);
llSetColor(<0,1,0>, ALL_SIDES);
llSleep(5.0);
llSetScale(<0.5, 0.5, 0.5>);
llSetColor(<1,0,0>, ALL_SIDES);
llSleep(5.0);
llSetColor(<1,1,1>, ALL_SIDES);
llSetTexture("016f11b3-da03-be29-41fc-6f12f217d51e", ALL_SIDES);
llSleep(5.0);
string texture = llGetTexture(0);
llSay(0, "The UUID of the texture on face 0 is: " + texture) <<<<--- Deliberately causing an Error!
<<<<--- By Omitting the ; from the end of the line.
}
}

The server will return the following error information:
"(25, 4) : ERROR Syntax error"

Which means that something has gone wrong on, or before, line 17, at position 4 in our script.
Notice the column of line numbers along the left hand side of the script, those are very useful
for remembering where things are when your making changes, correcting errors and working
with long scripts with a lot of functionality.

Feel free to deliberately cause errors in the script to see what the server tells you about the error
you have caused.

Errors can become fairly tricky to catch when you are dealing with many variables and
functions. Luckily the script we are working with right now is not too complicated, but scripts
do get complicated.

The key to "Debugging" a script is understanding what the functions do and how they interact
with other functions and variables in the script. Studying a script to see how it works is a very
common activity used by many scripters to overcome, adapt and innovate new ideas.

When a script throws an error in World you will see a little white error icon appear above the
scripted object, you will also see a little error icon appear above your viewer in the information
bar at the top. If you click on the little white error icon in the information bar at the top of you viewer
the "Debug" window will open up showing you more information about the error which you can
use to track down and correct the error with.
These users thanked the author Krull Kitty for the post (total 4):
Ada RadiusFrank SquirrelHerderAlexina ProctorMichael Timeless
User avatar
Krull Kitty
Posts: 100
Joined: Thu Aug 06, 2020 1:25 pm
Has thanked: 39 times
Been thanked: 81 times

Re: Krull Kitty's Scripting Course

Post by Krull Kitty »

###### PART 3 ######

In our first two classes we learned many important concepts and
rules for scripting in this virtual environment.

********Dialog Drop Down Menu********

Today let's look at a very helpful script which combines some simple
functions to create a drop down menu which can control many things.

In fact a drop down menu is one of the most requested things
a scripter gets requests for.

Let's look at a bare bones drop down menu script;

integer channel = 505050; <<<--- We setup a channel variable at the top of our script.
default
{
state_entry()
{
llListen(channel,"", "",""); <<<---We then initiate a "Listener".
}
touch_start(integer count) <<<--- If someone touches causing a touch event do the following.
{
?????---Send a drop down menu to the user with the following information.
llDialog(llDetectedKey(0), "Base Menu Infrastructure .\n\n Please Modify Script as needed.", ["1", "2", "3", "4"], channel);
}
????---This is the actual event that listens for the data from the drop down menu.
listen(integer chan, string name, key id, string mes)
{
????--- THis is where the script listens for specific commands from the menu.
if (mes == "1")
{
llSay(0, mes);
}
????---If the string called (mes) equals the value ("2") then do something!
if (mes == "2")
{
????--- Very simply in this case, the script chats out the value of the strings contents.
llSay(0, mes);
}
if (mes == "3")
{
llSay(0, mes);
}
if (mes == "4")
{
llSay(0, mes);
}
???--- If the string called (mes) contains no logical value then do nothing.
else
{
//Null Foo
}
}
}

The beauty of using drop down menues is that you can use them as a framework for
just about anything! They offer a simple and elegant solution for your scripts if your
scripts offer multiple options.

Let's break down the llDialog function into it's component parts;

????--- This is the complete function line which generates the drop down menu.
llDialog(llDetectedKey(0), "Base Menu Infrastructure .\n\n Please Modify Script as needed.", ["1", "2", "3", "4"], channel);

llDialog ? this is the function itself.

(llDetectedKey(0), ? This instructs the function to send the menu to the first AV that clicks the object.

Note: That llDetectedKey() is a function itself. It is possible to embed functions as arguments
within other functions and use the values they represent within other functions.

????--- The next part is simply text between quotes. This message appears in the top area of your menu.
"Base Menu Infrastructure .\n\n Please Modify Script as needed.",
????--- If your message requires more than 8 lines, a vertical scroll bar will appear in the dialog.
The message text can be formatted somewhat using "\n" (for newline) and "\t" (for tab).
You can not change the font face, size or weight.

["1", "2", "3", "4"], ? This section of the code is what the menu displays as actual buttons on the menu.
The text you see within the quotes is what shows as options on the menu.

For example, if we wanted to be a little more exact, we could use words as options instead of the
numbers I have used above;

["Option 1", "Option 2", "Option 3", "Option 4", "Option 5", "Option 6", "Option 7", "Option 8"] Etc...
????--- The quoted text above would then appear on individual buttons on the menu itself.

A menu can support 12 buttons (Per Page), which means a menu can have an almost infinite
number of choices. The order in which the buttons are displayed on a menu are as follows:

9 - 10 - 11
6 - 7 - 8
3 - 4 - 5
0 - 1 - 2

This means that in our original line; ["1", "2", "3", "4"], Our buttons would appear as follows:

¦¦¦4¦¦¦
¦¦¦1¦¦¦ ¦¦¦2¦¦¦ ¦¦¦3¦¦¦

There is no way to change the actual size of the dialog, nor change its color.

The average number of characters that can be displayed on a dialog line is about 35 characters
per line in ASCII characters. It depends upon the width of the characters.

The number of characters that can be displayed on a button depends upon the width of the characters.

If the distance between the root prim of the listening object and the dialog generating prim is greater
than 20 meters when a button is pressed, the response will not be heard.

If the button definitions are empty, the menu will default to a simple ["OK"].
If a button is named "Ignore", it will behave like the small "Ignore" button on the menu
(i.e. pressing it will *not* get "Ignore" sent to the menu channel). If you need an "Ignore" button on your
menu and wish to have its name sent back to the script when you press it, then use spaces in the button
name (e.g. " Ignore ").

An error will be shouted on DEBUG_CHANNEL, if there are more than 12 buttons.

More detailed information about Dialog menues can be found on the scripting portal page at:
http://wiki.secondlife.com/wiki/Lldialog

A step by step guide to Dialog menues is available as well at:
http://wiki.secondlife.com/wiki/Dialog_Menus

********Common & Often Used Functions********

When looking through scripts you will often find many of the functions in the list
below.

Let's have a closer look and discuss the functions in this list:

Functions
• llListen
• llTextBox
• llRegionSay
• llWhisper – Sends chat limited to 10 meters
• llSay – Sends chat limited to 20 meters
• llShout – Sends chat limited to 100 meters
• llInstantMessage – Sends chat to the specified user
• llOwnerSay – Sends chat to the owner only
• llGetPos
• llCollision
• llGetRot
• llGetScale
• llSetPos
• llSetScale
• llResetScript
• llRezAtRoot
• llRezObject
• llSensor
• llGetOwner
• llKey2Name
• llDetectedKey
• llSetTexture
• llSetColor
• llDetectedGroup
• llDie
• llListen
• llSetTimerEvent
• llSetTextureAnim
• llGetInventoryNumber
• llGetInventoryName
• llGetInventoryKey
• llPreloadSound
• llPlaySound
• llTargetOmega
• llSetRot
• llGetObjectName
• llGetObjectDesc
• llSleep
• llSetParcelMusicURL
• llSetAlpha
• llStartAnimation
• llStopAnimation
• llSetObjectDesc
• llSetObjectName
• llSetSitText
• llLoopSound
• llSensorRepeat
• llGetCreator
• llFrand

These are some of the more common functions found in many scripts
through out the virtual environment.

For a complete listing of all available functions to date please visit:
http://wiki.secondlife.com/wiki/Category:LSL_Functions

Always remember that the LSL scripting portal will not only be your guide,
but will also be your friend and companion throughout your scripting
endeavors.
http://wiki.secondlife.com/wiki/LSL_Portal

Functions change, some are added, some are removed. Sometimes
they begin to work differently because the server has been modified.
These users thanked the author Krull Kitty for the post (total 4):
Ada RadiusFrank SquirrelHerderAlexina ProctorMichael Timeless
User avatar
Krull Kitty
Posts: 100
Joined: Thu Aug 06, 2020 1:25 pm
Has thanked: 39 times
Been thanked: 81 times

Re: Krull Kitty's Scripting Course

Post by Krull Kitty »

###### Part 4 ######

In our last class we looked at Dialog Menus and how they work.
In this class we will look at (Subroutines), what Subroutines are
and how useful they are in scripting.

********Sub Routines********

A (Subroutine) is a block of code created to produce a reuseable
set of instructions. So instead of retyping, or copying, a function
over and over again inside your script you can create the instructions
once and call them over and over again from within your script
anytime you need them.

A subroutine looks like an event block with the exception that it
must be placed Above the main default{} code area.

A subroutine can be named pretty much whatever you want it to
be, for example;

myfunction()
{

}

Is the general format of a subroutine, whatever code appears
between the curly braces {} will be carried out by the script when
you call the subroutine in the script;

myfunction();

Lets look at how we can use a subroutine in an actual script;

We begin with the standard code block.

default
{
state_entry()
{

}

touch_start(integer total_number)
{

}
}

Then we add our subroutine above the main code block in the same area
where we would declare our global variables.

say-it() <<<<----This is the name of the new subroutine.
{
llSay(0," I said something !!"); <<<<----This is a function within the subroutine.
}

default
{
state_entry()
{

}

touch_start(integer total_number)
{
say-it(); <<<<---- This is where I call the subroutine.
}
}

A script can have many many subroutines designed to process many forms
of text and data, including performing repetitive mathematical functions.

A subroutine can also accept data in the form of variables for processing.
Lets now look at how we can pass data to and from subroutines in our script.

integer num; <<<<----I have added a new global variable declaration.

say-it(integer x) <<<<----Let our subroutine know that we are expecting
{ an integer value and assign it to the subroutine variable (x).
llSay(0,"The next number is:" + (string)x); <<<<----Chat out the number but convert it to a string with the
} (string) cast option which turns an integer into a string for the llSay function.

default
{
state_entry()
{

}

touch_start(integer total_number)
{
num++; <<<<----Increment our integer by one or (+ 1).
say-it(num); <<<<----Send the integer value by placing the name of the variable
inside the subroutine call brackets.
}
}

The entire script looks like this:

integer num;

say-it(integer x)
{
llSay(0,"The next number is:" + (string)x);
}

default
{
state_entry()
{

}

touch_start(integer total_number)
{
num++;
say-it(num);
}
}

Now, lets say your subroutine, or (Function), performs a math function and does
something with numbers and needs to return a value to the main script, the best
way to do this, in my opinion, is have the subroutine assign the calculated result
to a pre defined global variable. Then you can access the value in that variable
from anywhere in the script.

integer num;
integer newnum; <<<<----Newly delcared global variable.

say-it(integer x)
{
newnum = x + 5; <<<<---- We are now assigning whatever (x) is + 5 to the variable newnum.
}

default
{
state_entry()
{

}

touch_start(integer total_number)
{
num++;
say-it(num); <<<<----Notice that the function occurs Before the chat statement below and the newnum variable will have a new value.
llSay(0, (string)newnum); <<<<----Here we grab the value in newnum and chat it out as a string.
}
}

(Subroutines) are also known as (Functions) in LSL scripting. They are one and the same
for all intents.

Lets practice now by creating a script with a subroutine that does whatever you
want it to do and call that subroutine from the touch_start event in your script.

You can use the basic script framework above or the one below to create your
own subroutine based script.

default
{
state_entry()
{

}

touch_start(integer total_number)
{

}
}
These users thanked the author Krull Kitty for the post (total 3):
Ada RadiusAlexina ProctorMichael Timeless
User avatar
Krull Kitty
Posts: 100
Joined: Thu Aug 06, 2020 1:25 pm
Has thanked: 39 times
Been thanked: 81 times

Re: Krull Kitty's Scripting Course

Post by Krull Kitty »

###### PART 5 ######
In our last class we looked at Subroutines and how they work.
In this class we will look at (States), what States are
and how useful they are to scripters.

********States********

The main state is the default state. When a script is compiled, reset or loaded,
this is the state it enters by default. After the default state definition can follow
additional state definitions which the script may use to change how and which
events are handled.

The default state must be defined before all others.

User-defined (global) functions cannot change a script's state.

If a new state has a timer event, and the previous state has a timer set, the timer
event in the new state will be triggered on the interval set in the previous state.

If target state is the same as the current state, no state change occurs nor do
any of the side effects.

A basic example of how state changes work are shown in the simple script below:

default
{
touch_end(integer a)
{
state hello;
}
}

state hello
{
state_entry()
{
llOwnerSay("Hello");
state default;
}
state_exit()
{
llOwnerSay("Goodbye");
}
}

A new State is almost like a whole new script with the exception of the State rules
listed at the start of this notecard.

A new state can still make use of global variables and subroutines, in fact, all States
have access to globals.

This makes it easier to manage different sets of rules and systems within a given
script.

To enter into a new State from within a script you simply call the State by name
from the State you are starting in, ie:

state default;

This statement would send the script back to the original (Default) state.

States can be named however you like, a state is a main block of code that acts
much like the default state, you can also call it like a subroutine and jump back
and forth from state to state easily.

Multiple states can be used to change the way a script handles different events
or to simply change the events that the script reacts to.

We are going to create 3 states in todays class:

default
{
touch_end(integer a)
{
state hello;
}
}

state hello
{
state_entry()
{
llSay(0, "");
state default;
}
state_exit()
{
llOwnerSay("Goodbye");
}
}
These users thanked the author Krull Kitty for the post (total 3):
Ada RadiusAlexina ProctorMichael Timeless
User avatar
Krull Kitty
Posts: 100
Joined: Thu Aug 06, 2020 1:25 pm
Has thanked: 39 times
Been thanked: 81 times

Re: Krull Kitty's Scripting Course

Post by Krull Kitty »

###### FUNCTION LIST ######

llSin(float theta);
llCos(float theta);
llTan(float theta);
llAtan2(float y, float x);
llSqrt(float val);
llPow(float decbase, float exponent);
llAbs(int val);
llFabs(float val);
llFrand(float mag);
llFloor(float val);
llCeil(float val);
llRound(float val);
llVecMag(Vector3 v);
llVecNorm(Vector3 v);
llVecDist(Vector3 v1, Vector3 v2);
llRot2Euler(Quaternion q);
llEuler2Rot(Vector3 v);
llAxes2Rot(Vector3 fwd, Vector3 left, Vector3 up);
llRot2Fwd(Quaternion q);
llRot2Left(Quaternion q);
llRot2Up(Quaternion q);
llRotBetween(Vector3 v1, Vector3 v2);
llWhisper(int channel, string msg);
llSay(int channel, string msg);
llShout(int channel, string msg);
llListen(int channel, string name, string id, string msg);
llListenControl(int number, int active);
llListenRemove(int number);
llSensor(string name, string id, int type, float range, float arc);
llSensorRepeat(string name, string id, int type, float range, float arc, float rate);
llSensorRemove();
llDetectedName(int number);
llDetectedKey(int number);
llDetectedOwner(int number);
llDetectedType(int number);
llDetectedPos(int number);
llDetectedVel(int number);
llDetectedGrab(int number);
llDetectedRot(int number);
llDetectedGroup(int number);
llDetectedLinkNumber(int number);
llDie();
llGround(Vector3 offset);
llCloud(Vector3 offset);
llWind(Vector3 offset);
llSetStatus(int status, int value);
llGetStatus(int status);
llSetScale(Vector3 scale);
llGetScale();
llSetColor(Vector3 color, int face);
llGetAlpha(int face);
llSetAlpha(float alpha, int face);
llGetColor(int face);
llSetTexture(string texture, int face);
llScaleTexture(float u, float v, int face);
llOffsetTexture(float u, float v, int face);
llRotateTexture(float rot, int face);
llGetTexture(int face);
llSetPos(Vector3 pos);
llGetPos();
llGetLocalPos();
llSetRot(Quaternion rot);
llGetRot();
llGetLocalRot();
llSetForce(Vector3 force, int local);
llGetForce();
llTarget(Vector3 position, float range);
llTargetRemove(int number);
llRotTarget(Quaternion rot, float error);
llRotTargetRemove(int number);
llMoveToTarget(Vector3 target, float tau);
llStopMoveToTarget();
llApplyImpulse(Vector3 force, int local);
llApplyRotationalImpulse(Vector3 force, int local);
llSetTorque(Vector3 torque, int local);
llGetTorque();
llSetForceAndTorque(Vector3 force, Vector3 torque, int local);
llGetVel();
llGetAccel();
llGetOmega();
llGetTimeOfDay();
llGetWallclock();
llGetTime();
llResetTime();
llGetAndResetTime();
llSound(string sound, float volume, int queue, int loop);
llPlaySound(string sound, float volume);
llLoopSound(string sound, float volume);
llLoopSoundMaster(string sound, float volume);
llLoopSoundSlave(string sound, float volume);
llPlaySoundSlave(string sound, float volume);
llTriggerSound(string sound, float volume);
llStopSound();
llPreloadSound(string sound);
llGetSubString(string src, int start, int end);
llDeleteSubString(string src, int start, int end);
llInsertString(string dst, int position, string src);
llToUpper(string src);
llToLower(string src);
llGiveMoney(string destination, int amount);
llMakeExplosion(int particles, float scale, float vel, float lifetime, float arc, string texture, Vector3 offset);
llMakeFountain(int particles, float scale, float vel, float lifetime, float arc, int bounce, string texture, Vector3 offset, float bounce_offset);
llMakeSmoke(int particles, float scale, float vel, float lifetime, float arc, string texture, Vector3 offset);
llMakeFire(int particles, float scale, float vel, float lifetime, float arc, string texture, Vector3 offset);
llRezObject(string inventory, Vector3 pos, Vector3 vel, Quaternion rot, int param);
llLookAt(Vector3 target, float strength, float damping);
llStopLookAt();
llSetTimerEvent(float sec);
llSleep(float sec);
llGetMass();
llCollisionFilter(string name, string id, int accept);
llTakeControls(int controls, int accept, int pass_on);
llReleaseControls();
llAttachToAvatar(int attach_point);
llDetachFromAvatar();
llTakeCamera(string avatar);
llReleaseCamera(string avatar);
llGetOwner();
llInstantMessage(string user, string message);
llEmail(string address, string subject, string message);
llGetNextEmail(string address, string subject);
llGetKey();
llSetBuoyancy(float buoyancy);
llSetHoverHeight(float height, int water, float tau);
llStopHover();
llMinEventDelay(float delay);
llSoundPreload(string sound);
llRotLookAt(Quaternion target, float strength, float damping);
llStringLength(string str);
llStartAnimation(string anim);
llStopAnimation(string anim);
llPointAt(Vector3 pos);
llStopPointAt();
llTargetOmega(Vector3 axis, float spinrate, float gain);
llGetStartParameter();
llGodLikeRezObject(string inventory, Vector3 pos);
llRequestPermissions(string agent, int perm);
llGetPermissionsKey();
llGetPermissions();
llGetLinkNumber();
llSetLinkColor(int linknumber, Vector3 color, int face);
llCreateLink(string target, int parent);
llBreakLink(int linknum);
llBreakAllLinks();
llGetLinkKey(int linknumber);
llGetLinkName(int linknumber);
llGetInventoryNumber(int type);
llGetInventoryName(int type, int number);
llSetScriptState(string name, int run);
llGetEnergy();
llGiveInventory(string destination, string inventory);
llRemoveInventory(string item);
llSetText(string text, Vector3 color, float alpha);
llWater(Vector3 offset);
llPassTouches(int pass);
llRequestAgentData(string id, int data);
llRequestInventoryData(string name);
llSetDamage(float damage);
llTeleportAgentHome(string id);
llModifyLand(int action, int brush);
llCollisionSound(string impact_sound, float impact_volume);
llCollisionSprite(string impact_sprite);
llGetAnimation(string id);
llResetScript();
llMessageLinked(int linknum, int num, string str, string id);
llPushObject(string id, Vector3 impulse, Vector3 ang_impulse, int local);
llPassCollisions(int pass);
llGetScriptName();
llGetNumberOfSides();
llAxisAngle2Rot(Vector3 axis, float angle);
llRot2Axis(Quaternion rot);
llRot2Angle(Quaternion rot);
llAcos(float val);
llAsin(float val);
llAngleBetween(Quaternion a, Quaternion b);
llGetInventoryKey(string name);
llAllowInventoryDrop(int add);
llGetSunDirection();
llGetTextureOffset(int face);
llGetTextureScale(int side);
llGetTextureRot(int side);
llSubStringIndex(string source, string pattern);
llGetOwnerKey(string id);
llGetCenterOfMass();
llListSort(LSLList src, int stride, int ascending);
llGetListLength(LSLList src);
llList2Integer(LSLList src, int index);
llList2Float(LSLList src, int index);
llList2String(LSLList src, int index);
llList2Key(LSLList src, int index);
llList2Vector(LSLList src, int index);
llList2Rot(LSLList src, int index);
llList2List(LSLList src, int start, int end);
llDeleteSubList(LSLList src, int start, int end);
llGetListEntryType(LSLList src, int index);
llList2CSV(LSLList src);
llCSV2List(string src);
llListRandomize(LSLList src, int stride);
llList2ListStrided(LSLList src, int start, int end, int stride);
llGetRegionCorner();
llListInsertList(LSLList dest, LSLList src, int start);
llListFindList(LSLList src, LSLList test);
llGetObjectName();
llSetObjectName(string name);
llGetDate();
llEdgeOfWorld(Vector3 pos, Vector3 dir);
llGetAgentInfo(string id);
llAdjustSoundVolume(float volume);
llSetSoundQueueing(int queue);
llSetSoundRadius(float radius);
llKey2Name(string id);
llSetTextureAnim(int mode, int face, int sizex, int sizey, float start, float length, float rate);
llTriggerSoundLimited(string sound, float volume, Vector3 top_north_east, Vector3 bottom_south_west);
llEjectFromLand(string avatar);
llParseString2List(string src, LSLList separators, LSLList spacers);
llOverMyLand(string id);
llGetLandOwnerAt(Vector3 pos);
llGetNotecardLine(string name, int line);
llGetAgentSize(string id);
llSameGroup(string id);
llUnSit(string id);
llGroundSlope(Vector3 offset);
llGroundNormal(Vector3 offset);
llGroundCountour(Vector3 offset);
llGetAttached();
llGetFreeMemory();
llGetRegionName();
llGetRegionTimeDilation();
llGetRegionFPS();
llParticleSystem(LSLList rules);
llGroundRepel(float height, int water, float tau);
llGiveInventoryList(string target, string folder, LSLList inventory);
llSetVehicleType(int type);
llSetVehicleFloatParam(int param, float value);
llSetVehicleVectorParam(int param, Vector3 vec);
llSetVehicleRotationParam(int param, Quaternion rot);
llSetVehicleFlags(int flags);
llRemoveVehicleFlags(int flags);
llSitTarget(Vector3 offset, Quaternion rot);
llAvatarOnSitTarget();
llAddToLandPassList(string avatar, float hours);
llSetTouchText(string text);
llSetSitText(string text);
llSetCameraEyeOffset(Vector3 offset);
llSetCameraAtOffset(Vector3 offset);
llDumpList2String(LSLList src, string separator);
llScriptDanger(Vector3 pos);
llDialog(string avatar, string message, LSLList buttons, int chat_channel);
llVolumeDetect(int detect);
llResetOtherScript(string name);
llGetScriptState(string name);
llSetRemoteScriptAccessPin(int pin);
llRemoteLoadScriptPin(string target, string name, int pin, int running, int start_param);
llOpenRemoteDataChannel();
llSendRemoteData(string channel, string dest, int idata, string sdata);
llRemoteDataReply(string channel, string message_id, string sdata, int idata);
llCloseRemoteDataChannel(string channel);
llMD5String(string src, int nonce);
llSetPrimitiveParams(LSLList rules);
llStringToBase64(string str);
llBase64ToString(string str);
llXorBase64Strings(string s1, string s2);
llLog10(float val);
llLog(float val);
llGetAnimationList(string id);
llSetParcelMusicURL(string url);
llGetRootPosition();
llGetRootRotation();
llGetObjectDesc();
llSetObjectDesc(string name);
llGetCreator();
llGetTimestamp();
llSetLinkAlpha(int linknumber, float alpha, int face);
llGetNumberOfPrims();
llGetNumberOfNotecardLines(string name);
llGetBoundingBox(string obj);
llGetGeometricCenter();
llGetPrimitiveParams(LSLList parms);
llIntegerToBase64(int number);
llBase64ToInteger(string str);
llGetGMTclock();
llGetSimulatorHostname();
llSetLocalRot(Quaternion rot);
llParseStringKeepNulls(string src, LSLList separators, LSLList spacers);
llRezAtRoot(string inventory, Vector3 pos, Vector3 vel, Quaternion rot, int param);
llGetObjectPermMask(int mask);
llSetObjectPermMask(int mask, int value);
llGetInventoryPermMask(string item, int mask);
llSetInventoryPermMask(string item, int mask, int value);
llGetInventoryCreator(string item);
llOwnerSay(string msg);
llRequestSimulatorData(string simulator, int data);
llForceMouselook(int mouselook);
llGetObjectMass(string id);
llListReplaceList(LSLList dest, LSLList src, int start, int end);
llLoadURL(string avatar, string message, string url);
llParcelMediaCommandList(LSLList command);
llParcelMediaQuery(LSLList query);
llModPow(int a, int b, int c);
llGetInventoryType(string name);
llSetPayPrice(int price, LSLList quick_pay_buttons);
llGetCameraPos();
llGetCameraRot();
llSetPrimURL(string url);
llRefreshPrimURL();
llEscapeURL(string url);
llUnescapeURL(string url);
llMapDestination(string simname, Vector3 pos, Vector3 look_at);
llAddToLandBanList(string avatar, float hours);
llRemoveFromLandPassList(string avatar);
llRemoveFromLandBanList(string avatar);
llSetCameraParams(LSLList rules);
llClearCameraParams();
llListStatistics(int operation, LSLList src);
llGetUnixTime();
llGetParcelFlags(Vector3 pos);
llGetRegionFlags();
llXorBase64StringsCorrect(string s1, string s2);
llHTTPRequest(string url, LSLList parameters, string body);
llResetLandBanList();
llResetLandPassList();
llGetObjectPrimCount(string object_id);
llGetParcelPrimOwners(Vector3 pos);
llGetParcelPrimCount(Vector3 pos, int category, int sim_wide);
llGetParcelMaxPrims(Vector3 pos, int sim_wide);
llGetParcelDetails(Vector3 pos, LSLList parms);
llSetLinkPrimitiveParams(int linknumber, LSLList rules);
llSetLinkTexture(int linknumber, string texture, int face);
llStringTrim(string src, int trim_type);
llRegionSay(int channel, string msg);
llGetObjectDetails(string id, LSLList parms);
llSetClickAction(int action);
llGetRegionAgentCount();
llTextBox(string avatar, string message, int chat_channel);
llGetAgentLanguage(string avatar);
llDetectedTouchUV(int index);
llDetectedTouchFace(int index);
llDetectedTouchPos(int index);
llDetectedTouchNormal(int index);
llDetectedTouchBinormal(int index);
llDetectedTouchST(int index);
llSHA1String(string src);
llGetFreeURLs();
llRequestURL();
llRequestSecureURL();
llReleaseURL(string url);
llHTTPResponse(string request_id, int status, string body);
llGetHTTPHeader(string request_id, string header);
llSetPrimMediaParams(int face, LSLList parms);
llGetPrimMediaParams(int face, LSLList parms);
llClearPrimMedia(int face);
llSetLinkPrimitiveParamsFast(int linknumber, LSLList rules);
llGetLinkPrimitiveParams(int linknumber, LSLList rules);
llLinkParticleSystem(int linknumber, LSLList rules);
llSetLinkTextureAnim(int link, int mode, int face, int sizex, int sizey, float start, float length, float rate);
llGetLinkNumberOfSides(int link);
llGetUsername(string id);
llRequestUsername(string id);
llGetDisplayName(string id);
llRequestDisplayName(string id);
iwMakeNotecard(string name, LSLList data);
iwAvatarName2Key(string firstName, string lastName);
iwLinkTargetOmega(int linknumber, Vector3 axis, float spinrate, float gain);
These users thanked the author Krull Kitty for the post (total 2):
Ada RadiusMichael Timeless
User avatar
Ada Radius
Posts: 435
Joined: Sun Dec 23, 2012 6:20 pm
Has thanked: 659 times
Been thanked: 545 times

Re: Krull Kitty's Scripting Course

Post by Ada Radius »

Fabulous, thank you!
These users thanked the author Ada Radius for the post:
Krull Kitty
User avatar
John Mela
Posts: 91
Joined: Tue Feb 04, 2014 9:50 pm
Has thanked: 139 times
Been thanked: 127 times
Contact:

Re: Krull Kitty's Scripting Course

Post by John Mela »

Hi Krull. Can I suggest you enclose your code samples in "code" blocks to preserve formatting? It's the button labelled "</>" in the toolbar above the message editing box. Or you can do it manually by putting the code between [code] and [/code] tags.

This is how indented code appears with those tags in place:

Code: Select all

default
{
    state_entry()
    {
        llSay(0, "Hello, Avatar!");
    }
}
These users thanked the author John Mela for the post (total 3):
Ilan TochnerFrank SquirrelHerderMichael Timeless
User avatar
Krull Kitty
Posts: 100
Joined: Thu Aug 06, 2020 1:25 pm
Has thanked: 39 times
Been thanked: 81 times

Re: Krull Kitty's Scripting Course

Post by Krull Kitty »

Hello John,

I posted this quickly from the same series of notecards I made for the course.
Directly from notecards to forum.

Some script examples are not fully functional so Im not sure if that would work out
or confuse someone into thinking that perhaps the encapsulated code is workable.

Such is the nature of code training.

Cheers.
User avatar
Krull Kitty
Posts: 100
Joined: Thu Aug 06, 2020 1:25 pm
Has thanked: 39 times
Been thanked: 81 times

Re: Krull Kitty's Scripting Course

Post by Krull Kitty »

###### EVENT CODE BLOCKS ######

Code: Select all

integer channel = 123456;

default
{
    on_rez(integer a) //On Rez is a control block that describes an event when the object is first rezzed.
    {
        llResetScript();
    }

    state_entry() //State Entry is a control block that describes when the script starts.
    {
     llSensor("", NULL_KEY, AGENT_BY_LEGACY_NAME, 10.0, PI); //Defines the sensor control block below
     llListen(channel, "", NULL_KEY, "" ); //Defines the listen control block below.
    }

    collision_start(integer num) //This event control block detects a collision and excutes the code within.
    {
        llSay(0,"No pushing.");
    }

    sensor (integer num_detected)
    {
        //This event control block creates a sensor event within a given range.
        //The sensors range and other attributes are defined within llSensor() call in the state_entry block.
        //The llSensor() call is required for the sensor block to work.
    }

    touch_start(integer num_detected)
    {
       //This event control block executes code when an AV touches the object.
    }

    listen(integer channel, string name, key id, string message)
    {
        //This event control block listens for string messages on a predefined channel.
        //This control block then grabs the string and inserts it into the varibale "message".
        //The String variable can then be manipulated, equated or used in any manner within
        //this block. The llListen() call in the state_entry block is required for the
        //listen() control block to work.
    }

    link_message(integer source, integer num, string str, key id)
    {
        //This event block listens for messages from other scripts within a set
        //of linked prims.
        //llMessageLinked(LINK_SET, 0, anyStringvariable, ""); //For sending messages to other
        //scripts in a linkset.
    }

    //Most "EVENT CONTROL BLOCKS" are separate entities within the scripts global scope inside
    //the default{}, or main block, if you program in C++

    //Define your globals outside of the default{} block. Any variables created within
    //an event block, loop or timer event will only be accessible within that scope.
}
Post Reply