Difference between revisions of "Dialog Menus Control"

From Second Life Wiki
Jump to navigation Jump to search
m (lsl code tagging)
m (<lsl> tag to <source>)
 
(7 intermediate revisions by one other user not shown)
Line 1: Line 1:
{{LSL Header}}
{{LSL Header}}
{{KBcaution|This script is considered obsoleted. Latest version of [[Dialog Control]] has this functionality built-in! An obsoleted version of Nargus Dialog Control script is required to work with this script.}}
This is example of usage and function library needed in each scripts to use this dialog menus module.
This is example of usage and function library needed in each scripts to use this dialog menus module.


'''IMPORTANT NOTE:''' This menus control REQUIRED [[Dialog Control|Nargus Dialog Control script]]. You MUST have both Nargus Dialog Control and Nargus Dialog Menus in the same prim for it to work.
'''IMPORTANT NOTE:''' This menus control REQUIRED [[Dialog Control|Nargus Dialog Control script]]. You MUST have both Nargus Dialog Control and Nargus Dialog Menus in the same prim for it to work.


;Menus Usage:
==Menus Usage==
# Initialize menus control using:
# Initialize menus control using:
#* llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
#* llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
Line 23: Line 25:


# Dialog will return value the same way as usual call to Nargus Dialog Module script.
# Dialog will return value the same way as usual call to Nargus Dialog Module script.
==Sample Scripts==
* '''[[OnTouchSelectTexture]]''' (Tiyuk Quellmalz)


If anyone uses this module, please IM ''Nargus Asturias'', I'd love to hear what you think.
If anyone uses this module, please IM ''Nargus Asturias'', I'd love to hear what you think.


==Scripts & Example==
<source lang="lsl2">
// READ ME:
// To see this sample in action;
// Put "Nargus Dialog Control" and "Nargus Dialog Menus" along with this script
// in a prim and touch.
// Dialog constants
integer lnkDialog = 14001;
integer lnkDialogNotify = 14004;
integer lnkDialogResponse = 14002;
integer lnkDialogTimeOut = 14003;
integer lnkDialogReshow = 14011;
integer lnkDialogCancel = 14012;
integer lnkMenuClear = 15001;
integer lnkMenuAdd = 15002;
integer lnkMenuShow = 15003;
string seperator = "||";
integer dialogTimeOut = 0;
// ********** DIALOG FUNCTIONS **********
string packDialogMessage(string message, list buttons, list returns){
    string packed_message = message + seperator + (string)dialogTimeOut;
   
    integer i;
    integer count = llGetListLength(buttons);
    for(i=0; i<count; i++) packed_message += seperator + llList2String(buttons, i) + seperator + llList2String(returns, i);
    return packed_message;
}
dialogReshow(){llMessageLinked(LINK_THIS, lnkDialogReshow, "", NULL_KEY);}
dialogCancel(){
    llMessageLinked(LINK_THIS, lnkDialogCancel, "", NULL_KEY);
    llSleep(1);
}


<lsl>
dialogNotify(key id, string message){
// READ ME:
    list rows;
// To see this sample in action;
   
// Put "Nargus Dialog Control" and "Nargus Dialog Menus" along with this script
    llMessageLinked(LINK_THIS, lnkDialogNotify,
// in a prim and touch.
        message + seperator + (string)dialogTimeOut + seperator,
        id);
// Dialog constants
}
integer lnkDialog = 14001;
// ********** END DIALOG FUNCTIONS **********
integer lnkDialogNotify = 14004;
 
integer lnkDialogResponse = 14002;
 
integer lnkDialogTimeOut = 14003;
default{
    state_entry(){
integer lnkDialogReshow = 14011;
        llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
integer lnkDialogCancel = 14012;
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
            "[ Main Menu ]\n" +
integer lnkMenuClear = 15001;
            "Messages go here",
integer lnkMenuAdd = 15002;
            [ "BUTTON_1", "BUTTON_2", "BUTTON_3", "BUTTON_X" ],
integer lnkMenuShow = 15003;
            [ "MENU_SubMenu1", "MENU_SubMenu2", "MENU_SubMenu3", "EXIT" ]
        ), "MainMenu");
string seperator = "||";
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
integer dialogTimeOut = 0;
            "[ Sub Menu 1 ]\n" +
            "Messages go here",
// ********** DIALOG FUNCTIONS **********
            [ "SUB_1_1", "SUB_1_2", "SUB_1_3", "MAIN MENU", "SUB_3", "BUTTON_X" ],
string packDialogMessage(string message, list buttons, list returns){
            [ "1.1", "1.2", "1.3", "MENU_MainMenu", "MENU_SubMenu3", "EXIT" ]
    string packed_message = message + seperator + (string)dialogTimeOut;
        ), "SubMenu1");
   
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
    integer i;
            "[ Sub Menu 2 ]\n" +
    integer count = llGetListLength(buttons);
            "Messages go here",
    for(i=0; i<count; i++) packed_message += seperator + llList2String(buttons, i) + seperator + llList2String(returns, i);
            [ "SUB_2_1", "SUB_2_2", "SUB_2_3", "MAIN MENU", "SUB_1", "BUTTON_X" ],
            [ "2.1", "2.2", "2.3", "MENU_MainMenu", "MENU_SubMenu1", "EXIT" ]
    return packed_message;
        ), "SubMenu2");
}
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
            "[ Sub Menu 3 ]\n" +
dialogReshow(){llMessageLinked(LINK_THIS, lnkDialogReshow, "", NULL_KEY);}
            "Messages go here",
dialogCancel(){
            [ "SUB_3_1", "SUB_3_2", "SUB_3_3", "MAIN MENU", "SUB_2", "BUTTON_X" ],
    llMessageLinked(LINK_THIS, lnkDialogCancel, "", NULL_KEY);
            [ "3.1", "3.2", "3.3", "MENU_MainMenu", "MENU_SubMenu2", "EXIT" ]
    llSleep(1);
        ), "SubMenu3");
}
       
        llSetText("Touch me to show menu", <1,1,1>, 1);
dialogNotify(key id, string message){
    }
    list rows;
 
   
    link_message(integer sender_num, integer num, string str, key id){
    llMessageLinked(LINK_THIS, lnkDialogNotify,
        if(num == lnkDialogTimeOut){
        message + seperator + (string)dialogTimeOut + seperator,
            dialogNotify(llGetOwner(), "Menu time-out. Please try again.");
        id);
            state default;
}
        }else if(num == lnkDialogResponse){
// ********** END DIALOG FUNCTIONS **********
            llWhisper(0, str);
        }
    }
default{
   
    state_entry(){
    touch_start(integer num_detected){
        llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
        llMessageLinked(LINK_THIS, lnkMenuShow, "", llDetectedOwner(0));
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
    }
            "[ Main Menu ]\n" +
}
            "Messages go here",
</source>
            [ "BUTTON_1", "BUTTON_2", "BUTTON_3", "BUTTON_X" ],
            [ "MENU_SubMenu1", "MENU_SubMenu2", "MENU_SubMenu3", "EXIT" ]
        ), "MainMenu");
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
            "[ Sub Menu 1 ]\n" +
            "Messages go here",
            [ "SUB_1_1", "SUB_1_2", "SUB_1_3", "MAIN MENU", "SUB_3", "BUTTON_X" ],
            [ "1.1", "1.2", "1.3", "MENU_MainMenu", "MENU_SubMenu3", "EXIT" ]
        ), "SubMenu1");
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
            "[ Sub Menu 2 ]\n" +
            "Messages go here",
            [ "SUB_2_1", "SUB_2_2", "SUB_2_3", "MAIN MENU", "SUB_1", "BUTTON_X" ],
            [ "2.1", "2.2", "2.3", "MENU_MainMenu", "MENU_SubMenu1", "EXIT" ]
        ), "SubMenu2");
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
            "[ Sub Menu 3 ]\n" +
            "Messages go here",
            [ "SUB_3_1", "SUB_3_2", "SUB_3_3", "MAIN MENU", "SUB_2", "BUTTON_X" ],
            [ "3.1", "3.2", "3.3", "MENU_MainMenu", "MENU_SubMenu2", "EXIT" ]
        ), "SubMenu3");
       
        llSetText("Touch me to show menu", <1,1,1>, 1);
    }
    link_message(integer sender_num, integer num, string str, key id){
        if(num == lnkDialogTimeOut){
            dialogNotify(llGetOwner(), "Menu time-out. Please try again.");
            state default;
        }else if(num == lnkDialogResponse){
            llWhisper(0, str);
        }
    }
   
    touch_start(integer num_detected){
        llMessageLinked(LINK_THIS, lnkMenuShow, "", llDetectedOwner(0));
    }
}
</lsl>


Nargus Dialog Menus v1.01 (by Nargus Asturias)
Nargus Dialog Menus v1.01 (by Nargus Asturias)


<lsl>
<source lang="lsl2">
// ********** DIALOG MENUS MODULE ********** //
// ********** DIALOG MENUS MODULE ********** //
// By Nargus Asturias
// By Nargus Asturias
// Version 1.00
// Version 1.01
//
//
// Multi-layer menus management module for Nargus Dialog Control.
// Multi-layer menus management module for Nargus Dialog Control.
// Use same packing method as Nargus Dialog Control
// Use same packing method as Nargus Dialog Control
//
//
// HOW TO USE:
// HOW TO USE:
// 1) Initialize menu by sending "lnkMenuClear" signal:
// 1) Initialize menu by sending "lnkMenuClear" signal:
//          llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
//          llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
//
//
// 2) Add menu dialog using provided function (or manually, please referr to Nargus Dialog Control  
// 2) Add menu dialog using provided function (or manually, please referr to Nargus Dialog Control  
//    manual). Make sure signal is sent with "lnkMenuAdd" and key field is menu's name;
//    manual). Make sure signal is sent with "lnkMenuAdd" and key field is menu's name;
//          llMessageLinked(LINK_THIS, lnkMenuAdd, ......, "MainMenu");
//          llMessageLinked(LINK_THIS, lnkMenuAdd, ......, "MainMenu");
//
//
//    To make a button show submenu, use following as return value of the button:
//    To make a button show submenu, use following as return value of the button:
//          MENU_<name>
//          MENU_<name>
//    Replace "<name>" with the actual name of the added menu (without parenthesis).
//    Replace "<name>" with the actual name of the added menu (without parenthesis).
//
//
// 3) Repeat (2) for as much menus as needed
// 3) Repeat (2) for as much menus as needed
//
//
// 4) To show a menu, use:
// 4) To show a menu, use:
//          llMessageLinked(LINK_THIS, lnkMenuShow, name, llGetOwner());
//          llMessageLinked(LINK_THIS, lnkMenuShow, name, llGetOwner());
//    When "name" is name of the menu to show. To show last-used menu, leave this field empty.
//    When "name" is name of the menu to show. To show last-used menu, leave this field empty.
//
//
// 5) Dialog will return value the same way as usual call to Nargus Dialog Module script.
// 5) Dialog will return value the same way as usual call to Nargus Dialog Module script.
// ******************************************* //
// ******************************************* //
 
// Dialog constants
// Dialog constants
integer lnkDialog = 14001;
integer lnkDialog = 14001;
integer lnkDialogNotify = 14004;
integer lnkDialogNotify = 14004;
integer lnkDialogResponse = 14002;
integer lnkDialogResponse = 14002;
integer lnkDialogTimeOut = 14003;
integer lnkDialogTimeOut = 14003;
 
integer lnkDialogReshow = 14011;
integer lnkDialogReshow = 14011;
integer lnkDialogCancel = 14012;
integer lnkDialogCancel = 14012;
 
string seperator = "||";
string seperator = "||";
integer dialogTimeOut = 0;
integer dialogTimeOut = 0;
 
// ********** DIALOG FUNCTIONS **********
// ********** DIALOG FUNCTIONS **********
dialogReshow(){llMessageLinked(LINK_THIS, lnkDialogReshow, "", NULL_KEY);}
dialogReshow(){llMessageLinked(LINK_THIS, lnkDialogReshow, "", NULL_KEY);}
dialogCancel(){
dialogCancel(){
    llSleep(1);
    llSleep(1);
    llMessageLinked(LINK_THIS, lnkDialogCancel, "", NULL_KEY);
    llMessageLinked(LINK_THIS, lnkDialogCancel, "", NULL_KEY);
}
}
// ********** END DIALOG FUNCTIONS **********
// ********** END DIALOG FUNCTIONS **********
 
// Constants
// Constants
integer lnkMenuClear = 15001;
integer lnkMenuClear = 15001;
integer lnkMenuAdd = 15002;
integer lnkMenuAdd = 15002;
integer lnkMenuShow = 15003;
integer lnkMenuShow = 15003;
 
// Menus variables
// Menus variables
list menuNames;            // List of names of all menus
list menuNames;            // List of names of all menus
list menus;                // List of packed menus command, in order of menuNames
list menus;                // List of packed menus command, in order of menuNames
 
// Variables
// Variables
integer lastMenuIndex;      // Latest called menu's index
integer lastMenuIndex;      // Latest called menu's index
 
// ********** Menu Functions **********
// ********** Menu Functions **********
clearMenusList(){
clearMenusList(){
    menuNames = [];
    menuNames = [];
    menus = [];
    menus = [];
 
    lastMenuIndex = 0;
    lastMenuIndex = 0;
}
}
 
addMenu(string name, string message, list buttons, list returns){
addMenu(string name, string message, list buttons, list returns){
    // Reduced menu request time by packing request commands
    // Reduced menu request time by packing request commands
    string packed_message = message + seperator + (string)dialogTimeOut;
    string packed_message = message + seperator + (string)dialogTimeOut;
   
    integer i;
    integer count = llGetListLength(buttons);
    for(i=0; i<count; i++) packed_message += seperator + llList2String(buttons, i) + seperator + llList2String(returns, i);
    // Add menu to the menus list
    menuNames += [name];
    menus += [packed_message];
}
showMenu(string name, key id){
    if(llGetListLength(menuNames) <= 0) return;
      
      
    integer index;
    integer i;
    if(name != ""){
    integer count = llGetListLength(buttons);
        index = llListFindList(menuNames, [name]);
    for(i=0; i<count; i++) packed_message += seperator + llList2String(buttons, i) + seperator + llList2String(returns, i);
        if(index < 0) index = lastMenuIndex;
 
    }else index = lastMenuIndex;
    // Add menu to the menus list
   
    menuNames += [name];
    lastMenuIndex = index;
    menus += [packed_message];
   
}
    // Load menu command and execute
 
    string packed_message = llList2String(menus, index);     
showMenu(string name, key id){
    llMessageLinked(LINK_THIS, lnkDialog, packed_message, id);
    if(llGetListLength(menuNames) <= 0) return;
}
 
    integer index;
// ********** States **********
    if(name != ""){
default{
        index = llListFindList(menuNames, [name]);
    state_entry(){
        if(index < 0) index = lastMenuIndex;
        clearMenusList();
    }else index = lastMenuIndex;
    }
   
    lastMenuIndex = index;
    link_message(integer sender_num, integer num, string str, key id){
   
        // Menu response commands
    // Load menu command and execute
        if(num == lnkDialogResponse){
    string packed_message = llList2String(menus, index);     
            if(llGetSubString(str, 0, 4) == "MENU_"){
    llMessageLinked(LINK_THIS, lnkDialog, packed_message, id);
                str = llDeleteSubString(str, 0, 4);
}
                showMenu(str, id);
 
            }
// ********** States **********
        }
default{
       
    state_entry(){
        // Menu management commands
        clearMenusList();
        else if(num == lnkMenuClear)
    }
            clearMenusList();
 
        else if(num == lnkMenuAdd){
    link_message(integer sender_num, integer num, string str, key id){
            list data = llParseString2List(str, [seperator], []);
        // Menu response commands
        if(num == lnkDialogResponse){
            string message = llList2String(data, 0);
            if(llGetSubString(str, 0, 4) == "MENU_"){
            list buttons = [];
                str = llDeleteSubString(str, 0, 4);
            list returns = [];
                showMenu(str, id);
            }
            integer i;
        }
            integer count = llGetListLength(data);
       
            for(i=2; i<count;){
        // Menu management commands
                buttons += [llList2String(data, i++)];
        else if(num == lnkMenuClear)
                returns += [llList2String(data, i++)];
            clearMenusList();
            }
        else if(num == lnkMenuAdd){
            list data = llParseString2List(str, [seperator], []);
            addMenu((string)id, message, buttons, returns);
 
            string message = llList2String(data, 0);
        }else if(num == lnkMenuShow){
            list buttons = [];
            dialogCancel();
            list returns = [];
            showMenu(str, id);
 
        }
            integer i;
    }
            integer count = llGetListLength(data);
}
            for(i=2; i<count;){
</lsl>
                buttons += [llList2String(data, i++)];
                returns += [llList2String(data, i++)];
            }
 
            addMenu((string)id, message, buttons, returns);
 
        }else if(num == lnkMenuShow){
            dialogCancel();
            showMenu(str, id);
        }
    }
}
</source>


{{LSLC|Library|Dialog Menus Control}}
{{LSLC|Library|Dialog Menus Control}}

Latest revision as of 10:57, 25 January 2015

KBcaution.png Important: This script is considered obsoleted. Latest version of Dialog Control has this functionality built-in! An obsoleted version of Nargus Dialog Control script is required to work with this script.

This is example of usage and function library needed in each scripts to use this dialog menus module.

IMPORTANT NOTE: This menus control REQUIRED Nargus Dialog Control script. You MUST have both Nargus Dialog Control and Nargus Dialog Menus in the same prim for it to work.

Menus Usage

  1. Initialize menus control using:
    • llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
  1. Using "packDialogMessage" function to generate new menu, and add it to menus list:
    • llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(....), "MenuName");
    • While "MenuName" is the same of this menu, ie: MainMenu
  1. To make a dialog button show a sub-menu, use following as return value of the button:
    • MENU_<name>
    • Replace "<name>" with the actual name of the added menu (without parenthesis).
  1. Repeat (2) and (3) for all menus you want
  1. To show a menu, use:
    • llMessageLinked(LINK_THIS, lnkMenuShow, "MenuName", llGetOwner());
    • Where "MenuName" is the name of menu to show. To show last-used menu, leave this field empty.
  1. Dialog will return value the same way as usual call to Nargus Dialog Module script.

Sample Scripts

If anyone uses this module, please IM Nargus Asturias, I'd love to hear what you think.

Scripts & Example

// READ ME:
// To see this sample in action;
// Put "Nargus Dialog Control" and "Nargus Dialog Menus" along with this script
// in a prim and touch.

// Dialog constants
integer lnkDialog = 14001;
integer lnkDialogNotify = 14004;
integer lnkDialogResponse = 14002;
integer lnkDialogTimeOut = 14003;

integer lnkDialogReshow = 14011;
integer lnkDialogCancel = 14012;

integer lnkMenuClear = 15001;
integer lnkMenuAdd = 15002;
integer lnkMenuShow = 15003;

string seperator = "||";
integer dialogTimeOut = 0;

// ********** DIALOG FUNCTIONS **********
string packDialogMessage(string message, list buttons, list returns){
    string packed_message = message + seperator + (string)dialogTimeOut;
    
    integer i;
    integer count = llGetListLength(buttons);
    for(i=0; i<count; i++) packed_message += seperator + llList2String(buttons, i) + seperator + llList2String(returns, i);

    return packed_message;
}

dialogReshow(){llMessageLinked(LINK_THIS, lnkDialogReshow, "", NULL_KEY);}
dialogCancel(){
    llMessageLinked(LINK_THIS, lnkDialogCancel, "", NULL_KEY);
    llSleep(1);
}

dialogNotify(key id, string message){
    list rows;
    
    llMessageLinked(LINK_THIS, lnkDialogNotify,
        message + seperator + (string)dialogTimeOut + seperator,
        id);
}
// ********** END DIALOG FUNCTIONS **********


default{
    state_entry(){
        llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
            "[ Main Menu ]\n" +
            "Messages go here",
            [ "BUTTON_1", "BUTTON_2", "BUTTON_3", "BUTTON_X" ],
            [ "MENU_SubMenu1", "MENU_SubMenu2", "MENU_SubMenu3", "EXIT" ]
        ), "MainMenu");
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
            "[ Sub Menu 1 ]\n" +
            "Messages go here",
            [ "SUB_1_1", "SUB_1_2", "SUB_1_3", "MAIN MENU", "SUB_3", "BUTTON_X" ],
            [ "1.1", "1.2", "1.3", "MENU_MainMenu", "MENU_SubMenu3", "EXIT" ]
        ), "SubMenu1");
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
            "[ Sub Menu 2 ]\n" +
            "Messages go here",
            [ "SUB_2_1", "SUB_2_2", "SUB_2_3", "MAIN MENU", "SUB_1", "BUTTON_X" ],
            [ "2.1", "2.2", "2.3", "MENU_MainMenu", "MENU_SubMenu1", "EXIT" ]
        ), "SubMenu2");
        llMessageLinked(LINK_THIS, lnkMenuAdd, packDialogMessage(
            "[ Sub Menu 3 ]\n" +
            "Messages go here",
            [ "SUB_3_1", "SUB_3_2", "SUB_3_3", "MAIN MENU", "SUB_2", "BUTTON_X" ],
            [ "3.1", "3.2", "3.3", "MENU_MainMenu", "MENU_SubMenu2", "EXIT" ]
        ), "SubMenu3");
        
        llSetText("Touch me to show menu", <1,1,1>, 1);
    }

    link_message(integer sender_num, integer num, string str, key id){
        if(num == lnkDialogTimeOut){
            dialogNotify(llGetOwner(), "Menu time-out. Please try again.");
            state default;
        }else if(num == lnkDialogResponse){
            llWhisper(0, str);
        }
    }
    
    touch_start(integer num_detected){
        llMessageLinked(LINK_THIS, lnkMenuShow, "", llDetectedOwner(0));
    }
}

Nargus Dialog Menus v1.01 (by Nargus Asturias)

// ********** DIALOG MENUS MODULE ********** //
// By Nargus Asturias
// Version 1.01
//
// Multi-layer menus management module for Nargus Dialog Control.
// Use same packing method as Nargus Dialog Control
//
// HOW TO USE:
// 1) Initialize menu by sending "lnkMenuClear" signal:
//          llMessageLinked(LINK_THIS, lnkMenuClear, "", NULL_KEY);
//
// 2) Add menu dialog using provided function (or manually, please referr to Nargus Dialog Control 
//    manual). Make sure signal is sent with "lnkMenuAdd" and key field is menu's name;
//          llMessageLinked(LINK_THIS, lnkMenuAdd, ......, "MainMenu");
//
//    To make a button show submenu, use following as return value of the button:
//          MENU_<name>
//    Replace "<name>" with the actual name of the added menu (without parenthesis).
//
// 3) Repeat (2) for as much menus as needed
//
// 4) To show a menu, use:
//          llMessageLinked(LINK_THIS, lnkMenuShow, name, llGetOwner());
//    When "name" is name of the menu to show. To show last-used menu, leave this field empty.
//
// 5) Dialog will return value the same way as usual call to Nargus Dialog Module script.
// ******************************************* //

// Dialog constants
integer lnkDialog = 14001;
integer lnkDialogNotify = 14004;
integer lnkDialogResponse = 14002;
integer lnkDialogTimeOut = 14003;

integer lnkDialogReshow = 14011;
integer lnkDialogCancel = 14012;

string seperator = "||";
integer dialogTimeOut = 0;

// ********** DIALOG FUNCTIONS **********
dialogReshow(){llMessageLinked(LINK_THIS, lnkDialogReshow, "", NULL_KEY);}
dialogCancel(){
    llSleep(1);
    llMessageLinked(LINK_THIS, lnkDialogCancel, "", NULL_KEY);
}
// ********** END DIALOG FUNCTIONS **********

// Constants
integer lnkMenuClear = 15001;
integer lnkMenuAdd = 15002;
integer lnkMenuShow = 15003;

// Menus variables
list menuNames;             // List of names of all menus
list menus;                 // List of packed menus command, in order of menuNames

// Variables
integer lastMenuIndex;      // Latest called menu's index

// ********** Menu Functions **********
clearMenusList(){
    menuNames = [];
    menus = [];

    lastMenuIndex = 0;
}

addMenu(string name, string message, list buttons, list returns){
    // Reduced menu request time by packing request commands
    string packed_message = message + seperator + (string)dialogTimeOut;
    
    integer i;
    integer count = llGetListLength(buttons);
    for(i=0; i<count; i++) packed_message += seperator + llList2String(buttons, i) + seperator + llList2String(returns, i);

    // Add menu to the menus list
    menuNames += [name];
    menus += [packed_message];
}

showMenu(string name, key id){
    if(llGetListLength(menuNames) <= 0) return;
   
    integer index;
    if(name != ""){
        index = llListFindList(menuNames, [name]);
        if(index < 0) index = lastMenuIndex;
    }else index = lastMenuIndex;
    
    lastMenuIndex = index;
    
    // Load menu command and execute
    string packed_message = llList2String(menus, index);    
    llMessageLinked(LINK_THIS, lnkDialog, packed_message, id);
}

// ********** States **********
default{
    state_entry(){
        clearMenusList();
    }

    link_message(integer sender_num, integer num, string str, key id){
        // Menu response commands
        if(num == lnkDialogResponse){
            if(llGetSubString(str, 0, 4) == "MENU_"){
                str = llDeleteSubString(str, 0, 4);
                showMenu(str, id);
            }
        }
        
        // Menu management commands
        else if(num == lnkMenuClear)
            clearMenusList();
        else if(num == lnkMenuAdd){
            list data = llParseString2List(str, [seperator], []);

            string message = llList2String(data, 0);
            list buttons = [];
            list returns = [];

            integer i;
            integer count = llGetListLength(data);
            for(i=2; i<count;){
                buttons += [llList2String(data, i++)];
                returns += [llList2String(data, i++)];
            }

            addMenu((string)id, message, buttons, returns);

        }else if(num == lnkMenuShow){
            dialogCancel();
            showMenu(str, id);
        }
    }
}