How to get stamina script to work

I have a simple weapon script and a stamina system linked with a folder in each player with a stringvalue that holds their current stamina, I wanted to integrate it into my weapons, and after some trial and error I was able to properly make swinging the weapon take away stamina. The only problem is, when I run out of stamina I cant swing again until I rejoin the game. Here is the portion of the script that handles it (sorry for the bad code):

script.Parent.Activated:Connect(function()
	if not db and Stamina.Value >= 0.01 then
		if combo == 1 then
		db = true
		slash:Play()
		Stamina.Value = Stamina.Value - 0.1
		script.Parent.Handle.Swing1:Play()
		wait(.1)
		slashCaster:Start()
		wait(.5)
		slashCaster:Stop()
		db = false
		combo = combo + 1
		elseif combo == 2 then
		db = true
		slash2:Play()
		Stamina.Value = Stamina.Value - 0.1
		script.Parent.Handle.Swing2:Play()
		wait(.1)
		slashCaster:Start()
		wait(.5)
		slashCaster:Stop()
		db = false
		combo = combo + 1
		elseif combo == 3 then
		db = true
		slash3:Play()
		Stamina.Value = Stamina.Value - 0.1
		script.Parent.Handle.Swing3:Play()
		wait(.1)
		slashCaster:Start()
		wait(.5)
		slashCaster:Stop()
		db = false
		combo = combo + 1
		elseif combo == 4 then
		combo = 1
		end
	end
end)

3 Likes

You need a local script running somewhere (PlayerScripts is a good option) that will refill your stamina. This should be in a script that is not apart of your tools.

A simple while loop inside this script while increasing the stamina by a bit should be good. Just make sure you don’t overfill.

That was in place previously, and worked fine, the stamina gui even tweens properly and everything, I even checked the stringvalue and watched it refill, but I still couldnt swing after running out of stamina once. Do I need an elseif its less than or equal to 0.01?

Try putting some prints in the event to see what’s the value of Stamina, just to make sure if that’s the problem.

I printed the stamina value every time it was subtracted and it functions fine, I can sprint just fine even after I am unable to swing my weapon.

My final guess is that I need to check if its >= 0 every frame, but honestly I am super confused on what is causing this.

Check the value before you enter the if statement. Does it stay at 0?

After looking through the prints, I noticed it goes to -0.1 after the last swing, so maybe that is the cause? But why? Also if you didn’t know already the stamina value starts at 1 and goes down by increments of 0.1 every swing.

Once it goes to -.1, click again after a few seconds. Does it go back up over 0? If not, your stamina refill isn’t working properly.

Breakthrough! It stays stuck at -0.1.

But I don’t understand why it still isn’t counting back up? Here is the regen script

wait(1)
 
local Stamina = game.Players.LocalPlayer.Data:WaitForChild("Stamina")
 
while wait() do
while Stamina.Value < 0.9999 do
wait(0.1)
Stamina.Value = Stamina.Value + 0.008
end
end

Woah, scary double loop! Try this instead:

while true do
    wait(.1)
    if Stamina.Value < 1 then
        Stamina.Value = math.min(Stamina.Value + .008, 1)
    end
end

Also, I would set your max to 100 and instead use whole numbers in your system. Decimal numbers have lots of problems…

Thank you so much! I will try this!

It didn’t seem to solve the problem with the weapon, I tried to replace all the decimals with whole numbers but it kind of broke the tweening stamina bar, I don’t understand why it just stops after it runs out.

For the tween, you probably need to do Stamina.Value/100

Regarding your issue, the only thing left to do is absolutely make sure the right stamina Value is getting updated.

Also, are they all local scripts?

The scripts that handle regen and tweening are all local, the only server scripts is the one that creates the data folder and the stamina value and the weapon script is serverside.

Oh, that’s your issue. Since you subtract this value on the server, your regen script should also be on the server. Since it’s a local script, it won’t update the server sided data since it doesn’t replicate like that. You need to replicate it manually. To you keep your game safe, you should update this value only on the server and read it from the local scripts.

How exactly would I implement this into a server script since I can’t index the local player? I tried parenting the regen script to starterplayerscripts and using the script there but it didn’t seem to regen, any solutions? Here is the script (also I’m terribly sorry for the late response, I have been busy with school)

wait(1)
local player = script.Parent
print(player.Name .. "Loaded!")
local data = player:WaitForChild("Data")
local stamina = data.Stamina
print(stamina.Value .. "Stamina Loaded")

while wait() do
	if stamina.Value < 1 then
		wait(0.1)
		stamina.Value = math.min(stamina.Value + .008, 1)
	end
end

So, it looks like you have portions of your stamina system on the server, and portions of it on the client. I’d recommend putting it all in the same place just to make things easier (though it is possible to have them separate if you insist). I’d recommend the client-side since you’re working with tools, and because generally it’s better to do movement modification on the client-side anyway.

Since it sounds like you’ll be using multiple tools, and each tool will be modifying the same stamina system, I’d recommend you use a ModuleScript on the client that all the LocalScripts for the tools can access. I recommend this since it’ll be easy to keep track of what the current stamina is and update all the other tools with the current stamina when we modify it. I like to put my clients’ modules in game.ReplicatedStorage. For this example, lets name this module “StaminaModule”.

`ModuleScript` in `game.ReplicatedStorage` named "StaminaModule"
-- // In a ModuleScript in game.ReplicatedStorage
local module = {}

local currentlyRegening = false
local regenIncrement = 1 -- // How fast the player will regain stamina
module.maxStamina = 100
module.currentStamina  = module.maxStamina

-- // Where you should put whatever tween you are using. 
function StaminaUITween()
    -- // If you're adjusting the size of a GUI object, and `1` is the size when
    -- // it is full, use something like this:
    guiObject:TweenSize( -- // You'll have to define 'guiObject' with whatever you're animating
        UDim2.new(module.currentStamina/module.maxStamina, 0, guiObject.Size.Y.Scale, 0), -- // endSize (required)
        Enum.EasingDirection.In, -- // easingDirection (default Out)
        Enum.EasingStyle.Sine, -- // easingStyle (default Quad)
        .08, -- // time (default: 1)
        true -- // should this tween override ones in-progress? (default: false)
    )
end

function RegenStamina()
    if (currentlyRegening) then -- // Don't want to start multiple regen loops
        return nil
    end
    currentlyRegening = true
    
    coroutine.wrap(function() -- // Create a seperate thread so we don't yield every time we modify the stamina
        print("We have started regeneration stamina")
        while (module.currentStamina < module.maxStamina) do
            module.currentStamina = math.min(module.currentStamina + regenIncrement, module.maxStamina)
            StaminaUITween() -- // Tween the stamina guiObject
            wait(.1) -- // Our loop's yield
        end
        print("We have regenerated back to full stamina")
        currentlyRegening = false -- // Make it so we can start the regeneration loop if needed
    end)()
end

-- // Changes the module.currentStamina to whatever <newStamina> is equal to
function module.ModifyStamina(newStamina)
    if (not tonumber(newStamina)) then
        warn("Failed to update stamina, `newStamina` was not a number")
        return nil
    end
    module.currentStamina = math.clamp(newStamina, 0, module.maxStamina) -- // Set the new stamina while making sure it is a valid number that stamina could be
   
    if (module.currentStamina < module.maxStamina) then
        print("We have modified the current stamina to", module.currentStamina)
        RegenStamina() -- // Start regenerating the stamina
    else
        StaminaUITween() -- // Tween the stamina guiObject
    end
end

print("Stamina module has been successfully 'require'-d ")

return module

Now that we have the stamina module setup, we have to actually utilize it in whatever tool that we’ve got.

`LocalScript` for an example `Tool` object
-- // This is a `LocalScript` inside of a `Tool` object

local staminaModule = require(game.ReplicatedStorage:WaitForChild("StaminaModule"))
local staminaRequired = staminaModule.maxStamina * .10 -- // It takes 10% of our maximum stamina to perform an action with this tool

-- // When we activate the tool
script.Parent.Activated:Connect(function()
    if (staminaModule.currentStamina >= staminaRequired) then -- // Make sure we have enough stamina
        print("We have enough stamina to preform an action with", script.Parent.Name .. "!")
        print("Subtracting stamina!")
        staminaModule.ModifyStamina(staminaModule.currentStamina - staminaRequired)
       
         -- // Do whatever the tool is supposed to do here

    end
end)

Sorry, I may have used some complicated stuff here, I’ll link some stuff here if you want to understand:

ModuleScript
coroutine
GuiObject:TweenSize()

Hopefully this helps!

Here is a place download if you want, incase my explanation on the setup was too complicated

Baseplate.rbxl (37.1 KB)

1 Like