User:Cow Taurog/Prim owner board

From Second Life Wiki
< User:Cow Taurog
Revision as of 03:09, 22 April 2014 by Cow Taurog (talk | contribs) (Created page with "__NOTOC__ ==Prim poller== <source lang="lsl"> // This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. // To view a copy of …")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Prim poller

// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
// Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
// 
// Cow Taurog's prim owner info fetcher
// Last edited on 08/27/2010
//
// This script will grab a list of people that have prims on the parcel, prim count, and online status.
// The list will be sorted by descending prim count, and their names resolved, then sent over chat and/or link message.
// You can use the output provided in your own script, or drop in the display scripts.
//
// This will not work if you aren't in the same sim unless:
// -The land is owned by a group, not an individual.
// -This object is deeded to (owned by) the group, not an individual.
// You will need to set full perms, and share with the group if you want to be able to edit
// the server once it is deeded. You will also need to share with group again after it is deeded.
// Group names cannot be resolved from their key, so any group owned objects will show as unknown.
// This whole "not working when the owner is gone" thing is why we need this to act by itself as a server.

// -Settings-

float gfPoll=90;          // How often to update in seconds. Depends on how fast the display you will use refreshes.

integer giLinkMsgChan=43; // Channel to output the data over link message on (0 to disable).

integer giChatChan=643;   // Channel to output the data over chat on (0 to disable).

// The data is output as a pipe seperated list of the key, name, prim count, and presence of all prim owners.
// The parcel key is the first item in the list, useful for making sure we get the right info.
// <parcel key>|<owner1 key>|<owner1 name>|<owner1 primcount>|<owner1 in sim (1/0)>|<owner2 key>...

list glExcludeKeys=["38429ab1-2d0a-4535-962f-a909cee910e0","83b1a9ee-d1fa-1e11-486c-1aa470872db5"];
// You can choose to exclude any person or group from being shown on the list. I have myself and my group in this list.

float gfDataTimeout=3.0;  // How long before giving up on response from the name resolution (owner is a group or <1 day old)

//
// There are no more settings past this line. 
//

list glRaw; // Stores raw data so we can sort and add to it
key gkAct; // Target's key
integer giCount; // Target's prim count
integer giRawLen; // Length of the raw data list
integer giExcLen; // Length of the key exclusion list
list glData; // Sorted and completed data
integer i; // Counter
integer k; // Counter
key gkReq; // Dataserver request handle
integer DEBUG=0; // Debug level. 0=none, 1=minimal, 2-verbose
key gkDebugTo=""; // Key to IM debug messages to. Blank to disable.
debug2(string mess){if(DEBUG==2){if(gkDebugTo==""){llInstantMessage(gkDebugTo,"Debug: "+mess);}}} // Verbose debug function
debug1(string mess){if(DEBUG>0){if(gkDebugTo==""){llInstantMessage(gkDebugTo,"Debug: "+mess);}}} // Minimal debug function
default{
    on_rez(integer param){llResetScript();} //Reset when rezzed
    changed(integer change){if(change&CHANGED_OWNER){llResetScript();}} // Reset when owner changes
    state_entry(){
        glData=[]; // Clear data from the last run
        glRaw=llGetParcelPrimOwners(llGetPos()); // Get keys and prim counts from the parcel
        giRawLen=llGetListLength(glRaw); // Calculate length of the raw data
        giExcLen=llGetListLength(glExcludeKeys); // Calculate length of the exclusion list
        debug1("glRaw: "+llList2CSV(glRaw));
        // Remove anyone on the exclusion list
        for(i=0;i<giExcLen;i++){ // Check every entry in the exclusion list
            string sF=llList2String(glExcludeKeys,i); // Store target key
            debug2("sF: "+sF);
            integer iAt=llListFindList(glRaw,[(key)sF]); // Store location of target key
            debug2("iAt: "+(string)iAt);
            if(iAt!=-1){ glRaw=llDeleteSubList(glRaw,iAt,iAt+1);} // If the target is in the list, remove it
        }
        debug2("glRaw after exclusion: "+llList2CSV(glRaw));
        // We can only sort by the first item in a strided list, so we need to reverse the list.
        // Put the prim count first, and make sure it is casted as an integer instead of a string.
        for(i=0;i<giRawLen;i=i+2){ // Loop through the entire list (stride of 2, note the i=i+2 instead of i++)
            integer iCount=llList2Integer(glRaw,i+1); // Store prim count as integer to ensure proper typecasting
            string sOwner=llList2String(glRaw,i); // Store owner key
            glData=glData+[iCount,sOwner]; // Add these to the new data list in reverse order
        }
        // Sort the data by prim count
        integer iDL=llGetListLength(glData)-4; // There is one blank stride on the list for some reason, note the -4.
        debug2("glData before chop: "+llList2CSV(glData));
        glData=llDeleteSubList(glData,iDL,-1); // Chop off the extra entry
        debug2("glData before sort: "+llList2CSV(glData));
        glRaw=[]; // Blank out the raw info from earlier, we don't need it
        glRaw=llListSort(glData,2,FALSE); // Sort data and store it into the empty list
        glData=[]; // Blank out the data we just sorted from
        debug2("glRaw after sort: "+llList2CSV(glRaw));
        i=0; // Set i to zero so we can use it
        // The script now has a sorted list of keys and prim counts. We now resolve their names, and find if they are here
        // We will toggle back and forth between two identical states to resolve the names from the dataserver.
        state fillA; // Go to the first state
    }
}
state fillA{
    on_rez(integer param){llResetScript();}
    changed(integer change){if(change&CHANGED_OWNER){llResetScript();}}
    timer(){ // If the timer event is triggered, the name could not be found, either it is a group or <1 day old.
        debug1("Timeout.");
        glData=glData+[gkAct,"(unknown)",giCount,1]; // Store their info into the final list
        i=i+2; // Increment i by 2 since the list is strided
        if(i+4<giRawLen){state fillB;} // If there is is still more to resolve, go to the next state
        else{debug2("show");state show;} // Otherwise finish and show the results
    }
    state_entry(){
        llSetTimerEvent(gfDataTimeout); // Set request timeout
        gkAct=llList2Key(glRaw,i+1); // Store target's key (these are global since they are used in dataserver too)
        giCount=llList2Integer(glRaw,i); // Store target's prim count
        gkReq=llRequestAgentData(gkAct,DATA_NAME);  // Request the name from the dataserver
        debug2("Requested (A)");
    }
    dataserver(key req,string mess){if(req==gkReq){ // Make sure this is our request, and not some random one
        llSetTimerEvent(0); // Keep the timeout event from triggering since we got our result
        debug2("Dataserver (A): "+mess);
        vector vO=llGetAgentSize(gkAct); // Store the target's size (will be <0,0,0> if they are a group, or aren't in the sim)
        if(vO!=ZERO_VECTOR){glData=glData+[gkAct,mess,giCount,1];} // Put their info into the final list, and a 1 for presence
        else{glData=glData+[gkAct,mess,giCount,0];} // Put their info into the final list, and a 0 for presence
        llSleep(0.1); // Wait for a tiny bit to prevent weirdness
        i=i+2; // Increment i by 2 to advance to the next entry
        if(i+4<giRawLen){state fillB;} // If there is still more to resolve, go to the next state
        else{debug2("show");state show;} // Otherwise finish and show the results
    }}
}
state fillB{ // Second verse, same as the first. Only this one goes to state fillA instead.
    on_rez(integer param){llResetScript();}
    changed(integer change){if(change&CHANGED_OWNER){llResetScript();}}
    timer(){
        debug1("Timeout.");
        glData=glData+[gkAct,"(unknown)",giCount,1];
        llSleep(0.1);
        i=i+2;
        if(i+4<giRawLen){state fillA;}else{debug2("show");state show;}
    }
    state_entry(){
        llSetTimerEvent(gfDataTimeout);
        gkAct=llList2Key(glRaw,i+1);
        giCount=llList2Integer(glRaw,i);
        gkReq=llRequestAgentData(gkAct,DATA_NAME);
        debug2("Requested (B)");
    }
    dataserver(key req,string mess){if(req==gkReq){
        llSetTimerEvent(0);
        debug2("Dataserver (B): "+mess);
        vector vO=llGetAgentSize(gkAct);
        if(vO!=ZERO_VECTOR){glData=glData+[gkAct,mess,giCount,1];}
        else{glData=glData+[gkAct,mess,giCount,0];}
        llSleep(0.1);
        i=i+2;
        if(i+4<giRawLen){state fillA;}else{debug2("show");state show;}
    }}
}
state show{
    on_rez(integer param){llResetScript();}
    changed(integer change){if(change&CHANGED_OWNER){llResetScript();}}
    state_entry(){
        llSetTimerEvent(gfPoll); // Start the timer so we can do this all over again
        llListen(giChatChan+1,"","",""); // Listen for a reset message
        debug1("glData: "+llList2CSV(glData));
        string sD=llDumpList2String(glData,"|"); // Dump the whole thing into a string seperated with "|"
        string sI=llList2Key(llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_ID]),0); // Store the parcel key
        if(giLinkMsgChan!=0){llMessageLinked(LINK_SET,giLinkMsgChan,sD,(key)sI);} // Output data on linkmsg
        if(giChatChan!=0){llRegionSay(giChatChan,sI+"|"+sD);debug2((string)giChatChan+": "+sI+"|"+sD);} // Output on chat
    }
    timer(){i=0;glData=[];state default;} // Time to poll again, reset the list and the counter, and start over.
    listen(integer chan,string name,key id,string mess){
        if(llSameGroup(id)==TRUE){if(mess=="refresh"){i=0;glData=[];state default;}} // Refresh if told to
    }
}

Hovertext prim owner display

// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
// Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
// 
//This script is meant to provide a easy and fast display that shows the parcel's prim owner info as hovertext.
//You can drop this into any object on the parcel.
integer giInputChan=643; // Chat channel to listen for data on
vector gvColor=<0.3,0.6,1>; // Text color
float gfAlpha=1; // Text transparency (0=transparent, 1=opaque)
//
// There are no more settings past this line.
//
string gsOutput; // Stores final output
key gkParcel; // Stores the parcel's key
list glKeys; // Stores prim owner's keys
list glNames; // Stores prim owner's names
list glCounts; // Stores prim counts
list glPresences; // Stores presence status
list glRaw; // Stores raw data
integer i; // Counter
integer DEBUG=0; // Debug level. 0=none, 1=minimal, 2-verbose
debug2(string mess){if(DEBUG==2){llOwnerSay("Debug: "+mess);}} // Verbose debug function
default{
    on_rez(integer param){llResetScript();}
    changed(integer change){if(change&CHANGED_OWNER){llResetScript();}}
    touch_start(integer num){if(llDetectedKey(num-1)==llGetOwner()){
        llSetText("",gvColor,gfAlpha);llRegionSay(giInputChan+1,"refresh");
    }}
    state_entry(){
        llSetText("",gvColor,gfAlpha);
        gkParcel=llList2Key(llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_ID]),0);
        llListen(giInputChan,"","","");
    }
    listen(integer chan,string name,key id,string mess){if(llSameGroup(id)==TRUE){
        debug2("mess: "+mess);
        glRaw=llParseString2List(mess,["|"],[]);
        debug2("glRaw: "+llList2CSV(glRaw));
        if(llList2Key(glRaw,0)!=gkParcel){state default;}
        glRaw=llDeleteSubList(glRaw,0,0);
        debug2("glRaw after removed parcel: "+llList2CSV(glRaw));
        integer iRawLen=llGetListLength(glRaw);
        for(i=0;i<iRawLen;i=i+4){
            glKeys=glKeys+[llList2Key(glRaw,0)];
            glNames=glNames+[llList2String(glRaw,1)];
            glCounts=glCounts+[llList2Integer(glRaw,2)];
            glPresences=glPresences+[llList2Integer(glRaw,3)];
            glRaw=llDeleteSubList(glRaw,0,3);
            debug2("glRaw entry removal: "+llList2CSV(glRaw));
        }
        glRaw=[];
        debug2("glKeys: "+llList2CSV(glKeys));
        debug2("glNames: "+llList2CSV(glNames));
        debug2("glCounts: "+llList2CSV(glCounts));
        debug2("glPresences: "+llList2CSV(glPresences));
        float fClock=llGetGMTclock();
        integer iHours=((integer)fClock/3600);
        integer iMinutes=((integer)fClock/60)-(iHours*60);
        string sHours=(string)iHours;
        if(iHours<10){sHours="0"+sHours;}
        string sMinutes=(string)iMinutes;
        if(iMinutes<10){sMinutes="0"+sMinutes;}
        gsOutput=
         " Updated "+sHours+sMinutes+"Z\n"+
         (string)(llGetParcelMaxPrims(llGetPos(),1)-llGetParcelPrimCount(llGetPos(),PARCEL_COUNT_TOTAL,1))+
         " prims remain\n";
        for(i=1;i<=llGetListLength(glKeys);i++){
            key kL=(key)((string)i);
            gsOutput=gsOutput+" "+llList2String(glNames,i-1)+" ("+llList2String(glCounts,i-1)+")";
            if(llList2String(glPresences,i-1)=="1"){gsOutput=gsOutput+"\n";}
            else{gsOutput=gsOutput+" (not here)\n";}
        }
        llSetText(gsOutput,gvColor,gfAlpha);
        glKeys=[];
        glNames=[];
        glCounts=[];
        glPresences=[];
    }}
}

Xyzzy text prim owner display

// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
// Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
// 
// This script will make a xyzzytext display show info about the prim owners on your parcel.
// Drop this and the xyzzy controller into your display, and set the number of lines to match yours.
integer giInputChan=643; // Chat channel to listen for data on.
integer giScreenRows=10; // Number of rows in your xytext display.
vector gvOnColor=<0,0.25,0.5>; // Font color for people who are here.
vector gvOffColor=<0.5,0.25,0>; // Font color for people who aren't here.
vector gvTextColor=<0,0.25,0>; // Font color for normal text
float gfDelay=90; // How often to poll for changes
//
// There are no more settings past this line.
//
integer giLinesShown; // Counts number of lines used so we don't have to blank all of them
key gkParcel; // Stores the parcel's key
list glKeys; // Stores prim owner's keys
list glNames; // Stores prim owner's names
list glCounts; // Stores prim counts
list glPresences; // Stores presence status
list glRaw; // Stores raw data
integer i; // Counter
integer DEBUG=0; // Debug level. 0=none, 1=minimal, 2-verbose
debug2(string mess){if(DEBUG==2){llOwnerSay("Debug: "+mess);}} // Verbose debug function
default{
    on_rez(integer param){llResetScript();}
    changed(integer change){if(change&CHANGED_OWNER){llResetScript();}}
    touch_start(integer num){if(llDetectedKey(num-1)==llGetOwner()){
        //for(i=0;i<=giLinesShown+2;i++){llMessageLinked(LINK_SET,204000,"",(string)i);}
        llRegionSay(giInputChan+1,"refresh");
        llMessageLinked(LINK_SET,99292,"poll","");
    }}
    //timer(){llMessageLinked(LINK_SET,99292,"poll","");}
    state_entry(){
        giScreenRows++; // Rows start at zero, so add 1 to use normal human numbers
        //llSetTimerEvent(gfDelay);
        llMessageLinked(LINK_SET,204000,"","0");
        llMessageLinked(LINK_SET,204006,(string)gvOnColor,(string)i);
        for(i=4;i<giScreenRows;i++){
            llMessageLinked(LINK_SET,204000,"",(string)i);
            llMessageLinked(LINK_SET,204006,(string)gvOnColor,(string)i);
        }
        //for(i=0;i<giScreenRows;i++){llMessageLinked(LINK_SET,204000,"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",(string)i);}
        gkParcel=llList2Key(llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_ID]),0);
        llListen(giInputChan,"","","");
        llRegionSay(giInputChan+1,"refresh");
        llMessageLinked(LINK_SET,99292,"poll","");
    }
    listen(integer chan,string name,key id,string mess){if(llSameGroup(id)==TRUE){
        debug2("raw mess: "+mess);
        if(llGetSubString(mess,36,-1)=="||(unknown)|0|1"){
            float fClock=llGetGMTclock();
            integer iHours=((integer)fClock/3600);
            integer iMinutes=((integer)fClock/60)-(iHours*60);
            string sHours=(string)iHours;
            if(iHours<10){sHours="0"+sHours;}
            string sMinutes=(string)iMinutes;
            if(iMinutes<10){sMinutes="0"+sMinutes;}
            llMessageLinked(LINK_SET,204000,
            " Updated "+sHours+sMinutes+"Z        "+
            (string)(llGetParcelMaxPrims(llGetPos(),1)-llGetParcelPrimCount(llGetPos(),PARCEL_COUNT_TOTAL,1))+
            " prims remain ","0");
            //for(i=4;i<=giScreenRows;i++){llMessageLinked(LINK_SET,204000,"",(string)i);}
            llMessageLinked(LINK_SET,204006,(string)gvOnColor,"4");
            llMessageLinked(LINK_SET,204000,"* Welcome! No prims are in use","4");  
        }else{
            debug2("mess: "+mess);
            glRaw=llParseString2List(mess,["|"],[]);
            debug2("glRaw: "+llList2CSV(glRaw));
            if(llList2Key(glRaw,0)!=gkParcel){state default;}
            glRaw=llDeleteSubList(glRaw,0,0);
            debug2("glRaw after removed parcel: "+llList2CSV(glRaw));
            integer iRawLen=llGetListLength(glRaw);
            for(i=0;i<iRawLen;i=i+4){
                glKeys=glKeys+[llList2Key(glRaw,0)];
                glNames=glNames+[llList2String(glRaw,1)];
                glCounts=glCounts+[llList2Integer(glRaw,2)];
                glPresences=glPresences+[llList2Integer(glRaw,3)];
                glRaw=llDeleteSubList(glRaw,0,3);
                debug2("glRaw entry removal: "+llList2CSV(glRaw));
            }
            giLinesShown=llGetListLength(glKeys);
            for(i=4;i<=giLinesShown+1;i++){llMessageLinked(LINK_SET,204000,"",(string)i);}
            glRaw=[];
            debug2("glKeys: "+llList2CSV(glKeys));
            debug2("glNames: "+llList2CSV(glNames));
            debug2("glCounts: "+llList2CSV(glCounts));
            debug2("glPresences: "+llList2CSV(glPresences));
            float fClock=llGetGMTclock();
            integer iHours=((integer)fClock/3600);
            integer iMinutes=((integer)fClock/60)-(iHours*60);
            string sHours=(string)iHours;
            if(iHours<10){sHours="0"+sHours;}
            string sMinutes=(string)iMinutes;
            if(iMinutes<10){sMinutes="0"+sMinutes;}
            llMessageLinked(LINK_SET,204000,
             " Updated "+sHours+sMinutes+"Z        "+
             (string)(llGetParcelMaxPrims(llGetPos(),1)-llGetParcelPrimCount(llGetPos(),PARCEL_COUNT_TOTAL,1))+
             " prims remain ","0");
            for(i=4;i<giScreenRows;i++){
                string sM;
                sM=" "+llList2String(glNames,i-4)+" ("+llList2String(glCounts,i-4)+")";
                debug2("sM: "+sM);
                if(llList2String(glKeys,i-4)!=""){
                    if(llList2Integer(glPresences,i)==0){
                        sM=sM+" (not here)";
                        llMessageLinked(LINK_SET,204006,(string)gvOffColor,(key)((string)i));
                        llMessageLinked(LINK_SET,204000,sM,(key)((string)i));
                    }else{
                        llMessageLinked(LINK_SET,204006,(string)gvOnColor,(key)((string)i));
                        llMessageLinked(LINK_SET,204000,sM,(key)((string)i));
                    }
                }
            }
        }
        glKeys=[];
        glNames=[];
        glCounts=[];
        glPresences=[];
    }}
}

Prim tracker

// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
// Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
// 
// This script will track who rezzes new prims, removes all their prims, and leaves without cleaning up.
//
integer giInputChan=643; // Chat channel to listen for data on
integer giLeftBehindTol=125; // Don't nag someone unless they have more than this
//
// There are no more settings past this line.
//
key gkParcel; // Stores the parcel's key
list glKeys; // Stores prim owner's keys
list glNames; // Stores prim owner's names
list glCounts; // Stores prim counts
list glPresences; // Stores presence status
list glOldKeys;
list glOldNames;
list glOldCounts;
list glOldPresences;
list glWarnList;
list glRaw; // Stores raw data
integer i; // Counter
integer DEBUG=0; // Debug level. 0=none, 1=minimal, 2-verbose
say(string mess, string hours, string minutes){llOwnerSay(hours+minutes+"Z: "+mess);}
debug2(string mess){if(DEBUG==2){llOwnerSay("Debug: "+mess);}} // Verbose debug function
debug1(string mess){if(DEBUG>0){llOwnerSay("Debug: "+mess);}} // Minimal debug function
default{
    on_rez(integer param){llResetScript();}
    changed(integer change){if(change&CHANGED_OWNER){llResetScript();}}
    touch_start(integer num){if(llDetectedKey(num-1)==llGetOwner()){
        llRegionSay(giInputChan+1,"refresh");
    }}
    state_entry(){
        llSetColor(<1,0,0>,-1);
        gkParcel=llList2Key(llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_ID]),0);
        llListen(giInputChan,"","","");
    }
    listen(integer chan,string name,key id,string mess){if(llSameGroup(id)==TRUE){
        debug2("mess: "+mess);
        glRaw=llParseString2List(mess,["|"],[]);
        debug2("glRaw: "+llList2CSV(glRaw));
        if(llList2Key(glRaw,0)!=gkParcel){state default;}
        glRaw=llDeleteSubList(glRaw,0,0);
        debug2("glRaw after removed parcel: "+llList2CSV(glRaw));
        integer iRawLen=llGetListLength(glRaw);
        for(i=0;i<iRawLen;i=i+4){
            glKeys=glKeys+[llList2Key(glRaw,i)];
            glNames=glNames+[llList2String(glRaw,i+1)];
            glCounts=glCounts+[llList2Integer(glRaw,i+2)];
            glPresences=glPresences+[llList2Integer(glRaw,i+3)];
        }
        glRaw=[];
        debug2("glKeys: "+llList2CSV(glKeys));
        debug2("glNames: "+llList2CSV(glNames));
        debug2("glCounts: "+llList2CSV(glCounts));
        debug2("glPresences: "+llList2CSV(glPresences));
        glOldKeys=glKeys;
        glOldNames=glNames;
        glOldCounts=glCounts;
        glOldPresences=glPresences;
        debug2("glOldKeys: "+llList2CSV(glOldKeys));
        debug2("glOldNames: "+llList2CSV(glOldNames));
        debug2("glOldCounts: "+llList2CSV(glOldCounts));
        debug2("glOldPresences: "+llList2CSV(glOldPresences));
        glKeys=[];
        glNames=[];
        glCounts=[];
        glPresences=[];
        state running;
    }}
}
state running{
    on_rez(integer param){llResetScript();}
    changed(integer change){if(change&CHANGED_OWNER){llResetScript();}}
    touch_start(integer num){if(llDetectedKey(num-1)==llGetOwner()){
        llRegionSay(giInputChan+1,"refresh");
    }}
    state_entry(){
        llSetColor(<0,1,0>,-1);
        gkParcel=llList2Key(llGetParcelDetails(llGetPos(),[PARCEL_DETAILS_ID]),0);
        llListen(giInputChan,"","","");
    }
    listen(integer chan,string name,key id,string mess){if(llSameGroup(id)==TRUE){
        debug2("mess: "+mess);
        glRaw=llParseString2List(mess,["|"],[]);
        debug2("glRaw: "+llList2CSV(glRaw));
        if(llList2Key(glRaw,0)!=gkParcel){state running;}
        glRaw=llDeleteSubList(glRaw,0,0);
        debug2("glRaw after removed parcel: "+llList2CSV(glRaw));
        integer iRawLen=llGetListLength(glRaw);
        for(i=0;i<iRawLen;i=i+4){
            glKeys=glKeys+[llList2Key(glRaw,i)];
            glNames=glNames+[llList2String(glRaw,i+1)];
            glCounts=glCounts+[llList2Integer(glRaw,i+2)];
            glPresences=glPresences+[llList2Integer(glRaw,i+3)];
            //glRaw=llDeleteSubList(glRaw,0,3);
            //debug2("glRaw entry removal: "+llList2CSV(glRaw));
        }
        glRaw=[];
        debug2("glKeys: "+llList2CSV(glKeys));
        debug2("glNames: "+llList2CSV(glNames));
        debug2("glCounts: "+llList2CSV(glCounts));
        debug2("glPresences: "+llList2CSV(glPresences));
        debug2("glOldKeys: "+llList2CSV(glOldKeys));
        debug2("glOldNames: "+llList2CSV(glOldNames));
        debug2("glOldCounts: "+llList2CSV(glOldCounts));
        debug2("glOldPresences: "+llList2CSV(glOldPresences));
        float fClock=llGetGMTclock();
        integer iHours=((integer)fClock/3600);
        integer iMinutes=((integer)fClock/60)-(iHours*60);
        string sHours=(string)iHours;
        if(iHours<10){sHours="0"+sHours;}
        string sMinutes=(string)iMinutes;
        if(iMinutes<10){sMinutes="0"+sMinutes;}
        integer iOL=llGetListLength(glOldKeys);
        debug2("iOL: "+(string)iOL);
        integer iKL=llGetListLength(glKeys);
        debug2("iKL: "+(string)iKL);
        for(i=0;i<iKL;i++){
            key kT=llList2Key(glKeys,i);
            string sN=llList2String(glNames,i);
            integer iNC=llList2Integer(glCounts,i);
            integer iOC;
            integer iOCAt=llListFindList(glOldKeys,[kT]);
            if(iOCAt==-1){iOC=-1;}else{iOC=llList2Integer(glOldCounts,iOCAt);}
            integer iNP=llList2Integer(glPresences,i);
            integer iOP;
            integer iOPAt=llListFindList(glOldKeys,[kT]);
            if(iOPAt==-1){iOP=0;}else{iOP=llList2Integer(glOldPresences,iOPAt);}
            debug1("kT: "+(string)kT);
            debug1("sN: "+sN);
            debug1("iNC: "+(string)iNC);
            debug1("iOC: "+(string)iOC);
            debug1("iNP: "+(string)iNP);
            debug1("iOP: "+(string)iOP);
            debug1("\n");
            if(kT!="(unknown)"){if(iOCAt==-1){
                if(iNC==1){say(sN+" rezzed 1 prim.",sHours,sMinutes);}
                else{say(sN+" rezzed "+(string)iNC+" prims.",sHours,sMinutes);}
            }}
            if(iOP==0){if(iNP==1){if(iOPAt!=-1){
                say(sN+" came back.",sHours,sMinutes);
            }}}
            if(iNC>iOC){if(kT!="(unknown)"){
                if(iNC-iOC==1){say(sN+" rezzed 1 more prim.",sHours,sMinutes);}
                else{say(sN+" rezzed "+(string)(iNC-iOC)+" more prims.",sHours,sMinutes);}
            }}
            if(iOC>iNC){if(kT!="(unknown)"){
                if(iOC-iNC==1){say(sN+" removed 1 prim.",sHours,sMinutes);}
                else{say(sN+" removed "+(string)(iOC-iNC)+" prims.",sHours,sMinutes);}
            }}
            if(iOP==1){if(iNP==0){if(kT!="(unknown)"){
                say(sN+" left "+(string)iNC+" prims behind.",sHours,sMinutes);
                if(iNC>giLeftBehindTol){
                    //llInstantMessage(kT,"You have left "+(string)iNC+" prims behind in "+llGetRegionName()+". Please go back and clean up after yourself so other people can use them.");
                    say(sN+" was warned for not cleaning up.",sHours,sMinutes);
                }
            }}}
        }
        for(i=0;i<iKL;i++){
            key kT=llList2Key(glOldKeys,i);
            string sN=llList2String(glOldNames,i);
            integer iOC=llList2Integer(glOldCounts,i);
            integer iNKAt=llListFindList(glKeys,[kT]);
            if(iNKAt==-1){if(iOC>0){if(kT!="(unknown)"){
                say(sN+" removed all "+(string)iOC+" of their prims.",sHours,sMinutes);
            }}}
        }
        glOldKeys=[];
        glOldNames=[];
        glOldCounts=[];
        glOldPresences=[];
        glOldKeys=glKeys;
        glOldNames=glNames;
        glOldCounts=glCounts;
        glOldPresences=glPresences;
        glKeys=[];
        glNames=[];
        glCounts=[];
        glPresences=[];
    }}
}

Cager finder

// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
// Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
// 
//Bounding box: <-3.659322, -3.659323, -2.942255>, <3.659322, 3.659322, 2.992700>
//Prim count: 2
//
//[22:35] Cager finder: Bounding box: <-3.659322, -3.659323, -2.942255>, <3.659322, 3.659322, 2.992700>
//Prim count: 2
//
//[22:35] Cager finder: Bounding box: <-1.321905, -1.321905, -1.606233>, <1.321905, 1.321905, 1.566233>
//Prim count: 3
string gsTarget=">:)"; // Name of the object to seek
integer giPrimCount=3; // How many prims the object is
integer giType; // Type of object
float gfMass=19.712570; // Mass of object
//float gfMassTol=0.1; // Mass tolerance
list glIdiots; // Idiot list
list glBound=[<-1.321905,-1.321905,-1.606233>,<1.321905,1.321905,1.566233>]; // Bounding box
//vector gvBoundTol=0.15; // Tolerance of bounding box
float gfRange=96.0; // Range of sensor
float gfPoll=2; // How often to poll
default{
    on_rez(integer param){llResetScript();}
    changed(integer change){if(change&CHANGED_OWNER){llResetScript();}}
    state_entry(){
        giType=ACTIVE|PASSIVE;
        llSetText("",<0.8,0.8,0.8>,1);
        llSensorRepeat(gsTarget,"",giType,gfRange,PI,gfPoll);
    }
    sensor(integer num){integer i;for(i=0;i<num;i++){
        string sM;
        sM=sM+"Bounding box: "+llList2CSV(llGetBoundingBox(llDetectedKey(i)))+"\n";
        sM=sM+"Prim count: "+(string)llGetObjectPrimCount(llDetectedKey(i))+"\n";
        llOwnerSay(sM);
        //llSetText(sM,<0.8,0.8,0.8>,1);
        if(llGetObjectPrimCount(llDetectedKey(i))==giPrimCount){
            llOwnerSay("Prim count");
        if(gfMass==llGetObjectMass(llDetectedKey(i))){
            
        //if(llGetBoundingBox(llDetectedKey(i))==glBound){
            key kO=llDetectedOwner(i);
            if(llListFindList(glIdiots,[kO])==-1){glIdiots=glIdiots+[kO];}
        }}//}
    }}
    touch_start(integer num){if(llDetectedKey(num-1)==llGetOwner()){
        llOwnerSay("Idiots: "+llList2CSV(glIdiots));
    }}
}

Info Fetcher

// This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
// To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to
// Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
//
key gkReq;
integer giRate;
vector gvColor=<0,0.25,0>;
default{
    //touch_start(integer num){if(llDetectedKey(0)==llGetOwner()){llResetScript();}}
    state_entry(){
        llMessageLinked(LINK_SET,204006,(string)gvColor,"1");
        llMessageLinked(LINK_SET,204006,(string)gvColor,"2");
        llMessageLinked(LINK_SET,204006,(string)gvColor,"3");
        llMessageLinked(LINK_SET,204000,"","1");
        llMessageLinked(LINK_SET,204000,"","2");
        llMessageLinked(LINK_SET,204000,"","3");
        state poll;
    }
}
state poll{
    state_entry(){giRate=0;llSetTimerEvent(60);gkReq=llHTTPRequest("http://secondlife.com/httprequest/homepage.php",[],"");}
    http_response(key req,integer status,list meta,string mess){if(status==200){
        list lT=llParseString2List(mess,["\n"],[]);
        llMessageLinked(LINK_SET,204000,"* Sim population: "+(string)llGetRegionAgentCount(),"1");
        llMessageLinked(LINK_SET,204000,"* Grid population: "+llList2String(lT,17),"2");
        llMessageLinked(LINK_SET,204000,"* Exchange rate: L$"+(string)llRound(llList2Float(lT,11))+" per USD","3");
    }}
    link_message(integer sender,integer num,string mess,key id){if(num==99292){
        if(mess=="poll"){state poll;}
    }}
    timer(){
        giRate++;
        llMessageLinked(LINK_SET,204000,"* Sim population: "+(string)llGetRegionAgentCount(),"1");
        if(giRate>30){state poll;}
    }
}

Template:MP