Help with tool cooldown

Hi Devs! I have a problem(im not that good at scripting but i tried all the methods i knew)…

The game is a simulator(like eating simulator)

The problem is, when i click the ball(tool) the animation is ok, but the script that gives the currency doesn’t have a cooldown, so when i spam click the animation is regular, but the click script continue to give me the currency. i tried to put these line of code(that didn’t work for me):

wait(1)

repeat wait() until tool.GripPos == Vector3.new(0,0,0)

local debounce

I also tried to disable the script when the animation is running but it breaks.

So, if you want to help these are my scripts:

Tool animation script(Cloned in every ball):

local Tool = script.Parent
local cooldown = false
local player = game.Players.LocalPlayer

script.Parent.Activated:Connect(function()
	if cooldown == false then
		cooldown = true
		Tool.GripPos = Vector3.new(0, 0, 0)
		wait(0.01)
		Tool.GripPos = Vector3.new(0.0, 0, 0.5)
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 1)
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 1.5)
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 2)
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 2.5)
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 3)
		Tool.Bounce:Play()
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 2.5)
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 2)
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 1.5)
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 1)
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 0.5)
		wait(0.01)
		Tool.GripPos = Vector3.new(0, 0, 0)
		wait(0.60)
		cooldown = false
	end
end)

Script that fires when i click(tool)(ServerStorage):

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local remotes = ReplicatedStorage:FindFirstChild("Remotes")

local tool = script.Parent


tool.Activated:Connect(function()
	remotes.ToolActivated:FireServer()
	wait(1)
end)

ToolManager script where it defines the event that is firing from the previous script(ServerScriptService):

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local ServerScriptService = game:GetService("ServerScriptService")

local Stats = require(ServerScriptService.Utils.Stats)
local Rewards = require(ServerScriptService.Utils.Rewards)
local remotes = ReplicatedStorage:FindFirstChild("Remotes")
local tools = ServerStorage:FindFirstChild("Tools")
local scripts = ServerStorage:FindFirstChild("Scripts")
local toolConfig = require(ReplicatedStorage:FindFirstChild("Config"):FindFirstChild("ToolConfig"))

remotes.ToolActivated.OnServerEvent:Connect(function(player: Player)
	Rewards.Dribbles(player, Stats.Dribbles(player))
end)

for _, tool in ipairs(tools:GetChildren()) do
	local script = scripts.Click:Clone()
	script.Parent = tool
	local animation = scripts.Animation:Clone()
	animation.Parent = tool
	local bounce = ReplicatedStorage:WaitForChild("Sounds"):WaitForChild("Bounce"):Clone()
	bounce.Parent = tool
end

Module script where gives the currency(ServerScriptService):

local ServerScriptService = game:GetService("ServerScriptService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")


local Remotes = ReplicatedStorage.Remotes
local backpackConfig = require(ReplicatedStorage.Config.BackpackConfig)
local Stats = require(ServerScriptService.Utils.Stats)


local Rewards = {}

local function getMaxDribbles(player: Player)
	for _, config in ipairs(backpackConfig) do
		if config.ID == player.inventory.EquippedBackpack.Value then
			return config.Stat
		end
	end
end

function Rewards.Dribbles(player: Player, amount: number, useMultiplier: boolean)
	useMultiplier = if useMultiplier ~= nil then useMultiplier else true
	local multiplier = if useMultiplier == true then Stats.DribblesMultiplier(player) else 1
	local total = player.leaderstats.Dribbles.Value + (amount * multiplier)
	local max = getMaxDribbles(player)
	
	if total > max then
		player.leaderstats.Dribbles.Value = max
	else
		player.leaderstats.Dribbles.Value = total
	end
	
	if player.leaderstats.Dribbles.Value == max then
		Remotes.MaxDribbles:FireClient(player)
	end
end

function Rewards.Coins(player: Player, amount: number, useMultiplier: boolean)
	useMultiplier = if useMultiplier ~= nil then useMultiplier else true
	local multiplier = if useMultiplier == true then Stats.CoinMultiplier(player) else 1
	player.leaderstats.Coins.Value += amount * multiplier
end

return Rewards

Thanks!

1 Like

The remote event is unnecessary for your use case, if you want communication between scripts you could use bindable events.

A simple solution is just calling the reward function at the end or start of the “animation” since I see you have a debounce set up, good work.

script.Parent.Activated:Connect(function()
		if cooldown == false then
			cooldown = true
			-- reward function.
			-- animation
			-- or vice versa
			cooldown = false
		end
	end)

Now if you insist on doing this in the tool handler, like I said, use a bindable event

1 Like

Ye, i know, but how do i put a cooldown that works?

1 Like

I edited my comment, check it out

1 Like

Thanks for replying, i edited the “Animation” script eith this:

local Tool = script.Parent
local cooldown = false
local Rewards = require(game.ServerScriptService.Utils.Rewards)
local Stats = require(game.ServerScriptService.Utils.Stats)

local function anim()
	Tool.GripPos = Vector3.new(0, 0, 0)
	wait(0.01)
	Tool.GripPos = Vector3.new(0.0, 0, 0.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 1)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 1.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 2)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 2.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 3)
	Tool.Bounce:Play()
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 2.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 2)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 1.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 1)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 0.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 0)
end

script.Parent.Activated:Connect(function(player: Player)
	if cooldown == false then
		cooldown = true
		anim()
		Rewards.Dribbles(player, Stats.Dribbles(player))
		cooldown = false
	end
end)

But when i click, the animation fires once, and i didn’t give any currency.

Thanks for help!

So the animation plays once and then never again?

I also forgot to specify, this is on the server right.

1 Like

Yes, it is in a script, not local script.

Yes, the animation plays ince and then never again.

Thanks!

1 Like

Can you please specify the error in the output?

1 Like

Oh, sorry i didn’t see the error, this is the error:

image

Script:

local function getItemStat(name: string, type: string)
	local list = if type == "Ball" then ToolConfig elseif type == "Rank" then RankConfig else backpackConfig
	for _, configLine in ipairs(list) do
		if configLine.ID == name then
			return configLine.Stat
		end
	end
end

function Stats.Dribbles(player: Player)
	local total = 0
	local item = getItemStat(player.inventory.EquippedTool.Value, "Ball")
	total += item
	return total
end

1 Like

that seems to be a totally separate issue

It looks like the issue is that the currency is being given to the player immediately after clicking the tool, regardless of whether the animation has completed or not. To fix this, you can add a cooldown to the click script so that it only fires once per animation.

Here’s an example of how you could modify your existing code to implement a cooldown:

In the Tool animation script, you can add a variable to keep track of whether the animation is currently playing:

local isAnimating = false

Then, you can set this variable to true at the beginning of the animation, and set it back to false at the end:

script.Parent.Activated:Connect(function()
if cooldown == false and isAnimating == false then
isAnimating = true
cooldown = true
Tool.GripPos = Vector3.new(0, 0, 0)
wait(0.01)
– rest of animation code here
wait(0.60)
isAnimating = false
cooldown = false
end
end)

Finally, in the click script, you can check whether the animation is currently playing before giving the currency:

local ToolActivated = remotes.ToolActivated

tool.Activated:Connect(function()
if not isAnimating then
ToolActivated:FireServer()
end
end)

This way, the click script will only fire the ToolActivated event if the animation is not currently playing, preventing the player from receiving currency multiple times for a single click.

1 Like

Hey, thanks for the help, i edited my script and them look like this:

Click script:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remotes = ReplicatedStorage:FindFirstChild("Remotes")
local tool = script.Parent
local isAnimating = false
local ToolActivated = remotes.ToolActivated

tool.Activated:Connect(function()
	if not isAnimating then
		ToolActivated:FireServer()
	end
end)

Animation script:

local Tool = script.Parent
local cooldown = false
local isAnimating = false

local function anim()
	Tool.GripPos = Vector3.new(0, 0, 0)
	wait(0.01)
	Tool.GripPos = Vector3.new(0.0, 0, 0.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 1)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 1.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 2)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 2.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 3)
	Tool.Bounce:Play()
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 2.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 2)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 1.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 1)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 0.5)
	wait(0.01)
	Tool.GripPos = Vector3.new(0, 0, 0)
end

script.Parent.Activated:Connect(function()
	if cooldown == false and isAnimating == false then
		isAnimating = true
		cooldown = true
		Tool.GripPos = Vector3.new(0, 0, 0)
		wait(0.01)
		anim()
		wait(0.60)
		isAnimating = false
		cooldown = false
	end
end)

Thanks!

1 Like