Jump to content

Multi Level Dialog based on Rolig's URL Selector


Carbon Philter
 Share

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

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

Recommended Posts

Hi all.
In my continuing quest to master LSL I need some more assistance, please.

I'm trying to construct an on-touch flag texture changer. I came across Rolig's URL dialog script in the Forum which I reckoned was a good starting point and so used that as the basis - my method of learning the intricacies of LSL involves cannibalising and cobbling available scripts in an attempt to understand their working.

As an aside, many thanks to Rolig and Void for making their work so freely available to us lesser scripting mortals

So I've managed to adapt the URL script to read a set of textures from a notecard list of countries and apply the textures to each side of a flag shaped prim on touch and selection from the dialog box list.
So far so good, and it works very satisfactorily, but the last piece of logic escapes me and some help would be much appreciated.

There are too many world countries to have all the flags read in as one single notecard so I have split them up to their respective continents and propose to have an initial dialog which first allows selection of the continent before going on to display the countries read from that continent's notecard.
I added the list of Continents at the outset and got the dialog to read that first. What happens now is the first dialog comes up and then flick on to the second dialog, which still functions with the list of country flags. I need the Continents dialog to wait for a response and, based on that response, make the variable 'gList', which was used to read the single inventory notecard, now equal the gList sub-variable so that the script can generate the approriate country dialog from that notecard.
Here's the script working for the single notecard.

 

//URL Chooser -- Rolig Loon -- February 2011

// Reads web site information from a notecard in the format   Site name = http://www.a_great_URL.com
// and presents result in a URL prompt.

list Continents = [" ", "Miscellany", " ", "N America", "Oceania", "S America", "Africa", "Asia", "Europe"];
integer menu; //variable to keep track of which menu is chosen
string country;

// Multipage dialog function uDlgBtnLst by Void Singer ( http://community.secondlife.com/t5/LSL-Scripting-Library/Dynamic-Multi-page-Dialog-AKA-Pagination/m-... )
list uDlgBtnLst( integer vIntPag )
{
    integer vIdxBeg = 10 * (~-vIntPag);          //-- 10 * (vIntPag - 1), enclose "~-X" in parens to avoid LSL bug
    integer vIdxMax = -~(~([] != gLstMnu) / 10); //-- (llGetListLength( gLstMnu ) - 1) / 10 + 1
    list vLstRtn =
      llListInsertList(
        llList2List( gLstMnu, vIdxBeg, vIdxBeg + 9 ), //-- grab 10 dialog buttons
        (list)("  <<---(" + (string)(vIntPag + (-(vIntPag > 1) | vIdxMax - vIntPag)) + ")"), //-- back button
        -1 ) + //-- inserts back button at index 9, pushing the last menu item to index 10
      (list)("  (" + (string)(-~((vIntPag < vIdxMax) * vIntPag)) + ")--->>"); //-- add fwd button at index 11
   
    return //-- fix the order to L2R/T2B
      llList2List( vLstRtn, -3, -1 ) + llList2List( vLstRtn, -6, -4 ) +
      llList2List( vLstRtn, -9, -7 ) + llList2List( vLstRtn, -12, -10 );
}

//--                       Anti-License Text                         --//*/
//     Contributed Freely to the Public Domain without limitation.     //*/
//   2009 (CC0) [ http://creativecommons.org/publicdomain/zero/1.0 ]   //*/
//  Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ]  //*/
//--

list gLstMnu;
integer gLine;
string gCard;
string gCard1;
string gCard2;
string gCard3;
string gCard4;
string gCard5;
string gCard6;
integer gDChan;
integer gDLisn;
key gQuery;
integer gCount;
list Sites;
list Tex1;
list Tex2;
list gDlabels;

default
{
    state_entry()
    {
        if (llGetInventoryNumber(INVENTORY_NOTECARD) > 0)
        {
            gCard = llGetInventoryName(INVENTORY_NOTECARD,0);
            gQuery =llGetNotecardLine(gCard,0);
            gCard1 = llGetInventoryName(INVENTORY_NOTECARD,1);
            gCard2 = llGetInventoryName(INVENTORY_NOTECARD,2);
            gCard3 = llGetInventoryName(INVENTORY_NOTECARD,3);
            gCard4 = llGetInventoryName(INVENTORY_NOTECARD,4);
            gCard5 = llGetInventoryName(INVENTORY_NOTECARD,5);
            gCard6 = llGetInventoryName(INVENTORY_NOTECARD,6);
            gCount = 1;
        }
        else
        {
            llOwnerSay("No Flag notecard detected.");
        }
    }
    
    changed (integer change)
    {
        if (change & CHANGED_INVENTORY)
        {
            llResetScript();
        }
    }
    
    dataserver(key qID, string data)
    {
        if (qID == gQuery)
        {
            if (data != EOF)
            {
                integer idx = llSubStringIndex(data,"=");
                if (~idx)
                {
                    Sites += [llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM)];  //Site names from NC
                    Tex1 += [llStringTrim(llGetSubString(data,idx+1,idx+37),STRING_TRIM)];  //Texture from NC
                    Tex2 += [llStringTrim(llGetSubString(data,idx+39,-1),STRING_TRIM)];  //Flip texture from NC
                    gDlabels += [(string)gCount + ". " +llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM) + " \n"]; //Dialog text
                    gLstMnu += [(string)gCount]; // Button labels
                    ++gCount;
                }
                gQuery = llGetNotecardLine(gCard,++gLine);
            }
            else
            {
                llSay(0,"Initialized.");
                state running;
            }
        }
    }
}
                
state running
{
    changed (integer change)
    {
        if (change & CHANGED_INVENTORY)
        {
            llResetScript();
        }
    }
    
    touch_start(integer num)
    {
        if (llDetectedOwner(0) == llGetOwner())
        {
//         menu = 0;   //show main menu, called Continents
        gDChan = (integer)("0xF" + llGetSubString(llDetectedKey(0),0,6));
        llDialog(llDetectedKey(0), "\n\nSelect the Continent for Country flags", Continents, gDChan);       
        llSetTimerEvent(10.0);
//        gDChan = (integer)("0xF" + llGetSubString(llDetectedKey(0),0,6));
        gDLisn = llListen(gDChan,"","","");
        string temp = "";
        integer i;
        //Display the first 10 sites in dialog
        for (i=0;i<10;++i)
            {
            temp += llList2String(gDlabels,i);
            }
        llDialog(llDetectedKey(0),"Which country do you want to display? \n"+ temp, uDlgBtnLst(1) ,gDChan);
        }
    }
    
    listen (integer channel, string name, key id, string msg)
    {
        llSetTimerEvent(0.0);
        llListenRemove(gDLisn);
        // Has the user clicked either the ">>" or "<<" button?
        if (!llSubStringIndex( msg, "  " ))  //-- detects 2 (hidden) leading spaces
        {
            llSetTimerEvent(10.0);
            gDLisn = llListen(gDChan,"","","");
            string temp = "";
            integer menu =  (integer)llGetSubString( msg, -~llSubStringIndex( msg, "(" ), -1 );
            integer i;
            for (i=(10*(menu-1)-1);i<(10*menu);++i)
            {
                temp += llList2String(gDlabels,i);
            }
            llDialog( id, "Which country do you want to visit? \n"+ temp, uDlgBtnLst(menu), gDChan );
        }
        else // If user has clicked a numbered button
        {
        integer Choice = (integer) msg -1;
        llSetTexture(llList2String(Tex1,Choice),4);
        llSetTexture(llList2String(Tex2,Choice),2);
        }
    }
    
    timer()
    {
        llSetTimerEvent(0.0);
        llWhisper(0,"Timeout. Please close the dialog box on your screen.");
        llListenRemove(gDLisn);
    }      
}

Apologies for any untidiness - work in progress.  :)


By my reckoning I need to use an if/else sequence from the Continents dialog to make the script read from the appropriate notecard list and I made several attempts failed miserably. I don't know if it's because the variable I'm trying to set is in the wrong sequence to register with the rest of the script or I'm getting my llListen set up wrong.

Worst case scenario I reckon I could set up a master script to switch on/off one of a series of scripts based on the Continents dialog and pass a message to trigger the country selection dialog but that strikes me as a bit messy so I'm hoping there's just some simple step I'm missing.

I hope this all makes sense.
Thanks.
Carbon

Link to comment
Share on other sites

State default, as it is written, is where you are going to be reading each notecard as you need it.  The way it's structured right now, it will always read the first notecard in inventory, no matter what, because that's the one defined as gCard. So, the first thing you have to do is think through how you are going to find the right one when you need it later.  It would be handy if they were named alphabetically so that they end up in inventory in the same order as the elements in your global list called Continents.   If that were the case, then you could use the Continents elements as dialog button labels and just say

 

if(message == "Africa"){    gCard = llGetInventoryName(INVENTORY_NOTECARD,6);}

 That's not the only approach, but it's a handy one.

In any case, your first llDialog call has to present you with the choice of notecards to read.  Suppose the user clicks the "Africa" button ....  The listen event in state running should be prepared to recognize that response and then send the script back to read the correct notecard.  Without messing with the way your script is already structured, that would be something like

if(message == "Africa"){    gCard = llGetInventoryName(INVENTORY_NOTECARD,6);    gLine = 0;    state default;}

 Now you're back in state default, where you read the proper notecard.  When that's done and you have loaded a new array of button labels from the contents of the notecard, you need to get back to state running.  As you do it, be sure that you have set some kind of flag (gCountries) that says "OK, now I'm not presenting a Continents dialog.  This is a Countries dialog." That way, when you pop back to state running again, there's something in the touch_start event that says

 

if (gCountries == TRUE){    llDialog(llDetectedKey(0),"Which country do you choose?", country_buttons,gDChan);}

 And the listen event is prepared to know that to do if it hears one of the new button names.

Working through the logic of something like this can be a bit of a challenge, but this is where the heart of scripting is --- follwing your nose along the logical path that you want the script to execute. 

There are some things you can do to make life easy for yourself.  When I have to do something like this, for example, I tend to prefer using numbers as button labels instead of using lists of names that (1) don't fit on the buttons and (2) are a bear to keep track of.  As I read each line of data from the notecard, I build two lists. One will end up being used to create the text in the dialog box and the other, which will be the button labels, just adds a new number for each notecard line: ["1","2","3","4","5"] and so on.  Then when I need to evaluate the result of a dialog button push, I can write something like

llSetTexture(llList2String(Tex1,(integer)message - 1),4);

and can be confident that pressing button #5 will apply the 4th texture listed in list Tex1.

 

 

Link to comment
Share on other sites

Thanks for replying, Rolig.

Your last comment about numbered buttons is what attracted me to your combined script with Void's - after getting to the selected continent it has the potential to present the user with a list of numbers with corresponding country names so the selection buttons just have the numbers to click - the likes of 'St Kitts & Nevis' won't fit on any button!  :)

However I'm afraid I'm still confused, maybe even more so.

I think I understand the process you are explaining but states and how they work in sequence or loop round confuses the hell out of me.

I get the principle of reacting to the Continent button pressed to feed in the appropriate notecard to be read, but my reading of your comment is that I would put that in state running which is after the default state entry section which has the initial check as to whether there is a card in inventory and if so to read that as the data source before stepping on to the dataserver event. If I don't define gCard first time round I get a script load error reporting Notecard could not be found and the script simply won't run as dataserver has nothing to work with.
As such, I can't see how I get to state running to make the Continent choice then bounce back to state default to get the dataserver event to read the particular notecard contents.

Here's the furthe hacked script in which I remmed out the gCard definition line and which compiles ok but gives me the load error:

//URL Chooser -- Rolig Loon -- February 2011// Reads web site information from a notecard in the format   Site name = http://www.a_great_URL.com// and presents result in a URL prompt.list Continents = [" ", "Miscellany", " ", "N America", "Oceania", "S America", "Africa", "Asia", "Europe"];integer menu; //variable to keep track of which menu is chosenstring country;// Multipage dialog function uDlgBtnLst by Void Singer ( http://community.secondlife.com/t5/LSL-Scripting-Library/Dynamic-Multi-page-Dialog-AKA-Pagination/m-... )list uDlgBtnLst( integer vIntPag ){    integer vIdxBeg = 10 * (~-vIntPag);          //-- 10 * (vIntPag - 1), enclose "~-X" in parens to avoid LSL bug    integer vIdxMax = -~(~([] != gLstMnu) / 10); //-- (llGetListLength( gLstMnu ) - 1) / 10 + 1    list vLstRtn =      llListInsertList(        llList2List( gLstMnu, vIdxBeg, vIdxBeg + 9 ), //-- grab 10 dialog buttons        (list)("  <<---(" + (string)(vIntPag + (-(vIntPag > 1) | vIdxMax - vIntPag)) + ")"), //-- back button        -1 ) + //-- inserts back button at index 9, pushing the last menu item to index 10      (list)("  (" + (string)(-~((vIntPag < vIdxMax) * vIntPag)) + ")--->>"); //-- add fwd button at index 11       return //-- fix the order to L2R/T2B      llList2List( vLstRtn, -3, -1 ) + llList2List( vLstRtn, -6, -4 ) +      llList2List( vLstRtn, -9, -7 ) + llList2List( vLstRtn, -12, -10 );}//--                       Anti-License Text                         --//*///     Contributed Freely to the Public Domain without limitation.     //*///   2009 (CC0) [ http://creativecommons.org/publicdomain/zero/1.0 ]   //*///  Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ]  //*///--list gLstMnu;integer gLine;string gCard;string gCard1;string gCard2;string gCard3;string gCard4;string gCard5;string gCard6;integer gDChan;integer gDLisn;key gQuery;integer gCount;list Sites;list Tex1;list Tex2;list gDlabels;default{    state_entry()    {        if (llGetInventoryNumber(INVENTORY_NOTECARD) > 0)        {//            gCard = llGetInventoryName(INVENTORY_NOTECARD,5);            gQuery =llGetNotecardLine(gCard,0);            gCount = 1;        }        else        {            llOwnerSay("No Flag notecard detected.");        }    }        changed (integer change)    {        if (change & CHANGED_INVENTORY)        {            llResetScript();        }    }        dataserver(key qID, string data)    {        if (qID == gQuery)        {            if (data != EOF)            {                integer idx = llSubStringIndex(data,"=");                if (~idx)                {                    Sites += [llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM)];  //Site names from NC                    Tex1 += [llStringTrim(llGetSubString(data,idx+1,idx+37),STRING_TRIM)];  //Texture from NC                    Tex2 += [llStringTrim(llGetSubString(data,idx+39,-1),STRING_TRIM)];  //Flip texture from NC                    gDlabels += [(string)gCount + ". " +llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM) + " \n"]; //Dialog text                    gLstMnu += [(string)gCount]; // Button labels                    ++gCount;                }                gQuery = llGetNotecardLine(gCard,++gLine);            }            else            {                llSay(0,"Initialized.");                llSay(0,gCard);                state running;            }        }    }}                state running{    changed (integer change)    {        if (change & CHANGED_INVENTORY)        {            llResetScript();        }    }        touch_start(integer num)    {        if (llDetectedOwner(0) == llGetOwner())        {//         menu = 0;   //show main menu, called Continents        gDChan = (integer)("0xF" + llGetSubString(llDetectedKey(0),0,6));        llDialog(llDetectedKey(0), "\n\nSelect the Continent for Country flags", Continents, gDChan);               llSetTimerEvent(10.0);        gDLisn = llListen(gDChan,"","","");        string temp = "";        integer i;        //Display the first 10 sites in dialog        for (i=0;i<10;++i)            {            temp += llList2String(gDlabels,i);            }//        llDialog(llDetectedKey(0),"Which country do you want to display? \n"+ temp, uDlgBtnLst(1) ,gDChan);        }    }        listen (integer channel, string name, key id, string msg)    {    llSetTimerEvent(0.0);            if(msg == "Africa")        {            gCard = llGetInventoryName(INVENTORY_NOTECARD,0);            gQuery =llGetNotecardLine(gCard,0);            gLine = 0;            state default;        }        else if(msg == "Asia")        {            gCard = llGetInventoryName(INVENTORY_NOTECARD,1);            gQuery =llGetNotecardLine(gCard,0);            gLine = 0;            state default;        }        else if(msg == "Europe")        {            gCard = llGetInventoryName(INVENTORY_NOTECARD,2);            gQuery =llGetNotecardLine(gCard,0);    gLine = 0;            state default;        }        else if(msg == "N America")        {            gCard = llGetInventoryName(INVENTORY_NOTECARD,4);            gQuery =llGetNotecardLine(gCard,0);            gLine = 0;            state default;        }        else if(msg == "Oceania")        {            gCard = llGetInventoryName(INVENTORY_NOTECARD,5);            gQuery =llGetNotecardLine(gCard,0);            gLine = 0;            state default;        }        else if(msg == "S America")        {            gCard = llGetInventoryName(INVENTORY_NOTECARD,6);            gQuery =llGetNotecardLine(gCard,0);            gLine = 0;            state default;        }        else if(msg == "Miscellany")        {            gCard = llGetInventoryName(INVENTORY_NOTECARD,3);            gQuery =llGetNotecardLine(gCard,0);            gLine = 0;            state default;        }        llListenRemove(gDLisn);        // Has the user clicked either the ">>" or "<<" button?        if (!llSubStringIndex( msg, "  " ))  //-- detects 2 (hidden) leading spaces        {            llSetTimerEvent(10.0);            gDLisn = llListen(gDChan,"","","");            string temp = "";            integer menu =  (integer)llGetSubString( msg, -~llSubStringIndex( msg, "(" ), -1 );            integer i;            for (i=(10*(menu-1)-1);i<(10*menu);++i)            {                temp += llList2String(gDlabels,i);            }            llDialog( id, "Which country do you want to visit? \n"+ temp, uDlgBtnLst(menu), gDChan );        }        else // If user has clicked a numbered button        {        integer Choice = (integer) msg -1;        llSetTexture(llList2String(Tex1,Choice),4);        llSetTexture(llList2String(Tex2,Choice),2);        }    }        timer()    {        llSetTimerEvent(0.0);        llWhisper(0,"Timeout. Please close the dialog box on your screen.");        llListenRemove(gDLisn);    }      }

 

Sorry - scripting is not my natural environment, I guess. Could you please indulge/spoon feed me further and add any additional details which will help me comprehend the process.

Link to comment
Share on other sites

OK, here's a semi-schematic of the top part of your script.  I left out Void's multipagination function and a bunch  of other stuff, to just focus on the logical flow through the start of the dialogs. I'll assume that your notecards are named in the same alphabetical order as the elements in the list called gContinents below.  That's important, so that we know which card to read.  Notice, among other things, that this means we don't need that stack of names gCard1, gCard2, etc.

This is only schematic, and probably has a typo or two......

list gContinents = ["Africa","Asia","Europe","N America","Oceania","S America","Miscellany"];list gSites;list gTex1;list gTex2;list gLstMnu;list gDlabels;list Lbls;integer gRunOnce;integer gCrdNo;integer gCount;integer gLine;string gCard;key gQuery;default{	state_entry()	{		if(!gRunOnce)	//This is the first time through		{			if (llGetInventoryNumber(INVENTORY_NOTECARD))	//There are no notecards present			{				llOwnerSay("No Flag notecard detected.");			}			else			{				gQuery =llGetNotecardLine(llGetInventoryName(INVENTORY_NOTECARD,0),0);				gCrdNo = 0;	//Reading card #0				gCount = 1;	//Set index for first line in dialog box text			}		}		else	//Not the first time through. Just read the chosen card.		{			gCount = 1;	//Set index for first line in dialog box text			gQuery = llGetNotecardLine(gCard,0);		}	}	dataserver(key qID, string data)	{		if (qID == gQuery)		{			if (data != EOF)			{				integer idx = llSubStringIndex(data,"=");				if (~idx)				{					gSites += [llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM)];  //Site names from NC					gTex1 += [llStringTrim(llGetSubString(data,idx+1,idx+37),STRING_TRIM)];  //Texture from NC					gTex2 += [llStringTrim(llGetSubString(data,idx+39,-1),STRING_TRIM)];  //Flip texture from NC					gDlabels += [(string)gCount + ". " +llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM) + " \n"]; //Dialog text					gLbls += [(string)gCount]; // Button labels					++gCount;				}				gQuery = llGetNotecardLine(gCard,++gLine);			}			else			{				llSay(0,"Card " + gCard + " reading complete.");				state running;			}		}	}}state running{	state_entry()	{		gRunOnce = TRUE; //You've determined that there are notecards present. No need to do it again.	}	touch_start(integer num)	{		if(llDetectedKey(0) == llGetOwner())		{			gDChan = (integer)("0xF" + llGetSubString(llGetOwner(),0,6));			gDLsn = llListen(gDChan,"","","");			llDialog(llGetOwner(),"Pick a continent.",gContinents,gDChan); //Always start with a continent dialog		}	}	listen (integer channel, string name, key id, string msg)	{		if (~channel = llListFindList(gContinents,[msg])    //Was this a Continent question ?		{			if(channel != gCrdNo)	//If the selected continent is not the one we read last time ....			{				gCrdNo = channel;	//We've selected a different continent, so empty all the lists first				gSites = [];				gTex1 = [];				gTex2 = [];				gDlabels = [];				gLbls = [];	//Then ....				gCard = llGetInventoryName(INVENTORY_NOTECARD,gCrdNo);	//go back and read its card now.				state default;			}			else			{				// Do your country dialog based on the first ten lines of the current card			}		}		else	//The User has not just answered a Continent dialog question, so		{			//Did the user hit a << or >> button? If so advance page or go back //Else //What texture did the user choose? Act on the choice.		}	}}

  So, that first if test at the top of the listen event in state running always tests to see if you chose a continent. If you did, and if it's not the same continent you read the last time, it goes back to state default and reads the new continent's notecard.  (This is a little clunky, because it means that the user will have to answer a Continent dialog question again, but this time he will be chosing the continent that was just read.  You could get around that extra click easily enough, but for now ...)  If the user selected the continent that was read most recently, then you present him with a country dialog based on that continent's notecard.  From there on, it's straight sailing .... second star to the right and straight on till morning.

Link to comment
Share on other sites

Many thanks once again, Rolig. I'm not going to have so much time in the immediate future and your response may well take some serious time for me to absorb, so in the meantime, have a great festive season.

And re. the directional travel advice - it's going to take a shed load of pixie dust to get me off the ground scripting-wise let alone all the way to Never Never Land. I'm definitely one of the Lost Boys.  :D

Link to comment
Share on other sites

  • 3 weeks later...

Hi again everyone, and a Good New Year to all.
So after a break I'm back wrestling with scripting and my dialog/notecard problem in particular.

Rolig, I've read through your 'semi-schematic' example for a few times now. I believe I understand the process but I'm still falling over - no sudden flashbulb of total comprehension going off in my head - and I'm not sure why. I think I may be getting messed up with all the global variables.

I reckoned that your latest example should function even in a limited fashion, and so with a bit of tweaking to rectify what I thought was stopping it running - I added global variables integer gDChan and integer gDLsn which were referred to in the script body but couldn't be found, and I changed line 'if (llGetInventoryNumber(INVENTORY_NOTECARD))' to read: 'if (llGetInventoryNumber(INVENTORY_NOTECARD)<1)'.
I also added in a couple of OwnerSays to try and track progress. The script compiled ok so I dropped it in a prim with the notecards named to match the list.

The script started its initial run, and I got the two OwnerSays indicating that it was at least starting ok but it then threw up a script warning/error reporting "Could not find notecard ''."
I then fired it up in LSL Editor and ran debug to see if that would help me. It reported one alert - line 91: The left-hand side of an assignment must be a variable, property or indexer, which I have to admit doesn't help me any.

So with much apology I have to ask for further help to get me over this mental block I'm having. Is it anything to do with you maybe having used different global variable names in the semi-schematic you put together or could it even be the result of any typo which you mention could be a possibility.

Here's the script in it's current 'almost working' form.

list gContinents = ["1Africa","2Asia","3Europe","4N America","5Oceania","6S America","7Miscellany"];list gSites;list gTex1;list gTex2;list gLstMnu;list gDlabels;list gLbls;integer gRunOnce;integer gCrdNo;integer gCount;integer gLine;integer gDChan;integer gDLsn;string gCard;key gQuery;default{    state_entry()    {        if(!gRunOnce)    //This is the first time through        {            if (llGetInventoryNumber(INVENTORY_NOTECARD)<1)    //There are no notecards present            {                llOwnerSay("No Flag notecard detected.");            }            else            {                llOwnerSay("Read script this far");                gQuery =llGetNotecardLine(llGetInventoryName(INVENTORY_NOTECARD,0),0);                gCrdNo = 0;    //Reading card #0                gCount = 1;    //Set index for first line in dialog box text                llOwnerSay( llGetInventoryName(INVENTORY_NOTECARD,0));//                llOwnerSay(gcard);            }        }        else    //Not the first time through. Just read the chosen card.        {            gCount = 1;    //Set index for first line in dialog box text            gQuery = llGetNotecardLine(gCard,0);        }    }    dataserver(key qID, string data)    {        if (qID == gQuery)        {            if (data != EOF)            {                integer idx = llSubStringIndex(data,"=");                if (~idx)                {                    gSites += [llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM)];  //Site names from NC                    gTex1 += [llStringTrim(llGetSubString(data,idx+1,idx+37),STRING_TRIM)];  //Texture from NC                    gTex2 += [llStringTrim(llGetSubString(data,idx+39,-1),STRING_TRIM)];  //Flip texture from NC                    gDlabels += [(string)gCount + ". " +llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM) + " \n"]; //Dialog text                    gLbls += [(string)gCount]; // Button labels                    ++gCount;                }                gQuery = llGetNotecardLine(gCard,++gLine);            }            else            {                llSay(0,"Card " + gCard + " reading complete.");                state running;            }        }    }}state running{    state_entry()    {        gRunOnce = TRUE; //You've determined that there are notecards present. No need to do it again.    }    touch_start(integer num)    {        if(llDetectedKey(0) == llGetOwner())        {            gDChan = (integer)("0xF" + llGetSubString(llGetOwner(),0,6));            gDLsn = llListen(gDChan,"","","");            llDialog(llGetOwner(),"Pick a continent.",gContinents,gDChan); //Always start with a continent dialog        }    }    listen (integer channel, string name, key id, string msg)    {        if (~channel = llListFindList(gContinents,[msg]))    //Was this a Continent question ?        {                if(channel != gCrdNo)    //If the selected continent is not the one we read last time ....            {                gCrdNo = channel;    //We've selected a different continent, so empty all the lists first                gSites = [];                gTex1 = [];                gTex2 = [];                gDlabels = [];                gLbls = [];    //Then ....                gCard = llGetInventoryName(INVENTORY_NOTECARD,gCrdNo);    //go back and read its card now.                state default;            }            else            {                // Do your country dialog based on the first ten lines of the current card            }        }        else    //The User has not just answered a Continent dialog question, so        {            //Did the user hit a << or >> button? If so advance page or go back //Else //What texture did the user choose? Act on the choice.        }    }}

 




Thanks once again.
Carbon

Link to comment
Share on other sites

That's my typo on the line that's kicking up an error.  Sorry.  :smileyembarrassed:  It should be

        if (~(channel = llListFindList(gContinents,[msg])))
 
This is a compressed if test. First, it's asking whether the button that the user just clicked has a label (msg) that matches anything in the gContinents list.  Then, the statement is saving whatever that index is and assigning it to the variable channel, so that we can use it in the next if test ...

                if(channel != gCrdNo)

to see whether this is the same index that we found the last time we checked.  Finally, we use the ~ operator on the entire quantity (channel = llListFindList(gContinents,[msg])), because we want to count any index that is >= 0 as TRUE. (Re-using channel is a bit of a no-no if you are a scripting pro, but it saves us defining yet another throwaway integer variable here.  Besides, we aren't using channel for anything else anyway.  You can thank Void for this one.  I just stole the idea.)

Edited for clarity (and because a kind friend pointed out that I screwed up on my first try at a response). :smileysurprised:

Link to comment
Share on other sites

  • 1 month later...

Hi Rolig.

Apologies to resurrect this thread - I had hoped your last advice was going to be enough to resolve my problems.

After a time away to get my head round easier things such as quantum physics and diy brain surgery, I readdressed the issue but am still stumped. I made the amendment you indicated to the part script but continue to get an error - Could not find notecard ''.

I did some more reading on the wiki and tracked down what I suspect might be the cause. On the page covering llGetNotecardLine I see that "If name is not a valid notecard, or if the notecard is empty, the object will print to the Script Errors/Warning window, "Couldn't find notecard NAME" where "NAME" is the name of the invalid notecard." I'm sorry, but I've stared at the script until I'm going cross eyed and can't see where it's going wrong and not finding the name of the notecard.

I confess I copped out and came up with a clunky alternative using a master 'Continents' dialog to switch on/off other single continent scripts which pull up the dialog options as desired. It seems to work ok after I wait for the various bits to initialise but I reckon that to 'real' scripters it looks like the work of the devil and is something to be avoided like the plague.

So........... In the increasingly unlikely case that I'll ever understand scripting properly, once again I rely on your good grace and tolerance to ask if you can help and pinpoint where the script is not seeing the notecard correctly.

Many thanks.

Carbon

For completeness sake the script which still throws up the error is as follows:

list gContinents = ["1Africa","2Asia","3Europe","4N America","5Oceania","6S America","7Miscellany"];list gSites;list gTex1;list gTex2;list gLstMnu;list gDlabels;list gLbls;integer gRunOnce;integer gCrdNo;integer gCount;integer gLine;integer gDChan;integer gDLsn;string gCard;key gQuery;default{    state_entry()    {        if(!gRunOnce)    //This is the first time through        {            if (llGetInventoryNumber(INVENTORY_NOTECARD)<1)    //There are no notecards present            {                llOwnerSay("No Flag notecard detected.");            }            else            {                llOwnerSay("Read script this far");                gQuery = llGetNotecardLine(llGetInventoryName(INVENTORY_NOTECARD,0),0);                gCrdNo = 0;    //Reading card #0//                gCard = 0;                gCount = 1;    //Set index for first line in dialog box text                llOwnerSay( llGetInventoryName(INVENTORY_NOTECARD,0));                llOwnerSay((string)gQuery);            }        }        else    //Not the first time through. Just read the chosen card.        {            gCount = 1;    //Set index for first line in dialog box text            gQuery = llGetNotecardLine(gCard,0);        }    }    dataserver(key qID, string data)    {        if (qID == gQuery)        {            if (data != EOF)            {                integer idx = llSubStringIndex(data,"=");                if (~idx)                {                    gSites += [llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM)];  //Site names from NC                    gTex1 += [llStringTrim(llGetSubString(data,idx+1,idx+37),STRING_TRIM)];  //Texture from NC                    gTex2 += [llStringTrim(llGetSubString(data,idx+39,-1),STRING_TRIM)];  //Flip texture from NC                    gDlabels += [(string)gCount + ". " +llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM) + " \n"]; //Dialog text                    gLbls += [(string)gCount]; // Button labels                    ++gCount;                }                gQuery = llGetNotecardLine(gCard,++gLine);            }            else            {                llSay(0,"Card " + gCard + " reading complete.");                state running;            }        }    }}state running{    state_entry()    {        gRunOnce = TRUE; //You've determined that there are notecards present. No need to do it again.    }    touch_start(integer num)    {        if(llDetectedKey(0) == llGetOwner())        {            gDChan = (integer)("0xF" + llGetSubString(llGetOwner(),0,6));            gDLsn = llListen(gDChan,"","","");            llDialog(llGetOwner(),"Pick a continent.",gContinents,gDChan); //Always start with a continent dialog        }    }    listen (integer channel, string name, key id, string msg)    {        if (~(channel = llListFindList(gContinents,[msg])))    //Was this a Continent question ?        {                if(channel != gCrdNo)    //If the selected continent is not the one we read last time ....            {                gCrdNo = channel;    //We've selected a different continent, so empty all the lists first                gSites = [];                gTex1 = [];                gTex2 = [];                gDlabels = [];                gLbls = [];    //Then ....                gCard = llGetInventoryName(INVENTORY_NOTECARD,gCrdNo);    //go back and read its card now.                state default;            }            else            {                // Do your country dialog based on the first ten lines of the current card            }        }        else    //The User has not just answered a Continent dialog question, so        {            //Did the user hit a << or >> button? If so advance page or go back //Else //What texture did the user choose? Act on the choice.        }    }}

 

Link to comment
Share on other sites

You've done something funny with your gContinents list. I'm not sure why you put a digit at the start of each name in tyhe list.  It doesn't seem to be serving any purpose, and I doubt that your cards have those names. That's probably why the script is telling you that it can't find them.  As always, the heart of scripting is logic.  Assuming that you have a  readable (compilable) script, it will do exactly what you tell it to. You just have to be clear about what you mean.  The best way to find a spot where your logic is flawed is often to insert temporary llOwnerSay statements at key places and ask the script to tell you what it is doing there.  You'll find it.

Link to comment
Share on other sites

Thanks for encouragement, R.
Please bear with me as although I know it's all pure logic I don't find it straightforward with all the if/else divergences and varying states. I now know what Captain Kirk and the rest of the crew feels like when confronted by Mister Spock.

OK. Firstly, the reason the gContinents  list had numbers added was to ensure that the notecards, which are actually correctly titled the same as the list entries, was read in the same order. I took that from one of your earlier posts.

I did some more butchering to try and determine the main flow and added lots more OwnerSay's than I already had and got a bit further.I tracked the error report down to the dataserver event. On first pass it runs through the process of building up the Sites, Tex1, and Tex2 lists - or appears to do so - until it gets to the line: gQuery = llGetNotecardLine(gCard,++gLine);

So I guessed that gCard needs to be defined as whatever card is being read for that particular pass of the process. I put the line gCard = llGetInventoryName(INVENTORY_NOTECARD,gCrdNo); in the first time run section of state entry() and it seems to go motoring. Now I'll have to reintroduce the rest of the script and see where that takes me.
C

Link to comment
Share on other sites

Hi again, Rolig and others.

Bear with me, please - it's all coming together very gradually, but I've run up against another puzzle.

I now have the initial card being read into memory ok - I used OwnerSay to report what has been defined as gSites, gTex1, gTex2, gDlabels, and gLbls, and they all report the whole notecard contents - so no memory constraint there. However, when I select a different Continent in the Dialog and the script goes back through to read the replacement notecard, it either only reads the first line, or skips a whole series of entries in the middle. I've tried substituting each notecard to be the initial read, and in each instance they are read without problem. It is only happening when the global variables are cleared and the selected new card is attempted to be read.

Is there anything obvious I'm missing - a script limit or truncation of data for some reason that would be causing this? Anything to do with speed of data transfer? I just can't see what would cause the reading process to skip.

Thanks once more

Carbon

Link to comment
Share on other sites

Just out of curiostity, how many other copies of the script do you have running in the same area while you are working on this one?  It sounds as if they are talking to each other.  I like using the owner's UUID as the basis for a unique communication channel, but doing that presumes that the owner doesn't have other scripts around that are doing the same thing.  Try changing the channel selection to, say

gDChan = -1* (10000 + (integer)llFrand(100000.0));

Link to comment
Share on other sites

Back again, and a step further on. Woohoo!!!!

I checked the comms channel and number of script copies running as you suggested and it wasn't that which was messing up.

I finally worked out that the sequential counter '++gLine' was continuing from where it left off on the previous run, so I added another line to reset it to 0 at the same time as clearing all the lists and it looks as if that hurdle is now cleared.

I suspect I'm not out of the woods yet but even curing this last problem has boosted my morale somewhat and I'm hopeful of ever more competent scripting skills.

:matte-motes-big-grin:

Link to comment
Share on other sites

Thank you, Rolig, for those kind words, and, as I said in my IM, my appreciation for all the assistance you and others have provided in this Forum.

I sent a copy of the flag selector to Rolig for her amusement but I realise that there may be others out there who persevered in following the thread and might wish to emulate or surpass (not difficult) my effort. I put a bit too much work into the flag textures to distribute them free but given the amount of collaborative assistance in here, the least I can do is make the script available.

I know it's not totally right yet - the Continents menu buttons and lists of flag textures have got out of sync and I need to mess about to correct that, aqnd I'd like the Country choice dialogue to come up automatically once the Continent is chosen but these should be relatively minor corrections by comparison with the achievement of getting the thing functioning in the first place.

If/when I get the last glitches sorted, I'll post it to the Library but I don't think I should do that until it's squeaky clean. So, for those who want to potter about and use the script as a basis for something else, here it is:

 

//Script cobbled together by Carbon Philter, March 2012, based originally on URL Chooser -- Rolig Loon -- February 2011// Reads texture information from notecards in the format   Country = textureUUID1, textureUUID2// and applies result to faces of a prim// Multipage dialog function uDlgBtnLst by Void Singer ( http://community.secondlife.com/t5/LSL-Scripting-Library/Dynamic-Multi-page-Dialog-AKA-Pagination/m-... )list uDlgBtnLst( integer vIntPag ){	integer vIdxBeg = 10 * (~-vIntPag);          //-- 10 * (vIntPag - 1), enclose "~-X" in parens to avoid LSL bug	integer vIdxMax = -~(~([] != gLbls) / 10); //-- (llGetListLength( gLstMnu ) - 1) / 10 + 1      list vLstRtn =      llListInsertList(        llList2List( gLbls, vIdxBeg, vIdxBeg + 9 ), //-- grab 10 dialog buttons        (list)("  <<---(" + (string)(vIntPag + (-(vIntPag > 1) | vIdxMax - vIntPag)) + ")"), //-- back button        -1 ) + //-- inserts back button at index 9, pushing the last menu item to index 10     	(list)("  (" + (string)(-~((vIntPag < vIdxMax) * vIntPag)) + ")--->>"); //-- add fwd button at index 11	return //-- fix the order to L2R/T2B      llList2List( vLstRtn, -3, -1 ) + llList2List( vLstRtn, -6, -4 ) +      llList2List( vLstRtn, -9, -7 ) + llList2List( vLstRtn, -12, -10 );}//--                       Anti-License Text                         --//*///     Contributed Freely to the Public Domain without limitation.     //*///   2009 (CC0) [ http://creativecommons.org/publicdomain/zero/1.0 ]   //*///  Void Singer [ https://wiki.secondlife.com/wiki/User:Void_Singer ]  //*///--list gContinents = ["Africa","Asia","Europe","N America","Oceania","S America","Miscellany"];list gSites;list gTex1;list gTex2;list gLstMnu;list gDlabels;list gLbls;integer gRunOnce;integer gCrdNo;integer gCount;integer gLine;integer gDChan;integer gDLsn;string gCard;key gQuery;default{    state_entry()    {        if(!gRunOnce)    //This is the first time through        {            if (llGetInventoryNumber(INVENTORY_NOTECARD)<1)    //There are no notecards present            {                llOwnerSay("No Flag notecard detected.");            }            else            {                gQuery = llGetNotecardLine(llGetInventoryName(INVENTORY_NOTECARD,0),0);                gCrdNo = 0;    //Reading card #0                gCard = llGetInventoryName(INVENTORY_NOTECARD,gCrdNo);                gCount = 1;    //Set index for first line in dialog box text            }        }        else    //Not the first time through. Just read the chosen card.        {            gCount = 1;    //Set index for first line in dialog box text            gQuery = llGetNotecardLine(gCard,0);        }    }    dataserver(key qID, string data)    {        if (qID == gQuery)        {            if (data != EOF)            {                integer idx = llSubStringIndex(data,"=");                if (~idx)                {                    gSites += [llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM)];  //Site names from NC                    gTex1 += [llStringTrim(llGetSubString(data,idx+1,idx+37),STRING_TRIM)];  //Texture from NC                    gTex2 += [llStringTrim(llGetSubString(data,idx+39,-1),STRING_TRIM)];  //Flip texture from NC                    gDlabels += [(string)gCount + ". " +llStringTrim(llGetSubString(data,0,idx-1),STRING_TRIM) + " \n"]; //Dialog text                    gLbls += [(string)gCount]; // Button labels                    ++gCount;                }                gQuery = llGetNotecardLine(gCard,++gLine);            }            else            {                llSay(0,"Card " + gCard + " reading complete.");                state running;            }        }    }}state running{    state_entry()    {        gRunOnce = TRUE; //You've determined that there are notecards present. No need to do it again.    }    touch_start(integer num)    {        if(llDetectedKey(0) == llGetOwner())        {            gDChan = (integer)("0xF" + llGetSubString(llGetOwner(),0,6));            gDLsn = llListen(gDChan,"","","");            llDialog(llGetOwner(),"Pick a continent.", gContinents, gDChan); //Always start with a continent dialog        }    }    listen (integer channel, string name, key id, string msg)    {        if (~(channel = llListFindList(gContinents,[msg])))    //Was this a Continent question ?        {                if(channel != gCrdNo)    //If the selected continent is not the one we read last time ....            {                gCrdNo = channel;    //We've selected a different continent, so empty all the lists first                gSites = [];                gTex1 = [];                gTex2 = [];                gDlabels = [];                gLbls = [];    //Then ....                gCard = llGetInventoryName(INVENTORY_NOTECARD,gCrdNo);                gLine = 0;    //go back and read its card now.                state default;            }            else            {// Do your country dialog based on the first ten lines of the current card        string temp = "";        integer i;//Display the first 10 sites in dialog        for (i=0;i<10;++i)            {            temp += llList2String(gDlabels,i);            }                    llDialog(llGetOwner(),"Which country do you want to display? \n"+ temp, uDlgBtnLst(1) ,gDChan);            }        }        else    //The User has not just answered a Continent dialog question, so        {            //Did the user hit a << or >> button? If so advance page or go back //Else //What texture did the user choose? Act on the choice.                if (!llSubStringIndex( msg, "  " ))  //-- detects 2 (hidden) leading spaces        {            llSetTimerEvent(10.0);            gDLsn = llListen(gDChan,"","","");            string temp = "";            integer menu =  (integer)llGetSubString( msg, -~llSubStringIndex( msg, "(" ), -1 );            integer i;            for (i=(10*(menu-1)-1);i<(10*menu);++i)            {                temp += llList2String(gDlabels,i);            }            llDialog( id, "Which country do you want to visit? \n"+ temp, uDlgBtnLst(menu), gDChan );        }        else // If user has clicked a numbered button        {         integer Choice = (integer) msg -1;         llSetTexture(llList2String(gTex1,Choice),4);         llSetTexture(llList2String(gTex2,Choice),2);        }    }}}

 Thanks, and rest assured - I'll be back for more assistance on other scripting problems.

Carbon

Link to comment
Share on other sites

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