[Tutorial] Making an NPC [NOT JUST FOR WALKING :) ]
#1

Making an NPC
[Non-playing character/bot]



Introduction

For those who do not know, SA-MP has support for NPC's or bots.
NPC's are non-playing characters.
These characters can move.
Today, I will teach you how to enable these NPC's to do a LOT more than just walking.

Today, we will learn how to -
  1. Successfully make and connect an NPC
  2. Enable him to interact and talk



Making an NPC and connecting him/her

First of all, We need a .PWN file and .REC file.
Use any NPC-recording filterscript in order to do so.
NOTE - Avoid HUGE recordings since NPC's use a LOT of bandwidth

Now, we begin with the real shit

On top of your gamemode -


pawn Код:
new npcis;
We will be using this variable for future reference in order to make the NPC perform normal player functions.
NOTE - If you have more NPC's, add more cells to the same var or whatever, but I'd still recommend only ONE NPC since they consume a LOT of bandwidth.

Now, we connect the NPC


pawn Код:
public OnGameModeInIt()
{
    npcis = INVALID_PLAYER_ID; // This sets npcis to INVALID_PLAYER_ID to make sure there are no bugs further
    ConnectNPC("name_as_string", "Name_of_.pwn_file_without_extension");
    return 1;
}
pawn Код:
ConnectNPC(name [ ], filename [ ]);
This is a simple function used to connect an NPC.

NOTE - BE SURE THAT 'MAX NPCS' IN SERVER.CFG IS AT LEAST 1 ELSE IT WILL FAIL TO CONNECT!

Now, to avoid going through a loop ALL time, we do this -


pawn Код:
public OnPlayerConnect(playerid)
{
    if(IsPlayerNPC(playerid))
    {
        npcis = playerid;
        // Set his skin, admin level, animations, drunk level, score, kills, deaths, or whatever
        return 1; // This makes sure our NPC doesn't freeze in your registered-checks or whatever
    }
    return 1;
}
This will save the NPC's ID into a variable called 'npcis' which we declared earlier.

pawn Код:
public OnPlayerDisconnect(playerid, reason)
{
    if(playerid == npcis)
    {
        npcis = INVALID_PLAYER_ID; // To tell the server that NPC is not connected anymore, hence breaking further operations
    }
    return 1;
}

I'll explain WHY are we using this variable instead of a loop

Think this for yourself for one minute -
What would be better,
1. To loop through all players just to find an NPC
2. To save the NPC's ID into a variable for global reference

Ob...viously it'll be the first one


Congrats! We've successfully created a NPC and successfully connected it!

Extensive use
of NPC's



How can we further expand the use of this NPC to become more than just a walking dummy?

Here's the answer how -

Prepare an array with some random dialogues

In my case, I've taken some dialogues from Jim Carrey's movies and compiled them into an array -


pawn Код:
new BotWords[][] = {
    {"You're bored? Go fuck yourself, that'd be a good entertainment! "},
    {"Ya know, there ain't no kid in town capable of bustin' nude hackers like meh! "},
    {"I'm feeling a little itch on my right hand today, anybody feel like takin' a slap?! "},
    {"Our love is like a red, red rose... and I am a little thorny. "},
    {"You gotta ask yourself one question. 'Do I feel lucky?' Well, do ya? Punks! "},
    {"You were good, kid, real good. But as long as I'm around, you'll always be second best, see?"},
    {"B-E-A-UTIFUL"},
    {"I CAN'T LIE!!!!"},
    {"Why don't ya nigga's go plant some weed?!"},
    {"Alllrightyy then, you asked for it!"},
    {"I'll send you to Wonderland if you don't shut the fuck up! "},
    {"Good dog, good dog, now come to papa! "}
};
This prepares an array called 'BotWords' with the following dialogues.
But does this automatically enable the script to send it using NPC's name? The answer is NO.
We need to create an implementation of this under OnPlayerText -


pawn Код:
public OnPlayerText(playerid, text [ ])
{
    if(strfind(text, "Jim", true) != -1 || strfind(text, "Carrey", true) != -1) // My NPC's name is Jim Carrey
        // Replace 'Jim' here with your NPC's first name and 'Carrey' with his second name
    {
        new string[124], name[20]; // We declare 2 strings, one to store the message to be sent and one to store NPC's name
        new rand = random(sizeof(BotWords)); // To choose one of the random dialogues from the array we made
        format(string, sizeof(string), "%s[%d]:{FFFFFF} %s",GetPlayerName(playerid, name, 20),npcis, BotWords[rand][0]); // Formatting the message
        SendClientMessageToAll(GetPlayerColor(npcis), string); // Sending it
    }
        return 1;
}
What does this do?
Okay, let's divide it

First, we detect if the text contains the NPC's name
Second, we choose a random dialogue, get the NPC's name, and declare new string which will have the message
Third, we format the message with NPC name, NPC ID, and random dialogue
Fourth, we send it in the colour of the NPC
NOTE - Be sure to use SetPlayerColour under OnPlayerConnect in if(IsPlayerNPC(playerid)) case or the message sent will be black.


Congrats! You've successfully made a way for NPC to talk


To simplify further, here's a sample script -

pawn Код:
new npcis;

new BotWords[][] = {
    {"You're bored? Go fuck yourself, that'd be a good entertainment! "},
    {"Ya know, there ain't no kid in town capable of bustin' nude hackers like meh! "},
    {"I'm feeling a little itch on my right hand today, anybody feel like takin' a slap?! "},
    {"Our love is like a red, red rose... and I am a little thorny. "},
    {"You gotta ask yourself one question. 'Do I feel lucky?' Well, do ya? Punks! "},
    {"You were good, kid, real good. But as long as I'm around, you'll always be second best, see?"},
    {"B-E-A-UTIFUL"},
    {"I CAN'T LIE!!!!"},
    {"Why don't ya nigga's go plant some weed?!"},
    {"Alllrightyy then, you asked for it!"},
    {"I'll send you to Wonderland if you don't shut the fuck up! "},
    {"Good dog, good dog, now come to papa! "}
};

public OnGameModeInIt( )
{
    npcis = INVALID_PLAYER_ID;
    ConnectNPC("Jim_Carrey", "NPC");
    return 1;
}

public OnPlayerConnect(playerid)
{
    if(IsPlayerNPC(playerid))
    {
         npcis = playerid;
         SetPlayerColor(playerid, -1);
    }
    return 1;
}

public OnPlayerDisconnect(playerid)
{
     if(IsPlayerNPC(playerid))
     {
          npcis = INVALID_PLAYER_ID;
     }
     return 1;
}

public OnPlayerText(playerid, text [ ])
{
    if(strfind(text, "Jim", true) != -1 || strfind(text, "Carrey", true) != -1)
    {
        new string[124];
        new rand = random(sizeof(BotWords));
        format(string, sizeof(string), "%s[%d]:{FFFFFF} %s", pname(sInfo[npcis]), sInfo[npcis], BotWords[rand][0]);
        SendClientMessageToAll(GetPlayerColor(sInfo[npcis]), string);
    }
      return 1;
}
You can further expand the usage of this NPC simply.
I've implemented the usage of NPC's in my anti-cheat, and you can do it too!

You can expand the usage of NPC's in almost every sort of servers!

In all kinds of servers - these can be used for basic interactions
In RP's - these can used for job-reference, info, robberies (Implement OnPlayerTakeDamage and OnPlayerShootPlayer for this)
In CnR's - these can be used for robberies, help, reference

But in the end, an NPC is always an artificial player with no intelligence, it will do only what you tell it to do, and there is no way NPC's can replace players.

Of course the things mentioned above CAN be done without using an NPC, but oh well, if you like things entertaining and not just working, then I'd say go for an NPC-talking-bot with anti-cheat abilities.

P.S - I tried my best to explain everything, and if something lacks explanation, feel free to point it out

An example is


pawn Код:
public OnPlayerStateChange(playerid, newstate, oldstate)
{
    new act = GetPlayerSpecialAction(playerid);
    if(act == SPECIAL_ACTION_USEJETPACK && IsPlayerAdmin(playerid) != 1)
    {
        new rsn[80];
        format(rsn, 80, "%d Jetpack_Hacks", playerid);
        return cmd_ban(npcis, rsn);
    }
        return 1;
}
P.S Indentation is fucked up in pawn codes due to some copy-paste and some written on spot
Reply
#2

Nice tutorial !

Gonna use this
Reply
#3

Nice tut
Reply
#4

cool, going to try this.
Reply
#5

This should be bumped up, so thanks nig.

Had to search through 11 pages
Reply
#6

Have you even tested it?

1- How do you suppose the NPC (you don't need an NPC and a slot reserved just for simple text messages) will send any text, or that OnPlayerText would be called for the NPC?
2- The code under OnPlayerText will be called for anyone with their name containing Jim or Carrey.

You jetpack detection and the ban method aren't nicely done either.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)