Last tool's effect persists after death which overrides next tool's time period

  1. What do you want to achieve? Keep it simple and clear!
    Each tool (potion) has a timer embedded into their respective function on the server script which is run when the event is triggered from a local script, this timer is used to determine how long a potion’s effect should last for and after the time is up, follow-up code is run to remove player’s boosts from this potion. [note: potion gets DELETED from the player’s backpack when they use it]

When a player uses a tool (potion) and die during it’s effect period, the effect will not persist after death (for example, if it was a speed potion, player loses that speed boost when they respawn) which is intended and it’s wait period gets removed as well so it doesn’t tamper with the next potion’s effect period.

  1. What is the issue? Include screenshots / videos if possible!
    When a player uses a tool (potion) and die during it’s effect, the effect will not persist after death (which is intended) but the follow-up code AFTER the wait period is up will run and mess up the player statistics (only if another tool (potion) is used during the last tool’s wait period).
  2. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I have been looking for ways to incorporate wait periods on tools as it seems the wait periods currently in place are conflicting with one another, but since the tools are 1-time use only and get removed after use, I can’t think of a way of checking which tool has been used and is currently in cooldown (so it could be cancelled after death). Please let me know of any ways and I’ll review them.

I am 100% sure that the wait statements are the core issue here, I’ll present a scenario where it would cause an issue:

  • Player drinks a defence potion with 60 seconds of effect and cooldown and provides 15% of immunity to any damage taken (for this example, let’s assume player will use potion of the same type and size (boost))
  • Player dies within the first 30 seconds of gameplay, after they respawn the initial effect of the potion is cancelled by another script which handles player statistics to ensure that the statistics are correct based on levels which ignores any boosts, which is all intended, but the wait statement continues to wait for another 30 seconds because the potion’s effect/wait period was 60, if a player doesn’t drink the same potion of this type for the last 30 seconds, the follow-up code will remove the boost correctly and everything will work fine (in this case, player had 20% defence immunity with boost, now has 5%) but if a player Drinks another potion of this type within the last potion’s wait period, the last potion’s wait period will take priority and remove player’s statistics based on the boost of the last potion (which is 20% - 15% = 5%) AND THEN after this current potion’s wait period is done, it’ll remove ANOTHER 15% (which is 5% - 15% = -10%)

Please note that potions are divided into different categories which is used to determine which potion ‘type’ is being used in order to allocate the right statistics boost to the player.

game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function(character)
		local levelSelection = player:WaitForChild("levelSelection")
		local defenceStatValue = levelSelection:WaitForChild("DefenceValue")
		local hum = character:FindFirstChild("Humanoid")
		local healthCooldownValue = levelSelection:FindFirstChild("HealthCooldown")
		local speedCooldownValue = levelSelection:FindFirstChild("SpeedCooldown")
		local defenceCooldownValue = levelSelection:FindFirstChild("DefenceCooldown")
		local replicatedStorage = game:GetService("ReplicatedStorage")
		local smallHealthCooldownEvent = replicatedStorage:WaitForChild("PotionEvents").SmallHealthEvent
		local smallSpeedCooldownEvent = replicatedStorage:WaitForChild("PotionEvents").SmallSpeedEvent
		local smallDefenceCooldownEvent = replicatedStorage:WaitForChild("PotionEvents").SmallDefenceEvent
		local mediumHealthCooldownEvent = replicatedStorage:WaitForChild("PotionEvents").MediumHealthEvent
		local mediumSpeedCooldownEvent = replicatedStorage:WaitForChild("PotionEvents").MediumSpeedEvent
		local mediumDefenceCooldownEvent = replicatedStorage:WaitForChild("PotionEvents").MediumDefenceEvent
		local LargeHealthCooldownEvent = replicatedStorage:WaitForChild("PotionEvents").LargeHealthEvent
		local LargeSpeedCooldownEvent = replicatedStorage:WaitForChild("PotionEvents").LargeSpeedEvent
		local LargeDefenceCooldownEvent = replicatedStorage:WaitForChild("PotionEvents").LargeDefenceEvent
		---events for each potion so that the right name can be found in the character and remove the tool after it's used
		
		local healthLevel = levelSelection:FindFirstChild("HealthLevel")
		local speedLevel = levelSelection:FindFirstChild("SpeedLevel")
		local defenceLevel = levelSelection:FindFirstChild("DefenceLevel")
		local baseHealth = 150
		local baseSpeed = 20
		local baseDefence = 0
		local incrementSpeed = 2
		local incrementDefence = 0.05
		-- finding the base stats and their equivalent after calculations of levels, this is used to bring back the right stats to play after potion effect expires
		
		local function calculateHealth(boost, cooldownType)
			hum.MaxHealth = baseHealth * healthLevel.Value
			if hum.Health <= boost and cooldownType.Value == true then
				hum.Health = 1
			elseif hum.Health > boost and cooldownType.Value == true then
				hum.Health -= boost
			elseif cooldownType.Value == false then
				return -- player drink debounce is false, don't do anything
			end
		end

		local function calculateSpeed(boost, cooldownType)
			local speedBoost = incrementSpeed * speedLevel.Value
			if cooldownType.Value == true then
				hum.WalkSpeed = baseSpeed + speedBoost
			else
				return -- player drink debounce is false, don't do anything
			end
		end

		local function calculateDefence(boost, cooldownType)
			local defenceBoost = incrementDefence * defenceLevel.Value
			if cooldownType.Value == true then
				defenceStatValue.Value -= boost
			else
				defenceStatValue.Value = baseDefence + defenceBoost
			end
		end
		
		healthCooldownValue.Value = false
		speedCooldownValue.Value = false
		defenceCooldownValue.Value = false
		---when player joins, the values reset and the player can drink a potion
		
		-- this Round function is for rounding up the result of the 0.05 + 0.05, for whatever reason the float points glitch creates up to 10 decimal place number outcomes
		-- and with this function, it gets converted to 3 decimal places for correct calculation
		local function Round(Number, Digits, Multiples)
			local Num = math.round(Number * 10^Digits) / 10^Digits
			if Multiples then Num = math.round(Num / Multiples) * Multiples end
			print("worked, and the value is", Num)
			return Num
		end
		
		local function potionConsumed(cooldownType, boost, toolName, cooldownPeriod)
			local hum = character:FindFirstChild("Humanoid")
			local tools = character:GetChildren()
			for _, tool in pairs(tools) do
				if tool:IsA("Tool") then
					if tool.Name == toolName then
						if cooldownType.Value == false then
							cooldownType.Value = true
							if cooldownType == defenceCooldownValue then
								local calculation = tonumber(defenceStatValue.Value) + tonumber(boost)
								local trueValue = Round(calculation, 3)
								defenceStatValue.Value = trueValue
								task.wait(1.5)
								tool:Destroy()
								task.wait(cooldownPeriod)
								calculateDefence(boost, cooldownType)
								cooldownType.Value = false
							elseif cooldownType == speedCooldownValue then
								hum.WalkSpeed = hum.WalkSpeed + boost
								task.wait(1.5)
								tool:Destroy()
								task.wait(cooldownPeriod)
								calculateSpeed(boost, cooldownType)
								cooldownType.Value = false
							elseif cooldownType == healthCooldownValue then
								hum.MaxHealth = hum.MaxHealth + boost
								if toolName == "Small Health Potion" then
									local humanoidHealth = hum.MaxHealth
									local healthToAdd = humanoidHealth * 0.25
									if hum.Health + healthToAdd >= humanoidHealth then
										hum.Health = humanoidHealth
									else
										hum.Health += healthToAdd
									end
								elseif toolName == "Medium Health Potion" then
									local humanoidHealth = hum.MaxHealth
									local healthToAdd = humanoidHealth * 0.5
									if hum.Health + healthToAdd >= humanoidHealth then
										hum.Health = humanoidHealth
									else
										hum.Health += healthToAdd
									end
								elseif toolName == "Large Health Potion" then
									local humanoidHealth = hum.MaxHealth
									local healthToAdd = humanoidHealth * 0.75
									if hum.Health + healthToAdd >= humanoidHealth then
										hum.Health = humanoidHealth
									else
										hum.Health += healthToAdd
									end
								end
								task.wait(1.5)
								tool:Destroy()
								task.wait(cooldownPeriod)
								calculateHealth(boost, cooldownType)
								cooldownType.Value = false
							end
						end
					end
				end		--FIX SO THAT TOOLS GET CHECKED FIRST, AND IF PLAYER DOESN'T HAVE THE TOOL, THE LOOP STOPS TO AVOID EXPLOITERS EXPLOITING THIS
			end
		end
		smallHealthCooldownEvent.OnServerEvent:Connect(function()
			potionConsumed(healthCooldownValue, 100, "Small Health Potion", 30) -- put in the cooldown type, the boost and the name of the tool and the function will handle the rest
		end)
		smallSpeedCooldownEvent.OnServerEvent:Connect(function()
			potionConsumed(speedCooldownValue, 3, "Small Speed Potion", 30) -- put in the cooldown type, the boost and the name of the tool and the function will handle the rest
		end)
		smallDefenceCooldownEvent.OnServerEvent:Connect(function()
			potionConsumed(defenceCooldownValue, 0.05, "Small Defence Potion", 30) -- put in the cooldown type, the boost and the name of the tool and the function will handle the rest
		end)
		mediumHealthCooldownEvent.OnServerEvent:Connect(function()
			potionConsumed(healthCooldownValue, 200, "Medium Health Potion", 45) -- put in the cooldown type, the boost and the name of the tool and the function will handle the rest
		end)
		mediumSpeedCooldownEvent.OnServerEvent:Connect(function()
			potionConsumed(speedCooldownValue, 7, "Medium Speed Potion", 45) -- put in the cooldown type, the boost and the name of the tool and the function will handle the rest
		end)
		mediumDefenceCooldownEvent.OnServerEvent:Connect(function()
			potionConsumed(defenceCooldownValue, 0.1, "Medium Defence Potion", 45) -- put in the cooldown type, the boost and the name of the tool and the function will handle the rest
		end)
		LargeHealthCooldownEvent.OnServerEvent:Connect(function()
			potionConsumed(healthCooldownValue, 300, "Large Health Potion", 60) -- put in the cooldown type, the boost and the name of the tool and the function will handle the rest
		end)
		LargeSpeedCooldownEvent.OnServerEvent:Connect(function()
			potionConsumed(speedCooldownValue, 12, "Large Speed Potion", 60) -- put in the cooldown type, the boost and the name of the tool and the function will handle the rest
		end)
		LargeDefenceCooldownEvent.OnServerEvent:Connect(function()
			potionConsumed(defenceCooldownValue, 0.15, "Large Defence Potion", 60) -- put in the cooldown type, the boost and the name of the tool and the function will handle the rest
			-- last number in the function is the length of cooldown and effect that the potion is going to have on the player
		end)
	end)
end)

You can just check to see if your character is dead.

if hum.Health == 0 then
      return
end

It won’t accidentally check it inside of the freshly spawned character. Look into scopes if you find this confusing, in layman’s terms you effectively generate a whole new script whenever a character spawns while still keeping the old one tied to the old character around running in the background.

1 Like

Hello @Kizylle,

Thank you for your reply,

This actually explains a lot…during testing I was finding myself print various values of numerous Booleans and there have been instances where the script would not reflect what the values actually were…which now makes sense, I’ll utilise this approach going forward,

I was under the impression that the scripts found under the tools would actually get deleted alongside the tool and stop the script from progressing, but I’m guessing the server has already been prompted to carry on the logic anyway in some cache it may have.