Pages

Saturday, November 27, 2010

Detecting A Name

Just had a quick question about detecting a name with a script. It's super easy to do, you only need one line:

touch_start(integer total_number)
    {
        llOwnerSay(llDetectedName(0));
    }

In this example I put it in a touch event, but it could also go in a collision event. You can also set things to be run by the owner of the object only by using the following snippet. Anything between the brackets will be owner only:

if(llDetectedKey(0) == llGetOwner()){

}

Sunday, September 19, 2010

The Sigil Stone


I have been asked a few times about how this is done so I thought I'd do a blog post (I need more stuff to blog about anyway, merp). I'm sure you've probably seen this kind of effect before, it's mostly used with cartoon avatars, to give them that black drawn outline look. Here's how it's done.

First take the prim you want to use for the inside, then copy it and make it slightly larger than the inside prim. Make it as hollow as it can get, then texture the outside invisible, so you can see the inside, and retexture the inside of the hollow prim.

You can do this with sculptie prims too but it's done slightly differently since you can't make them hollow. Create the two prims in the same way, so that one is slightly larger than the other. This time, on the larger prim, go to the "object" tab in the build menu, and under the sculptie texture input, select "inside out".

Monday, August 16, 2010

Setting up your own Open Sim

Well, a few months ago I had tried this and became deeply, deeply frustrated. It seemed nothing I did was working, and the situation was hopeless, so I stopped trying to set up my own Open Sim on my local machine. Yesterday however someone asked me if I ever got it working, and I told them no, but maybe I could look into it again.

So I did. Only to find that my first google search and attempt at setting it up again were successful. I love when things work out :)

Here are the instructions that I followed :

http://arianeb.wordpress.com/2010/04/14/setting-up-a-simple-open-sim-sandbox-on-your-hard-drive/

Saturday, August 14, 2010

Allow Inventory Drop

So I received a question today about making it so that someone else could add inventory to an object that is no-mod. The answer is really simple. llAllowInventoryDrop(). The parameters are either TRUE or FALSE. You can put it wherever you want in your script so that it will set to either true or false exactly when you want, like if you want it that way all the time, just set it to true in state_entry. Or if you only want it to be that way for a few seconds, put it in an event, set it to true on one line, use llSleep() to stop the script for a few seconds, then set it back to false after that.

If it's set to true, anyone can drop inventory in, any object type except for scripts. The exception to this is that scripts can be transferred from object to object if llAllowInventoryDrop() is true, but the scripts are transferred in a non-running state, meaning they either need to be compiled again, or the object needs to be saved and re-rezzed.

Monday, August 02, 2010

Skinning Cats

Well we all know there's more than one way to skin a cat. Or a less violent alternative, multiple directions to pet them. They all have their pro's and cons, like, petting a cat one way will give you a nasty static shock but also make the kitteh rub against you affectionately, and another will make it barf in your shoes. Or something. Anyway, enough about cats (mew).

Here are a few ways to do a click and drag thinger with a HUD. They all have their pros and cons.
1. Dragging out a selection box texture on a prim. This requires 2 prims, one for the actual box and one for an image under it (so you can see the box).
Pro: Looks cool and will drag a 2D selection box on the surface of a prim.
Con: Only affects the texture and doesn't move a prim. Well I guess that's not a con if you're into that kind of thing.

You can find the code for that at the LSL code receptacle on the wiki. http://wiki.secondlife.com/wiki/ClickAndDrag

2. Dragging a prim around using llDetectedTouchPos
Pros: Only uses one prim and can be dragged as far as you want in any direction.
Cons: Can only be dragged so fast because if you move your mouse off the surface of the prim, the touch event will stop and the prim won't move anymore. *Edit* Tahlie pointed out to me that the event doesn't actually stop, just that the prim isn't getting information on where to move anymore, and you can keep moving the prim if you move your mouse back over the prim.

//Written and given permission to duplicate by Tahlie Teskat
key owner;

// For move Function
vector LastTouchPos;

default {
// Reset Security
state_entry() {
owner = llGetOwner();
}
on_rez(integer rezzed) {
if (owner != llGetOwner()) llResetScript();
}
link_message(integer sender_num, integer num, string str, key id) {
if (num == 666 && str == "reset") llResetScript();
}
// Reset Security
touch_start(integer total) {
LastTouchPos = llDetectedTouchPos(0);
}
touch(integer total) {
vector delta;
vector touchPos = llDetectedTouchPos(0);
if (touchPos != <0.0,0.0,0.0>) delta = touchPos - LastTouchPos;
if (delta != <0.0,0.0,0.0>) llSetPos(llGetLocalPos() + delta);
if (touchPos != <0.0,0.0,0.0>) LastTouchPos = touchPos;
}
}
3. Using a the UV coordinates of the texture of an invisible prim to drag another prim.
Pros: can click anywhere and the prim will follow. Can click and drag without any limit on speed.
Cons: only works with 1 prim at a time (in this script's current state), requires 2 prims, doesn't always drag directly under where your mouse is (again probably just the way the script is now, it needs some tweeks.) Put this script in the root and make that prim invisible, stretch it to however large of an area you want, and link it to another object you want to drag and make sure it's under the root object.

//written by Valent1ne
default
{
touch(integer total_number)
{
vector offset = <.58,.45,0>; //this sort of random vector is the offset, you'll have to play with it to get it to work just right. At least until I figure out a better way.
vector pos = llDetectedTouchUV(0) - offset;
llSetLinkPrimitiveParamsFast(LINK_ALL_CHILDREN, [PRIM_POSITION,pos]);
}
}

Tuesday, July 27, 2010

Remove inventory

Sometimes the solution to your problem is the easiest or most obvious. Whenever someone asks me about a problem, the first thing I usually ask is the most obvious answer, the kind of thing that makes you *facepalm* because it's so simple or right in front of your nose.

Someone asked me tonight wanting to know how to get more than one script to delete, including itself. The answer was simple, have the other scripts delete first, then have the script self destruct. Remember LSL reads top to bottom, left to right. So if you have one function before the other, the one on the topmost line will run first.
llRemoveInventory("New Script 1");
llRemoveInventory("New Script 2");
llRemoveInventory(llGetScriptName());

Sunday, July 04, 2010

Hiding Object Name and Carriage Returns

So the topic came up of how to hide the name of the object when using llSay or llInstantMessage. Well as far as I know there is no way to completely get rid of the object name with llInstantMessage, as it will display as "(empty)" if there is nothing, but this way works great for llSay. Also, if you want to insert a carriage return into your string, you can use \n to make a new line.

llSetObjectName(""); //sets the name of the object to nothing
llSay(0, "This is some text \n and this will end up on the next line");
llSetObjectName("object"); //this is to set the name of the object back to what it was originally

Saturday, June 19, 2010

Tiny Smoke

So Patti asked me how to make smoke that is tiny and have it look good too. Well I have a stock script I use to base my particles off of. You can see it below. As it is set up now, the script below will produce a tiny smoke plume. They trick to creating tiny particles is using a texture that has been shrunk down, meaning there is only something in the middle and the rest is alpha. The scripted size of particles can only get so small, that is to say I think the smallest they can be is 0.03. Below that and they won't even be rendered.

Below the particle script is a rotation script, you can throw that in the prim or combine it with the top script; it will make the prim rotate.

float maxsysage = 0.0;
float maxspeed = 0.02;
float minspeed = 0.02;
float burstrad = 0.0;
integer burstcount = 20;
float burstrate = 0.01;
float outangle = 0.1;
float inangle = 0.001;
vector omega = <0.0,0.0,0.0>;
vector startcol = <1.0,>;
vector endcol = <.0, 0.0, 0.>;
float startalph = 0.1;
float endalph = 0.00;
vector startscale = <0.04,0.04,0.04>;
vector endscale = <.00,0.00,0.00>;
float maxage = 4.0;
vector accel = <0.0,>;
string texture = "cb722f94-f87a-2a53-e6df-0f5f03ce6f6d";

integer flight;
integer pilot;

ParticlesOn()
{
llParticleSystem([PSYS_PART_FLAGS,
PSYS_PART_INTERP_COLOR_MASK |
PSYS_PART_INTERP_SCALE_MASK |
PSYS_PART_FOLLOW_SRC_MASK |
PSYS_PART_FOLLOW_VELOCITY_MASK |
PSYS_PART_EMISSIVE_MASK,
PSYS_SRC_PATTERN,
PSYS_SRC_PATTERN_ANGLE,
PSYS_PART_START_COLOR, startcol,
PSYS_PART_START_ALPHA, startalph,
PSYS_PART_END_COLOR, endcol,
PSYS_PART_END_ALPHA, endalph,
PSYS_PART_START_SCALE, startscale,
PSYS_PART_END_SCALE, endscale,
PSYS_PART_MAX_AGE, maxage,
PSYS_SRC_ACCEL, accel,
PSYS_SRC_TEXTURE, texture,
PSYS_SRC_BURST_RATE, burstrate,
PSYS_SRC_INNERANGLE, inangle,
PSYS_SRC_OUTERANGLE, outangle,
PSYS_SRC_BURST_PART_COUNT, burstcount,
PSYS_SRC_BURST_RADIUS, burstrad,
PSYS_SRC_BURST_SPEED_MIN, minspeed,
PSYS_SRC_BURST_SPEED_MAX, maxspeed,
PSYS_SRC_MAX_AGE, maxsysage,
PSYS_SRC_OMEGA, omega ]);
}

ParticlesOff()
{
llParticleSystem([PSYS_PART_FLAGS,
PSYS_PART_INTERP_COLOR_MASK |
PSYS_PART_INTERP_SCALE_MASK |
PSYS_PART_FOLLOW_SRC_MASK |
PSYS_PART_FOLLOW_VELOCITY_MASK |
PSYS_PART_EMISSIVE_MASK,
PSYS_SRC_PATTERN,
PSYS_SRC_PATTERN_ANGLE,
PSYS_PART_START_COLOR, startcol,
PSYS_PART_START_ALPHA, startalph,
PSYS_PART_END_COLOR, endcol,
PSYS_PART_END_ALPHA, endalph,
PSYS_PART_START_SCALE, startscale,
PSYS_PART_END_SCALE, endscale,
PSYS_PART_MAX_AGE, 0.01,
PSYS_SRC_ACCEL, accel,
PSYS_SRC_TEXTURE, texture,
PSYS_SRC_BURST_RATE, burstrate,
PSYS_SRC_INNERANGLE, inangle,
PSYS_SRC_OUTERANGLE, outangle,
PSYS_SRC_BURST_PART_COUNT, burstcount,
PSYS_SRC_BURST_RADIUS, burstrad,
PSYS_SRC_BURST_SPEED_MIN, minspeed,
PSYS_SRC_BURST_SPEED_MAX, maxspeed,
PSYS_SRC_MAX_AGE, 0.01,
PSYS_SRC_OMEGA, omega ]);
}

default
{
state_entry()
{
llSetTimerEvent(0.0);
llParticleSystem([]);
ParticlesOn();
}

on_rez(integer sparam)
{
llResetScript();
}

link_message (integer sender, integer num, string msg, key id)
{
if (num == 0 && msg == "flameon")
{
ParticlesOn();
}
if(num == 0 && msg == "flameoff")
{
ParticlesOff();
}
}
}

default
{
state_entry()
{
llTargetOmega(<0,0,1>,PI,0.20);
}

}

Wednesday, May 26, 2010

And now for something completely unrelated.....

I was asked about making sculpties in Blender. Well the fact of the matter is that it's a little bit of a pain to set up if you're doing it from scratch. So what I've done is I've taken care of the initial steps and saved the file, and that is available to everyone here: http://bitcracked.com/sl/sculpty.html Just download the file, unzip and open it.

I have it set up with the default cylinder. If you want more vertices just push A (hotkey to select all), go to edit mode, click editing (looks like a sqaure with dots at the corners) and click subdivide.


To export your sculpty map, follow these steps.
1. Move your mouse right over the line between the top and bottom window and choose "split area"

2. Click the little box at the bottom left of the new window you just created and select "UV/image editor"

3. Click on Image > new, and set the dimensions for 256x256. Then, push F10 to go to the render menu, and click the "bake" tab. In the right column, click "Textures", and then click the large "Bake" button. You will see your colored sculpt map appear in the right window.



4. Once the image has been baked, click on image again, choose Save As, and select where you want to save your image. At the bottom of the save screen make sure you select to save your image as a Targa file.

I know there are plugins and junk to make sculpties in blender, but if you don't feel like using those or they're giving you trouble, this can be an easier way to make them without plugins. Just make sure you don't save over your sculptstart.blend file :)

Also, I know that SL will trim down your image to be 128x128 (and 32x33 verts) when you use it as a sculpt map but I always like to start high res and then let it be trimmed down as needed.

Dave's Giant Database Insertion Tutorial

So, I've had a request to explain inserting data into an external database from SL. This is a pretty lengthy subject but to shorten it up for this post I'm going to assume a few things, such as:
  1. You have a web server and a place that this database/web script can go.
  2. You have a database and don't need help setting one up
  3. You have at least very basic knowledge of PHP and writing MySQL requests.
As a side note, everything on this page that is highlighted in orange is something that you will need to rename yourself.

That being said, let's get started. The first thing you will need is to set up your database and know what you are going to store. For this example let's say you want to insert the name of an avatar into a database whenever the object is touched, and keep a running tab of how many times they have touched it.

Assume you have a database called "SL" with a table called "stats". Stats has two columns, "name" and "number". Name will be the name of the avatar (for this example it would need to be set as unique). Number will represent the number of times the prim was clicked.

Now what we are going to do is set up our PHP script. What will happen is that every time the prim is clicked, it will send a request to this PHP script, which will then update the database. Here is an example of what the PHP script should look like for this example.

<?php
$db = mysql_connect("localhost", "db_username", "your_password") or die ("<html><script language='JavaScript'>alert('Unable to connect to database! Please try again later.')</script></html>");
mysql_select_db("SL",$db);

$name = $_GET['name']; //$_GET takes variables that are passed from the url (see the LSL example)
$usertable = "stats";

$update = "INSERT INTO $usertable SET name = '$name', number = 1 ON DUPLICATE KEY UPDATE number = number + 1";
$result = mysql_query($update);

?>

And now for the LSL script that will send the request to the PHP page:



string owner_name;
key owner_name_query;
default
{
    state_entry()
    {
       
    }


    touch_start(integer total_number)
    {
       owner_name_query = llRequestAgentData(llGetOwner(), DATA_NAME);
    }
     dataserver(key queryid, string data){
        if (owner_name_query == queryid){
            owner_name = data;
            llHTTPRequest("http://www.yoursite.com/yourphppage.php?name=" + owner_name, [], "");
        }
    }
}
 Let's take a look at the URL in the llHTTPRequest function. http://www.yoursite.com/yourphppage.php?name=" + owner_name. Remember the $_GET['name'] part of the PHP script? Well this is where that variable is taking data from. ?name= denotes a variable that can be passed to PHP using a URL. If you want to pass more variables, you can string them along with ampersands like this: ?name=Joe_Shmo&id=123456&status=living

Well I hope that is enough to get you started loading things into databases. Next time we can talk about how to get data back out of the database.

Sunday, May 23, 2010

Beacon

So Patti wanted a beacon for a radio tower she was making, and I came up with this script. It's a pretty simple script but there's a nifty trick in here I felt like I just *had* to blog about. Here is the beacon script.

float delay = 0.01;
float k = 0;
integer toggle = 0;
default
{
state_entry()
{
llSetTimerEvent(delay);
}
timer(){
if(toggle == 0){
llSetLinkPrimitiveParamsFast(LINK_SET, [25, ALL_SIDES, k]);
k += 0.03; //changing this will change how fast the blink is
if (k >= .5){
toggle = 1;
}
}
if(toggle == 1){
llSetLinkPrimitiveParamsFast(LINK_SET, [25, ALL_SIDES, k]);
k -= 0.03;
if (k <= 0.04){ toggle = 0; } } } }

The neat trick is using llSetLinkPrimitiveParamsFast instead of llSetPrimitiveParams. Check out the video to see why :) The one using llSetLinkPrimitiveParamsFast is on the left. Nice and smooth :)

Oh! The one thing to look out for: you have to be careful changing the speed, do some math and make sure it won't try setting the glow under 0 or over 1. Otherwise you get a super annoying script error D:

Saturday, May 22, 2010

Remote control



Mmmmmkay so COKE asked me the other day about making a remote control for some curtains, like if you click a button then all the curtains should open or half shut or close. Well COKE I'll give you a real helpful snippet and hopefully you can figure out where to go from there. Of course if you need more help you're always welcome to ask more questions :P

Kay so here goes.

My super basic remote control script looks like this (it goes in the object that you're using to be the remote):

default
{
state_entry()
{

}

touch_start(integer total_number)
{
llRegionSay(-999, "1");
}
}
And this is the script that would go in the curtains (it would need to be the same script that controls whether they're open or closed and whatnot):

default
{
state_entry()
{
llListen(-999, "", "1bd1faad-303f-748e-bf5c-745d124e751e", "");
}
listen(integer channel, string name, key id, string message)
{
if(message == "1"){
llSay(0, "Hi everybody :)");
}
}
}
Here is an explanation of the llListen function. The parameters are like this: llListen( integer channel, string name, key id, string msg );(thanks wiki :) )
The parameters act as filters for what you want to listen for. This is great for cutting down on lag and makes sure the script doesn't have to sift through tons of unrelated chat. Channel is obviously the channel you want to listen for the message on (I used -999). Name will listen only for chat from specific av's or objects (I used "" to leave that blank). ID will filter for a specific object or avatar UUID. You'll notice that I used the UUID of a specific prim. You can get this really easily from the build menu using Emerald (see fig 1.). Msg will filter for a specific message, but since we will need to use different messages, you should leave that blank too using "".

Fig 1.
I think the "listen" event is pretty self explanatory. I have it set up so that if the message is "1", the prim will say a message. Sooooo, you can set up your remote control script to cycle through saying "open", "half_open", "close", and then set up your listener script to either open, set the curtains to half shut, or closed, based on the message.

Let me know if you have any more questions, you know where to find me :)

Friday, May 21, 2010

Hot Topics (Part 1)

Ok so I've helped several people with several questions pertaining to several things. None of which were answered on the blog so I figure I'll pick and choose and write a post about a few things I've helped with here and there. This one will be a quickie.

Shila was working on a script that reads a notecard, and she wanted to know how to reset the script whenever the notecard is edited and saved. The code for this is pretty quick and simple. All you have to do is add the "changed" event to your code.

changed(integer change){
    if ( change & CHANGED_INVENTORY){
        llResetScript();
    }
    }

Tuesday, May 18, 2010

Get a bunch of info on someone (llRequestAgentData example)

Shila asked how to get an avatar's name , DOB, Payment Info  and online status. Doing this can be lengthy because each of these things need to be handled differently as they return different data types. Here is an example script I wrote this afternoon that gets all of these pieces of information:

key online_query;
string name_query;
string birthday_query;
string payinfo_query;
string owner_name;
string online;
string birthday;
string payinfo;

default
{
   touch_start(integer total_number)
    {
        key id = llDetectedKey(0);
        name_query = llRequestAgentData(id, DATA_NAME);
        online_query = llRequestAgentData(id, DATA_ONLINE);
        birthday_query = llRequestAgentData(id, DATA_BORN);
        payinfo_query = llRequestAgentData(id, DATA_PAYINFO);
    }
    dataserver(key queryid, string data)
    {
        //Find out their name --------------------------------------
        if ( name_query == queryid )
        {
            owner_name = data;
            llSay(0, "The name of the person is : " + owner_name );
        }
       
        //Find out if they are online-------------------------------
        if ( online_query == queryid )
        {
              online = data;
            if (online == "1"){
                llSay(0, "he or she is online");               
            }
            else
            {
                llSay(0, "he or she is offline");          
            }
        }
       
        //Find when their birthday is -------------------------------
        if ( birthday_query == queryid )
        {
            birthday = data;
            llSay(0, "Their birthday is "+ birthday);
        }
       
        //Find out what their payment info status is ----------------
        if ( payinfo_query == queryid )
        {
            payinfo = data;
            if (payinfo == "0"){
            llSay(0, "They have no payment info on file");
            }
            if (payinfo == "1"){
            llSay(0, "They have payment info on file");
            }
            if (payinfo == "3"){
            llSay(0, "Their payment info has been used");
            }//end if(payinfo == "3")
        }//end query if
    }//end dataserver
}//end default
There are a few things you'll notice right away. First of all I have this set up so it gets the info of whoever touched the prim. The next thing is that I have four queries set up for each of the pieces of data we want to get, and finally inside the dataserver event we have four "if" statements that handle each of the queries. The name query returns the avatar's name as a string, their online status returns as an integer disguised as a string (either 1 or 0 depending on their online status), their birthday returns as a string in the format YYYY-MM-DD, and their payment info also returns as integers in string format, 0 for no payment info, 1 for pay info on file, and 3 for pay info used. Don't ask what happened to 2.

So now you know how to get most of the data on someone's avi. If you want to do other things with this info you can put your functions in the dataserver event, inside the if statement pertaining to that piece of information.

Monday, May 17, 2010

Whoopie! (A quick sit detect script)

Nettrice's first question referred to detecting when an avatar has planted their big fat butt on a prim. Of course we've all seen this before with lucky chairs, as well as any poseball. Here's a quick example:

vector sitoffset=<0.0, 0.0, 0.1>; // sit position offset (x = front back, y = left right, z = updown)
default{
    state_entry(){
        llSitTarget(sitoffset, ZERO_ROTATION);
    }
    changed(integer change)
    {
        if (change & CHANGED_LINK)
        {
           
            if (llAvatarOnSitTarget() != NULL_KEY)
            {
                 llSay(0, "zomgz!!");
            }
               
        }
    }
}
You don't have to do this, but I put in a sit target function (llSitTarget) just so that I could sit on the object easier. I would probably recommend this though, I had a rough time getting my av to sit down on the prim without it ("no room to sit here, try somewhere else").  All you would have to do to change this script to make it do what you want is put all your functions where " llSay(0, "zomgz!!");" is right now, and to implement it into another script just copy and paste everything in the "changed" event.

Happy sitting!

Sunday, May 16, 2010

Collision Detection Goodness

Nettrice had a couple of questions but I've had a long weekend and I'm draggin so I'm going to answer her second question first and save the other one for tomorrow.

Her question was in regards to making part of a ramp/walkway light up as the avatar touches those certain parts, similar to the piano keys you play by walking on (e.g. Tom Hanks in Big).

You can achieve this with just a few lines of code.

default
{
    state_entry()
    {
        llVolumeDetect(TRUE); // Starts llVolumeDetect
    }
    collision_start(integer total_number)
    {
 //Your functions will go here, for example the color changing and sound playing
llPlaySound(yoursound, 1);
          llSetColor(<0.6,0.5,0.4>, ALL_SIDES);
    }
}
 llVolumeDetect triggers the collision_start event, so whatever happens in that event will be triggered when an avatar (or object) collides with that object. There are a few things to keep in mind, the first being that the object will turn phantom, so make sure you have another solid prim under that prim if he is walking on it. The other thing to remember is that this function must be applied to the root object.

Hope this helps! Check back tomorrow for the answer to your first question.

Tuesday, May 04, 2010

Debug Assertion Failed!

PatriciaAnne Daviau writes:
Hello...This so does not have anything to do with LSL and not sure if you can help me but I am gonna throw it out to you anyway. I got a popup error in a project I was trying to compile. It read:
Debug Assertion Failed!
Program: D:\\3pt\MsPlatformSDK\2000_04\bin\RegSvr32.exe
File: oletyplb.cpp
Line: 32

Press Retry to debug the application
Abort Retry Ignore

I tried clicking retry but it gave me nothing. The other two options didn't help either.

Well, I'm not super great with C++ but I took a crack at the problem. Basically, from my understanding, the debug assertion is a part of the code that runs when it is compiled and if it returns false, stops compiling and gives you an annoying message so that you can go into the debugger before something explodes.

The part that I would look at is the "Line: 32" part. My guess is that something on that line in oletyplb.cpp is causing the compile to fail. Based on some of my research I found that the culprit is usually something like using an invalid pointer or trying to index an array beyond its boundaries.

Well I hope that helps, keep us updated on your progress!

Monday, May 03, 2010

Intro

Hi :) This is not really intended to be your typical blog, rather it will (hopefully) be a question and answer page for anything and everything related to LSL scripting. I also have a background in PHP, Javascript (and Processing), Actionscript 2.0, as well has HTML/CSS, so any questions related to those languages are fair game, although lets try to stick with questions that relate to LSL. That being said, feel free to post a comment to this post, or shoot me an email with your questions.

When asking a question, please leave your SL name and whether you would like to remain anonymous in the answer.

I hope to hear from you all soon!