Logic problem in my script, but I don't know what

Hello everyone! I’ve run into yet another problem with this combat script that I need to go back to you all for.

I’ll let this video speak for itself.


You can see what happens here is I swing 5 times then hit the NPC once, and it seems to stack up the hits even when I miss them before actually landing a hit on anything. This makes no sense to me, because in the Attack() function which controls dealing damage and stunning the enemy, damage will only be dealt if the hitbox detects something inside of it, as well as blacklisting that enemy from being hit multiple times in the same swing.

What really puzzles me is that this only happened after I implemented the “Combo Reset” system. It could’ve been something to do with me tidying up my code and accidentally creating a logic error when I did, but I went and ported the new features I have in the script now back to my old iteration, and the same issues persisted.

Anyway, here’s the code.

-- // Variables
local tool = script.Parent
local anims = script.Parent.Animations
local ws = game:GetService("Workspace")
local box = tool.box
local box2 = tool.box2
local oparams = OverlapParams.new()
oparams.FilterType = Enum.RaycastFilterType.Exclude
oparams.MaxParts = math.huge
local effect = script.Parent.Handle.Blood
local btrail = script.Parent.Handle.BloodTrail

-- // Controls
local equip
local slash
local idle
local db = false
local canHit = false
local hitboxed = false
local randomSlash = 1
local boxc
local value
local slashval = tool.Slash
local dewit = true
local resetthread = nil
local didHit = false -- messy variable

-- // Animation Startup
script.Parent.Equipped:Connect(function()
	tool.Handle.Equip:Play()
	local humanoid = script.Parent.Parent:FindFirstChild("Humanoid")
	if not equip then equip = humanoid:LoadAnimation(anims.Equip) end
	equip:Play()
	if not idle then idle = humanoid:LoadAnimation(anims.Idle) end
	idle.Priority = Enum.AnimationPriority.Movement
	idle:Play()
end)

-- // Animation Shutdown
script.Parent.Unequipped:Connect(function()
	if idle then idle:Stop() end
	if equip then equip:Stop()
		if slash then slash:Stop() end
	end
end)

-- // Light Attack Reset CD
local animCD = function()
	print("combo cd has begun")
	task.wait(2)
		randomSlash = 1
		slashval.Value = randomSlash
		print("combo has been reset")
end

--// Prevent Combo Reset
slashval.Changed:Connect(function()
	if resetthread == nil then print("combo reset perceived nil") return end
	coroutine.yield(resetthread)
	coroutine.close(resetthread)
	print("combo reset cancelled")
end)

-- // Light Attacks
script.Parent.Activated:Connect(function()

	local char = tool.Parent
	local root = char:WaitForChild("HumanoidRootPart")
	local hum = char:WaitForChild("Humanoid")

	if char.Stunned.Value or char.Dashing.Value or db then return end
		db = true
	
		local function Attack()
			if canHit or not db or hitboxed then return end
					canHit = true
					hitboxed = true
		
					local doKnockback = false
					
					if randomSlash == 1 or randomSlash == 2 or randomSlash == 5 then
						boxc = box:Clone()
						value = -3
					elseif randomSlash == 3 or randomSlash == 4 then
						boxc = box2:Clone()
						value = -5
					end
		
					if didHit == false then didHit = true end

					oparams.FilterDescendantsInstances = {char}

					local humanoidsDamaged = {}
					
					tool.ClickEvent.OnServerEvent:Connect(function(plr, cf)					
						boxc.Parent = ws.Scripted
						boxc.CFrame = cf * CFrame.new(0,0,value)
						game:GetService("Debris"):AddItem(boxc,0.3)
						
						local hits = ws:GetPartsInPart(boxc,oparams)

						for i = 1, #hits do

							if hits[i].Parent ~= char and hits[i].Parent:FindFirstChild("Humanoid") and hits[i].Parent:FindFirstChild("Dashing") and char.Stunned.Value == false then
								if hits[i].Parent.Dashing.Value == false and not table.find(humanoidsDamaged, hits[i].Parent.Parent) then
									table.insert(humanoidsDamaged, hits[i].Parent.Parent)
									local hitSFX = Instance.new("Sound",hits[i].Parent.Head)
									hitSFX.SoundId = "rbxassetid://566593606"; hitSFX:Play()
											hits[i].Parent.Humanoid:TakeDamage(5)
											hits[i].Parent:FindFirstChild("Hitstun"):Fire()
											
											if randomSlash == 1 and didHit == true then
												local delta = hits[i].Parent:FindFirstChild("HumanoidRootPart").Position - root.Position
												local bv = Instance.new("BodyVelocity")
												bv.maxForce = Vector3.new(1e9, 1e9, 1e9)
												bv.velocity = delta.unit * 128
												bv.Parent = hits[i].Parent:FindFirstChild("HumanoidRootPart")
												game:GetService("Debris"):AddItem(bv, 0.01)
											end

									effect.Enabled = true
									btrail.Enabled = true

									local slashfx = tool.Effects.Slash.Attachment:Clone()
									slashfx.Parent = hits[i].Parent:FindFirstChild("HumanoidRootPart")
									local r = math.random(-360,360)
									slashfx.slash.Rotation = NumberRange.new(r)
									task.delay(0.3,function()
										slashfx:Destroy()
									end)

								end
								task.delay(0.2,function()
									effect.Enabled = false
									btrail.Enabled = false
								end)
							end
							
						end
					end)
					task.delay(0.3,function()
						canHit = false
						hitboxed = false
					end)
		end
		
		Attack()
		
		if not slash then
			slash = hum:LoadAnimation(anims["Attack".. randomSlash])

			if randomSlash == 5 then
				randomSlash = 1
				slashval.Value = randomSlash
				print("randomslash set to "..randomSlash)
			else
				randomSlash += 1
				slashval.Value = randomSlash
				print("randomslash set to "..randomSlash)
			end
		end

		local val = tool.Parent.Attacking
		val.Value = true
		
		slash:Play()
		
		script.Parent.Handle.Trail.Enabled = true
		task.wait(.15)
		tool.Handle.Slash:Play()
		
		if randomSlash == 5 or randomSlash == 4 then
			tool.Handle.Chain:Play()
		end
		task.wait(.15)
		hitboxed = false
	
		if slash then
			slash = nil
		end
	
		script.Parent.Handle.Trail.Enabled = false
		resetthread = coroutine.create(animCD)
		coroutine.resume(resetthread)
		print("combo reset coroutine created")
	
		if randomSlash == 1 then
			task.wait(2)
			db = false
		else
			db = false
		end
	
		task.delay(.15,function()
			val.Value = false
		end)
end)

Any help is appreciated, thank you.

P.S: Any clarification you need as to what certain variables or things are, just let me know and I’ll explain.

3 Likes

Try disconnecting this after a little amount of time.

I’ve had this problem before.

My recommendation is to disconnect or return the function when it doesn’t detect a HumanoidRootPart.