Difference between revisions of "Hierarchics"

From Second Life Wiki
Jump to navigation Jump to search
(Made Ref code smarter, (now supports: Degree-Eulers and Quaternions; Ref == ZERO))
m (<lsl> tag to <source>)
 
(11 intermediate revisions by 2 users not shown)
Line 4: Line 4:




Simple Example:
'''Simple Example:'''
Create a prim and shift-drag to create a tower of 4 prims.
Create a prim and shift-drag to create a tower of 4 prims.
Name 3 of them as following, from top to bottom
Name 3 of them as following, from top to bottom
Line 15: Line 15:


Create a new script in the root object. Put the following constants as globals.
Create a new script in the root object. Put the following constants as globals.
<lsl>
<source lang="lsl2">
integer Link_HierarchicsRot    = 660333;
integer Link_HierarchicsRot    = 660333;
rotation LastQuatA;
rotation LastQuatA;
rotation LastQuatB;
rotation LastQuatB;
</lsl>
</source>


In the touch_start event, put the following.
In the touch_start event, put the following.
<lsl>
<source lang="lsl2">
     rotation QuatA = llEuler2Rot( < 0, 0, 15 > * DEG_TO_RAD ) * LastQuatA;
     rotation QuatA = llEuler2Rot( < 0, 0, 15 > * DEG_TO_RAD ) * LastQuatA;
     rotation QuatB = llEuler2Rot( < 5, 0, 0 > * DEG_TO_RAD ) * LastQuatB;
     rotation QuatB = llEuler2Rot( < 5, 0, 0 > * DEG_TO_RAD ) * LastQuatB;
Line 28: Line 28:
     LastQuatA = QuatA;
     LastQuatA = QuatA;
     LastQuatB = QuatB;
     LastQuatB = QuatB;
</lsl>
</source>


Keep touching and observe the prims following their commanded rotations.
Keep touching and observe the prims following their commanded rotations.
Line 35: Line 35:




Script Hierarchic.31.lsl
Script Hierarchic.40.lsl
<lsl>
<source lang="lsl2">
///////////////////////////////////
///////////////////////////////////
/// Hierarchy Script            //
/// Hierarchy Script            //
/// Creator:    Nexii Malthus  //   
/// Creator:    Nexii Malthus  //   
/// Revision:  v0.3.1+      //
/// Revision:  v0.4.0        //
///////////////////////////////
///////////////////////////////
// 06 May 2009              //
// Public Domain
// Available under the Creative Commons Attribution-Share Alike 3.0 License
// http://creativecommons.org/licenses/by-sa/3.0/
///////////////////////////
///////////////////////////
// Tweaked by Strife Onizuka


list hNm  = [];
list hNm  = [];
Line 51: Line 50:
list hPos = [];
list hPos = [];
list hRot = [];
list hRot = [];
list hRef = [];
//list hRef = [];


vector  lastPos;
vector  lastPos;
rotation lastRot;
rotation lastRot;
rotation mRef;


integer Link_HierarchicsRot    = 660333;
integer Link_HierarchicsRot    = 660333;   //0xA136D
integer Link_HierarchicsPos    = 660334;
integer Link_HierarchicsPos    = 660334;   //0xA136E
integer Link_HierarchicsPR      = 660335;
integer Link_HierarchicsPR      = 660335;   //0xA136F
integer Link_HierarchicsReset  = 660336;
integer Link_HierarchicsReset  = 660336;   //0xA1370
integer Link_HierarchicsReport  = 660337;
integer Link_HierarchicsReport  = 660337;   //0xA1371
integer Link_HierarchicsGet    = 660338;
integer Link_HierarchicsEdit    = 660338;   //0xA1372
integer Link_HierarchicsEdit    = 660338;
integer Link_HierarchicsGet    = 660339;   //0xA1373
 
integer Commanded = FALSE;
integer Commanded = FALSE;
integer Report = FALSE;
integer Report = FALSE;
integer EditMode = FALSE;
integer EditMode = FALSE;
 
float  CheckTimer = 0.3;
float  CheckTimer = 0.3;
 
rotation RotError = <-3.402823466E+38, -3.402823466E+38, -3.402823466E+38, -3.402823466E+38>;
 
Update(){
Update(){
     vector Pos = llList2Vector( hPos, 0 );
     vector Pos = llList2Vector( hPos, 0 );
     rotation Rot;
     rotation Rot;
   
     integer x = ( hNm != [] ) - 0; integer y; string z;
     integer x = ( hNm != [] ) - 0; integer y;
     for( y = 1; y < x; ++y ){
     for( y = 1; y < x; ++y ){
         Rot = llList2Rot( hRot, y - 1) * Rot;
         Rot = llList2Rot( hRot, y - 1) * Rot;
         Pos += llList2Vector( hPos, y ) * Rot;
         Pos += llList2Vector( hPos, y ) * Rot;
     }
     }
   
     Rot = llList2Rot( hRef,-1 ) * llList2Rot( hRot, -1 ) * Rot;
     Rot = mRef * llList2Rot( hRot, -1 ) * Rot;
     Commanded = TRUE;
     Commanded = TRUE;
     llSetPrimitiveParams([ PRIM_POSITION, Pos, PRIM_ROTATION, Rot / llGetRootRotation() ]);
     llSetPrimitiveParams([ PRIM_POSITION, Pos, PRIM_ROTATION, Rot / llGetRootRotation() ]);
}
}
 
AngleString2Rot(string in, rotation backupRot){
rotation RefAndRot(string RefString, rotation CurrentRot){
     rotation Rot = ZERO_ROTATION;
     rotation Rot = ZERO_ROTATION;
     rotation Ref = (rotation)in;
     rotation Ref = (rotation)RefString;
     if(Ref == Rot) {//it might not be a quaternion
     if(Ref == Rot){//it might not be a quaternion
         vector v = (vector)in;
         vector v = (vector)RefString;
         if(v)
         if(v){
             Ref = llEuler2Rot(v * DEG_TO_RAD);
             Ref = llEuler2Rot(v * DEG_TO_RAD);
         else { //it might not even be a vector
         } else { //it might not even be a vector
             integer index = llSubStringIndex(in, "<");
             integer index = llSubStringIndex(RefString, "<");
             if(~index) {//"<" was found, now insert "-"
             if(~index){//"<" was found, now insert "-"
                 in = llGetSubString(in, 0, index) + "-" +  
                 RefString = llGetSubString(RefString, 0, index) + "-" +  
                     llStringTrim(llDeleteSubString(in, 0, index), STRING_TRIM_HEAD);
                     llStringTrim(llDeleteSubString(RefString, 0, index), STRING_TRIM_HEAD);
                 if((string)((vector)in) == (string)v)
                 if((string)((vector)RefString) == (string)v)
                     Rot = backupRot;//Ref couldn't be parsed
                     Rot = CurrentRot;//Ref couldn't be parsed
            } else {
                Rot = CurrentRot;//Ref couldn't be parsed
             }
             }
            else
                Rot = backupRot;//Ref couldn't be parsed
         }
         }
     }
     }
     hRot += Rot;
     hRot += Rot;
     hRef += Ref;
     //hRef += Ref;
}//Strife Onizuka 2009, cc-by-sa 3.0
    return Ref;
 
}//Strife Onizuka was here
key Developer1 = "75078730-ebc8-4a80-adb9-1cfd2d95b5ca";
key Developer2 = "3cc2e3fa-2ab0-40fa-822b-6f4ebf66f575";
key Developer3 = "26eb83d3-43e6-4ce9-bb58-5a08c49494a1";
key NewOwner = NULL_KEY;
integer OwnerChanged = FALSE;
integer Link_Delete        = 1337;
 
integer CheckValidity(){
    if( ((llGetOwner() != Developer1)||(llGetOwner() != Developer2)||(llGetOwner() != Developer3)) ){
        if( ( llGetOwner() != NewOwner ) && !OwnerChanged ){
            OwnerChanged = TRUE;
            NewOwner = llGetOwner();
        } else if( llGetOwner() != NewOwner ){
            return FALSE;
        }
    }
   
    integer x;integer y = llGetInventoryNumber(INVENTORY_SCRIPT);key Creator;
    for(x = 0;x < y;++x){
        Creator = llGetInventoryCreator(llGetInventoryName(INVENTORY_SCRIPT,x));
        if(!((Creator != Developer1)
          ||(Creator != Developer2)
          ||(Creator != Developer3))) return FALSE;
    }
    Creator = llGetCreator();
    return ((Creator != Developer1)||(Creator != Developer2)||(Creator != Developer3));
}
 
Die(){
    if(llGetAttached()){
        llMessageLinked(LINK_ALL_OTHERS,Link_Delete,"","");
        llRemoveInventory(llGetScriptName());
    } else llDie();
}
 
default{
default{
    on_rez( integer p ){ if( !CheckValidity() ) Die(); }
   
    changed( integer change ){
        if( change & CHANGED_INVENTORY ){
            if( !CheckValidity() ) Die();
        }
    }
   
     state_entry(){
     state_entry(){
         vector rPos; rotation rRot;
         vector rPos; rotation rRot;
Line 163: Line 119:
         string a = llGetObjectName();
         string a = llGetObjectName();
         list b = llParseString2List( a, ["."], []);
         list b = llParseString2List( a, ["."], []);
       
         integer y;integer z = (b!=[])-1;string txt;
         integer y;integer z = (b!=[]) - 1;string txt;
         for(y = 0;y < z;++y){
         for(y = 0;y < z;++y){
             integer x = llGetNumberOfPrims();
             integer x = llGetNumberOfPrims();
Line 171: Line 127:
                             [OBJECT_NAME,OBJECT_DESC,OBJECT_POS,OBJECT_ROT]);
                             [OBJECT_NAME,OBJECT_DESC,OBJECT_POS,OBJECT_ROT]);
                 list d = llParseString2List( llList2String(c,0), ["."], []);
                 list d = llParseString2List( llList2String(c,0), ["."], []);
                 if( (d!=[])-1 <= y )
                 if( (d!=[]) - 1 <= y )
                 {
                 {
                    string cNm = llList2String(d,(d!=[])-1);
                     if(llList2String(d,y) == llList2String(b,y)){
                     if(llList2String(d,y) == llList2String(b,y)){
                         txt += ( llList2String(d,y) +", " );
                         txt += ( llList2String(d,y) +", " );
Line 179: Line 134:
                         hLnk += [x];
                         hLnk += [x];
                         hPos += (llList2Vector(c,2)-rPos)/rRot;
                         hPos += (llList2Vector(c,2)-rPos)/rRot;
                         AngleString2Rot(llList2String(c,1), llList2Rot( c,3 )/rRot);
                         RefAndRot(llList2String(c,1), llList2Rot( c,3 )/rRot);
                     }
                     }
                 }
                 }
Line 188: Line 143:
         if(g > 1){
         if(g > 1){
             for(f = 1;f < g;++f){
             for(f = 1;f < g;++f){
                 hPos = llListReplaceList(hPos, [llList2Vector(temp,f)-llList2Vector(temp,f-1)], f, f);
                 hPos = llListReplaceList(hPos, [llList2Vector(temp,f)-llList2Vector(temp,f - 1)], f, f);
             }
             }
         }
         }
         hNm  += llGetObjectName();
         hNm  += llGetObjectName();
         if(g) hPos += llGetLocalPos()-llList2Vector(temp,(hPos!=[])-1);
         if(g) hPos += llGetLocalPos()-llList2Vector(temp,(hPos!=[]) - 1);
         else  hPos += llGetLocalPos();
         else  hPos += llGetLocalPos();
         AngleString2Rot(llGetObjectDesc(), llList2Rot( c,3 )/rRot);
         mRef = RefAndRot(llGetObjectDesc(), llGetLocalRot());
         state Main;
         state Main;
     }
     }
}
}
 
state Main{
state Main{
    on_rez( integer p ){ if( !CheckValidity() ) Die(); }
   
    changed( integer change ){
        if( change & CHANGED_INVENTORY ){
            if( !CheckValidity() ) Die();
        }
    }
   
     state_entry(){
     state_entry(){
         integer x;string txt;
         integer x;string txt;
Line 215: Line 162:
         if( EditMode || Report ) llSetTimerEvent( CheckTimer );
         if( EditMode || Report ) llSetTimerEvent( CheckTimer );
     }
     }
   
     link_message(integer sn,integer n,string s,key k){
     link_message(integer sn,integer n,string s,key k){
         if( n == Link_HierarchicsRot ){
         if( n == Link_HierarchicsRot ){
Line 225: Line 172:
             for(x = 0;x < si;++x){
             for(x = 0;x < si;++x){
                 if( llList2String(kl,x) == llGetObjectName() ){
                 if( llList2String(kl,x) == llGetObjectName() ){
                     integer y = (hPos!=[])-1;
                     integer y = (hPos!=[]) - 1;
                     hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,x)], y, y);
                     hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,x)], y, y);
                     Update = TRUE;
                     Update = TRUE;
                 } else {
                 } else {
                     integer Find = llListFindList( hNm, [llList2String(kl,x)] );
                     integer Find = llListFindList( hNm, [llList2String(kl,x)] );
                     if( Find != -1 ){
                     if( ~Find ){
                         hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,x)], Find, Find);
                         hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,x)], Find, Find);
                         Update = TRUE;
                         Update = TRUE;
Line 237: Line 184:
             }
             }
             if(Update) Update();
             if(Update) Update();
           
         } else if( n == Link_HierarchicsPos ){
         } else if( n == Link_HierarchicsPos ){
             integer Update;
             integer Update;
Line 246: Line 192:
             for(x = 0;x < si;++x){
             for(x = 0;x < si;++x){
                 if( llList2String(kl,x) == llGetObjectName() ){
                 if( llList2String(kl,x) == llGetObjectName() ){
                     integer y = (hPos!=[])-1;
                     integer y = (hPos!=[]) - 1;
                     hPos = llListReplaceList( hPos, [(vector)llList2String(sl,x)], y, y);
                     hPos = llListReplaceList( hPos, [(vector)llList2String(sl,x)], y, y);
                     Update = TRUE;
                     Update = TRUE;
                 } else {
                 } else {
                     integer Find = llListFindList( hNm, [llList2String(kl,x)] );
                     integer Find = llListFindList( hNm, [llList2String(kl,x)] );
                     if( Find != -1 ){
                     if( ~Find ){
                         hPos = llListReplaceList( hPos, [(vector)llList2String(sl,x)], Find, Find);
                         hPos = llListReplaceList( hPos, [(vector)llList2String(sl,x)], Find, Find);
                         Update = TRUE;
                         Update = TRUE;
Line 258: Line 204:
             }
             }
             if(Update) Update();
             if(Update) Update();
           
         } else if( n == Link_HierarchicsPR ){
         } else if( n == Link_HierarchicsPR ){
             integer Update;
             integer Update;
Line 267: Line 212:
             for(x = 0;x < ki;++x){
             for(x = 0;x < ki;++x){
                 if( llList2String(kl,x) == llGetObjectName() ){
                 if( llList2String(kl,x) == llGetObjectName() ){
                     integer y = (hPos!=[])-1;
                     integer y = (hPos!=[]) - 1;
                     hPos = llListReplaceList( hPos, [(vector)llList2String(sl,z)], y, y);
                     hPos = llListReplaceList( hPos, [(vector)llList2String(sl,z)], y, y);
                     hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,z+1)], y, y);
                     hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,z+1)], y, y);
Line 273: Line 218:
                 } else {
                 } else {
                     integer Find = llListFindList( hNm, [llList2String(kl,x)] );
                     integer Find = llListFindList( hNm, [llList2String(kl,x)] );
                     if( Find != -1 ){
                     if( ~Find ){
                         hPos = llListReplaceList( hPos, [(vector)llList2String(sl,z)], Find, Find);
                         hPos = llListReplaceList( hPos, [(vector)llList2String(sl,z)], Find, Find);
                         hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,z+1)], Find, Find);
                         hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,z+1)], Find, Find);
Line 305: Line 250:
         } else if( n == Link_HierarchicsGet ){
         } else if( n == Link_HierarchicsGet ){
             if( s == "all" ){
             if( s == "all" ){
                 //vector cPos; rotation cRot;
                 llMessageLinked( LINK_ROOT, Link_HierarchicsGet,
                //llMessageLinked( LINK_ROOT, Link_HierarchicsGet,
                    llDumpList2String([llGetLocalPos(),llGetLocalRot()],";"),
                //    llDumpList2String([llGetLocalPos(),llGetLocalRot()],";"),
                    llDumpList2String([],";") );
                //    llDumpList2String([],";") );
                //               
             } else {
             } else {
                //list sl = llParseString2List(s,[";"],[]);
                list sl = llParseString2List(s,[";"],[]);
                //if( ~llListFindList( sl, [llGetObjectName()]) )
                if( ~llListFindList( sl, [llGetObjectName()]) )
                //    Report = (integer)((string)k);
                    llMessageLinked( LINK_ROOT, Link_HierarchicsGet,
                        llDumpList2String([llGetLocalPos(),llGetLocalRot()],";"),
                        llDumpList2String([],";") );
             }
             }
        } else if( n == Link_Delete ){
            Die();
         }
         }
     }
     }
   
     timer(){
     timer(){
         integer ChangedRot = ( lastRot != llGetLocalRot() );
         integer ChangedRot = ( lastRot != llGetLocalRot() );
Line 329: Line 272:
                 return;
                 return;
             }
             }
           
             if( Report ){
             if( Report ){
                 llMessageLinked( LINK_ROOT, Link_HierarchicsReport,
                 llMessageLinked( LINK_ROOT, Link_HierarchicsReport,
                     (string)llGetLocalPos(), (string)llGetLocalRot() );
                     (string)llGetLocalPos(), (string)llGetLocalRot() );
               
             }
             }
             if( EditMode ){
             if( EditMode ){
                 if( ChangedRot ){
                 if( ChangedRot && ChangedPos ){
                    vector newPos = (llGetLocalPos() - lastPos);
                    if( (hRot!=[]) > 1 ) newPos /= llList2Rot( hRot, -2 );
                    newPos = llList2Vector(hPos,-1) + newPos;
                    rotation diffRot = (llGetLocalRot() / lastRot) * llList2Rot(hRot,-1);
                    hPos = llListReplaceList(hPos,[newPos],-1,-1);
                    hRot = llListReplaceList(hRot,[diffRot],-1,-1);
                    llMessageLinked( LINK_ALL_OTHERS, Link_HierarchicsPR,
                            (string)newPos+";"+(string)diffRot, llGetObjectName() );
                } else if( ChangedRot ){
                     rotation diffRot = (llGetLocalRot() / lastRot) * llList2Rot(hRot,-1);
                     rotation diffRot = (llGetLocalRot() / lastRot) * llList2Rot(hRot,-1);
                     hRot = llListReplaceList(hRot,[diffRot],-1,-1);
                     hRot = llListReplaceList(hRot,[diffRot],-1,-1);
Line 348: Line 300:
                     llMessageLinked( LINK_ALL_OTHERS, Link_HierarchicsPos,
                     llMessageLinked( LINK_ALL_OTHERS, Link_HierarchicsPos,
                             (string)newPos, llGetObjectName() );
                             (string)newPos, llGetObjectName() );
                } else if( ChangedRot && ChangedPos ){
                    vector newPos = (llGetLocalPos() - lastPos);
                    if( (hRot!=[]) > 1 ) newPos /= llList2Rot( hRot, -2 );
                    newPos = llList2Vector(hPos,-1) + newPos;
                    rotation diffRot = llList2Rot(hRot,-1) / lastRot;
                    hPos = llListReplaceList(hPos,[newPos],-1,-1);
                    hRot = llListReplaceList(hRot,[diffRot],-1,-1);
                    llMessageLinked( LINK_ALL_OTHERS, Link_HierarchicsPR,
                            (string)newPos+";"+(string)diffRot, llGetObjectName() );
                 }
                 }
             }
             }
Line 363: Line 306:
     }
     }
}
}
</lsl>
</source>

Latest revision as of 21:32, 24 January 2015

This is a script that has been painstakingly crafted by Nexii Malthus to create a highly efficient and advanced system of controlling a large linkset of prims in a parametric fashion of a mechanical structure or robotic limb. I am giving out this script to the people now, to me it is a huge contribution to the community as I have spent many weeks designing the plans and debugging the script as well as studying and researching efficient script design. This can be used in your product under the condition you put credit in a visible location to the consumer that you used my work or derived from my work.


Simple Example: Create a prim and shift-drag to create a tower of 4 prims. Name 3 of them as following, from top to bottom

A.B.C
A.B
A

Link them all up so the 4th unnamed prim is the root object, which should be the last prim on the bottom as a base.

Drop the Hierarchics script into each of the named prims.

Create a new script in the root object. Put the following constants as globals.

integer Link_HierarchicsRot     = 660333;
rotation LastQuatA;
rotation LastQuatB;

In the touch_start event, put the following.

    rotation QuatA = llEuler2Rot( < 0, 0, 15 > * DEG_TO_RAD ) * LastQuatA;
    rotation QuatB = llEuler2Rot( < 5, 0, 0 > * DEG_TO_RAD ) * LastQuatB;
    llMessageLinked(LINK_SET, Link_HierarchicsRot, (string)QuatA+";"+(string)QuatB, "A;A.B" );
    LastQuatA = QuatA;
    LastQuatB = QuatB;

Keep touching and observe the prims following their commanded rotations.



Script Hierarchic.40.lsl

///////////////////////////////////
/// Hierarchy Script            //
/// Creator:    Nexii Malthus  //  
/// Revision:   v0.4.0        //
///////////////////////////////
// Public Domain
///////////////////////////
// Tweaked by Strife Onizuka

list hNm  = [];
list hLnk = [];
list hPos = [];
list hRot = [];
//list hRef = [];

vector   lastPos;
rotation lastRot;
rotation mRef;

integer Link_HierarchicsRot     = 660333;   //0xA136D
integer Link_HierarchicsPos     = 660334;   //0xA136E
integer Link_HierarchicsPR      = 660335;   //0xA136F
integer Link_HierarchicsReset   = 660336;   //0xA1370
integer Link_HierarchicsReport  = 660337;   //0xA1371
integer Link_HierarchicsEdit    = 660338;   //0xA1372
integer Link_HierarchicsGet     = 660339;   //0xA1373
 
integer Commanded = FALSE;
integer Report = FALSE;
integer EditMode = FALSE;
 
float   CheckTimer = 0.3;
 
Update(){
    vector Pos = llList2Vector( hPos, 0 );
    rotation Rot;
 
    integer x = ( hNm != [] ) - 0; integer y;
    for( y = 1; y < x; ++y ){
        Rot = llList2Rot( hRot, y - 1) * Rot;
        Pos += llList2Vector( hPos, y ) * Rot;
    }
 
    Rot = mRef * llList2Rot( hRot, -1 ) * Rot;
    Commanded = TRUE;
    llSetPrimitiveParams([ PRIM_POSITION, Pos, PRIM_ROTATION, Rot / llGetRootRotation() ]);
}
 
rotation RefAndRot(string RefString, rotation CurrentRot){
    rotation Rot = ZERO_ROTATION;
    rotation Ref = (rotation)RefString;
    if(Ref == Rot){//it might not be a quaternion
        vector v = (vector)RefString;
        if(v){
            Ref = llEuler2Rot(v * DEG_TO_RAD);
        } else { //it might not even be a vector
            integer index = llSubStringIndex(RefString, "<");
            if(~index){//"<" was found, now insert "-"
                RefString = llGetSubString(RefString, 0, index) + "-" + 
                    llStringTrim(llDeleteSubString(RefString, 0, index), STRING_TRIM_HEAD);
                if((string)((vector)RefString) == (string)v)
                    Rot = CurrentRot;//Ref couldn't be parsed
            } else {
                Rot = CurrentRot;//Ref couldn't be parsed
            }
        }
    }
    hRot += Rot;
    //hRef += Ref;
    return Ref;
}//Strife Onizuka was here
 
default{
    state_entry(){
        vector rPos; rotation rRot;
        if( llGetLinkNumber() == LINK_ROOT ){
            rPos = llGetPos(); rRot = llGetRot();
        } else {
            rPos = llGetRootPosition(); rRot = llGetRootRotation();
        }
        string a = llGetObjectName();
        list b = llParseString2List( a, ["."], []);
 
        integer y;integer z = (b!=[]) - 1;string txt;
        for(y = 0;y < z;++y){
            integer x = llGetNumberOfPrims();
            while(x){
                list c = llGetObjectDetails(llGetLinkKey(x),
                            [OBJECT_NAME,OBJECT_DESC,OBJECT_POS,OBJECT_ROT]);
                list d = llParseString2List( llList2String(c,0), ["."], []);
                if( (d!=[]) - 1 <= y )
                {
                    if(llList2String(d,y) == llList2String(b,y)){
                        txt += ( llList2String(d,y) +", " );
                        hNm  += llList2List(c,0,0);
                        hLnk += [x];
                        hPos += (llList2Vector(c,2)-rPos)/rRot;
                        RefAndRot(llList2String(c,1), llList2Rot( c,3 )/rRot);
                    }
                }
                --x;
            }
        }
        integer f;integer g = (hPos!=[]);list temp = hPos;
        if(g > 1){
            for(f = 1;f < g;++f){
                hPos = llListReplaceList(hPos, [llList2Vector(temp,f)-llList2Vector(temp,f - 1)], f, f);
            }
        }
        hNm  += llGetObjectName();
        if(g) hPos += llGetLocalPos()-llList2Vector(temp,(hPos!=[]) - 1);
        else  hPos += llGetLocalPos();
        mRef = RefAndRot(llGetObjectDesc(), llGetLocalRot());
        state Main;
    }
}
 
state Main{
    state_entry(){
        integer x;string txt;
        for(x = 0;x < (hNm!=[]);++x)
            txt += ( llList2String( hNm, x ) + ", " );
        lastPos = llGetLocalPos(); lastRot = llGetLocalRot();
        if( EditMode || Report ) llSetTimerEvent( CheckTimer );
    }
 
    link_message(integer sn,integer n,string s,key k){
        if( n == Link_HierarchicsRot ){
            integer Update;
            list sl = llParseString2List(s,[";"],[]);// Values
            list kl = llParseString2List(k,[";"],[]);// Keys
            integer si = (sl!=[]);
            integer x;
            for(x = 0;x < si;++x){
                if( llList2String(kl,x) == llGetObjectName() ){
                    integer y = (hPos!=[]) - 1;
                    hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,x)], y, y);
                    Update = TRUE;
                } else {
                    integer Find = llListFindList( hNm, [llList2String(kl,x)] );
                    if( ~Find ){
                        hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,x)], Find, Find);
                        Update = TRUE;
                    }
                }
            }
            if(Update) Update();
        } else if( n == Link_HierarchicsPos ){
            integer Update;
            list sl = llParseString2List(s,[";"],[]);// Values
            list kl = llParseString2List(k,[";"],[]);// Keys
            integer si = (sl!=[]);
            integer x;
            for(x = 0;x < si;++x){
                if( llList2String(kl,x) == llGetObjectName() ){
                    integer y = (hPos!=[]) - 1;
                    hPos = llListReplaceList( hPos, [(vector)llList2String(sl,x)], y, y);
                    Update = TRUE;
                } else {
                    integer Find = llListFindList( hNm, [llList2String(kl,x)] );
                    if( ~Find ){
                        hPos = llListReplaceList( hPos, [(vector)llList2String(sl,x)], Find, Find);
                        Update = TRUE;
                    }
                }
            }
            if(Update) Update();
        } else if( n == Link_HierarchicsPR ){
            integer Update;
            list sl = llParseString2List(s,[";"],[]);// Values
            list kl = llParseString2List(k,[";"],[]);// Keys
            integer ki = (kl!=[]);
            integer x; integer z;
            for(x = 0;x < ki;++x){
                if( llList2String(kl,x) == llGetObjectName() ){
                    integer y = (hPos!=[]) - 1;
                    hPos = llListReplaceList( hPos, [(vector)llList2String(sl,z)], y, y);
                    hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,z+1)], y, y);
                    Update = TRUE;
                } else {
                    integer Find = llListFindList( hNm, [llList2String(kl,x)] );
                    if( ~Find ){
                        hPos = llListReplaceList( hPos, [(vector)llList2String(sl,z)], Find, Find);
                        hRot = llListReplaceList( hRot, [(rotation)llList2String(sl,z+1)], Find, Find);
                        Update = TRUE;
                    }
                }
                z += 2;
            }
            if(Update) Update();
        } else if( n == Link_HierarchicsEdit ){
            if( s == "all" ){
                EditMode = (integer)((string)k);
            } else {
                list sl = llParseString2List(s,[";"],[]);
                if( ~llListFindList( sl, [llGetObjectName()]) )
                    EditMode = (integer)((string)k);
            }
            if( EditMode ) llSetTimerEvent( CheckTimer );
            else if( !Report ) llSetTimerEvent( FALSE );
        } else if( n == Link_HierarchicsReset ){
            llResetScript();
        } else if( n == Link_HierarchicsReport ){
            if( s == "all" ) Report = (integer)((string)k);
            else {
                list sl = llParseString2List(s,[";"],[]);
                if( ~llListFindList( sl, [llGetObjectName()]) )
                    Report = (integer)((string)k);
            }
            if( Report ) llSetTimerEvent( CheckTimer );
            else if( !Report && !EditMode ) llSetTimerEvent( FALSE );
        } else if( n == Link_HierarchicsGet ){
            if( s == "all" ){
                llMessageLinked( LINK_ROOT, Link_HierarchicsGet,
                    llDumpList2String([llGetLocalPos(),llGetLocalRot()],";"),
                    llDumpList2String([],";") );
            } else {
                 list sl = llParseString2List(s,[";"],[]);
                 if( ~llListFindList( sl, [llGetObjectName()]) )
                    llMessageLinked( LINK_ROOT, Link_HierarchicsGet,
                        llDumpList2String([llGetLocalPos(),llGetLocalRot()],";"),
                        llDumpList2String([],";") );
            }
        }
    }
 
    timer(){
        integer ChangedRot = ( lastRot != llGetLocalRot() );
        integer ChangedPos = ( lastPos != llGetLocalPos() );
        if( ChangedRot || ChangedPos ){
            if( Commanded ){
                Commanded = FALSE;
                lastPos = llGetLocalPos(); lastRot = llGetLocalRot();
                return;
            }
 
            if( Report ){
                llMessageLinked( LINK_ROOT, Link_HierarchicsReport,
                    (string)llGetLocalPos(), (string)llGetLocalRot() );
 
            }
            if( EditMode ){
                if( ChangedRot && ChangedPos ){
                    vector newPos = (llGetLocalPos() - lastPos);
                    if( (hRot!=[]) > 1 ) newPos /= llList2Rot( hRot, -2 );
                    newPos = llList2Vector(hPos,-1) + newPos;
                    rotation diffRot = (llGetLocalRot() / lastRot) * llList2Rot(hRot,-1);
                    hPos = llListReplaceList(hPos,[newPos],-1,-1);
                    hRot = llListReplaceList(hRot,[diffRot],-1,-1);
                    llMessageLinked( LINK_ALL_OTHERS, Link_HierarchicsPR,
                            (string)newPos+";"+(string)diffRot, llGetObjectName() );
                } else if( ChangedRot ){
                    rotation diffRot = (llGetLocalRot() / lastRot) * llList2Rot(hRot,-1);
                    hRot = llListReplaceList(hRot,[diffRot],-1,-1);
                    llMessageLinked( LINK_ALL_OTHERS, Link_HierarchicsRot,
                            (string)diffRot, llGetObjectName() );
                } else if( ChangedPos ){
                    vector newPos = (llGetLocalPos() - lastPos);
                    if( (hRot!=[]) > 1 ) newPos /= llList2Rot( hRot, -2 );
                    newPos = llList2Vector(hPos,-1) + newPos;
                    hPos = llListReplaceList(hPos,[newPos],-1,-1);
                    llMessageLinked( LINK_ALL_OTHERS, Link_HierarchicsPos,
                            (string)newPos, llGetObjectName() );
                }
            }
            lastPos = llGetLocalPos(); lastRot = llGetLocalRot();
        }
    }
}