Jump to content

Interface Script - Inventory Reader


Bugs Larnia
 Share

You are about to reply to a thread that has been inactive for 467 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

This was something that was born out of laziness (that happens to me a lot ๐Ÿ˜). Every time I had to write a script that did something like "get this prim's inventory and [insert action to take here]", I had to rewrite the inventory retrieval routine again. So, partly inspired by @Quistess Alpha (yes, again), I began creating a series of interface scripts: generic scripts that did tasks and sent the result though llMessageLinked. That way, I can just insert that script and focus my attention on what I want to do with the result (in case of this example: the aforementioned inventory list).

Below is just an example of an interface script and a test implementation. I use an interface ID as a sort of "key", which is used by the implementing script to make sure the link_message event is raised by this particular script.

// This is the interface ID: you can use this as a communication key to avoid clutter if you use multieple interface scripts
integer GetInterfaceId()
{
    return -55440986;
}

GenerateAndSendInventoryList()
{
    SendInventoryList(GenerateInventoryList());
}

list GenerateInventoryList()
{
    list lInventory;
    integer iInventoryCount = llGetInventoryNumber(INVENTORY_ALL);
    if (iInventoryCount > 0)
    {
        integer i;
        for (i = 0; i < iInventoryCount; ++i)
        {
            string sName = llGetInventoryName(INVENTORY_ALL, i);
            //Since we can have multiple scripts in inventory, we can't just remove this script from the list
            if (llGetInventoryType(sName) != INVENTORY_SCRIPT)
            {
                lInventory += llGetInventoryName(INVENTORY_ALL, i);
            }
        }
    }
    return lInventory;
}

SendInventoryList(list plInventory)
{
    llMessageLinked(LINK_SET, GetInterfaceId(), llDumpList2String(plInventory, "|"), NULL_KEY);
}

default
{
    state_entry()
    {
        GenerateAndSendInventoryList();
    }

    changed(integer piChange)
    {
        if (piChange & CHANGED_INVENTORY)
        {
            GenerateAndSendInventoryList();
        }
    }

    on_rez(integer piParam)
    {
        llResetScript();
    }
}

As you can see, this script updates the inventory on certain events and then sends it through llMessageLinked. So in and of itself, this script does nothing.

The implementing script, in this case, might, for example, look something like this:

list glInventory;

//Use the same interface ID as the interface script
integer GetInterfaceId()
{
    return -55440986;
}

default
{    
    touch_start(integer total_number)
    {
        if (glInventory != [])
        {
            llGiveInventoryList(llDetectedKey(0), llGetObjectName(), glInventory);
        }
        else
        {
            llRegionSayTo(llDetectedKey(0), 0, "Bah! Humbug!");
        }
    }
    
    link_message(integer piLinkNum, integer piNum, string psMsg, key pkId)
    {
        if (piNum == GetInterfaceId())
        {
            glInventory = llParseString2List(psMsg, ["|"], []);
        }
    }
}

As you can see, I use the same key, encapsulated in GetInterfaceId(), to make sure that my signal comes from the right caller. Now all I have to do is write what I want to do with my inventory list. Mostly you'd want to give it to a person, but perhaps in another implementation, you want to transfer objects to another prim (like a HUD), or show a menu with these items. With these interface scripts, you can just add building blocks for repetitive tasks.

This is just one very simple example of such a script to show you the principle behind it. Another example would be an on/off switch interface. What that does can be handled in an implementing script: a lamp, a scanner, movement, etc.

I am sure others have a lot more of these, so feel free to add them in the comments.

ย 

  • Like 1
Link to comment
Share on other sites

Well since you mentioned me, I think I might have shared this before, but just to have it in the correct place, here's an early script I made from cobbling together examples on the wiki to 'select a nearby person'. I'm pretty sure it has a few bugs if there are too many people (with long complicated display names) nearby, but it works 'well enough' in most cases.

list gItemList;
list gLstMnu; // global list for the menu.

integer gChannel;
integer gListenHandle; // TODO: make this a strided handler,user list for multiple users.

list uDlgBtnLst( integer vIdxPag ){
    list vLstRtn;
    if ((gLstMnu != []) > 12){ //-- we have more than one possible page
        integer vIntTtl = -~((~([] != gLstMnu)) / 10);                                 //-- Total possible pages
        integer vIdxBgn = (vIdxPag = (vIntTtl + vIdxPag) % vIntTtl) * 10;              //-- first menu index
        string  vStrPag = llGetSubString( "                     ", 21 - vIdxPag, 21 ); //-- encode page number as spaces
         //-- get ten (or less for the last page) entries from the list and insert back/fwd buttons
        vLstRtn = llListInsertList( llList2List( gLstMnu, vIdxBgn, vIdxBgn + 9 ), (list)(" ยซ" + vStrPag), 0xFFFFFFFF ) +
                  (list)(" ยป" + vStrPag);
    }else{ //-- we only have 1 page
        vLstRtn = gLstMnu; //-- just use the list as is
    }
    return //-- fix the order for [L2R,T2B] and send it out
      llList2List( vLstRtn, -3, -1 ) + llList2List( vLstRtn, -6, -4 ) +
      llList2List( vLstRtn, -9, -7 ) + llList2List( vLstRtn, -12, -10 );
}/*//  Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ]  //*/
string uList2nString(list l,integer offset)
{   integer index = llGetListLength(l);
    string sReturn;
    while(index>0)
    {   index--;
        //string item = "secondlife:///app/agent/" + llList2String(l,index) + "/inspect";
        string item = llList2String(l,index);
        sReturn = (string)(index+offset) + ") " + item + "\n" + sReturn;
    }
    return sReturn;
}
default
{
    link_message(integer sender,integer n,string str,key who)
    {
        if(n==3)
        {
            gItemList=llParseString2List(str,[";"],[]);
            /*fill gLstMnu with numbers from 0 to llGetListLength(AgentList)*/
            integer index=0;
            integer max = llGetListLength(gItemList);
            gLstMnu=[];
            while(index<max)
            {
                gLstMnu+=(string)(index++);
            }
            gChannel = (integer)(llFrand(-1000000000.0) - 1000000000.0);
            gListenHandle = llListen(gChannel,"",who,"");
            list items=gItemList;
            if(llGetListLength(items)>10)
                items=llList2List(gItemList,0,10);
            llDialog( who, uList2nString(items,0), uDlgBtnLst( 0 ), gChannel );
            llSetTimerEvent(60); // 60 second timeout
        }
    }
    listen( integer vIntChn, string vStrNom, key vKeySpk, string vStrMsg ){
        if (!llSubStringIndex( vStrMsg, " " ))
        { //-- detects (hidden) leading non-breaking space of page change buttons
            integer vIdxPage = ( llStringLength( vStrMsg ) + llSubStringIndex( vStrMsg, "ยป" ) - 2 );
            integer vIdxBgn = 0;
            if(vIdxPage !=0)
            { /* calculate the index of the first item in list for this page*/
                integer vIntTtl = -~((~([] != gLstMnu)) / 10);
                vIdxBgn = (vIdxPage = (vIntTtl + vIdxPage) % vIntTtl) * 10;              //-- first menu index
            }
            llDialog( vKeySpk,
                      uList2nString( llList2List(gItemList,vIdxBgn, vIdxBgn+9),vIdxBgn ),
                      uDlgBtnLst(vIdxPage),
                      vIntChn );
        }else
        {   //-- button was not a page button, your code goes here,
            //-- use (llListFindList( gLstMnu, (list)vStrMsg ) / 10) for remenu command if present
            //integer vIdxPage=(llListFindList( gLstMnu, (list)vStrMsg ) / 10);
            llListenRemove(gListenHandle);
            ///*DEBUG*/llSay(0,"Test! "+(string)llList2Key(gAgentList,(integer)vStrMsg));
            llMessageLinked(LINK_THIS,-3,llList2String(gItemList,(integer)vStrMsg),"");
        }
    }
    timer()
    {
        llListenRemove(gListenHandle);
        llSetTimerEvent(0);
    }
}

and a template usage script:

key gTarget=NULL_KEY;
default
{
    touch_start(integer total_number)
    {
        llSay(0, "secondlife:///app/agent/"+(string)gTarget+"/inspect");
        llMessageLinked(LINK_THIS,2,"",llDetectedKey(0)); //settarget dialog.
        
    }
    link_message(integer link,integer n,string text,key ID)
    {
        if(n==-2) // settarget
        {
            gTarget=ID;
        }
    }
}

It's better to not use these sorts of things when possible, but sometimes the action is so common and just annoying enough to implement that it make sense to have it in a sepparate "plugin" script.

  • Like 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 467 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...