First of all, the problem is that while attacking the player or patrolling, it suddenly starts to move forward by hanging. I can’t find the reason. I just noticed something that when I open the console, the script works at the level it should when the rate is 3 and 3>x is large, but the problem starts when the rate is 2.
-- ModuleScript: ServerScriptService/EnemyNPCAI
local module = {}
function module.Run(EnemyNPC)
local humanoid = EnemyNPC:WaitForChild("Humanoid")
local rootPart = EnemyNPC:WaitForChild("HumanoidRootPart")
EnemyNPC.PrimaryPart:SetNetworkOwner(nil)
local mapClone = workspace
local waypoints = mapClone:FindFirstChild("waypoint"):GetChildren()
local enemyHealthThreshold = 200
local normalSpeed = 12
local chaseSpeed = 20
local lastAttackTime = 0
local attackCooldown = 3
local lastRockCheck = 0
local rockCooldown = 5
local lastSeenPosition = nil
local lostTargetTimer = 0
local maxLostTime = 5
local angerValue = EnemyNPC:FindFirstChild("Anger")
local animationsFolder = game.ReplicatedStorage:WaitForChild("Animations")
local attackAnimation = humanoid:LoadAnimation(animationsFolder:WaitForChild("Punch"))
local hideAnimation = humanoid:LoadAnimation(animationsFolder:WaitForChild("Hide"))
local grabRockAnim = humanoid:LoadAnimation(animationsFolder:WaitForChild("GrabRock"))
local FitalityAnimation = humanoid:LoadAnimation(animationsFolder:WaitForChild("Grab"))
local throwRockAnim = humanoid:LoadAnimation(animationsFolder:WaitForChild("ThrowRock"))
local originalMaxHealth = humanoid.MaxHealth
local originalHealth = humanoid.Health
local function createRock()
local rock = Instance.new("Part")
rock.Name = "Rock"
rock.Size = Vector3.new(1.5, 1.5, 1.5)
rock.Shape = Enum.PartType.Block
rock.Material = Enum.Material.Slate
rock.BrickColor = BrickColor.new("Dark stone grey")
rock.Anchored = false
rock.CanCollide = false
rock.Massless = false
rock.Parent = EnemyNPC
local weld = Instance.new("Motor6D")
weld.Name = "RockWeld"
weld.Part0 = EnemyNPC:FindFirstChild("Right Arm")
weld.Part1 = rock
weld.C0 = CFrame.new(0, -1.2, -0.5)
weld.Parent = rock
rock.Position = EnemyNPC["Right Arm"].Position - Vector3.new(0, 1.2, 0.5)
return rock, weld
end
local function findNearbyThrowableNpc(position, radius)
for _, npc in pairs(workspace:GetChildren()) do
if npc.Name == "ThrowableNpc" and npc:FindFirstChild("HumanoidRootPart") then
if (npc.HumanoidRootPart.Position - position).Magnitude <= radius then
return npc
end
end
end
return nil
end
local function throwRockAtTarget(target)
if not target or not target:FindFirstChild("HumanoidRootPart") then return end
humanoid.WalkSpeed = 0
grabRockAnim:Play()
local ThrowableNpc = findNearbyThrowableNpc(EnemyNPC.HumanoidRootPart.Position, 20)
local thrownPart, weld
if ThrowableNpc then
local humanoidThrowableNpc = ThrowableNpc:FindFirstChildOfClass("Humanoid")
if humanoidThrowableNpc then
humanoidThrowableNpc:ChangeState(Enum.HumanoidStateType.Physics)
humanoidThrowableNpc:SetStateEnabled(Enum.HumanoidStateType.FallingDown, false)
humanoidThrowableNpc:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)
humanoidThrowableNpc:SetStateEnabled(Enum.HumanoidStateType.Ragdoll, false)
humanoidThrowableNpc:SetStateEnabled(Enum.HumanoidStateType.Seated, false)
end
if ThrowableNpc:FindFirstChild("Humanoid") and ThrowableNpc.Humanoid:FindFirstChild("EvaluateStateMachine") then
ThrowableNpc.Humanoid.EvaluateStateMachine = false
end
for _, part in pairs(ThrowableNpc:GetDescendants()) do
if part:IsA("BasePart") then
part.CanCollide = true
part.Anchored = false
elseif part:IsA("Script") or part:IsA("LocalScript") then
part:Destroy()
end
end
weld = Instance.new("Motor6D")
weld.Name = "ThrowableNpcWeld"
weld.Part0 = EnemyNPC:FindFirstChild("Right Arm")
weld.Part1 = ThrowableNpc.HumanoidRootPart
weld.C0 = CFrame.new(0, -1.2, -0.5)
weld.Parent = ThrowableNpc.HumanoidRootPart
thrownPart = ThrowableNpc.HumanoidRootPart
else
thrownPart, weld = createRock()
end
task.wait(0.5)
throwRockAnim:Play()
task.wait(0.6)
humanoid.WalkSpeed = chaseSpeed
if weld then weld:Destroy() end
thrownPart.CanCollide = false
local direction = (target.HumanoidRootPart.Position - thrownPart.Position).Unit
local bodyVelocity = Instance.new("BodyVelocity")
bodyVelocity.Velocity = direction * 100
bodyVelocity.MaxForce = Vector3.new(1e5, 1e5, 1e5)
bodyVelocity.Parent = thrownPart
game.Debris:AddItem(bodyVelocity, 0.5)
local function cleanup(hit)
if hit and hit.Parent == target then
if target:FindFirstChild("Humanoid") then
target.Humanoid:TakeDamage(40)
else
if ThrowableNpc then
ThrowableNpc:Destroy()
else
thrownPart:Destroy()
end
end
end
end
thrownPart.Touched:Connect(cleanup)
delay(3, function()
if thrownPart and thrownPart.Parent then
if ThrowableNpc then
ThrowableNpc:Destroy()
else
thrownPart:Destroy()
end
end
end)
end
local function canSeeTarget(target)
local origin = EnemyNPC.HumanoidRootPart.Position
local direction = (target.HumanoidRootPart.Position - origin).unit * 100
local ray = Ray.new(origin, direction)
local hit, pos = workspace:FindPartOnRay(ray, EnemyNPC)
if hit and hit:IsDescendantOf(target) then
local npcForwardVector = EnemyNPC.HumanoidRootPart.CFrame.LookVector
local directionToTarget = (target.HumanoidRootPart.Position - origin).unit
local dotProduct = npcForwardVector:Dot(directionToTarget)
if dotProduct > math.cos(math.rad(150)) then
return true
end
end
return false
end
local function findTarget()
local maxDistance = math.huge
local nearestTarget = nil
for _, player in ipairs(game.Players:GetPlayers()) do
local character = player.Character
if character and character:FindFirstChild("HumanoidRootPart") then
local dist = (EnemyNPC.HumanoidRootPart.Position - character.HumanoidRootPart.Position).Magnitude
if dist < maxDistance then
if canSeeTarget(character) or dist <= 10 then
nearestTarget = character
maxDistance = dist
end
end
end
end
local npcFolder = workspace:FindFirstChild("NPCs")
if npcFolder then
for _, npc in ipairs(npcFolder:GetChildren()) do
if npc:IsA("Model") and npc:FindFirstChild("HumanoidRootPart") then
local dist = (EnemyNPC.HumanoidRootPart.Position - npc.HumanoidRootPart.Position).Magnitude
if dist < maxDistance then
if canSeeTarget(npc) or dist <= 10 then
nearestTarget = npc
maxDistance = dist
end
end
end
end
end
return nearestTarget
end
local function getPath(destination)
local PathfindingService = game:GetService("PathfindingService")
local pathParams = {
AgentHeight = 15,
AgentRadius = 4,
AgentCanJump = false,
}
local path = PathfindingService:CreatePath(pathParams)
path:ComputeAsync(EnemyNPC.HumanoidRootPart.Position, destination.Position)
return path
end
local function turnAndPlayAnimation(target)
EnemyNPC:SetPrimaryPartCFrame(
CFrame.lookAt(
EnemyNPC.HumanoidRootPart.Position,
target.HumanoidRootPart.Position
)
)
end
local function isPathClearOrJump(targetPos)
local origin = EnemyNPC.HumanoidRootPart.Position
local direction = (targetPos - origin).Unit * 6
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {EnemyNPC}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local forwardResult = workspace:Raycast(origin, direction, raycastParams)
local downOrigin = origin + Vector3.new(0, -2, 0)
local downDirection = direction + Vector3.new(0, -6, 0)
local downResult = workspace:Raycast(downOrigin, downDirection, raycastParams)
if forwardResult then
local hitPos = forwardResult.Position
local heightAboveGround = hitPos.Y - origin.Y
if heightAboveGround <= 6 then
if humanoid:GetState() ~= Enum.HumanoidStateType.Jumping then
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
return true
else
return false
end
elseif not downResult then
return false
else
return true
end
end
local function chaseTarget(target)
while target and target.Parent and target:FindFirstChild("Humanoid") and target.Humanoid.Health > 0 do
local distance = (target.HumanoidRootPart.Position - EnemyNPC.HumanoidRootPart.Position).Magnitude
if canSeeTarget(target) then
lastSeenPosition = target.HumanoidRootPart.Position
lostTargetTimer = 0
if distance > 20 and math.random() < 0.1 then
local currentTime = tick()
if currentTime - lastRockCheck >= rockCooldown then
lastRockCheck = currentTime
throwRockAtTarget(target)
end
end
if distance <= 5 then
humanoid:MoveTo(EnemyNPC.HumanoidRootPart.Position)
if target.Humanoid.Health <= 25 then
local weld = Instance.new("Motor6D")
weld.Part0 = EnemyNPC:FindFirstChild("Left Arm")
weld.Part1 = target.HumanoidRootPart
weld.C1 = CFrame.new(0, -0.2, -2) * CFrame.Angles(math.rad(-90), 0, 0)
weld.Parent = EnemyNPC.HumanoidRootPart
local player = game.Players:GetPlayerFromCharacter(target)
if player then
local closeRemote = game.ReplicatedStorage:FindFirstChild("CloseLocalEffects")
if closeRemote then
closeRemote:FireClient(player)
end
end
FitalityAnimation:Play()
task.wait(FitalityAnimation.Length)
humanoid.WalkSpeed = 0
if EnemyNPC:FindFirstChild("GrabKill") then
EnemyNPC.GrabKill:Play()
end
local humanoid2 = target:FindFirstChild("Humanoid")
if humanoid2 then
humanoid2.EvaluateStateMachine = false
humanoid2.PlatformStand = true
end
for _, part in ipairs(target:GetDescendants()) do
if part:IsA("BasePart") then
part.CanCollide = false
end
end
local head = target:FindFirstChild("Head")
if head and head:FindFirstChild("Neck") then
head.Neck:Destroy()
end
for _, part in ipairs(target:GetDescendants()) do
if part:IsA("BasePart") then
part.CanCollide = true
end
end
if humanoid2 then
humanoid2.EvaluateStateMachine = true
humanoid2.PlatformStand = false
end
weld:Destroy()
target.Humanoid.Health = 0
return
else
target.Humanoid.WalkSpeed = 16
local currentTime = tick()
if currentTime - lastAttackTime >= attackCooldown then
lastAttackTime = currentTime
if not attackAnimation.IsPlaying then
attackAnimation:Play()
end
task.spawn(function()
for i = 0, 1 do
if target and target:FindFirstChild("Humanoid") and target.Humanoid.Health > 0 then
target.Humanoid:TakeDamage(10)
task.wait(1)
else
break
end
end
end)
end
return
end
else
if distance <= 10 then
humanoid:MoveTo(target.HumanoidRootPart.Position)
else
if isPathClearOrJump(target.HumanoidRootPart.Position) then
humanoid:MoveTo(target.HumanoidRootPart.Position)
else
local path = getPath(target.HumanoidRootPart)
if path.Status == Enum.PathStatus.Success then
for _, waypoint in ipairs(path:GetWaypoints()) do
humanoid:MoveTo(waypoint.Position)
humanoid.MoveToFinished:Wait(0.1)
if not canSeeTarget(target) then
break
end
end
end
end
end
end
else
if lastSeenPosition then
humanoid:MoveTo(lastSeenPosition)
lostTargetTimer += 0.5
task.wait(0.5)
if (EnemyNPC.HumanoidRootPart.Position - lastSeenPosition).Magnitude <= 6 then
lastSeenPosition = nil
end
if lostTargetTimer >= maxLostTime then
lastSeenPosition = nil
return
end
else
return
end
end
task.wait(0.1)
end
end
local function walkTo(destination)
local path = getPath(destination)
if path.Status == Enum.PathStatus.Success then
for _, waypoint in ipairs(path:GetWaypoints()) do
local target = findTarget()
if target and target:FindFirstChild("Humanoid") and target.Humanoid.Health > 0 then
task.wait(0.6)
chaseTarget(target)
break
else
local heightDifference = waypoint.Position.Y - EnemyNPC.HumanoidRootPart.Position.Y
if heightDifference > 6 then
if humanoid:GetState() ~= Enum.HumanoidStateType.Jumping then
humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
end
end
humanoid:MoveTo(waypoint.Position)
humanoid.MoveToFinished:Wait()
end
end
else
humanoid:MoveTo(destination.Position - (EnemyNPC.HumanoidRootPart.CFrame.LookVector * 10))
end
end
local function patrol()
local wpList = mapClone:FindFirstChild("waypoint"):GetChildren()
local randomNum = math.random(1, #wpList)
walkTo(wpList[randomNum])
end
humanoid.WalkSpeed = normalSpeed
while true do
task.wait(0.5)
local target = findTarget()
if target and target:FindFirstChild("HumanoidRootPart") and target.Humanoid.Health > 0 then
turnAndPlayAnimation(target)
humanoid.WalkSpeed = chaseSpeed
chaseTarget(target)
else
humanoid.WalkSpeed = normalSpeed
patrol()
end
end
end
return module
Several time later…