620 lines
No EOL
21 KiB
Text
620 lines
No EOL
21 KiB
Text
/*
|
|
|
|
Copyright Aria's Creations 2024
|
|
Dialog Module - Next Engine
|
|
v1.0.080124.1829
|
|
|
|
08-2024 INITIAL RELEASE
|
|
* Finished hooking up listener and timer
|
|
* Add ability to replace menu buttons (Toggles)
|
|
|
|
06-2024 INITIAL VERSION
|
|
* Manage memory more efficiently than all other current systems
|
|
* Channels for dialogs will always be negative
|
|
* User-input prompts will use a positive channel and inform the user the channel number for manual longer input
|
|
* Event signal on link message when requesting only a channel number
|
|
* Two helper functions allow serializing and deserializing menus from the linkset_data
|
|
* Menus are not stored in memory, only a pointer to it
|
|
* Menus consist of a linksetdata json object
|
|
* In-memory objects consist of channel number, menu name pointing to LSD, ID listening to
|
|
* ID may not be a user for listen only. In this case the menu name is blank.
|
|
* Dynamic Menus.
|
|
* Menu Construction. We as part of the startup process, send a signal to all scripts asking for menu / registration. All subsequent buttons will be treated as possible submenus, a signal will be sent for them recursively to build up the menu hierarchy.
|
|
|
|
|
|
*/
|
|
|
|
integer LINK_SIGNAL_GEN_CHANNEL = 0601241;
|
|
integer LINK_SIGNAL_CHANNEL_BACK = 0601242;
|
|
integer LINK_SIGNAL_SHOW_MENU = 0601243;
|
|
integer LINK_SIGNAL_MENU_TIMEOUT = 0601244;
|
|
integer LINK_SIGNAL_REREGISTER_MENUS= 0601245;
|
|
integer LINK_SIGNAL_QUERY_MENU = 0602241;
|
|
integer LINK_SIGNAL_REGISTER_MENU = 0602242;
|
|
integer LINK_SIGNAL_RESET = 0602243;
|
|
integer LINK_SIGNAL_MENU_DATA = 0602244;
|
|
integer LINK_SIGNAL_MENU_BACK = 0801241;
|
|
integer LINK_SIGNAL_REPLACE_BUTTON = 0804241;
|
|
|
|
|
|
|
|
string PREVIOUS_MENU = "<--";
|
|
string EXIT_MENU = "-exit-";
|
|
string NEXT_MENU = "-->";
|
|
|
|
|
|
integer g_iDebugIndent=0;
|
|
|
|
|
|
|
|
returnMenu(key kID, string sMenu, integer iPage, string sReply) {
|
|
llMessageLinked(LINK_SET, LINK_SIGNAL_MENU_BACK, llList2Json(JSON_OBJECT, ["menu", sMenu, "page", iPage, "reply", sReply]), kID);
|
|
}
|
|
|
|
|
|
integer DEBUG_ENABLED() {
|
|
return FALSE;
|
|
}
|
|
|
|
DEBUG_FUNC(integer iEnter, string sLabel, list lParams) {
|
|
if(!DEBUG_ENABLED()) return;
|
|
if(iEnter){
|
|
llOwnerSay(MakeIndent() + "ENTER " + sLabel + " [" + llList2CSV(lParams) + "]");
|
|
g_iDebugIndent++;
|
|
} else {
|
|
g_iDebugIndent --;
|
|
if(g_iDebugIndent<0)g_iDebugIndent=0;
|
|
|
|
llOwnerSay(MakeIndent() + "LEAVE " + sLabel + " [" + llList2CSV(lParams) + "]");
|
|
}
|
|
}
|
|
|
|
DEBUG_STMT(integer iEnter, string sLabel) {
|
|
if(!DEBUG_ENABLED()) return;
|
|
if(iEnter) {
|
|
llOwnerSay(MakeIndent() + "STMT " + sLabel);
|
|
g_iDebugIndent ++;
|
|
}else {
|
|
g_iDebugIndent--;
|
|
if(g_iDebugIndent<0)g_iDebugIndent=0;
|
|
|
|
llOwnerSay(MakeIndent() + "RET " + sLabel);
|
|
}
|
|
}
|
|
|
|
DEBUG(string sMsg) {
|
|
if(!DEBUG_ENABLED()) return;
|
|
llOwnerSay(MakeIndent() + " > " + sMsg);
|
|
}
|
|
|
|
|
|
|
|
string MakeIndent()
|
|
{
|
|
integer i = 0;
|
|
string sIndent = "";
|
|
for(i = 0;i<g_iDebugIndent;i++){
|
|
sIndent += " ";
|
|
}
|
|
|
|
return "[" + llGetScriptName() + "] " + sIndent;
|
|
}
|
|
|
|
string SLURL(key kID){
|
|
return "secondlife:///app/agent/"+(string)kID+"/about";
|
|
}
|
|
|
|
integer IsLikelyUUID(string sID)
|
|
{
|
|
if(sID == (string)NULL_KEY)return TRUE;
|
|
if(llStringLength(sID)==32)return TRUE;
|
|
key kID = (key)sID;
|
|
if(kID)return TRUE;
|
|
if(llStringLength(sID) >25){
|
|
if(llGetSubString(sID,8,8)=="-" && llGetSubString(sID, 13,13) == "-" && llGetSubString(sID,18,18) == "-" && llGetSubString(sID,23,23)=="-") return TRUE;
|
|
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
integer IsLikelyAvatarID(key kID)
|
|
{
|
|
if(!IsLikelyUUID(kID))return FALSE;
|
|
// Avatar UUIDs always have the 15th digit set to a 4
|
|
if(llGetSubString(kID,8,8) == "-" && llGetSubString(kID,14,14)=="4")return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
integer IsListOfIDs(list lIDs)
|
|
{
|
|
integer i=0;
|
|
integer end = llGetListLength(lIDs);
|
|
for(i=0;i<end;i++){
|
|
if(IsLikelyUUID(llList2String(lIDs,i)))return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
integer generateChannel(integer iPositive) {
|
|
integer iRand = llRound(llFrand(0xFFFF));
|
|
if(iPositive) {
|
|
return llAbs(iRand);
|
|
}else
|
|
{
|
|
if(iRand > 0) return -iRand;
|
|
else return iRand;
|
|
}
|
|
}
|
|
|
|
// This function serializes a named menu to the buffer
|
|
saveMenu(string sName, list lButtons, list lUtilityButtons, integer iMenuVersion, string sMenuText) {
|
|
llLinksetDataWrite("menus." + sName, llList2Json(JSON_OBJECT, [
|
|
"buttons", llList2Json(JSON_ARRAY, lButtons),
|
|
"utility", llList2Json(JSON_ARRAY, lUtilityButtons),
|
|
"version", iMenuVersion, // This flag is used to know if on startup a script needs to overwrite this menu definition,
|
|
"prompt", sMenuText
|
|
]));
|
|
}
|
|
|
|
updateMenu(string sName, string sJson) {
|
|
llLinksetDataWrite("menus." + sName, sJson);
|
|
}
|
|
|
|
// This function deserializes a menu from the buffer
|
|
string readMenu(string sName) {
|
|
string sMenu = llLinksetDataRead("menus." + sName);
|
|
|
|
return sMenu;
|
|
}
|
|
|
|
integer STRIDE = 7;
|
|
integer STRIDE_ID = 0;
|
|
integer STRIDE_PATH = 1;
|
|
integer STRIDE_CHANNEL = 2;
|
|
integer STRIDE_TEXT = 3;
|
|
integer STRIDE_PAGE = 4;
|
|
integer STRIDE_HANDLE = 5;
|
|
integer STRIDE_TIMER = 6;
|
|
|
|
list g_lListeners = [];
|
|
integer MENU_TIMER = 30;
|
|
integer GENERAL_TIMER = 120;
|
|
|
|
startListen(key kAv, integer iChannel, string sMenuName, string sMenuText, integer iTimer) {
|
|
integer iIndex=llListFindList(g_lListeners, [kAv]);
|
|
if(iIndex == -1) {
|
|
integer iListener = llListen(iChannel, "", kAv, "");
|
|
g_lListeners += [kAv, sMenuName, iChannel, sMenuText, 0, iListener, llGetUnixTime() + iTimer];
|
|
}else {
|
|
stopListen(kAv);
|
|
|
|
startListen(kAv, iChannel, sMenuName, sMenuText, iTimer);
|
|
}
|
|
}
|
|
|
|
stopListen(key kAv) {
|
|
integer iIndex = llListFindList(g_lListeners, [kAv]);
|
|
if(iIndex != -1) {
|
|
g_lListeners = llDeleteSubList(g_lListeners, iIndex, iIndex+STRIDE-1); // Stride is 6 - ID, path, channel, text, page, listen handle
|
|
}
|
|
}
|
|
|
|
updatePage(key kID, integer iPage) {
|
|
integer iIndex = llListFindList(g_lListeners, [kID]);
|
|
if(iIndex!=-1) {
|
|
g_lListeners = llListReplaceList(g_lListeners, [iPage], iIndex+STRIDE_PAGE, iIndex+STRIDE_PAGE);
|
|
}
|
|
}
|
|
|
|
integer getListenTimer(key kID) {
|
|
integer iIndex = llListFindList(g_lListeners, [kID]);
|
|
if(iIndex != -1) {
|
|
integer iVal = llList2Integer(g_lListeners, iIndex+STRIDE_TIMER);
|
|
return iVal;
|
|
}else return -1;
|
|
}
|
|
|
|
integer getPageNumber(key kID) {
|
|
integer iIndex = llListFindList(g_lListeners, [kID]);
|
|
if(iIndex != -1) {
|
|
return llList2Integer(g_lListeners, iIndex + STRIDE_PAGE);
|
|
} else return -1;
|
|
}
|
|
|
|
updateTimer(key kID, integer iNewTimer) {
|
|
integer iIndex = llListFindList(g_lListeners, [kID]);
|
|
if(iIndex != -1) {
|
|
g_lListeners = llListReplaceList(g_lListeners, [llGetUnixTime() + iNewTimer], iIndex + STRIDE_TIMER, iIndex + STRIDE_TIMER);
|
|
}
|
|
}
|
|
|
|
string getMenuID(key kID) {
|
|
integer iIndex = llListFindList(g_lListeners, [kID]);
|
|
if(iIndex != -1) {
|
|
return llList2String(g_lListeners, iIndex + STRIDE_PATH);
|
|
} else return "";
|
|
}
|
|
|
|
integer getChannel(key kID) {
|
|
integer iIndex = llListFindList(g_lListeners, [kID]);
|
|
if(iIndex!=-1) {
|
|
return llList2Integer(g_lListeners, iIndex+STRIDE_CHANNEL);
|
|
} else return -1;
|
|
}
|
|
|
|
string CreateBlankMenu() {
|
|
return llList2Json(JSON_OBJECT, [
|
|
"prompt", "",
|
|
"buttons", "[]",
|
|
"utility", llList2Json(JSON_ARRAY, []),
|
|
"version", "1"
|
|
]);
|
|
}
|
|
|
|
string AddMenuButton(string sJson, string sButton) {
|
|
list lButtons = llJson2List(llJsonGetValue(sJson, ["buttons"]));
|
|
lButtons += [sButton];
|
|
|
|
return llJsonSetValue(sJson, ["buttons"], llList2Json(JSON_ARRAY, lButtons));
|
|
}
|
|
|
|
integer jsonValueExists(string sJson, list lElems) {
|
|
if(llJsonValueType(sJson, lElems) == JSON_INVALID) return FALSE;
|
|
else return TRUE;
|
|
}
|
|
|
|
integer hasPreviousPage(integer page){
|
|
if(page == 1) {
|
|
return FALSE;
|
|
}else return TRUE;
|
|
}
|
|
|
|
integer hasNextPage(integer page, integer maxPages) {
|
|
if(page == maxPages) return FALSE;
|
|
else return TRUE;
|
|
}
|
|
|
|
list getNavigatorButtons(integer page, integer max) {
|
|
if(hasPreviousPage(page)) {
|
|
if(hasNextPage(page,max)) {
|
|
return [PREVIOUS_MENU, EXIT_MENU, NEXT_MENU];
|
|
}else return [PREVIOUS_MENU, EXIT_MENU, " "];
|
|
}else {
|
|
if(hasNextPage(page,max)) {
|
|
return [" ", EXIT_MENU, NEXT_MENU];
|
|
}else return [" ", EXIT_MENU, " "];
|
|
}
|
|
}
|
|
|
|
// This function takes the json menu as a parameter, calculates the maximum number of pages from total buttons 12 - utility - page buttons if applicable
|
|
integer calcMaxPages(string sMenu) {
|
|
// Retrieve buttons and utility lists from JSON
|
|
list lButtons = llJson2List(llJsonGetValue(sMenu, ["buttons"]));
|
|
list lUtility = llJson2List(llJsonGetValue(sMenu, ["utility"]));
|
|
|
|
// Combine buttons and utility lists
|
|
list lFinal = lButtons + lUtility;
|
|
// Calculate the total number of buttons
|
|
integer totalButtons = llGetListLength(lFinal);
|
|
|
|
// Check if the total buttons exceed the limit for a single page
|
|
if (totalButtons > 12) {
|
|
// Define constants
|
|
integer navigation = 3; // 3 navigation buttons (previous, next, and exit)
|
|
integer utility = llGetListLength(lUtility); // Number of utility buttons
|
|
integer buttons = llGetListLength(lButtons); // Number of actual buttons
|
|
|
|
// Calculate available space for actual buttons on each page
|
|
integer availableSpacePerPage = 12 - navigation - utility;
|
|
|
|
// Calculate the total number of pages needed
|
|
integer maxPages = (integer)llCeil((float)buttons / (float)availableSpacePerPage);
|
|
|
|
return maxPages;
|
|
} else {
|
|
// If total buttons are 12 or less, only one page is needed
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
string getPage(string sMenu, integer iPage, integer iCheckUUID) {
|
|
DEBUG_FUNC(TRUE, "getPage", [sMenu, iPage, iCheckUUID]);
|
|
// Retrieve buttons and utility lists from JSON
|
|
list lButtons = llJson2List(llJsonGetValue(sMenu, ["buttons"]));
|
|
list lUtility = llJson2List(llJsonGetValue(sMenu, ["utility"]));
|
|
|
|
// Define constants
|
|
integer navigation = 3; // 3 navigation buttons (previous, next, and page indicator)
|
|
integer utility = llGetListLength(lUtility); // Number of utility buttons
|
|
integer buttonsPerPage = 12 - navigation - utility; // Available space for actual buttons on each page
|
|
|
|
// Calculate the total number of pages using the existing function
|
|
integer totalPages = calcMaxPages(sMenu);
|
|
|
|
// Ensure iPage is within valid range
|
|
if (iPage < 1) iPage = 1;
|
|
if (iPage > totalPages) iPage = totalPages;
|
|
|
|
// Calculate start and end indices for the buttons on the requested page
|
|
integer startIndex = (iPage - 1) * buttonsPerPage;
|
|
integer endIndex = startIndex + buttonsPerPage - 1;
|
|
|
|
// Get the actual buttons to be displayed on this page
|
|
list lPageButtons = [];
|
|
|
|
// Add utility buttons to the page
|
|
lPageButtons += lUtility;
|
|
|
|
// Add the buttons for the specified page
|
|
integer i;
|
|
for (i = startIndex; i <= endIndex && i < llGetListLength(lButtons); ++i) {
|
|
lPageButtons += llList2String(lButtons, i);
|
|
}
|
|
|
|
// Add navigation buttons
|
|
lPageButtons = getNavigatorButtons(iPage, totalPages) + lPageButtons;
|
|
|
|
// Loop over the buttons, check if UUID, replace with a number instead if UUID
|
|
string sExtraText = " ";
|
|
if(!iCheckUUID) jump returnMenu;
|
|
i =0;
|
|
integer end = llGetListLength(lPageButtons);
|
|
integer idNum = 0;
|
|
for(i=0;i<end;i++) {
|
|
string sButton = llList2String(lPageButtons, i);
|
|
if(IsLikelyAvatarID(sButton)) {
|
|
lPageButtons = llListReplaceList(lPageButtons, [(string)idNum], i,i);
|
|
idNum++;
|
|
|
|
sExtraText += SLURL(sButton) + "\n";
|
|
}
|
|
}
|
|
|
|
@returnMenu;
|
|
DEBUG("Buttons list: " + llList2CSV(lPageButtons));
|
|
string jsReply=llList2Json(JSON_OBJECT, ["text", sExtraText, "buttons", "~!~" + llDumpList2String(lPageButtons, "~!~") + "~!~"]);
|
|
DEBUG_FUNC(FALSE, "getPage", [jsReply]);
|
|
return jsReply;
|
|
}
|
|
|
|
AppendMenuButton(string sMenu, string sButton) {
|
|
string json = readMenu(sMenu);
|
|
AddMenuButton(json, sButton);
|
|
|
|
updateMenu(sMenu, json);
|
|
}
|
|
|
|
default
|
|
{
|
|
state_entry() {
|
|
llLinksetDataDeleteFound("menus", "");
|
|
llMessageLinked(LINK_SET, LINK_SIGNAL_QUERY_MENU, "root", "");
|
|
|
|
llLinksetDataDeleteFound("colors", "");
|
|
// Query color menu buttons and color pairs. Stride 3 instead of 2
|
|
}
|
|
|
|
timer() {
|
|
integer i = 0;
|
|
integer end = llGetListLength(g_lListeners);
|
|
for(i=0;i<end;i+=STRIDE) {
|
|
key kID = llList2Key(g_lListeners, i + STRIDE_ID);
|
|
|
|
integer iTimer = getListenTimer(kID);
|
|
if(llGetUnixTime() > iTimer) {
|
|
stopListen(kID);
|
|
|
|
llRegionSayTo(kID, 0, "Listener Timed Out");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
changed(integer t) {
|
|
if(t & CHANGED_INVENTORY) {
|
|
llSleep(2);
|
|
llResetScript();
|
|
}
|
|
}
|
|
|
|
listen(integer c,string n,key i,string m) {
|
|
// Get the menu path
|
|
DEBUG_FUNC(TRUE, "listen", [i,m]);
|
|
|
|
string sMenuID = getMenuID(i);
|
|
|
|
// Get the current page number
|
|
integer iPage = getPageNumber(i);
|
|
DEBUG("Get current page number for menu " + sMenuID + ": " + (string)iPage);
|
|
|
|
string jsMenu = "";
|
|
|
|
if(sMenuID != "") jsMenu = readMenu(sMenuID);
|
|
DEBUG("Menu Json: " + jsMenu);
|
|
|
|
integer iMaxPages = 0;
|
|
if(sMenuID != "") iMaxPages = calcMaxPages(jsMenu);
|
|
DEBUG("Get max number of pages: " + (string)iMaxPages);
|
|
|
|
if(m == PREVIOUS_MENU) {
|
|
DEBUG_STMT(TRUE, "Previous Menu");
|
|
// Update the time remaining
|
|
updateTimer(i, MENU_TIMER);
|
|
|
|
iPage--;
|
|
|
|
if(iPage < 0) iPage=0;
|
|
|
|
string sPage = getPage(jsMenu, iPage, TRUE);
|
|
|
|
list lPageButtons = llParseString2List(llJsonGetValue(sPage, ["buttons"]), ["~!~"], []);
|
|
|
|
updatePage(i, iPage);
|
|
string sAppend = llJsonGetValue(sPage, ["text"]);
|
|
|
|
if(iMaxPages > 1) sAppend += "\n\nPage " + (string)iPage + "/" + (string)(iMaxPages-1);
|
|
llDialog(i, llJsonGetValue(jsMenu, ["prompt"]) + sAppend, lPageButtons, getChannel(i));
|
|
DEBUG_STMT(FALSE, "Previous Menu");
|
|
} else if(m == NEXT_MENU) {
|
|
DEBUG_STMT(TRUE, "Next Menu");
|
|
// Update the time remaining
|
|
updateTimer(i, MENU_TIMER);
|
|
|
|
iPage++;
|
|
|
|
if(iPage < iMaxPages-1) iPage=iMaxPages-1;
|
|
|
|
string sPage = getPage(jsMenu, iPage, TRUE);
|
|
|
|
list lPageButtons = llParseString2List(llJsonGetValue(sPage, ["buttons"]), ["~!~"], []);
|
|
|
|
updatePage(i, iPage);
|
|
string sAppend = llJsonGetValue(sPage, ["text"]);
|
|
|
|
if(iMaxPages > 1) sAppend += "\n\nPage " + (string)iPage + "/" + (string)(iMaxPages-1);
|
|
llDialog(i, llJsonGetValue(jsMenu, ["prompt"]) + sAppend, lPageButtons, getChannel(i));
|
|
DEBUG_STMT(FALSE, "Next Menu");
|
|
} else if(m == " ") {
|
|
DEBUG_STMT(TRUE, "Empty Button");
|
|
// Update the time remaining
|
|
updateTimer(i, MENU_TIMER);
|
|
|
|
string sPage = getPage(jsMenu, iPage, TRUE);
|
|
|
|
list lPageButtons = llParseString2List(llJsonGetValue(sPage, ["buttons"]), ["~!~"], []);
|
|
|
|
updatePage(i, iPage);
|
|
string sAppend = llJsonGetValue(sPage, ["text"]);
|
|
|
|
if(iMaxPages > 1) sAppend += "\n\nPage " + (string)iPage + "/" + (string)(iMaxPages-1);
|
|
llDialog(i, llJsonGetValue(jsMenu, ["prompt"]) + sAppend, lPageButtons, getChannel(i));
|
|
DEBUG_STMT(FALSE, "Empty Button");
|
|
} else if(m == EXIT_MENU) {
|
|
DEBUG_STMT(TRUE, "Exit Menu");
|
|
stopListen(i);
|
|
DEBUG_STMT(FALSE, "Exit Menu");
|
|
} else {
|
|
DEBUG_STMT(TRUE, "Process Response");
|
|
// Stop listening, and send a signal
|
|
string sPage = "";
|
|
if(jsMenu != "") sPage = getPage(jsMenu, iPage, FALSE);
|
|
|
|
DEBUG("Parse Buttons");
|
|
// Check Message, if message is found in list, it isn't UUID.
|
|
// If message is not found, it is likely uuid
|
|
list lButtons = llParseString2List(llJsonGetValue(sPage, ["buttons"]), ["~!~"], []);
|
|
integer iIndex = llListFindList(lButtons, [m]);
|
|
|
|
DEBUG("Buttons : " + llDumpList2String(lButtons, " ~ "));
|
|
|
|
if(iIndex==-1 && sMenuID != "") {
|
|
// Loop over to find the index
|
|
integer iIDNum = (integer)m;
|
|
integer x = 0;
|
|
integer xe = llGetListLength(lButtons);
|
|
integer iID = 0;
|
|
for(x=0;x<xe;x++) {
|
|
string sButton = llList2String(lButtons, x);
|
|
if(IsLikelyAvatarID(sButton)) {
|
|
if(iIDNum == iID) {
|
|
returnMenu(i, sMenuID, iPage, sButton);
|
|
jump epr;
|
|
}
|
|
|
|
iID ++;
|
|
}
|
|
}
|
|
} else {
|
|
// Send reply signal
|
|
returnMenu(i, sMenuID, iPage, m);
|
|
}
|
|
|
|
@epr;
|
|
|
|
stopListen(i);
|
|
DEBUG_STMT(FALSE, "Process Response");
|
|
}
|
|
|
|
DEBUG_FUNC(FALSE, "listen", []);
|
|
}
|
|
|
|
link_message(integer s,integer n,string m,key i) {
|
|
if(n == LINK_SIGNAL_GEN_CHANNEL) {
|
|
integer iChan = generateChannel((integer)m);
|
|
startListen(i, iChan, "", "", GENERAL_TIMER);
|
|
llMessageLinked(LINK_SET, LINK_SIGNAL_CHANNEL_BACK, (string)iChan, "");
|
|
} else if(n == LINK_SIGNAL_SHOW_MENU) {
|
|
string jsMenu = readMenu(llJsonGetValue(m,["menu"]));
|
|
integer iChan = generateChannel(FALSE);
|
|
|
|
startListen(i, iChan, llJsonGetValue(m,["menu"]), llJsonGetValue(jsMenu, ["prompt"]), MENU_TIMER);
|
|
|
|
// Show the dialog window now after constructing pages if needed.
|
|
integer maxPages = calcMaxPages(jsMenu);
|
|
// Now show the dialog for page 1
|
|
integer iPage = 1;
|
|
if(jsonValueExists(m, ["page"])) iPage = (integer)llJsonGetValue(m,["page"]);
|
|
|
|
string jsPage = getPage(jsMenu, iPage, TRUE);
|
|
list lPageButtons = llParseString2List(llJsonGetValue(jsPage, ["buttons"]), ["~!~"], []);
|
|
|
|
updatePage(i, iPage);
|
|
string sAppend = llJsonGetValue(jsPage, ["text"]);
|
|
|
|
if(maxPages>1) sAppend += "\n\nPage " + (string)iPage+"/" + (string)(maxPages-1);
|
|
|
|
//llOwnerSay("DEBUG\n" + llJsonGetValue(sMenu, ["prompt"]) + sAppend + "\n\n" + llJsonGetValue(sPage, ["buttons"]));
|
|
|
|
|
|
llDialog(i, llJsonGetValue(jsMenu, ["prompt"])+sAppend, lPageButtons, getChannel(i));
|
|
} else if(n == LINK_SIGNAL_REGISTER_MENU) {
|
|
string sMenuJson = llLinksetDataRead("menus." + (string)i);
|
|
if(sMenuJson == "" ) {
|
|
// No current menu
|
|
sMenuJson = CreateBlankMenu();
|
|
|
|
sMenuJson = AddMenuButton(sMenuJson, m);
|
|
}else sMenuJson = AddMenuButton(sMenuJson, m);
|
|
|
|
llLinksetDataWrite("menus."+(string)i, sMenuJson);
|
|
llSleep(0.5);
|
|
llMessageLinked(LINK_SET, LINK_SIGNAL_QUERY_MENU, (string)i + "/" + m, "");
|
|
} else if(n == LINK_SIGNAL_RESET) {
|
|
llResetScript();
|
|
} else if(n == LINK_SIGNAL_MENU_DATA) {
|
|
// This signal is used to replace metadata, like the menu text, or utility buttons.
|
|
// Based on what values are set in the json object, we will replace those elements in the actual menu
|
|
string sJson = readMenu(i);
|
|
if(jsonValueExists(m, ["utility"])) {
|
|
sJson = llJsonSetValue(sJson, ["utility"], llJsonGetValue(m, ["utility"]));
|
|
}
|
|
|
|
if(jsonValueExists(m, ["prompt"])) {
|
|
sJson = llJsonSetValue(sJson, ["prompt"], llJsonGetValue(m, ["prompt"]));
|
|
}
|
|
|
|
llLinksetDataWrite("menus." + (string)i, sJson);
|
|
} else if(n == LINK_SIGNAL_REPLACE_BUTTON) {
|
|
string jsMenu = readMenu(llJsonGetValue(m, ["menu"]));
|
|
list lButtons = llJson2List(llJsonGetValue(jsMenu, ["buttons"]));
|
|
|
|
integer iIndex = llListFindList(lButtons, [llJsonGetValue(m,["btn"])]);
|
|
if(iIndex != -1) {
|
|
lButtons = llListReplaceList(lButtons, [llJsonGetValue(m, ["newBtn"])], iIndex, iIndex);
|
|
jsMenu = llJsonSetValue(jsMenu, ["buttons"], llList2Json(JSON_ARRAY, lButtons));
|
|
updateMenu(llJsonGetValue(m,["menu"]), jsMenu);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
linkset_data(integer iAction, string sKey, string sValue) {
|
|
if(iAction == LINKSETDATA_RESET) {
|
|
llMessageLinked(LINK_SET, LINK_SIGNAL_REREGISTER_MENUS, "", "");
|
|
llResetScript();
|
|
}
|
|
}
|
|
} |