[Tutorial] Interactive Dialogs
#1

Interactive Dialogs


[ame="http://www.youtube.com/watch?v=QLYC6-zMjNo"]http://www.youtube.com/watch?v=QLYC6-zMjNo[/ame]
Hello folks!
I would like to share this great tutorial on interactive dialogs, meaning that you can add or remove listitems of a
dialog while it is being shown to one or more players, making it look like the dialog updates its items. I found this
tutorial here, and I thought I translate it for you guys. I do not take credit for any of this. This is a tutorial created
by a guy named Jeffry on the German SA:MP board. You can find the original text here.

Short Overview

You might wonder what this is good for. It’s simple – with a few methodical steps, neat little functions and enough
working effort you will be able to create a dialog that updates its content on occasions you want it to update! Of
course, it’s up to you to choose where or how exactly to implement it. This is merely a general tutorial on how this
whole stuff works. In fact, we won’t be using any timers in this tutorial, making it even more efficient. Move along,
and you will see!

Let’s go through the code!

Step 1 – Variables

First thing’s first – variables. In order for us to later be able to know which player has currently opened a dialog, we
need to declare a global variable for all players. And let’s set the variable’s value straight to -1 to avoid mistakes.

pawn Код:
new DialogOpened[MAX_PLAYERS] = {-1,…};
Next, we need to declare the variables that allow us to handle our dialogs easier. This way we avoid having multiple
repeating code blocks, keeping the code shorter and giving us a much better overview.
First, we define a constant that determines the maximum amount of dialogs being used in your gamemode (it’s really
up to you to set this value).

pawn Код:
#define MAX_DIALOGS 100
Moving on with the variables. We need 4 more global ones for the caption, the info and the two buttons.

pawn Код:
new Caption[MAX_DIALOGS][36];
new Info[MAX_DIALOGS][256];
new Button1[MAX_DIALOGS][8];
new Button2[MAX_DIALOGS][8];
Step 2 – stock functions

These little functions ensure that we can easily handle our dialogs. Since we are talking about dialogs, we need to
modify ShowPlayerDialog a little bit.

pawn Код:
stock ShowUpdateDialog(playerid, dialogid, style, caption[], info[], button1[], button2[])
{
    //This simply states that the player (playerid) has opened a certain dialog (dialogid).
    DialogOpened[playerid] = dialogid;

    //Next, we just go ahead and show the player the dialog like we are used to.
    ShowPlayerDialog(playerid, dialogid, style, caption, info, button1, button2);

    //If an existing dialog has been opened, the according data shown in the dialog will be saved in our global
    //variables.
    if(dialogid > -1 && dialogid < MAX_DIALOGS)
    {
        format(Caption[dialogid], sizeof(Caption[]), caption);
        format(Info[dialogid], sizeof(Info[]), info);
        format(Button1[dialogid], sizeof(Button1[]), button1);
        format(Button2[dialogid], sizeof(Button2[]), button2);
    }
    return 1;
}
Since we’re at the subject, let’s go ahead and create more of those neat little functions.

pawn Код:
stock GetPlayerDialog(playerid)
{
        return DialogOpened[playerid];
}
stock GetDialogCaption(dialogid) return Caption[dialogid];
stock GetDialogInfo(dialogid) return Info[dialogid];
stock GetDialogButton1(dialogid) return Button1[dialogid];
stock GetDialogButton2(dialogid) return Button2[dialogid];

//And to make life a tad bit easier, let’s also add this one.
stock PlayerName(playerid)
{
    new pName[MAX_PLAYER_NAME];
    GetPlayerName(playerid, pName, sizeof(pName));
    return pName;
}
Step 3 – Adding and removing items

This is an essential part of this whole tutorial. Let’s begin with adding items to a dialog. We create the function
"AddItemToDialog” by passing the dialogid and the text of the listitem. In order to make sure that we are not facing
any troubles, we check whether the same item is already in the list. If so it gets removed and again added.

pawn Код:
stock AddItemToDialog(dialogid, item[])
{  
    //We search the item.
    new ItemPosition = strfind(Info[dialogid], item);

    //If the item has been found, it will be deleted.
    if(ItemPosition != -1) strdel(Info[dialogid], ItemPosition, ItemPosition(item)  + strlen(item) + 1);

    //Afterwards, the item will be added to the list.
    format(Info[dialogid], sizeof(Info[]), “%s%s\n”, Info[dialogid], item);
   
    //We finish the function by updating the dialog for all players.
    return UpdateDialogForAll(dialogid);
}
The removing function looks pretty much the same, only with a few minor differences.

pawn Код:
stock RemoveItemFromDialog(dialogid, item[])
{
    //We search the item.
    new ItemPosition = strfind(Info[dialogid], item);

    //If the item has not been found, nothing will be done.
    if(ItemPosition == -1) return 0;

    //Else it will be removed.
    strdel(Info[dialogid], ItemPosition, ItemPosition + strlen(item) + 1);

    //Again, we finish the function by updating the dialog for all players.
    return UpdateDialogForAll(dialogid);
}
You certainly have noticed that our last two functions returned “UpdateDialogForAll”, but we don’t have such a function until now. Let’s quickly change that!

pawn Код:
stock UpdateDialogForAll(dialogid)
{
    //We do a loop through all players (i)
    for(new i = 0; i < MAX_PLAYERS; i++)
    {
        if(DialogOpened[i] == dialogid) //If the player has currently opened an edited/updated dialog…
        {
            //…we simply show it to him again with the new updated content.
            ShowPlayerDialog(i, DialogOpened[i], DIALOG_STYLE_LIST, Caption[DialogOpened[i]], Info[DialogOpened[i]], Button1[DialogOpened[i]], Button2[DialogOpened[i]]);
        }
    }
    return 1;
}
Short explanation of Info[DialogOpened[i]].
What does it do? It calls the info text (global variable “Info”) from the dialogid (DialogOpened) the player has
opened.

There is one more function we need for our system. We want to have a function that returns an item on the basis of
a listitem from OnDialogResponse. We simply need to count the word wraps (\n). If the right amount has been found
(=listitem), the string will be splitted and the item will be returned.

pawn Код:
stock GetItemFromDialog(dialogid, listitem)
{
    new string[64], count, lastpos = -1, tmp[sizeof(Info[])];
    for(new i = 0; i < strlen(Info[dialogid]); i++)
    {
        if(Info[dialogid][i] == '\n')
        {
            if(count == listitem)
            {
                tmp = Info[dialogid];
                strdel(tmp, i, strlen(Info[dialogid]));
                strdel(tmp, 0, lastpos + 1);
                break;
            }
            count++;
            lastpos = i;
        }
    }
    format(string, sizeof(string), tmp);
    return string;
}
Step 4 – Callbacks

Phew, we’re almost there! Let’s take a look at the callbacks we need to feed with some code!

pawn Код:
public OnPlayerDisconnect(playerid, reason)
{
    //We set the value of the player’s variable to -1 since a disconnected player can’t have a dialog opened.
    DialogOpened[playerid] = -1;
    return 1;
}
Last but not least, I will provide you with some examples. I will be using ZCMD, just for the sake of simplicity. You can use whatever you want.

pawn Код:
COMMAND:showlist(playerid, params[])
{
    //If the length of the info text equals 0, then there are no items listed.
    if(!strlen(GetDialogInfo(0))) return SendClientMessage(playerid, -1, “Nobody is listed in this dialog.”);

    //Else, the dialog will be shown to the player.
    ShowUpdateDialog(playerid, 0, DIALOG_STYLE_LIST, “Example”, GetDialogInfo(0), “OK”, “Cancel”);
}

COMMAND:additem(playerid, params[])
{
    //We add our name to the list with the ID 0.
    AddItemToDialog(0, PlayerName(playerid));
    return 1;
}

COMMAND:removeitem(playerid, params[])
{
    //We remove our name from the list with the ID 0.
    RemoveItemFromDialog(0, PlayerName(playerid));
    return 1;
}
And some examples for OnDialogResponse.

pawn Код:
public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    //If the player selects something the dialog will always be closed. So we set our value to -1 since after closing a dialog it is not opened anymore.
    DialogOpened[playerid] = -1;

    //Here, we check whether the dialogid is 0 and whether the first button (button1) has been pressed.
    if(dialogid == 0 && response == 1)
    {
        //We search for the player ID on the basis of the name that has been entered in the list.
        new item[64], founded = -1;
   
        //We return the name on the basis of the listitem using the following function:
        item = GetItemFromDialog(dialogid, listitem);

        //If a wrong listitem has been passed, an error message will be sent.
        if(!strlen(item)) return SendClientMessage(playerid, -1, “ERROR: Item could not be found.”);

        //Eventually, we search for the name of the player.
        for(new = 0; i < MAX_PLAYERS; i++)
        {
            if(IsPlayerConnected(i) && !strcmp(PlayerName(i), item))
            {
                //If the name has been found, it will be saved to our variable and the loop will be stopped.
                foundid = i;
                break;
            }
        }
        //Now, we can do whatever we want, but let’s just stick to a simple client message.
        new string[150];
        format(string, sizeof(string), “INFO: I have clicked %s with the ID %d.”, PlayerName(foundid), foundid);
        return SendClientMessage(playerid, -1, string);
    }
    return 0;
}
That was it! I hope you learn something from this!
Please inform me about errors of any kind. I will fix them if necessary.

------------------------------------------------------------------
Edit1: Typo.
Edit2: Typo & added a sample video.
Edit3: Code fixes.
Edit4: Code fixes again. It should be fully functional now.
Reply
#2

Oh, this is nice
Never thought if it was even possible.

Thanks to you and Jeffery!
Reply
#3

Schreenshots have?
Reply
#4

I have added a sample video from Jeffry on top of the tutorial.
Reply
#5

I have to say Manyula translated this very very well! Once again Thanks to him for his effort, to share this Tutorial/Code here too. Hopefully it will be helpful for some people around.

+Rep for you!
Reply
#6

Thank you very much! I hope too that this method will be applied by many advanced scripters. I'm still on it, it's not that easy, I must admit.
Reply
#7

you did a great job!
Reply
#8

Good tutorial! Very good, Thanks
Reply
#9

Lovely Bro
Reply
#10

Thank you for your feedback! I've fixed some minor typos. The code should be fully functional now.
Reply
#11

very nice
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)