22.08.2013, 11:22
Introduction
As stated in wiki, the max ID of a dialog is 32767. This is more than enough in most cases, but sometimes you might need to exceed the limit. In other cases you might simply want to group your dialog types. Now - nobody said that the id's can't be reusable.
Defining the dialogs
Let's start with defining dialog groups
(notice the small letter in enum label - this causes it to be a weak tag)
Wrapping ShowPlayerDialog
Instead of messy switch statement in OnDialogResponse we can harness the power of automata (which uses same opcodes as switch, but looks fancier and cleaner at the same time). tagDialogGroup will grab tag automatically from dialogid argument and then set the state to the one we need (there is no possibility of assigning variable to state, and conditional state is not optimal in this case).
Adding commands and handlers
DIALOG_FOO has e_DIALOG_BASIC tag, and DIALOG_FOOBAR has e_DIALOG_ADVANCED tag. State values are equal to our tags (and e_DIALOG_BASIC is handled as default group). Everything works, let's celebrate! Using only just two groups we can handle up to 65536 dialogs. Whenever you want, you can add another group by adding 3 lines in ShowPlayerDialogEx, another enumerator and additional handler.
God damn it
Just as you are about to open the champagne, sudden realization hits you - we don't have any protection from cheaters and party crashers. That's not good. Usually it's handled by fixes.inc, but now it's not!
Let's fix it
We have two ways of doing this. One would require adding protection in every dialogresponse handler, and the other one requires us to get rid of magic state machines. The second option is easier, and that's what we are going to do. Good bye tidy code!
Fixes.inc is written by people who know pawn inside-out, so we will use it, while adding additional functionality.
Each player needs to have his current dialog group stored somewhere - earlier we dealt with it using state machines, now we have to do it manually.
We are assigning the tag of dialogid directly. In fact ShowPlayerDialogEx looks nicer now, and could be transformed into macro
Your choice.
And that's it. We can now use best of both worlds. Your whole additional logic (checking the dialogid, listitem selected, etc.) goes inside specific case. Additionally you can add some actions which will fire up on multiple dialog groups, or all of them.
That's all folks!
As stated in wiki, the max ID of a dialog is 32767. This is more than enough in most cases, but sometimes you might need to exceed the limit. In other cases you might simply want to group your dialog types. Now - nobody said that the id's can't be reusable.
Defining the dialogs
Let's start with defining dialog groups
pawn Code:
enum e_DIALOG_BASIC {
DIALOG_FOO,
DIALOG_BAR
}
enum e_DIALOG_ADVANCED {
DIALOG_FOOBAR,
DIALOG_BARFOO
}
Wrapping ShowPlayerDialog
pawn Code:
stock ShowPlayerDialogEx(playerid, dialogid, style, caption[], info[], button1[], button2[], tagDialogGroup = tagof dialogid) {
switch(tagDialogGroup) {
case (tagof e_DIALOG_ADVANCED): {
state dialogHandler:e_DIALOG_ADVANCED;
}
default: {
state dialogHandler:e_DIALOG_BASIC;
}
}
return ShowPlayerDialog(playerid, dialogid, style, caption, info, button1, button2);
}
Adding commands and handlers
pawn Code:
CMD:basic(id, params[]) {
return ShowPlayerDialogEx(id, DIALOG_FOO, DIALOG_STYLE_MSGBOX, "Basic text", "Basic info", "Ok", "Have fun");
}
CMD:adv(id, params[]) {
return ShowPlayerDialogEx(id, DIALOG_FOOBAR, DIALOG_STYLE_MSGBOX, "Adv text", "Adv info", "Ok", "Have fun");
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) <> {
printf("Dialog %d of BASIC", dialogid);
return 1;
}
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) <dialogHandler:e_DIALOG_ADVANCED> {
printf("Dialog %d of Advanced", dialogid);
return 1;
}
God damn it
Just as you are about to open the champagne, sudden realization hits you - we don't have any protection from cheaters and party crashers. That's not good. Usually it's handled by fixes.inc, but now it's not!
Let's fix it
We have two ways of doing this. One would require adding protection in every dialogresponse handler, and the other one requires us to get rid of magic state machines. The second option is easier, and that's what we are going to do. Good bye tidy code!
Fixes.inc is written by people who know pawn inside-out, so we will use it, while adding additional functionality.
pawn Code:
new PlayerDialogGroup[MAX_PLAYERS];
pawn Code:
stock ShowPlayerDialogEx(playerid, dialogid, style, caption[], info[], button1[], button2[], tagDialogGroup = tagof dialogid) {
PlayerDialogGroup[playerid] = tagDialogGroup;
return ShowPlayerDialog(playerid, dialogid, style, caption, info, button1, button2);
}
pawn Code:
#define ShowPlayerDialogEx(%1,%2,%3,%4,%5,%6,%7) (PlayerDialogGroup[%1] = tagof(%2), ShowPlayerDialog(%1,%2,%3,%4,%5,%6,%7))
pawn Code:
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[]) {
switch(PlayerDialogGroup[playerid]) {
case (tagof e_DIALOG_ADVANCED): {
printf("Dialog %d of ADVANCED", dialogid);
}
default: {
printf("Dialog %d of BASIC", dialogid);
}
}
return 1;
}
That's all folks!