Function Triggers 16 Times

BaseMechanics.InflictDamage = function(Hitbox:Part, Attacker:Model, Damage, Knockback, PostureDamage, Blockable, Dodgeable, Parryable, StatusEffects)
	local AlreadyHit = {}
	Hitbox.Touched:Connect(function()
		local PartsHitByAttack = workspace:GetPartsInPart(Hitbox)
		for i, Part:Part in pairs(PartsHitByAttack) do
			local TargetCharacter = Part.Parent
			if not table.find(AlreadyHit, TargetCharacter) and TargetCharacter ~= nil and TargetCharacter:FindFirstChildOfClass("Humanoid") and TargetCharacter ~= Attacker then
				print("does this part loop?")
				local TargetHumanoid:Humanoid = TargetCharacter:FindFirstChildOfClass("Humanoid")
				table.insert(AlreadyHit, TargetCharacter)
				local AlreadyHitClearer = coroutine.wrap(function()
					task.wait(3)
					table.remove(AlreadyHit, table.find(AlreadyHit, TargetCharacter))
					print("Cleared")
				end)
				AlreadyHitClearer()
				local ApplyStatusEffects = function()
					for i, Effect in pairs(StatusEffects) do
						local x = 0
						print(i, Effect, x + 1)
						Effect(TargetCharacter, Damage)
					end
				end
				print("is this looping")
				if Knockback ~= nil or Knockback > 0 then
					TargetHumanoid:ChangeState(Enum.HumanoidStateType.Ragdoll, true)
					local KnockbackVelocity = Instance.new("LinearVelocity")
					KnockbackVelocity.Enabled = true
					KnockbackVelocity.MaxForce = 10000000
					KnockbackVelocity.Attachment0 = TargetCharacter:FindFirstChild("HumanoidRootPart"):FindFirstChild("RootAttachment")
					KnockbackVelocity.VectorVelocity = Attacker.PrimaryPart.CFrame.LookVector * Knockback
					KnockbackVelocity.Parent = TargetCharacter.PrimaryPart
					DebrisService:AddItem(KnockbackVelocity, .3)
				end
				if Blockable == true or Blockable ~= true then
					if Blockable == true then
						if TargetHumanoid:GetAttribute("IsBlocking") == true then
							local CurrentPosture = TargetHumanoid:GetAttribute("Posture")
							TargetHumanoid:SetAttribute("Posture", CurrentPosture + PostureDamage)
							if TargetHumanoid:GetAttribute("Posture") >= TargetHumanoid:GetAttribute("MaxPosture") then
								PostureBroken(TargetHumanoid)
								TargetHumanoid:TakeDamage(Damage)
								--ApplyStatusEffects()
							end
						else
							TargetHumanoid:TakeDamage(Damage)
							HitStun(TargetHumanoid)
							ApplyStatusEffects()
						end
					end
				elseif Dodgeable == true or Dodgeable ~= true then
					if Dodgeable == true then
						if TargetHumanoid:GetAttribute("IsDodging") == true then
							print("Attack Dodged")
						else
							TargetHumanoid:TakeDamage(Damage)
							HitStun(TargetHumanoid)
							--ApplyStatusEffects()
						end
					end
				elseif Parryable == true or Parryable ~= true then
					if Parryable == true then
						if TargetHumanoid:GetAttribute("IsParrying") == true then
							local CurrentPosture = TargetHumanoid:GetAttribute("Posture")
								TargetHumanoid:SetAttribute("Posture", CurrentPosture - 10)
						else
							TargetHumanoid:TakeDamage(Damage)
							HitStun(TargetHumanoid)
							--ApplyStatusEffects()
						end
					end
				elseif TargetHumanoid:GetAttribute("Evasions") > 0 or TargetHumanoid:GetAttribute("Evasions") == 0 then
					if TargetHumanoid:GetAttribute("Evasions") > 0 then
						TargetHumanoid:SetAttribute("Evasions", TargetHumanoid:GetAttribute("Evasions") - 1)
						HitStun(TargetHumanoid)
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						--ApplyStatusEffects()
					end
				end
			end
		end
	end)
end

My code used to be fine before I added the ApplyStatusEffects() Function. Whenever I would run it without that function, :TakeDamage and HitStun(TargetHumanoid) Would run ONLY once as intended. However the moment I uncomment the ApplyStatusEffects(), if my AlreadyHitClearer ends before the Status Effect that is applied ends, it reactivates TargetHumanoid:TakeDamage(Damage), HitStun(TargetHumanoid), AND ApplyStatusEffects().

Why does ApplyStatusEffects() in particular cause all of these problems? Why is it fine when that function is gone?

2 Likes

It would be helpful to see what the function even does.
I say it might be stalling the execution of other code so try wrapping it in a spawn()

spawn(function()
   ApplyStatusEffects()
end)

This should only be used as a test since this would mean the code isn’t very secure so things like delays from ping could end up breaking it again.

			local ApplyStatusEffects = function()
				for i, Effect in pairs(StatusEffects) do
					local x = 0
					print(i, Effect, x + 1)
					Effect(TargetCharacter, Damage)
				end
			end

But if you’re looking for the actual function itself:

	StatusEffectFunction = function(Character:Model, AttackDamage)
		local Humanoid = Character:FindFirstChildOfClass("Humanoid")
		local DamageToDeal = ElementsModule.FireMagic.Damage * AttackDamage
		if Humanoid:GetAttribute("Burning") == nil then
			Humanoid:SetAttribute("Burning", ElementsModule.FireMagic.StatusEffectLength)
			while Humanoid:GetAttribute("Burning") ~= nil and Humanoid:GetAttribute("Burning") > 0 do
				task.wait(1)
				Humanoid:SetAttribute("Burning", Humanoid:GetAttribute("Burning") - 1)
				Humanoid:SetAttribute("Temperature", Humanoid:GetAttribute("Temperature") + 1)
				Humanoid:TakeDamage(AttackDamage)
				if Humanoid:GetAttribute("Burning") == 0 then
					Humanoid:SetAttribute("Burning", nil)
				end
			end
		elseif Humanoid:GetAttribute("Burning") ~= nil then
			Humanoid:SetAttribute("Burning", ElementsModule.FireMagic.StatusEffectLength)
		end
	end,

I think that without ApplyStaticEffects the code runs fast enough that all the parts are marked hit before Touched fires again. With ApplyStaticEffects the function delays enough that some parts aren’t being marked hit before the next Touched event fires.

I think you could run the PartsHitByAttack loop twice. First, check whether each character was already hit or remember the Humanoid for further processing. The check will then run quickly and not be affected by how long the effects code takes.

	local AlreadyHit = {}
	Hitbox.Touched:Connect(function()
		local HumanoidsHit = {}
		local PartsHitByAttack = workspace:GetPartsInPart(Hitbox)
		for i, Part:Part in pairs(PartsHitByAttack) do
			local TargetCharacter = Part.Parent
			if not table.find(AlreadyHit, TargetCharacter) and TargetCharacter ~= nil and TargetCharacter:FindFirstChildOfClass("Humanoid") and TargetCharacter ~= Attacker then
				print("does this part loop?")
				local TargetHumanoid:Humanoid = TargetCharacter:FindFirstChildOfClass("Humanoid")
				table.insert(AlreadyHit, TargetCharacter)
				local AlreadyHitClearer = coroutine.wrap(function()
					task.wait(3)
					table.remove(AlreadyHit, table.find(AlreadyHit, TargetCharacter))
					print("Cleared")
				end)
				AlreadyHitClearer()
				table.insert(HumanoidsHit,TargetHumanoid)
			end
		end
		for i, TargetHumanoid in pairs(HumanoidsHit) do
			-- Status Effects Code
		end
	end
local debounce = false
Hitbox.Touched:Connect(function(hit)
    if debounce then return end
    if hit.Parent:FindFirstChild("Humanoid") then
        debounce = true
    --    
    -- Your code
    --
    end
    task.wait(1)
    debounce = false
end)

It’s hitting your foot, leg, exc … 16 times. Time for a debounce.

There is a debounce it is under the table AlreadyHit, which is a local table in the function which is why it is being called 16 times. It needs to be a declared at the top of the script. Other than that AlreadyHit is just constantly a blank table.

Ugg, it’s never easy is it…

Try this
BaseMechanics.InflictDamage = function(Hitbox:Part, Attacker:Model, Damage, Knockback, PostureDamage, Blockable, Dodgeable, Parryable, StatusEffects)
	local AlreadyHit = {}
	Hitbox.Touched:Connect(function()
		local PartsHitByAttack = workspace:GetPartsInPart(Hitbox)
		for i, Part:Part in pairs(PartsHitByAttack) do
			local TargetCharacter = Part.Parent
			if not table.find(AlreadyHit, TargetCharacter) and TargetCharacter ~= nil and TargetCharacter:FindFirstChildOfClass("Humanoid") and TargetCharacter ~= Attacker then
				local TargetHumanoid:Humanoid = TargetCharacter:FindFirstChildOfClass("Humanoid")
				table.insert(AlreadyHit, TargetCharacter)
				local AlreadyHitClearer = coroutine.wrap(function()
					task.wait(3)
					table.remove(AlreadyHit, table.find(AlreadyHit, TargetCharacter))
				end)
				AlreadyHitClearer()

				local ApplyStatusEffects = function()
					for i, Effect in pairs(StatusEffects) do
						Effect(TargetCharacter, Damage)
					end
				end

				if Knockback ~= nil or Knockback > 0 then
					TargetHumanoid:ChangeState(Enum.HumanoidStateType.Ragdoll, true)
					local KnockbackVelocity = Instance.new("LinearVelocity")
					KnockbackVelocity.Enabled = true
					KnockbackVelocity.MaxForce = 10000000
					KnockbackVelocity.Attachment0 = TargetCharacter:FindFirstChild("HumanoidRootPart"):FindFirstChild("RootAttachment")
					KnockbackVelocity.VectorVelocity = Attacker.PrimaryPart.CFrame.LookVector * Knockback
					KnockbackVelocity.Parent = TargetCharacter.PrimaryPart
					DebrisService:AddItem(KnockbackVelocity, .3)
				end

				if Blockable then
					if TargetHumanoid:GetAttribute("IsBlocking") then
						local CurrentPosture = TargetHumanoid:GetAttribute("Posture")
						TargetHumanoid:SetAttribute("Posture", CurrentPosture + PostureDamage)
						if TargetHumanoid:GetAttribute("Posture") >= TargetHumanoid:GetAttribute("MaxPosture") then
							PostureBroken(TargetHumanoid)
							TargetHumanoid:TakeDamage(Damage)
							ApplyStatusEffects()
						end
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				elseif Dodgeable then
					if TargetHumanoid:GetAttribute("IsDodging") then
						print("Attack Dodged")
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				elseif Parryable then
					if TargetHumanoid:GetAttribute("IsParrying") then
						local CurrentPosture = TargetHumanoid:GetAttribute("Posture")
						TargetHumanoid:SetAttribute("Posture", CurrentPosture - 10)
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				elseif TargetHumanoid:GetAttribute("Evasions") > 0 or TargetHumanoid:GetAttribute("Evasions") == 0 then
					if TargetHumanoid:GetAttribute("Evasions") > 0 then
						TargetHumanoid:SetAttribute("Evasions", TargetHumanoid:GetAttribute("Evasions") - 1)
						HitStun(TargetHumanoid)
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				end
			end
		end
	end)
end
1 Like

It might be as simple as this

local AlreadyHit = {}
BaseMechanics.InflictDamage = function(Hitbox:Part, Attacker:Model, Damage, Knockback, PostureDamage, Blockable, Dodgeable, Parryable, StatusEffects)
	
	Hitbox.Touched:Connect(function()
		local PartsHitByAttack = workspace:GetPartsInPart(Hitbox)
		for i, Part:Part in pairs(PartsHitByAttack) do
			local TargetCharacter = Part.Parent
			if not table.find(AlreadyHit, TargetCharacter) and TargetCharacter ~= nil and TargetCharacter:FindFirstChildOfClass("Humanoid") and TargetCharacter ~= Attacker then
				local TargetHumanoid:Humanoid = TargetCharacter:FindFirstChildOfClass("Humanoid")
				table.insert(AlreadyHit, TargetCharacter)
				local AlreadyHitClearer = coroutine.wrap(function()
					task.wait(3)
					table.remove(AlreadyHit, table.find(AlreadyHit, TargetCharacter))
				end)
				AlreadyHitClearer()

				local ApplyStatusEffects = function()
					for i, Effect in pairs(StatusEffects) do
						Effect(TargetCharacter, Damage)
					end
				end

				if Knockback ~= nil or Knockback > 0 then
					TargetHumanoid:ChangeState(Enum.HumanoidStateType.Ragdoll, true)
					local KnockbackVelocity = Instance.new("LinearVelocity")
					KnockbackVelocity.Enabled = true
					KnockbackVelocity.MaxForce = 10000000
					KnockbackVelocity.Attachment0 = TargetCharacter:FindFirstChild("HumanoidRootPart"):FindFirstChild("RootAttachment")
					KnockbackVelocity.VectorVelocity = Attacker.PrimaryPart.CFrame.LookVector * Knockback
					KnockbackVelocity.Parent = TargetCharacter.PrimaryPart
					DebrisService:AddItem(KnockbackVelocity, .3)
				end

				if Blockable then
					if TargetHumanoid:GetAttribute("IsBlocking") then
						local CurrentPosture = TargetHumanoid:GetAttribute("Posture")
						TargetHumanoid:SetAttribute("Posture", CurrentPosture + PostureDamage)
						if TargetHumanoid:GetAttribute("Posture") >= TargetHumanoid:GetAttribute("MaxPosture") then
							PostureBroken(TargetHumanoid)
							TargetHumanoid:TakeDamage(Damage)
							ApplyStatusEffects()
						end
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				elseif Dodgeable then
					if TargetHumanoid:GetAttribute("IsDodging") then
						print("Attack Dodged")
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				elseif Parryable then
					if TargetHumanoid:GetAttribute("IsParrying") then
						local CurrentPosture = TargetHumanoid:GetAttribute("Posture")
						TargetHumanoid:SetAttribute("Posture", CurrentPosture - 10)
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				elseif TargetHumanoid:GetAttribute("Evasions") > 0 or TargetHumanoid:GetAttribute("Evasions") == 0 then
					if TargetHumanoid:GetAttribute("Evasions") > 0 then
						TargetHumanoid:SetAttribute("Evasions", TargetHumanoid:GetAttribute("Evasions") - 1)
						HitStun(TargetHumanoid)
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				end
			end
		end
	end)
end```

I like it…

optimized
local AlreadyHit = {}
BaseMechanics.InflictDamage = function(Hitbox:Part, Attacker:Model, Damage, Knockback, PostureDamage, Blockable, Dodgeable, Parryable, StatusEffects)
	Hitbox.Touched:Connect(function()
		local PartsHitByAttack = workspace:GetPartsInPart(Hitbox)
		for _, Part:Part in pairs(PartsHitByAttack) do
			local TargetCharacter = Part.Parent
			if TargetCharacter and TargetCharacter:FindFirstChildOfClass("Humanoid") and TargetCharacter ~= Attacker and not table.find(AlreadyHit, TargetCharacter) then
				local TargetHumanoid = TargetCharacter:FindFirstChildOfClass("Humanoid")
				table.insert(AlreadyHit, TargetCharacter)
				
				local ClearHitCooldown = coroutine.wrap(function()
					task.wait(3)
					table.remove(AlreadyHit, table.find(AlreadyHit, TargetCharacter))
				end)
				ClearHitCooldown()

				local ApplyStatusEffects = function()
					for _, Effect in pairs(StatusEffects) do
						Effect(TargetCharacter, Damage)
					end
				end

				if Knockback > 0 then
					TargetHumanoid:ChangeState(Enum.HumanoidStateType.Ragdoll, true)
					local KnockbackVelocity = Instance.new("LinearVelocity")
					KnockbackVelocity.Enabled = true
					KnockbackVelocity.MaxForce = 10000000
					KnockbackVelocity.Attachment0 = TargetCharacter:FindFirstChild("HumanoidRootPart"):FindFirstChild("RootAttachment")
					KnockbackVelocity.VectorVelocity = Attacker.PrimaryPart.CFrame.LookVector * Knockback
					KnockbackVelocity.Parent = TargetCharacter.PrimaryPart
					DebrisService:AddItem(KnockbackVelocity, .3)
				end

				if Blockable then
					if TargetHumanoid:GetAttribute("IsBlocking") then
						local CurrentPosture = TargetHumanoid:GetAttribute("Posture")
						TargetHumanoid:SetAttribute("Posture", CurrentPosture + PostureDamage)
						if TargetHumanoid:GetAttribute("Posture") >= TargetHumanoid:GetAttribute("MaxPosture") then
							PostureBroken(TargetHumanoid)
							TargetHumanoid:TakeDamage(Damage)
							ApplyStatusEffects()
						end
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				elseif Dodgeable then
					if TargetHumanoid:GetAttribute("IsDodging") then
						print("Attack Dodged")
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				elseif Parryable then
					if TargetHumanoid:GetAttribute("IsParrying") then
						local CurrentPosture = TargetHumanoid:GetAttribute("Posture")
						TargetHumanoid:SetAttribute("Posture", CurrentPosture - 10)
					else
						TargetHumanoid:TakeDamage(Damage)
						HitStun(TargetHumanoid)
						ApplyStatusEffects()
					end
				elseif TargetHumanoid:GetAttribute("Evasions") > 0 then
					TargetHumanoid:SetAttribute("Evasions", TargetHumanoid:GetAttribute("Evasions") - 1)
					HitStun(TargetHumanoid)
				else
					TargetHumanoid:TakeDamage(Damage)
					HitStun(TargetHumanoid)
					ApplyStatusEffects()
				end
			end
		end
	end)
end