Make Tank AI not kill players

This tank AI attacks NPCS but also attacks players. How do I add players onto the ally list on this tank AI?

local clone = script.Parent:Clone()

--Latency Fix
for i,v in ipairs(script.Parent:GetDescendants()) do
	if v:IsA("BasePart") then
		if v:CanSetNetworkOwnership() == true then
			v:SetNetworkOwner(nil)
		end
	end
end


--Main body
local myHuman = script.Parent.Humanoid
local myHead = script.Parent.Head
local myTorso = script.Parent.Torso
local engine = script.Parent.Engine
local bodyBG = myTorso.BodyGyro
local status = script.Parent.Status
local bodyColor = script.Parent.TankColor

--Gun parts
local gunBackMain = script.Parent.GunBackMain
local gunBase = script.Parent.GunBase
local gunBG = gunBackMain.BodyGyro
local barrel = script.Parent.Barrel
local gunTip = script.Parent.GunBarrelTip
local gunBarrelTube = script.Parent.GunBarrelTube
local gunBarrelTube2 = script.Parent.GunBarrelTube2
local barrelWeld = script.Parent.BarrelWeld
local smokeSpot = barrel.SmokeSpot
local flash = barrel.Flash
local barrelSmoke = smokeSpot.Smoke

local allies = {script.Parent.Name, "Davarian Marine"}

--Sounds
local shootSound = barrel.Shoot
local engineSound = engine:WaitForChild("EngineNoise")
local explosionSound = engine:WaitForChild("Explosion")

local sight = 200
local detection = 3000
local failedPaths = 0

local touchedEvents = {}
local pathArgs = {
	["AgentRadius"] = 16,
	["AgentHeight"] = 13,
	["AgentCanJump"] = false	
}

local gunCool = true
local pathBlocked = false

--Inital Adjustments
engineSound:Play()
bodyBG.CFrame = myTorso.CFrame
gunBG.CFrame = gunBackMain.CFrame
barrelSmoke.Parent = nil

--Engine pitch adjuster
spawn(function()
	repeat 
		wait(0.1)
		if myTorso.Velocity.Magnitude > 5 or myTorso.RotVelocity.Magnitude > 0.1 then
			game:GetService("TweenService"):Create(engineSound,TweenInfo.new(0.2),{PlaybackSpeed = 0.35}):Play()
		else
			game:GetService("TweenService"):Create(engineSound,TweenInfo.new(0.2),{PlaybackSpeed = 0.3}):Play()
		end
	until myHuman.Health < 1 
end)

--Set team color
for i,v in ipairs(script.Parent:GetDescendants()) do
	if v:IsA("BasePart") and v.Name ~= "Headlight" and v.Name ~= "Status" then
		v.BrickColor = bodyColor.Value
	end
end

function checkDist(part1,part2)
	return (part1.Position - part2.Position).Magnitude
end

function checkForObstacles(direction)
	for i = -13, 13, 0.5 do
		local ray
		if direction == "front" then
			ray = Ray.new((myTorso.CFrame * CFrame.new(i,1,-16)).Position, myTorso.CFrame.LookVector * 5)
		elseif direction == "back" then
			ray = Ray.new((myTorso.CFrame * CFrame.new(i,0,13)).Position, -myTorso.CFrame.LookVector * 5)
		elseif direction == "right" then
			ray = Ray.new((myTorso.CFrame * CFrame.new(13,-0.5,i)).Position, myTorso.CFrame.RightVector * 5)
		elseif direction == "left" then
			ray = Ray.new((myTorso.CFrame * CFrame.new(-13,-0.5,i)).Position, -myTorso.CFrame.RightVector * 5)
		else
			print("Invalid direction suppled")
			ray = Ray.new(Vector3.new(0,0,0),Vector3.new(0,0,0))
		end
		local hit,pos = workspace:FindPartOnRayWithIgnoreList(ray,{script.Parent})
		if hit then
			if hit:IsGrounded() or hit.Anchored then
				return true
			end
		end
	end
	return false
end

--Collision detection logic
for _,v in ipairs(script.Parent:GetDescendants()) do
	if v:IsA("BasePart") and v.Name ~= "Wheel" and v.Name ~= "Wheel Lip" then
		local db = true
		local touch = v.Touched:Connect(function(obj)
			if db == true then
				db = false
				if obj.Parent and not obj:IsDescendantOf(script.Parent) then	
					local human = obj.Parent:FindFirstChild("Humanoid")	
					if not human and obj.Position.Y >= myTorso.Position.Y - 0.5 then
						--Break small objects that are in the way
						if obj:IsGrounded() and obj:GetMass() < 100 and not obj.Anchored then
							obj:BreakJoints()
						elseif obj:IsGrounded() or obj.Anchored then 
							if checkForObstacles("front") then
								backaway(obj)
							end
						end
					elseif human then
						if human.Health > 0 then
							for i,x in ipairs(allies) do
								if obj.Parent.Name == x then
									if checkForObstacles("front") then
										backaway(obj)
									end
									break
								elseif i == #allies then
									if v.Velocity.Magnitude > 15 then
										human:ChangeState(Enum.HumanoidStateType.Ragdoll)
										human:TakeDamage(math.random(20,30))
									end
								end
							end
						end	
					end
					wait(0.2)
					db = true
				end
			end
		end)
		table.insert(touchedEvents,touch)
	end
end

function changeStatus(color3)
	game:GetService("TweenService"):Create(status,TweenInfo.new(1),{Color = color3}):Play()
end

function backaway(target)
	pathBlocked = true
	changeStatus(Color3.fromRGB(110, 153, 202)) --Medium blue status
	for i = 1, 8 do
		wait(0.1)
		myHuman:Move(-myTorso.CFrame.LookVector)
	end
	myHuman:Move(Vector3.new(0,0,0))
	pathBlocked = false
end

function getUnstuck()
	changeStatus(Color3.fromRGB(255, 102, 204))--Pink status
	if not checkForObstacles("front") then		
		myHuman:Move(myTorso.CFrame.LookVector)
	elseif not checkForObstacles("back") then
		myHuman:Move(-myTorso.CFrame.LookVector)
	elseif not checkForObstacles("right") then
		game:GetService("TweenService"):Create(bodyBG,TweenInfo.new(0.5),{CFrame = myTorso.CFrame * CFrame.Angles(0,math.rad(-90),0)}):Play()
		wait(0.5)
		myHuman:Move(myTorso.CFrame.LookVector)
	elseif not checkForObstacles("left") then
		game:GetService("TweenService"):Create(bodyBG,TweenInfo.new(0.5),{CFrame = myTorso.CFrame * CFrame.Angles(0,math.rad(90),0)}):Play()
		wait(0.5)
		myHuman:Move(myTorso.CFrame.LookVector)
	end
	wait(0.5)
	myHuman:Move(Vector3.new(0,0,0))
end

function checkSight(target)
	local ray = Ray.new(myTorso.Position,(target.Position - myTorso.Position).Unit * sight)
	local hit,position = workspace:FindPartOnRayWithIgnoreList(ray,{script.Parent})
	
	local ray2 = Ray.new(gunBackMain.Position,(target.Position - gunBackMain.Position).Unit * sight)
	local hit2,position2 = workspace:FindPartOnRayWithIgnoreList(ray2,{script.Parent})
	if hit and hit2 then
		if hit:IsDescendantOf(target.Parent) and hit2:IsDescendantOf(target.Parent) then
			return true
		end
	end
	return false
end

function findTarget()
	local dist = detection
	local target = nil
	local potentialTargets = {}
	local seeTargets = {}
	--Find potential targets
	for _,v in ipairs(workspace:GetChildren()) do
		local human = v:FindFirstChild("Humanoid")
		local torso = v:FindFirstChild("HumanoidRootPart") or  v:FindFirstChild("Torso") 
		if human and torso and v ~= script.Parent then
			if (myTorso.Position - torso.Position).magnitude < dist and human.Health > 0 then
				for i,x in ipairs(allies) do
					if x == v.Name then
						break
					elseif i == #allies then
						table.insert(potentialTargets,torso)
					end
				end
			end
		end
	end
	--Check potential targets for targets within sight
	if #potentialTargets > 0 then
		for i,v in ipairs(potentialTargets) do
			if checkSight(v) then
				table.insert(seeTargets,v)
			end
		end
	end
	--If we cant see any targets find a target that we can move to
	if #potentialTargets > 0 and #seeTargets == 0 then
		for i,v in ipairs(potentialTargets) do
			if (myTorso.Position - v.Position).magnitude < dist and math.abs(myTorso.Position.Y - v.Position.Y) < 2 then
				local path = game:GetService("PathfindingService"):CreatePath(pathArgs)
				target = v
				dist = (myTorso.Position - v.Position).magnitude 
			end
		end
	end
	--If we have targets within sight target the cloest one
	if #seeTargets > 0 then
		dist = sight
		for i,v in ipairs(seeTargets) do
			if (myTorso.Position - v.Position).magnitude < dist then
				target = v
				dist = (myTorso.Position - v.Position).magnitude
			end
		end
	end
	return target
end

function rotate(target)
	if checkDist(target,myTorso) > 1.5 then
		local look = Vector3.new(target.Position.X,myTorso.Position.Y,target.Position.Z)
		local lookDiff = (myTorso.CFrame.lookVector - CFrame.new(myTorso.Position,look).lookVector).Magnitude
		game:GetService("TweenService"):Create(bodyBG,TweenInfo.new(lookDiff),{CFrame = CFrame.new(myTorso.Position,look)}):Play()
		wait(lookDiff)
	end
end

function pathToTarget(target)
	pathBlocked = false
	changeStatus(Color3.fromRGB(213, 115, 61)) --Neon orange status
	local path = game:GetService("PathfindingService"):CreatePath(pathArgs)
	path:ComputeAsync(myTorso.Position, target.Position)
	local waypoints = path:GetWaypoints()
	if path.Status == Enum.PathStatus.Success then
		for i,v in ipairs(waypoints) do
			spawn(function() rotate(v) end)
			local timer = 1
			local success = true
			repeat
				wait()
				myHuman:Move(myTorso.CFrame.LookVector)
				timer = timer + 1
				if timer > 40 then
					success = false 
					break
				end
			until checkDist(myTorso,v) < 4 
			if success == false or pathBlocked == true then
				if pathBlocked == true then
					myHuman:Move(Vector3.new(0,0,0))
					wait(2)
				end
				break
			elseif (waypoints[#waypoints].Position - target.Position).magnitude > 20 then
				break
			elseif not target.Parent or target.Parent.Humanoid.Health <= 0 then 
				break
			end
			if i % 5 == 0 then
				if checkSight(target) and checkDist(myTorso,target) < 50 then
					break
				end
			end
		end
		myHuman:Move(Vector3.new(0,0,0))
	else
		failedPaths = failedPaths + 1
		if failedPaths > 10 then
			getUnstuck()
		end
	end
end

function shoot(target)
	if gunCool then
		shootSound:Play()
		local missile = Instance.new("Part")
		missile.CanCollide = false
		missile.Size = Vector3.new(0.4,0.4,2.5)
		missile.Material = Enum.Material.Neon
		missile.BrickColor = BrickColor.new("New Yeller")
		missile.Touched:Connect(function(obj)
			if not obj:IsDescendantOf(script.Parent) then
				local human = obj.Parent:FindFirstChild("Humanoid")
				if human then
					human:TakeDamage(100)
					for i,v in ipairs(obj.Parent:GetChildren()) do
						if v:IsA("BasePart") then
							local f = Instance.new("Fire",v)
							f.Size = v:GetMass() / 2
							game:GetService("TweenService"):Create(f,TweenInfo.new(3),{Heat = 0, Size = 0}):Play()
							delay(3,function()
								f.Enabled = false
								game:GetService("Debris"):AddItem(f,0.5)
							end)
						end
					end
				end
				
				if obj:GetMass() < 100 then
					local f = Instance.new("Fire",obj)
					f.Size = obj:GetMass() / 2
					game:GetService("TweenService"):Create(f,TweenInfo.new(3),{Heat = 0, Size = 0}):Play()
					delay(3,function()
						f.Enabled = false
						game:GetService("Debris"):AddItem(f,0.5)
					end)
				end
				
				local x = Instance.new("Explosion",workspace)
				x.Position = missile.Position
				missile:Destroy()
				game:GetService("Debris"):AddItem(x,0.5)
			end
		end)
		missile.Parent = workspace
		missile:SetNetworkOwner(nil)
		missile.CFrame = barrel.CFrame
		
		local bv = Instance.new("BodyVelocity",missile)
		bv.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
		bv.Velocity = barrel.CFrame.LookVector * 200
		
		local s = Instance.new("Sound",missile)
		s.Volume = 1
		s.PlaybackSpeed = 1.5
		s.Looped = true
		s.SoundId = "rbxasset://sounds/Rocket whoosh 01.wav"
		s:Play()
		
		local s = Instance.new("Sound",missile)
		s.Volume = 1
		s.SoundId = "rbxassetid://142070127"
		s.PlayOnRemove = true
		
		flash.Enabled = true
		delay(0.1,function()
			flash.Enabled = false
		end)
		
		local a1 = Instance.new("Attachment",missile)
		a1.Position = Vector3.new(0,0.2,0)
		local a2 = Instance.new("Attachment",missile)
		a2.Position = Vector3.new(0,-0.2,0)
		local t = Instance.new("Trail",missile)
		t.Attachment0 = a1
		t.Attachment1 = a2
		t.Color = ColorSequence.new(missile.Color)
		t.WidthScale = NumberSequence.new(1,0)
		t.Lifetime = 0.5
		
		barrelSmoke.Parent = smokeSpot
		game:GetService("TweenService"):Create(barrelSmoke,TweenInfo.new(0.2),{Opacity = 0.5}):Play()
		
		gunCool = false
		delay(1,function()
			game:GetService("TweenService"):Create(barrelSmoke,TweenInfo.new(1),{Opacity = 0}):Play()
			wait(1)
			barrelSmoke.Parent = nil
			gunCool = true
		end)
		
		
		--Give some recoil
		for i=0,1,0.4 do
			barrelWeld.Part1 = nil
			gunBarrelTube.CFrame = gunBarrelTube.CFrame:lerp(gunBarrelTube.CFrame * CFrame.new(0,0.5,0),i)
			barrelWeld.Part1 = gunBarrelTube
			wait()
		end
		for i=0,1,0.4 do
			barrelWeld.Part1 = nil
			gunBarrelTube.CFrame = gunBarrelTube.CFrame:lerp(gunBarrelTube.CFrame * CFrame.new(0,-0.5,0),i)
			barrelWeld.Part1 = gunBarrelTube
			wait()
		end		
	end
end

function aim(target)
	changeStatus(Color3.fromRGB(255, 0, 0)) --Really red status
	local lookDiff = (gunBG.CFrame.LookVector - CFrame.new(gunBackMain.CFrame.p,target.CFrame.p).LookVector).Magnitude
	game:GetService("TweenService"):Create(gunBG,TweenInfo.new(lookDiff),{CFrame = CFrame.new(gunBackMain.CFrame.p,target.CFrame.p)}):Play()
end

function turretRestore()
	local lookDiff = (gunBG.CFrame.LookVector - myTorso.CFrame.LookVector).Magnitude
	game:GetService("TweenService"):Create(gunBG,TweenInfo.new(lookDiff),{CFrame = myTorso.CFrame}):Play()
end

function targetLocked(target)
	local ray = Ray.new(gunBackMain.Position,gunBackMain.CFrame.LookVector * 200)
	local hit,position = workspace:FindPartOnRayWithIgnoreList(ray,{script.Parent})
	if hit then
		if hit:IsDescendantOf(target.Parent) then
			return true
		elseif (target.Position - position).Magnitude < 7 then
			return true
		end
	end
	return false
end

local vitalParts = {"GunBase","Wheel","Wheel","Wheel","Wheel"}
local gunVitalParts = {"Barrel","GunBarrelTip","GunBarrelTube","GunBarrelTube2"}

function checkVitalParts()
	local tankBits = myTorso:GetConnectedParts(true)
	local vitalCount = 0
	for _,v in ipairs(tankBits) do 
		for _,x in ipairs(vitalParts) do
			if x == v.Name then
				vitalCount = vitalCount + 1
				break
			end
		end
	end
	if vitalCount < #vitalParts then
		myHuman.Health = 0
	end
	local gunBits = gunBackMain:GetConnectedParts(true)
	vitalCount = 0
	for _,v in ipairs(gunBits) do
		for _,x in ipairs(gunVitalParts) do
			if x == v.Name then
				vitalCount = vitalCount + 1
				break
			end
		end
	end
	if vitalCount < #gunVitalParts then
		myHuman.Health = 0
	end
end

local oldHealth = myHuman.Health
myHuman.HealthChanged:Connect(function(health)
	if health < oldHealth then
		checkVitalParts()
	end
end)

myHuman.Died:Connect(function()
	engineSound:Stop()
	explosionSound:Play()
	engine.CanCollide = true
	for i,v in ipairs(touchedEvents) do
		v:Disconnect()
	end
	for i,v in ipairs(engine:GetConnectedParts()) do
		v.Velocity = Vector3.new(math.random(20),math.random(5,10),math.random(20))
		if math.random(20) == 1 then
			 local f = Instance.new("Fire",v)
			f.Size = v:GetMass()
		end
	end
	local x = Instance.new("Explosion",engine)
	x.Position = engine.Position
	for i,v in ipairs(script.Parent:GetDescendants()) do
		if v:IsA("WeldConstraint") or v:IsA("PointLight") then
			v:Destroy()
		elseif v:IsA("BasePart") then
			if v.Material == Enum.Material.Neon then
				v.Material = Enum.Material.SmoothPlastic
			end
		end
	end
	wait(3)
	for i,v in ipairs(script.Parent:GetDescendants()) do
		if v:IsA("BasePart") or v:IsA("Decal") then
			game:GetService("TweenService"):Create(v,TweenInfo.new(0.5),{Transparency = 1}):Play()
		end
	end
	wait(0.5)
	clone.Parent = workspace
	script.Parent:Destroy()
end)

local mainTarget = nil
local targetHuman = nil

--Gun logic controller
spawn(function()
	while wait(0.1) do
		if mainTarget then
			if checkSight(mainTarget) and checkDist(myTorso,mainTarget) > 25 then
				aim(mainTarget)
				if gunCool and mainTarget and targetLocked(mainTarget) and mainTarget.Parent then
					shoot(mainTarget)
				end
			else
				turretRestore()
			end
		else
			turretRestore()
		end
		if myHuman.Health <= 0 then
			break
		end
	end
end)

function main()
	pathBlocked = false
	if mainTarget then
		if not checkSight(mainTarget) or not mainTarget.Parent then
			mainTarget = nil
		end
	end
	if not mainTarget or targetHuman.Health <= 0 then
		mainTarget = findTarget()
		if mainTarget then
			targetHuman = mainTarget.Parent.Humanoid
		end
	end
	if mainTarget then
		--Ram target if close enough
		if (myTorso.Position - mainTarget.Position).magnitude < 35 and not pathBlocked then
			changeStatus(Color3.fromRGB(255, 176, 0)) --Deep orange status
			rotate(mainTarget)
			repeat
				myHuman:Move(myTorso.CFrame.LookVector)
				wait(0.1)
				spawn(function() rotate(mainTarget) end)
			until targetHuman.Health <= 0 or myTorso.Velocity.Magnitude < 1 or
				(myTorso.Position - mainTarget.Position).Magnitude > 35 or pathBlocked
			if not pathBlocked then 
				myHuman:Move(Vector3.new(0,0,0))
			end
		elseif checkDist(myTorso,mainTarget) > 120 or not checkSight(mainTarget) then
			pathToTarget(mainTarget)
		end
	end
end

while wait(0.2) do
	checkVitalParts()
	if myHuman.Health <= 0 then
		break
	end
	main()
end

Im too lazy to read over the script, but I would try to get all the players you want the AI to exclude, then before firing, check if the target is a player in the player table, if it is, move on, if it isnt, shoot.

1 Like

I’m confused, how would I do this?

1 Like

Heres an example:

local Players = game:GetService("Players")

function OnFire(target)
	local GetPlayers = Players:GetPlayers()
	
	for _, Player in ipairs(GetPlayers) do
		if target.Name == Player.Name then return end -- Dont continue if the target is a player
	end
	
	print("Fired")
end

OnFire(workspace:WaitForChild("JAcoboiskaka1121")) -- Wont print "Fired"
OnFire(workspace.SpawnLocation) -- Will print "Fired"
1 Like

if game.Players:GetPlayerFromCharacter(Character) then
don’t fire
else
fire
end

or, put a boolean value in the players and npcs called “FriendlyToTank”

local friendlycheck = character:FindFirstChild(“FriendlyToTank”)
if not friendlycheck then
warn("Could not find FriendlyToTank boolean value inside "… Character.Name)
else
if friendlycheck.Value == true then
Do not fire
else
Fire
end

I am too lazy to read the code but just check if the character is a player using game.Players:GetPlayerFromCharacter() if it returns nil then its an npc else its a player

There is this function which finds targets and there’s this part where it shoots players.

function findTarget()
	local dist = detection
	local target = nil
	local potentialTargets = {}
	local seeTargets = {}
	--Find potential targets
	for _,v in ipairs(workspace:GetChildren()) do
		local human = v:FindFirstChild("Humanoid")
		local torso = v:FindFirstChild("HumanoidRootPart") or  v:FindFirstChild("Torso") 
		if human and torso and v ~= script.Parent then
			if (myTorso.Position - torso.Position).magnitude < dist and human.Health > 0 then
				for i,x in ipairs(allies) do
					if x == v.Name then
						break
					elseif i == #allies then
						table.insert(potentialTargets,torso)
					end
				end
			end	
		end
	end
	--Check potential targets for targets within sight
	if #potentialTargets > 0 then
		for i,v in ipairs(potentialTargets) do
			if checkSight(v) then
				table.insert(seeTargets,v)
			end
		end
	end
	--If we cant see any targets find a target that we can move to
	if #potentialTargets > 0 and #seeTargets == 0 then
		for i,v in ipairs(potentialTargets) do
			if (myTorso.Position - v.Position).magnitude < dist and math.abs(myTorso.Position.Y - v.Position.Y) < 2 then
				local path = game:GetService("PathfindingService"):CreatePath(pathArgs)
				target = v
				dist = (myTorso.Position - v.Position).magnitude 
			end
		end
	end
	--If we have targets within sight target the cloest one
	if #seeTargets > 0 then
		dist = sight
		for i,v in ipairs(seeTargets) do
			if (myTorso.Position - v.Position).magnitude < dist then
				target = v
				dist = (myTorso.Position - v.Position).magnitude
			end
		end
	end
	return target
end

I could just make it not target players, how would I add that?

I already gave you an idea, implement my idea into your code.

local clone = script.Parent:Clone()

local Players = game.Players

--Latency Fix
for i,v in ipairs(script.Parent:GetDescendants()) do
	if v:IsA("BasePart") then
		if v:CanSetNetworkOwnership() == true then
			v:SetNetworkOwner(nil)
		end
	end
end


--Main body
local myHuman = script.Parent.Humanoid
local myHead = script.Parent.Head
local myTorso = script.Parent.Torso
local engine = script.Parent.Engine
local bodyBG = myTorso.BodyGyro
local status = script.Parent.Status
local bodyColor = script.Parent.TankColor

--Gun parts
local gunBackMain = script.Parent.GunBackMain
local gunBase = script.Parent.GunBase
local gunBG = gunBackMain.BodyGyro
local barrel = script.Parent.Barrel
local gunTip = script.Parent.GunBarrelTip
local gunBarrelTube = script.Parent.GunBarrelTube
local gunBarrelTube2 = script.Parent.GunBarrelTube2
local barrelWeld = script.Parent.BarrelWeld
local smokeSpot = barrel.SmokeSpot
local flash = barrel.Flash
local barrelSmoke = smokeSpot.Smoke

local allies = {script.Parent.Name, "Davarian Marine"}

--Sounds
local shootSound = barrel.Shoot
local engineSound = engine:WaitForChild("EngineNoise")
local explosionSound = engine:WaitForChild("Explosion")

local sight = 200
local detection = 3000
local failedPaths = 0

local touchedEvents = {}
local pathArgs = {
	["AgentRadius"] = 16,
	["AgentHeight"] = 13,
	["AgentCanJump"] = false	
}

local gunCool = true
local pathBlocked = false

--Inital Adjustments
engineSound:Play()
bodyBG.CFrame = myTorso.CFrame
gunBG.CFrame = gunBackMain.CFrame
barrelSmoke.Parent = nil

--Engine pitch adjuster
spawn(function()
	repeat 
		wait(0.1)
		if myTorso.Velocity.Magnitude > 5 or myTorso.RotVelocity.Magnitude > 0.1 then
			game:GetService("TweenService"):Create(engineSound,TweenInfo.new(0.2),{PlaybackSpeed = 0.35}):Play()
		else
			game:GetService("TweenService"):Create(engineSound,TweenInfo.new(0.2),{PlaybackSpeed = 0.3}):Play()
		end
	until myHuman.Health < 1 
end)

--Set team color
for i,v in ipairs(script.Parent:GetDescendants()) do
	if v:IsA("BasePart") and v.Name ~= "Headlight" and v.Name ~= "Status" then
		v.BrickColor = bodyColor.Value
	end
end

function checkDist(part1,part2)
	return (part1.Position - part2.Position).Magnitude
end

function checkForObstacles(direction)
	for i = -13, 13, 0.5 do
		local ray
		if direction == "front" then
			ray = Ray.new((myTorso.CFrame * CFrame.new(i,1,-16)).Position, myTorso.CFrame.LookVector * 5)
		elseif direction == "back" then
			ray = Ray.new((myTorso.CFrame * CFrame.new(i,0,13)).Position, -myTorso.CFrame.LookVector * 5)
		elseif direction == "right" then
			ray = Ray.new((myTorso.CFrame * CFrame.new(13,-0.5,i)).Position, myTorso.CFrame.RightVector * 5)
		elseif direction == "left" then
			ray = Ray.new((myTorso.CFrame * CFrame.new(-13,-0.5,i)).Position, -myTorso.CFrame.RightVector * 5)
		else
			print("Invalid direction suppled")
			ray = Ray.new(Vector3.new(0,0,0),Vector3.new(0,0,0))
		end
		local hit,pos = workspace:FindPartOnRayWithIgnoreList(ray,{script.Parent})
		if hit then
			if hit:IsGrounded() or hit.Anchored then
				return true
			end
		end
	end
	return false
end

--Collision detection logic
for _,v in ipairs(script.Parent:GetDescendants()) do
	if v:IsA("BasePart") and v.Name ~= "Wheel" and v.Name ~= "Wheel Lip" then
		local db = true
		local touch = v.Touched:Connect(function(obj)
			if db == true then
				db = false
				if obj.Parent and not obj:IsDescendantOf(script.Parent) then	
					local human = obj.Parent:FindFirstChild("Humanoid")	
					if not human and obj.Position.Y >= myTorso.Position.Y - 0.5 then
						--Break small objects that are in the way
						if obj:IsGrounded() and obj:GetMass() < 100 and not obj.Anchored then
							obj:BreakJoints()
						elseif obj:IsGrounded() or obj.Anchored then 
							if checkForObstacles("front") then
								backaway(obj)
							end
						end
					elseif human then
						if human.Health > 0 then
							for i,x in ipairs(allies) do
								if obj.Parent.Name == x then
									if checkForObstacles("front") then
										backaway(obj)
									end
									break
								elseif i == #allies then
									if v.Velocity.Magnitude > 15 then
										human:ChangeState(Enum.HumanoidStateType.Ragdoll)
										human:TakeDamage(math.random(20,30))
									end
								end
							end
						end	
					end
					wait(0.2)
					db = true
				end
			end
		end)
		table.insert(touchedEvents,touch)
	end
end

function changeStatus(color3)
	game:GetService("TweenService"):Create(status,TweenInfo.new(1),{Color = color3}):Play()
end

function backaway(target)
	pathBlocked = true
	changeStatus(Color3.fromRGB(110, 153, 202)) --Medium blue status
	for i = 1, 8 do
		wait(0.1)
		myHuman:Move(-myTorso.CFrame.LookVector)
	end
	myHuman:Move(Vector3.new(0,0,0))
	pathBlocked = false
end

function getUnstuck()
	changeStatus(Color3.fromRGB(255, 102, 204))--Pink status
	if not checkForObstacles("front") then		
		myHuman:Move(myTorso.CFrame.LookVector)
	elseif not checkForObstacles("back") then
		myHuman:Move(-myTorso.CFrame.LookVector)
	elseif not checkForObstacles("right") then
		game:GetService("TweenService"):Create(bodyBG,TweenInfo.new(0.5),{CFrame = myTorso.CFrame * CFrame.Angles(0,math.rad(-90),0)}):Play()
		wait(0.5)
		myHuman:Move(myTorso.CFrame.LookVector)
	elseif not checkForObstacles("left") then
		game:GetService("TweenService"):Create(bodyBG,TweenInfo.new(0.5),{CFrame = myTorso.CFrame * CFrame.Angles(0,math.rad(90),0)}):Play()
		wait(0.5)
		myHuman:Move(myTorso.CFrame.LookVector)
	end
	wait(0.5)
	myHuman:Move(Vector3.new(0,0,0))
end

function checkSight(target)
	local ray = Ray.new(myTorso.Position,(target.Position - myTorso.Position).Unit * sight)
	local hit,position = workspace:FindPartOnRayWithIgnoreList(ray,{script.Parent})

	local ray2 = Ray.new(gunBackMain.Position,(target.Position - gunBackMain.Position).Unit * sight)
	local hit2,position2 = workspace:FindPartOnRayWithIgnoreList(ray2,{script.Parent})
	if hit and hit2 then
		if hit:IsDescendantOf(target.Parent) and hit2:IsDescendantOf(target.Parent) then
			return true
		end
	end
	return false
end

function findTarget()
	local getPlayers = Players:GetPlayers()
	local dist = detection
	local target = nil
	local potentialTargets = {}
	local seeTargets = {}
	
	for _, Player in ipairs(getPlayers) do
		if target.Name == Player.Name then return end
	end
	
	for _,v in ipairs(workspace:GetChildren()) do
		local human = v:FindFirstChild("Humanoid")
		local torso = v:FindFirstChild("HumanoidRootPart") or  v:FindFirstChild("Torso") 
		if human and torso and v ~= script.Parent then
			if (myTorso.Position - torso.Position).magnitude < dist and human.Health > 0 then
				for i,x in ipairs(allies) do
					if x == v.Name then
						break
					elseif i == #allies then
						table.insert(potentialTargets,torso)
					end
				end
			end
		end
	end
	--Check potential targets for targets within sight
	if #potentialTargets > 0 then
		for i,v in ipairs(potentialTargets) do
			if checkSight(v) then
				table.insert(seeTargets,v)
			end
		end
	end
	--If we cant see any targets find a target that we can move to
	if #potentialTargets > 0 and #seeTargets == 0 then
		for i,v in ipairs(potentialTargets) do
			if (myTorso.Position - v.Position).magnitude < dist and math.abs(myTorso.Position.Y - v.Position.Y) < 2 then
				local path = game:GetService("PathfindingService"):CreatePath(pathArgs)
				target = v
				dist = (myTorso.Position - v.Position).magnitude 
			end
		end
	end
	--If we have targets within sight target the cloest one
	if #seeTargets > 0 then
		dist = sight
		for i,v in ipairs(seeTargets) do
			if (myTorso.Position - v.Position).magnitude < dist then
				target = v
				dist = (myTorso.Position - v.Position).magnitude
			end
		end
	end
	return target
end

function rotate(target)
	if checkDist(target,myTorso) > 1.5 then
		local look = Vector3.new(target.Position.X,myTorso.Position.Y,target.Position.Z)
		local lookDiff = (myTorso.CFrame.lookVector - CFrame.new(myTorso.Position,look).lookVector).Magnitude
		game:GetService("TweenService"):Create(bodyBG,TweenInfo.new(lookDiff),{CFrame = CFrame.new(myTorso.Position,look)}):Play()
		wait(lookDiff)
	end
end

function pathToTarget(target)
	pathBlocked = false
	changeStatus(Color3.fromRGB(213, 115, 61)) --Neon orange status
	local path = game:GetService("PathfindingService"):CreatePath(pathArgs)
	path:ComputeAsync(myTorso.Position, target.Position)
	local waypoints = path:GetWaypoints()
	if path.Status == Enum.PathStatus.Success then
		for i,v in ipairs(waypoints) do
			spawn(function() rotate(v) end)
			local timer = 1
			local success = true
			repeat
				wait()
				myHuman:Move(myTorso.CFrame.LookVector)
				timer = timer + 1
				if timer > 40 then
					success = false 
					break
				end
			until checkDist(myTorso,v) < 4 
			if success == false or pathBlocked == true then
				if pathBlocked == true then
					myHuman:Move(Vector3.new(0,0,0))
					wait(2)
				end
				break
			elseif (waypoints[#waypoints].Position - target.Position).magnitude > 20 then
				break
			elseif not target.Parent or target.Parent.Humanoid.Health <= 0 then 
				break
			end
			if i % 5 == 0 then
				if checkSight(target) and checkDist(myTorso,target) < 50 then
					break
				end
			end
		end
		myHuman:Move(Vector3.new(0,0,0))
	else
		failedPaths = failedPaths + 1
		if failedPaths > 10 then
			getUnstuck()
		end
	end
end

function shoot(target)
	if gunCool then
		shootSound:Play()
		local missile = Instance.new("Part")
		missile.CanCollide = false
		missile.Size = Vector3.new(0.4,0.4,2.5)
		missile.Material = Enum.Material.Neon
		missile.BrickColor = BrickColor.new("New Yeller")
		missile.Touched:Connect(function(obj)
			if not obj:IsDescendantOf(script.Parent) then
				local human = obj.Parent:FindFirstChild("Humanoid")
				if human then
					human:TakeDamage(100)
					for i,v in ipairs(obj.Parent:GetChildren()) do
						if v:IsA("BasePart") then
							local f = Instance.new("Fire",v)
							f.Size = v:GetMass() / 2
							game:GetService("TweenService"):Create(f,TweenInfo.new(3),{Heat = 0, Size = 0}):Play()
							delay(3,function()
								f.Enabled = false
								game:GetService("Debris"):AddItem(f,0.5)
							end)
						end
					end
				end

				if obj:GetMass() < 100 then
					local f = Instance.new("Fire",obj)
					f.Size = obj:GetMass() / 2
					game:GetService("TweenService"):Create(f,TweenInfo.new(3),{Heat = 0, Size = 0}):Play()
					delay(3,function()
						f.Enabled = false
						game:GetService("Debris"):AddItem(f,0.5)
					end)
				end

				local x = Instance.new("Explosion",workspace)
				x.Position = missile.Position
				missile:Destroy()
				game:GetService("Debris"):AddItem(x,0.5)
			end
		end)
		missile.Parent = workspace
		missile:SetNetworkOwner(nil)
		missile.CFrame = barrel.CFrame

		local bv = Instance.new("BodyVelocity",missile)
		bv.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
		bv.Velocity = barrel.CFrame.LookVector * 200

		local s = Instance.new("Sound",missile)
		s.Volume = 1
		s.PlaybackSpeed = 1.5
		s.Looped = true
		s.SoundId = "rbxasset://sounds/Rocket whoosh 01.wav"
		s:Play()

		local s = Instance.new("Sound",missile)
		s.Volume = 1
		s.SoundId = "rbxassetid://142070127"
		s.PlayOnRemove = true

		flash.Enabled = true
		delay(0.1,function()
			flash.Enabled = false
		end)

		local a1 = Instance.new("Attachment",missile)
		a1.Position = Vector3.new(0,0.2,0)
		local a2 = Instance.new("Attachment",missile)
		a2.Position = Vector3.new(0,-0.2,0)
		local t = Instance.new("Trail",missile)
		t.Attachment0 = a1
		t.Attachment1 = a2
		t.Color = ColorSequence.new(missile.Color)
		t.WidthScale = NumberSequence.new(1,0)
		t.Lifetime = 0.5

		barrelSmoke.Parent = smokeSpot
		game:GetService("TweenService"):Create(barrelSmoke,TweenInfo.new(0.2),{Opacity = 0.5}):Play()

		gunCool = false
		delay(1,function()
			game:GetService("TweenService"):Create(barrelSmoke,TweenInfo.new(1),{Opacity = 0}):Play()
			wait(1)
			barrelSmoke.Parent = nil
			gunCool = true
		end)


		--Give some recoil
		for i=0,1,0.4 do
			barrelWeld.Part1 = nil
			gunBarrelTube.CFrame = gunBarrelTube.CFrame:lerp(gunBarrelTube.CFrame * CFrame.new(0,0.5,0),i)
			barrelWeld.Part1 = gunBarrelTube
			wait()
		end
		for i=0,1,0.4 do
			barrelWeld.Part1 = nil
			gunBarrelTube.CFrame = gunBarrelTube.CFrame:lerp(gunBarrelTube.CFrame * CFrame.new(0,-0.5,0),i)
			barrelWeld.Part1 = gunBarrelTube
			wait()
		end		
	end
end

function aim(target)
	changeStatus(Color3.fromRGB(255, 0, 0)) --Really red status
	local lookDiff = (gunBG.CFrame.LookVector - CFrame.new(gunBackMain.CFrame.p,target.CFrame.p).LookVector).Magnitude
	game:GetService("TweenService"):Create(gunBG,TweenInfo.new(lookDiff),{CFrame = CFrame.new(gunBackMain.CFrame.p,target.CFrame.p)}):Play()
end

function turretRestore()
	local lookDiff = (gunBG.CFrame.LookVector - myTorso.CFrame.LookVector).Magnitude
	game:GetService("TweenService"):Create(gunBG,TweenInfo.new(lookDiff),{CFrame = myTorso.CFrame}):Play()
end

function targetLocked(target)
	local ray = Ray.new(gunBackMain.Position,gunBackMain.CFrame.LookVector * 200)
	local hit,position = workspace:FindPartOnRayWithIgnoreList(ray,{script.Parent})
	if hit then
		if hit:IsDescendantOf(target.Parent) then
			return true
		elseif (target.Position - position).Magnitude < 7 then
			return true
		end
	end
	return false
end

local vitalParts = {"GunBase","Wheel","Wheel","Wheel","Wheel"}
local gunVitalParts = {"Barrel","GunBarrelTip","GunBarrelTube","GunBarrelTube2"}

function checkVitalParts()
	local tankBits = myTorso:GetConnectedParts(true)
	local vitalCount = 0
	for _,v in ipairs(tankBits) do 
		for _,x in ipairs(vitalParts) do
			if x == v.Name then
				vitalCount = vitalCount + 1
				break
			end
		end
	end
	if vitalCount < #vitalParts then
		myHuman.Health = 0
	end
	local gunBits = gunBackMain:GetConnectedParts(true)
	vitalCount = 0
	for _,v in ipairs(gunBits) do
		for _,x in ipairs(gunVitalParts) do
			if x == v.Name then
				vitalCount = vitalCount + 1
				break
			end
		end
	end
	if vitalCount < #gunVitalParts then
		myHuman.Health = 0
	end
end

local oldHealth = myHuman.Health
myHuman.HealthChanged:Connect(function(health)
	if health < oldHealth then
		checkVitalParts()
	end
end)

myHuman.Died:Connect(function()
	engineSound:Stop()
	explosionSound:Play()
	engine.CanCollide = true
	for i,v in ipairs(touchedEvents) do
		v:Disconnect()
	end
	for i,v in ipairs(engine:GetConnectedParts()) do
		v.Velocity = Vector3.new(math.random(20),math.random(5,10),math.random(20))
		if math.random(20) == 1 then
			local f = Instance.new("Fire",v)
			f.Size = v:GetMass()
		end
	end
	local x = Instance.new("Explosion",engine)
	x.Position = engine.Position
	for i,v in ipairs(script.Parent:GetDescendants()) do
		if v:IsA("WeldConstraint") or v:IsA("PointLight") then
			v:Destroy()
		elseif v:IsA("BasePart") then
			if v.Material == Enum.Material.Neon then
				v.Material = Enum.Material.SmoothPlastic
			end
		end
	end
	wait(3)
	for i,v in ipairs(script.Parent:GetDescendants()) do
		if v:IsA("BasePart") or v:IsA("Decal") then
			game:GetService("TweenService"):Create(v,TweenInfo.new(0.5),{Transparency = 1}):Play()
		end
	end
	wait(0.5)
	clone.Parent = workspace
	script.Parent:Destroy()
end)

local mainTarget = nil
local targetHuman = nil

--Gun logic controller
spawn(function()
	while wait(0.1) do
		if mainTarget then
			if checkSight(mainTarget) and checkDist(myTorso,mainTarget) > 25 then
				aim(mainTarget)
				if gunCool and mainTarget and targetLocked(mainTarget) and mainTarget.Parent then
					shoot(mainTarget)
				end
			else
				turretRestore()
			end
		else
			turretRestore()
		end
		if myHuman.Health <= 0 then
			break
		end
	end
end)

function main()
	pathBlocked = false
	if mainTarget then
		if not checkSight(mainTarget) or not mainTarget.Parent then
			mainTarget = nil
		end
	end
	if not mainTarget or targetHuman.Health <= 0 then
		mainTarget = findTarget()
		if mainTarget then
			targetHuman = mainTarget.Parent.Humanoid
		end
	end
	if mainTarget then
		--Ram target if close enough
		if (myTorso.Position - mainTarget.Position).magnitude < 35 and not pathBlocked then
			changeStatus(Color3.fromRGB(255, 176, 0)) --Deep orange status
			rotate(mainTarget)
			repeat
				myHuman:Move(myTorso.CFrame.LookVector)
				wait(0.1)
				spawn(function() rotate(mainTarget) end)
			until targetHuman.Health <= 0 or myTorso.Velocity.Magnitude < 1 or
				(myTorso.Position - mainTarget.Position).Magnitude > 35 or pathBlocked
			if not pathBlocked then 
				myHuman:Move(Vector3.new(0,0,0))
			end
		elseif checkDist(myTorso,mainTarget) > 120 or not checkSight(mainTarget) then
			pathToTarget(mainTarget)
		end
	end
end

while wait(0.2) do
	checkVitalParts()
	if myHuman.Health <= 0 then
		break
	end
	main()
endturn target
end

Not tested, give it a shot

I did not read the full code yet but you should be able to exclude the allied players or allied npcs or anything that is allied from the “find nearest target” function that you are most likely using.

Everyone here suggested to check whether the target is an ally but instead you should implement something that prevents the ally from being a target in the first place!

You could do that by just going over a table of allies and removing them from the table of possible targets in your “find nearest target” function.

I am now going to look into the code and will come back with a more coherent solution

Your code does not make alot of sense to me even after reading the find function. This is how I would handle it and I recommend you think about how to structure code and take a look at some bad practices. Looping through all of workspace to find the humanoids is crazy.

Also: ipairs is not superior pairs, you used it where it wasn’t necessary, look into what it actually is and what the difference to pairs is!

local function get_distance()

end

local function check_sight()

end

local function move_to()

end

local function get_nearest_target(targets)
	local nearest = {model = nil, distance = math.huge}
	
	for i, target in pairs(targets) do
		if target.distance < nearest.distance then nearest = target end
	end
	
	return (nearest.model ~= nil and nearest) or nil
end

local function get_target(allies)
	local npc_folder  = workspace.npcs -- the folder where all npc characters are in (nothing else!)
	local targets 	  = {}
	local pot_targets = {}
	
	for i, npc in pairs(npc_folder) do -- add all (not allied) npcs to targets
		if not table.find(allies, npc) then -- if the model of the npc is in ally array it should not be added to targets
			table.insert(targets, {model = npc, distance = get_distance(npc)}) -- the second index in the array is the distance to that model
		end
	end
	
	for i, player in pairs(game.Players:GetPlayers()) do
		local character = player.Character
		
		if not table.find(allies, character) then
			table.insert(targets, {model = character, distance = get_distance(character)})
		end
	end
	
	pot_targets = table.clone(targets)
	-- now we have all potential targets and we start removing from the list
	
	for i, target in pairs(targets) do -- if not in sight, remove from target list BUT KEEP IN POTENTIAL LIST
		if not check_sight(target.model) then 
			table.remove(targets, table.find(targets, target))
		end
	end
	
	if #targets == 0 then -- we have to move to the nearest potential target
		move_to(get_nearest_target(pot_targets))
		return nil
	end
	
	return get_nearest_target(targets)
end
1 Like

Add an extra condition to check if a character doesn’t belong to a player:

local function isPlayer(character: Model): boolean
	for _, player in pairs(game.Players:GetPlayers()) do
		if player.Character == character then return true end
	end
	return false
end

if isPlayer(targetCharacterHere) then
	warn("This isn't an NPC! Don't attack it!")
	return --you may want to add return to prevent attack code from running
end

The code isn’t mine btw, but the way I made it not shoot people was to make the tank search through a folder in workspace, and not workspace and I solved it by getting inspiration.

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