Difference between revisions of "Primset script"

From Second Life Wiki
Jump to navigation Jump to search
Line 10: Line 10:
     list list_cast(list in)
     list list_cast(list in)
     {
     {
list out;
        list out;
integer i;
        integer i;
integer l= llGetListLength(in);
        integer l= llGetListLength(in);
for (i=0; i < l; i++)
        for (i=0; i < l; i++)
{
        {
    string d= llStringTrim(llList2String(in,i),STRING_TRIM);
            string d= llStringTrim(llList2String(in,i),STRING_TRIM);
    if (d == "") out += "";
            if (d == "") out += "";
    else
            else
    {
            {
if (llGetSubString(d,0,0) == "<")
                if (llGetSubString(d,0,0) == "<")
{
                {
    if (llGetSubString(d,-1,-1) == ">")
                    if (llGetSubString(d,-1,-1) == ">")
    {
                    {
list s = llParseString2List(d,[","],[]);
                        list s = llParseString2List(d,[","],[]);
integer sl= llGetListLength(s);
                        integer sl= llGetListLength(s);
if (sl == 3) {
                        if (sl == 3) {
    out += (vector)d;
                            out += (vector)d;
} else if(sl == 4) {
                        } else if(sl == 4) {
    out += (rotation)d;
                            out += (rotation)d;
} else
                        } else
    out += [d];
                            out += [d];
    } else
                    } else
out += [d];
                        out += [d];
} else if (~llSubStringIndex(d,".")) {
                } else if (~llSubStringIndex(d,".")) {
    out += (float)d;
                    out += (float)d;
} else {
                } else {
    integer lold = (integer)d;
                    integer lold = (integer)d;
    if ((string)lold == d) out += lold;
                    if ((string)lold == d) out += lold;
    else
                    else
    {
                    {
key kold = (key)d;
                        key kold = (key)d;
if (kold) out += [kold];
                        if (kold) out += [kold];
else out += [d];
                        else out += [d];
    }
                    }
}
                }
    }
            }
}
        }


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


return out;
        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 );
        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 )
     resize_linkset( vector scal )
     {
     {
integer primindx;
        integer primindx;
list primP;
        list primP;
vector s = llGetScale();
        vector s = llGetScale();
integer validDim = dimTest( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );
        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]);
            primP = llGetLinkPrimitiveParams( primindx, [PRIM_SIZE]);
    s = llList2Vector( primP, 0 );
            s = llList2Vector( primP, 0 );
    validDim = validDim && dimTest( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );
            validDim = validDim && dimTest( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );
}
        }


if ( validDim )
        if ( validDim )
{
        {
    s = llGetScale();
            s = llGetScale();
    llSetScale( <scal.x*s.x,scal.y*s.y,scal.z*s.z> );  
            llSetScale( <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, PRIM_POSITION]);
vector primScale = llList2Vector( primP, 0 );
                vector primScale = llList2Vector( primP, 0 );
primScale = <primScale.x*scal.x, primScale.y*scal.y, primScale.z*scal.z>;
                primScale = <primScale.x*scal.x, primScale.y*scal.y, primScale.z*scal.z>;
vector primPos = llList2Vector( primP, 1 ) - llGetPos();
                vector primPos = llList2Vector( primP, 1 ) - llGetPos();
primPos = <primPos.x*scal.x, primPos.y*scal.y, primPos.z*scal.z>;
                primPos = <primPos.x*scal.x, primPos.y*scal.y, primPos.z*scal.z>;
llSetLinkPrimitiveParamsFast( primindx, [PRIM_SIZE, primScale, PRIM_POSITION, primPos/llGetRootRotation()]);
                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");
     }
     }


Line 99: Line 99:
     reply(string msg)
     reply(string msg)
     {
     {
llRegionSayTo(llGetOwner(), outchan, msg);
        llRegionSayTo(llGetOwner(), outchan, msg);
if (outchan) {
        if (outchan) {
    debugout(msg);
            debugout(msg);
}
        }
     }
     }


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


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


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


    outchan = 0;
            outchan = 0;


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


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


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


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


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


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


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


    debugout("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)
    llSetLinkPrimitiveParamsFast(llList2Integer(sub,i), cmds);
                    llSetLinkPrimitiveParamsFast(llList2Integer(sub,i), cmds);
else //if (llGetListEntryType(subset,i) == TYPE_STRING)
                else //if (llGetListEntryType(subset,i) == TYPE_STRING)
{
                {
    integer k;
                    integer k;
    string x=llList2String(sub,i);
                    string x=llList2String(sub,i);
    list exp;
                    list exp;
    for (k=llGetNumberOfPrims(); k; k--) {
                    for (k=llGetNumberOfPrims(); k; k--) {
if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),[x]))
                        if (~llListFindList(llGetLinkPrimitiveParams(k,[PRIM_NAME,PRIM_DESC]),[x]))
{
                        {
    llSetLinkPrimitiveParamsFast(k, cmds);
                            llSetLinkPrimitiveParamsFast(k, cmds);
    exp += k;
                            exp += k;
}
                        }
    }
                    }
    debugout(x + " is " + llList2CSV(exp));
                    debugout(x + " is " + llList2CSV(exp));
}
                }
    }
            }
}
        }
     }
     }

Revision as of 02:55, 14 December 2011

   //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. 
   //Extremely useful for feeding user data into llSetPrimitiveParams
   //It takes a list as an 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 entirely 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));
               }
           }
       }
   }