Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local Players = game:GetService('Players')
- local module = {}
- local existingNPC = {}
- function module.new(npc)
- if not existingNPC[npc.Name] then
- return module:create(npc)
- end
- return existingNPC[npc.Name]
- end
- function module:create(npc)
- local newNPC = {}
- setmetatable(newNPC, self)
- self.NPC = npc
- self.Name = self.NPC.Name
- self.Root = self.NPC.PrimaryPart
- self.Humanoid = self.NPC:WaitForChild('Humanoid')
- self.Health = self.Humanoid.Health
- self.MaxHealth = self.Humanoid.MaxHealth
- self.TargetChanged = nil
- -- Stats
- self.Visibility = 100
- self.WalkingSpeed = 9
- self.RunningSpeed = 15
- self.ScareFactor = 0.25 -- Determines the health at which it stops attacking in order to heal.
- -- Info
- self.Target = nil
- self.TargetPoints = {}
- self.Distance = 0
- self.Path = nil
- -- Internal
- self.WalkSpeed = self.Humanoid.WalkSpeed
- self.States = {Walking = self.WalkingSpeed, Running = self.RunningSpeed}
- self.State = self.States.Walking
- self.UnusedStateTypes = {
- Enum.HumanoidStateType.Flying,
- Enum.HumanoidStateType.Seated,
- Enum.HumanoidStateType.StrafingNoPhysics,
- Enum.HumanoidStateType.Climbing,
- Enum.HumanoidStateType.Swimming
- }
- function self.CheckDistance(player)
- local character = player.Character or player.CharacterAdded:Wait()
- return math.abs((self.Root.Position - character.PrimaryPart.Position).Magnitude)
- end
- function self.MandateType(object)
- if typeof(object) ~= Vector3 then
- return object.Position
- end
- return object
- end
- function self.GetNearestPlayer()
- local closestDistance = self.Visibility
- local closestPlayer = nil
- for _, player in pairs(Players:GetPlayers()) do
- local dist = self.CheckDistance(player)
- self.TargetPoints[player.Name] = dist
- if dist < closestDistance then
- closestDistance = dist
- closestPlayer = player
- end
- end
- return closestPlayer, closestDistance
- end
- function self.RayCast(thing)
- thing = self.MandateType(thing)
- local ray = Ray.new(self.Root.Position, (thing - self.Root.Position).Unit * (self.Visibility + 10))
- local part, pos = workspace:FindPartOnRay(ray, self.NPC)
- local distance = math.abs((self.Root.Position - pos).Magnitude)
- return part, pos, distance
- end
- function self.AvoidEnemyPosition()
- local targetPos = self.Target.Character.PrimaryPart.Position
- local rand = Random.new():NextNumber(-90, 90)
- local unit = (targetPos - self.Root.Position).Unit
- local angle = math.atan2(-unit.Z, -unit.X) + math.rad(rand)
- local cframe = CFrame.new(self.Root.Position) * CFrame.Angles(0, angle, 0) * CFrame.new(0, 0, -1)
- return (cframe.Position - self.Root.Position).Unit
- end
- function self.Logic()
- -- still doing
- end
- function self.Init()
- self.Target, self.Distance = self.GetNearestPlayer()
- if not self.TargetChanged then
- repeat wait() until self.TargetChanged
- end
- self.TargetChanged:Fire(self.Target)
- end
- function self.Setup()
- coroutine.resume(coroutine.create(function()
- for _, stateType in pairs(self.UnusedStateTypes) do
- self.Humanoid:SetStateEnabled(stateType, false)
- end
- end))
- if not script:FindFirstChild(self.Name .. 'Event') then
- self.TargetChanged = Instance.new('BindableEvent')
- self.TargetChanged.Name = self.Name .. 'Event'
- self.TargetChanged.Parent = script
- end
- -- Update state/walkspeed
- script[self.Name .. 'Event'].Event:Connect(function(target)
- self.State = (not self.Target and self.States.Walking) or self.States.Running
- self.WalkSpeed = self.State
- end)
- end
- existingNPC[self.Name] = self
- self.__tostring = self.Name
- self.__index = self
- self.Setup()
- return self
- end
- return module
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement