[Tutorial] Making a simple PM system with ZCMD & sscanf
#1

Hi there, I'll show you have to make a simple PM command system using ZCMD (Click Me!) and sscanf.

First off, lets include zcmd (download it if you don't have it).
pawn Код:
#include <zcmd>
So now we can use zcmd!

Now, lets create the command pm.
pawn Код:
CMD:pm(playerid, params[])
{
    return 1;
}
Now that we have the actual command, we can start declaring new things to add.

pawn Код:
new str[128], str2[128], id, Name1[MAX_PLAYER_NAME], Name2[MAX_PLAYER_NAME];
We need to make those, so we don't get "Unknown Symbol".

So, next up is using sscanf to check if the player typed anything after "/pm"
pawn Код:
if(sscanf(params, "us", id, str2))
{
    SendClientMessage(playerid, 0xFF0000FF, "Usage: /pm <id/name> <message>");
    return 1;
}
Lets sort it out:
u = ID, or Name.
s = string.

{Float,_}:...
ID/Name = The ID/Name they inserted into their PM.
str2 = The message they inserted into their PM.

------------------------------------------------

So now that we have checked if they inserted a ID and Message, sscanf automatically assigns it to the declaration.

so no need to do str2 = strrest(params, idx). (Thank god ******).

Next we check if the player they entered is connected or not:
pawn Код:
if(!IsPlayerConnected(id)) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: That player is not connected!");
//We did IsPlayerConnected(id)) because we are checking the player they want to send the pm too.
Now we check if they sent the PM to themselves, or another person.
pawn Код:
if(playerid != id) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: You cannot pm yourself!");
So now we move on to sending the messages!

First off, we need to get the player's name, and the receiver's name.
pawn Код:
GetPlayerName(playerid, Name1, sizeof(Name2)); //The Sender's Name so we use (playerid).
GetPlayerName(id, Name2, sizeof(Name2)); //The Receiver's Name so we use (id).

Then, now that we have their names, we format the string (message) to send/receive.
pawn Код:
//This is where we use string #1 (str). Now that we have created, we float The Receiver's name, their ID, and the message!
format(str, sizeof(str), "PM To %s(ID %d): %s", Name2, id, str2);
//Now we send the sender a message repeating what they sent to the receiver:
SendClientMessage(playerid, 0xFF0000FF, str); //Notice its (playerid, not id)

//Now we repeat the first format, but we change it a little, this is the message getting sent to the receiver:
format(str, sizeof(str), "PM From %s(ID %d): %s", Name1, playerid, str2);
//Float Sender's Name, Sender's ID, and Sender's Message.

//After we have formated the message, we send it to the receiver!
SendClientMessage(id, 0xFF0000FF, Message); //Notice its (id, not playerid).

And so, with all of this added, it should look something like this:
pawn Код:
CMD:pm(playerid, params[])
{
    new str[256], str2[256], id, Name1[MAX_PLAYER_NAME], Name2[MAX_PLAYER_NAME];
    if(sscanf(params, "us", id, str2))
    {
        SendClientMessage(playerid, 0xFF0000FF, "Usage: /pm <id> <message>");
        return 1;
    }
    if(!IsPlayerConnected(id)) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: Player not connected");
    if(playerid == id) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: You cannot pm yourself!")
    {
        GetPlayerName(playerid, Name1, sizeof(Name1));
        GetPlayerName(id, Name2, sizeof(Name2));
        format(str, sizeof(str), "PM To %s(ID %d): %s", Name2, id, str2);
        SendClientMessage(playerid, 0xFF0000FF, str);
        format(str, sizeof(str), "PM From %s(ID %d): %s", Name1, playerid, str2);
        SendClientMessage(id, 0xFF0000FF, str);
    }
    return 1;
}
Hoped this helped!

| - The Toni - |
Reply
#2

Excellent tutorial.
Reply
#3

teheh nice i can easily change that to dcmd xD tanks a lot
Reply
#4

Quote:
Originally Posted by willsuckformoney
Посмотреть сообщение
teheh nice i can easily change that to dcmd xD tanks a lot


would you mind giving me that dcmd coding when you finish it? =D (im too lazy to do it myself)
Reply
#5

just change CMDm to dcmd_pm
Reply
#6

^^ && sure i was busy with other stuff /me /finish now xD
Reply
#7

Awesome xD, Nice job
Reply
#8

Thanks guy
Reply
#9

I got a problem

Did everything right, i gues, put the include
Код:
#include <zcmd>
and the code
Код:
CMD:es(playerid, params[])
{
    new str[256], str2[256], id, Name1[MAX_PLAYER_NAME], Name2[MAX_PLAYER_NAME];
    if(sscanf(params, "us", id, str2))
    {
    	SendClientMessage(playerid, 0xFF0000FF, "Vihje: /es <id> <sхnum>");
  		return 1;
    }
    if(!IsPlayerConnected(id)) return SendClientMessage(playerid, 0xFF0000FF, "VIGA: Player not connected");
    if(playerid != id) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: You cannot pm yourself!");
    {
		GetPlayerName(playerid, Name1, sizeof(Name1));
 		GetPlayerName(id, Name2, sizeof(Name2));
        format(str, sizeof(str), "ES kasutajalt %s(ID %d): %s", Name2, id, str2);
        SendClientMessage(playerid, 0xFF0000FF, str);
        format(str, sizeof(str), "ES kasutajalt %s(ID %d): %s", Name1, playerid, str2);
        SendClientMessage(id, 0xFF0000FF, str);
    }
    return 1;
}
but i keep getting this error while i try to compile it ( just started scripting, i think i'm with good brain... just dont figure this out )

Код:
C:\Documents and Settings\Owner\Desktop\BBRP GM\gamemodes\bbrp.pwn(51) : error 017: undefined symbol "sscanf"
Pawn compiler 3.2.3664	 	 	Copyright © 1997-2006, ITB CompuPhase


1 Error.
Btw. It's translated to Estonian, as you can see, dont mind that ^^.
Reply
#10

Uh, uh. This would be working optimized code.

pawn Code:
CMD:pm(playerid, params[])
{
    new str[128],id,pname[MAX_PLAYER_NAME];
    if(sscanf(params, "us", id, params)) SendClientMessage(playerid, 0xFF0000FF, "Usage: /pm <id> <message>");
    else if(id == INVALID_PLAYER_ID) SendClientMessage(playerid, 0xFF0000FF, "ERROR: Player not connected");
    if(playerid == id) SendClientMessage(playerid, 0xFF0000FF, "ERROR: You cannot pm yourself!")
    else
    {
        GetPlayerName(id, pname, sizeof(pname));
        format(str, sizeof(str), "PM To %s(ID %d): %s", pname, id, params);
        SendClientMessage(playerid, 0xFF0000FF, str);
        GetPlayerName(playerid, pname, sizeof(pname));
        format(str, sizeof(str), "PM From %s(ID %d): %s", pname, playerid, params);
        SendClientMessage(id, 0xFF0000FF, str);
    }
    return 1;
}
Reply
#11

Quote:
Originally Posted by M3ntaL
Посмотреть сообщение
I got a problem

Did everything right, i gues, put the include
Код:
#include <zcmd>
and the code
Код:
CMD:es(playerid, params[])
{
    new str[256], str2[256], id, Name1[MAX_PLAYER_NAME], Name2[MAX_PLAYER_NAME];
    if(sscanf(params, "us", id, str2))
    {
    	SendClientMessage(playerid, 0xFF0000FF, "Vihje: /es <id> <sхnum>");
  		return 1;
    }
    if(!IsPlayerConnected(id)) return SendClientMessage(playerid, 0xFF0000FF, "VIGA: Player not connected");
    if(playerid != id) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: You cannot pm yourself!");
    {
		GetPlayerName(playerid, Name1, sizeof(Name1));
 		GetPlayerName(id, Name2, sizeof(Name2));
        format(str, sizeof(str), "ES kasutajalt %s(ID %d): %s", Name2, id, str2);
        SendClientMessage(playerid, 0xFF0000FF, str);
        format(str, sizeof(str), "ES kasutajalt %s(ID %d): %s", Name1, playerid, str2);
        SendClientMessage(id, 0xFF0000FF, str);
    }
    return 1;
}
but i keep getting this error while i try to compile it ( just started scripting, i think i'm with good brain... just dont figure this out )

Код:
C:\Documents and Settings\Owner\Desktop\BBRP GM\gamemodes\bbrp.pwn(51) : error 017: undefined symbol "sscanf"
Pawn compiler 3.2.3664	 	 	Copyright © 1997-2006, ITB CompuPhase


1 Error.
Btw. It's translated to Estonian, as you can see, dont mind that ^^.
You need the plugin sscanf - or this code;
pawn Код:
stock sscanf(string[], format[], {Float,_}:...)
{
    #if defined isnull
    if (isnull(string))
    #else
    if (string[0] == 0 || (string[0] == 1 && string[1] == 0))
    #endif
    {
        return format[0];
    }
    #pragma tabsize 4
    new
        formatPos = 0,
        stringPos = 0,
        paramPos = 2,
        paramCount = numargs(),
        delim = ' ';
    while (string[stringPos] && string[stringPos] <= ' ')
    {
        stringPos++;
    }
    while (paramPos < paramCount && string[stringPos])
    {
        switch (format[formatPos++])
        {
            case '\0':
            {
                return 0;
            }
            case 'i', 'd':
            {
                new
                    neg = 1,
                    num = 0,
                    ch = string[stringPos];
                if (ch == '-')
                {
                    neg = -1;
                    ch = string[++stringPos];
                }
                do
                {
                    stringPos++;
                    if ('0' <= ch <= '9')
                    {
                        num = (num * 10) + (ch - '0');
                    }
                    else
                    {
                        return -1;
                    }
                }
                while ((ch = string[stringPos]) > ' ' && ch != delim);
                setarg(paramPos, 0, num * neg);
            }
            case 'h', 'x':
            {
                new
                    num = 0,
                    ch = string[stringPos];
                do
                {
                    stringPos++;
                    switch (ch)
                    {
                        case 'x', 'X':
                        {
                            num = 0;
                            continue;
                        }
                        case '0' .. '9':
                        {
                            num = (num << 4) | (ch - '0');
                        }
                        case 'a' .. 'f':
                        {
                            num = (num << 4) | (ch - ('a' - 10));
                        }
                        case 'A' .. 'F':
                        {
                            num = (num << 4) | (ch - ('A' - 10));
                        }
                        default:
                        {
                            return -1;
                        }
                    }
                }
                while ((ch = string[stringPos]) > ' ' && ch != delim);
                setarg(paramPos, 0, num);
            }
            case 'c':
            {
                setarg(paramPos, 0, string[stringPos++]);
            }
            case 'f':
            {
                setarg(paramPos, 0, _:floatstr(string[stringPos]));
            }
            case 'p':
            {
                delim = format[formatPos++];
                continue;
            }
            case '\'':
            {
                new
                    end = formatPos - 1,
                    ch;
                while ((ch = format[++end]) && ch != '\'') {}
                if (!ch)
                {
                    return -1;
                }
                format[end] = '\0';
                if ((ch = strfind(string, format[formatPos], false, stringPos)) == -1)
                {
                    if (format[end + 1])
                    {
                        return -1;
                    }
                    return 0;
                }
                format[end] = '\'';
                stringPos = ch + (end - formatPos);
                formatPos = end + 1;
            }
            case 'u':
            {
                new
                    end = stringPos - 1,
                    id = 0,
                    bool:num = true,
                    ch;
                while ((ch = string[++end]) && ch != delim)
                {
                    if (num)
                    {
                        if ('0' <= ch <= '9')
                        {
                            id = (id * 10) + (ch - '0');
                        }
                        else
                        {
                            num = false;
                        }
                    }
                }
                if (num && IsPlayerConnected(id))
                {
                    setarg(paramPos, 0, id);
                }
                else
                {
                    #if !defined foreach
                        #define foreach(%1,%2) for (new %2 = 0; %2 < MAX_PLAYERS; %2++) if (IsPlayerConnected(%2))
                        #define __SSCANF_FOREACH__
                    #endif
                    string[end] = '\0';
                    num = false;
                    new
                        name[MAX_PLAYER_NAME];
                    id = end - stringPos;
                    foreach (Player, playerid)
                    {
                        GetPlayerName(playerid, name, sizeof (name));
                        if (!strcmp(name, string[stringPos], true, id))
                        {
                            setarg(paramPos, 0, playerid);
                            num = true;
                            break;
                        }
                    }
                    if (!num)
                    {
                        setarg(paramPos, 0, INVALID_PLAYER_ID);
                    }
                    string[end] = ch;
                    #if defined __SSCANF_FOREACH__
                        #undef foreach
                        #undef __SSCANF_FOREACH__
                    #endif
                }
                stringPos = end;
            }
            case 's', 'z':
            {
                new
                    i = 0,
                    ch;
                if (format[formatPos])
                {
                    while ((ch = string[stringPos++]) && ch != delim)
                    {
                        setarg(paramPos, i++, ch);
                    }
                    if (!i)
                    {
                        return -1;
                    }
                }
                else
                {
                    while ((ch = string[stringPos++]))
                    {
                        setarg(paramPos, i++, ch);
                    }
                }
                stringPos--;
                setarg(paramPos, i, '\0');
            }
            default:
            {
                continue;
            }
        }
        while (string[stringPos] && string[stringPos] != delim && string[stringPos] > ' ')
        {
            stringPos++;
        }
        while (string[stringPos] && (string[stringPos] == delim || string[stringPos] <= ' '))
        {
            stringPos++;
        }
        paramPos++;
    }
    do
    {
        if ((delim = format[formatPos++]) > ' ')
        {
            if (delim == '\'')
            {
                while ((delim = format[formatPos++]) && delim != '\'') {}
            }
            else if (delim != 'z')
            {
                return delim;
            }
        }
    }
    while (delim > ' ');
    return 0;
}
But I think the plugin is much more effective.

@ Sergei, yeah, as there are lots of ways to do it.
Reply
#12

k, tnx, got it work, nice tutorial btw
Reply
#13

@The Toni, there should be only one way. I don't know why people who write tutorials put some effort, so other people can learn efficent coding.

Code:
    if(playerid != id) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: You cannot pm yourself!");
    {
Two mistakes in two lines of code.
Reply
#14

Quote:
Originally Posted by Sergei
View Post
@The Toni, there should be only one way. I don't know why people who write tutorials put some effort, so other people can learn efficent coding.

Code:
    if(playerid != id) return SendClientMessage(playerid, 0xFF0000FF, "ERROR: You cannot pm yourself!");
    {
Two mistakes in two lines of code.
I do put effort, but you have to admit, not everyone knows everything. Now I know that you can use a string array for more then one format!
Reply
#15

You could also do without openning pname array!

pawn Code:
new str[128], id;
GetPlayerName(id, str, 24);
format(str, sizeof(str), "PM To %s(ID %d): %s", str, id, params);
Reply
#16

Quote:
Originally Posted by Sergei
View Post
You could also do without openning pname array!

pawn Code:
new str[128], id;
GetPlayerName(id, str, 24);
format(str, sizeof(str), "PM To %s(ID %d): %s", str, id, params);
Thanks, got that now
Reply
#17

Thanks for the tutorial, but is there a way to make your PM message in two lines, if your message is too big?

PM from Player: first line here i am talking and how are yo...
...u continue here.
Reply
#18

Quote:
Originally Posted by Blades
View Post
Thanks for the tutorial, but is there a way to make your PM message in two lines, if your message is too big?

PM from Player: first line here i am talking and how are yo...
...u continue here.
Increase the string size, that should work.
Reply
#19

Quote:
Originally Posted by The Toni
View Post
Increase the string size, that should work.
What I mean is, I want it to be scripted somehow so when it reaches a certain amount of the text, it will make a new line and continue it.
Reply
#20

Sorry for bump, but I really need this. Can anyone help me with what I mentioned above?
Reply


Forum Jump:


Users browsing this thread: 5 Guest(s)