Shooting NPCs behaving strangely

Hello guys!
Im making a script which makes armed NPCs follow and shoot, however when i join and enable the script im getting almost insta-killed, npc doesnt walk as intended and npc doesnt seem like to reload.
Can you guys help me?

local CS = game:GetService("CollectionService")
local RS = game:GetService("RunService")
local MINIMAL_DISTANCE = 2.5

local function gettrack(hum, animid)
	local asset = 'rbxassetid://'..animid
	local animation = Instance.new("Animation")
	animation.AnimationId = asset
	local track = hum:WaitForChild("Animator"):LoadAnimation(animation)
	return track
end

local function FindNearestPlayer(position)
	local found
	local last = math.huge
	for _,player in pairs(game.Players:GetPlayers()) do
		local distance = player:DistanceFromCharacter(position)
		if distance < last then
			found = player
			last = distance
		end
	end
	return found
end

local PFS = game:GetService("PathfindingService")
local function getPath(OriginalPosition ,destination)
	local path = PFS:CreatePath()
	path:ComputeAsync(OriginalPosition, destination)
	return path
end

local function ProceedTo(Hum, Path)
	local walkto = getPath(Hum.Parent:WaitForChild("HumanoidRootPart").Position, Path)
	local HumRoot = Hum.Parent:WaitForChild("HumanoidRootPart")
	local plr = FindNearestPlayer(HumRoot.Position)
	local dist = (plr.Character:WaitForChild("HumanoidRootPart").Position - HumRoot.Position).Magnitude
	for _, waypoint in pairs(walkto:GetWaypoints()) do
		if dist <= MINIMAL_DISTANCE then
			break
		else
			Hum:MoveTo(waypoint.Position)
			Hum.MoveToFinished:Wait()
		end
	end
end
local DesiredParts = {
	'Head';
	'LeftFoot';
	'LeftHand';
	'LeftLowerArm';
	'LeftLowerLeg';
	'LeftUpperArm';
	'LeftUpperLeg';
	'LowerTorso';
	'RightFoot';
	'RightHand';
	'RightLowerArm';
	'RightUpperLeg';
	'RightLowerLeg';
	'RightUpperArm';
	'UpperTorso';
	'HumanoidRootPart';
	'Main';
	'Mag';
	'Charging Handle';
	'Carry Handle'
}
local function ScanForAPlayer(Hum, Plr)
	if Hum:GetAttribute("ReadyToShoot") == false then
		local RCParams = RaycastParams.new()
		RCParams.FilterType = Enum.RaycastFilterType.Exclude
		local HUMTABLE = {}
		for i, v in pairs(Hum.Parent:GetChildren()) do
			if v:IsA("MeshPart") or v:IsA("Part") then
				table.insert(HUMTABLE, v)
			end
		end
		RCParams.FilterDescendantsInstances = HUMTABLE
		if Plr.Character then
			local targetchar = Plr.Character
			local Direction = (targetchar:WaitForChild("HumanoidRootPart").Position - Hum.Parent:WaitForChild("Main").Position)
			local RCResult = workspace:Raycast(Hum.Parent:WaitForChild("Main").Position, Direction, RCParams)
			if RCResult then
				if table.find(DesiredParts, RCResult.Instance.Name) and RCResult.Instance.Parent == Plr.Character then
					Hum:SetAttribute("ReadyToShoot", true)
					return RCResult
				end
			end
		end
	end
end
local function ScanForAPlayerNONSTRICT(Hum, Plr)
	local RCParams = RaycastParams.new()
	RCParams.FilterType = Enum.RaycastFilterType.Exclude
	local HUMTABLE = {}
	for i, v in pairs(Hum.Parent:GetChildren()) do
		if v:IsA("MeshPart") or v:IsA("Part") then
			table.insert(HUMTABLE, v)
		end
	end
	RCParams.FilterDescendantsInstances = HUMTABLE
	if Plr.Character then
		local targetchar = Plr.Character
		local Direction = (targetchar:WaitForChild("HumanoidRootPart").Position - Hum.Parent:WaitForChild("Main").Position)
		local RCResult = workspace:Raycast(Hum.Parent:WaitForChild("Main").Position, Direction, RCParams)
		if RCResult then
			if table.find(DesiredParts, RCResult.Instance.Name) and RCResult.Instance.Parent == Plr.Character then
				Hum:SetAttribute("ReadyToShoot", true)
				return RCResult
			else
				Hum:SetAttribute("ReadyToShoot", false)
			end
		end
	end
end
local ShootSound = script.Shoot
-- PREPARING --

for _, Humanoid in pairs(CS:GetTagged("AttackingM4A1NPC")) do
	Humanoid:SetAttribute("MaxAmmo", 30)
	Humanoid:SetAttribute("CurrentAmmo", 30)
	Humanoid:SetAttribute("ReadyToShoot", false)
	Humanoid:SetAttribute("OnReload", false)
end
for _, Humanoid in pairs(CS:GetTagged("AttackingM4A1NPC")) do
	local IdleTrack = gettrack(Humanoid, 17610353949)
	local WalkTrack = gettrack(Humanoid, 17610788856)
	local ShootTrack = gettrack(Humanoid, 17610777560)
	local ReloadTrack = gettrack(Humanoid, 17610939799)
	local MaxAmmo = Humanoid:GetAttribute("MaxAmmo")
	local CurrentAmmo = Humanoid:GetAttribute("CurrentAmmo")
	IdleTrack:Play()
	Humanoid.Running:Connect(function(speed)
		if speed > 0 then
			IdleTrack:Stop()
			WalkTrack:Play()
		else
			IdleTrack:Play()
			WalkTrack:Stop()
		end
	end)
	RS.Heartbeat:Connect(function()
		local targetplayer = FindNearestPlayer(Humanoid.Parent:WaitForChild("HumanoidRootPart").Position)
		if Humanoid.Health > 0 then
			if Humanoid:GetAttribute("CurrentAmmo") <= 0 then
				Humanoid:SetAttribute("OnReload", true)
				ReloadTrack:Play()
				task.delay(ReloadTrack.Length, function()
					Humanoid:SetAttribute("CurrentAmmo", Humanoid:GetAttribute("MaxAmmo"))
					Humanoid:SetAttribute("OnReload", false)
				end)
			end
			ProceedTo(Humanoid, targetplayer.Character:WaitForChild("HumanoidRootPart").Position)
			if ScanForAPlayerNONSTRICT(Humanoid, targetplayer) and Humanoid:GetAttribute("ReadyToShoot") == true then
				task.delay(0.3, function()
					while ScanForAPlayerNONSTRICT(Humanoid, FindNearestPlayer(Humanoid.Parent:WaitForChild("HumanoidRootPart").Position)) ~= nil do
						if Humanoid:GetAttribute("CurrentAmmo") <= 0 then
							Humanoid:SetAttribute("OnReload", true)
							ReloadTrack:Play()
							task.delay(ReloadTrack.Length, function()
								Humanoid:SetAttribute("CurrentAmmo", Humanoid:GetAttribute("MaxAmmo"))
								Humanoid:SetAttribute("OnReload", false)
							end)
						end
						wait(0.1)
						if Humanoid:GetAttribute("CurrentAmmo") <= 0 then
							Humanoid:SetAttribute("OnReload", true)
							ReloadTrack:Play()
							task.delay(ReloadTrack.Length, function()
								Humanoid:SetAttribute("CurrentAmmo", Humanoid:GetAttribute("MaxAmmo"))
								Humanoid:SetAttribute("OnReload", false)
							end)
						end
						local targ = FindNearestPlayer(Humanoid.Parent:WaitForChild("HumanoidRootPart").Position)
						local neededchar = targ.Character
						local HUMTABLEE = {}
						for i, v in pairs(Humanoid.Parent:GetChildren()) do
							if v:IsA("MeshPart") or v:IsA("Part") then
								table.insert(HUMTABLEE, v)
							end
						end
						local RCParameters = RaycastParams.new()
						RCParameters.FilterType = Enum.RaycastFilterType.Exclude
						RCParameters.FilterDescendantsInstances = HUMTABLEE
						local Direct = (neededchar:WaitForChild("HumanoidRootPart").Position - Humanoid.Parent:WaitForChild("Main").Position)
						local Raycastresult = workspace:Raycast(Humanoid.Parent:WaitForChild("Main").Position, Direct, RCParameters)
						if Raycastresult and Raycastresult.Instance then
							local hittarget = Raycastresult.Instance
							if table.find(DesiredParts, Raycastresult.Instance.Name) then
								if hittarget.Parent:WaitForChild("Humanoid") then
									local ShootClone = ShootSound:Clone()
									ShootClone.Parent = Humanoid.Parent:WaitForChild("Main")
									ShootClone:Play()
									task.delay(ShootClone.TimeLength, function()
										ShootClone:Destroy()
									end)
									ShootTrack:Play()
									hittarget.Parent:WaitForChild("Humanoid"):TakeDamage(5)
								end
							end
						else
							Humanoid:SetAttribute("ReadyToShoot", false)
							break
						end
					end
				end)
			end
		end
	end)
end

You only seem to exit your loop when the NPC raycast misses - I believe that would be the reason why you die almost instantly?

i dont think so, part of the script which shoots the player is coming only after raycast hit the player

Multiple things going on with this script:

  • You have the scanning on a HeartBeat:Connect function - Why? This means that your scanning is happening every frame - the NPC is thus registering and shooting on a per frame basis.
  • Your loop is confusing and repetitive. You call the same function both before and during a loop.

All I can suggest for now is changing the Heartbeat function to one that fires synchronously - while task.wait() perhaps.

i tried using it, however i got the same result, one thing i noticed that attributes i set doesnt work as intended. It just doesnt change the value.

ill try using values instead of attributes, ill see if it works.
P.S. found out that didnt count a shot value

There’s a problem with loops in collection service - they work with only one object until loop ends, i’ll just gonna modify my old script. Thanks for helping.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.