SA-MP Forums

Go Back   SA-MP Forums > SA-MP Scripting and Plugins > Scripting Help > Tutorials

Reply
 
Thread Tools Display Modes
Old 11/01/2014, 02:15 PM   #1
Voxel
Gangsta
 
Voxel's Avatar
 
Join Date: Sep 2013
Location: The Netherlands
Posts: 578
Reputation: 70
Default Making A Simple Hunger/Thirst System

Simple Hunger/Thirst System
Tutorial by Voxel

Introduction
Hello and welcome to my new tutorial on how to make a hunger and thirst system. In this tutorial we
will be using SQLite to save the players stats, if you are not familiar with SQLite I reccomend taking a look
at my SQLite filterscript and the tutorial which is made by Konstatinos.
This tutorial will expect you to know the basics for pawn scripting.
Lets get going shall we?!

Tutorial
Setting up our database to save our stats

First of all we are going to need some enums for our stats
pawn Code:
enum USER_DATA
{
    USER_ID, //here we save the account id in the database
    USER_NAME[MAX_PLAYER_NAME], //same goes for the name
    USER_PASSWORD[129], //and we save the password
    USER_HUNGER, //here we save the players hunger
    USER_THIRST, //and the thirst aswell

    bool: USER_LOGGED_IN
};

new User[MAX_PLAYERS][USER_DATA];
new DB: Database;
Next we will set up the rest of the database
pawn Code:
public OnFilterScriptInit()
{
    Database = db_open("server.db");
    db_query(Database, "CREATE TABLE IF NOT EXISTS users (userid INTEGER PRIMARY KEY AUTOINCREMENT, username VARCHAR(24) COLLATE NOCASE, password VARCHAR(129), hunger INTEGER DEFAULT 0 NOT NULL, thirst INTEGER DEFAULT 0 NOT NULL)");
    AddPlayerClass(1, 2528.9143,-1667.7504,15.1689,91.2860,0,0,0,0,0,0);
    return 1;
}

public OnPlayerConnect(playerid)
{
    for(new i; i < _: USER_DATA; ++i) User[playerid][USER_DATA: i] = 0;

    GetPlayerName(playerid, User[playerid][USER_NAME], MAX_PLAYER_NAME);

    new Query[71], DBResult: Result;
    format(Query, sizeof(Query), "SELECT password FROM users WHERE username = '%s' LIMIT 0, 1", DB_Escape(User[playerid][USER_NAME]));
    Result = db_query(Database, Query);
    if(db_num_rows(Result))
    {
        db_get_field_assoc(Result, "password", User[playerid][USER_PASSWORD], 129);
        ShowPlayerDialog(playerid, 0, DIALOG_STYLE_PASSWORD, "Login pannel", "Login pannel", "Please login to play", "Login", "Exit");
    }
    else ShowPlayerDialog(playerid, 1, DIALOG_STYLE_PASSWORD, "Register pannel", "Please register to play", "Register", "Exit");
    db_free_result(Result);
    return 1;
}

public OnPlayerDisconnect(playerid, reason)
{
    if(User[playerid][USER_LOGGED_IN] == true)
    {
        new Query[128];
        format(Query, sizeof(Query), "UPDATE users SET hunger= %s, thirst = %s WHERE username = '%s'", User[playerid][USER_HUNGER], User[playerid][USER_THIRST], DB_Escape(User[playerid][USER_NAME]));
        db_query(Database, Query);
    }
    for(new i; i < _: USER_DATA; ++i) User[playerid][USER_DATA: i] = 0;
    return 1;
}

public OnPlayerSpawn(playerid)
{
    return 1;
}

public OnPlayerDeath(playerid, killerid, reason)
{
    return 1;
}

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    if(dialogid == 0)
    {
        if(response)
        {
            if(!inputtext[0]) return ShowPlayerDialog(playerid, 0, DIALOG_STYLE_PASSWORD, "Login pannel", "Please login to play", "Login", "Exit");
            new buf[129];
            WP_Hash(buf, 129, inputtext);
            if(!strcmp(buf, User[playerid][USER_PASSWORD], false))
            {
                new Query[75], DBResult: Result;
                format(Query, sizeof(Query), "SELECT * FROM users WHERE username = '%s' LIMIT 0, 1", DB_Escape(User[playerid][USER_NAME]));
                Result = db_query(Database, Query);
                if(db_num_rows(Result))
                {
                    db_get_field_assoc(Result, "userid", Query, 7);
                    User[playerid][USER_ID] = strval(Query);

                    db_get_field_assoc(Result, "hunger", Query, 3);
                    User[playerid][USER_HUNGER] = strval(Query);

                    db_get_field_assoc(Result, "thirst", Query, 3);
                    User[playerid][USER_THIRST] = strval(Query);

                    User[playerid][USER_LOGGED_IN] = true;

                    SendClientMessage(playerid, -1, "You have successfully logged in to your account!");
                }
                db_free_result(Result);
            }
            else
            {
                SendClientMessage(playerid, -1, "Incorrect password!");
                ShowPlayerDialog(playerid, 0, DIALOG_STYLE_PASSWORD, "Login pannel", "Please login to play", "Login", "Exit");

            }
        }
        else Kick(playerid);
        return 1;
    }
    if(dialogid == 1)
    {
        if(response)
        {
            if(!IsValidPassword(inputtext))
            {
                SendClientMessage(playerid, -1, "The password is invalid, Valid characters are: A-Z, a-z, 0-9");
                ShowPlayerDialog(playerid, 1, DIALOG_STYLE_PASSWORD, "Register pannel", "Please register to play", "Register", "Exit");
                return 1;
            }
            if(strlen(inputtext) < 3 || strlen(inputtext) > 24)
            {
                SendClientMessage(playerid, -1, "The password is invalid, Its lenght should be 3-24 characters");
                ShowPlayerDialog(playerid, 1, DIALOG_STYLE_PASSWORD, ""COL_BLUE"SERVER NAME"COL_WHITE" Register pannel", "Please register to play", "Register", "Exit");
                return 1;
            }
            new Query[208];
            WP_Hash(User[playerid][USER_PASSWORD], 129, inputtext);
            format(Query, sizeof(Query), "INSERT INTO users (username, password) VALUES ('%s', '%s')", DB_Escape(User[playerid][USER_NAME]), DB_Escape(User[playerid][USER_PASSWORD]));
            db_query(Database, Query);

            User[playerid][USER_LOGGED_IN] = true;
            SendClientMessage(playerid, -1, "You have just registered to our server! You have been automatically logged in!");
        }
        else Kick(playerid);
        return 1;
    }
    return 1;
}

stock DB_Escape(text[])
{
    new ret[ 80 * 2 ], ch, i, j;
    while((ch = text[i++]) && j < sizeof(ret))
    {
        if(ch == '\'')
        {
            if(j < sizeof(ret) - 2)
            {
                ret[j++] = '\'';
                ret[j++] = '\'';
            }
        }
        else if(j < sizeof(ret))
        {
            ret[j++] = ch;
        }
        else
        {
            j++;
        }
    }
    ret[sizeof(ret) - 1] = '\0';
    return ret;
}

stock IsValidPassword(const password[])
{
    for(new i = 0; password[i] != EOS; ++i)
    {
        switch(password[i])
        {
            case '0'..'9', 'A'..'Z', 'a'..'z': continue;
            default: return 0;
        }
    }
    return 1;
}
Now that we have a database to save our hunger and thirst in we can begin the real tutorial!
Right so first we will set the player stats when he first registers to the server:
pawn Code:
//this is our register part of the script over at the dialogs
User[playerid][USER_LOGGED_IN] = true;
SendClientMessage(playerid, -1, "You have just registered to our server! You have been automatically logged in!");
User[playerid][USER_HUNGER] == 100); //we set the hunger to 100
User[playerid][USER_THIRST] == 100); //and the thirst to 100
Now that we set the values correctly we can begin making the functions to decrease these stats
an example would be:
pawn Code:
//you need this define on top of your script to detect keys properly
#define PRESSED(%0) \
    (((newkeys & (%0)) == (%0)) && ((oldkeys & (%0)) != (%0)))

//everytime you jump you will loose a bit of energy which means u will get more hungry and thirsty
public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
     if(PRESSED(KEY_JUMP))
     {
          User[playerid][USER_HUNGER] -= 5); //we take 5 of the players hunger
          User[playerid][USER_THIRST] -= 7); //and 7 of the thirst
     }
     return 1;
}
Now that we have something that decreases our hunger and thirst we need to detect if the hunger or thirst is getting to low and the player will loose some health and maybe you could
also disable his sprinting since you would have no energy for that. So it would look like this:
pawn Code:
public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
     if(PRESSED(KEY_JUMP))
     {
          if(User[playerid][USER_HUNGER] <= 10 || User[playerid][USER_THIRST] <= 10)
          {
               SendClientMessage(playerid, -1, "You do not have enough energy to jump, try eating and drinking"); //send a message informing the player his energy is to low
               new Float:X, Float:Y, Float:Z;
               GetPlayerPos(playerid, x, y, z);
               SetPlayerPos(playerid, x, y, z);
               //just a quick way to disable the jumping (not tested)
          }
          else
          {
               //if the player have larger hunger and thirst then 10
               User[playerid][USER_HUNGER] -= 5); //we take 5 of the players hunger
               User[playerid][USER_THIRST] -= 7); //and 7 of the thirst
          }
     }
     return 1;
}
Now we will need a way to eat and drink to increase our hunger and thirst, you can use this at your
code where you buy food and such:
pawn Code:
//example
if(listitem == 0) //asuming you have a dialog and this is list item 0 which would be a burger or something
{
     User[playerid][USER_HUNGER] += 20); //we give the player +20 hunger
     SendClientMessage(playerid, -1, "You ate a burger, +20 hunger");
}
if(listitem == 1) //and this would be a soda or such
{
     User[playerid][USER_THIRST] += 20); //we give the player +20 thirst
     SendClientMessage(playerid, -1, "You drank a soda, +20 thirst");
}
Allright so now we will make a /energy command to check how hungry and thirsty you are.
pawn Code:
//Using ZCMD
CMD:energy(playerid,params[])
{
    new hunger= User[playerid][USER_HUNGER]; //we make a variable to store our stats in
    new thirst= User[playerid][USER_THIRST]; //same here
    new string[60],stats[60];
       
    format(string, sizeof string, "Hunger: %s\nThirst: %s", hunger, thirst); //we display the stats in our dialog
    format(stats, sizeof stats, "%s", string);
    ShowPlayerDialog(playerid,6,DIALOG_STYLE_MSGBOX,"Energy",string,"Ok","");
    return 1;
}
Thats about it, you can make more features like a timer every 10 minutes that decreases the hunger and thirst
and when you get low on energy you loose some health etc.

I hope you learned something and have fun!
__________________
My Work:
[GameMode]The Nether Survival
[Filterscript]SQLite Database Start
[Tutorial]SQLite Commands
[Tutorial]Loot/ Inventory System
[Tutorial]Simple Hunger/Thirst System
[Tutorial]Converting Binary
[Map]Tropical Island + Pier
[Map]San Fierro Apocalypse

Last edited by Voxel; 11/01/2014 at 04:37 PM.
Voxel is offline   Reply With Quote
Old 11/01/2014, 04:25 PM   #2
sammp
Gangsta
 
sammp's Avatar
 
Join Date: Jan 2014
Posts: 584
Reputation: 49
Default Re: Making A Simple Hunger/Thirst System

Very nice indeed +1
__________________
SA-MP must become open-source to maximise longetivity of the project.
sammp is offline   Reply With Quote
Old 11/01/2014, 06:55 PM   #3
Pottus
High-roller
 
Pottus's Avatar
 
Join Date: Jun 2012
Posts: 4,885
Reputation: 1351
Default Re: Making A Simple Hunger/Thirst System

You shouldn't really have to this at all just make sure all settings are set when a player logs in or registers.

pawn Code:
for(new i; i < _: USER_DATA; ++i) User[playerid][USER_DATA: i] = 0;
Pottus is offline   Reply With Quote
Old 11/01/2014, 07:08 PM   #4
Voxel
Gangsta
 
Voxel's Avatar
 
Join Date: Sep 2013
Location: The Netherlands
Posts: 578
Reputation: 70
Default Re: Making A Simple Hunger/Thirst System

Quote:
Originally Posted by [uL]Pottus View Post
You shouldn't really have to this at all just make sure all settings are set when a player logs in or registers.

pawn Code:
for(new i; i < _: USER_DATA; ++i) User[playerid][USER_DATA: i] = 0;
That would work for regular player stats such as kills and deaths but not with hunger and thirst in this system where they are set to 100 which would mean your stomach is full etc.

But thanks for your reply!
__________________
My Work:
[GameMode]The Nether Survival
[Filterscript]SQLite Database Start
[Tutorial]SQLite Commands
[Tutorial]Loot/ Inventory System
[Tutorial]Simple Hunger/Thirst System
[Tutorial]Converting Binary
[Map]Tropical Island + Pier
[Map]San Fierro Apocalypse
Voxel is offline   Reply With Quote
Old 11/01/2014, 07:13 PM   #5
Pottus
High-roller
 
Pottus's Avatar
 
Join Date: Jun 2012
Posts: 4,885
Reputation: 1351
Default Re: Making A Simple Hunger/Thirst System

Well you would just load them from your database when a player joins that is what I do on the DayZ server so you can't tell me it wouldn't work
Pottus is offline   Reply With Quote
Old 11/01/2014, 07:59 PM   #6
Voxel
Gangsta
 
Voxel's Avatar
 
Join Date: Sep 2013
Location: The Netherlands
Posts: 578
Reputation: 70
Default Re: Making A Simple Hunger/Thirst System

Quote:
Originally Posted by [uL]Pottus View Post
Well you would just load them from your database when a player joins that is what I do on the DayZ server so you can't tell me it wouldn't work
Oh lol okay !
__________________
My Work:
[GameMode]The Nether Survival
[Filterscript]SQLite Database Start
[Tutorial]SQLite Commands
[Tutorial]Loot/ Inventory System
[Tutorial]Simple Hunger/Thirst System
[Tutorial]Converting Binary
[Map]Tropical Island + Pier
[Map]San Fierro Apocalypse
Voxel is offline   Reply With Quote
Old 16/01/2014, 08:16 PM   #7
twerko13
Little Clucker
 
Join Date: Dec 2013
Posts: 10
Reputation: 2
Default Re: Making A Simple Hunger/Thirst System

Seems legit... Gonna use it for my gamemode...
__________________
My work:
twerko13 is offline   Reply With Quote
Old 17/01/2014, 05:05 AM   #8
Voxel
Gangsta
 
Voxel's Avatar
 
Join Date: Sep 2013
Location: The Netherlands
Posts: 578
Reputation: 70
Default Re: Making A Simple Hunger/Thirst System

Quote:
Originally Posted by twerko13 View Post
Seems legit... Gonna use it for my gamemode...
Good luck!
__________________
My Work:
[GameMode]The Nether Survival
[Filterscript]SQLite Database Start
[Tutorial]SQLite Commands
[Tutorial]Loot/ Inventory System
[Tutorial]Simple Hunger/Thirst System
[Tutorial]Converting Binary
[Map]Tropical Island + Pier
[Map]San Fierro Apocalypse
Voxel is offline   Reply With Quote
Old 17/01/2014, 08:29 AM   #9
twerko13
Little Clucker
 
Join Date: Dec 2013
Posts: 10
Reputation: 2
Default Re: Making A Simple Hunger/Thirst System

It works, even used this as a base for my admin system.... Gonna put you in my server credits (visible to everyone on the server)!
__________________
My work:
twerko13 is offline   Reply With Quote
Old 17/01/2014, 09:05 AM   #10
Voxel
Gangsta
 
Voxel's Avatar
 
Join Date: Sep 2013
Location: The Netherlands
Posts: 578
Reputation: 70
Default Re: Making A Simple Hunger/Thirst System

Quote:
Originally Posted by twerko13 View Post
It works, even used this as a base for my admin system.... Gonna put you in my server credits (visible to everyone on the server)!
Heh glad it works and enjoy! thanks.
__________________
My Work:
[GameMode]The Nether Survival
[Filterscript]SQLite Database Start
[Tutorial]SQLite Commands
[Tutorial]Loot/ Inventory System
[Tutorial]Simple Hunger/Thirst System
[Tutorial]Converting Binary
[Map]Tropical Island + Pier
[Map]San Fierro Apocalypse
Voxel is offline   Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[Tutorial] Making A Simple Rank System Nirzor Tutorials 11 05/01/2014 10:46 AM
[FilterScript] Simple Hunger System - Ideal for roleplay RedWolfX Filterscripts 11 01/12/2013 04:11 PM
Link please for Hunger/Thirst system Leo Delvecchio Scripting Help 1 12/05/2012 08:53 AM
[FilterScript] Simple Hunger System AlexTracer Filterscripts 4 15/03/2012 01:06 PM
Making a simple cop system ricardo178 Scripting Help 6 24/02/2012 02:19 PM


All times are GMT. The time now is 12:50 PM.


Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.