[Tutorial] How to: Implement Roleplay Chats [zcmd, sscanf, foreach]
#1

How to: Implement Roleplay Chats

Getting Started
Stocks
Before we begin, we will also need a couple of useful functions that will make scripting tons easier.
Note: Stock and public functions are alike in many ways, however the main difference between the two is that stocks may not be called via SetTimer, CallRemoteFunction, etc...
  • Removing "_" from a name.
    In order to do so, we need a string replace function.
    pawn Код:
    stock strreplace(string[], find, replace)
    {
        for(new i=0; string[i]; i++)
        {
            if(string[i] == find)
            {
                string[i] = replace;
            }
        }
    }
    Here is an example of how the string replace stock would replace an underscore from a name.
    pawn Код:
    new name[24];
    GetPlayerName(playerid, name, sizeof(name));
    strreplace(name, '_', ' ');
    Confused? I'll break it down for you.

    pawn Код:
    new
        name[24];
    This just simply defines a string called 'name' with the size of 24. (24 is the max string size of a player name in SA:MP)
    pawn Код:
    GetPlayerName(playerid, name, sizeof(name));
    Using the native function GetPlayerName, we grab the 'name' string, get the name of the player, and store it into the string in the second parameter.
    pawn Код:
    strreplace(name, '_', ' ');
    This is the string replace function in use. The first parameter gets the string. The second one finds what you want to find in the string (which in this case it's the underscore). The last one replaces the characters in the second parameter with the one in the third. So if we want to remove the underscore, we first search for it, and replace it with an empty(null) character (a space).

    So now that we have that, we will make another stock called GetName that will be used later in the tutoral.
    pawn Код:
    stock GetName(playerid)
    {
        new
            name[24];
        GetPlayerName(playerid, name, sizeof(name));
        strreplace(name, '_', ' ');
        return name;
    }
  • ProxDetector
    For those who don't know, the famous ProxDetector function was introduced in The Godfather Roleplay. Every time a player would type something into the main chat, it would send the message to the nearby players only, and according to their distance from a player, the message would appear darker or lighter. For instance, if I was 30 feet from a player and they typed in the normal chat, the message would come to me dark. If I were to move closer, the message would become lighter. This function was responsible for making the server chat 'realistic' by sending the message to only the players nearby.
    Note: Using the easier-to-understand version, the changing in color in light of the player distance will not be featured.
    pawn Код:
    stock ProxDetector(Float:radi, playerid, string[],color)
    {
        new Float:x,Float:y,Float:z;
        GetPlayerPos(playerid,x,y,z);
        foreach(Player,i)
        {
            if(IsPlayerInRangeOfPoint(i,radi,x,y,z))
            {
                SendClientMessage(i,color,string);
            }
        }
    }
    Still confused? I'll break it down for you.

    pawn Код:
    new Float:x,Float:y,Float:z;
    This line defines floats that will hold the position of the player. It is important you use the "Float:" tag, because coordinates are decimal numbers.
    pawn Код:
    GetPlayerPos(playerid, x, y, z);
    Using the native function GetPlayerPos we grab the floats defined above, get the player's position, and store the coordinates into the floats.
    pawn Код:
    foreach(Player, i)
    Using foreach, we will efficiently loop through all the players and store the playerids into the variable " i " which is in the second parameter.
    pawn Код:
    if(IsPlayerInRangeOfPoint(i,radi,x,y,z))
    With the foreach loop in the line above, we will now check for every player that is 'in range' of the desired player by using the native function IsPlayerInRangeOfPoint. The " i " in the first parameter represents every player that is in range of the desired player. The second parameter is the range the player has to be in. So if you put 2 in this parameter, then the player has to be within two GTA units of the desired player in order for the statement to be true. Now remember those three floats x, y, and z we defined earlier? This is where it comes in. The last three parameters are the coordinates the player has to be in range of, in this case they have to be in range of the desired player.
    pawn Код:
    SendClientMessage(i,color,string);
    Finally, with all the code above, we send the message to every player who is in range using SendClientMessage. The variable " i " represents all the players in range.
The Local Chat
Now that we have all of our stocks, we will make what's called the 'local' chat. To do this, we will be using the callback called OnPlayerText since it is called every time a person types into the main chat. So go to your script and find "OnPlayerText".
  • New Message
    In order to make the chat realistic, we must format the text so that it is in 'roleplay' format, so we must define a new string that will be the message with a cell size of 128.
    pawn Код:
    new
        message[128];
  • Formatting the Message

    Now that we have defined the the string that will hold our new message, we will use the function format to insert variables like name and text in it.
    pawn Код:
    format(message, sizeof(message), "%s says: %s", GetName(playerid), text);
    Remember the stock GetName from earlier? Well formatting GetName into our message will return the name of whoever typed the message, but it will also remove the underscore! When we insert the "text" into our message, that is the text of whoever typed it. In conclusion, the string will output this.
    Код:
    NameHere says: Text here.
  • Sending Message to Players In Range
    Now that we have inserted the name and the text, we will now need to send the message to every player in range. To do this, we will now put the ProxDetector function into use!
    pawn Код:
    ProxDetector(30.0, playerid, message, -1);
    The first number you see is "30.0". This means that every player within 30 GTA units of the player will recieve the message. The next parameter is the playerid of whom has typed. Now remember our formatted string message? Well the next parameter is what to send to all the players nearby, which is the formatted message! The last number is the color parameter in which I put "-1". -1 is white, so it'll send the message to everyone nearby in white color. You can also change the color to whatever you want.
  • Final Step
    Up to this point, we have made a new string, inserted the text and name of the player (with underscore removed), and have successfully sent the message to all the players nearby. Everything is working, but one thing. If you have compiled your script up to this point, and go in-game, you will not only see our formatted message, but you will also see the 'traditional' SAMP chat (message sent to all). To get rid of the default SAMP chat, go to the end of your OnPlayerText callback, and instead of
    pawn Код:
    return 1;
    change it to
    pawn Код:
    return 0;
    Returning 0 will get rid of the default SA-MP chat, and send your formatted roleplay message instead.
  • Conclusion
    So after everything we have added under OnPlayerText, this is what is should look like.
    pawn Код:
    public OnPlayerText(playerid, text[])
    {
        new
            message[128];
        format(message, sizeof(message), "%s says: %s", GetName(playerid), text);
        ProxDetector(30.0, playerid, message, -1);
        return 0;
    }
Commands
Before we start, we will need to define the RP purple color on the top of your script.
pawn Код:
#define     COLOR_PURPLE        0xC2A2DAAA
So now we have the local chat, but what about the other roleplay chat commands? We will now use the ProxDetector function in a command!
  • /me
    We will be using zcmd, and sscanf 2.6 to create our /me command.
    pawn Код:
    new
            string[128],
            action[100];
    We will be using 2 different strings. 'string' represents the total message, and 'action' will represent the action the player is doing.
    pawn Код:
    if(sscanf(params, "s[100]", action))
    {
        SendClientMessage(playerid, -1, "USAGE: /me [action]");
        return 1;  
    }
    Using sscanf 2.6 we will check if the player typed something after typing /me, if they didn't, then sscanf 2.6 will return the message telling them how to use it.
    pawn Код:
    else
    {
        format(string, sizeof(string), "* %s %s", GetName(playerid), action);
        ProxDetector(30, playerid, string, COLOR_PURPLE);
    }
    So up to this point, if a player has typed something after /me, we will use an else statement to check if they have. In this else statement we will format the action and the name into the string like we did before! After that has been done, we use our ProxDetector to send it to everyone nearby! Remember the COLOR_PURPLE define? Well COLOR_PURPLE represents the hexadecimal color for purple (classic /me color).
    So now we have a /me command and it should look like this. You should now know how to make a /do command!
    pawn Код:
    CMD:me(playerid, params[])
    {
        new
            string[128],
            action[100];
        if(sscanf(params, "s[100]", action))
        {
            SendClientMessage(playerid, -1, "USAGE: /me [action]");
            return 1;
        }
        else
        {
            format(string, sizeof(string), "* %s %s", GetName(playerid), action);
            ProxDetector(30, playerid, string, COLOR_PURPLE);
        }
        return 1;
    }
  • /shout and /s command
    To create a shout command, you would use the same method used above, but what if you want the shout command to be both /shout or /s? I'll show you how.
    pawn Код:
    CMD:shout(playerid, params[])
    {
        new
            string[128],
            shout[100];
        if(sscanf(params, "s[100]", shout))
        {
            SendClientMessage(playerid, -1, "USAGE: /(s)hout [message]");
            return 1;
        }
        else
        {
            format(string, sizeof(string), "%s shouts: %s!",GetName(playerid),shout);
            ProxDetector(50.0, playerid, string, -1);
        }
        return 1;
    }
    So that is the shout command, I will not explain it as thoroughly, but you can see we used the same method, only difference is it's in a command now! So if they type /shout it will process the command above, but we also want the command /s to available too!
    pawn Код:
    CMD:s(playerid, params[]) return cmd_shout(playerid, params);
    So, if they type /s, then it will process the actual shout command! If you have learned anything, now you can go on to make a /low command, or a local ooc chat command! Challenge yourself!
Credits
  • ****** for his foreach include, and his sscanf plugin.
  • Zeex for his zcmd include.
  • Original creator of the ProxDetector function (used as a reference).
  • VincentDunn for writing the tutorial.


Reply
#2

Great tutorial.

Lol'd at your signature.
Reply
#3

God tutorials!

*** I love you signature !
Reply
#4

Quote:
Originally Posted by [Full]Garfield[XDB]
Посмотреть сообщение
God tutorials!

*** I love you signature !
yeah ^ x
Sweet tutorial ; i never knew about ProxDetector that much :P though its easy x:P
Reply
#5

Nice, this will help me a-lot, but now i need to sleep. ^^
and as the others have said your signature is awesome!
Reply
#6

Thank you all for the positive comments!
Reply
#7

Great tutorial i really like the format of it, i hope all people who make tutorial follow this format, really imperresive work
Reply
#8

Really nice , repped
Reply
#9

Good
Reply
#10

Defiantly An Amazing Tutorial.
Well Done, Defiantly Will Help the Newbies.

Cheerin,
Reply
#11

Thank you for this tutorial it helped me
Reply
#12

Nice one,
you can make a nice "ProxDetector" with IsPlayerInRangeOfPoint, too.
Reply
#13

this is a good tutorial,
very nicely laid out, and easy to understand!


Good work!
Reply
#14

Quote:
Originally Posted by irinel1996
View Post
Nice one,
you can make a nice "ProxDetector" with IsPlayerInRangeOfPoint, too.
Haha, what?

Thank you all for the positive comments. An accent section is planned.
Reply
#15

nice tut and also very nice chat
Reply
#16

i was thinking how to make dat , its Really helpful thanks :P
Reply
#17

I get these errors, please help me.
I've marked the line numbers.

C:\Users\Arjan\Desktop\MIJN RP\gamemodes\MYRP.pwn(66) : error 025: function heading differs from prototype
C:\Users\Arjan\Desktop\MIJN RP\gamemodes\MYRP.pwn(67) : error 021: symbol already defined: "strreplace"
C:\Users\Arjan\Desktop\MIJN RP\gamemodes\MYRP.pwn(75) : warning 209: function "strreplace" should return a value
Pawn compiler 3.2.3664 Copyright © 1997-2006, ITB CompuPhase


2 Errors.

SCRIPT:

Code:
//---------------CHAT SYSTEM--------------------
stock strreplace(string[], find, replace)
{
    for(new i=0; string[i]; i++)
    {
        if(string[i] == find)
        {
            string[i] = replace;
        }
    }
}

stock GetName(playerid)
{
    new
        name[24];
    GetPlayerName(playerid, name, sizeof(name));
    strreplace(name, "_", " ");
    return name;
}

stock ProxDetector(Float:radi, playerid, string[],color)
{
    new Float:x,Float:y,Float:z;
    GetPlayerPos(playerid,x,y,z);
    foreach(Player,i)
    {
        if(IsPlayerInRangeOfPoint(i,radi,x,y,z))
        {
            SendClientMessage(i,color,string);
        }
    }
}
Please help me, I will +rep!
Reply
#18

You either have strreplace defined in an include are already define in the gamemode.

All the code I posted works 100% if you followed every step.
Reply
#19

Nice work brother. I liked the new ProxDetector you added, Can be useful for commands like /me and /do. Rep+
Reply
#20

Good tutorial but... you can remove the '_' from the name without strreplace:

Quote:

Removing "_" from a name.
In order to do so, we need a string replace function.

-False , you do NOT need it , but you can use it , another way of replacing, without creating any stocks/functions is:

pawn Code:
new name[MAX_PLAYER_NAME];
GetPlayerName(playerid,name,MAX_PLAYER_NAME);
name[strfind(name, "_", false)] = ' ';
So it does the exact same thing , but without any stocks...
I'm just saying that creating stocks when they are not needed is not very smart.. but anyways 10/10 amazing tutorial.
Reply


Forum Jump:


Users browsing this thread: 3 Guest(s)