If you are going to make an LSL script for Second Life that needs interaction with the user, probably you will end up needing a menu. If you don’t understand or don’t know the appropiate metodologies to design menus in LSL you will waste too much time trying to figure out how to do them and the final result will not be very good so let’s consider some topics that we must consider when making a menu:

  • Little resources consumption: menus uses listeners, you must be careful using them.
  • User friendly:  should be browseable
  • Interference: should not interfere with other listeners
  • Security: some menu options could be owner only

Example 1: a basic menu

A menu with A,B and C options

// Example made by Kahiro Watanabe, visit modernclix.info for lsl and php/mysql tutorials
// You can share this script with anyone

integer listener;  // Listener for handling different channels
integer simpleMenuChannel; // The channel used for the menu

// Function that returns a random number (used for generating a random channel)
integer randomNumber()
{
    return((integer)(llFrand(99999.0)*-1));
}

menu(key id, integer channel, string title, list buttons) // Generic menu creator
{
    llListenRemove(listener);
    listener = llListen(channel,"",id,"");
    llDialog(id,title,buttons,channel);
    llSetTimerEvent(10.0);   // if no menu button is pressed in 20 seconds the timer is triggered to kill the listener
}

simpleMenu(key id) // This function calls the menu creator
{
    simpleMenuChannel = randomNumber();
    menu(id,simpleMenuChannel,"Select an option",["A","B","C"]);
}

default
{

    touch_start(integer num)
    {
        simpleMenu(llDetectedKey(0));
    }

    listen (integer channel, string name, key id, string message)
    {
        if (message == "A")
        {
            llSay(0,"You selected option A");
            //do something else here
        }
        else if (message == "B")
        {
            llSay(0,"You selected option B");
                //do something else here
        }
        else if (message == "C")
        {
            llSay(0,"You selected option C");
                //do something else here
        }
        simpleMenu(id); // refresh menu
    }

    timer()
    {
        llListenRemove(listener); // kill the listener
        llSetTimerEvent(0.0); // stop the timer
    }
}

Example 2: submenus and browse buttons

A menu with two buttons A and B each one with a submenu.

A -> 1,2,<< Back

B -> 3,4,<< Back

 

 

// Example made by Kahiro Watanabe, visit modernclix.info for lsl and php/mysql tutorials
// You can share this script with anyone

integer listener;  // Thist listens the buttons message

integer mainMenuChannel;
integer subMenuAChannel;
integer subMenuBChannel;

// Function that returns a random number (used for generating a random channel)
integer randomNumber()
{
    return((integer)(llFrand(99999.0)*-1));
}

menu(key id, integer channel, string title, list buttons) // Generic menu creator
{
    llListenRemove(listener);
    listener = llListen(channel,"",id,"");
    llDialog(id,title,buttons,channel);
    llSetTimerEvent(10.0);   // if no menu button is pressed in 20 seconds the timer is triggered to kill the listener
}

mainMenu(key id) // This function calls the menu creator
{
    mainMenuChannel = randomNumber();
    menu(id,mainMenuChannel,"Select an option",["A","B"]);
}

subMenuA(key id)
{
    subMenuAChannel = randomNumber();
    menu(id,subMenuAChannel,"Select an option",["1","2","<< Back"]);
}

subMenuB(key id)
{
    subMenuBChannel = randomNumber();
    menu(id,subMenuBChannel,"Select an option",["3","4","<< Back"]);
}

default
{

    touch_start(integer num)
    {
        mainMenu(llDetectedKey(0));
    }

    listen (integer channel, string name, key id, string message)
    {
        if (message == "<< Back") // lets go back to the main menu
        {
            mainMenu(id);
            return; //event stops here
        }

        // Now we need to know what channel is being listened
        if (channel == mainMenuChannel)
        {
            if (message == "A")
            {
                subMenuA(id);
            }
            else
            {
                subMenuB(id);
            }
        }
        else if (channel == subMenuAChannel)
        {
            llSay(0,"You selected number " + message + " from sub menu A");
            subMenuA(id);
        }
        else
        {
            llSay(0,"You selected number " + message + " from sub menu B");
            subMenuB(id);
        }
    }

    timer()
    {
        llListenRemove(listener); // kill the listener
        llSetTimerEvent(0.0); // stop the timer
    }
}

 

Basically these two scripts have a generic function (‘menu’) to build menus and small functions that call this main menu creator. The listener listens only the channel that is being used, that’s why in the first example we don’t ask for the channel in the listen event because there’s only one. The channel used is always a new random number so the script doesn’t interfere accidentaly with other ones.

Pay attention to the timer and how to correctly kill the listener so it doesn’t stay open, basically if you don’t press a button within 20 seconds the timer event is triggered killing the listener and also stoping the timer. This way you make sure that you are not leaving open channels that could lead to a wrong script execution and stack heap collitions.

Since there’s too much information to process here I will make the Example 3 in the next post when you will learn how to limit access to certain menu options and how to make useful things.