Health Increase per level

Hey everyone, I’ll try and keep this brief.

I’m currently working on an RPG leaderboard / stat tracker and everything is currently working except the players max health increase per level. I’d appreciate any advice. The first codeblock is a snippet of the script that regards the health increase and the codeblock below is the full script.

plr:WaitForChild("Values").Level.Changed:Connect(function()
			plr.MaxHealth = plr.MaxHealth + 5 * plr.Values[LevelName].Value
			plr.Health = plr.MaxHealth
local dataStoreService = game:GetService("DataStoreService")
local dataStore = dataStoreService:GetDataStore("BaseStats")

local ExpName = "Exp"
local LevelName = "Level"
local CoinName = "Gold"

game.Players.PlayerAdded:Connect(function(plr)
	local leader = Instance.new("IntValue")
	leader.Name = "leaderstats"
	leader.Parent = plr

	local Values = Instance.new("IntValue")
	Values.Name = "Values"
	Values.Parent = plr

	local Level = Instance.new("IntValue")
	Level.Name = LevelName
	Level.Value = 1
	Level.Parent = Values

	local Exp = Instance.new("IntValue")
	Exp.Name = ExpName
	Exp.Value = 0
	Exp.Parent = Values

	local Coin = Instance.new("IntValue")
	Coin.Name = CoinName
	Coin.Value = 100
	Coin.Parent = Values
	
	local save = {
		Level.Value,
		Exp.Value,
		Coin.Value
	}

	local s, e = pcall(function()
		local data = dataStore:GetAsync(plr.UserId, save)
		
		if data ~= nil then
			Level.Value = data[1]
			Exp.Value = data[2]
			Coin.Value = data[3]
		end
	end)
	
	plr:WaitForChild("Values").Exp.Changed:Connect(function()
		local Maxexp = plr.Values[LevelName].Value * 15

		if plr.Values[ExpName].Value >= Maxexp and plr.Values[LevelName].Value < 100 then
			plr.Values[ExpName].Value = 0
			plr.Values[LevelName].Value = plr.Values[LevelName].Value + 1
			game.ReplicatedStorage.LevelSystem.LevelUpGui:FireClient(plr)
		end
		
		plr:WaitForChild("Values").Level.Changed:Connect(function()
			plr.MaxHealth = plr.MaxHealth + 5 * plr.Values[LevelName].Value
			plr.Health = plr.MaxHealth
		
	end)
end)

game.Players.PlayerRemoving:Connect(function(plr)
	local save = {
		plr.Values[LevelName].Value,
		plr.Values[ExpName].Value,
		plr.Values[CoinName].Value
	}
	
	local s, e = pcall(function()
		dataStore:SetAsync(plr.UserId, save)
		end)
		end)
end)
1 Like

I don’t get the problem.

Is this a ressource to help those who could need this or do you have an issue?

he’s asking for help regarding a script.

What advices? I am sorry if I am exaggerating, but is his script not working? Does he need help with how to organize his code better? How to comment it correctly?

You have already defined “Exp” and “Level”. Directly use the variables, instead of using WaitForChild.

plr:WaitForChild("Values").Exp.Changed:Connect(function()
-- Should be
Exp.Changed:Connect(function()
plr:WaitForChild("Values").Level.Changed:Connect(function()
-- Should be
Level.Changed:Connect(function()

When you want to add/substract a value to it’s current value don’t do this:

plr.MaxHealth = plr.MaxHealth + 5 * plr.Values[LevelName].Value
-- In this case do this instead:
plr.MaxHealth += 5 * plr.Values[LevelName].Value

maybe something like this?

local function SetCharacterLevel(player, level)
    if player.Character == nil then return end
    local humanoid = player.Character:WaitForChild("Humanoid")
    local health = level * 5
    humanoid.MaxHealth = health
    humanoid.Health = health
end

game.Players.PlayerAdded:Connect(function(player)
    local playerDataFolder = player:WaitForChild("Data")
    local levelValue = playerDataFolder:WaitForChild("Level")

    SetCharacterLevel(player, levelValue.Value)
    player.CharacterAdded:Connect(function(character)
        SetCharacterLevel(player, levelValue.Value)
    end)

    levelValue.Changed:Connect(function(value)
        SetCharacterLevel(player, value)
    end
end)

and maybe something like this for the datastore

local playerLoaded = {}

game.Players.PlayerAdded:Connect(function(player)
    -- when the player enters the game try to load there data
    local success, value = pcall(dataStore.GetAsync, dataStore, player.UserId)
    if success == false then return end
   
    -- if the value = nil then set value to a empty table
    value = value or {}

    -- clone the data folder inside this script with all its values
    local folder = script.Data:Clone()

    -- loop all values and set them to match what was last saved in the datastore
    for i, child in ipairs(folder) do child.Value = value[child.Name] or child.Value end

    -- place the folder into the player
    folder.Parent = player

    -- set the playerloaded to true so we can keep track if there are players loaded so that bind to close can wait
    playerLoaded[player] = true
end)

game.Players.PlayerRemoving:Connect(function(player)
    -- if player loaded == nil meaning the player failed to load when they entered we simple exit because we dont want to overwrite the old data
    if playerLoaded[player] == nil then return end
 
    -- create a table and set the the values from there data folder
    local playerData = {}
    for i, child in ipairs(player.Data:GetChildren()) do
        playerData[child.Name] = child.Value
    end

    -- now save this table to the datastore
    local success, value = pcall(dataStore.SetAsync, dataStore, player.UserId, playerData)

    -- now set playerLoaded to nil so that bindtoclose can stop looping and allow the server to close
    playerLoaded[player] = nil
end)

-- while players are loaded dont close the server (only works upto 30 seconds)
game:BindToClose(function()
    while next(playerLoaded) ~= nil do
        task.wait()
    end
end)

PlayerDataFolder and LevelValue is not a thing before he creates them when a player joins the game, so you can’t wait for them to be there, when they’re non existent

Also there’s a few issues with your SetCharacterLevel function. :slight_smile: Haven’t taken a look at the bottom script.

Edit: After looking at the bottom script. Don’t have multiple CharacterAdded or PlayerAdded events in your game.
image

in the second script it creates PlayerDataFolder and LevelValue so the first script will wait until the second script has created them

iv just double checked the SetCharacterLevel function and i see no problem what problem do you see?

the hole point of events is to have as many functions as you like connected to them i’m not sure why you think you should only have one function connected to a event

and we are not using unsynchronised threads so not sure what the image is about

Hi!

After looking at the bottom script, I saw that there wasn’t a problem with waiting for PlayerDataFolder or LevelValue. (As stated above)

PlayerAdded will be unsyncronized, if we have multiple of them. One of them starts before the other, hint to why you’re using WaitForChild.

Correct me if I’m some of my statements are wrong. :slight_smile:

so that’s correct if you connect multiple functions to the same event the order that the functions will be called is undefined so that’s why i’m waitForChild to make sure the order is correct

currently Roblox only uses 1 thread (that’s why functions get called one after the other and not at the same time) but they do have a beta feature that allows you to have multiple threads in studio but not in published games you can read more here Parallel Lua Beta

i believe the Unsafe warning has something to do with the new parallel lua feature but i’m not sure because i have not really tested it

Alright, I will read the article when I have the time. :slight_smile:

But since you’re WaitingForChild anyway I would suggest only having 1 PlayerAdded event, since I personally feel that it’s a unneccessary wait.

I personally do this approach:

  • Create all core ReplicatedDataValues (leaderstats or what fits your game)
  • Load PlayerData (or give defaultData if no Data was found for the core ReplicatedDataValue, and create ReplicatedDataValues for non-core Data (like if you have a dictionary of pets you own or something)
  • Parent all ReplicatedDataValues into leaderstats(or what ever fits your game), since we don’t want to add them before the values of them are correct
  • Any other checks here
  • Spawn their character

Hey, thanks for all the replies guys as stated in the original description everything in the script is working properly except the health increasing per level.

plr.MaxHealth = plr.MaxHealth + 5 * plr.Values[LevelName].Value
-- In this case do this instead:
plr.MaxHealth += 5 * plr.Values[LevelName].Value

This is the current line in the script and I’m wondering how i can get it to work properly? Its currently not increasing the players max health per level as intended and I’m stumped on how to fix the problem.

Have you checked if the replicated value that you have stored in the player updates?

It does, the players level increases after getting Exp but the players health is not increasing with level.

I ended up finding a solution while looking through some free models. For anyone curious or looking for a solution I’ve put an exerpt from the script i found below.

local hum = child.Character:FindFirstChild("Humanoid")
if (hum ~= nil) then
hum.MaxHealth = hum.MaxHealth + 5 * lvl.Value
hum.Health = hum.MaxHealth
end end)
child.CharacterAdded:connect(
function(character)
local hum = character:FindFirstChild("Humanoid")
if (hum ~= nil) then
hum.MaxHealth = hum.MaxHealth + 5 * lvl.Value
hum.Health = hum.MaxHealth
end 
1 Like