Wednesday, November 26, 2008

Region wide door w/ Master Controller

Ok, Zanthar on OS Scripters asked about a region wide door... figured I'd code in a blog post for a minute...

Concept - Master Controller that you would list all the names in, slave door script that would talk to the master controller.

**** Note. I never tried to compile this ******

Master Controller
--


default
{
list validusers = ["Redbeard McCellan"];

state_entry()
{
llSetName("DOORCONTROLLER");
llListen(-8988,"", NULL_KEY, "");
//Randomly picked a channel, but it needs to be static.
}

listen( integer channel, string name, key id, string message )
{
if(llListFindList(validusers,(list)message) != -1)
{
llRegionSay(-8989,(string)id);
}
}

}




Door Script
--
default
{
state_entry()
{
llListen(-8989, "DOORCONTROLLER", NULL_KEY, (string)llGetKey());
//Randomly picked a channel, but it needs to be static.
}

touch_start(integer total_number)
{
llRegionSay(-8988, (string)llDetectedName(0));
}


listen( integer channel, string name, key id, string message )
{
if(message == (string)llGetKey()) //expects back the it's own key if it is supposed to open
{
llSetTimerEvent(15);
llSetAlpha(0,ALL_SIDES);
llSetStatus(STATUS_PHANTOM,TRUE);
}
}

timer()
{
llSetTimerEvent(0);
llSetAlpha(1,ALL_SIDES);
llSetStatus(STATUS_PHANTOM,FALSE);
}
}

Lazy

I suppose I should get back into posting here.....

Saturday, March 29, 2008

Rezzing obects - rotation adjustment

On Scripters Support Group today someone asked about adjusting for rotation when rezzing objects.

You can use llRot2Fwd, llRot2Up and llRot2Left to adjust.

For example:

llRezAtRoot(llGetInventoryName(INVENTORY_OBJECT,0), llGetPos()-llRot2Fwd(llGetRot())+llRot2Left(llGetRot()),llGetVel(),llGetRot(),llGetStartParamater());

Would (with not a lot of efficiency) rez the first object in inventory 1m to the rear and to the left.

Wiki wiki wiki....



Jansen Miles IM'd me with a modification:


//llRot2Fwd() and it's kin represent a normalization of 1.0. So just multiply that by your actual desired vector components!
default
{

touch_start(integer total_number)
{
//* Rezzed object offset from rezzer center.
vector offset = <0, 0, 0.35>;

llRezObject(llGetInventoryName(INVENTORY_OBJECT,0),
llGetPos() + (llRot2Fwd(llGetRot()) * offset.x) + (llRot2Left(llGetRot()) * offset.y) + (llRot2Up(llGetRot()) * offset.z),
llGetVel(), llGetRot(), llGetStartParameter());

}
}




A slightly better example including Jansen's suggestion:


string inventory_item;

default
{
state_entry()
{
inventory_item=llGetInventoryName(INVENTORY_OBJECT,0); // get the name of the first object in inventory
}
touch_start(integer p)
{
rot=llGetRot();

//a vector is used to represent your offset in terms of fwd/back, left,right, up/down
// eg. <-2,0,1> would be 2m back, 1m up

vector offset=<-2,0,1>;


vector rezpos=llGetPos() + (llRot2Fwd(rot) * offset.x) + (llRot2Left(rot) * offset.y) + (llRot2Up(rot) * offset.z);

llRezAtRoot(inventory_item, rezpos, ZERO_VECTOR, rot, 0);
//ZERO_VECTOR is used instead of a velocity. One *could* use llGetVel if you "rezzer" is moving
//the last "0' is the paramater that will be passed to on_rez in teh rezzed object


}
}



I like the use of the vector for offsets!

Thursday, March 20, 2008

A trick for flipping a flag in LSL

Chatting on the Scripters Support Group, Trent Platthy posted an interesting trick I hadn't thought of before for flipping a flag variable.

flag=!flag;


Nice and simple. :)

A code example:

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

touch_start(integer total_number)
{
if(flag)
{
//flag is set
llSay(0,"Flag is Set");
}
else
{
llSay(0,"Flag is not set.");
}
flag=!flag; //toggle
}
}

Saturday, March 15, 2008

Detailed example of a Dialog Box

Dialog boxes are handled using the llDialog command. See the wiki for more details on the arguments.

This example is a low-lag design of using llListen - it is called after touch_start is called so that the user's key can be added as a filter to the llListen call. Adding the user's key is the most efficient filter, but requires us to remember to remove the listen handle using llListenRemove. Note that we call this in two spots - in the listen() handler (a user successfully clicks Yes or No) or in the timer() handler to handle a timeout.

To handle a timeout we also have to call llSetTimerEvent in a few spots. In touch_start to start a timeout countdown, in listen to cancel the timeout if we receive a response and in timer itself to stop trigger a second timeout in th event a timeout occurs.

Note the use of llFrand to assign a random channel for the llListen and llDialog commands.



integer channel;
integer listenhandle;

default
{
state_entry()
{
channel=(integer)llFrand(10000)+100;
}

touch_start(integer total_number)
{
//This example does not handle two people touching the prim at the same time
//You should use a for loop and total_number to handle multiple clicks
if(!listenhandle) // only act on touches if not already waiting for someone to answer
{
llSay(0, "Touched by "+llDetectedName(0));
llSetTimerEvent(30); // give user 30 seconds to click
listenhandle=llListen(channel, "", llDetectedKey(0), ""); // low lag only listen for one user.
llDialog(llDetectedKey(0), "Answer Yes or No", ["Yes","No"],channel);
}
}
timer()
{
llSetTimerEvent(0);
llListenRemove(listenhandle); //stop listening
llSay(0,"Timed out.");

}
listen(integer chan, string name, key id, string message)
{
if(message=="Yes")
{
llSay(0,"Yes");
}
else if (message=="No")
{
llSay(0,"No");
}
llListenRemove(listenhandle); //stop listening
llSetTimerEvent(0);
}
}

Wednesday, March 12, 2008

Taryn London's website

Stayed up late helping Taryn get her blog rolling... Taryn is a great SL Mentor and will have lots of tips on her website. She's also going to be a host blogger here!

Check out www.TarynLondon.com

Tuesday, March 11, 2008

Listen event fails after object changes ownership

A problem I often see on the the Scripting chat is about users that are having troubles with listen() events after an object's owner changes. (i.e. someone buys the object).

This happens because users often call llListen() in the state_entry() handler and specify llGetOwner() as a filter. Using llGetOwner() as a filter is a good idea because it is the lowest lag option, but then special attention needs to be given on handling ownership changes.

Fortunately, the changed() handler gives us an easy fix - simply add to your code a "changed handler" that resets the script [llResetScript()] on change of ownership.

The code looks something like this:

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



Note that the change integer in the arguments is bitwise compared to the constant CHANGED_OWNER. if(change==CHANGED_OWNER) would work most of the time, but it is possible to get a single call to changed() with multiple options bitwise ANDed together.

I'll write future posts on how to avoid resetting the script and more about bitwise operations.

Official Second Life Blog