Jump to content
Kai Sirenz

llDialog questions!

Recommended Posts

Hi, I'm new to LSL and I'm trying to work on a Dialog box, that opens another dialog box when an option is clicked, I'm looking at the Wiki examples, the "primitive" one I can understand and follow quite well but the more advanced one I can't, but even with the basic one I can't work out how to call a second Dialog box when an option  is pressed!

My biggest issue is that I can't understand where in the script it actually *tells* the box what to do with each button? When I close the first if statement every option just prints "!shoot" - been trying to solve it for hours and it's giving me a headache now, any help would be appreciated!

list buttons = ["Weapons", "Music", "Return"];
string dialogInfo = "\nHow can I help you?.";
 
key ToucherID;
integer dialogChannel;
integer listenHandle;
 
default
{
    state_entry()
    {
        dialogChannel = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );
    }
 
    touch_start(integer num_detected)
    {
        ToucherID = llDetectedKey(0);
        llListenRemove(listenHandle);
        listenHandle = llListen(dialogChannel, "", ToucherID, "");
        llDialog(ToucherID, dialogInfo, buttons, dialogChannel);
        llSetTimerEvent(60.0); // Here we set a time limit for responses
    }
 
    listen(integer channel, string name, key id, string message)
    {
        if (message == "Programs")
        {       
            //string dialogInfo = "\nWhich function should I perform?");
            //list buttons = ["R000", "R030", "R050"];
            //llSay(dialogChannel,"Programs Selected)"
        }
            if (message = "R000")
            {
                llSay(0,"!shoot");
            }
            else if (message == "R030")
            {
                llSay(0,"This function is not operable yet.");
            }
            else if (message == "R050")
            {
                llSay(0,"This function is not operable yet.");
            }
        else if (message == "Music")
        {
            llSay(0,"This function is not Operable yet.");
        }
        else if (message == "Return")
        {
            llSay(0,"Until next time.");
        }
    }

 
    timer()
    {
    //  stop timer
        llSetTimerEvent(0);
 
        llListenRemove(listenHandle);
        llWhisper(0, "Sorry. You snooze; you lose.");
    }
} 

 

Share this post


Link to post
Share on other sites

The way menus work is that they give the user's viewer a channel (the menu's channel), and when you click a button, your viewer will say the button name on the given channel.

So, for the script to know which button was clicked and what to do with that button, it needs to be listening on the menu channel and do things based on which message (button name) it heard.

Since clicking on a button closes the menu and causes the avatar to speak on the menu channel, you can put an llDialog into the listen event, either before or after all of the if checks. This way the user will get a new menu every time they click a button.

Share this post


Link to post
Share on other sites

so I need to call llDialog for each new menu I want to work? I'm still a bit confused, I tried adding llDialog before if r000 and it didnt work!

Edited by Kai Sirenz

Share this post


Link to post
Share on other sites

Kai,

 

Your if structure was incorrect, and yes .. you need to call dialog each time you want a menu .. the below should work:

list buttons = ["Weapons", "Music", "Return"];
string dialogInfo = "\nHow can I help you?.";
 
key ToucherID;
integer dialogChannel;
integer listenHandle;
 
default
{
    state_entry()
    {
        dialogChannel = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );
    }
 
    touch_start(integer num_detected)
    {
        ToucherID = llDetectedKey(0);
        listenHandle = llListen(dialogChannel, "", ToucherID, "");
        llDialog(ToucherID, dialogInfo, buttons, dialogChannel);
        llSetTimerEvent(60.0); // Here we set a time limit for responses
    }
 
    listen(integer channel, string name, key id, string message)
    {
        //stop the timer
        llSetTimerEvent(0.0);
        //remove listen
        llListenRemove(listenHandle);

        //first level menu responses
        if (message == "Programs")
        {       
            string dialogInfo = "\nWhich function should I perform?";
            list buttons = ["R000", "R030", "R050"];

            //call second level menu
            listenHandle = llListen(dialogChannel, "", ToucherID, "");
            llDialog(ToucherID, dialogInfo, buttons, dialogChannel);
            llSetTimerEvent(60.0); // Here we re set a time limit for responses            
        }
        else if (message == "Music")
        {
            llSay(0,"This function is not Operable yet.");
        }
        else if (message == "Return")
        {
            llSay(0,"Until next time.");
        }
        else if (message = "R000")
        {
            llSay(0,"!shoot");
        }
        else if (message == "R030")
        {
            llSay(0,"This function is not operable yet.");
        }
        else if (message == "R050")
        {
            llSay(0,"This function is not operable yet.");
        } 
       
    }

 
    timer()
    {
    //  stop timer
        llSetTimerEvent(0);
 
        llListenRemove(listenHandle);
        llWhisper(0, "Sorry. You snooze; you lose.");
    }
} 

 

  • Like 2

Share this post


Link to post
Share on other sites
5 hours ago, Kai Sirenz said:

so I need to call llDialog for each new menu I want to work? I'm still a bit confused, I tried adding llDialog before if r000 and it didnt work

Maybe this example would help:

float fTimeOutInterval = 30.0;
integer iDialogChannel;
integer iHandle;
key kToucher;
list lMainMenu =["Sizes","Colours"];
list lSizesMenu = ["Small", "Medium", "Large"];
list lColoursMenu = ["Red","Green","Blue"];
list lSubMenu;
string strText;

default
{
    state_entry()
    {
        iDialogChannel = (integer)llFrand(9999999.0);//generate a random channel
    }
    touch_start(integer total_number)
    {
        kToucher = llDetectedKey(0);//make a note of the toucher's uuid
        llListenRemove(iHandle);//remove any open listeners
        iHandle = llListen(iDialogChannel,"",kToucher,"");//start listening to the toucher
        llDialog(kToucher,"Please choose an option",lMainMenu,iDialogChannel);//present a dialog to the toucher, with the two main menu options
        llSetTimerEvent(fTimeOutInterval);//start the timer
    }

    listen(integer channel, string name, key id, string message)
    {
        llListenRemove(iHandle);//close the listener
        llSetTimerEvent(0.0);//close the timer
        if(~llListFindList(lMainMenu,[message])){//if the nessage is an item on the main menu list,
            
            if("Sizes"==message){
                lSubMenu = lSizesMenu;
                strText = "Please choose a size";
            }
            else if ("Colours" == message){
                lSubMenu = lColoursMenu;
                strText = "Please choose a colour";
            }
            iHandle = llListen(iDialogChannel,"",kToucher,"");//start listening to the toucher again
            llDialog(kToucher,strText,lSubMenu,iDialogChannel);//and present the toucher with the submenu
            llSetTimerEvent(fTimeOutInterval);//restart the timer
        }
        else{//message from one of the submenus
            llRegionSayTo(kToucher,0,"You chose "+message);
            //and give the toucher the item, or whatever you want to do with the message

        }
    }

    timer()
    {
        llListenRemove(iHandle);
        llSetTimerEvent(0.0);
        llRegionSayTo(kToucher,0,"The menu has timed out");
    }
}

 

  • Like 1

Share this post


Link to post
Share on other sites

So using this @Wandering Soulstar where the second dialog box is called, it does nothing once "Weapons" is pressed, no new box is opened! And @Innula Zenovka I understand that snippet to make a second menu box appear I would just call llDialog and set up the listener and timer in one of the if statements with a new list and string?

list buttons = ["Weapons", "Music", "Return"];
string dialogInfo = "\nHow can I help you?.";
 
key ToucherID;
integer dialogChannel;
integer listenHandle;
 
default
{
    state_entry()
    {
        dialogChannel = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );
    }
 
    touch_start(integer num_detected)
    {
        ToucherID = llDetectedKey(0);
        listenHandle = llListen(dialogChannel, "", ToucherID, "");
        llDialog(ToucherID, dialogInfo, buttons, dialogChannel);
        llSetTimerEvent(60.0); // Here we set a time limit for responses
    }
 
    listen(integer channel, string name, key id, string message)
    {
        //stop the timer
        llSetTimerEvent(0.0);
        //remove listen
        llListenRemove(listenHandle);

        //first level menu responses
        if (message == "Programs")
        {       
            string dialogInfo = "\nWhich function should I perform?";
            list buttons = ["R000", "R030", "R050"];

            //call second level menu
            listenHandle = llListen(dialogChannel, "", ToucherID, "");
            llDialog(ToucherID, dialogInfo, buttons, dialogChannel);
            llSetTimerEvent(60.0); // Here we re set a time limit for responses 
              
                if (message = "R000")
                {
                    //stop the timer
                    llSetTimerEvent(0.0);
                    //remove listen
                    llListenRemove(listenHandle); 
                     
                    llSay(0,"!shoot");
                }
                 else if (message == "R030")
                {
                    llSay(0,"This function is not operable yet.");
                }
                else if (message == "R050")
                {
                    llSay(0,"This function is not operable yet.");
                } 
        }
        else if (message == "Music")
        {
            llSay(0,"This function is not Operable yet.");
        }
        else if (message == "Return")
        {
            llSay(0,"Until next time.");
        }

       
    }

 
    timer()
    {
    //  stop timer
        llSetTimerEvent(0);
 
        llListenRemove(listenHandle);
        llWhisper(0, "Sorry. You snooze; you lose.");
    }
} 

 

Edited by Kai Sirenz

Share this post


Link to post
Share on other sites
1 minute ago, Kai Sirenz said:

And @Innula Zenovka I understand that snippet to make a second menu box appear I would just call llDialog and set up the listener and timer in one of the if statements with a new list and string?

That's it.  You've got it, I think.   If the message is an item from the top-level menu, use the message to determine which submenu is needed, and call llDialog again with the appropriate list of menu buttons and message.   Otherwise, if the message is from one of the second level menus, then process it accordingly.

Share this post


Link to post
Share on other sites

It's because 

//first level menu responses 
if (message == "Programs")

should be

//first level menu responses 
if (message == "Weapons")

(I had to look hard for it, too -- typos like that are the worst thing to have to find).

Edited by Innula Zenovka
  • Like 2

Share this post


Link to post
Share on other sites

  if (message = "R000")  will make the message R000 making that statement true everytime. It needs to be   if (message == "R000") also you are recalling the listen event. It's not part of the Weapons portion so you should have that closed off. Kinda like R000 was a button option to begin with. Sorry if that sounds confusing, but it will be more like this.

list buttons = ["Weapons", "Music", "Return"];
string dialogInfo = "\nHow can I help you?.";
 
key ToucherID;
integer dialogChannel;
integer listenHandle;
 
default
{
    state_entry()
    {
        dialogChannel = -1 - (integer)("0x" + llGetSubString( (string)llGetKey(), -7, -1) );
    }
 
    touch_start(integer num_detected)
    {
        ToucherID = llDetectedKey(0);
        listenHandle = llListen(dialogChannel, "", ToucherID, "");
        llDialog(ToucherID, dialogInfo, buttons, dialogChannel);
        llSetTimerEvent(60.0); // Here we set a time limit for responses
    }
 
    listen(integer channel, string name, key id, string message)
    {
        //stop the timer
        llSetTimerEvent(0.0);
        //remove listen
        llListenRemove(listenHandle);

        //first level menu responses
        if (message == "Weapons")
        {       
            string dialogInfo = "\nWhich function should I perform?";
            list buttons = ["R000", "R030", "R050"];

            //call second level menu
            listenHandle = llListen(dialogChannel, "", ToucherID, "");
            llDialog(ToucherID, dialogInfo, buttons, dialogChannel);
            llSetTimerEvent(60.0); // Here we re set a time limit for responses 
              }
                if (message == "R000")
                {
                    //stop the timer
                    llSetTimerEvent(0.0);
                    //remove listen
                    llListenRemove(listenHandle); 
                     
                    llSay(0,"!shoot");
                }
                 else if (message == "R030")
                {
                    llSay(0,"This function is not operable yet.");
                }
                else if (message == "R050")
                {
                    llSay(0,"This function is not operable yet.");
                } 
        
        else if (message == "Music")
        {
            llSay(0,"This function is not Operable yet.");
        }
        else if (message == "Return")
        {
            llSay(0,"Until next time.");
        }

       
    }

 
    timer()
    {
    //  stop timer
        llSetTimerEvent(0);
 
        llListenRemove(listenHandle);
        llWhisper(0, "Sorry. You snooze; you lose.");
    }
} 

 

  • Like 2

Share this post


Link to post
Share on other sites

Thank you all for your help! My next question is that the object is obviously saying this, from what I can see on the Wiki and posts about it they can't listen to themselves, is there a way I can get round this? i.e making my avatar say it on 1 or something? The other script is triggered by saying !shoot n I figured it wouldn't be more complicated than that lol

Edited by Kai Sirenz

Share this post


Link to post
Share on other sites
2 hours ago, Kai Sirenz said:

Thank you all for your help! My next question is that the object is obviously saying this, from what I can see on the Wiki and posts about it they can't listen to themselves, is there a way I can get round this? i.e making my avatar say it on 1 or something? The other script is triggered by saying !shoot n I figured it wouldn't be more complicated than that lol

If I understood correctly, you have another script that is activated by "!shoot" on channel 0 and it doesn't activate when your scripted object says it?

Then the other script is checking that it's only the avatar speaking and nothing else.

The only way for a script to make your avatar talk is through a dialog menu. If you give the dialog on channel 0, your avatar will say "!shoot" in local chat. Your avatar will also say any other button in local too, though.

I would recommend a gesture instead, so you can press a button to automatically say the command.

Share this post


Link to post
Share on other sites

Then the other script is checking that it's only the avatar speaking and nothing else.

8 minutes ago, Wulfie Reanimator said:

If I understood correctly, you have another script that is activated by "!shoot" on channel 0 and it doesn't activate when your scripted object says it?

Then the other script is checking that it's only the avatar speaking and nothing else.

That's right, I don't understand the second line though

Share this post


Link to post
Share on other sites

Kai,

From what I am reading above, the other script that you want to activate is in the same prim as the one with the dialogs, yes? In that case what you should do is send a linked message.

Snippet in Dialog script:

        else if (message = "R000")
        {
            //this can be removed if you actually do not need this in open chat
            llSay(0,"!shoot");

            //call to other Script
            llMessageLinked(LINK_THIS, 0, "!shoot!", NULL_KEY);
        }

Snippet in Other script:

    link_message(integer sender_number, integer number, string message, key id)
    {
        if (message == "!shoot!")
        {
            //activate
        }
    }

 

  • Like 1

Share this post


Link to post
Share on other sites

Yes the other script is in the prim as well! Would I still need the listen function when doing this?  Because I removed the listen part and replaced it with link_message and ultimately did nothing, I presume it would need both but I'm unsure how to do that. This is the shoot script, I can understand the code in the dialog is telling it to link "!shoot" into the shooting script on channel 0, where the script is listening, it prints "!shoot" into chat but does not rez.

 

default
{
    state_entry() 
    {
        llListen(0,"", NULL_KEY, "");
    }

    listen(integer channel, string name, key id, string message) 
    {
        if (message == "!shoot")
        {
            vector myPos = llGetPos();
            rotation myRot = llGetRot();
            vector rezPos = myPos+relativePosOffset*myRot;
            vector rezVel = relativeVel*myRot;
            rotation rezRot = relativeRot*myRot;

 

Edited by Kai Sirenz

Share this post


Link to post
Share on other sites
1 hour ago, Kai Sirenz said:

That's right, I don't understand the second line though

Never mind that, it's not relevant now that I know the other script is in the same object.

Share this post


Link to post
Share on other sites

Alright so I tried this in the shooting script

	state_entry() 
    {
        llMessageLinked(LINK_THIS, 0, llGetScriptName(), "");
    }

    link_message(integer sender_number, integer number, string message, key id) 
    {
        if (message == "!shoot")
        {
            vector myPos = llGetPos();
            rotation myRot = llGetRot();
            vector rezPos = myPos+relativePosOffset*myRot;
            vector rezVel = relativeVel*myRot;
            rotation rezRot = relativeRot*myRot;
            llRezObject(object, rezPos, rezVel, rezRot, startParam);

And this in the Dialog 

                if (message == "R:000")
                {
                    //stop the timer
                    llSetTimerEvent(0.0);
                    //remove listen
                    llListenRemove(listenHandle); 
                    
                    //this can be removed if you actually do not need this in open chat
                    llSay(0,"!shoot");
                    //call to other Script
                    llMessageLinked(LINK_THIS, 0, "!shoot!", NULL_KEY);
				}

With no luck (shooting script works on it's own without the linking if "!shoot" is typed into public chat)

Edited by Kai Sirenz

Share this post


Link to post
Share on other sites

Kai,

You do not need a listen, and not sure what the llMessageLinked you have in state_entry is for. You do not need to set up anything to get linked messages. the problem I see is that in the dialog you are sending !shoot! .. while in the shooting script you are checking for !shoot ... i.e. you are sending an extra ! at the end.

  • Like 1

Share this post


Link to post
Share on other sites

Hey so just on the back of this 

                if (message == "R000")
                {
                    llSetTimerEvent(0.0);
                    llListenRemove(listenHandle); 
                    llSay(0,"Activating turret.");
                    
                //  llSay(0,"Pod Program R:000 is currently undergoing maintenance."); 
                    llSay(1,"!shoot");
                    llMessageLinked(LINK_THIS, 1, "!shoot", NULL_KEY);
                }

                else if (message == "R050")
                {
                    llSetTimerEvent(0.0);
                    llListenRemove(listenHandle); 
                    llSay(0, "Activating Pod Program: R050.");
                    
                //  llSay(0,"Pod Program R:000 is currently undergoing maintenance."); 
                    llSay(1,"!spear");
                    llMessageLinked(LINK_THIS, 1, "!spear", NULL_KEY);
                } 

The script usually runs if I refresh the spear script object name, but other than that it doesn't and is currently flooding me with 

Script trying to break links but PERMISSION_CHANGE_LINKS permission not set!

I'm very confused

Share this post


Link to post
Share on other sites

Since it looks as if the other script is the one that's causing the problems, it would help to see the other script in its entirety -- please post the whole script, since problems are often not where you think they're going to be (at least that's my experience, when I suddenly spot what's breaking my scripts after spending hours searching in a completely different place).

Share this post


Link to post
Share on other sites
string object = "Nier: Automata Pod Program Spear"; // Name of object in inventory
vector relativePosOffset = <0.0, 0.0, 0.25>; // "Forward" and a little "above" this prim
vector relativeVel = <0.0, 0.0, 0.0>; // Traveling in this prim's "forward" direction at 1m/s
rotation relativeRot = <10.0, 5.0, 10.0, 10.0>; // Rotated 90 degrees on the x-axis compared to this prim
integer countC = 0;
integer startParam = 10;
 
default
{
    link_message(integer sender_number, integer number, string message, key id)  
    {
        while (message == "!spear" && countC < 15)
        {
            countC++;
            vector myPos = llGetPos();
            rotation myRot = llGetRot();
            vector rezPos = myPos+relativePosOffset*myRot;
            vector rezVel = relativeVel*myRot;
            rotation rezRot = relativeRot*myRot;
            relativePosOffset.x++;
            relativeRot.y++;
            llRezObject(object, rezPos, rezVel, rezRot, startParam);
        }
    }
}

 

Share this post


Link to post
Share on other sites

I think the reason it keeps needing to be reset is that you never reset countC after you've finished firing the first 15 shots;

Try something like this:

    link_message(integer sender_num, integer num, string message, key id) {
        if("!spear"==message){
            CountC = 0; //zero the counter each time
            vector myPos = llGetPos();//only need to calculate this once at run time, unless the rezzer is moving
            rotation myRot = llGetRot();
            rotation rezRot = relativeRot*myRot;
            do{
                vector rezPos = myPos+relativePosOffset*myRot;
                vector rezVel = relativeVel*myRot;
                llRezObject(object, rezPos, rezVel, rezRot, startParam);
                relativePosOffset.x++;
                relativeRot.y++;   
            }
            while(++CountC <15);
        }
    }

No idea why you're getting error messages about breaking links.  One of your scripts must be calling http://wiki.secondlife.com/wiki/LlBreakLink, but it's clearly not this one.   Is the projectile maybe?

Share this post


Link to post
Share on other sites

If I do that surely it will end up as an infinite loop since CountC is reset at the start of every statement? I'm not sure what you mean by projectile, there is no projectile script, the movement is set with velocity inside that script, if you mean the object it contains no scripts

 

If !spear is the message then CountC = 0, get pos etc and then the script is told to do the rez + increments, I'm unsure what the while does here. Hypothetically wouldn't something like this work just as well?

 

string object = "Nier: Automata Pod Program Spear"; // Name of object in inventory
vector relativePosOffset = <0.0, 0.0, 0.25>; // "Forward" and a little "above" this prim
vector relativeVel = <0.0, 0.0, 0.0>; // Traveling in this prim's "forward" direction at 1m/s
rotation relativeRot = <10.0, 5.0, 10.0, 10.0>; // Rotated 90 degrees on the x-axis compared to this prim
integer countC = 0;
integer startParam = 10;
 
default
{
    link_message(integer sender_number, integer number, string message, key id)  
    {
        while (message == "!spear" && countC < 15)
        {
            countC++;
            vector myPos = llGetPos();
            rotation myRot = llGetRot();
            vector rezPos = myPos+relativePosOffset*myRot;
            vector rezVel = relativeVel*myRot;
            rotation rezRot = relativeRot*myRot;
            relativePosOffset.x++;
            relativeRot.y++;
            llRezObject(object, rezPos, rezVel, rezRot, startParam);
        }                                
        CountC = 0;
    }
}

 

Edited by Kai Sirenz

Share this post


Link to post
Share on other sites

There's no real difference in this example between doing it as a while() loop or do {   }while().    I just wrote it that way because that's how I'm used to doing loop.s

However, I don't understand why you say 

1 hour ago, Kai Sirenz said:

f I do that surely it will end up as an infinite loop since CountC is reset at the start of every statement?

Think about the script logic.   If the message is ""!spear", then do something.   The something in my example is first,  reset the counter to 0.   Then the next step is to run the loop, rezzing the object and advancing  the counter by one, until the counter == 15.    It doesn't really matter where you reset the counter -- before or after the loop -- so long as you do it outside the loop.

As to my reference to the projectile script, I was simply trying to suggest reasons why you might be getting flooded with messages saying  "Script trying to break links but PERMISSION_CHANGE_LINKS permission not set!" It can't be the rezzer script, since there's nothing there about breaking links, so it must be another script.

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...