Checking Value Increase

Hello! I’m making an obby game and every time you beat a stage, you should get 3 coins.

The problem is, I get coins regularly but I’m at stage 24 and when I restart, I couldn’t get any until I reach the one after which is Stage 25. Still, if I restart at Stage 3 after that, I still need to reach Stage 25 to get coins again, or I can rejoin. But I shouldn’t rejoin just to fix it- after restarting, no matter what stage I was previously on, I should get 3 coins every stage I beat.

I tried it every way I could to try to fix it but it never worked out.
My current script is below, and the main problem is above. Help is appreciated!

local DataStoreService = game:GetService("DataStoreService")
local DS = DataStoreService:GetDataStore("PlayerData")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

-- Main player setup and data handling
local function OnCharacterAdded(character)
	local player = Players:GetPlayerFromCharacter(character)
	if player and player.TeleportedStage.Value < 251 then
		RunService.Stepped:Wait()
		local humanoidRootPart = character:WaitForChild("HumanoidRootPart")
		humanoidRootPart.CFrame = workspace.Checkpoints[tostring(player.TeleportedStage.Value)].CFrame + Vector3.new(0, 3.25, 0)
	end
end

local function SetupPlayerValues(player)
	-- Create leaderstats and values folders
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local values = Instance.new("Folder")
	values.Name = "Values"
	values.Parent = player

	-- Create all value instances
	local stage = Instance.new("IntValue")
	stage.Name = "Stage"
	stage.Parent = leaderstats

	local coins = Instance.new("IntValue")
	coins.Name = "Coins"
	coins.Parent = leaderstats

	local teleportedStage = Instance.new("IntValue")
	teleportedStage.Name = "TeleportedStage"
	teleportedStage.Parent = player

	local speedCoil = Instance.new("BoolValue")
	speedCoil.Name = "SpeedCoil"
	speedCoil.Value = false
	speedCoil.Parent = values

	local jumpCoil = Instance.new("BoolValue")
	jumpCoil.Name = "JumpCoil"
	jumpCoil.Value = false
	jumpCoil.Parent = values

	local fusionCoil = Instance.new("BoolValue")
	fusionCoil.Name = "FusionCoil"
	fusionCoil.Value = false
	fusionCoil.Parent = values

	local laserWall = Instance.new("IntValue")
	laserWall.Name = "LaserWall"
	laserWall.Value = 0
	laserWall.Parent = values

	return leaderstats, values
end

local function LoadPlayerData(player)
	local key = "player_" .. player.UserId
	local success, savedData = pcall(function()
		return DS:GetAsync(key)
	end)

	if success and savedData then
		-- Load saved data
		player.leaderstats.Stage.Value = savedData.Stage or 0
		player.leaderstats.Coins.Value = savedData.Coins or 0
		player.TeleportedStage.Value = savedData.Stage or 0
		player.Values.SpeedCoil.Value = savedData.SpeedCoil or false
		player.Values.JumpCoil.Value = savedData.JumpCoil or false
		player.Values.FusionCoil.Value = savedData.FusionCoil or false
		player.Values.LaserWall.Value = savedData.LaserWall or 0

		-- Initialize reward tracking
		if not player:FindFirstChild("_RewardData") then
			local rewardData = Instance.new("Folder")
			rewardData.Name = "_RewardData"
			rewardData.Parent = player

			local lastRewarded = Instance.new("IntValue")
			lastRewarded.Name = "LastRewardedStage"
			lastRewarded.Value = player.leaderstats.Stage.Value
			lastRewarded.Parent = rewardData

			local needsInitialReward = Instance.new("BoolValue")
			needsInitialReward.Name = "NeedsInitialReward"
			needsInitialReward.Value = true
			needsInitialReward.Parent = rewardData
		end
	else
		-- Set default values
		player.leaderstats.Stage.Value = 0
		player.leaderstats.Coins.Value = 0
		player.TeleportedStage.Value = 0

		-- Initialize reward tracking
		if not player:FindFirstChild("_RewardData") then
			local rewardData = Instance.new("Folder")
			rewardData.Name = "_RewardData"
			rewardData.Parent = player

			local lastRewarded = Instance.new("IntValue")
			lastRewarded.Name = "LastRewardedStage"
			lastRewarded.Value = 0
			lastRewarded.Parent = rewardData

			local needsInitialReward = Instance.new("BoolValue")
			needsInitialReward.Name = "NeedsInitialReward"
			needsInitialReward.Value = true
			needsInitialReward.Parent = rewardData
		end
	end
end

local function SavePlayerData(player)
	local key = "player_" .. player.UserId
	local rewardData = player:FindFirstChild("_RewardData")
	local dataToSave = {
		Stage = player.leaderstats.Stage.Value,
		Coins = player.leaderstats.Coins.Value,
		SpeedCoil = player.Values.SpeedCoil.Value,
		JumpCoil = player.Values.JumpCoil.Value,
		FusionCoil = player.Values.FusionCoil.Value,
		LaserWall = player.Values.LaserWall.Value,
		LastRewardedStage = rewardData and rewardData.LastRewardedStage.Value or player.leaderstats.Stage.Value
	}

	local success, err = pcall(function()
		DS:SetAsync(key, dataToSave)
	end)

	if not success then
		warn("Failed to save data for "..player.Name..": "..err)
	end
end

local function HandleCoilItems(player)
	if player.Values.SpeedCoil.Value then
		if not player.Backpack:FindFirstChild("SpeedCoil") then
			game.ServerStorage.SpeedCoil:Clone().Parent = player.Backpack
			game.ServerStorage.SpeedCoil:Clone().Parent = player.StarterGear
		end
	end

	if player.Values.JumpCoil.Value then
		if not player.Backpack:FindFirstChild("JumpCoil") then
			game.ServerStorage.JumpCoil:Clone().Parent = player.Backpack
			game.ServerStorage.JumpCoil:Clone().Parent = player.StarterGear
		end
	end

	if player.Values.FusionCoil.Value then
		if not player.Backpack:FindFirstChild("FusionCoil") then
			game.ServerStorage.FusionCoil:Clone().Parent = player.Backpack
			game.ServerStorage.FusionCoil:Clone().Parent = player.StarterGear
		end
	end
end

local function OnPlayerAdded(player)
	-- Setup player values
	SetupPlayerValues(player)

	-- Load saved data
	LoadPlayerData(player)

	-- Set up character event
	player.CharacterAdded:Connect(function(character)
		OnCharacterAdded(character)
		HandleCoilItems(player)
	end)

	-- Handle initial character if already exists
	if player.Character then
		OnCharacterAdded(player.Character)
	end

	-- Set up stage change tracking for coins
	player.leaderstats.Stage:GetPropertyChangedSignal("Value"):Connect(function()
		local rewardData = player:FindFirstChild("_RewardData")
		if not rewardData then return end

		local currentStage = player.leaderstats.Stage.Value
		local lastRewarded = rewardData:FindFirstChild("LastRewardedStage")
		local needsReward = rewardData:FindFirstChild("NeedsInitialReward")

		if not lastRewarded or not needsReward then return end

		-- INITIAL REWARD AFTER JOINING
		if needsReward.Value and currentStage > lastRewarded.Value then
			player.leaderstats.Coins.Value += 3
			if game.ReplicatedStorage:FindFirstChild("StageCompleted") then
				game.ReplicatedStorage.StageCompleted:FireClient(player)
			end
			lastRewarded.Value = currentStage
			needsReward.Value = false
			return
		end

		-- NORMAL PROGRESSION
		if currentStage > lastRewarded.Value then
			local stagesGained = currentStage - lastRewarded.Value
			player.leaderstats.Coins.Value += stagesGained * 3
			if game.ReplicatedStorage:FindFirstChild("StageCompleted") then
				game.ReplicatedStorage.StageCompleted:FireClient(player)
			end
			lastRewarded.Value = currentStage
		end
	end)
end

-- Set up checkpoint system
for _, checkpoint in pairs(workspace.Checkpoints:GetChildren()) do
	checkpoint.Touched:Connect(function(hit)
		local player = Players:GetPlayerFromCharacter(hit.Parent)
		if player then
			local checkpointNumber = tonumber(checkpoint.Name)
			if player.leaderstats.Stage.Value == checkpointNumber - 1 then
				if player.leaderstats.Stage.Value < checkpointNumber then
					player.leaderstats.Stage.Value = checkpointNumber
				end
			end
			if player.leaderstats.Stage.Value >= checkpointNumber then
				player.TeleportedStage.Value = checkpointNumber
			end
		end
	end)
end

local RS = game:GetService("ReplicatedStorage")

repeat wait() until script.Main ~= nil

local main = require(script.Main)

function recived(plr, direction)
	if direction == "up" then
		main.up(plr, direction)
	elseif direction == "down" then
		main.down(plr, direction)
	elseif direction == "doubleup" then
		main.doubleup(plr, direction)
	elseif direction == "doubledown" then
		main.doubledown(plr, direction)
	elseif plr.Stages > main.TOTAL_STAGES_IN_GAME then
		print("Player is in an older version of the game!")
	end
end

RS.StageTransfer.OnServerEvent:Connect(recived)

for _, v in pairs(workspace.Checkpoints:GetChildren()) do
	v.Touched:Connect(function(hit)
		if v ~= nil then
			if v.Parent == workspace.Checkpoints then
				local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
				if player then
					if player.leaderstats.Stage.Value == tonumber(v.Name) - 1 then
						if player.leaderstats.Stage.Value < tonumber(v.Name) then
							player.leaderstats.Stage.Value = tonumber(v.Name)
						end
					end
					if player.leaderstats.Stage.Value >= tonumber(v.Name) then
						player.TeleportedStage.Value = tonumber(v.Name)
					end
				end
			end
		end
	end)
end

-- Connect player events
Players.PlayerAdded:Connect(OnPlayerAdded)
Players.PlayerRemoving:Connect(SavePlayerData)

-- Set up auto-save
while true do
	wait(120) -- Save every 2 minutes
	for _, player in pairs(Players:GetPlayers()) do
		SavePlayerData(player)
	end
end

I’m sorry the script is very long so I made some comments. You may ask me for any scripts for something that helps fix this. Again, help is appreciated!

Could you provide the script where it resets the player to the beginning?

Yes, I can. I’ll provide the script where it fires and where it receives the signal.
LocalScript in button:

local plr = game.Players.LocalPlayer

script.Parent.MouseButton1Click:Connect(function()
	game.ReplicatedStorage.Restart:FireServer(plr)
end)

The other script is the server script. There are more things in the same script that don’t seem to be necessary because it is about losing coins.

r.Restart.OnServerEvent:Connect(function(plr)
	game.Workspace[plr.Name].HumanoidRootPart.CFrame = game.Workspace.SpawnLocation.CFrame
	plr:WaitForChild("TeleportedStage").Value = 0
	plr.leaderstats:WaitForChild("Stage").Value = 0
	plr.PlayerGui.Present.Claimed.Visible = true
	plr.PlayerGui.Present.Claimed.Text = "Successfully restarted! Your stage has been reset."
	wait(2)
	plr.PlayerGui.Present.Claimed.Visible = false
end)

Below that are other scripts and I don’t think I might need it right now.
Under the Main Script I provided in the first post(creation), I have two scripts:
This one saving the values:

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local Saver = DataStoreService:GetDataStore("SaveValues")

Players.PlayerAdded:Connect(function(player)
	local Data = nil
	local success, errormessage = pcall(function()
		Data = Saver:GetAsync(tostring(player.UserId))
	end)

	if success then
		if Data then
			for i, v in pairs(Data) do
				player:WaitForChild("Values"):WaitForChild(i).Value = v
			end
		end
	else
		error(errormessage)
	end
end)

local function Save(player)
	local SavedData = {}
	for _, v in pairs(player.Values:GetChildren()) do
		SavedData[v.Name] = v.Value
	end

	local success, errormessage = pcall(function()
		Saver:SetAsync(tostring(player.UserId), SavedData)
	end)
	if not success then
		error(errormessage)
	end
end

Players.PlayerRemoving:Connect(Save)

game:BindToClose(function()
	for _, v in pairs(Players:GetPlayers()) do
		Save(v)
	end
end)

And this one for the stage selector module:

local trasferHandler = {}

local TOTAL_STAGES_IN_GAME = 0

for _, stage in pairs(workspace.Checkpoints:GetChildren()) do
	if tonumber(stage.Name) > TOTAL_STAGES_IN_GAME then
		TOTAL_STAGES_IN_GAME = tonumber(stage.Name)
	end
end

function trasferHandler.up(plr, direction)
	local tpStage = plr.TeleportedStage
	if tpStage.Value < plr.leaderstats.Stage.Value and tpStage.Value < 250 then
		tpStage.Value += 1
		plr.Character.HumanoidRootPart.CFrame = workspace.Checkpoints[plr.TeleportedStage.Value].CFrame + Vector3.new(0,3.25,0)
	else
		tpStage.Value = 0
		plr.Character.HumanoidRootPart.CFrame = workspace.Checkpoints["0"].CFrame + Vector3.new(0,3.25,0)
	end
end

function trasferHandler.doubleup(player, direction)
	local tpStage = player.TeleportedStage
	if tpStage.Value < player.leaderstats.Stage.Value - 10 and player.leaderstats.Stage.Value > 241 then
		tpStage.Value += 10
		player.Character.HumanoidRootPart.CFrame = workspace.Checkpoints[player.TeleportedStage.Value].CFrame + Vector3.new(0,3.25,0)
	elseif tpStage.Value == player.leaderstats.Stage.Value then
		tpStage.Value = 0
		player.Character.HumanoidRootPart.CFrame = workspace.Checkpoints["0"].CFrame + Vector3.new(0,3.25,0)
	elseif tpStage.Value >= player.leaderstats.Stage.Value - 10 and player.leaderstats.Stage.Value < 241 then
		tpStage.Value = player.leaderstats.Stage.Value
		player.Character.HumanoidRootPart.CFrame = workspace.Checkpoints[tpStage.Value].CFrame + Vector3.new(0,3.25,0)
	elseif tpStage.Value > 239 then
		tpStage.Value = 250
		player.Character.HumanoidRootPart.CFrame = workspace.Checkpoints["250"].CFrame + Vector3.new(0,3.25,0)
	elseif tpStage.Value > 249 then
		tpStage.Value = 0
		player.Character.HumanoidRootPart.CFrame = workspace.Checkpoints["0"].CFrame + Vector3.new(0,3.25,0)
	end
end

function trasferHandler.down(plr, direction)
	local tpStage = plr.TeleportedStage
	if tpStage.Value > 0 then
		tpStage.Value -= 1
		plr.Character.HumanoidRootPart.CFrame = workspace.Checkpoints[tpStage.Value].CFrame + Vector3.new(0,3.25,0)
	elseif tpStage.Value == 0 then
		if plr.leaderstats.Stage.Value < 251 then
			tpStage.Value = plr.leaderstats.Stage.Value
			plr.Character.HumanoidRootPart.CFrame = workspace.Checkpoints[plr.leaderstats.Stage.Value].CFrame + Vector3.new(0,3.25,0)
		else
			tpStage.Value = 250
			plr.Character.HumanoidRootPart.CFrame = workspace.Checkpoints[250].CFrame + Vector3.new(0,3.25,0)
		end
	end
end

function trasferHandler.doubledown(plr, direction)
	local tpStage = plr.TeleportedStage
	if tpStage.Value > 9 then
		tpStage.Value -= 10
		plr.Character.HumanoidRootPart.CFrame = workspace.Checkpoints[tpStage.Value].CFrame + Vector3.new(0,3.25,0)
	elseif tpStage.Value < 10 then
		tpStage.Value = 0
		plr.Character.HumanoidRootPart.CFrame = workspace.
			Checkpoints["0"].CFrame + Vector3.new(0,3.25,0)
	elseif tpStage.Value == 0 then
		if plr.leaderstats.Stage.Value < 251 then
			tpStage.Value = plr.leaderstats.Stage.Value
			plr.Character.HumanoidRootPart.CFrame = workspace.Checkpoints["0"].CFrame + Vector3.new(0,3.25,0)
		else
			tpStage.Value = 250
			plr.Character.HumanoidRootPart.CFrame = workspace.Checkpoints["250"].CFrame + Vector3.new(0,3.25,0)
		end
	end
end

return trasferHandler

I’m pretty sure you are not resetting the lastRewarded value, so here in the main script

if currentStage > lastRewarded.Value then
			local stagesGained = currentStage - lastRewarded.Value
			player.leaderstats.Coins.Value += stagesGained * 3
			if game.ReplicatedStorage:FindFirstChild("StageCompleted") then
				game.ReplicatedStorage.StageCompleted:FireClient(player)
			end
			lastRewarded.Value = currentStage
		end

when the player resets, the lastRewarded variable is still stage 26, so it only fires when the current stage is above stage 26.

sorry for late reply lmao

This script you wrote did not change anything. Could you point out which part to solve?

Oh yeah, it didn’t reset. I put it on the restart script to set the value to 0 and it worked. Thank you!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.