Leaderstats support

Hey devs, I have an issue where I have issues making the kills leaderstat to add +1 after each player the client has killed.
I’m quite new to scripting and I have somewhat beginner knowledge.
I’ve made this script with support.

  1. What do you want to achieve?
    I would like to make a function that gives +1 kills after every person the client has killed.
-- local dataStoreService = game:GetService("DataStoreService")
local killSave = dataStoreService:GetDataStore("PlayerKills")

game.Players.PlayerAdded:Connect(function(player)
	
	local totalKills
	local success, err=pcall(function()
		totalKills = killSave:GetAsync("Player_"..player.UserId)
	end)
	
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	local kills = Instance.new("IntValue")
	
	if success then
		kills.Value = totalKills
	else
		kills.Value = 0
	end
	
	kills.Name = "Kills" -- Name that shows in game.
	kills.Value = 0 -- Value of Kills When A Player Joins.
	kills.Parent = leaderstats
	
	local rank = Instance.new("StringValue")
	rank.Name = "Rank" -- Same as Line 7.
	rank.Value = "Newbie"
	rank.Parent = leaderstats
	
	local function updateKills(newKills)
		if newKills then
			
		if newKills >= 20 then -- Change number for the amount of kills to rank up.
			rank.Value = "Intermediate" -- New rank name.
		end
		if newKills >= 30 then -- Change number for the amount of kills to rank up.
			rank.Value = "Initiated" -- New rank name.
		end
		if newKills >= 40 then -- Change number for the amount of kills to rank up.
			rank.Value = "Capable" -- New rank name.
		end
		if newKills >= 50 then -- Change number for the amount of kills to rank up.
			rank.Value = "Skilled" -- New rank name.
		end
		if newKills >= 100 then -- Change number for the amount of kills to rank up.
			rank.Value = "Proficient" -- New rank name.
		end
		if newKills >= 200 then -- Change number for the amount of kills to rank up.
			rank.Value = "Professional" -- New rank name.
		end
		if newKills >= 300 then -- Change number for the amount of kills to rank up.
			rank.Value = "Specialist" -- New rank name.
		end
		if newKills >= 400 then -- Change number for the amount of kills to rank up.
			rank.Value = "Advanced" -- New rank name.
		end
		if newKills >= 500 then -- Change number for the amount of kills to rank up.
			rank.Value = "Expert" -- New rank name.
		end
		if newKills >= 1000 then -- Change number for the amount of kills to rank up.
			rank.Value = "Incredible" -- New rank name.
		end
		if newKills >= 2000 then -- Change number for the amount of kills to rank up.
			rank.Value = "Outstanding" -- New rank name.
		end
		if newKills >= 3000 then -- Change number for the amount of kills to rank up.
			rank.Value = "Elite" -- New rank name.
		end
		if newKills >= 4000 then -- Change number for the amount of kills to rank up.
			rank.Value = "Superior" -- New rank name.
		end
		if newKills >= 5000 then -- Change number for the amount of kills to rank up.
			rank.Value = "Master" -- New rank name.
		end
		if newKills >= 10000 then -- Change number for the amount of kills to rank up.
			rank.Value = "Ultimate Master" -- New rank name.
			end
		end
	end
	
	
	updateKills()
	kills.Changed:Connect(updateKills)
	
end)

local function save(player)
	local success, err = pcall(function()
		killSave:SetAsync("Player"..player.UserId,player.leaderstats.Kills.Value)
	end)
	
	if success then
		print("Saving Succeeded.")
	else
		print("Failure.")
	end
end

local function autosave()
	while wait(15)do
for i, player in pairs(game:GetService("Players"):GetPlayers()) do
			print("Saving")
			save(player)
		end
	end
end

NOTE: The script does not contain the function that gives out +1 kills after a client has killed another player.

1 Like

Something I’ve learned is that code should never be data or something along those lines. That confused me at first, but it has been very helpful after I understood it.

In your code you have this:

The first “wrong” thing about this is that the checks are in the wrong order, as you will now check and update a value for each possible rank, the second “wrong” thing about this is that you are now storing Data inside Code.

You could replace this by making a table containing the data instead, something along these lines:

local rankRequirements = {
	[20] = "Intermediate",
	[30] = "Initiated",
	... -- Etc
}

You can then loop through this and decide which rank should be awarded.

for requirement, title in pairs(rankRequirements) do
	if newKills >= rankRequirements then
		rank.Value = title
	end
end

This will still look through it in the wrong order, but it will use a lot let code, and makes it a lot easier to add/modify ranks.

To actually count kills you should have a script which is responsible for dealing damage. This script can very easily see which player was killed, and by whom (and even by which weapon if you set it up in that way).

3 Likes

Thanks for the advice, definitely useful!
The script which is the script for dealing the damage is:

local debounce = false 
local HealthLoss = 10-- Change this to the damage you need. 
function OnTouched(Part) 
	if Part.Parent ~= nil then--Keep Parentless blocks from breaking it. 
	if debounce == false and Part.Parent:findFirstChild("Humanoid") ~= nil then 
		debounce = true 
		Part.Parent:findFirstChild("Humanoid"):TakeDamage(HealthLoss)
			wait(0.11)--Wait two seconds before the brick can hurt someone. 
		debounce = false 
		end	
	end 
end


script.Parent.Touched:connect(OnTouched)

I know, this script is quite messy.
This script works just like a damage brick, I’m creating a punching tool and it works great!
It’s only that I’m unsure on where to place the function and how to create the function itself.

I would call that function after the animation [if you have any] has been completed.

2 Likes

This is the point where you deal damage. If you check the HP of the humanoid hit here then you can decide whether it was killed or not. If it was killed, then update kills for the player who owns the tool/whatever this is connected to.

local debounce = false 
local HealthLoss = 10-- Change this to the damage you need. 
function OnTouched(Part) 
	if Part.Parent ~= nil then--Keep Parentless blocks from breaking it. 
	if debounce == false and Part.Parent:findFirstChild("Humanoid") ~= nil then 
		debounce = true 
		local humanoid = Part.Parent:FindFirstChild("Humanoid")
		humanoid:TakeDamage(HealthLoss)
		if humanoid.Health <= 0 then
			print(humanoid.Parent, " was killed by", PLAYER)
		end
		task.wait(0.11)--Wait two seconds before the brick can hurt someone. 
		debounce = false 
		end	
	end 
end


script.Parent.Touched:connect(OnTouched)

PLAYER, in the script above, is either game.Players.LocalPlayer if its a localscript, or game:GetPlayerFromCharacter(script:FindFirstAncestorWhichIsA("Tool").Parent) if it is a tool.

1 Like

This is good stuff. Much better than pushing values on every single kill, every single player has, to a data store that really shouldn’t even be involved in this. Saving the data store has nothing to do with kills. Best to just keep them totally separated in everyway code wise. When a player moves a rank you update the leaderboard kills.Value variable and maybe someplace that shows it on the interface if you have that. The leaderboard sign should be on an update timer linked to the data store it uses, and will take care of itself by using the kills.Value you are setting. When the player is leaving the game would be when you update the actual data store.

Like how this is done … Global-Resetting-Leaderboard

1 Like

Whilst I was doing the things you advised me to do, the damaging brick stopped working and it does not show any type of error.

local player = game:GetPlayerFromCharacter(script:FindFirstAncestorWhichIsA("Tool").Parent)
local debounce = false 
local HealthLoss = 10-- Change this to the damage you need. 
function OnTouched(Part) 
	if Part.Parent ~= nil then--Keep Parentless blocks from breaking it. 
		if debounce == false and Part.Parent:findFirstChild("Humanoid") ~= nil then 
			debounce = true 
			local humanoid = Part.Parent:FindFirstChild("Humanoid")
			humanoid:TakeDamage(HealthLoss)
			if humanoid.Health <= 0 then
				print(humanoid.Parent, " was killed by", player)
			end
			task.wait(0.11)--Wait two seconds before the brick can hurt someone. 
			debounce = false
		end	
	end 
end


script.Parent.Touched:connect(OnTouched)

This script is a child of the handle and is not a local script.
If I’ve done anything wrong in this script, please tell me so.
vvvvvvvvvvvvvvvvvvvvvvvvvvv
image

kind of simple
damage script

local debounce = false 
local HealthLoss = 10-- Change this to the damage you need.
local Player = script.Parent.Parent.Parent.Parent --tool will be in backpack and player is the parent of that backpack
--extra check
script.Parent.Parent:GetPropertyChangedSignal("Parent"):Connect(function() --parent of tool changes
	local newParent = game.Players:FindFirstChild(script.Parent.Parent.Parent)
	if newParent then --if he is a player
		Player = newParent
	end
end)

function OnTouched(Part) 
	if Part.Parent ~= nil then--Keep Parentless blocks from breaking it. 
		if debounce == false and Part.Parent:findFirstChild("Humanoid") ~= nil then 
			debounce = true 
			Part.Parent:findFirstChild("Humanoid"):TakeDamage(HealthLoss)
			--adding a tag
			local creatorTag = Instance.new("StringValue" , Part.Parent:findFirstChild("Humanoid"))
			creatorTag.Name = "Creator"
			creatorTag.Value = Player.Name
			game:GetService("Debris"):AddItem(creatorTag , .3) --destroying without yeilding
			wait(0.11)--Wait two seconds before the brick can hurt someone. 
			debounce = false 
		end	
	end 
end

script.Parent.Touched:connect(OnTouched)

another script

for _ , v in pairs(workspace:GetChildren()) do
	if v:IsA("Model") and v:FindFirstChildWhichIsA("Humanoid") then --is it a character?
		v:FindFirstChildWhichIsA("Humanoid").Died:Connect(function() --player died
			local Tag = v:FindFirstChildWhichIsA("Humanoid"):FindFirstChild("Creator") --tag we made earlier
			game.Players[Tag.Value].leaderstats.Kills.Value += 1 --add a kill
		end)
	end
end
1 Like

For the “another script”, where do I place them?

for _ , v in pairs(workspace:GetChildren()) do
	if v:IsA("Model") and v:FindFirstChildWhichIsA("Humanoid") then --is it a character?
		v:FindFirstChildWhichIsA("Humanoid").Died:Connect(function() --player died
			local Tag = v:FindFirstChildWhichIsA("Humanoid"):FindFirstChild("Creator") --tag we made earlier
			game.Players[Tag.Value].leaderstats.Kills.Value += 1 --add a kill
		end)
	end
end

in serverScriptService and it should be a normal script

Doesn’t work, maybe I’d have to put it into the leaderstats script?

how did u test it? is there any errors?

Here is where I’ve placed this script:

local debounce = false 
local HealthLoss = 10-- Change this to the damage you need.
local Player = script.Parent.Parent.Parent.Parent --tool will be in backpack and player is the parent of that backpack
--extra check
script.Parent.Parent:GetPropertyChangedSignal("Parent"):Connect(function() --parent of tool changes
	local newParent = game.Players:FindFirstChild(script.Parent.Parent.Parent)
	if newParent then --if he is a player
		Player = newParent
	end
end)

function OnTouched(Part) 
	if Part.Parent ~= nil then--Keep Parentless blocks from breaking it. 
		if debounce == false and Part.Parent:findFirstChild("Humanoid") ~= nil then 
			debounce = true 
			Part.Parent:findFirstChild("Humanoid"):TakeDamage(HealthLoss)
			--adding a tag
			local creatorTag = Instance.new("StringValue" , Part.Parent:findFirstChild("Humanoid"))
			creatorTag.Name = "Creator"
			creatorTag.Value = Player.Name
			game:GetService("Debris"):AddItem(creatorTag , .3) --destroying without yeilding
			wait(0.11)--Wait two seconds before the brick can hurt someone. 
			debounce = false 
		end	
	end 
end

script.Parent.Touched:connect(OnTouched)

image
NOTE: This handle is in a tool.

Here’s where I’ve placed the other script:

for _ , v in pairs(workspace:GetChildren()) do
	if v:IsA("Model") and v:FindFirstChildWhichIsA("Humanoid") then --is it a character?
		v:FindFirstChildWhichIsA("Humanoid").Died:Connect(function() --player died
			local Tag = v:FindFirstChildWhichIsA("Humanoid"):FindFirstChild("Creator") --tag we made earlier
			game.Players[Tag.Value].leaderstats.Kills.Value += 1 --add a kill
		end)
	end
end

image

So far, the scripts has never printed any type of error nor I have spotted an error in the script.

i meant how did u test to say it doesn’t work, i dont think i made any mistakes…

I’ve tested it by using the servers, which you can test 2 people in the game.

Can you go through the scripts that have been posted above? I may have made a mistake.

1 Like

change kills script

while wait() do
	for _ , v in pairs(game.Players:GetPlayers()) do
		v.Character:FindFirstChildWhichIsA("Humanoid").Died:Connect(function() --player died
			local Tag = v:FindFirstChildWhichIsA("Humanoid"):FindFirstChild("Creator") --tag we made earlier
			game.Players[Tag.Value].leaderstats.Kills.Value += 1 --add a kill
		end)
	end
end

Still, nothing. I may have made a mistake.
Although, the damage brick works perfectly fine.

1 Like

wdym exactly? [chars aaassssaaa]

I mean that the following scripts that I’ve posted above may have broken or interrupted the Kills script.