creating a basic exp system

what i need is a basic system, the system need not be coded now but i need it so that whenever a player kills a specific NPC type he is awarded with “exp points” which would be defined with “xp”
thing is, i dont know where to start, all the other tutorials badly explain the functions and the reason im coding this is to learn and not use it actually.
im not asking to be spoon fed but i would appreciate any help.

If you want the player to get experience when they kill, say, zombies, you’d want to do something like:


hook.Add( "OnNPCKilled", "Award XP", function( npc, attacker, inflictor )
  if npc:Classify( ) == CLASS_ZOMBIE and attacker:IsPlayer( ) then
    attacker.xp = ( attacker.xp or 0 ) + <some amount>
  end
end )

I prefer to use NPC:Classify( ) to check against generic npc types unless you want it to be against only one single npc class ( npc_zombie ).

But if you want it to only work against a specific class, you’d change the if statement to something like


if npc:GetClass( ) == "npc_zombie" and attacker:IsPlayer( ) then

He is trying to learn, so I assume jello has no idea what you just said Kogitsune,
I will assume jello that you are familiar with the bare minimum of lua but are very new to programming

If you don’t understand what is happening in the code Kog posted, I will explain it to the best I can, but be weary that I am not the best at this.

the first line is



hook.Add( "OnNPCKilled", "Award XP", function( npc, attacker, inflictor )


A hook is an event,
hook.Add says that we are going to do something when something happens, we want something to happen when a NPC dies, thankfully, there is a hook that garry has made for us, “OnNPCKilled” will be called (so when OnNPCKilled is ‘called’ all the hook.Add’s with “OnNPCKilled” will be ran) when an npc is killed (quite obviously)

so now we have
hook.Add( “OnNPCKilled”
the next part “Award XP” is just a random string, it is really there to stop conflicting with other hooks and stuff, just put something random in there.

the last part is the function, what will happen when OnNPCKilled is called?
the function has 3 arguments (values that OnNPCKilled will give us)
it will give us the npc that was killed, the attacker and the weapon
so hopefully that explains the first part:
hook.Add( “OnNPCKilled”, “Award XP”, function( npc, attacker, inflictor )

the second line is a condition, an if statement, it will check if something is true or false, if it is true, it will do a specific task, the if statement checks if the npc is a zombie and it also checks to make sure that the person that killed the zombie is an actual player and not gravity or a prop, if the attacker is a player and the npc is a zombie, we will give the attacker xp,
I will break it down:
attacker.xp = ( attacker.xp or 0 ) + <some amount>

the attacker gets a variable “xp”, which can be accessed with Player.xp
I say Player.xp because the player now has this value, so say if we had a for loop looping through all players
for k,v in pairs(player.GetAll()) do
print(v.xp)
end

v = Player, so if you have a bit of code that has ply or pl or any value name which is a player, you can get the xp

next we have the assignment of xp, first we check if the player has xp already, ( attacker.xp or 0 ), if the attacker has xp already, make his xp his current xp otherwise we set it to 0, then we add how much we want for killing the zombie, if you want 20 xp, then change <some amount> to 20 like so
attacker.xp = ( attacker.xp or 0 ) + 20

I hope this helped? If it confuses you, just ignore it and wait for Acecool or someone to save the day

Could always take a look at this great XP system that was released here: http://forum.facepunch.com/showthread.php?t=1376143 Maybe read through the files and try get an understanding of how it all works. Along with what the other two guys said.

alright, that was a great explanation for simple scripts like these, thanks a bunch!

so now that i have a little script i have to ask if i wanted to print my xp to the chat do i need a hook or a function, and which? i tried looking at the exp system you linked me but the code is pretty complicated and theres alot of things i dont want like ranks. could i just put


for k,v in pairs(player.GetAll()) do
print(v.xp)
end

in a script? or do i need more to print the value

Should work fine, however, you should remember doing this clientsided.

Yep, but I recommend having your script like this



hook.Add("PlayerInitialSpawn", "SetPlayerXP", function( ply )
	ply.xp = 0
end)

hook.Add( "OnNPCKilled", "Award XP", function( npc, attacker, inflictor )
  if npc:Classify( ) == CLASS_ZOMBIE and attacker:IsPlayer( ) then
    attacker.xp = ( attacker.xp or 0 ) + 20
  end
end )

function PrintAllXP()
	for k,v in pairs(player.GetAll()) do
		print(v.xp)
	end
end


So when they first join, we set their xp to 0, then when they kill a zombie we add xp, then just call PrintAllXP() to print everyones xp

The hook ‘PlayerInitialSpawn’ is called when someone joins the server and spawns for the first time, we set their xp to zero because what if we didn’t have that, so someone joins and then you call PrintAllXP()? well, since the player never killed a zombie, v.xp would not be defined, so we define it when they first spawn, I also recommend saving everyones xp to a table then to a txt document (I would do MySQL, but that’s a little more advanced and isn’t completely necessary for you to do)

For simplicity I will show you how to read and save with txt documents.



local xp = { }
local filename = "MyServerXP.txt"

hook.Add("PlayerInitialSpawn", "SetPlayerXP", function( ply )
	ReadXP() // when they spawn give them their xp
end)

function PlySaid( ply, text, public )
	if ( string.sub(text, 1, 3) == "/xp" ) then // if they write /xp tell them their xp
		PrintXP(ply)
		return ""
	end
end
hook.Add( "PlayerSay", "PlySaid", PlySaid );

hook.Add( "OnNPCKilled", "Award XP", function( npc, attacker, inflictor )
  if npc:Classify( ) == CLASS_ZOMBIE and attacker:IsPlayer( ) then
    attacker.xp = ( attacker.xp or 0 ) + 20
	SaveXP() // save their xp
  end
end )

function PrintXP(ply)
	ply:PrintMessage(HUD_PRINTTALK, "You have "..ply.xp.." xp") // Prints xp to that player
end

function PrintAllXP()
	for k,v in pairs(player.GetAll()) do
		print(v:Nick().." has ".. tostring(v.xp) .." xp") // Loops through all players and prints to console their xp
	end
end

function SaveXP()
	for k,v in pairs(player.GetAll()) do // loops through all players
		low = string.lower(v:SteamID()) // makes a value with their steam id lowercased because when we save a table it lowercases
		if(v.xp == nil) then v.xp = 20 end // a check to make sure we dont do something stupid
		xp[low] = v.xp // update table
	end
	ab = util.TableToKeyValues(xp) // convert table to key value 
	file.Write(filename, ab) // save
end

function ReadXP()
	if(file.Exists(filename, "DATA")) then // checks if file exists
		xp = util.KeyValuesToTable(file.Read(filename, "DATA")) // converts from key value to table
		for k,v in pairs(player.GetAll()) do // loops through players
			low = string.lower(v:SteamID()) // lowers steam id
			if(xp[low]) == nil then v.xp = 0; xp[low] = v.xp end // a check to see if they exist in table, if not give them 0 xp
			v.xp = xp[low] // give them their xp
		end
	end
end


hopefully that code makes sense, if you need help understanding feel free to leave a comment and I will explain in as much detail as possible
Also if it doesn’t work tell me

holy shit thanks but what does


local xp = { }


and



hook.Add( "PlayerSay", "PlySaid", PlySaid );


do?

It looks like the xp table stores everything that goes into the file for reading/writing purposes.
The hook.Add is a function which allows your function to be run whenever a certain event (which you specify) occurs. In this case, “PlayerSay” is a hook called whenever a player hits sends a chat message. The “PlySaid” is the identifier, and PlySaid the name of the function. The purpose of this is to tell the player their current XP.
More info on hooks here

local xp = {}

that creates an empty table, which we can add our player and their xp to, so if we do
xp[1] = 4
xp[2] = 7
that would be the same as:
local xp = { 4, 7 }

so if we do
xp[v:SteamID()] = v.xp

if my steam id is “STEAM_0:0:15683” and my xp is 20, it is the same as
xp[“STEAM_0:0:15683”] = 20

which is also the same as

local xp = { [“STEAM_0:0:15683”] = 20 }

A really good explanation is here: http://lua-users.org/wiki/TablesTutorial

I use it so I can easily save and read what the players xp’s are

The hook.Add( “PlayerSay”, “PlySaid”, PlySaid ); is pretty much what I said last time about hooks
the hook is an event, PlayerSay is called when someone says something, so if I type “hey” in the chat, that hook.Add will be called, explanation here: http://maurits.tv/data/garrysmod/wiki/wiki.garrysmod.com/indexd101.html

Also, hook.Add( “PlayerSay”, “PlySaid”, PlySaid );
the end part, PlySaid, is the function, but instead of creating a function we call one, it is the exact same as doing this



hook.Add( "PlayerSay", "PlySaid", function( ply )
     PlySaid( ply )
end)


Also, ignore the “;”, they are optional and do nothing, the only reason you will see me use them sometimes is because I switch between allot of languages, and I generally code in C#, which requires a “;”. So ignore “;” in Lua, they are optional.

if i wanted a reward system would


function ClaimReward()
	if xp => 600 then
	ply:SetWalkSpeed( 300 )
	end
end

work? i was a little confused when writing this

No as you have to put ply in your arguments as that is what you’re modifying. Assuming you have defined xp then yes. Maybe look into for k,v in pairs checks and check if the player has that xp and return true if they have it.

http://forum.facepunch.com/showthread.php?t=1390994&p=44719557#post44719557

Made this just for you give me a shout if you need any help. If you’re wondering why I made it actually, its because I’m procrastinating from doing some studying :v:

What I tend to do, when creating an XP system; is I make a list of all the xp / level math right away. Each time you run one of the functions to calculate xp based on level, etc, it can be expensive. I do it in one swoop so its stored in memory.

Way better then my example, god.
Should have made that before I had posted my crappy example :stuck_out_tongue: