How would I go about making a stamina system?

I’ve tried for about 5 hours now to make a stamina system for my game. It needs to be serversided so exploiters can’t change their own stamina.

  • The stamina system will be removing stamina in a loop, while the player is running.

  • The stamina system will remove x stamina points whenever the player punches.

  • The stamina system will remove x stamina points whenever the player jumps

  • The stamina system will remove x stamina points whenever the player dashes.

  • At last the stamina system should regenerate after x amount of time the events has not happened.

  • Note, the dash, jump, run and combat scripts are different scripts, so I don’t know how I will communicate from server to server and from client to server.

Thanks In advance.

This is the latest code I ditched, it was just a test with a bindable event from a server script. It didn’t work ofc.

local RS = game:GetService("ReplicatedStorage")
local STAM_REMOTE = RS:WaitForChild("Remotes"):WaitForChild("Stamina")
local SS = game:GetService("ServerStorage")
local STAM_EVENT = SS:WaitForChild("Stam")

local CanRegen = true
local running = false

STAM_EVENT.Event:Connect(function(plr, action)
	
	local stam = plr.Character:FindFirstChild("Stamina").Value
	
	print(plr, action)
	
	if action == "punch" then
		
		if stam > 7 then
			
			stam = stam - 7
			
			print(stam)
			
		else
			
			stam = 0
			
		end
		
	end
	
end)
2 Likes
  • For the running I would first use Humanoid.Running:Connect(function(speed) to check if the player is actually running.

  • I think for this one you already have an idea seeing your script already have this kind of condition player punch, lose A stamina.

  • For this one same as the running Humanoid:GetPropertyChangedSignal("Jump"):Connect(function()

  • Same as the punching instead of action == "punch" it’s action == "dash"

  • For this one I would use tick() and subtract it with, when was the player last use the event then player can regen.

This is the idea of how I would create A stamina system if ever I would create one for my self.

I’m not sure what x is you said “system will remove x stamina”, then you said “should regenerate after x amount of time”, I’m not sure if your talking about value or time here, maybe both, since both are separate I thought both are the same thing.

3 Likes

with x i meant x amount of stamina, and regenerate after x amount of time yes.

I know all this you mentioned, but how would I make it safe and server sided. I can’t connect a function to a humanoid event since it’s on the server. I would have to fire the server to do that.

I think I’ll end up firing the server from the client anyways so let’s leave that behind.

And for last, how can I communicate from server script to server script?

I tried BindableFunctions, and BindableEvents but they didn’t work as intended.

1 Like

That doesn’t mean you can’t connect events of a humanoid on the server. You CAN connect those events on the server. You just have to loop through each player’s character model and get their humanoid instance and connect the events.

BindableFunctions and BindableEvents. If it doesn’t work then you’re probably using them wrong.

You should spawn a thread for every singe player in your game that handles their stamina system. It should be in a while loop, and inside it you should check if they are jumping, running, dashing or other things that would cost stamina. If any one of these is true, you deduct the stamina accordingly, otherwise you can safely regenerate the stamina.

3 Likes

Is that not really demanding of the server to keep iterating all players’ character and check if something is changed?

I would like more of an event style, like when you start running the server gets fired.

I will try to make something ASAP and be right back

You misread my point here. You should use a while loop to constantly regenerate the stamina. If you want to deduct any stamina, use Humanoid.StateChanged just like what @MakerDoe said.

2 Likes

How would I get Humanoid.StateChanged for every player in a server script?

1 Like

Did you even read what I’ve said?

Instead of connecting the events in a while loop, just connect them outside the while loop whilst in the thread.

1 Like

Okayy, I will also try that to see what’s best.

1 Like

I tried to make a simple repeat until loop, but it does not work.

local RS = game:GetService("ReplicatedStorage")
local STAM_REMOTE = RS:WaitForChild("Remotes"):WaitForChild("Stamina")

STAM_REMOTE.OnServerEvent:Connect(function(plr, action)
	
	local run = false
	local stamina = plr.Character:WaitForChild("Stamina").Value
	
	if action == "startedRun" then
		
		run = true
		
		repeat
			
			if stamina >= 1 then
				
				stamina -= 1
				
				wait(0.05)
				
				if stamina == 0 then
					
					run = false
					
				end
				
			else
				
				stamina = 0
				
			end
			
			print(stamina)
			
		until run == false
		
	elseif action == "stoppedRun" then
		
		print("tried to stop")
		
		run = false
	
	end
	
end)

When the stoppedRun action is fired it does set run to false, but the repeat loop does not stop for some reason?

What is isn’t working? Did you make sure you supply the correct arguments?

When action is “stoppedRun” then it prints “tried to stop” and it sure does set run to false, but the repeat until run == false still continues

Nvm, I put the run variable inside the connection so it would keep making a new thread with new values. My bad

Of course it won’t work because the compiler didn’t even get to tell the repeat until loop about it because it’s not compiled in the same scope.

You should spawn a separate thread that handles this.

Now I have made the stamina reducing part, atleast for the running.

How would I make it so after each event is done, a timer is reset and when that timer hits 0 it will begin generating stamina?

This part is really tricking me

This part tricks me as well, but I need some time to think about it. For now, try to brainstorm with the first step as doing a check whenever one of the events/actions is fired.

Sure will! I will update you when I have every action reducing stamina.

Just finished adding it all to reduce. It works well, now just for the generating part! :pray:

local RS = game:GetService("ReplicatedStorage")
local STAM_REMOTE = RS:WaitForChild("Remotes"):WaitForChild("Stamina")
local STAM_BIND = RS:WaitForChild("Remotes"):WaitForChild("StaminaBind")
local run = false
local timer = 0

STAM_REMOTE.OnServerEvent:Connect(function(plr, action)

	local stamina = plr.Character:WaitForChild("Stamina")
	
	if action == "startedRun" then
		
		run = true
		
		while run == true do
			
			if stamina.Value >= 1 then
				
				stamina.Value -= 1
				
				wait(0.05)
				
				if stamina.Value == 0 then
					
					run = false
					
				end
				
			else
				
				stamina.Value = 0
				break
				
			end
			
			print(stamina.Value)
			
		end
		
	elseif action == "stoppedRun" then
		
		run = false
		
	elseif action == "jump" then
		
		if stamina.Value >= 10 then

			stamina.Value -= 10


		else

			stamina = 0

		end
		
		print(stamina.Value)

	end
	
end)

STAM_BIND.Event:Connect(function(plr, action)
	
	local stamina = plr.Character:WaitForChild("Stamina")
	
	if action == "punch" then
		
		if stamina.Value >= 5 then
			
			stamina.Value -= 5
			
			
		else
			
			stamina = 0
			
		end
		
		print(stamina.Value.. " punch")
		
	end
		
end)

like I said use tick(), I’ll show you an example of what I made from the past although the script is checking if the client is spamming the event, but this should give you an idea of how you would implement it.

local lastCall = {}

event.OnServerEvent:Connect(function(player, data)
	if not lastCall[player.Name] then
		lastCall[player.Name] = {0, 0, 0}
	else
		if (math.max(tick() - lastCall[player.Name][1], 0.001)) < 0.3 then
			if (tick() - lastCall[player.Name][3]) > 5 then
				lastCall[player.Name][2] += 1
				lastCall[player.Name][3] = tick()

				warn(player.Name.." is consecutively fireing the remote event.\nWarnning:", lastCall[player.Name][2])

				if lastCall[player.Name][2] > 3 then
					player:Kick(player.Name, "is consecutively fireing the remote event")
				end
			end
		else
			lastCall[player.Name][3] = tick()
		end
	end

	lastCall[player.Name][1] = tick()
end)

For the regen I think what I would do is spawn(fucntion() then add wait then use if statement and check if the lastCall has changed. It’s just an idea maybe there are other ideas out there that I’m not familiar with yet, or you could use while loop though for this one I’m not particularly sure since this feel’s like a server intensive.

Note: if you wan’t to remove the player from the array just create a PlayerRemoving function and just set the lastCall[player.Name] = nil.

Hmm, if you can look at my latest post I made 2 different parts. The first part a remote event, and the second part a BindableEvent. Since it’s not a single thread how would i go about making that???