Primset script

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>