[Tutorial] Creating a faction system [basics]
#1

Hello, noticed a thread about this and saw that not many tutorials were made about this topic, figured I'd help those of you who are in need of help.

PS: Realize this is my first created tutorial, so please do not talk shit on here, although constructive criticism is advised.

What do I need?
Well, you need nothing but pawno and the default includes that come with sa-mp. I am going to be using ZCMD and sscanf for this tutorial as a command processor, so make sure you have that if you wish to just copy/paste the command.

Step 1: Includes
Of course, all you need is a_samp, that is provided with the server package, therefore simply add this code that will allow you to use the stuff from the include file.

pawn Code:
#include <a_samp>
Step 2: Creating the variables
Alright, now we are going to need to create the variables that stores your faction and your faction rank. For this, we are going to create an enumerator. If you already have one, feel free to just add to it.

pawn Code:
enum PlayerData //We create an enumerator entitled "PlayerData"
{ //Open bracket
    Faction, //This is the variable we are going to store our faction id in.
    Rank //The variable that we store the faction rank in.
}; //Close bracket and semi-colon to finish the enumerator
new pData[MAX_PLAYERS][PlayerData]; //We create a variable that stores our enumerator info for each player.
Now, correct me if I'm wrong, but when we create a new variable, it is always set to 0 (might be -1, not sure), so leave it as it is, no need to set the value right away, because 0 will be the value for civilian.

Step 2: Creating a few commands
Now we are going to create a few commands that will allow us to make a person leader of a specific faction, remove them from the faction, and allow the faction leader to set the faction rank of a specific member.

REMINDER: I will be using ZCMD as a command processor for this tutorial, and sscanf, so remember you must download it or do a similar method using a different command processor.

pawn Code:
CMD:makeleader(playerid, params[])
{
    new targetid, factionid, string[128], targetname[24], playername[24];
    if(sscanf(params, "ui", targetid, factionid)) return SendClientMessage(playerid, -1, "Usage: /makeleader [playerid][factionid]"); //Checks if they typed in anything for the playerid and factionid parameters, and if they don't, return a client message.
    if(AdminVariable[playerid] != 6) return SendClientMessage(playerid, -1, "You are not an admin"); //Checks if they are an admin.  Remember, change this to your admin variable, or use !IsPlayerAdmin to check if they aren't rcon admin.
    if(!IsPlayerConnected(targetid)) return SendClientMessage(playerid, -1, "Invalid playerid!"); //Sends a message if the player is not connected
    if(0 < factionid < 3) //Checks if the factionid is between 0 and 3, and if so, continue.  You can also type this like so: if(factionid >= 1 && factionid <= 2) or if(factionid == 1 || factionid == 2)
    {
        GetPlayerName(playerid, playername, sizeof(playername)); //Gets the players name and saves it to the variable playername
        GetPlayerName(targetid, targetname, sizeof(targetname)); //Gets the targets name and saves it to the variable targetname
        format(string, sizeof(string), "You made %s leader of faction id %i!", targetname, factionid); //Formats the string that you will receive
        SendClientMessage(playerid, -1, string); //Sends a message to the person who changes the other persons faction in a random color
        format(string, sizeof(string), "You were made leader of faction id %i by %s", factionid, playername);//Formats the string that the player will receive
        SendClientMessage(playerid, -1, string); //Sends a message to the person who is made the faction leader
        pData[playerid][Faction] == factionid;
        pData[playerid][Rank] == 6; //Leader, use a switch case or if/else if statement if you want to make it so certain factions have seperate highest ranks
    }
    else return SendClientMessage(playerid, -1, "Invalid factionid.  Factionid's: 1-2"); //Sends a message if the faction is NOT between 0 and 3
    return 1;// Returns 1 to end the command, as we NEED to return a value.
}
pawn Code:
CMD:removefromfaction(playerid, params[]) //Format to create a command
{ //Open bracket
    new targetid, targetname[24], playername[24], string[128]; //Create the variables
    if(sscanf(params, "u", targetid)) return SendClientMessage(playerid, -1, "Usage: /removefromfaction [playerid/partofname]"); //Sends message if they do not type something in for the targetid/name
    if(!IsPlayerConnected(targetid)) return SendClientMessage(playerid, -1, "Invalid playerid!"); //Sends a message if the player isn't connected
    if(AdminVariable[playerid] != 6 && pData[playerid][Rank] != 6) return SendClientMessage(playerid, -1, "You are not a high enough admin or you aren't the leader!"); //Sends a message if they aren't the leader of the faction and if they aren't admin
    GetPlayerName(targetid, targetname, sizeof(targetname)); //Stores the targetid's name in the targetname variable
    GetPlayerName(playerid, playername, sizeof(playername)); //Stores the playerid's name in the playername variable
    format(string, sizeof(string), "You removed %s from his (now) previous faction!", targetname);//Formats the message that will be sent to you (the player)
    SendClientMessage(playerid, -1, string);//Sends the message that is formatted above to the playerid in a random color
    format(string, sizeof(string), "You were removed from your faction by %s!", playername);//Formats the message that will be sent to the targetid
    SendClientMessage(targetid, -1, string);//Sends the message that is formatted above to the targetid in a random color
    pData[targetid][Faction] == 0; //Sets their faction variable to 0 (civilian)
    pData[targetid][Rank] == 0; //Sets their rank variable to 0 (no rank)
    return 1; //Returns a value
} //Closed bracket
pawn Code:
CMD:setrank(playerid, params[])
{
    new targetid, rank, targetname[24], playername[24], string[128]; //Creates our variable
    if(sscanf(params, "ui", targetid, rank)) return SendClientMessage(playerid, -1, "Usage: /setrank [playerid/partofname][rank]"); //Sends correct usage if they do not type in the rank and playerid
    if(pData[playerid][Rank] != 6) return SendClientMessage(playerid, -1, "You are not the leader of a faction!"); //If their rank is not 6, send the message.  Their rank won't be 6 unless they are in a faction, no need to check their faction
    if(!IsPlayerConnected(targetid)) return SendClientMessage(playerid, -1, "That player is not connected!"); //Sends a message if the targetid is not connected
    if(pData[targetid][Faction] != pData[playerid][Faction]) return SendClientMessage(playerid, -1, "That player is not in your faction!"); //Sends a message if the targetid is not in their faction
    if(0 < rank < 7) //If the rank is between 0 and 7, seeing as below 1 and above 6 is not a valid rank
    { //Open bracket
        GetPlayerName(playerid, playername, sizeof(playername)); //Stores the playerid's name into the playername variable
        GetPlayerName(targetid, targetname, sizeof(targetname)); //Stores the targetid's name into the targetname variable
        if(pData[targetid][Rank] < rank) //If the players rank is less than the rank being given (promotion)
        { //Open bracket
            format(string, sizeof(string), "You have been promoted to rank %i by %s!", rank, playername); //Formats the message for the targetid
            SendClientMessage(targetid, -1, string); //Sends formatted message to targetid
            format(string, sizeof(string), "You promoted %s to rank %i", targetname, rank); //Formats the message for the playerid
            SendClientMessage(playerid, -1, string); //Sends formatted message to playerid
        } //Closed bracket
        else //Else (demotion)
        { //Open bracket
            format(string, sizeof(string), "You have been demoted to rank %i by %s!", rank, playername); //Same as above
            SendClientMessage(targetid, -1, string); //Same as above
            format(string, sizeof(string), "You demoted %s to rank %i", targetname, rank); //Same as above
            SendClientMessage(playerid, -1, string); //Same as above
        } //Closed bracket
    } //Closed bracket
    return 1; //Return a value
}
Okay, now that we go this finished, we can now successfully make people leader, set their rank if they are the leader, and remove them from the faction.

This is how you check if the player is in a specific faction, or several factions:

pawn Code:
if(pData[playerid][Faction] == 1) //If the faction is 1

if(pData[playerid][Faction] == 1 || pData[playerid][Faction] == 2) //Checks if it is faction 1 or 2

if(0 < pData[playerid][Faction] < 3) //Checks if it is between 0 and 3

if(pData[playerid][Faction] != 0) //If the faction is not 0

if(pData[playerid][Faction] == 1 && pData[playerid][Rank] == 6) //If the faction is 1 and the rank is 6

//How do I check if something is 1 AND something else is 2
//&& == and, || == or, use accordingly like shown above
Step 3: Saving/Loading
Now, we are going to want to save it.

These are just some notable examples for saving with certain file saving systems:

pawn Code:
//Place where you want to save it
dini_IntSet(File,"Factionid",pData[playerid][Faction]); //Saving using dini
dini_IntSet(File,"Rank", pData[playerid][Rank]); //Saving using dini

INI_WriteInt(File, "Factionid", pData[playerid][Faction]); //Saving using y_ini
INI_WriteInt(File, "Rank", pData[playerid][Rank]); //Saving using y_ini

GetPlayerName(playerid, playername, sizeof(playername)); //You still have to create the variable playername
format(string, sizeof(string), "UPDATE `table` SET factionid = %i, rank = %i WHERE Username = %s", pData[playerid][Faction], pData[playerid][Rank], playername); //Updating mysql database with facitonid/rank
mysql_query(string); //Sending the query.  Remember, must still create the variable "string"
And next, to load it:

pawn Code:
//Place where you want to load it
pData[playerid][Faction] = dini_Get(File, "Factionid"); //Loading using dini
pData[playerid][Rank] = dini_Get(File, "Rank"); //Loading using dini

INI_Int("Factionid",pData[playerid][Faction]);
INI_Int("Rank",pData[playerid][Rank]);

//Not going to show loading for mysql, this is a pain to create from scratch right now, and it is boring.
Of course, these are just for the popular saving systems, you can also use the default and other file saving systems, but you gotta find out how yourself.

HINT: Optional methods coming soon, such as Divisions

OPTIONAL: Making faction-specific vehicles
Alright, so you're going to want to make faction specific vehicles most of the time. These will prevent anyone who is not in the designated faction to be pulled from the vehicle when he tries to enter as the DRIVER, although this will allow anyone to get in as a passenger.

First, we are going to need to create our global vehicle variable, and create the vehicles.

For this example, I am going to create a variable, and later on, if anyone requests it, I can create a two dimensional array that will make it easier instead of using a variable for every faction.

pawn Code:
new LSPDVehicles[11]; //Lets say that factionid 1 is LSPD, so we will name our vehicle variable LSPDVehicles and it will be able to store 11 vehicles
Now that we created our variable, we can now begin creating our vehicles.

pawn Code:
LSPDVehicles[0] = AddStaticVehicle(596, 1570.4307, -1710.5015, 5.6118, 359.0704, 0, 1); // Took this AddStaticVehicle from a help thread.  This is our first vehicle.
This is our vehicle w created. Whenever you make a new faction vehicle, make sure you increase the variable dimension, so lets say we have 11 vehicles, we have to increase it by 1, meaning we have 11 vehicles but it is new LSPDVehicles[12].

Alright, after that, we will make it so only people in the faction can enter it, like so:

pawn Code:
public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)
{
    for(new i = 0; i < 12; i++) //Loop.  It counts to 11
    { //Open Bracket
        if(vehicleid == LSPDVehicles[i]) //If the vehicleid is an LSPD vehicle
        { //Open Bracket
            if(pData[playerid][Faction] != 1) //If the player is not in faction 1 (LSPD, in this case)
            { //Open Bracket
                ClearAnimations(playerid); //Clears their animation, preventing them from entering the vehicle.
                SendClientMessage(playerid, -1, "You don`t have the keys for this car."); //Sends a message to the player that he cannot enter it.
            } //Closed Bracket
        } //Closed Bracket
    } //Closed Bracket
    return 1; //Return a value
}
PS: I am tired right now, I might have made a few mistakes, and this is not tested, which I am sorry for. If anything occurs, please reply below so that I can help you and/or fix my mistakes in the thread
Reply
#2

Nice work Kindred. What about Integrating a Dynamic Faction system with the Player Data. I mean editing factions is awesome. Dynamic Faction system would be better i'd say. but i understand the reason behind this.

Good Work bro.
Reply
#3

Good job will really help me alot
Reply
#4

Thanks for the tutorial!
Reply
#5

Added faction specific vehicles as an optional step.

Remember, I may have screwed up on something, so if I did, feel free to PM me or reply here.

And if you get errors, feel free to reply below.
Reply
#6

Nice work man.
Reply
#7

The tutorial is very clear, and seems you put effort on it, perfect job i say.
Reply
#8

I found a bug. When you're leader 1 for LSPD faction. You cannot enter any car when you add LSPDVehicles[0],LSPDVehicles[1] and so on.
Reply
#9

Quote:
Originally Posted by Roddan
View Post
I found a bug. When you're leader 1 for LSPD faction. You cannot enter any car when you add LSPDVehicles[0],LSPDVehicles[1] and so on.
You positive you did all this? Because I see no reason why it wouldn't work. It checks if you aren't in factionid x, and sends a message. It does nothing if you are in the faction.
Reply
#10

listen i know this is kinda strange can you please show me which line got the faction id thing because i am kinda sleepy and couldn't see it
Reply


Forum Jump:


Users browsing this thread: 3 Guest(s)