Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Converting a wear-able prim to a sit-on prim...

Sydney Alexander
Registered User
Join date: 19 Feb 2005
Posts: 69
06-19-2005 13:43
I have read that this is easy to do, but I have found nothing in the wiki that points me int the right direction. Anyone knwowhere I should look with in the wiki for this information?

thanks
Catherine Omega
Geometry Ninja
Join date: 10 Jan 2003
Posts: 2,053
06-19-2005 16:51
You're after a way to sit on a prim that's attached to someone? While it's attached to them? Unfortunately, you can't do that. You used to be able to, but you can't any longer. (For a couple of years, now, if I recall correctly.) This is presumably because of some kind of physics issue.
_____________________
Need scripting help? Visit the LSL Wiki!
Omega Point - Catherine Omega's Blog
Sydney Alexander
Registered User
Join date: 19 Feb 2005
Posts: 69
06-19-2005 17:58
Hi Cathrine,

I have a something I can "wear" and issues commands to change poses. I would ike to sit on the prim and not have to wear it. I want to have clients sit on the object and I can cycle throught the animations. T
here is an open source dance bracelet I have used as the base for this project. In a post on this forum it was said that changing over from an attachment to something you sit on is less than 10 lines of code?

Thanks,

Sydney
Eggy Lippmann
Wiktator
Join date: 1 May 2003
Posts: 7,939
06-19-2005 17:59
Look in your script and you will probably find something like this:

attach()
{
//Select and then copy this code
}

You need to put it inside something like this:

changed(integer change)
{

if(change & CHANGED_LINK)
{
//Paste code here
}

}
Sydney Alexander
Registered User
Join date: 19 Feb 2005
Posts: 69
06-19-2005 18:16
From: Eggy Lippmann
Look in your script and you will probably find something like this:

attach()
{
//Select and then copy this code
}

You need to put it inside something like this:

changed(integer change)
{

if(change & CHANGED_LINK)
{
//Paste code here
}

}


Hi Eggy! here is the script I am using:

CODE

// script Name: Animation Bracelet
// Creator: Kurt Zidane
// Cersion: 7.14
// Type: Open source script, reffer to included open sources licences. Do not remove licences.
/ outline: Animation Bracelet is a multiple animation attachment. It responds to voice command given by the weaer. This script aniamtes the avatar by keoping track witch animation is playing by invitory number. Animation string name, and anmation key is expected to be set by invitory number.



//-- globals -- //
//-users
key userID = NULL_KEY ;
//-lisson
integer channel = 1 ;
integer listenHandle;
string commandName = "" ; //Prefix (prefix command peramiter), if "" not prefix will be expected.
//-animation tracking
integer currentAnimation = 0 ;
integer TotalNumberOfAnimations = 0 ;
key animation = NULL_KEY ;
string animationName = "" ;
//hacks
integer ugly = FALSE ;



// -- functions -- //

//determins the number of animations in invitory, check to makre sure current animation is in range.
initialize()
{
//Set Total Number of Animations
TotalNumberOfAnimations = llGetInventoryNumber(INVENTORY_ANIMATION);

//Safe Check - confirms currentAnimation is in range.
if (currentAnimation > TotalNumberOfAnimations)
{
currentAnimation = 0;
}

//sudo code: reset currentAnimation to match proper pos..
}



//triggered when some one sits
//reffer to gPermisstionToAnimattion() to add commands at start.
commenceSetup( key id )
{
userID = id;
animationStart( id );
}


//insheating set up
animationStart (key id )
{
if ( ( llGetPermissions() & PERMISSION_TRIGGER_ANIMATION ) == PERMISSION_TRIGGER_ANIMATION )
{
// disabled, need to create a function to covert llGetAnimation's result to llStopAnimation format. //llStopAnimation( llGetAnimation(id) );
stopAllAnimations( id );

gAnimationDetails(currentAnimation);

startAnimation( animationName );

listenHandle = llListen( channel, "", id, "");

if ( channel != 0 )
{
llInstantMessage( id, "type '/" + (string)channel + " help' for instructions." ) ;
}
else if ( commandName != "" )
{
llInstantMessage( id, "type '" + commandName + " help' for instructions." ) ;
}
else
{
llInstantMessage( id, "type 'help' for instructions." ) ;
}
//note state channel != 0 && commandName != "" not included
}
else
{
llRequestPermissions( id, PERMISSION_TRIGGER_ANIMATION | PERMISSION_ATTACH );
}
}


//triggered when some one stands up
// removes lisson, waist not want not.
commenceShutDown()
{
llListenRemove(listenHandle);

stopAnimation( animationName );

userID = NULL_KEY;
}


instructions( key user)
{
//declaration
list instructions;

//process
if ( channel != 0 )
{
instructions += (string)("all commands should be typed on channel " + (string)channel + ". ie '/" + (string)channel + " next'");
}
else if ( commandName != "" && channel == 0 )
{
instructions += (string)("all commands should be typed after the word " + commandName + ". ie '" + commandName + " next'" );
}

instructions += [
"'next' to navigates forword, or 'next (number)' to move forword (number) of poses.",
"'back' to navigates backwords, or 'back (number)' to move backword (number) of poses.",
"'name' will give you the name of the current pose.",
"'name (pose name)' will set the pose with that name.",
"'list' will retreve a list of poses to chose from, or 'list active' will return a list of active poses and animations.",
"'stop' will stop current pose, or 'stop all' to stop all poses.",
"'start' will start or re-start the current pose.",
"'number' will return the current pose number, or 'number (number)' to trigger the a specific pose by number.",
" Note: a pose's number can change as more poses are added, or poses are removed.",
"'random' will chose a pose at random, and start that pose.",
"'done' will detach the pose braclet from your model, and stops the current pose.",
"'help' will displays this set of instructions again."
];

//out put
messageList ( user, instructions );
}


//removes the current listen, and set a new listen based on passed integer
//set global variable: channel
changeListen( integer chan )
{
llListenRemove(listenHandle);

channel = chan;

listenHandle = llListen( channel, "", userID, "");
}


messageList ( key avatar, list read )
{
integer numLines = llGetListLength( read );

integer counter;
for ( counter = 0; counter < numLines; counter++ )
{
llInstantMessage( avatar, llList2String( read, counter ) );
}
}


integer randomInteger( integer maxNumber )
{
float random = llFrand((float)maxNumber);
for ( ; random > ( (float)maxNumber - 1.0 ) + 0.4; )
{
random = llFrand((float)maxNumber);
}

return (integer)random;
}

randomAnimation (integer range)
{
changeAnimation ( randomInteger( range ) );
}

listActiveAnimations ( key avatar )
{
list activeList = ["Active Animations:"] + llGetAnimationList ( avatar );

messageList ( avatar, activeList );
}

//commandNexus read the value of a passed string
// compares that value to preset values
// and triggeres the apropret function for that command.
commandNexus(string inPut)
{
//decloration
list commands = [] ;
integer langth = 0 ;
integer partTracker = 0 ;

string command = "" ; //used for commands performance boost


commands = llParseString2List( inPut, [], (list)" " );
langth = llGetListLength( commands );


//commands
if ( (channel != 0) || ( (channel == 0) && (commandName == "") ) || ((commandName != "") && (llList2String(commands,partTracker)==commandName)) )
{
//for prefix
if ( commandName != "")
{
partTracker += 2;
}

//speeding up idenifty command command
if ( partTracker < langth )
{
command = llList2String(commands, partTracker);
partTracker += 2;
}

//idenifty command, and act acordingly
if ( command == "next")
{
if ( partTracker < langth )//( langth > part && parts >= 3 ) || ( langth > 1 && parts < 3 ) )
{
incrimentAnimation( llList2Integer( commands, partTracker) );
}
else
{
incrimentAnimation( 1 );
}
}
else if ( command == "back" )
{
if ( partTracker < langth )
{
incrimentAnimation( -llList2Integer( commands, partTracker) );
}
else
{
incrimentAnimation( -1 );
}
}
else if ( command == "list" )
{
if ( llList2String ( commands, partTracker) == "active")
{
partTracker += 2;
listActiveAnimations ( userID );
}
else
{
listAnimations();
}
}
else if (command == "stop" )
{
//detect "stop"," ","all"
if ( (partTracker < langth ) && ( (string)llList2List( commands, partTracker, (langth - 1) ) == "all" ) )
{
stopAllAnimations( userID );
// disabled untill a function to translate llGetAnimation results into llStopAnimation format. //llStopAnimation( llGetAnimation(userID) );
}
//defolt
else
{
stopAnimation( animation );
}
}
else if ( command == "start" )
{
changeAnimation ( currentAnimation );
}
else if ( command == "help" || command == "h" || command == "H" || command == "Help")
{
instructions( userID ); //message( userID, instructions );
}
else if ( command == "" && commandName != "" && channel == 0)
{
llInstantMessage( userID, "No Command Detected" );
}
else if ( command == "name" && partTracker < langth )
{
validAnimation( (string)llList2List( commands, partTracker, (langth - 1) ) );
}
else if ( command == "name" )
{
llInstantMessage( userID, "Animation Name: " + (string)animationName );
}
else if ( command == "random")
{
randomAnimation ( TotalNumberOfAnimations );
}
else if ( command == "number" && partTracker < langth )
{
integer temp = llList2Integer( commands, partTracker);
if ( 1 < temp && temp < TotalNumberOfAnimations + 1 )
{
changeAnimation ( temp - 1 );
}
else
{
llInstantMessage( userID, "Sorry, '" + llList2String( commands, partTracker) + "' is not a valid number" );
}
}
else if ( command == "number" )
{
llInstantMessage( userID, "Animation Number: " + (string)(currentAnimation + 1) );
}
else if ( command == "max" )
{
llInstantMessage( userID, "Total Number /1 of Animations: " + (string)TotalNumberOfAnimations );
}
else if ( command == "key" )
{
llInstantMessage( userID, "Animation Key : " + (string)animation );
}
else if ( command == "done" )
{
if ( ( llGetPermissions() & PERMISSION_ATTACH ) == PERMISSION_ATTACH )
{
llDetachFromAvatar();
}
else
{
llInstantMessage( userID, "sorry this script dose not have permission to detach object" );
}
}
if ( command == "channel")
{
if ( partTracker < langth )//( langth > part && parts >= 3 ) || ( langth > 1 && parts < 3 ) )
{
changeListen( llList2Integer( commands, partTracker) );
llInstantMessage ( userID, "Channel set to: " + (string)channel );
}
else
{
llInstantMessage ( userID, "Channel is: " + (string)channel );
}
}
}
}


//add change to currentNumber, and then uses max to make sure the resolts is in range,
// and then returns the resolts.
integer counter ( integer currentNumber, integer change, integer max)
{
integer value = currentNumber + change;

for ( ; value < 0 ;)
{
value += max;
}
for ( ; value >= max; )
{
value -= max;
}

return value;
}


listAnimations()
{
llInstantMessage( userID, "Listing animations:") ;

integer counter = 0;
for (counter = 0; counter < TotalNumberOfAnimations; counter++)
{
llInstantMessage( userID, (string)(counter + 1) + " '" + llGetInventoryName( INVENTORY_ANIMATION, counter ) + "'");
}

llInstantMessage( userID, "Listing complet.");
}

//creates a list of all animations being played, and compares that list to the passed list
// if the passed key is on he list, the value is stoped.
stopAnimation( string stopThisAnimation )
{
if ( stopThisAnimation != "" )
{
llStopAnimation(stopThisAnimation);
}
// this code is an 'ugly hack.' It's here because of the flaw in llGetInventoryKey()
// in the case you stop NULL_KEY, it will stop all animaitons
else
{
stopAllAnimations ( userID );
}
}

//stops all animations being played.
//this function uses 1 as first number aposed to 0
//creates a list of animations, and then stops each animation in list
stopAllAnimations(key id)
{
list animations = [];
animations = llGetAnimationList(id);
integer listLagth = llGetListLength(animations);

integer counter = 0;
for(counter = 1; ( (counter > 0) && (counter <= listLagth) ); counter++)
{
llStopAnimation(llList2String(animations, counter - 1));
}
}


//my plan is to improve this function at a latter date... I'll probable incldue findInvitoryAnimation, or some thing like that.
startAnimation( string name )
{
if ( name != "" )
{
llStartAnimation( name );
}
}


//uses a loop to compare all the string names of invitory_animations with the target string
// returns -1 if fails, returns a number > -1 if true
//documented un nessisary lines out, for a very small 'speed' improvement. Bad coder bad! lol
integer findInvitoryAnimation( string startThisAnimation )
{
//integer ivitoryNumber = 0;

integer counter = 0;
for (counter = 0; counter < TotalNumberOfAnimations; counter++)
{
if ( startThisAnimation == llGetInventoryName( INVENTORY_ANIMATION, counter ) )
{
return counter; //ivitoryNumber = counter;
}
}


return -1;//return ivitoryNumber;
}


//checks target string is valid before checking animation permistion
// it then stops the current animation, updates globals to match new animation.
// and then it start the new animation.
validAnimation( string targetName )
{
integer posibleValue = findInvitoryAnimation( targetName );
if ( posibleValue != -1 )
{
changeAnimation ( posibleValue );
}
}


//sets global vales by invitory animation number
//this function should only be values that are needed for animation.
gAnimationDetails(integer invitory)
{
animationName = llGetInventoryName( INVENTORY_ANIMATION, invitory );
animation = llGetInventoryKey( animationName );
}

//function under the same logic as the controlls of a loop.
// But each incriment is triggered by another function then loop
incrimentAnimation(integer incriment)
{
changeAnimation ( counter( currentAnimation , incriment, TotalNumberOfAnimations) );
}


changeAnimation ( integer target )
{
if ( ( llGetPermissions() & PERMISSION_TRIGGER_ANIMATION ) == PERMISSION_TRIGGER_ANIMATION )
{
stopAnimation( animationName );

currentAnimation = target;
gAnimationDetails( currentAnimation );

startAnimation( animationName );
}
else
{
currentAnimation = target;
gAnimationDetails( currentAnimation );

animationStart ( userID );
}
}


// -- states & events -- //

//default state detect sitting, and on true forwards the script to state sitting
default
{
state_entry()
{
initialize();
//this line is only usefull in development // userID = NULL_KEY;
//this code makes it posible to recompile the script, while object is attach to avatar, and properly function.
if ( llGetAttached() != 0 )
{
commenceSetup( llGetOwner() );
}
}

on_rez(integer param)
{
if ( userID == NULL_KEY )
{
llInstantMessage( llGetOwner(), "script reset" );
llResetScript();
}
}

touch_start ( integer num )
{
key touchID = llDetectedKey( 0 );
if ( userID == touchID )
{
llInstantMessage( userID, "For instructions type '/" + (string)channel + " help' for instructions." );
}
}

changed(integer change)
{
//detects animation drop.
if ( change == CHANGED_INVENTORY )
{
initialize();
}
}

// assumes listen is set to only listen to avatar with control.
listen( integer channel, string name, key id, string message )
{
commandNexus(message);
}

run_time_permissions(integer perm)
{
if ( ( perm & PERMISSION_TRIGGER_ANIMATION ) == PERMISSION_TRIGGER_ANIMATION )
{
animationStart( userID );
}
//Nothing happens when attached is called. See commandNexus, detach for use
//if ( ( perm & PERMISSION_ATTACH ) == PERMISSION_ATTACH )
//{
//}
}

attach(key attached)
{
//teleported or loged in
if ( (attached != NULL_KEY) && attached == userID )
{
changeListen( channel );
}
// attach
else if (attached != NULL_KEY )
{
commenceSetup( attached );
}
// detach
else if ( attached == NULL_KEY )
{
commenceShutDown();
}
}
}


I want to stand on this and not wear it. I would also like to add these functions:

-Make the prim transparent -DONE-
-Click gives the note card with the commands or a /command to get a copy -DONE-
-I would love for the owner of the object to be able to call the commands and change the animations while the model is on the prim.

Thanks,

Sydney