Math operation only works once

The purpose of this script is for handling a sprinting effect. Everytime you sprint, the Run.Heartbeat event from the server script will deduct your max stamina with the stamina cost until it reaches less than the stamina cost. My problem is the first time you tried to sprint whole holding shift, it ONLY subtracts once and it stopped subtracting. And whenever the stamina value is changed, it will fire a remote event. And that also doesn’t work. I need desperate help to solve both of this issue. Please help.

Client script:

-- services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")

-- instances
local RemotesFolder = ReplicatedStorage:WaitForChild("Remotes")
local SprintingSignal = RemotesFolder:WaitForChild("SprintingSignal")
local StaminaUpdate = RemotesFolder:WaitForChild("StaminaUpdate")

-- setup
UserInputService.InputBegan:Connect(function(key)
	if key.KeyCode == Enum.KeyCode.LeftShift then
		SprintingSignal:FireServer("Began")
	end
end)

UserInputService.InputEnded:Connect(function(key)
	if key.KeyCode == Enum.KeyCode.LeftShift then
		SprintingSignal:FireServer("Ended")
	end
end)

StaminaUpdate.OnClientEvent:Connect(function(currentStamina,maxStamina)
	print("changed")
	local size = (currentStamina / maxStamina) * 0.27
	script.Parent.Bar.Size = UDim2.new(size,0,0.09,0)
end)

Server script:

-- services
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Run = game:GetService("RunService")
local Players = game:GetService("Players")

-- spriting settings
local walkspeedMultiplier = 1.6
local maxStamina = 100
local regen = 2 -- per frame
local decrease = 10 -- per frame
local resetSpeed = 16

local sprintingPlayers = {}

-- instances
local RemotesFolder = ReplicatedStorage:WaitForChild("Remotes")
local SprintingSignal = RemotesFolder:WaitForChild("SprintingSignal")
local StaminaUpdate = RemotesFolder:WaitForChild("StaminaUpdate")

-- setup

-- to handle the size of the gui
Players.PlayerAdded:Connect(function(player)
	local stamina = Instance.new("IntValue")
	stamina.Parent = player
	stamina.Name = "Stamina"
	stamina.Value = maxStamina
	
	stamina:GetPropertyChangedSignal("Value"):Connect(function() -- this is supposed to be fired whenever the value is changed, unfortunately it didn't got fired even though the value is changed.
		print("hello")
		StaminaUpdate:FireClient(player,stamina.Value,maxStamina)
	end)
	print("event connected")
end)

-- handles the sprinting
SprintingSignal.OnServerEvent:Connect(function(player,state)
	-- define characters and stuffs
	local char = player.Character
	local humanoid = char.Humanoid
	
	if state == "Began" then
		print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
		sprintingPlayers[player.UserId] = humanoid.WalkSpeed or 16 -- assign their current speed before multiplying
		humanoid.WalkSpeed *= walkspeedMultiplier
	elseif state == "Ended" then
		humanoid.WalkSpeed = sprintingPlayers[player.UserId] -- gives back the speed they had before their speed gets multiplied
		sprintingPlayers[player.UserId] = nil -- discard the value
	end
end)

-- handles the size for gui
Run.Heartbeat:Connect(function()
	for _, player in pairs(Players:GetPlayers()) do
		local char = player.Character or player.CharacterAdded:Wait()
		local humanoid = char:WaitForChild("Humanoid")
		
		local userId = player.UserId
		local stamina = player.Stamina.Value
		
		if not sprintingPlayers[userId] then -- if selected player is not sprinting, do the regen
			if stamina > maxStamina then -- just incase if player is hacking or speed is over max
				stamina = maxStamina
			elseif stamina < maxStamina then -- the player's stamina needs to be regen
				stamina += regen
			end
		elseif sprintingPlayers[userId] then -- if selected player is sprinting
			print("player is sprinting")
			if stamina >= decrease then -- if their current stamina is more than or equal the cost
				stamina -= decrease -- this is the code line that it only subtracts once.
				print(stamina)
			else -- if their speed is less tahn the cost
				humanoid.WalkSpeed = sprintingPlayers[player.UserId] -- gives back the speed they had before their speed gets multiplied
				sprintingPlayers[player.UserId] = nil -- discard the value
			end
		end
	end
end)

GUI Hierachy (this bar will change according to the stamina you have.)
image
image

PLEASE HELP ME.

1 Like

I am totally just replying without reading here, but for things like stamina and cooldowns I always use tick(). In this case, you could let SprintStarted be equal to the tick when the sprint started (using SprintStarted = tick()) and then if tick() - SprintStarted is greater than the amount of time that you want the player to be able to sprint for maximum, let’s say 3, stop sprinting.

function CheckSprintingAllowed(Player)
if SprintStart[Player.UserId] and tick() - SprintStart[Player.UserId] >= 3 then
return false
else
return true
end
end
1 Like

Do you mean it worked the whole way down to zero one time and then the next time you try to sprint it doesn’t work, or that when you press down shift, it subtracts the decrease once and then stops while you’re still holding shift?

Regardless, I think both of your issues are connected in that you are only modifying the stamina variable. When you define

local stamina = player.Stamina.Value

it takes the intvalue’s value and places it in the variable you made. Modifying this won’t modify the actual intvalue, it will only modify the variable, and so your event to update the GUI won’t happen. This could also be causing the one time subtraction, although I’m unsure how it would happen once to begin with.

1 Like

That’s literally not my issue.

@FroggoBLOX What I meant is, it only does the math operation once, when I press shift down for the first time, and after I pressed shift down multiple times, the math operation doesn’t work anymore. And I don’t think that still solves the problem because it DID took away the number only once, so I don’t think that this will solve my script. Also, it doesn’t mean I’m cloning a new variable to store the value, I’m pretty sure the script will think I’m referencing it so I can refer the value easily with a variable, not cloning that value and store it inside a new variable.

Have you verified that it changes the intvalue and not the variable? You have to think about the use case of it like this: if it worked that way, there would be no way to sample the intvalue once and play with the number without changing the intvalue itself.

1 Like

I’m not confident to say the answer, but I assume it’s cloning the variable, because now that I imagined that if I fired an event with a value of something else and edit it somewhere without referencing the parent of that value, it wouldn’t change anything on the parent. So I guess it is NOT referencing it. For now, I’ll mark your comment as solution because it made sense.

Hi!

@ItzMeZeus_IGotHacked I got it working with some slight improvements. I’ll update this post in a couple of minutes with a link to Uncopylocked place.

EDIT
Here it is. Please excuse the basic look of the GUI, as visual styling was not a priority.

Changes
The code looks different, but the process is very similar to yours. Instead of looping through all the players, I rather create a new thread (using coroutines) for each of them. Other changes involve code styling and remote events. Strive to exchange as low amounts of data as possible between clients and the server.

I am not actually sure where the problem was hiding. In the place above, values you were creating are also removed. If you need them for some other game process, I can insert them back.