Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

[Discussion/Libray] - Dialog-Maker

Haruki Watanabe
llSLCrash(void);
Join date: 28 Mar 2007
Posts: 434
12-13-2007 15:13
I was getting tired of copy/pasting the same scripts over and over again, so I thought, I'd make something like an extended function, that's put into a script on itself. The script can be placed into the Contents of an object (even in a linkset) and called through llMessageLinked. It will present the Agent one of these blue dialogs and will send the answer back to the calling script...

I don't even know whether that's a good idea - therefore the name of this thread :)

The first part is the «function» itself. Put this in a script and put it in a prim (single prim or linked-object). I named the script «func.show_dialog» so I'll remember what it is :)

[EDIT]

I slightly altered the script, sending the Command (SHOW_DIALOG) back to the requesting script to make it easier to determine, what's in the linked message

CODE


// Dialog-Maker
// By Haruki Watanabe

// This script is public domain - use it, share it, to whatever you wanna do... :)
// If you've got any improvements, please post them in the forum

// *******************************************************
// Constants
// *******************************************************

integer REQUESTING_SCRIPT; // Number of the requesting script
integer REQUESTING_LINK; // Link-Number where the request comes from

integer DLG_CHANNEL; // Channel on which the result of the dialog will be passed back
integer LISTENER_DLG; // The Listener-ID
integer LIST_OFFSET; // Offset of the List

integer TOTAL_ENTRIES; // Total Entries in the whole list to be presented

integer SHOW_ENTRIES; // BOOLEAN Whether or not to show the number of entries in the dialog-title (e.g. 'showing 1-9/25')
integer BACKLINK; // BOOLEAN Whether or not give the user the option to go back (useful if you're in a Sub-Menu)

string DLG_TITLE; // Title of the dialog
string CMD; // The Command that's passed to this function-script

key AGENT_REQUEST; // Key of the requesting Agent

list DLG_CONTENT; // The contents that the user can choose from

float MAX_LISTEN_TIME = 240.0; // Maximum seconds the Listener keeps listening for an answer

// *******************************************************
// Functions
// *******************************************************

show_dlg(list PASS_MENU) // Presents the Dialog-Menu to the requesting user
{
llListenRemove(LISTENER_DLG); // Delete any old listener

if(llGetListLength(PASS_MENU) == 0 || TOTAL_ENTRIES == 0) // If there are no entries in the list, send an error-Message to the User
{
llInstantMessage(AGENT_REQUEST, "There are no entries in the list...");
}
else
{
string TITLE = DLG_TITLE;

integer start; // number where the list starts
integer end; // number where the list ends -> these two shouldn't be confused with the list offset!

start = LIST_OFFSET + 1;
end = start + 9;

if(end > TOTAL_ENTRIES)
end = TOTAL_ENTRIES;

if(SHOW_ENTRIES == TRUE)
{
TITLE = TITLE + "\n showing entries " + (string)start + " - " + (string)end + " of " + (string)TOTAL_ENTRIES;
}

list MENU = llList2List(PASS_MENU, LIST_OFFSET, LIST_OFFSET + 9); // Get the portion of the list that fits into a dialog

// Give the user a 'back'-option

if(BACKLINK == TRUE || LIST_OFFSET > 0)
MENU += ["Back..."];

// if the list is too big to fit into one Menu, give the user a 'next'-option

if(end < TOTAL_ENTRIES)
MENU += ["Next..."];

// Show the dialog and initialize a listener

LISTENER_DLG = llListen(DLG_CHANNEL, "", AGENT_REQUEST, "");

llDialog(AGENT_REQUEST, TITLE, MENU, DLG_CHANNEL);

llSetTimerEvent(MAX_LISTEN_TIME); // Initialize a timer, in case the user clicks on 'ignore'
}

}

// Create an arbitrary dialog channel

integer randInt(integer n)
{
return (integer)llFrand(n + 1);
}

integer randIntBetween(integer min, integer max)
{
return min + randInt(max - min);
}

integer make_dlg_channel()
{
return randIntBetween(-65356, 0);
}

// *******************************************************
// Main-Section
// *******************************************************

default
{
link_message(integer sender, integer num, string str, key id)
{
AGENT_REQUEST = id;
REQUESTING_LINK = sender;

// split up the passed string into a list

list temp = llParseString2List(str, ["|"], []);

CMD = llList2String(temp, 0);

if(CMD == "SHOW_DIALOG")
{

DLG_CONTENT = llCSV2List(llList2String(temp, 1));
DLG_TITLE = llList2String(temp, 2);
REQUESTING_SCRIPT = llList2Integer(temp, 3);
SHOW_ENTRIES = llList2Integer(temp, 4);
BACKLINK = llList2Integer(temp, 5);

LIST_OFFSET = 0; // Set the List offset to the beginning of the list

TOTAL_ENTRIES = llGetListLength(DLG_CONTENT); // Determine the total length of the list

DLG_CHANNEL = make_dlg_channel(); // Create an arbitrary channel to listen for the dialog

show_dlg(DLG_CONTENT);
}

}

listen(integer channel, string name, key id, string message)
{
if(channel == DLG_CHANNEL && id == AGENT_REQUEST) // The User clicked on an option
{
if(message == "Back...") // The selected option was 'back'
{
if(LIST_OFFSET > 0)
{
// if we're not at the beginning of the options-list,
// set the Offset back and call the dialog again

LIST_OFFSET -= 10;
show_dlg(DLG_CONTENT);
}
else
{
// We're at the beginning of the options list - send the back-msg back to the calling script

llMessageLinked(REQUESTING_LINK, REQUESTING_SCRIPT, "back", AGENT_REQUEST);
}
}
else if(message == "Next...")
{
// The User wants to see the next portion of the options-list
// increment the list-offset and show the dialog again

LIST_OFFSET += 10;
show_dlg(DLG_CONTENT);
}
else
{
// The user has made her/his choice - send the answer back to the calling script

llMessageLinked(REQUESTING_LINK, REQUESTING_SCRIPT, CMD + "|" + message, AGENT_REQUEST);
}

}
}

timer()
{
llListenRemove(LISTENER_DLG);
}

on_rez(integer bla)
{
llResetScript();
}
}





****************

Here comes the second part - a.k.a. how to call this function

Alter this script an put it in whatever object in your linkset (or a single-prim object) where you need to call a dialog.

CODE


// Dialog-Caller
// By Haruki Watanabe

// This script is public domain - use it, share it, to whatever you wanna do... :)

// The MENU is just for example purposes - you can add your own list of choice here...
// Event something like ["Yes", "No"] to simply present a yes/no dialog

list MENU = ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th", "13th"];

integer THIS_SCRIPT = 1000; // Number of this script - will be used to determine, whether a linked message is meant for this script

key AGENT_REQUEST; // ID of the Agent that clicked

default
{
state_entry()
{
llSetText("func.show_dialog", <255,255,255>, 1.0);
}

touch_start(integer total_number)
{
AGENT_REQUEST = llDetectedKey(0);

// Call the script with the Dialog maker

// The String that we send to the dialog-function is parsed by a pipe-sign «|»
// 6 Parts
// 0 = SHOW_DIALOG -> To tell the dialog-maker, that it's its turn
// 1 = The menu-options as CSV-List
// 2 = The title of the Dialog
// 3 = The number of this script (will be sent back with llMessageLinked, when the user clicked an option
// 4 = Whether or not to show the shown entries / total entries in the dialog-title
// 5 = Whether or not to show a «back»-Button in the dialog

// 4 and 5 -> 1 = Yes, 0 = No

string to_send = "SHOW_DIALOG|" + llList2CSV(MENU) + "|Please choose an item|" + (string)THIS_SCRIPT + "|1|1";

llMessageLinked(0, 0, to_send, AGENT_REQUEST);
}

link_message(integer sender, integer num, string str, key id)
{
if(num == THIS_SCRIPT && id == AGENT_REQUEST)
{

// parse the message to look for Commands

list tmp = llParseString2List(str, ["|"], []);

string CMD = llList2String(tmp, 0);

if(CMD == "SHOW_DIALOG")
{
llOwnerSay("The Agent's answer to the dialog was '" + str + "'");
}
}
}
}



Mrc Homewood
Mentor of Randomness
Join date: 24 Feb 2007
Posts: 779
12-13-2007 16:35
not bad
Bloodsong Termagant
Manic Artist
Join date: 22 Jan 2007
Posts: 615
12-14-2007 08:01
heyas;

couldn't you just use llGetInventoryNumber for the 'script number'? hmm... though i guess link_message only gives you the prim sender number, not the script that sent it.


personally, i would prefer just a function i could drop into my own script, rather than sending messages between scripts. but if it can read button lists, do back/next when there's more than twelve, keep track of what page it's on.... im all over it ;)
_____________________
Why Johnny Can't Rotate:
http://forums.secondlife.com/showthread.php?t=94705
Haruki Watanabe
llSLCrash(void);
Join date: 28 Mar 2007
Posts: 434
12-14-2007 08:17
@Bloodsong

I give that a try - llGetInventoryNumber() would result in an integer that I could use as the «script-number». Assuming that this number isn't used anywhere else to listen to linked_messages, this should work and it would be more of an automated approach than giving the calling-script a number.
If you mean, I could use the «sender»-var provided by the link_message()-event - it's true, this only gives you the prim where the calling script is in (though I use this as well, so you can actually call the dialog-script from a child-prim as well and it'll direct the result to the correct link-prim). One possibility would be to add a «function-prim» to every object, where a script-collection of functions is in, so they wouldn't fill up the main-prim - and would be a little «hidden» from the public. So if you build a new project, all you need to do is rez your function-prim and link it to your object - and voilà - all your basic functions would be there (without the need to put them into the contents of the object)...

One of the reasons I made this script using linked-messages is, that I don't want the same code over and over in my other scripts. One of the problems I have with the built in editor is, that the code gets confusing very quick when it's getting longer.
I love having small pieces where I don't have to scroll for ages to find the part I wanna work on.
I'm gonna try to follow this approach a little more - next thing that I need over and over again is a function that reads notecards, so I'll try to put this into a similar «function-script»...

[EDIT]

Well - llGetInventoryNumber() doesn't work either as this command only returns the total number of scripts in the contents... (*duh*)