Difference between revisions of "Primset script"

From Second Life Wiki
Jump to navigation Jump to search
m (added wiki links to the other parts of this system, tidied header only for appearance, not content)
 
(6 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{
See [[Primset]] and [[PrimControl HUD]] for explanation and the other parts of this system.
//primset+++ - Includes support for llGet/SetLinkPrimitiveParams, linkset resize, llLinkParticleSystem, and
//llSetKeyframeMotion
// Used by the primcontrol HUD.


//This function typecasts a list of strings, into the types they appear to be.  
<lsl>
//Extremely useful for feeding user data into llSetPrimitiveParams
//Primset+++
//It takes a list as an input, and returns that list, with all elements correctly typecast, as output
    // Includes support for
//Written by Fractured Crystal, 27 Jan 2010, Commissioned by WarKirby Magojiro, this function is Public Domain
    // llGet/SetLinkPrimitiveParams, linkset resize, llLinkParticleSystem, and llSetKeyframeMotion
//Modified by Rufus Darkfold to keep strings like <foo> instead of discarding them entirely from the output
    // Used by the PrimControl HUD
list list_cast(list in)
{
    // This function typecasts a list of strings into the types they appear to be.  
    list out;
    // Useful for feeding user data into llSetPrimitiveParams
    integer i;
    // Takes list input, and returns that list - with all elements correctly typecast - as output
    integer l= llGetListLength(in);
 
    for (i=0; i < l; i++)
    // Written by Fractured Crystal, 27 Jan 2010,  
    // Commissioned by WarKirby Magojiro, this function is Public Domain
    // Modified by Rufus Darkfold to keep strings like <foo> instead of discarding them from the output list
 
list_cast(list in)
     {
     {
         string d= llStringTrim(llList2String(in,i),STRING_TRIM);
         list out;
         if (d == "") out += "";
        integer i;
        else
        integer l= llGetListLength(in);
         for (i=0; i < l; i++)
         {
         {
             if (llGetSubString(d,0,0) == "<")
             string d= llStringTrim(llList2String(in,i),STRING_TRIM);
            if (d == "") out += "";
            else
             {
             {
                 if (llGetSubString(d,-1,-1) == ">")
                 if (llGetSubString(d,0,0) == "<")
                 {
                 {
                     list s = llParseString2List(d,[","],[]);
                     if (llGetSubString(d,-1,-1) == ">")
                    integer sl= llGetListLength(s);
                    {
                    if (sl == 3) {
                        list s = llParseString2List(d,[","],[]);
                        out += (vector)d;
                        integer sl= llGetListLength(s);
                    } else if(sl == 4) {
                        if (sl == 3) {
                        out += (rotation)d;
                            out += (vector)d;
                        } else if(sl == 4) {
                            out += (rotation)d;
                        } else
                            out += [d];
                     } else
                     } else
                         out += [d];
                         out += [d];
                 } else
                 } else if (~llSubStringIndex(d,".")) {
                    out += [d];
                    out += (float)d;
            } else if (~llSubStringIndex(d,".")) {
                } else {
                out += (float)d;
                    integer lold = (integer)d;
            } else {
                    if ((string)lold == d) out += lold;
                integer lold = (integer)d;
                    else
                if ((string)lold == d) out += lold;
                    {
                else
                        key kold = (key)d;
                {
                        if (kold) out += [kold];
                    key kold = (key)d;
                        else out += [d];
                    if (kold) out += [kold];
                    }
                    else out += [d];
                 }
                 }
             }
             }
         }
         }
        //for (i = 0; i< llGetListLength(out); i++){
        //    llOwnerSay("Element " + (string)i + " type is " + (string)llGetListEntryType(out, i)
        //                + " value is «" + llList2String(out,i) + "»");
        //}
        return out;
     }
     }
   
    //for (i = 0; i< llGetListLength(out); i++){
    //    llOwnerSay("Element " + (string)i + " type is " + (string)llGetListEntryType(out, i)
    //                + " value is «" + llList2String(out,i) + "»");
    //}
   
   
     return out;
     integer dimTest( vector vr )
}
 
integer dimTest( vector vr )
{
    return !( vr.x<0.01 || vr.y<0.01 || vr.z<0.01 || vr.x>64.0 || vr.y>64.0 || vr.z>64.0 );
}
 
resize_linkset( vector scal )
{
    integer primindx;
    list primP;
    vector s = llGetScale();
    integer validDim = dimTest( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );
    for ( primindx = 2; primindx <= llGetNumberOfPrims(); primindx++ )
     {
     {
         primP = llGetLinkPrimitiveParams( primindx, [PRIM_SIZE]);
         return !( vr.x<0.01 || vr.y<0.01 || vr.z<0.01 || vr.x>64.0 || vr.y>64.0 || vr.z>64.0 );
        s = llList2Vector( primP, 0 );
        validDim = validDim && dimTest( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );
     }
     }
 
     if ( validDim )
     resize_linkset( vector scal )
     {
     {
         s = llGetScale();
         integer primindx;
         llSetScale( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );  
        list primP;
        vector s = llGetScale();
         integer validDim = dimTest( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );
         for ( primindx = 2; primindx <= llGetNumberOfPrims(); primindx++ )
         for ( primindx = 2; primindx <= llGetNumberOfPrims(); primindx++ )
         {
         {
             primP = llGetLinkPrimitiveParams( primindx, [PRIM_SIZE, PRIM_POSITION]);
             primP = llGetLinkPrimitiveParams( primindx, [PRIM_SIZE]);
             vector primScale = llList2Vector( primP, 0 );
             s = llList2Vector( primP, 0 );
             primScale = <primScale.x*scal.x, primScale.y*scal.y, primScale.z*scal.z>;
             validDim = validDim && dimTest( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );
            vector primPos = llList2Vector( primP, 1 ) - llGetPos();
            primPos = <primPos.x*scal.x, primPos.y*scal.y, primPos.z*scal.z>;
            llSetLinkPrimitiveParamsFast( primindx, [PRIM_SIZE, primScale, PRIM_POSITION, primPos/llGetRootRotation()]);
         }
         }
        if ( validDim )
        {
            s = llGetScale();
            llSetScale( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );
            for ( primindx = 2; primindx <= llGetNumberOfPrims(); primindx++ )
            {
                primP = llGetLinkPrimitiveParams( primindx, [PRIM_SIZE, PRIM_POSITION]);
                vector primScale = llList2Vector( primP, 0 );
                primScale = <primScale.x*scal.x, primScale.y*scal.y, primScale.z*scal.z>;
                vector primPos = llList2Vector( primP, 1 ) - llGetPos();
                primPos = <primPos.x*scal.x, primPos.y*scal.y, primPos.z*scal.z>;
                llSetLinkPrimitiveParamsFast( primindx, [PRIM_SIZE, primScale, PRIM_POSITION, primPos/llGetRootRotation()]);
            }
        }
        else llOwnerSay("No resize! Out of limit sizes are not accepted");
     }
     }
     else llOwnerSay("No resize! Out of limit sizes are not accepted");
}
     debugout(string msg)
 
    {
debugout(string msg)
      llOwnerSay(msg);
{
  llOwnerSay(msg);
}
 
integer outchan =0;
reply(string msg)
{
    llRegionSayTo(llGetOwner(), outchan, msg);
    if (outchan) {
        debugout(msg);
     }
     }
}
 
    integer outchan =0;
integer channel = 884;
     reply(string msg)
 
list subset;
integer hlis;
float timeout = 300; // stop listening after 5 minutes of inactivity
vector lastpos;
rotation lastrot;
 
default
{
     timer()
     {
     {
         if (hlis){
         llRegionSayTo(llGetOwner(), outchan, msg);
            llOwnerSay("Deslecting " + llGetObjectName());
        if (outchan) {
            llListenRemove(hlis);
             debugout(msg);
             hlis = 0;
         }
         }
     }
     }
      
     touch_start(integer num)
     integer channel = 884;
    list subset;
     integer hlis;
    float timeout = 300; // stop listening after 5 minutes of inactivity
    vector lastpos;
    rotation lastrot;
    default
     {
     {
         llSetTimerEvent(timeout);
         timer()
        llResetTime();
         {
        if (!hlis) {
             if (hlis){
            hlis =  llListen(channel, "", "", "");
                 llOwnerSay("Deslecting " + llGetObjectName());
            llOwnerSay(llGetObjectName() + " selected. Listening on channel " + (string)channel);
                 llListenRemove(hlis);
            return;
                 hlis = 0;
        }
         while (num--) {
            integer child=llDetectedLinkNumber(num);
            integer j = llListFindList(subset,[child]);
             if (~j) {
                 llOwnerSay("Deselecting #" + (string)child);
                 subset = llDeleteSubList(subset, j, j);
            } else {
                 llOwnerSay("Selecting #" + (string)child);
                subset += child;
             }
             }
         }
         }
    }
 
        touch_start(integer num)
    listen(integer ch, string name, key id, string msg)
        {
    {
            llSetTimerEvent(timeout);
        //llOwnerSay(msg + " from " + (string)id + " owned by " + (string)llGetObjectDetails(id, [OBJECT_OWNER]));
            llResetTime();
        if (llGetOwner() != id) {
            if (!hlis) {
            if (llList2Key(llGetObjectDetails(id, [OBJECT_OWNER]),0) != llGetOwner())
                hlis =  llListen(channel, "", "", "");
                llOwnerSay(llGetObjectName() + " selected. Listening on channel " + (string)channel);
                 return;
                 return;
            }
            while (num--) {
                integer child=llDetectedLinkNumber(num);
                integer j = llListFindList(subset,[child]);
                if (~j) {
                    llOwnerSay("Deselecting #" + (string)child);
                    subset = llDeleteSubList(subset, j, j);
                } else {
                    llOwnerSay("Selecting #" + (string)child);
                    subset += child;
                }
            }
         }
         }
 
         outchan = 0;
         listen(integer ch, string name, key id, string msg)
          
         {
        if (msg == "") {
            //llOwnerSay(msg + " from " + (string)id + " owned by " + (string)llGetObjectDetails(id, [OBJECT_OWNER]));
            subset = [];
             if (llGetOwner() != id) {
             llSetTimerEvent(0.1);  // empty message = disconnect right away;
                if (llList2Key(llGetObjectDetails(id, [OBJECT_OWNER]),0) != llGetOwner())
            return;
                    return;
        }
             }
        llSetTimerEvent(timeout);
       
             outchan = 0;
        if (llGetSubString(msg, 0, 0) == "/") {  // specify response channel
            integer endch = llSubStringIndex(msg, " ");
            if (msg == "") {
             outchan = (integer)llGetSubString(msg, 1, endch);
             msg = llGetSubString(msg, endch+1, -1);
        }
 
        if (llGetSubString(msg,0,0) == "[") {
            integer e = llSubStringIndex(msg, "]");
            if (e > 1)
                subset = list_cast(llCSV2List(llGetSubString(msg, 1, e-1)));
            else
                 subset = [];
                 subset = [];
             msg = llStringTrim(llGetSubString(msg, e+1, -1), STRING_TRIM_HEAD);
                llSetTimerEvent(0.1);  // empty message = disconnect right away;
            if (llList2String(subset,0) == "*") {
                return;
            }
            llSetTimerEvent(timeout);
            if (llGetSubString(msg, 0, 0) == "/") {  // specify response channel
                integer endch = llSubStringIndex(msg, " ");
                outchan = (integer)llGetSubString(msg, 1, endch);
                msg = llGetSubString(msg, endch+1, -1);
             }
            if (llGetSubString(msg,0,0) == "[") {
                integer e = llSubStringIndex(msg, "]");
                if (e > 1)
                    subset = list_cast(llCSV2List(llGetSubString(msg, 1, e-1)));
                else
                    subset = [];
                msg = llStringTrim(llGetSubString(msg, e+1, -1), STRING_TRIM_HEAD);
                if (llList2String(subset,0) == "*") {
                    integer i;
                    subset = [];
                    for (i=1; i<=llGetNumberOfPrims(); i++) subset += i;
                }
            }
            list sub;
            list cmds;
            if (llGetSubString(msg,0,0) == "?") {
                cmds = list_cast(llCSV2List(llGetSubString(msg, 1, -1)));
                 integer i;
                 integer i;
                 subset = [];
                 list curr;
                 for (i=1; i<=llGetNumberOfPrims(); i++) subset += i;
                if (subset == []) // If not specified use root (or only) prim
                    sub = [ (llGetNumberOfPrims() > 1) ];
                else
                    sub = subset;
                debugout(llList2CSV(cmds));
                 for (i = 0; i<llGetListLength(sub); i++) {
                    if (llGetListEntryType(sub,i) == TYPE_INTEGER){
                        integer j = llList2Integer(sub,i);
                        curr = llGetLinkPrimitiveParams(j, cmds);
                        reply("[" + (string)j + "] " + llList2CSV(curr));
                    }     
                    else //if (llGetListEntryType(subset,i) == TYPE_STRING)
                    {
                        integer k;
                        string x=llList2String(sub,i);
                        list exp;
                        for (k=1; k<=llGetNumberOfPrims(); k++) {
                            if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),
                                                [x]))
                            {
                                curr = llGetLinkPrimitiveParams(k, cmds);
                                exp += k;
                                reply("[" + (string)k + "] " + llList2CSV(curr));
                          }
                        }
                        debugout(x + " is " + llList2CSV(exp));
                    }
                }
                return;
             }
             }
        }
            if (llGetSubString(msg,0,0) == "$") {
        list sub;
                msg = llDeleteSubString(msg,0,0);
        list cmds;
                vector v = (vector)msg;
        if (llGetSubString(msg,0,0) == "?") {
                if (v == ZERO_VECTOR) {
            cmds = list_cast(llCSV2List(llGetSubString(msg, 1, -1)));
                    float scal=(float)msg;
            integer i;
                    v = <scal,scal,scal>;
            list curr;
                }
            if (subset == []) // If not specified use root (or only) prim
                resize_linkset(v);
                sub = [ (llGetNumberOfPrims() > 1) ];  
                return;
            else
            } else if (llGetSubString(msg,0,0) == "%") {
                sub = subset;
                msg = llDeleteSubString(msg,0,0);
 
                cmds = list_cast(llCSV2List(msg));
            debugout(llList2CSV(cmds));
                if (subset == [])
            for (i = 0; i<llGetListLength(sub); i++) {
                    sub = [LINK_SET];
                if (llGetListEntryType(sub,i) == TYPE_INTEGER){
                else
                    integer j = llList2Integer(sub,i);
                    sub = subset;
                    curr = llGetLinkPrimitiveParams(j, cmds);
                     reply("[" + (string)j + "] " + llList2CSV(curr));
                debugout("ParticleSystem On " + llList2CSV(subset) +":\nCmds: "+ llDumpList2String(cmds,"; "));
                }     
                integer i;
                else //if (llGetListEntryType(subset,i) == TYPE_STRING)
                for (i = 0; i<llGetListLength(sub); i++) {
                {
                    if (llGetListEntryType(sub,i) == TYPE_INTEGER)
                    integer k;
                        llLinkParticleSystem(llList2Integer(sub,i), cmds);
                    string x=llList2String(sub,i);
                     else //if (llGetListEntryType(subset,i) == TYPE_STRING)
                    list exp;
                    {
                    for (k=1; k<=llGetNumberOfPrims(); k++) {
                        integer k;
                        if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),
                        string x=llList2String(sub,i);
                                            [x]))
                        list exp;
                        {
                        for (k=llGetNumberOfPrims(); k; k--) {
                            curr = llGetLinkPrimitiveParams(k, cmds);
                            if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),[x]))
                            exp += k;
                            {
                             reply("[" + (string)k + "] " + llList2CSV(curr));
                                llLinkParticleSystem(k, cmds);
                      }
                                exp += k;
                             }
                        }
                        debugout(x + " is " + llList2CSV(exp));
                    }
                }
                return;
            } else if (llGetSubString(msg,0,0) == "@") {
                if (subset != []) {
                    if (!~llListFindList(subset,[llGetNumberOfPrims() > 1]) && !~llListFindList(subset,[llGetObjectName()])) {
                        return;
                     }
                     }
                    debugout(x + " is " + llList2CSV(exp));
                 }
                 }
   
                integer direction = KFM_FORWARD;
                msg = llDeleteSubString(msg,0,0);
                string pfx2 = llGetSubString(msg,0,0);
                if ( pfx2 == "%")  {
                    direction = KFM_PING_PONG;
                    msg = llDeleteSubString(msg,0,0);
                } else if (pfx2 == "^")  {
                    direction = KFM_REVERSE;
                    msg = llDeleteSubString(msg,0,0);
                } else if (pfx2 == "@")  {
                    if (msg == "@@") {
                        llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_STOP]);
                        llSetPos(lastpos);
                        llSetRot(lastrot);
                        return;
                    }       
                    llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_PAUSE]);
                    return;
                } else if (pfx2 == "!") {
                    lastpos = llGetPos();
                    lastrot = llGetRot();
                    llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_PLAY]);
                    llSetTimerEvent(0.0);  // stop the timer while animation is running
                    return;
                } else if (msg == "") {
                    llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_STOP]);
                    return;
                }
                lastpos = llGetPos();
                lastrot = llGetRot();
                cmds = list_cast(llCSV2List(msg));
                llSetKeyframedMotion(cmds, [KFM_MODE, direction]);
                llSetTimerEvent(0.0);  // stop the timer while animation is running
                return;
             }
             }
            return;
        }
        if (llGetSubString(msg,0,0) == "$") {
            msg = llDeleteSubString(msg,0,0);
            vector v = (vector)msg;
            if (v == ZERO_VECTOR) {
                float scal=(float)msg;
                v = <scal,scal,scal>;
            }
            resize_linkset(v);
            return;
        } else if (llGetSubString(msg,0,0) == "%") {
            msg = llDeleteSubString(msg,0,0);
             cmds = list_cast(llCSV2List(msg));
             cmds = list_cast(llCSV2List(msg));
             if (subset == [])
             if (subset == [])
Line 237: Line 312:
             else
             else
                 sub  = subset;
                 sub  = subset;
               
             debugout("ParticleSystem On " + llList2CSV(subset) +":\nCmds: "+ llDumpList2String(cmds,"; "));
             debugout("On " + llList2CSV(subset) +":\nCmds: "+ llDumpList2String(cmds,"; "));
             integer i;
             integer i;
             for (i = 0; i<llGetListLength(sub); i++) {
             for (i = 0; i<llGetListLength(sub); i++) {
                 if (llGetListEntryType(sub,i) == TYPE_INTEGER)
                 if (llGetListEntryType(sub,i) == TYPE_INTEGER)
                     llLinkParticleSystem(llList2Integer(sub,i), cmds);
                     llSetLinkPrimitiveParamsFast(llList2Integer(sub,i), cmds);
                 else //if (llGetListEntryType(subset,i) == TYPE_STRING)
                 else //if (llGetListEntryType(subset,i) == TYPE_STRING)
                 {
                 {
Line 251: Line 326:
                         if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),[x]))
                         if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),[x]))
                         {
                         {
                             llLinkParticleSystem(k, cmds);
                             llSetLinkPrimitiveParamsFast(k, cmds);
                             exp += k;
                             exp += k;
                         }
                         }
Line 257: Line 332:
                     debugout(x + " is " + llList2CSV(exp));
                     debugout(x + " is " + llList2CSV(exp));
                 }
                 }
            }
            return;
        } else if (llGetSubString(msg,0,0) == "@") {
            if (subset != []) {
                if (!~llListFindList(subset,[llGetNumberOfPrims() > 1]) && !~llListFindList(subset,[llGetObjectName()])) {
                    return;
                }
            }
            integer direction = KFM_FORWARD;
            msg = llDeleteSubString(msg,0,0);
            string pfx2 = llGetSubString(msg,0,0);
            if ( pfx2 == "%")  {
                direction = KFM_PING_PONG;
                msg = llDeleteSubString(msg,0,0);
            } else if (pfx2 == "^")  {
                direction = KFM_REVERSE;
                msg = llDeleteSubString(msg,0,0);
            } else if (pfx2 == "@")  {
                if (msg = "@@") {
                    llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_STOP]);
                    llSetPos(lastpos);
                    llSetRot(lastrot);
                    return;
                }       
                llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_PAUSE]);
                return;
            } else if (pfx2 == "!") {
                lastpos = llGetPos();
                lastrot = llGetRot();
                llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_PLAY]);
                llSetTimerEvent(0.0);  // stop the timer while animation is running
                return;
            } else if (msg == "") {
                llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_STOP]);
                return;
            }
            lastpos = llGetPos();
            lastrot = llGetRot();
            cmds = list_cast(llCSV2List(msg));
            llSetKeyframedMotion(cmds, [KFM_MODE, direction]);
            llSetTimerEvent(0.0);  // stop the timer while animation is running
            return;
        }
       
        cmds = list_cast(llCSV2List(msg));
        if (subset == [])
            sub = [LINK_SET];
        else
            sub  = subset;
           
        debugout("On " + llList2CSV(subset) +":\nCmds: "+ llDumpList2String(cmds,"; "));
        integer i;
        for (i = 0; i<llGetListLength(sub); i++) {
            if (llGetListEntryType(sub,i) == TYPE_INTEGER)
                llSetLinkPrimitiveParamsFast(llList2Integer(sub,i), cmds);
            else //if (llGetListEntryType(subset,i) == TYPE_STRING)
            {
                integer k;
                string x=llList2String(sub,i);
                list exp;
                for (k=llGetNumberOfPrims(); k; k--) {
                    if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),[x]))
                    {
                        llSetLinkPrimitiveParamsFast(k, cmds);
                        exp += k;
                    }
                }
                debugout(x + " is " + llList2CSV(exp));
             }
             }
         }
         }
     }
     }
}
</lsl>
}

Latest revision as of 07:34, 21 June 2013

See Primset and PrimControl HUD for explanation and the other parts of this system.

<lsl> //Primset+++

   // Includes support for 
   // llGet/SetLinkPrimitiveParams, linkset resize, llLinkParticleSystem, and llSetKeyframeMotion
   // Used by the PrimControl HUD

   // This function typecasts a list of strings into the types they appear to be. 
   // Useful for feeding user data into llSetPrimitiveParams
   // Takes list input, and returns that list - with all elements correctly typecast - as output
   // Written by Fractured Crystal, 27 Jan 2010, 
   // Commissioned by WarKirby Magojiro, this function is Public Domain
   // Modified by Rufus Darkfold to keep strings like <foo> instead of discarding them from the output list 

list_cast(list in)

   {
       list out;
       integer i;
       integer l= llGetListLength(in);
       for (i=0; i < l; i++)
       {
           string d= llStringTrim(llList2String(in,i),STRING_TRIM);
           if (d == "") out += "";
           else
           {
               if (llGetSubString(d,0,0) == "<")
               {
                   if (llGetSubString(d,-1,-1) == ">")
                   {
                       list s = llParseString2List(d,[","],[]);
                       integer sl= llGetListLength(s);
                       if (sl == 3) {
                           out += (vector)d;
                       } else if(sl == 4) {
                           out += (rotation)d;
                       } else
                           out += [d];
                   } else
                       out += [d];
               } else if (~llSubStringIndex(d,".")) {
                   out += (float)d;
               } else {
                   integer lold = (integer)d;
                   if ((string)lold == d) out += lold;
                   else
                   {
                       key kold = (key)d;
                       if (kold) out += [kold];
                       else out += [d];
                   }
               }
           }
       }

       //for (i = 0; i< llGetListLength(out); i++){
       //    llOwnerSay("Element " + (string)i + " type is " + (string)llGetListEntryType(out, i) 
       //                + " value is «" + llList2String(out,i) + "»");
       //}

       return out;
   }

   integer dimTest( vector vr )
   {
       return !( vr.x<0.01 || vr.y<0.01 || vr.z<0.01 || vr.x>64.0 || vr.y>64.0 || vr.z>64.0 );
   }

   resize_linkset( vector scal )
   {
       integer primindx;
       list primP;
       vector s = llGetScale();
       integer validDim = dimTest( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );
       for ( primindx = 2; primindx <= llGetNumberOfPrims(); primindx++ )
       {
           primP = llGetLinkPrimitiveParams( primindx, [PRIM_SIZE]);
           s = llList2Vector( primP, 0 );
           validDim = validDim && dimTest( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );
       }

       if ( validDim )
       {
           s = llGetScale();
           llSetScale( <scal.x*s.x,scal.y*s.y,scal.z*s.z> ); 
           for ( primindx = 2; primindx <= llGetNumberOfPrims(); primindx++ )
           {
               primP = llGetLinkPrimitiveParams( primindx, [PRIM_SIZE, PRIM_POSITION]);
               vector primScale = llList2Vector( primP, 0 );
               primScale = <primScale.x*scal.x, primScale.y*scal.y, primScale.z*scal.z>;
               vector primPos = llList2Vector( primP, 1 ) - llGetPos();
               primPos = <primPos.x*scal.x, primPos.y*scal.y, primPos.z*scal.z>;
               llSetLinkPrimitiveParamsFast( primindx, [PRIM_SIZE, primScale, PRIM_POSITION, primPos/llGetRootRotation()]);
           }
       }
       else llOwnerSay("No resize! Out of limit sizes are not accepted");
   }

   debugout(string msg)
   {
     llOwnerSay(msg);
   }

   integer outchan =0;
   reply(string msg)
   {
       llRegionSayTo(llGetOwner(), outchan, msg);
       if (outchan) {
           debugout(msg);
       }
   }

   integer channel = 884;

   list subset;
   integer hlis;
   float timeout = 300; // stop listening after 5 minutes of inactivity
   vector lastpos;
   rotation lastrot;

   default
   {
       timer()
       {
           if (hlis){
               llOwnerSay("Deslecting " + llGetObjectName());
               llListenRemove(hlis);
               hlis = 0;
           }
       }

       touch_start(integer num)
       {
           llSetTimerEvent(timeout);
           llResetTime();
           if (!hlis) {
               hlis =  llListen(channel, "", "", "");
               llOwnerSay(llGetObjectName() + " selected. Listening on channel " + (string)channel);
               return;
           }
           while (num--) {
               integer child=llDetectedLinkNumber(num);
               integer j = llListFindList(subset,[child]);
               if (~j) {
                   llOwnerSay("Deselecting #" + (string)child);
                   subset = llDeleteSubList(subset, j, j);
               } else {
                   llOwnerSay("Selecting #" + (string)child);
                   subset += child;
               }
           }
       }

       listen(integer ch, string name, key id, string msg)
       {
           //llOwnerSay(msg + " from " + (string)id + " owned by " + (string)llGetObjectDetails(id, [OBJECT_OWNER]));
           if (llGetOwner() != id) {
               if (llList2Key(llGetObjectDetails(id, [OBJECT_OWNER]),0) != llGetOwner())
                   return;
           }

           outchan = 0;

           if (msg == "") {
               subset = [];
               llSetTimerEvent(0.1);  // empty message = disconnect right away;
               return;
           }
           llSetTimerEvent(timeout);

           if (llGetSubString(msg, 0, 0) == "/") {  // specify response channel
               integer endch = llSubStringIndex(msg, " ");
               outchan = (integer)llGetSubString(msg, 1, endch);
               msg = llGetSubString(msg, endch+1, -1);
           }

           if (llGetSubString(msg,0,0) == "[") {
               integer e = llSubStringIndex(msg, "]");
               if (e > 1)
                   subset = list_cast(llCSV2List(llGetSubString(msg, 1, e-1)));
               else
                   subset = [];
               msg = llStringTrim(llGetSubString(msg, e+1, -1), STRING_TRIM_HEAD);
               if (llList2String(subset,0) == "*") {
                   integer i;
                   subset = [];
                   for (i=1; i<=llGetNumberOfPrims(); i++) subset += i;
               }
           }
           list sub;
           list cmds;
           if (llGetSubString(msg,0,0) == "?") {
               cmds = list_cast(llCSV2List(llGetSubString(msg, 1, -1)));
               integer i;
               list curr;
               if (subset == []) // If not specified use root (or only) prim
                   sub = [ (llGetNumberOfPrims() > 1) ]; 
               else
                   sub = subset;

               debugout(llList2CSV(cmds));
               for (i = 0; i<llGetListLength(sub); i++) {
                   if (llGetListEntryType(sub,i) == TYPE_INTEGER){
                       integer j = llList2Integer(sub,i);
                       curr = llGetLinkPrimitiveParams(j, cmds);
                       reply("[" + (string)j + "] " + llList2CSV(curr));
                   }       
                   else //if (llGetListEntryType(subset,i) == TYPE_STRING)
                   {
                       integer k;
                       string x=llList2String(sub,i);
                       list exp;
                       for (k=1; k<=llGetNumberOfPrims(); k++) {
                           if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),
                                               [x]))
                           {
                               curr = llGetLinkPrimitiveParams(k, cmds);
                               exp += k;
                               reply("[" + (string)k + "] " + llList2CSV(curr));
                          }
                       }
                       debugout(x + " is " + llList2CSV(exp));
                   }

               }
               return;
           }
           if (llGetSubString(msg,0,0) == "$") {
               msg = llDeleteSubString(msg,0,0);
               vector v = (vector)msg;
               if (v == ZERO_VECTOR) {
                   float scal=(float)msg;
                   v = <scal,scal,scal>;
               }
               resize_linkset(v);
               return;
           } else if (llGetSubString(msg,0,0) == "%") {
               msg = llDeleteSubString(msg,0,0);
               cmds = list_cast(llCSV2List(msg));
               if (subset == [])
                   sub = [LINK_SET];
               else
                   sub  = subset;

               debugout("ParticleSystem On " + llList2CSV(subset) +":\nCmds: "+ llDumpList2String(cmds,"; "));
               integer i;
               for (i = 0; i<llGetListLength(sub); i++) {
                   if (llGetListEntryType(sub,i) == TYPE_INTEGER)
                       llLinkParticleSystem(llList2Integer(sub,i), cmds);
                   else //if (llGetListEntryType(subset,i) == TYPE_STRING)
                   {
                       integer k;
                       string x=llList2String(sub,i);
                       list exp;
                       for (k=llGetNumberOfPrims(); k; k--) {
                           if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),[x]))
                           {
                               llLinkParticleSystem(k, cmds);
                               exp += k;
                           }
                       }
                       debugout(x + " is " + llList2CSV(exp));
                   }
               }
               return;
           } else if (llGetSubString(msg,0,0) == "@") {
               if (subset != []) {
                   if (!~llListFindList(subset,[llGetNumberOfPrims() > 1]) && !~llListFindList(subset,[llGetObjectName()])) {
                       return;
                   }
               }
               integer direction = KFM_FORWARD;
               msg = llDeleteSubString(msg,0,0);
               string pfx2 = llGetSubString(msg,0,0);
               if ( pfx2 == "%")  {
                   direction = KFM_PING_PONG;
                   msg = llDeleteSubString(msg,0,0);
               } else if (pfx2 == "^")  {
                   direction = KFM_REVERSE;
                   msg = llDeleteSubString(msg,0,0);
               } else if (pfx2 == "@")  {
                   if (msg == "@@") {
                       llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_STOP]);
                       llSetPos(lastpos);
                       llSetRot(lastrot);
                       return;
                   }        
                   llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_PAUSE]);
                   return;
               } else if (pfx2 == "!") {
                   lastpos = llGetPos();
                   lastrot = llGetRot();
                   llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_PLAY]);
                   llSetTimerEvent(0.0);  // stop the timer while animation is running
                   return;
               } else if (msg == "") {
                   llSetKeyframedMotion([], [KFM_COMMAND, KFM_CMD_STOP]);
                   return;
               }
               lastpos = llGetPos();
               lastrot = llGetRot();
               cmds = list_cast(llCSV2List(msg));
               llSetKeyframedMotion(cmds, [KFM_MODE, direction]);
               llSetTimerEvent(0.0);  // stop the timer while animation is running
               return;
           }

           cmds = list_cast(llCSV2List(msg));
           if (subset == [])
               sub = [LINK_SET];
           else
               sub  = subset;

           debugout("On " + llList2CSV(subset) +":\nCmds: "+ llDumpList2String(cmds,"; "));
           integer i;
           for (i = 0; i<llGetListLength(sub); i++) {
               if (llGetListEntryType(sub,i) == TYPE_INTEGER)
                   llSetLinkPrimitiveParamsFast(llList2Integer(sub,i), cmds);
               else //if (llGetListEntryType(subset,i) == TYPE_STRING)
               {
                   integer k;
                   string x=llList2String(sub,i);
                   list exp;
                   for (k=llGetNumberOfPrims(); k; k--) {
                       if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),[x]))
                       {
                           llSetLinkPrimitiveParamsFast(k, cmds);
                           exp += k;
                       }
                   }
                   debugout(x + " is " + llList2CSV(exp));
               }
           }
       }
   }

</lsl>