I was trying to add on to my NPC system, where the NPC would chase a player and kill it. My goal was that if the player has a tool in their inventory, the NPC wouldn’t chase the player, but ignore it. I got to a point, where it just stands still and doesn’t do anything. Here’s the script.
wait(2)
local PathfindingService = game:GetService("PathfindingService")
local npc = script.Parent
local humanoid = npc:WaitForChild("Humanoid")
local hrp = npc:WaitForChild("HumanoidRootPart")
hrp:SetNetworkOwner(nil)
local walkAnim = humanoid.Animator:LoadAnimation(script.Walk)
local attackAnim = humanoid.Animator:LoadAnimation(script.Attack)
local RANGE = 60
local DAMAGE = 100
local REQUIRED_TOOL_NAME = "Tazer" -- Replace with the name of the required tool
local COOLDOWN = 5 -- Cooldown in seconds
-- Enum for AI states
local AIState = {
Patrol = "Patrol",
Attack = "Attack",
Cooldown = "Cooldown",
}
-- Helper function to check if the player has the required tool
local function hasRequiredTool(player)
local character = player.Character
if character and character:FindFirstChild(REQUIRED_TOOL_NAME) then
return true
end
return false
end
local function canSeeTarget(target)
local orgin = hrp.Position
local direction = (target.HumanoidRootPart.Position - hrp.Position).Unit * RANGE
local ray = workspace:Raycast(orgin, direction)
if ray and ray.Instance then
local hitPart = ray.Instance
local character = hitPart.Parent
-- Check if the hit part or its ancestor is the target
while character do
if character == target then
-- Check if the player has the required tool
return hasRequiredTool(target)
end
character = character.Parent
end
return false
else
return false
end
end
local function findTarget()
local players = game.Players:GetPlayers()
local maxDistance = RANGE
local nearestTarget
for i, player in pairs(players) do
if player.Character and player.Character:IsA("Model") then
local target = player.Character
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and canSeeTarget(target) then
nearestTarget = target
maxDistance = distance
end
end
end
return nearestTarget
end
local function attack(target)
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
if distance > 5 then
humanoid:MoveTo(target.HumanoidRootPart.Position)
else
npc.Head.AttackSound:Play()
attackAnim:Play()
target.Humanoid.Health -= DAMAGE
wait(0.5)
end
end
local function mainLoop()
local currentState = AIState.Patrol
local cooldownEndTime = 0
while true do
local target = findTarget()
if target then
if target.Humanoid.Health > 0 then
if currentState == AIState.Patrol then
currentState = AIState.Attack
elseif currentState == AIState.Attack then
attack(target)
currentState = AIState.Cooldown
cooldownEndTime = tick() + COOLDOWN
elseif currentState == AIState.Cooldown then
if tick() >= cooldownEndTime then
currentState = AIState.Patrol
end
end
end
else
currentState = AIState.Patrol
end
wait(0.2)
end
end
mainLoop()
You can check if the desired tool is in the player’s inventory. You can go about this by using for pairs but i think there is a better solution to these kinds of things.
EDIT: Fors is the best solution i think, create a table of all the items of that type and you can go about your day like such, you can also check how many of those items are in the player’s inventory using this method.
wait(2)
local PathfindingService = game:GetService("PathfindingService")
local npc = script.Parent
local humanoid = npc:WaitForChild("Humanoid")
local hrp = npc:WaitForChild("HumanoidRootPart")
hrp:SetNetworkOwner(nil)
local walkAnim = humanoid.Animator:LoadAnimation(script.Walk)
local attackAnim = humanoid.Animator:LoadAnimation(script.Attack)
local RANGE = 60
local DAMAGE = 100
local REQUIRED_TOOL_NAME = "Tazer" -- Replace with the name of the required tool
local COOLDOWN = 5 -- Cooldown in seconds
-- Enum for AI states
local AIState = {
Patrol = "Patrol",
Attack = "Attack",
Cooldown = "Cooldown",
}
-- Helper function to check if the player has the required tool
local function hasRequiredTool(player)
local character = player.Character
if (character and character:FindFirstChild(REQUIRED_TOOL_NAME)) or player.Backpack:FindFirstChild(REQUIRED_TOOL_NAME) then
return true
end
return false
end
local function canSeeTarget(target)
local orgin = hrp.Position
local direction = (target.HumanoidRootPart.Position - hrp.Position).Unit * RANGE
local ray = workspace:Raycast(orgin, direction)
if ray and ray.Instance then
local hitPart = ray.Instance
local character = hitPart.Parent
-- Check if the hit part or its ancestor is the target
while character do
if character == target then
-- Check if the player has the required tool
return hasRequiredTool(target)
end
character = character.Parent
end
return false
else
return false
end
end
local function findTarget()
local players = game.Players:GetPlayers()
local maxDistance = RANGE
local nearestTarget
for i, player in pairs(players) do
if player.Character and player.Character:IsA("Model") then
local target = player.Character
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and canSeeTarget(target) then
nearestTarget = target
maxDistance = distance
end
end
end
return nearestTarget
end
local function attack(target)
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
if distance > 5 then
humanoid:MoveTo(target.HumanoidRootPart.Position)
else
npc.Head.AttackSound:Play()
attackAnim:Play()
target.Humanoid.Health -= DAMAGE
task.wait(0.5)
end
end
local function mainLoop()
local currentState = AIState.Patrol
local cooldownEndTime = 0
while true do
local target = findTarget()
if target then
if target.Humanoid.Health > 0 then
if currentState == AIState.Patrol then
currentState = AIState.Attack
elseif currentState == AIState.Attack then
attack(target)
currentState = AIState.Cooldown
cooldownEndTime = tick() + COOLDOWN
elseif currentState == AIState.Cooldown then
if tick() >= cooldownEndTime then
currentState = AIState.Patrol
end
end
end
else
currentState = AIState.Patrol
end
task.wait(0.2)
end
end
mainLoop()
no i mean what if he wants to check the amount of items of the same type? could be useful for development further on so i think it is a better solution.
If they wanted to, they would’ve put it in the post or notified me. Also, a loop is worse for performance because you’ll also have to keep a counter of how many times the tool was found (which is not needed for the game, and why would you even need to track that?).
wait(2)
local PathfindingService = game:GetService("PathfindingService")
local npc = script.Parent
local humanoid = npc:WaitForChild("Humanoid")
local hrp = npc:WaitForChild("HumanoidRootPart")
hrp:SetNetworkOwner(nil)
local walkAnim = humanoid.Animator:LoadAnimation(script.Walk)
local attackAnim = humanoid.Animator:LoadAnimation(script.Attack)
local RANGE = 60
local DAMAGE = 100
local REQUIRED_TOOL_NAME = "Tazer" -- Replace with the name of the required tool
local COOLDOWN = 5 -- Cooldown in seconds
-- Enum for AI states
local AIState = {
Patrol = "Patrol",
Attack = "Attack",
Cooldown = "Cooldown",
}
-- Helper function to check if the player has the required tool
local function hasRequiredTool(player)
local character = player.Character
if (character and character:FindFirstChild(REQUIRED_TOOL_NAME)) or player.Backpack:FindFirstChild(REQUIRED_TOOL_NAME) then
return true
end
return false
end
local function canSeeTarget(player)
local target = player.Character
local orgin = hrp.Position
local direction = (target.HumanoidRootPart.Position - hrp.Position).Unit * RANGE
local ray = workspace:Raycast(orgin, direction)
if ray and ray.Instance then
local hitPart = ray.Instance
local character = hitPart.Parent
-- Check if the hit part or its ancestor is the target
while character do
if character == target then
-- Check if the player has the required tool
return hasRequiredTool(player)
end
character = character.Parent
end
return false
else
return false
end
end
local function findTarget()
local players = game.Players:GetPlayers()
local maxDistance = RANGE
local nearestTarget
for i, player in pairs(players) do
if player.Character and player.Character:IsA("Model") then
local target = player.Character
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and canSeeTarget(player) then
nearestTarget = target
maxDistance = distance
end
end
end
return nearestTarget
end
local function attack(target)
local distance = (hrp.Position - target.HumanoidRootPart.Position).Magnitude
if distance > 5 then
humanoid:MoveTo(target.HumanoidRootPart.Position)
else
npc.Head.AttackSound:Play()
attackAnim:Play()
target.Humanoid.Health -= DAMAGE
task.wait(0.5)
end
end
local function mainLoop()
local currentState = AIState.Patrol
local cooldownEndTime = 0
while true do
local target = findTarget()
if target then
if target.Humanoid.Health > 0 then
if currentState == AIState.Patrol then
currentState = AIState.Attack
elseif currentState == AIState.Attack then
attack(target)
currentState = AIState.Cooldown
cooldownEndTime = tick() + COOLDOWN
elseif currentState == AIState.Cooldown then
if tick() >= cooldownEndTime then
currentState = AIState.Patrol
end
end
end
else
currentState = AIState.Patrol
end
task.wait(0.2)
end
end
mainLoop()