Issue With Attacking NPC Damaging System

Hey everyone!
I’ve been working on an NPC attacking system similar to those in simulator games. You will automatically walk toward them and start attacking them by clicking your mouse on any NPC. I’ve found a bug that lets the player multiply their damage by interrupting the MoveTo() and clicking the NPC again. For example, if the player walks out of the MoveTo() and clicks the NPC and repeats that 3 times, they will do 10 x 3 damage which is 30.

Here is a clip of the bug happening:

The script that calls the function:

    local Attacking = Instance.new("ObjectValue")
	Attacking.Name = "Attacking"
	Attacking.Parent = Player.Character
	local Mouse = Player:GetMouse()
	UserInputService.InputBegan:Connect(function(Input, GameProcessed)
		if GameProcessed then return end
		if Input.UserInputType == Enum.UserInputType.MouseButton1 then
			if Mouse.Target and Mouse.Target.Parent.Parent == workspace.NPCs and Attacking.Value ~= Mouse.Target.Parent then
				AttackNPC(Mouse.Target.Parent, Player)
			end
		end
	end)

The function:

function AttackNPC(NPC, Player)
	local Character = Player.Character
	local Humanoid = Character.Humanoid
	Humanoid:MoveTo(NPC.PrimaryPart.Position + NPC.PrimaryPart.CFrame.LookVector * 3)
	Character.Attacking.Value = NPC
	local Connection
	Connection = Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
		Character.Attacking.Value = nil
		Connection:Disconnect()
		return
	end)
	Humanoid.MoveToFinished:Wait()
	while Character.Attacking.Value == NPC and NPC.Humanoid.Health > 0 do
		local AttackAnimations = {
			"rbxassetid://9972570264",
			"rbxassetid://9972635563",
		}
		local RandomAnimation = AttackAnimations[math.random(1, table.getn(AttackAnimations))]
		local Animation = Instance.new("Animation")
		Animation.AnimationId = RandomAnimation
		local Loaded = Humanoid.Animator:LoadAnimation(Animation)
		Loaded.Priority = Enum.AnimationPriority.Action
		Loaded:Play()
		task.wait(.3)
		NPC.Humanoid:TakeDamage(10)
		task.wait(.3)
	end
end

If anybody could help, that would be greatly appreciated. Thanks!

2 Likes

I’d start by checking whether or not a user is already attacking an NPC before letting AttackNPC run, whenever AttackNPC is called, set a boolean to true and don’t set it to false until the connection disconnects.

As an example:

local attackingNPC = false

function AttackNPC(NPC, Player)
 if not attackingNPC then
  attackingNPC = true

  connection = Humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
   attackingNPC = false
  end)
 end
end
1 Like

Hm. Wouldn’t that not allow the player to attack another NPC while they are already attacking one? What my system should do is let the player attack another NPC while they are already attacking one and cancel their attack if they want.

1 Like

You can just incorporate a method of cancelling then, right now I’m pretty sure your issue is multiple cases of AttackNPC running at the same time.

You can store connections in a table and disconnect all of them once a player clicks a separate NPC to attack.

2 Likes

I’ve went ahead and written up an un-tested example so you can hopefully understand what I mean.

local connections = {}
local currentNPC = nil
local isAttacking = false


local function cleanupConnections()
	for _, connection in ipairs (connections) do
		if connection.Connected then
			connection:Disconnect()
		end
	end
end

local function attackNPC(npc, player)
	--If they're not attacking or the NPC they want to attack is different than the one they're attacking
	if not isAttacking or npc ~= currentNPC then
		
		--Set attacking to true so we don't run this more than once
		isAttacking = true
		
		--Cleanup our old connections in case there's some lingering
		cleanupConnections()
		
		local character = player.Character
		local humanoid = character.Humanoid
		
		
		
		humanoid:MoveTo(npc.PrimaryPart.Position + npc.PrimaryPart.CFrame.LookVector * 3)
		character.Attacking.Value = npc
		
		--Insert our move direction connection into our connection table
		table.insert(connections, humanoid:GetPropertyChangedSignal("MoveDirection"):Connect(function()
			character.Attacking.Value = nil
			isAttacking = false
			--Cleanup the connections in case the user exits this way
			cleanupConnections()
			return
		end))
		
		humanoid.MoveToFinished:Wait()
		
		while character.Attacking.Value == npc and npc.Humanoid.Health > 0 do
			local AttackAnimations = {
				"rbxassetid://9972570264",
				"rbxassetid://9972635563",
			}
			local RandomAnimation = AttackAnimations[math.random(1, table.getn(AttackAnimations))]
			local Animation = Instance.new("Animation")
			Animation.AnimationId = RandomAnimation
			local Loaded = humanoid.Animator:LoadAnimation(Animation)
			Loaded.Priority = Enum.AnimationPriority.Action
			Loaded:Play()
			task.wait(.3)
			npc.Humanoid:TakeDamage(10)
			task.wait(.3)
		end
		
		
	end
end

local function onPress(inputObject, gameProcessed)
	if inputObject.UserInputType == Enum.UserInputType.MouseButton1 then
		local npc = mouse.Target.Parent
		if npc then
			attackNPC(npc, player)
		end
	end
end
2 Likes

Thanks! This should help with the error! :smile:

1 Like