2017-11-06

Flexible linkset

Yesterday afternoon Mistress had reason to play around with flexible path values for a linkset. In doing so she mentioned that it was a bit of a pain to have to set the parameters individually for each item in the linkset. Never having really played with this before, I was a little surprised to find that it's a prim parameter that you can't set on more than one prim at once; especially given it's one you can set on more than one prim at once from a script.

So, for fun, I knocked up a little tool that would let her experiment quickly and easily. Z&A Flex Linkset was born:

//////////////////////////////////////////////////////////////////////
// Z&A Flex Linkset
// By Antony Fairport
//
// Z&A Flex Linkset - Apply flexible path params to a whole linkset.
//
// Revision history:
// ------------------------------------------------------------
//
// 2017-11-05
// Initial revision.
//////////////////////////////////////////////////////////////////////
// Globals.
integer g_iSoftness = 2;
float g_nGravity = 0.300;
float g_nFriction = 2.000;
float g_nWind = 0.000;
float g_nTension = 1.000;
vector g_vForce;
//////////////////////////////////////////////////////////////////////
// Refresh the flexible path for the whole linkset.
RefreshFlexi()
{
llSetLinkPrimitiveParamsFast( LINK_SET, [
PRIM_FLEXIBLE, TRUE, g_iSoftness, g_nGravity, g_nFriction, g_nWind, g_nTension, g_vForce
] );
}
//////////////////////////////////////////////////////////////////////
// Get a parameter, with error checking and reporting.
float GetParam( list lCmd, string sName, float nCurrent, float nMin, float nMax )
{
float n = (float) llList2String( lCmd, 2 );
if ( ( n >= nMin ) && ( n <= nMax ) )
{
nCurrent = n;
}
else
{
llSay( 0, "Invalid value. " + sName + " should be in the range " +
( (string) nMin ) + " to " + ( (string) nMax ) + " inclusive." );
}
return nCurrent;
}
//////////////////////////////////////////////////////////////////////
// Default state.
default
{
//////////////////////////////////////////////////////////////////
// State entry.
state_entry()
{
// Set the initial state.
RefreshFlexi();
// Start listening to the owner.
llListen( 0, "", llGetOwner(), "" );
}
//////////////////////////////////////////////////////////////////
// Handle a listen.
listen( integer channel, string name, key id, string message )
{
if ( ( channel == 0 ) && ( id == llGetOwner() ) )
{
// Break up what was said.
list lCmd = llParseString2List( message, [ " " ], [] );
string sPrefix = llList2String( lCmd, 0 );
// Is it a flex command?
if ( sPrefix == "flex" )
{
// It is. Pull out the next part.
string sCmd = llList2String( lCmd, 1 );
if ( sCmd == "soft" )
{
integer i = (integer) llList2String( lCmd, 2 );
// Does it look like a valid softness value?
if ( ( i >= 0 ) && ( i <= 3 ) )
{
g_iSoftness = i;
}
else
{
llSay( 0, "Invalid value. Softness should be in the range 0 to 3 inclusive." );
}
}
else if ( sCmd == "grav" )
{
g_nGravity = GetParam( lCmd, "Gravity", g_nGravity, -10.0, 10.0 );
}
else if ( sCmd == "drag" )
{
g_nFriction = GetParam( lCmd, "Drag", g_nFriction, 0.0, 10.0 );
}
else if ( sCmd == "wind" )
{
g_nWind = GetParam( lCmd, "Wind", g_nWind, 0.0, 10.0 );
}
else if ( sCmd == "ten" )
{
g_nTension = GetParam( lCmd, "Tension", g_nTension, 0.0, 10.0 );
}
else if ( sCmd == "fx" )
{
g_vForce.x = GetParam( lCmd, "Force (X)", g_vForce.x, -10.0, 10.0 );
}
else if ( sCmd == "fy" )
{
g_vForce.y = GetParam( lCmd, "Force (Y)", g_vForce.y, -10.0, 10.0 );
}
else if ( sCmd == "fz" )
{
g_vForce.z = GetParam( lCmd, "Force (Z)", g_vForce.z, -10.0, 10.0 );
}
else if ( sCmd == "show" )
{
llSay( 0, "Current flexible path parameters:\n" +
"Softness: " + ( (string) g_iSoftness ) + "\n" +
"Gravity.: " + ( (string) g_nGravity ) + "\n" +
"Drag....: " + ( (string) g_nFriction ) + "\n" +
"Wind....: " + ( (string) g_nWind ) + "\n" +
"Force X.: " + ( (string) g_vForce.x ) + "\n" +
"Force Y.: " + ( (string) g_vForce.y ) + "\n" +
"Force Z.: " + ( (string) g_vForce.z ) + "\n" );
}
else if ( sCmd == "reset" )
{
llResetScript();
}
else if ( sCmd == "done" )
{
llSay( 0, "Sorry you don't want me any more. Enjoy your flexibility. :-(" );
llRemoveInventory( llGetScriptName() );
}
else if ( sCmd == "help" )
{
llSay( 0, "flex < soft | grav | drag | wind | ten | fx | fy | fz > <value>" );
llSay( 0, "flex show" );
llSay( 0, "flex reset" );
llSay( 0, "flex done" );
}
// Finally, refresh.
RefreshFlexi();
}
}
}
}
The script is designed so that it listens to the object owner in local chat, and accepts commands for setting the different parameters. When a parameter is given it's applied to the whole linkset. Commands include:

flex soft <value>
flex grav <value>
flex drag <value>
flex wind <value>
flex ten <value>
flex fx <value>
flex fy <value>
flex fz <value>

As well as commands for setting the flexible path parameters, there are also commands for controlling the script itself. To see the current parameters:

flex show

To reset the parameters to their default:

flex reset

And when you're done with the script and you want it to remove itself from the object:

flex done

And that's it. It was fun to knock together, Mistress had fun playing around with it, hopefully it's of some use to someone else too.

No comments:

Post a Comment