How do I restart an function?

I’m trying to make a stun script, that will run everytime the player is hit.

The issue is that whenever the player is hit twice, the event will run twice meaning that he will be unstunned earlier on the second hit.

I’ve tried courotines, disconnecting events… everything. I just haven’t found a valid solution to this yet.

			character.Humanoid:SetAttribute("Stunned", true)
			character.Humanoid.WalkSpeed = 8
			character.Humanoid.JumpPower = 0
			wait(0.5)
			character.Humanoid:SetAttribute("Stunned", false)
			character.Humanoid.WalkSpeed = 16
			character.Humanoid.JumpPower = 50

As you can see, the stun script causes the player to reduce movement. However, because of the wait function, this means that when the player is damaged a second time, he will recover quickly due to the first hit.

2 Likes

in the game i’m coding right now, i use a radically different system that works a lot more efficiently and will help combat your issue. how it works is quite simple;

  1. a script is inserted into every character to describe the consequences of an effect
  2. the effect stops and starts when a certain tag is attached to the character
  3. to enable a temporary effect, add the tag (In my Instance it’s a boolValue, but it can be anything as long as the name corresponds) and give it a debris timeout

so your script on the stunning part would be something like:
stuntag=Instance.new("BoolValue",character) stuntag.Name="StunEffect" game:GetService("Debris"):AddItem(stuntag,2) -- 2 here is the amount of seconds the stun lasts

and on the side of the character:

`script.Parent.ChildAdded:Connect(function(chl)
if chl.Name==“StunEffect” then
– do the stun starting here
end
end)

script.Parent.ChildRemoved:Connect(function(chl)
if script.Parent:FindFirstChild(“StunEffect”) then – we do that to make sure the stunning ends only when the last tag dissapears
else
– do the stun removing here
end)`
furthermore, this system is more centralised, meaning you can change the effects of a stun simply by changing the default character script!

2 Likes

Thanks for your response, but my aim is to have the function restart when it is called a second time.

Say for example the player was stunned twice - he will have 2 conflicting functions which will switch him from “stunned” to “stunned” again, and here is the problem - function1 will toggle “unstunned” rather than the latter (function2). In my game I’m trying to have a combo system which means that I need to have a stacking stun mechanic or player won’t be able to perform combos.

1 Like

you’re complicating your life with the Stunned Attribute, this code i offer only requires to verify if there is at least one StunEffect Tag within the character to make sure he’s stunned
of course if you need it in you can always just make sure to tick it off if and only if the last tag is getting removed

1 Like

what has that got to do with anything… the stun attribute is for other pieces of code to check. I have a working combat system outside of the script lol

Right now, the issue is with the stack of the function. I just want the player to be stunned for a certain amount of time, and to continue being stunned as the player is being hit. I want the latter hit to run the function without the first cancelling it.

1 Like

There isn’t really any way of restarting functions. The only thing you can do is call the function again, but only run the last part of the function conditionally if the function hasn’t been called again at a later point. Here’s one way you could do that with coroutines:


local numStuns = 0

--Apply a stun and remove it after some time (must be managed, see stun())
function stunEffect()
    local stunNum = numStuns + 1
    numStuns = numStuns + 1

    --Apply stun effect
    print("applying stun " .. stunNum)
    
    coroutine.yield() --Yield to allow manager to not continue this function, in case stun effect should not be removed (e.g. because a later stun effect was applied)

    --Remove stun effect
    print("removing stun " .. stunNum)
end

--Manage stuns
local latestStun
function stun()
    local stun = coroutine.create(stunEffect)
    coroutine.resume(stun)
    latestStun = stun
    
    wait(STUN_DURATION)

    if stun == latestStun then
        coroutine.resume(stun)
    end
end

stun()
stun()
-- Should print "applying 1 applying 2 removing 2"
5 Likes

A different way you could go about it is keeping a global variable that keeps track of when the stun effect should expire. Applying a stun sets this time to 3s in the future, and uses the previous “time to remove stun” to check if there is already a stun in effect. If there isn’t, apply a stun effect. As part of applying the stun effect, wait 3s and check if the “time to remove stun” has been reached. If not, that means it has been moved further into the future by a subsequently applied stun effect. If it has been reached, remove the effect.

1 Like

well the two can still be compatible, just make sure as i said to only tick the attribute off once all tags are gone

1 Like

This can be handled with FindFirstChild to check if a stun object is already inside the character’s stun folder.

local stunfolder = Character.StunFolder
local stunvalue = Instance.new("object here", stunfolder
game.Debris:AddItem(stunvalue, stunduration)

When changing the walkspeed and jump power simply do:

    if Character.StunFolder:FindFirstChild("YourStunValue") then return end

or

if not Character.StunFolder:FindFirstChild("Your stun value") then
--code
end

I suggest making a ModuleScript for speed changes so you have to do this only once.

To add the folder to a character simply use the CharacterAdded event.

player.CharacterAdded:Connect(function()
--add folder
end
2 Likes

Would it not be easier to have one numbervalue and detect if the value is above 0? Since you can cancel or change stun time.

Either way is possible, an object folder or a number value are both good ways of doing it.

This saves a lot of headaches.

Thank you, that works perfectly. But the outcome was different than you said, for me it printed

applying stun 1 -- 23.548
removing stun 1 -- 25.780
applying stun 2 -- 25.780
removing stun 2 -- 26.290

But the removing and applying happen at the same time, down to the millisecond. So it should be fine!

Cheers :smile:

It looks like your problem has been solved but just wanted to shed some light on my Stun Handler module. It can be used across multiple scripts and is fully customisable to suit your needs.

To use it, all you need to do is require the module. Whenever you want to stun a character, send the humanoid and stun duration to the function.
The function checks if the time remaining from the previous stun is shorter than the new stun, if it is shorter, the duration is updated to the new one that was sent.

Very important note to anyone trying to use Emma’s code: The code WILL NOT work in local scripts. I’ve tried it myself to make a restarting function for a text gui using a local script and it didn’t work so i tried putting it in a server script and it worked.