14.04.2015, 16:54
Introduction
This tutorial continues my series on the new features available in YSI 3.0. As I strive to get it stable and released, these tutorials should give people an idea of what's available and thus make it easier for people to test them and find bugs (please report any you find).
There are a number of dialog processing systems already, but they all have (IMHO) one fundamental flaw - they all still rely on dialog IDs. "y_dialog" does away with this requirement, instead maintaining a record of what IDs are in use internally and providing an API to get an available free one (if you even need to).
Example
This is basically the same API as before (you can still use the old functions and the system will register those IDs as in use), but with no "dialog" parameter. In actual fact, it is still there, it's just at the end.
Reuse
The optional existence of the "dialog" parameter means you can ignore it entirely (the second button parameter can also be left out), or you can give an ID when it is appropriate.
Showing a dialog to some set of players:
This way the same dialog seen by every player will always have the same ID (making processing easier). You could even register the ID in "OnGameModeInit" and always use that ID, ensuring that no two dialogs will ever conflict (and as with any YSI library, this works in all scripts at once):
Or, if it is a dialog that will only be used once, you can tell the system to reclaim the ID after no-one can see it ("garbage" collection):
"Garbage" will be automatically set for any dialog which is only shown to one player and for which no explicit dialog ID was provided:
In the code above "id" is initially set to "-1" (which means "assign an ID"), so the system assigns an ID for the first player, marks the ID as garbage (to be reclaimed when no-one can see the dialog any more) and returns this new ID. When the dialog is shown to the second player the existing ID is re-used but "garbage" status IS NOT cleared. This makes the code above DIFFERENT to the code in which "Dialog_ObtainID" is explicitly called first. Your choice of function call should reflect this difference.
Functions
There are a few other functions available for use:
Callbacks
There is one very important feature of y_dialogs that makes it (again, IMHO) vastly better than any other dialog processing system and that is it's ability to use "y_inline" for single dialog response processing instead of "OnDialogResponse":
That is all there is to processing a dialog using this system. The dialog id does not appear anywhere in that code (there is the variable "dialogid" passed to the inline function, but you don't need it). "inline" functions are mostly like normal functions, except they can be embedded inside other functions (including inside other "inline" functions).
There are a few VERY important things to note here:
You can also combine processing and show a dialog with a callback to mulitple people (and mark it as garbage or not).
This tutorial continues my series on the new features available in YSI 3.0. As I strive to get it stable and released, these tutorials should give people an idea of what's available and thus make it easier for people to test them and find bugs (please report any you find).
There are a number of dialog processing systems already, but they all have (IMHO) one fundamental flaw - they all still rely on dialog IDs. "y_dialog" does away with this requirement, instead maintaining a record of what IDs are in use internally and providing an API to get an available free one (if you even need to).
Example
pawn Код:
new
id = Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Title", "Message", "Button 1");
Reuse
The optional existence of the "dialog" parameter means you can ignore it entirely (the second button parameter can also be left out), or you can give an ID when it is appropriate.
Showing a dialog to some set of players:
pawn Код:
new
id = Dialog_ObtainID();
foreach (new i : Player)
{
if (ShouldSeeDialog(i))
{
Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Title", "Message", "Button 1", .dialog = id);
}
}
pawn Код:
#include <YSI\y_dialog>
new
gID = -1;
public OnGameModeInit()
{
gID = Dialog_ObtainID();
}
public OnPlayerConnect(playerid)
{
Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Welcome", "Welcome to the server!", "OK", "Cancel", gID);
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
if (dialogid == gID)
{
printf("player %d pressed %d", playerid, response);
}
return 1;
}
pawn Код:
new
id = Dialog_ObtainID();
foreach (new i : Player)
{
if (ShouldSeeDialog(i))
{
Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Title", "Message", "Button 1", .dialog = id);
}
}
Dialog_Garbage(id);
pawn Код:
new
id = -1;
foreach (new i : Player)
{
if (ShouldSeeDialog(i))
{
id = Dialog_Show(playerid, DIALOG_STYLE_MSGBOX, "Title", "Message", "Button 1", .dialog = id);
}
}
Functions
There are a few other functions available for use:
- Dialog_Get(playerid)
Get the ID of the dialog this player can currently see. Note that if you call this function in "OnDialogResponse" it WILL NOT return the correct ID as the player can no longer see it (but you still have "dialogid" there anyway).
- Dialog_Set(playerid, dialogid)
It's doubtful that you will ever need this function, but this is the opposite of "Dialog_Get".
- Dialog_Hide(playerid)
Hide the dialog that the player is currently viewing.
- ShowPlayerDialog(playerid, dialog, style, string:title[], string:caption[], string:button1[], string:button2[])
Callbacks
There is one very important feature of y_dialogs that makes it (again, IMHO) vastly better than any other dialog processing system and that is it's ability to use "y_inline" for single dialog response processing instead of "OnDialogResponse":
pawn Код:
public OnPlayerConnect(playerid)
{
inline Response(pid, dialogid, response, listitem, string:inputtext[])
{
#pragma unused pid, dialogid, response, listitem, inputtext
SendClientMessage(playerid, 0xFF0000AA, "You clicked a button! Good for you!");
// Inline function will end here.
}
Dialog_ShowCallback(playerid, using inline Response, DIALOG_STYLE_MSGBOX, "Title", "Message", "Button 1");
// Main function will end here.
}
There are a few VERY important things to note here:
- The callback "OnPlayerConnect" has a parameter called "playerid", the callback "OnDialogResponse" ALSO has a parameter called "playerid", and the "Response" inline function has the same parameters as "OnDialogResponse". However, you can't have two variables with the same name in one function so the second "playerid" has been renamed "pid".
- Further to the point above, "SendClientMessage" uses "playerid" NOT "pid". "OnPlayerConnect" is called when the player connects, "Response" is called when the player clicks something on the dialog (which could be many hours later if they're AFK). Despite this fact, you can still use "playerid" (and any other variable from the enclosing function) inside "Response" thanks to a feature called "closures".
- Strings do work, but strings passed to the enclosing function (there are none here) DO NOT work as they're a little different. Also, any string that is a parameter to an inline function (for example "inputtext") must be declared with the tag "string:", as above.
You can also combine processing and show a dialog with a callback to mulitple people (and mark it as garbage or not).