User:PixelProphet Lane/Scripts

From Second Life Wiki
Jump to navigation Jump to search

Fast List Prim Contents


This script loops through the Object Inventory of the Prim you add it to, and displays Itemname, Itemtype and next Owner permissions in chat by means of Owner message.

It's easier and much faster to loop through the Inventory Item types, store the current type in a variable, and then loop through each item that is an item of our currently stored type. This way you don't need to fetch the Inventory Item type for each item you find.

// Fast Display Prim Contents and corresponding next Owner permissions in chat
// By PixelProphet Lane
// This code is free to copy, modify and transfer.
// If you intend to distribute this code as is, then please leave the comments above as they are.
// In case you distribute this code as non modifiable part of your scripts, please include a reference to this page.
 
string ME;
string PARENT;
default
{
    on_rez(integer arg)
    {
        llResetScript();
    }
    
    state_entry()
    {
        ME = llGetScriptName();
        PARENT = llGetObjectName();
    }
    
    touch_start(integer total_number)
    {
        list InventoryConstants = [INVENTORY_TEXTURE,INVENTORY_SOUND,INVENTORY_OBJECT,INVENTORY_SCRIPT,INVENTORY_LANDMARK,
                                    INVENTORY_CLOTHING,INVENTORY_NOTECARD,INVENTORY_BODYPART];
        list ConstantNames = ["TEXTURE","SOUND","OBJECT","SCRIPT","LANDMARK","CLOTHING","NOTECARD","BODYPART"];
        integer type;
        integer item;
        integer len = llGetListLength(InventoryConstants);
        llSetObjectName("");
        for (type = 0; type < len; ++type)
        {
            integer constant = llList2Integer(InventoryConstants, type);
            string constname = llList2String(ConstantNames, type);
            integer num = llGetInventoryNumber(constant);
            
            for (item = 0; item < num; ++item)
            {
                string itemname = llGetInventoryName(constant, item);
                if (itemname != ME)
                {
                    integer nextPerms = llGetInventoryPermMask(itemname, MASK_NEXT);
                    string Perms;
                    if (nextPerms & PERM_COPY)
                    {
                        Perms += " Copy";
                    }
                    if (nextPerms & PERM_MODIFY)
                    {
                        Perms += " Modify";
                    }
                    if (nextPerms & PERM_TRANSFER)
                    {
                        Perms += " Transfer";
                    }
                    string output = "Name = "+itemname+", Type = "+constname+", Next Owner Permissions = "+Perms;
                    llOwnerSay("/me "+output);
                }
            }
        }
        llSetObjectName(PARENT);
        llRemoveInventory(ME);
    }
}


Real Object Inventory To Dialog


This script will display all items contained in an Object Inventory, regardless of the amount of items or length of item names. Further more, this script allows you to determine who has access to the Object using this script. It also provides an easy way to configure end, next and back buttons. I have used non standard unicode characters for my buttons in this example (characters that cannot be part of an item name). A simple giver has been implemented, which checks your permissions on any selected Inventory Item to see if it's actually transferable.

If the Owner uses the object, the above check is not done.

Apart from displaying content in a dialog, this script demonstrates several techniques that are useful in many ways.

// Real Object Inventory To Dialog
// By PixelProphet Lane
// Please note that any and every script published in the script library falls under the 
// Creative Commons Creative Commons Attribution-Share Alike 3.0 license.
// See https://wiki.secondlife.com/wiki/Project:Copyrights for details.
// If you intend to distribute this code as is, then please the comments above as they are.
// In case you distribute this code as non modifiable part of your scripts or objects, please include a reference to the page
// you aquired the source from.
 
integer DLGCHAN;
integer HDL;
integer ISACTIVE;
integer PAGE;
integer LINE;
integer INBOX;
integer UPDATE;
integer TIMEOUT = 20;
string  NOTECARD = "users";
string  BTN_NEXT = "next ►";
string  BTN_BACK = "◄ back";
string  BTN_END = "▣ end";
string  OBJECTNAME;
string  ME;
string  MESSAGE;
string  CURRENTUSERNAME;
key     CURRENTUSERKEY;
key     QUERY;
key     OWNER;
list    USERS;
list    BUTTONS;
 
SendDialog()
{
    if (INBOX == 0)
    {
        llDialog(CURRENTUSERKEY,"No items in inventory!",[],-1);
        return;   
    }
    integer items_per_dlg = 10;
    integer lastpage= llCeil((float)INBOX / (float)items_per_dlg);
    if (PAGE > lastpage)
    {
        PAGE = lastpage;
    }
    if (PAGE < 1)
    {
        PAGE = 1;
    }
    BUTTONS = [];
    MESSAGE = "";
    integer i;
    integer min = (PAGE - 1) * items_per_dlg;
    integer max = PAGE * items_per_dlg;
    if (max >= INBOX)
    {
        max = INBOX;
    }
    for (i = min; i < max; ++i)
    {
        string item =  llGetInventoryName(INVENTORY_ALL, i);
        //Don't give this script or users notecard away
        if (item != ME && item != NOTECARD)
        {
            MESSAGE += (string)i+" "+item+"\n";
            BUTTONS += (string)i;
        }
    }  
    if (PAGE == 1 && lastpage > 1)
    {
        BUTTONS += [BTN_END,BTN_NEXT];
    }
    if (PAGE == 1 && lastpage == 1)
    {
        BUTTONS += BTN_END;
    }
    if (PAGE > 1 && PAGE < lastpage)
    {
        BUTTONS += [BTN_BACK,BTN_NEXT];
    }
    if (PAGE == lastpage && PAGE != 1)
    {
        BUTTONS += BTN_BACK;
    }
    integer len = llGetListLength(BUTTONS);
    for (i = 0; i < len; i = i + 3)
    {
        BUTTONS = llListInsertList(llDeleteSubList(BUTTONS, -3, -1), llList2List(BUTTONS, -3, -1), i);
    }                
    llSetTimerEvent(TIMEOUT);
    llDialog(CURRENTUSERKEY, MESSAGE+" ",BUTTONS,DLGCHAN); 
}
 
integer IsAuthorized(string name)
{
    if (~llListFindList(USERS, [name]))
        return TRUE;
    return FALSE;
}
 
integer IsValidButton(string name)
{
    if (~llListFindList(BUTTONS, [name]))
        return TRUE;
    return FALSE;
}
 
default
{
    on_rez(integer arg)
    {
        llResetScript();   
    }
 
    state_entry()
    {
        ISACTIVE = FALSE;
        OWNER = llGetOwner();
        OBJECTNAME = llGetObjectName();
        ME = llGetScriptName();
        INBOX = llGetInventoryNumber(INVENTORY_ALL);
        DLGCHAN = ( -1 * (integer)("0x"+llGetSubString((string)llGetKey(),-5,-1)) );
        LINE = 0;
        PAGE = 1;
        //Notecards that have been newly created and have not been opened and saved at least once,
        //do not have a valid asset id and will return NULL_KEY (They're just placeholders)
        if (llGetInventoryKey(NOTECARD) != NULL_KEY)
        {
            QUERY = llGetNotecardLine(NOTECARD, LINE);
        }
        else
        {
            llWhisper(0,"No Notecard by the name of "+NOTECARD+" or "+NOTECARD+" is not a valid asset.");
        }
 
    }
 
    touch_start(integer num)
    {
        key avatarkey = llDetectedKey(0);
        string avatarname = llDetectedName(0);
        //Check if avatar who touched is authorized
        if(avatarkey != OWNER && !IsAuthorized(avatarname))
        {
            return;
        }
        if (UPDATE)
        {
            llDialog(avatarkey, OBJECTNAME+" is currently updating....\nPlease wait.", [] ,-1);
            return;
        }
        if (!ISACTIVE || avatarkey == CURRENTUSERKEY)
        {
            ISACTIVE = TRUE;
            llListenRemove(HDL);
            //Listen to this avatar only
            HDL = llListen(DLGCHAN, "", avatarkey, "");
            CURRENTUSERKEY = avatarkey;
            CURRENTUSERNAME = avatarname;
            PAGE = 1;
            SendDialog();
        }
        else
        {
            llDialog(avatarkey, OBJECTNAME+" is currently in use by "+CURRENTUSERNAME+"\nPlease wait.", [] ,-1);
        }
    }
 
    changed(integer change)
    {
        if (change & CHANGED_INVENTORY)
        {
            UPDATE = TRUE;
            //Wait until there are no changes for atleast 2 seconds until reading notecard again
            //Since there was a change in inventory, we can remove the listener too if there was one
            llSetTimerEvent(2);
        }
    }
 
    listen(integer channel, string name, key id, string msg)
    {
        if (msg == BTN_END)
        {
            llSetTimerEvent(0.1);
            return;   
        }
        if (msg == BTN_NEXT)
        {
            ++PAGE;
            SendDialog();
            return;
        }
        if (msg == BTN_BACK)
        {
            --PAGE;
            SendDialog();
            return;
        }
        //If it wasn't end, back or next, then check if it was valid
        if (IsValidButton(msg))
        { 
            string item = llGetInventoryName(INVENTORY_ALL, (integer)msg);
            if (item != "" && item != ME && item != NOTECARD)
            {
                //If the user is not the Owner, check to see that item is actually transferable
                if (id != OWNER)
                {
                    integer ownerPerms = llGetInventoryPermMask(item, MASK_OWNER);
                    if (ownerPerms & PERM_TRANSFER)
                    {
                        llGiveInventory(id,item);
                    }
                }
                else
                {
                    //Owner always gets item
                    llGiveInventory(id,item);
                }
            }
            SendDialog();
        }
 
    }
 
    dataserver(key query_id, string data)
    {
        if (query_id == QUERY)
        {
            if (data != EOF)
            {    
                //Remove leading and trailing spaces
                data = llStringTrim(data,STRING_TRIM);
                //If data still contains valid information after trimming, store it
                if (data != "\n" && data != "")
                    USERS += data;
                ++LINE;
                QUERY = llGetNotecardLine(NOTECARD, LINE);
            }
            else
            {
                UPDATE = FALSE;
                llOwnerSay("No more lines in "+NOTECARD+", read " + (string)LINE + " lines.");
            }
        }
    }
 
    timer()
    {
        llSetTimerEvent(0);
        llListenRemove(HDL);
        ISACTIVE = FALSE;
        CURRENTUSERNAME = "";
        CURRENTUSERKEY = NULL_KEY;
        if (UPDATE)
        {
            INBOX = llGetInventoryNumber(INVENTORY_ALL);
            LINE = 0;
            USERS = [];
            //Since inventory has changed and we need to read out notecard, we check again to see if it's valid
            if (llGetInventoryKey(NOTECARD) != NULL_KEY)
            {
                QUERY = llGetNotecardLine(NOTECARD, LINE);
            }
            else
            {
                llWhisper(0,"No Notecard by the name of "+NOTECARD+" or "+NOTECARD+" is not a valid asset.");
            }
        }
 
    }
}


Show Agent Script Count and memory


This script will display the amount of scripts attached to the avatar that touches the prim this script is in, and will display the amount of memory used by those scripts.

//Agent Script Count and memory usage by PixelProphet Lane
//bytesToSize function in PHP ThomasR, August 24th 2010, adapted to LSL by PixelProphet Lane 
string bytesToSize(integer bytes)
{
    list units = ["Bytes", "KiloBytes", "MegaBytes", "GigaBytes", "TerraBytes"];
    if (bytes == 0) return "n/a";
    integer i = llFloor(llLog(bytes) / llLog(1024));
    string val = (string)llRound(bytes / llPow(1024, i));
    return val + " " + llList2String(units,i);
}

string ONAME;
default
{
    on_rez(integer arg)
    {
        llResetScript();
    }
    
    state_entry()
    {
        ONAME = llGetObjectName();
        llSay(0,llGetEnv("sim_channel") + " " + llGetEnv("sim_version"));        
    }

    touch_start(integer total_number)
    {
        llSetObjectName(llDetectedName(0));
        list data = llGetObjectDetails(llDetectedKey(0),[OBJECT_TOTAL_SCRIPT_COUNT,OBJECT_SCRIPT_MEMORY]);
        string scripts = llList2String(data,0);
        integer mem = llList2Integer(data,1);
        string memory = bytesToSize(mem);
        llSay(0,"/me has "+scripts+" scripts attached using a total of "+memory);
        llSetObjectName(ONAME);
    }
}


Grid Status Feed


This script will periodically query the Second Life Grid Status Feed and will check to see the latest post is from the same day the request was made. If so, the script can optionally display title, link and description of the latest feed post to inform you. Posts from yesterday will not be displayed.

This script operates in a prim rezzed on your parcel, or inside an attachment. If you are using this script in an attachment, the data will be displayed using llOwnerSay. If you are using this script in a prim not attached to you, it will check if you are on the same region, and if so, use llOwnerSay. If you are on a different region, it will check your online status and use llInstantMessage if you are online. If you are offline, the script will not inform you.

/*
######## Grid Status Feed by PixelProphet Lane #########
######## Leave it at home, or carry it around with you #
*/

integer SEND_TITLE = TRUE;  //include title in IM ? FALSE = no, TRUE = yes
integer SEND_LINK = TRUE;   //include link in IM ? FALSE = no, TRUE = yes
integer SEND_DESC = TRUE;   //include description in IM ? FALSE = no, TRUE = yes
integer IS_ATTACHED = FALSE;

string KEYWORD_ALERT = ""; //Define a string of characters that trigger a keyword alert (Firestorm Viewer), or leave empty
string FEED_URL = "http://status.secondlifegrid.net/feed";
string PUB_DATE = "nothing";

key HTTP_REQID;
key DATA_REQID;
key OWNER;


RequstOnlineStatus()
{
    DATA_REQID = llRequestAgentData(OWNER, DATA_ONLINE);
}

RequestFeedData()
{
    HTTP_REQID = llHTTPRequest(FEED_URL,[],"");    
}

string Today()
{
    list months_short = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
    list ldate = llParseString2List(llGetDate(),["-"],[]);
    string day = (string)llList2Integer(ldate, 2);
    string month = llList2String(months_short, (llList2Integer(ldate, 1)-1));;
    string year = llList2String(ldate, 0);
    return day+" "+month+" "+year;
}

default
{
    on_rez(integer arg)
    {
        if (OWNER != llGetOwner())
            llResetScript();
    }
    
    state_entry()
    {
        if (!SEND_TITLE && !SEND_LINK && !SEND_DESC)
        {
            llOwnerSay("Please set at least one of SEND_TITLE,SEND_LINK or SEND_DESC to 1");
            return;
        }
        OWNER = llGetOwner();
        llSetTimerEvent(300);
        if ((IS_ATTACHED = llGetAttached()) != 0  || <0.0, 0.0, 0.0> != llGetAgentSize(OWNER))
            RequestFeedData();
        else
            RequstOnlineStatus();
    }
    
    attach(key id)
    {
        IS_ATTACHED = llGetAttached(); 
    }
    
    dataserver(key queryid, string data)
    {
        if (queryid != DATA_REQID)
            return;
        if (data == "1") 
            RequestFeedData();    
    }

    http_response (key request_id, integer status, list metadata, string body)
    {
        if (request_id != HTTP_REQID)
            return;
        if (status == 200) //Under normal circumstances the server will return 200
        {
            //body = llGetSubString(body, 0, 2048); //In future HTTP Requests may receive a lot more than 2048 bytes
            integer begin = llSubStringIndex(body, "<pubDate>") + 9;
            integer end = llSubStringIndex(body, "</pubDate>") - 1;
            string data;
            if (~begin && ~end) //If <pubDate> wasn't found, no need for further processing
            {
                data = llGetSubString(body, begin, end);
                if (-1 == llSubStringIndex(data,Today())) //Only posts from today
                    return;
                if (data != "" && data != PUB_DATE) //Make sure data even contains something
                {
                    PUB_DATE = data;
                    begin = llSubStringIndex(body, "<item>") + 6; //Get the beginning of first item
                    end = llSubStringIndex(body, "</item>") - 1; //Get the end of first item 
                    string item = llGetSubString(body, begin, end); //Crop the string
                    string data = KEYWORD_ALERT;            
                    if (SEND_TITLE)
                    {
                        begin = llSubStringIndex(item, "<title>") + 7;
                        end = llSubStringIndex(item, "</title>") - 1;
                        if (~begin && ~end)
                            data += "\n"+llGetSubString(item, begin, end);
                    }
                    if (SEND_LINK)
                    {
                        begin = llSubStringIndex(item, "<link>") + 6;
                        end = llSubStringIndex(item, "</link>") - 1;
                        if (~begin && ~end)
                            data += "\n"+llGetSubString(item, begin, end);   
                    }
                    if (SEND_DESC)
                    {
                        begin = llSubStringIndex(item,  "<description>") + 22; //len <description><![CDATA[
                        end = llSubStringIndex(item, "</description>") - 4;
                        item = llGetSubString(item, begin, end); //Crop the string
                        if (~begin && ~end)
                            data += "\n"+item;   
                    }
                    if (data != KEYWORD_ALERT) //did we even get any data ?
                    {
                        if (IS_ATTACHED || <0.0, 0.0, 0.0> != llGetAgentSize(OWNER)) //attached, or owner on region
                            llOwnerSay(data);
                        else
                            llInstantMessage(OWNER, data);     
                    }
                }
            }
        }
    }
    
    timer()
    {
        if (IS_ATTACHED || <0.0, 0.0, 0.0> != llGetAgentSize(OWNER))
            RequestFeedData();
        else
            RequstOnlineStatus();     
    }
}


Animation Permissions Tester


Just a script to test if animation scripts are generally operational on a region. Usage: Create a prim and drop this script inside, then either touch the prim, or sit on the prim. Sitting on the prim will use auto-grant permission, so you will not see a permissions request dialog.

default
{
    on_rez(integer arg)
    {
        llResetScript();
    }
    
    state_entry()
    {
        llSitTarget(<0,0,1>,ZERO_ROTATION);    
    }

    touch_start(integer total_number)
    {
        llRequestPermissions(llDetectedKey(0),PERMISSION_TRIGGER_ANIMATION);
    }
    
    
    changed(integer change)
    {
        if (change & CHANGED_LINK)
        {
            if (llAvatarOnSitTarget())
                llRequestPermissions(llAvatarOnSitTarget(),PERMISSION_TRIGGER_ANIMATION);
        }
    }
    
    run_time_permissions(integer perm)
    {
        if (perm & PERMISSION_TRIGGER_ANIMATION)
        {
            llWhisper(0,"PERMISSION_TRIGGER_ANIMATION granted");
            llStopAnimation("stand");
            llStopAnimation("sit");
            llStartAnimation("dance1");
        }
    }
}