Jump to content

LLDialog error. Buttons cannot be more than 24 characters long.


Heather Moonwing
 Share

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

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

Recommended Posts

Hey, been working on a frankenscript to generate a menu, read the objects, and then rez the selected object right above. Problem I'm running into is I have some items that arent mod, so I can't reduce their names to less than 24 characters. I would be greatly appreciative if someone could help me with the llgetsubstring, or how to truncate the names so I can use this script.

 

list MENU1 = [];
list MENU2 = [];
integer listener;
integer MENU_CHANNEL = 1000;
 
 
Dialog(key id, list menu)
{
llListenRemove(listener);
listener = llListen(MENU_CHANNEL, "", NULL_KEY, "");
llDialog(id, "Select one object below: ", menu, MENU_CHANNEL);
}
 
default
{
on_rez(integer num)
{
llResetScript();
}
 
touch_start(integer total_number)
{
integer i = 0;
MENU1 = [];
MENU2 = [];
integer c = llGetInventoryNumber(INVENTORY_OBJECT);
if (c <= 12)
{
for (; i < c; ++i)
MENU1 += llGetInventoryName(INVENTORY_OBJECT, i);
}
else
{
for (; i < 11; ++i)
MENU1 += llGetInventoryName(INVENTORY_OBJECT, i);
if(c > 22)
c = 22;
for (; i < c; ++i)
MENU2 += llGetInventoryName(INVENTORY_OBJECT, i);
MENU1 += ">>";
MENU2 += "<<";
}
Dialog(llDetectedKey(0), MENU1);
}
 
listen(integer channel, string name, key id, string message)
{
if (channel == MENU_CHANNEL)
{
llListenRemove(listener);
if (message == ">>")
{
Dialog(id, MENU2);
}
else if (message == "<<")
{
Dialog(id, MENU1);
}
else
{
// todo add offsets so box sites perfect on rezzer
llRezAtRoot(message, llGetPos() + <0.0, 0.0, 0.5> , ZERO_VECTOR, llGetRot(), 0);
}
}
}
}

The script itself works fine now, but anytime I try to add something so I can truncate the buttons, I get all flustered trying to figure this out. If you can help, Id be appreciative.

Link to comment
Share on other sites

It's not just a 24 character limit.  In practice, it's a 12-character limit.  You can use names that are 12-14 characters long, but only the first 12 (or so, depending on character width) will actually show up on the button.  So, you have two choices  (Three, if you count changing the names of the items in your objet's Contents).

1.  You can truncate object names and use the shortened versions as button labels.  That takes two steps.  First, you need to create a shortened name.  So

          

string NewName = llGetSubString(OldName,0,11);

 

gives you a 12-character version of OldName.  Unfortunately, though, you can't use that NewName when you want to rez, display, or give away the object.  That's why you need step two.  Every time you create a shortened name, you need to add it to a list of indexes that you can use to recover the original.  For example

           string NewName = llGetSubString(OldName,0,11);           ShortNames += [NewName] + [OldName];   // Where ShortNames is a global list you have created for this purpose.

 

Then, when you need to recover the full name for some reason, you refer to ShortNames, as in

    listen(integer channel, string name, key id, string msg)    {        integer idx = llListFindList(ShortNames,[msg]);        if (~idx)        {            llRezAtRoot(llList2String(ShortNames,idx+1),llGetPos() + <1.0,0.0,0.0>,ZERO_VECTOR,ZERO_ROTATION,12);        }    }

 

where you have rezzed the object that has the next highest index in ShortNames from the one you found.

  There are several disadvantages to using truncated names.   For example, several objects that share the same first 12 characters will end up with identical NewNames.  Also, truncated names are often ugly and hard to understand.

2.  So, the other option is to use numbered buttons instead of buttons with names on them.  Put the names into a list on the dialog box text.  Rather than explain how to do this, I suggest that you look at http://community.secondlife.com/t5/LSL-Library/Dialog-Choices-from-Numbered-Buttons/td-p/786825

  • Like 1
Link to comment
Share on other sites

Thank you very much. However, I'm a bit confused on how to add this into my script, so that I can have it do what it does now, which is look at the items in the inventory, generate a list, and then when I click on the button, it rezzes the object .5 meters above the container. I keep getting syntax errors, or in one case, the script compilied, but then wouldn't run at all. I'm VERY new to scripting, so a lot of what you said went over my head, to be honest. I'll keep plugging away at it, but if you could perhaps "dumb it down" a bit for me? I'm still learning. :D

 

If not, I still greatly appriecate the time you did take. Numbered buttons won't work for what I'm doing, but I did bookmark that link for further reading. 

Link to comment
Share on other sites

What I'm saying is that if you don't use a numbered list, which is more work up front but much more readable in the end, you can't just do what you have been doing.  The list you create by simply reading object names is always going to fail if you have names longer than 24 characters, and will be impractical if you have names with more than 12 characters.  You have to create a list of shortened names to use as button labels.

You can't use a list of shortened names when you want to rez objects, however, because you need to feed the full name into llRezAtRoot.  Therefore, you need to have a way to relate your shortened names to the full names.  That's why I suggested creating a list that does that.  Here's a more complete version of the listen event that I suggested earlier ....

listen(integer channel, string name, key id, string msg)    {        integer idx = llListFindList(ShortNames,[msg]);        if (~idx) // That is, if the message is also on the ShortNames list  ...        {            // ... identify the full name (the next name on the ShortNames list) and rez, using it instead.            llRezAtRoot(llList2String(ShortNames,idx+1),llGetPos() + <1.0,0.0,0.0>,ZERO_VECTOR,ZERO_ROTATION,12);        }        else  //On the other hand, if the message is NOT in ShortNames ...        {            //... go ahead and use the message itself            llRezAtRoot(msg,llGetPos() + <1.0,0.0,0.0>,ZERO_VECTOR,ZERO_ROTATION,12);        }    }

 See?  You need to create ShortNames as you are making your button list in the first place.  Your button list will include only the shortened names (because they're the ones that will fit on buttons) and the ShortNames list is the one you will have to use as I just described for the objects with longer names.

There are many other ways to accomplish the same thing, so this solution is not unique. 

 

Link to comment
Share on other sites

Cool.

BTW, that (~idx) part is shorthand.  (~idx ) = - ( idx + 1) .  That may not look any less confusing, but look at representative values of idx.  If idx = 1 or anything bigger than 1, (~idx) will be < -1.  Same thing if idx is more negative than -1. If idx = 0, then (~idx) = -1.  The only time when (~idx) = 0 is when idx = -1. 

So, if you are looking to see if llListFindList(ShortNames,[msg]) is TRUE, that is going to be the case for all values of idx >= 0.  It will be FALSE if idx = -1 , which is to say whenever [msg] is not in the ShortNames list.

You could accomplish the same thing in this case by writing if ( idx != -1) , since you know you don't have to worry about the case when idx < -1.

Link to comment
Share on other sites


Heather Moonwing wrote:

Ok, thank you very much for your help. Getting a syntax error at the 

 

if (~idx)    part, but I think I'm beginning to understand. Thank you so much for your help.

Add the missing semi-colon ( ) to the end of the line in Rolig's code that reads:

integer idx = llListFindList(ShortNames,[msg])
Link to comment
Share on other sites

np, we're all human (or neko, or furry, or ... :smileytongue:).

 

To the OP and any beginning coders, study http://lslwiki.net/lslwiki/wakka.php?wakka=debugging to get a handle on LSL's (usually) cryptic messages one will encounter when trying to save their efforts. It gives a good starting point on what may be wrong with your code and what may need corrected.

Link to comment
Share on other sites

lol, been years since i seen that menu script. You could untill you get to grips with script is be a bit hammer and watch and put the objects in another object that you can name and have it scripted to rezz the object inside.I.E have the object with a onrezz and delete it self, you be able to set the ofsets that way, becouse you strugging now never mind notecard reading.

Link to comment
Share on other sites

  • 2 weeks later...

 A little late coming to the party - the example you used is restricted to 2 pages
This script should handle any number of items and is customisable to a certain extent.  It is a cut down and adapted version of one I use for populating a dance hud.


Replace
// Dialog Based Object Rezzer Script// Susie Chaffe 2013// Free to use modify and mangle as you see fit // No Limit on Number of Object Names// Handles 24 character limit by creating alised object names// Has the option to create custom buttons / submenus if required// Is a little long winded for the sake of clarity //======================= SYSTEM VARIABLES ==========================// vector  vRezPos = <0.00, 0.00, 1.00>;integer dialogChannel;integer dialogHandle;integer iInvType = INVENTORY_OBJECT;integer iPageIdx = 0;list    lstShortName; //======================= CUSTOM FUNCTIONS ==========================// // Create Short name for Long Object Names and add to a look up list// Note that only the first 12 characters will normally show on the menu button// You can use a shorter substring if you preferstring AliasName(string sLongName){    string sShortName = (llGetSubString(sLongName,0,23));    lstShortName += [sShortName,sLongName];    return sShortName;} // Reorder Buttons as shown in listlist order(list buttons){    return llList2List(buttons, -3, -1) + llList2List(buttons, -6, -4) + llList2List(buttons, -9, -7) + llList2List(buttons, -12, -10);} // Dynamic menu dialog functiondoDialog(key av){    // Standard Buttons that will appear on every page - normally navigation buttons    list lstStatic = ["<< PREV","< MAIN >","NEXT >>"];    integer iBtnSlots = 12-llGetListLength(lstStatic)// Optional extra buttons that will only appear on the first page    // Can be used to create sub-menus if required    // list lstExtraBtn = []; // **Use this if you no extra buttons    list lstExtraBtn = ["-CONTENTS-"];  // ** This is just an example    integer iAdjSlots = llGetListLength(lstExtraBtn)// Dynamic buttons - read from inventory object names    integer iTotalNames = llGetInventoryNumber(iInvType)// Calculate menu last page index    integer iMaxPageIdx = (llFloor((float) (iTotalNames + iAdjSlots) / (float) iBtnSlots))// First & Last Page Navigation Toggle    if (iPageIdx < 0 ) iPageIdx = iMaxPageIdx;    else if (iPageIdx > iMaxPageIdx) iPageIdx = 0// Build the button list    list lstDialog = [];    lstShortName = [];    integer idxSlot = iPageIdx*iBtnSlots;     integer i;    // First menu page that has extra buttons    if((0 == iPageIdx) && ([] != lstExtraBtn))    {        for(i = idxSlot; (i < idxSlot+iBtnSlots-iAdjSlots) && (i <= iTotalNames-1 ); i++)        {            string sItemName = llGetInventoryName(iInvType,i);            if(24 < llStringLength(sItemName)) sItemName = AliasName(sItemName);            lstDialog += [sItemName];        }        //Add the Extra button(s)        lstDialog += lstExtraBtn;    }     // Other Pages or First Page if no extra buttons    else    {        for(i = idxSlot; (i < idxSlot+iBtnSlots) && (i <= iTotalNames-1 + iAdjSlots); i++)        {            string sItemName = llGetInventoryName(iInvType,i-iAdjSlots);            if(24 < llStringLength(sItemName)) sItemName = AliasName(sItemName);            lstDialog += [sItemName];        }    }     // Add Static Btns to the end of the Dyanamic List    lstDialog += lstStatic;     // Menu message    string msg = " \n Choose an Option: "  + "Page " + (string) (iPageIdx+1) + " of " + (string) (iMaxPageIdx + 1)//Open a Listen    dialogChannel = (integer)llFrand(DEBUG_CHANNEL)*-1;    dialogHandle = llListen(dialogChannel, "", "", "")// Call Function and set a time out for the listen    llDialog(av, msg , order(lstDialog), dialogChannel);    llSetTimerEvent(30.0);} close_menu(){    llSetTimerEvent(0);    llListenRemove(dialogHandle);} //=============================== RUN TIME =========================================// default{    touch_start(integer total_number)    {        key id = llDetectedKey(0);        close_menu();        doDialog(id);    }     listen( integer channel, string name, key id, string msg )    {        close_menu()if(msg == "< MAIN >")        {            iPageIdx=0;            doDialog(id);            return;        }         else if(msg == "<< PREV")        {            iPageIdx--;            doDialog(id);        }         else if(msg == "NEXT >>")        {            iPageIdx++;            doDialog(id);        }         else if(llGetInventoryType(msg) == 6)        {            llRezObject(msg, llGetPos() + vRezPos, ZERO_VECTOR, llGetRot(), 0);        }         else if(~llListFindList(lstShortName, [msg]))        {            integer idx = llListFindList(lstShortName, [msg]);            llRezObject(llList2String(lstShortName,idx+1), llGetPos() + vRezPos, ZERO_VECTOR, llGetRot(), 0);        }        // Example of Extra Button        else if(msg == "-CONTENTS-") llSay(0, "There are " + (string) llGetInventoryNumber(iInvType) + " items in this container");    }     timer()    {        close_menu();    }} //=============================================================================================//
Link to comment
Share on other sites

  • 6 months later...

Well i tried some of the code snippets here and it didn't worked for me as the list index exist of 2 names  (fullnameCuttedName)  so i wrote a script that make a couple of lists and make a dialog of the cutted names. and return full names by click a cutted name in dialog.

 

list avKeysInRegion; // all the avKeys in regionlist NEWavKeysInRegion; // all the keys without yourselfinteger numOfAvatars; // total avatars in regionlist fullNames; // full names listlist cuttedNames; // cutted names list for llDialoginteger listenChannel;integer listenHandle;listener(){// open listener and set timer    llListenRemove(listenHandle);    listenChannel = 0x80000000 | (integer)("0x"+(string)llGetKey());    listenHandle = llListen(listenChannel, "", "", "");    llSetTimerEvent(20);}// function that look for avatarslookForAvatars(){    avKeysInRegion = []; // empty this list first    NEWavKeysInRegion = []; // empty this list first        numOfAvatars = 0; // empty this integer first        fullNames = []; // empty this list first    cuttedNames = []; // empty this list first            avKeysInRegion = llGetAgentList(AGENT_LIST_REGION, []); // grab all keys in region    numOfAvatars = llGetListLength(avKeysInRegion) -1; // total number of avatars in region   -1 yourself        integer i; // counter    while (i < numOfAvatars) // while counter is lower then avatars in region    {        key id = llList2Key(avKeysInRegion, i); // grab keys ( its a while loop so go on till total avatars reached        string name = llKey2Name(id); // and offcourse their names from the    key id     above                    if( id != llGetOwner() ) // if the key is not owner key        {            fullNames += name; // fill fullNames list with the names of avatars in region            NEWavKeysInRegion += id; // fill in the new keys but without the key of yourself            cuttedNames += llGetSubString(name, 0, 11); // now fill the cuttedNames list for the llDialog        }        ++i; // count up till last avatar is reached    }        llDialog(llGetOwner(), "avatars", cuttedNames, listenChannel); // give dialog menu with the cuttedNames}default{    touch_start(integer total_number)    {        if( llDetectedKey(0) == llGetOwner() ) // if toucher is yourself        {            listener(); // trigger the listener function            lookForAvatars(); // then trigger the lookForAvatars function        }    }        listen(integer channel, string name, key id, string msg)    {        integer index = llListFindList(cuttedNames, [msg]); // returns -1 if not found        if(index != -1)        {// if index is higher then -1            llOwnerSay("\n---------------------------------\nYou choose: " + msg + "\nFullname: " + llList2String( fullNames, index ));                        llListenRemove(listenHandle);            llSetTimerEvent(0);        }    }        timer()    {        llSetTimerEvent(0);        llOwnerSay("You can close the dialog, the listener is removed anywayzzz");        llListenRemove(listenHandle);    }}

 



 

 

Offcourse this script does NOT handle more then 12 buttons but it is just a script so people can see how you can do this.

I know that some people like numeric buttons, i tried that and i found it not so nice, but for some items its better, for my item it look awfull, so i decided to use cutted names :)  this script i gonna build in more then 12 buttons offcourse but for now its just cuttednames to fullnames dialoger

 

Have fun:)  Climax Bailey

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 3736 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...