Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Either use ConnectionPool Multi-Functional Module
- -- Or Keep the ConnectionPool Simplified Module
- -- Get Rid of .Track and add RemoteMessenger Back.
- -- Delete the GoalPoints Folder in InfoRobots.
- -- By DevGabe
- -- Ragdolls and :Destroy() Cause Major Unnecessary Physics Lag and Delays! I'm Not Using It!
- -- Humanoid Never Dies to Avoid Laggy :Destroy() and Cloning
- -- When Making a New Character Appearance:
- -- * Make Humanoid DisplayDistanceType = "None" So It Hides Real Health
- -- *** Also, Set Humanoid.BreakJointsOnDeath = false
- -- *** You must Add a Happy and Hurt Sound in the Head of the Character.
- -- *** Make All Humanoid Max Health 1000000 with Health 1000000. This is for Fake Death, CFrame Far Away.
- -- *** Hide the Models that you Add, out of the Map in Workspace Before Putting them in Replicated Storage.
- -- * Make RSettings.MaxHealth Their Actual Health. You can Find it Below.
- -- *** (GAME CHANGER OF NO LAG) Finally, Set All the Parts Under the Characters to a Density of .1 (Not Too Low)
- -- and Everything Else to 0 To not Slip in CustomPhysicalProperties
- -- = In the Properties of Each Part. Use 'is:basepart' in Explorer Search Bar to Speed Up the Process.
- -- * Look For Hidden Damage Scripts in the Models from Toolbox.
- -- Press CTRL + F to Find Certain Words
- -- Search StopLoopedSound()
- -- Delete this Function if you Change the TypeOneSwingAnimation
- local Players = game.Players
- local RepStorage = game.ReplicatedStorage
- local Debris = game.Debris
- local PathfindingService = game:GetService("PathfindingService")
- local TweenService = game:GetService("TweenService")
- local ContentProvider = game:GetService("ContentProvider")
- local ObjectCache = require(RepStorage.ObjectCache)
- --local GetNetworkOwnerEvent = RepStorage.GetNetworkOwnerEvent
- local ConnectionPool = require(RepStorage.ConnectionPool)
- local GetIdleAnim = script:WaitForChild("IdleAnimation")
- local GetAttackAnim = script:WaitForChild("AttackAnimation")
- local GetToolNoneAnim = script:WaitForChild("ToolNoneAnimation")
- local GetTypeOneSwingAnim = script:WaitForChild("Swinging"):WaitForChild("TypeOneSwingAnimation")
- local GetTypeTwoSwingAnim = script:WaitForChild("Swinging"):WaitForChild("TypeTwoSwingAnimation")
- -- Storage Robots
- local StorageRobots = RepStorage.StorageRobots
- local StorageModels = StorageRobots.Models
- local Models = StorageModels:GetChildren()
- local GetWeapons = StorageRobots.Weapons
- local CurrentClock = os.clock()
- local M16 = GetWeapons.M16
- local M16Dmg = .1--1
- local M16Firerate = 3
- local M16Range = 50
- local M16RecoilImage = 4
- local M16RightHandOffset = CFrame.new(.6,-1,-.1) * CFrame.Angles(math.rad(180),0,math.rad(-20))
- local M16StopMovingDistanceToFire = 40 -- Stop Moving When Close to Target [With Respect to Gun Range]
- local TrenchShotgun = GetWeapons.TrenchShotgun
- local TrenchShotgunDmg = .1--7
- local TrenchShotgunFirerate = 4
- local TrenchShotgunRange = 40
- local TrenchShotgunRecoilImage = 10
- local TrenchShotgunRightHandOffset = CFrame.new(.2,0,.1) * CFrame.Angles(math.rad(270),math.rad(-20),0)
- local TrenchShotgunStopMovingDistanceToFire = 20
- -- Special Equip
- local FireAxe = GetWeapons.FireAxe
- local FireAxeDmg = .1--4
- local FireAxeFirerate = 2
- local FireAxeRange = 15
- local FireAxeRecoilImage = 10
- local FireAxeRightHandOffset = CFrame.new(0,0,-1) * CFrame.Angles(math.rad(270),math.rad(90),0)
- local FireAxeStopMovingDistanceToFire = 7
- -- Special Equip
- local Pistol = GetWeapons.Pistol
- local PistolDmg = .1--5
- local PistolFirerate = 4
- local PistolRange = 55
- local PistolRecoilImage = 4
- local PistolRightHandOffset = CFrame.new(0,-.4,0) * CFrame.Angles(math.rad(180),0,0)
- local PistolStopMovingDistanceToFire = 45
- local Sniper = GetWeapons.Sniper
- local SniperDmg = .1--10
- local SniperFirerate = 7
- local SniperRange = 90
- local SniperRecoilImage = 8
- local SniperRightHandOffset = CFrame.Angles(math.rad(270),math.rad(-10),0)
- local SniperStopMovingDistanceToFire = 70
- -- Body Gyro Types [Body Gyro Allows Robot To Turn towards Target]
- local ActiveGyro = Vector3.new(math.huge,math.huge,math.huge)
- local InActiveGyro = Vector3.new(0,0,0)
- local Scatter = Random.new()
- local NPCCorpseCaches = {} -- Table for NPC Corpse Body Parts
- local NPCTypeCounts = {} -- Table for Duplicating Count for Each Corpse
- local PathRobots = {} -- Table for Paths and Happy Sound and Sad Sound
- local AllAnimationsTable = {} -- Load Animations Prior
- local CurrentAnimTracksTable = {} -- Track Current Animation
- local StatusForNPCs = {} -- Status For NPCs
- -- Info Robots
- local InfoRobots = workspace:WaitForChild("InfoRobots")
- local AllRobots = InfoRobots:WaitForChild("AllRobots")
- local SpawnPoints = InfoRobots:WaitForChild("SpawnPoints"):GetChildren()
- -- Robot Settings
- local RSettings = {
- ProcessorSpeed = .1; -- Performance Reliance
- TargetSpeed = .25; -- Targetting Speed [With Respect to Smallest Firerate]
- AmountRobots = 35; -- Amount of Robots
- AgroDistance = 100; -- Detection Radius
- MaxPathFindingDistance = 1000; -- Max PathFinding Distance
- HalfGap = 40; -- Move More Precise to Target this Close
- ClosingGap = 25; -- Fluently Move to Target this Close
- RoamWalkSpeed = 12; -- WalkSpeed When Roaming
- AgroWalkSpeed = 18; -- WalkSpeed When Attacking
- NearWaypoint = 10; -- Accept Waypoint if this Close
- UnstuckPower = 40; -- Get Unstuck Leap Power
- CorpseTime = 20; -- Dead Body Time (Time Fade Out Should not be Higher than Corpse Time)
- TimeFadeIn = 1; -- Fade In When Respawning Time
- TimeFadeOut = 2; -- Fade Out When Being Hidden Time
- SearchHuntTime = 10; -- Time to Search for Targets
- HealthRegenAmount = 1; -- Health Regeneration Amount
- HealthRegenSpeed = 1; -- Health Regeneration Speed
- ReplaysHurtAfterRegenAmount = 10; -- Health Regen Amount Needed to Replay Hurt Sound
- NPCMaxHealth = 50; -- NPC Max Health
- DeathSoundID = "rbxassetid://24902294"; -- Death Sound ID
- SecondDeathSoundID = "rbxassetid://24902268";
- ThirdDeathSoundID = ""; -- Quiet
- IdleAnimDelayTime = .5; -- Delay Before Playing Idle Animation
- DistancePlusForNetworkOwnership = 200; -- Distance Plus to Get Network Ownership
- MinWaitZombieSound = 60; -- Min Wait Zombie Sound
- MaxWaitZombieSound = 200; -- Max Wait Zombie Sound
- RoamingRadius = 20; -- Roaming Random Radius
- MinStandStillDoNothing = 1; -- Min Stand Still Do Nothing
- MaxStandStillDoNothing = 15; -- Max Stand Still do Nothing
- }
- -- Stats Names
- local _State = "State"
- local _CurrentWaypoint = "CurrentWaypoint"
- local _LastHealth = "LastHealth"
- local _LastClock = "LastClock"
- local _LastGap = "LastGap"
- local _Strikes = "Strikes"
- local _SwitchStates = "SwitchStates"
- local _SearchHunt = "SearchHunt"
- local _LastSearchTime = "LastSearchTime"
- local _FirstSpawn = "FirstSpawn"
- local _LastHealthRegen = "LastHealthRegen"
- local _sHurtStrikes = "sHurtStrikes"
- local _LastTargetTime = "LastTargetTime"
- local _LastGunFirerate = "LastGunFirerate"
- local _Range = "Range"
- local _Damage = "Damage"
- local _Firerate = "Firerate"
- local _RecoilImage = "RecoilImage"
- local _StopMovingDistanceToFire = "StopMovingDistanceToFire"
- local _CurrentAnim = "CurrentAnim"
- local _FallSpeed = "FallSpeed"
- local _CurrentState = "CurrentState"
- local _IdleAnimDelay = "IdleAnimDelay"
- local _JumpingNow = "JumpingNow"
- local _NPCType = "NPCType"
- local _LastZombieSounds = "ZombieSounds"
- local _DoNothingTime = "DoNothingTime"
- local _ChosenDoNothingTime = "ChosenDoNothingTime"
- -- Robot States
- local Roaming = "Roaming"
- local Hostile = "Hostile"
- local Dead = "Dead"
- local KingFPS = 0
- local LowestDistance = RSettings.MaxPathFindingDistance
- -- Robot Animations R15 (Works with R6 Ids)
- local Animations = {
- idleAnimation = "http://www.roblox.com/asset/?id=507766388",--"http://www.roblox.com/asset/?id=507766666",
- walkAnimation = "http://www.roblox.com/asset/?id=507777826",
- jumpAnimation = "http://www.roblox.com/asset/?id=507765000",
- fallAnimation = "http://www.roblox.com/asset/?id=507767968",
- climbAnimation = "http://www.roblox.com/asset/?id=507765644",
- sitAnimation = "http://www.roblox.com/asset/?id=2506281703",
- }
- local ProjectileTemplate = Instance.new("Part")
- ProjectileTemplate.Name = "Bullet"
- ProjectileTemplate.Anchored = true
- ProjectileTemplate.CanCollide = false
- ProjectileTemplate.BrickColor = BrickColor.Yellow()
- ProjectileTemplate.Material = Enum.Material.Neon
- local MyObjectCache = ObjectCache.new(ProjectileTemplate, RSettings.AmountRobots + 5, workspace)
- -- [[ Storage ]] --
- -- Set Network Owner for NPC's Client Side Kingship from the Best FPS.
- local function SetNetworkOwnerForNPCs(Player, FPS)
- -- Check if Network Owner is Gone
- local CurrentFPSKing
- for i, NPCTable in ipairs(PathRobots) do
- local TargetHumRootPart = NPCTable.GetHumanoidRootPart
- if TargetHumRootPart and TargetHumRootPart.Parent and TargetHumRootPart:CanSetNetworkOwnership() and TargetHumRootPart:GetNetworkOwner() ~= Player then
- if TargetHumRootPart:GetNetworkOwner() ~= nil then
- CurrentFPSKing = true
- end
- end
- end
- if not CurrentFPSKing then
- KingFPS = 0
- end
- if FPS > KingFPS then
- KingFPS = FPS
- local CharHumRootPart = Player.Character and Player.Character:FindFirstChild("HumanoidRootPart")
- if CharHumRootPart then
- local HumRootPartPos = CharHumRootPart.Position
- local Distances = {}
- -- Collect Magnitudes
- for i, NPCTable in ipairs(PathRobots) do
- local TargetHumRootPart = NPCTable.GetHumanoidRootPart
- if TargetHumRootPart and TargetHumRootPart.Parent then
- local Mag = (HumRootPartPos - TargetHumRootPart.Position).Magnitude
- table.insert(Distances, Mag)
- end
- end
- if #Distances > 0 then
- -- Sort Distances
- table.sort(Distances)
- -- Get the Median Index
- local Count = #Distances
- local Result
- if Count % 2 == 1 then -- Odd
- Result = Distances[math.ceil(Count / 2)]
- else -- Even: Average the 2 Middle Numbers to Get the True Median Magnitude
- Result = (Distances[Count / 2] + Distances[(Count / 2) + 1]) / 2
- end
- -- Get a Centered Person for Network Owner Ship
- if Result <= LowestDistance + RSettings.DistancePlusForNetworkOwnership and Result < RSettings.MaxPathFindingDistance then
- LowestDistance = Result
- -- Set Network Owner
- for i, NPCTable in ipairs(PathRobots) do
- local TargetHumRootPart = NPCTable.GetHumanoidRootPart
- if TargetHumRootPart and TargetHumRootPart.Parent and TargetHumRootPart:CanSetNetworkOwnership() and TargetHumRootPart:GetNetworkOwner() ~= Player then
- TargetHumRootPart:SetNetworkOwner(Player)
- end
- end
- end
- end
- end
- end
- end
- ConnectionPool.AddListener("GetNetworkOwner", script, SetNetworkOwnerForNPCs)
- --GetNetworkOwnerEvent.OnServerEvent:Connect(SetNetworkOwnerForNPCs)
- -- Stop All Animations
- local function StopAllAnimations(NPCName)
- if CurrentAnimTracksTable[NPCName] then
- CurrentAnimTracksTable[NPCName]:Stop()
- CurrentAnimTracksTable[NPCName]:Destroy()
- CurrentAnimTracksTable[NPCName] = nil
- end
- end
- -- Play Animation By Name
- local function PlayAnimation(NPC, NPCName, Humanoid, Animator, AnimName)
- if AnimName == StatusForNPCs[NPCName][_CurrentAnim] then return end
- StopAllAnimations(NPCName)
- StatusForNPCs[NPCName][_CurrentAnim] = AnimName
- local FindThisInTable = AllAnimationsTable[NPCName]
- if AllAnimationsTable[NPCName] and AllAnimationsTable[NPCName][AnimName] then
- CurrentAnimTracksTable[NPCName] = Animator:LoadAnimation(AllAnimationsTable[NPCName][AnimName])
- CurrentAnimTracksTable[NPCName]:Play()
- if AnimName == "walkAnimation" and Humanoid.WalkSpeed >= RSettings.AgroWalkSpeed then
- CurrentAnimTracksTable[NPCName]:AdjustSpeed(1) -- Default Animation Speed
- else
- CurrentAnimTracksTable[NPCName]:AdjustSpeed(.5) -- Walking Speed
- end
- end
- end
- -- Get Distance Farthest or Shortest
- local function GetDistance(HumanoidRootPart, Folder, Decision)
- local Result, Other
- local Distance = Decision == "Farthest" and 0 or RSettings.AgroDistance
- for i, v in ipairs(Folder) do
- local Measurement = (HumanoidRootPart.Position - v.Position).Magnitude
- if Decision == "Farthest" and Measurement >= Distance then
- Distance = Measurement
- Result, Other = v, i
- elseif Decision == "Shortest" and Measurement <= Distance then
- Distance = Measurement
- Result, Other = v, Distance
- end
- end
- return Result, Other
- end
- -- Get Closest Player
- local function ClosestPlayer(HumanoidRootPart, GetPlayer)
- local Chosen, Distance
- local AllPlayers = Players:GetPlayers()
- if #AllPlayers ~= 0 then
- local PlyrPositions = {}
- for i, player in ipairs(AllPlayers) do
- local pChar = player.Character
- if pChar then
- local pHumanoid = pChar:FindFirstChild("Humanoid")
- if pHumanoid and pHumanoid.Health > 0 and pHumanoid.RootPart then
- table.insert(PlyrPositions, pHumanoid.RootPart)
- end
- end
- end
- Chosen, Distance = GetDistance(HumanoidRootPart,PlyrPositions,"Shortest")
- end
- if GetPlayer then -- Get Player Object
- return Chosen, Distance
- elseif not Chosen then -- Walk Randomly
- Chosen = HumanoidRootPart.CFrame * CFrame.new(Scatter:NextInteger(-50, 50), 0, Scatter:NextInteger(-50, 50))
- end -- Get Player Position
- return Chosen.Position, Distance
- end
- --(( NPC Functions
- -- Fade In NPC When Respawning or FadeOut NPC When Dead or Make NPC Invisible
- local function FadeNPC(NPC, Time, FadeType)
- for i, v in pairs(NPC:GetDescendants()) do
- if v:IsA("BasePart") and v.Name ~= "HumanoidRootPart" and v.Name ~= "GunFlash" and not v:FindFirstChild("Fire") then
- if FadeType == "Invisible" then
- v.Transparency = 1
- else
- local Fade = TweenService:Create(v,TweenInfo.new(Time),{Transparency = FadeType})
- Fade:Play()
- end
- end
- end
- end
- -- Create NPC
- local function CreateNPC(NPCName, HasNPCTypeName)
- local ClockNow = os.clock()
- local ScatterClock = Random.new(ClockNow)
- local NPC = HasNPCTypeName and StorageModels[HasNPCTypeName]:Clone() or Models[ScatterClock:NextInteger(1,#Models)]:Clone()
- local NPCTypeName = HasNPCTypeName or NPC.Name
- local Head = NPC.Head
- local Humanoid = NPC.Humanoid
- local Animator = Humanoid.Animator
- local HumanoidRootPart = NPC.HumanoidRootPart
- local RightHand = NPC.RightHand
- -- Count For Each NPC Type
- if NPCTypeCounts then
- for Index, NPCModel in pairs(Models) do -- Add Count in Tables
- if NPCModel.Name == NPCTypeName then
- NPCTypeCounts[NPCTypeName] = NPCTypeCounts[NPCTypeName] + 1
- end
- end
- end
- StatusForNPCs[NPCName] = {}
- StatusForNPCs[NPCName][_NPCType] = NPCTypeName -- Save NPC Type
- NPC.Name = NPCName
- Humanoid.MaxHealth = 100000 -- Fake Death = Big Number
- Humanoid.Health = 100000 -- Match Max Health
- Humanoid.WalkSpeed = RSettings.RoamWalkSpeed
- HumanoidRootPart.CFrame = SpawnPoints[ScatterClock:NextInteger(1,#SpawnPoints)].CFrame
- FadeNPC(NPC, nil, "Invisible") -- Make Invisible
- local Path = PathfindingService:CreatePath()
- PathRobots[NPCName] = {MyPath = Path,
- GetHumanoid = Humanoid,
- GetHumanoidRootPart = HumanoidRootPart,
- GetHead = Head,
- GetRightHand = RightHand,
- GetAnimator = Animator,
- sHappy = Head.Happy, sHurt = Head.Hurt}
- StatusForNPCs[NPCName][_State] = Roaming
- StatusForNPCs[NPCName][_LastHealth] = NPC.Humanoid.Health
- StatusForNPCs[NPCName][_Strikes] = 0
- StatusForNPCs[NPCName][_SwitchStates] = true
- StatusForNPCs[NPCName][_LastClock] = ClockNow
- StatusForNPCs[NPCName][_LastGap] = ClockNow
- StatusForNPCs[NPCName][_SearchHunt] = false
- StatusForNPCs[NPCName][_LastSearchTime] = ClockNow
- StatusForNPCs[NPCName][_LastHealthRegen] = ClockNow
- StatusForNPCs[NPCName][_sHurtStrikes] = 0
- StatusForNPCs[NPCName][_LastTargetTime] = ClockNow
- StatusForNPCs[NPCName][_LastGunFirerate] = ClockNow
- StatusForNPCs[NPCName][_CurrentAnim] = "idleAnimation"
- StatusForNPCs[NPCName][_FallSpeed] = 0
- StatusForNPCs[NPCName][_CurrentState] = ""
- StatusForNPCs[NPCName][_JumpingNow] = false
- StatusForNPCs[NPCName][_IdleAnimDelay] = 0
- StatusForNPCs[NPCName][_LastZombieSounds] = ClockNow
- StatusForNPCs[NPCName][_DoNothingTime] = ClockNow
- StatusForNPCs[NPCName][_ChosenDoNothingTime] = 0
- -- Animations
- AllAnimationsTable[NPCName] = {}
- local ArrayAnimTable = {}
- -- Preload Animations
- for AnimName, AnimId in pairs(Animations) do
- local AnimObject = Instance.new("Animation")
- AnimObject.Name = AnimName
- AnimObject.AnimationId = AnimId
- AllAnimationsTable[NPCName][AnimName] = AnimObject
- table.insert(ArrayAnimTable, AnimObject)
- end
- -- Preload Animations
- pcall(function()
- game:GetService("ContentProvider"):PreloadAsync(ArrayAnimTable)
- end)
- ArrayAnimTable = nil
- -- Sounds
- local function NewSound(SoundName, SoundID)
- local GetSound = Instance.new("Sound")
- GetSound.SoundId = SoundID
- GetSound.Name = SoundName
- GetSound.Parent = Head
- return GetSound
- end
- local sGettingUp = NewSound("GettingUp", "rbxasset://sounds/action_get_up.mp3")
- local sFreeFalling = NewSound("FreeFalling", "rbxasset://sounds/action_falling.mp3")
- local sJumping = NewSound("Jumping", "rbxasset://sounds/action_jump.mp3")
- local sLanding = NewSound("Landing", "rbxasset://sounds/action_jump_land.mp3")
- local sSplash = NewSound("Splash", "rbxasset://sounds/impact_water.mp3")
- local sRunning = NewSound("Running", "rbxasset://sounds/action_footsteps_plastic.mp3")
- sRunning.Looped = true
- local sSwimming = NewSound("Swimming", "rbxasset://sounds/action_swim.mp3")
- sSwimming.PlaybackSpeed = 1.6
- sSwimming.Looped = true
- local sClimbing = NewSound("Climbing", "rbxasset://sounds/action_footsteps_plastic.mp3")
- sClimbing.Looped = true
- -- Rotate To Target BodyGyro
- local BodyGyro = Instance.new("BodyGyro")
- BodyGyro.Name = "RotateToTarget"
- BodyGyro.D = 4000
- BodyGyro.P = 300000
- BodyGyro.MaxTorque = InActiveGyro
- BodyGyro.Parent = HumanoidRootPart
- NPC.Parent = AllRobots
- FadeNPC(NPC, RSettings.TimeFadeIn, 0) -- Fade In
- local Weapon
- --[[
- local RandNum = ScatterClock:NextInteger(1, 5)
- if RandNum == 1 then
- -- Weapon
- Weapon = M16:Clone()
- -- Position On Hand
- Weapon.CFrame = RightHand.CFrame * M16RightHandOffset
- -- Stats
- StatusForNPCs[NPCName][_Range] = M16Range
- StatusForNPCs[NPCName][_Damage] = M16Dmg
- StatusForNPCs[NPCName][_Firerate] = M16Firerate
- StatusForNPCs[NPCName][_RecoilImage] = M16RecoilImage
- StatusForNPCs[NPCName][_StopMovingDistanceToFire] = M16StopMovingDistanceToFire
- elseif RandNum == 2 then
- -- Weapon
- Weapon = TrenchShotgun:Clone()
- -- Position On Hand
- Weapon.CFrame = RightHand.CFrame * TrenchShotgunRightHandOffset
- -- Stats
- StatusForNPCs[NPCName][_Range] = TrenchShotgunRange
- StatusForNPCs[NPCName][_Damage] = TrenchShotgunDmg
- StatusForNPCs[NPCName][_Firerate] = TrenchShotgunFirerate
- StatusForNPCs[NPCName][_RecoilImage] = TrenchShotgunRecoilImage
- StatusForNPCs[NPCName][_StopMovingDistanceToFire] = TrenchShotgunStopMovingDistanceToFire
- elseif RandNum == 3 then
- ]]--
- -- Weapon
- Weapon = FireAxe:Clone()
- -- Position On Hand
- Weapon.CFrame = RightHand.CFrame * FireAxeRightHandOffset
- -- Stats
- StatusForNPCs[NPCName][_Range] = FireAxeRange
- StatusForNPCs[NPCName][_Damage] = FireAxeDmg
- StatusForNPCs[NPCName][_Firerate] = FireAxeFirerate
- StatusForNPCs[NPCName][_RecoilImage] = FireAxeRecoilImage
- StatusForNPCs[NPCName][_StopMovingDistanceToFire] = FireAxeStopMovingDistanceToFire
- --[[
- elseif RandNum == 4 then
- -- Weapon
- Weapon = Pistol:Clone()
- -- Position On Hand
- Weapon.CFrame = RightHand.CFrame * PistolRightHandOffset
- -- Stats
- StatusForNPCs[NPCName][_Range] = PistolRange
- StatusForNPCs[NPCName][_Damage] = PistolDmg
- StatusForNPCs[NPCName][_Firerate] = PistolFirerate
- StatusForNPCs[NPCName][_RecoilImage] = PistolRecoilImage
- StatusForNPCs[NPCName][_StopMovingDistanceToFire] = PistolStopMovingDistanceToFire
- elseif RandNum == 5 then
- -- Weapon
- Weapon = Sniper:Clone()
- -- Position On Hand
- Weapon.CFrame = RightHand.CFrame * SniperRightHandOffset
- -- Stats
- StatusForNPCs[NPCName][_Range] = SniperRange
- StatusForNPCs[NPCName][_Damage] = SniperDmg
- StatusForNPCs[NPCName][_Firerate] = SniperFirerate
- StatusForNPCs[NPCName][_RecoilImage] = SniperRecoilImage
- StatusForNPCs[NPCName][_StopMovingDistanceToFire] = SniperStopMovingDistanceToFire
- end
- ]]--
- -- Load Animations
- local function SetGunFlash()
- local GunFlash = Weapon.GunFlash
- PathRobots[NPCName].GunFlash = GunFlash
- PathRobots[NPCName].GunFlashChilds = GunFlash:GetChildren()
- end
- local SetOneAnim, SetTwoAnim
- if Weapon.Name == "FireAxe" then -- Swinging
- SetOneAnim = Animator:LoadAnimation(GetTypeOneSwingAnim)
- SetTwoAnim = Animator:LoadAnimation(GetTypeTwoSwingAnim)
- elseif Weapon.Name == "Pistol" then -- Tool None Anim
- SetOneAnim = Animator:LoadAnimation(GetToolNoneAnim)
- SetGunFlash()
- else
- SetOneAnim = Animator:LoadAnimation(GetIdleAnim)
- SetTwoAnim = Animator:LoadAnimation(GetAttackAnim)
- SetGunFlash()
- end
- PathRobots[NPCName].OneAnim = SetOneAnim
- PathRobots[NPCName].TwoAnim = SetTwoAnim
- PathRobots[NPCName].Weapon = Weapon
- PathRobots[NPCName].sEquip = Weapon.Equip
- PathRobots[NPCName].sFire = Weapon.Fire
- PathRobots[NPCName].sUnequip = Weapon.Unequip
- PathRobots[NPCName].sHitFade = Weapon.HitFade
- PathRobots[NPCName].sSplash = sSplash
- -- Hide Weapon
- Weapon.Transparency = 1
- Weapon.CastShadow = false
- local WeldConstraint = Weapon:FindFirstChild("HoldGun") or Instance.new("WeldConstraint")
- WeldConstraint.Name = "HoldGun"
- WeldConstraint.Part0 = Weapon
- WeldConstraint.Part1 = RightHand
- WeldConstraint.Parent = Weapon
- Weapon.Parent = NPC
- end
- -- Get Unstuck by Leaping Forward
- local function GetUnstuck(NPCName, Humanoid, HumanoidRootPart)
- -- warn("Getting Unstuck: ", Humanoid.Parent.Name)
- Humanoid.Jump = true
- StatusForNPCs[NPCName][_JumpingNow] = true
- task.wait(.25)
- HumanoidRootPart.Velocity = HumanoidRootPart.CFrame.LookVector * RSettings.UnstuckPower
- end
- local rayLength = -100
- -- Cast Ray Down to Hit Ground and Ignore Players
- local function CastAtOffset(originVector, offsetX, offsetZ)
- local CastParams = RaycastParams.new()
- CastParams.FilterType = Enum.RaycastFilterType.Exclude
- -- Ignore All Players and NPCs
- local IgnoreList = {}
- for i, ObjectCache in pairs(workspace:GetChildren()) do
- if ObjectCache.Name == "ObjectCache" then
- table.insert(IgnoreList, ObjectCache)
- end
- end
- for i, GetNPC in pairs(AllRobots:GetChildren()) do
- table.insert(IgnoreList, GetNPC)
- end
- for i, GetPlayer in pairs(Players:GetPlayers()) do
- if GetPlayer.Character then
- table.insert(IgnoreList, GetPlayer.Character)
- end
- end
- --CastParams.FilterDescendantsInstances = IgnoreList
- CastParams:AddToFilter(IgnoreList)
- -- Shift the Starting X and Z Spots While Keeping a Safe High Y Start
- local RayOrigin = Vector3.new(originVector.X + offsetX, originVector.Y, originVector.Z + offsetZ)
- local RayDirection = Vector3.new(0, rayLength, 0)
- local Result = workspace:Raycast(RayOrigin, RayDirection, CastParams)
- return Result
- end
- -- Detect On Death
- local function OnDeath(NPC, NPCName, Humanoid, Head)
- Humanoid.BreakJointsOnDeath = false
- -- NPC Corpse Cache: Reveal Corpse and Hide Real NPC
- local Corpse
- local NPCType = StatusForNPCs[NPCName][_NPCType]
- if Humanoid.RootPart then
- Corpse = NPCCorpseCaches[NPCType]:GetPart(Humanoid.RootPart.CFrame)
- Corpse.AssemblyLinearVelocity = Vector3.zero
- Corpse.AssemblyAngularVelocity = Vector3.zero
- Corpse.DiedSound:Play() -- Play Death Sound
- local BasePartsTaken = {}
- -- Make Corpse Fall Apart While Anchored
- for i, BasePart in pairs(Corpse.Parent:GetDescendants()) do
- if BasePart:IsA("BasePart") and BasePart.Name ~= "HumanoidRootPart" and not table.find(BasePartsTaken, BasePart) then
- table.insert(BasePartsTaken, BasePart)
- BasePart.Transparency = 0
- BasePart.CastShadow = true
- local NewPos = Corpse.Position
- if NPC:FindFirstChild(BasePart.Name) then
- BasePart.CFrame = NPC[BasePart.Name].CFrame
- NewPos = NPC[BasePart.Name].Position
- end
- local HitSpot = CastAtOffset(NewPos, Scatter:NextInteger(-5, 5), Scatter:NextInteger(-5, 5))
- if HitSpot then
- local function SlowlyMoveCorpseParts()
- for Index = 0, 1, 0.2 do
- BasePart.Position = NewPos:Lerp(HitSpot.Position, Index)
- task.wait(.01)
- end
- end
- task.spawn(SlowlyMoveCorpseParts)
- else
- BasePart.Transparency = 1
- BasePart.CastShadow = false
- end
- end
- end
- BasePartsTaken = nil
- -- Hide Real NPC
- Humanoid.RootPart.Anchored = true
- Humanoid.RootPart.CFrame = Humanoid.RootPart.CFrame * CFrame.new(0, 100000, 0)
- end
- -- Stop All Sounds and Play Death Sound
- if Head and Head.Parent then
- for _,Child in pairs(Head:GetChildren())do
- if Child and Child.ClassName == "Sound" then
- if Child.Name == "Died" then
- Child:Play()
- elseif Child.Name ~= "Landed" then
- Child:Stop()
- end
- end
- end
- end
- task.wait(RSettings.CorpseTime - RSettings.TimeFadeOut)
- if Corpse then
- FadeNPC(Corpse.Parent, RSettings.TimeFadeOut, 1) -- Fade Out
- task.wait(RSettings.TimeFadeOut)
- for i, BasePart in pairs(Corpse.Parent:GetDescendants()) do
- if BasePart:IsA("BasePart") then
- BasePart.Transparency = 1
- BasePart.CastShadow = false
- end
- end
- NPCCorpseCaches[NPCType]:ReturnPart(Corpse)
- else
- task.wait(RSettings.TimeFadeOut)
- end
- -- Respawn NPC
- if #AllRobots:GetChildren() <= RSettings.AmountRobots then
- -- Revive NPC
- if Humanoid.RootPart then
- -- Hide Weapon
- local Weapon = PathRobots[NPCName].Weapon
- --Weapon.Transparency = 1
- --Weapon.CastShadow = false
- Humanoid.Health = Humanoid.MaxHealth
- StatusForNPCs[NPCName][_State] = Roaming
- Humanoid.RootPart.Anchored = false
- Humanoid.RootPart.CFrame = SpawnPoints[Random.new(os.clock()):NextInteger(1,#SpawnPoints)].CFrame
- FadeNPC(NPC, nil, "Invisible") -- Make Invisible
- FadeNPC(NPC, RSettings.TimeFadeIn, 0) -- Fade In
- else -- If NPC is Missing from 'Void' then Respawn NPC
- NPC:Destroy()
- -- Clear Tables
- local HasNPCType = StatusForNPCs[NPCName][_NPCType]
- PathRobots[NPCName] = nil
- StatusForNPCs[NPCName] = nil
- AllAnimationsTable[NPCName] = nil
- CurrentAnimTracksTable[NPCName] = nil
- CreateNPC(NPCName, HasNPCType)
- end
- end
- end
- --))
- --(( PathFinding Functions
- -- Get Random Waypoint from NPC Position
- local function NewGoalpoint(NPCName, Humanoid, HumanoidRootPart)
- if Humanoid.WalkSpeed <= 0 then return end
- -- Stand Still and Do Nothing for Random Time
- if CurrentClock - StatusForNPCs[NPCName][_DoNothingTime] >= StatusForNPCs[NPCName][_ChosenDoNothingTime] then
- StatusForNPCs[NPCName][_DoNothingTime] = CurrentClock
- StatusForNPCs[NPCName][_ChosenDoNothingTime] = Scatter:NextInteger(RSettings.MinStandStillDoNothing, RSettings.MaxStandStillDoNothing)
- else -- Do Nothing
- return
- end
- -- Get Random Point In Circle
- local CenterPosition = HumanoidRootPart.Position
- local Radius = math.sqrt(Scatter:NextNumber()) * RSettings.RoamingRadius
- local Angle = Scatter:NextNumber(0, math.pi * 2)
- local X = CenterPosition.X + Radius * math.cos(Angle)
- local Z = CenterPosition.Z + Radius * math.sin(Angle)
- -- Random Position
- local BasePosition = Vector3.new(X, CenterPosition.Y + Scatter:NextNumber(-RSettings.RoamingRadius, RSettings.RoamingRadius), Z)
- -- Go Up 100 Studs
- local RayOrigin = BasePosition + Vector3.new(0, 100, 0)
- -- Ignore All Robots When Casting Ray
- local RaycastParamsInstance = RaycastParams.new()
- RaycastParamsInstance.FilterDescendantsInstances = AllRobots:GetChildren()
- RaycastParamsInstance.FilterType = Enum.RaycastFilterType.Exclude
- -- Starts at 0, ends at 40, Increments by 2 Each Time Creating a Cone Direction Down.
- for i = 0, 40, 2 do
- -- Randomly Choose 1 or -1 for X and Z Directions
- local SignX = (Scatter:NextInteger(1, 2) == 1) and 1 or -1
- local SignZ = (Scatter:NextInteger(1, 2) == 1) and 1 or -1
- -- Cast Ray 200 Studs Down with Spread
- local RayDirection = Vector3.new(i * SignX, -200, i * SignZ)
- -- Perform the Raycast
- local RaycastResult = workspace:Raycast(RayOrigin, RayDirection, RaycastParamsInstance)
- -- Return the Hit Ground Position or Original Base Position
- if RaycastResult then
- return RaycastResult.Position
- end
- end
- return BasePosition
- end
- -- New Path
- local function NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, DestinationPos)
- if not DestinationPos or Humanoid.WalkSpeed <= 0 then --[[warn("Destination Not Found")]] return end
- local Path = PathRobots[NPCName].MyPath
- -- Target Walk Towards Without PathFinding
- local function TargetWithoutPathFinding(Target)
- Humanoid:MoveTo(Target) -- Move Without PathFinding.
- if (HumanoidRootPart.Velocity.Magnitude < 0.5) then -- Not Moving.
- task.spawn(GetUnstuck, NPCName, Humanoid, HumanoidRootPart)
- end
- end
- -- Move Without PathFinding
- local function MoveWithoutPathFinding()
- warn("Path Failed: "..NPCName)
- local EnemyRootPart = ClosestPlayer(HumanoidRootPart, true)
- if EnemyRootPart then
- TargetWithoutPathFinding(EnemyRootPart.Position)
- else
- local Target = ClosestPlayer(HumanoidRootPart)
- if Target then
- TargetWithoutPathFinding(Target)
- end
- end
- end
- -- On Path Compute
- local function OnPathCompute()
- if not DestinationPos then return end
- local Distance = (DestinationPos - HumanoidRootPart.Position).Magnitude
- if Distance < RSettings.MaxPathFindingDistance then
- Path:ComputeAsync(HumanoidRootPart.Position, DestinationPos)
- if Path.Status == Enum.PathStatus.Success then
- local Waypoints = Path:GetWaypoints()
- if Waypoints[1] then
- StatusForNPCs[NPCName][_CurrentWaypoint] = 1
- Humanoid:MoveTo(Waypoints[1].Position)
- else
- StatusForNPCs[NPCName][_CurrentWaypoint] = nil
- end
- else
- MoveWithoutPathFinding()
- end
- else -- Too Far.
- MoveWithoutPathFinding()
- end
- end
- task.spawn(OnPathCompute)
- end
- -- Reset Waypoint
- local function ResetWaypoint(NPC, NPCName, Humanoid, HumanoidRootPart)
- if Humanoid.WalkSpeed <= 0 then return end
- local newWaypoint
- local MyState = StatusForNPCs[NPCName][_State]
- if MyState == Roaming then
- newWaypoint = NewGoalpoint(NPCName, Humanoid, HumanoidRootPart)
- elseif MyState == Hostile then
- newWaypoint = ClosestPlayer(HumanoidRootPart)
- end
- NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, newWaypoint)
- StatusForNPCs[NPCName][_Strikes] = 0
- end
- -- On Waypoint Completed
- local function OnWaypointCompleted(NPC, NPCName, Humanoid, HumanoidRootPart, Waypoints)
- if Humanoid.WalkSpeed <= 0 then return end
- local IdxCurrent = StatusForNPCs[NPCName][_CurrentWaypoint]
- if IdxCurrent then
- if IdxCurrent < #Waypoints then -- Next Waypoint
- local NewIdx = IdxCurrent + 1
- StatusForNPCs[NPCName][_CurrentWaypoint] = NewIdx
- local NextWaypoint = Waypoints[NewIdx]
- if NextWaypoint.Action == Enum.PathWaypointAction.Jump then
- Humanoid.Jump = true
- StatusForNPCs[NPCName][_JumpingNow] = true
- end
- Humanoid:MoveTo(NextWaypoint.Position)
- StatusForNPCs[NPCName][_Strikes] = 0
- else -- Completed All Waypoints
- ResetWaypoint(NPC, NPCName, Humanoid, HumanoidRootPart)
- end
- end
- end
- -- Play One Sound
- local function PlayOneSound(SoundName, Head)
- local GetSound
- for _, Child in pairs(Head:GetChildren()) do
- if Child and Child.ClassName == "Sound" then
- if Child.Name == SoundName then
- Child:Play()
- GetSound = Child
- elseif Child.Name ~= "Landing" then
- Child:Stop()
- end
- end
- end
- return GetSound
- end
- --))
- -- [[ Connections ]] --
- for i, NPCModel in pairs(Models) do -- Define Tables
- NPCTypeCounts[NPCModel.Name] = 0
- end
- for i = 1, RSettings.AmountRobots do
- CreateNPC(i.."-AI")
- task.wait(.1) -- For proper randomization seeds
- end
- for i, NPCModel in pairs(Models) do -- Create Cache for Each NPC Type
- local FakeCorpse = NPCModel:Clone()
- FakeCorpse.Humanoid:Destroy()
- local DeathSound = Instance.new("Sound")
- local ChosenDeathID
- local GetRandomSound = Scatter:NextInteger(1, 3)
- if GetRandomSound == 1 then
- ChosenDeathID = RSettings.DeathSoundID
- elseif GetRandomSound == 2 then
- ChosenDeathID = RSettings.SecondDeathSoundID
- else
- ChosenDeathID = RSettings.ThirdDeathSoundID
- end
- DeathSound.SoundId = ChosenDeathID
- DeathSound.Name = "DiedSound"
- DeathSound.Volume = 1
- DeathSound.Parent = FakeCorpse.PrimaryPart
- for i, BasePart in pairs(FakeCorpse:GetDescendants()) do
- if BasePart:IsA("BasePart") then
- BasePart.Anchored = true
- BasePart.CanCollide = false
- end
- end
- NPCCorpseCaches[NPCModel.Name] = ObjectCache.new(FakeCorpse, NPCTypeCounts[NPCModel.Name] + 3, workspace)
- end
- NPCTypeCounts = nil
- -- Update All Robot Status
- local function AddToConnectionPool()
- CurrentClock = os.clock()
- for i, NPC in pairs(AllRobots:GetChildren()) do
- local NPCName = NPC.Name
- local LastHealth = StatusForNPCs[NPCName][_LastHealth]
- -- Path
- local Waypoints = PathRobots[NPCName].MyPath:GetWaypoints()
- local CurrentWaypointIndex = StatusForNPCs[NPCName][_CurrentWaypoint]
- -- Reoccuring Values
- local State = StatusForNPCs[NPCName][_State]
- local SwitchStates = StatusForNPCs[NPCName][_SwitchStates]
- local Strikes = StatusForNPCs[NPCName][_Strikes]
- local sHurtStrikes = StatusForNPCs[NPCName][_sHurtStrikes]
- local Humanoid = PathRobots[NPCName].GetHumanoid
- local HumanoidRootPart = PathRobots[NPCName].GetHumanoidRootPart
- local Head = PathRobots[NPCName].GetHead
- local Animator = PathRobots[NPCName].GetAnimator
- if Humanoid and Humanoid.Parent and HumanoidRootPart and HumanoidRootPart.Parent and Head and Head.Parent and Animator and Animator.Parent then
- local HealthNow = Humanoid.Health
- if HealthNow > 0 and RSettings.NPCMaxHealth - (Humanoid.MaxHealth - HealthNow) > 0 then
- -- Zombie Sounds
- if CurrentClock - StatusForNPCs[NPCName][_LastZombieSounds] >= Scatter:NextInteger(RSettings.MinWaitZombieSound, RSettings.MaxWaitZombieSound) then
- StatusForNPCs[NPCName][_LastZombieSounds] = CurrentClock
- local ChooseOne = Scatter:NextInteger(1, 2)
- if ChooseOne == 1 then
- local sHappy = PathRobots[NPCName].sHappy
- if sHappy and sHappy.Parent and not sHappy.IsPlaying then
- sHappy:Play()
- end
- else
- local sHurt = PathRobots[NPCName].sHurt
- if sHurt and sHurt.Parent and sHurt.IsPlaying then
- sHurt:Play()
- end
- end
- end
- -- Track Animations and Sounds
- local HumanoidState = Humanoid:GetState()
- local StateSpeed = HumanoidRootPart.AssemblyLinearVelocity.Magnitude
- if StatusForNPCs[NPCName][_JumpingNow] then
- StatusForNPCs[NPCName][_JumpingNow] = false
- PlayAnimation(NPC, NPCName, Humanoid, Animator, "jumpAnimation")
- -- Jumping Sound
- local JumpingSound = PlayOneSound("Jumping", Head)
- end
- local IsFallingState = (HumanoidState == Enum.HumanoidStateType.FallingDown or HumanoidState == Enum.HumanoidStateType.Freefall)
- if IsFallingState and StatusForNPCs[NPCName][_CurrentState] ~= "FallingDown" then
- StatusForNPCs[NPCName][_CurrentState] = "FallingDown"
- local IsMovingDownward = Head.AssemblyLinearVelocity.Y < -5 -- Detects true downward falling
- if IsMovingDownward then
- PlayAnimation(NPC, NPCName, Humanoid, Animator, "fallAnimation")
- -- Free Falling Sound Setup
- local FreeFallingSound = PlayOneSound("FreeFalling", Head)
- FreeFallingSound.Volume = 0
- local ElapsedTime = 0
- local SoundConnection
- if StatusForNPCs[NPCName]["SoundConnection"] then
- StatusForNPCs[NPCName]["SoundConnection"]:Disconnect()
- StatusForNPCs[NPCName]["SoundConnection"] = nil
- end
- StatusForNPCs[NPCName]["SoundConnection"] = ConnectionPool.Track(script, function(DT)
- ElapsedTime = ElapsedTime + DT
- -- Linear volume fade calculations
- local Vol = math.clamp(ElapsedTime - 0.3, 0, 1)
- if FreeFallingSound and FreeFallingSound.Parent then
- FreeFallingSound.Volume = Vol
- end
- -- Automatically clean up the task once 1.5 seconds passes
- if ElapsedTime >= 1.5 then
- StatusForNPCs[NPCName]["SoundConnection"]:Disconnect()
- end
- end)
- -- Tracks maximum falling speed using modern AssemblyLinearVelocity
- StatusForNPCs[NPCName][_FallSpeed] = math.max(StatusForNPCs[NPCName][_FallSpeed], math.abs(Head.AssemblyLinearVelocity.Y))
- end
- elseif HumanoidState == Enum.HumanoidStateType.Swimming and StatusForNPCs[NPCName][_CurrentState] ~= "Swimming" then -- Swimming
- StatusForNPCs[NPCName][_CurrentState] = "Swimming"
- PlayAnimation(NPC, NPCName, Humanoid, Animator, "walkAnimation")
- if StateSpeed > .1 then
- local Vol = math.min(1.0, StateSpeed / 350)
- local SplashSound = PathRobots[NPCName].sSplash
- if SplashSound and SplashSound.Parent then
- SplashSound.Volume = Vol
- SplashSound:Play()
- end
- end
- local SwimmingSound = PlayOneSound("Swimming", Head)
- elseif HumanoidState == Enum.HumanoidStateType.Landed then -- Landed
- if StatusForNPCs[NPCName][_FallSpeed] > .1 then
- local Vol = math.min(1.0, math.max(0.0, (StatusForNPCs[NPCName][_FallSpeed] - 50) / 110))
- local sLanding = PathRobots[NPCName].sLanding
- if sLanding and sLanding.Parent then
- sLanding.Volume = Vol
- sLanding:Play()
- end
- StatusForNPCs[NPCName][_FallSpeed] = 0
- end
- elseif HumanoidState == Enum.HumanoidStateType.Running or HumanoidState == Enum.HumanoidStateType.None then -- Running
- if StateSpeed > 0.2 and StatusForNPCs[NPCName][_CurrentState] ~= "Running" and Humanoid.WalkSpeed > 0 then
- StatusForNPCs[NPCName][_CurrentState] = "Running"
- StatusForNPCs[NPCName][_IdleAnimDelay] = CurrentClock
- PlayAnimation(NPC, NPCName, Humanoid, Animator, "walkAnimation")
- -- Running Sound
- local RunningSound = PlayOneSound("Running", Head)
- RunningSound.Pitch = StateSpeed / 8
- elseif StateSpeed <= 0.2 and StatusForNPCs[NPCName][_CurrentState] ~= "Idle" and CurrentClock - StatusForNPCs[NPCName][_IdleAnimDelay] >= RSettings.IdleAnimDelayTime then -- Idle
- StatusForNPCs[NPCName][_CurrentState] = "Idle"
- StatusForNPCs[NPCName][_IdleAnimDelay] = CurrentClock
- PlayAnimation(NPC, NPCName, Humanoid, Animator, "idleAnimation")
- -- No Sound
- PlayOneSound("", Head)
- end
- elseif HumanoidState == Enum.HumanoidStateType.Climbing then -- Climbing
- if math.abs(StateSpeed) > 0.2 then
- if StatusForNPCs[NPCName][_CurrentState] ~= "Climbing" then
- StatusForNPCs[NPCName][_CurrentState] = "Climbing"
- PlayAnimation(NPC, NPCName, Humanoid, Animator, "climbAnimation")
- -- Climbing Sound
- if StateSpeed > .01 then
- local ClimbingSound = PlayOneSound("Climbing", Head)
- ClimbingSound.PlaybackSpeed = StateSpeed / 5.5
- else
- PlayOneSound("", Head)
- end
- elseif CurrentAnimTracksTable[NPCName] then
- CurrentAnimTracksTable[NPCName]:AdjustSpeed(1)
- end
- elseif CurrentAnimTracksTable[NPCName] then
- CurrentAnimTracksTable[NPCName]:AdjustSpeed(0)
- end
- elseif HumanoidState == Enum.HumanoidStateType.Seated and StatusForNPCs[NPCName][_CurrentState] ~= "Seated" then -- Seated
- StatusForNPCs[NPCName][_CurrentState] = "Seated"
- PlayAnimation(NPC, NPCName, Humanoid, Animator, "sitAnimation")
- elseif HumanoidState == Enum.HumanoidStateType.GettingUp then -- Getting Up
- local GettingUpSound = PlayOneSound("GettingUp", Head)
- end
- -- Checks If Velocity Has Gone Below 0.5 (Not Moving and Not Close to Target)
- if StatusForNPCs[NPCName][_State] == Hostile then
- if (HumanoidRootPart.Velocity.Magnitude < 0.5) and Humanoid.WalkSpeed > 0 then
- Strikes += 1
- if Strikes <= 25 and CurrentClock - StatusForNPCs[NPCName][_LastClock] >= 3 then
- StatusForNPCs[NPCName][_LastClock] = CurrentClock
- Humanoid.Jump = true
- StatusForNPCs[NPCName][_JumpingNow] = true
- if Waypoints then
- OnWaypointCompleted(NPC, NPCName, Humanoid, HumanoidRootPart, Waypoints)
- end
- elseif Strikes > 25 then
- StatusForNPCs[NPCName][_LastClock] = CurrentClock
- Strikes = 0
- task.spawn(GetUnstuck, NPCName, Humanoid, HumanoidRootPart)
- ResetWaypoint(NPC, NPCName, Humanoid, HumanoidRootPart)
- end
- StatusForNPCs[NPCName][_Strikes] = Strikes
- end
- else -- Roaming
- Strikes = 0
- StatusForNPCs[NPCName][_Strikes] = 0
- StatusForNPCs[NPCName][_LastClock] = CurrentClock
- end
- -- Custom MoveToFinished Indicator
- if Waypoints and #Waypoints > 0 and CurrentWaypointIndex and Waypoints[CurrentWaypointIndex] and HumanoidRootPart then
- local Finishwaypoint = (HumanoidRootPart.Position - Waypoints[CurrentWaypointIndex].Position).Magnitude
- if Finishwaypoint <= RSettings.NearWaypoint then
- OnWaypointCompleted(NPC, NPCName, Humanoid, HumanoidRootPart, Waypoints)
- end
- end
- -- Health Regen if Not MaxHealth
- if HealthNow < Humanoid.MaxHealth and CurrentClock - StatusForNPCs[NPCName][_LastHealthRegen] >= RSettings.HealthRegenSpeed then
- StatusForNPCs[NPCName][_LastHealthRegen] = CurrentClock
- StatusForNPCs[NPCName][_sHurtStrikes] = StatusForNPCs[NPCName][_sHurtStrikes] + 1
- Humanoid.Health += RSettings.HealthRegenAmount
- if Humanoid.Health >= Humanoid.MaxHealth then -- Reached Max Health
- PathRobots[NPCName].sHappy:Play()
- end
- end
- -- Patrol
- local EnemyRootPart, Distance = ClosestPlayer(HumanoidRootPart, true)
- if Distance and Distance <= RSettings.AgroDistance or HealthNow < LastHealth then -- Harm Found
- if State ~= Dead then
- StatusForNPCs[NPCName][_State] = Hostile
- end
- StatusForNPCs[NPCName][_SearchHunt] = true
- StatusForNPCs[NPCName][_LastSearchTime] = CurrentClock
- if HealthNow < LastHealth and StatusForNPCs[NPCName][_sHurtStrikes] >= RSettings.ReplaysHurtAfterRegenAmount then -- Damage Taken
- StatusForNPCs[NPCName][_sHurtStrikes] = 0
- PathRobots[NPCName].sHurt:Play()
- end
- if Distance then
- if Distance > 15 then -- Not Right next to Target
- local LastGap = StatusForNPCs[NPCName][_LastGap]
- if Distance <= RSettings.ClosingGap and CurrentClock - LastGap >= 1
- or Distance <= RSettings.HalfGap and CurrentClock - LastGap >= 2 then -- Move more Fluently near Target
- StatusForNPCs[NPCName][_LastGap] = CurrentClock
- ResetWaypoint(NPC, NPCName, Humanoid, HumanoidRootPart)
- end
- end
- -- Attack
- if CurrentClock - StatusForNPCs[NPCName][_LastTargetTime] >= RSettings.TargetSpeed and EnemyRootPart then
- StatusForNPCs[NPCName][_LastTargetTime] = CurrentClock
- local RightHand = PathRobots[NPCName].GetRightHand
- if RightHand and RightHand.Parent then -- Give Weapon
- local Weapon = PathRobots[NPCName].Weapon
- local GunFlash = PathRobots[NPCName].GunFlash
- local GunFlashChilds = PathRobots[NPCName].GunFlashChilds
- -- Animations
- local OneAnim = PathRobots[NPCName].OneAnim
- local TwoAnim = PathRobots[NPCName].TwoAnim
- -- Rotate To Target BodyGyro
- local BodyGyro = HumanoidRootPart.RotateToTarget
- -- Stop Moving When Too Close To Target
- if Distance <= StatusForNPCs[NPCName][_StopMovingDistanceToFire] then
- if Humanoid.WalkSpeed ~= 0 then
- Humanoid.WalkSpeed = 0
- end
- elseif Humanoid.WalkSpeed ~= RSettings.AgroWalkSpeed then
- Humanoid.WalkSpeed = RSettings.AgroWalkSpeed
- end
- if Distance <= StatusForNPCs[NPCName]["Range"] then
- -- Create A Ray so NPC Can't Attack Through Walls
- local RayParams = RaycastParams.new()
- RayParams.FilterDescendantsInstances = {NPC}
- RayParams.FilterType = Enum.RaycastFilterType.Exclude
- local Result = workspace:Raycast(HumanoidRootPart.Position, (EnemyRootPart.Position - HumanoidRootPart.Position).Unit * 500, RayParams)
- local TargetModel = EnemyRootPart.Parent
- if Result and Result.Instance and Result.Instance:IsDescendantOf(TargetModel) then
- local MyPosition = HumanoidRootPart.Position
- -- Turn Body To Face Target
- BodyGyro.MaxTorque = ActiveGyro
- BodyGyro.CFrame = CFrame.lookAt(MyPosition, EnemyRootPart.Position)
- -- Check if Correctly Facing Target to Attack Considering Firerate
- local FaceofMyCharacter = (EnemyRootPart.Position - MyPosition).Unit -- Unit Converts Numbers to Vector3
- local DotProduct = FaceofMyCharacter:Dot(HumanoidRootPart.CFrame.LookVector) -- Gets the Orientation from 1, the Players Look Direction to -1, Behind the Head
- -- Consider Last Gun Firerate
- if DotProduct > .95 and CurrentClock - StatusForNPCs[NPCName][_LastGunFirerate] >= StatusForNPCs[NPCName][_Firerate] then -- I am Facing Target
- StatusForNPCs[NPCName][_LastGunFirerate] = CurrentClock
- PathRobots[NPCName].sFire:Play()
- -- Attack Animation
- if Weapon.Name == "FireAxe" then
- local RandNum = Scatter:NextInteger(1, 2)
- if RandNum == 1 then
- if not PathRobots[NPCName].OneAnim.IsPlaying then
- PathRobots[NPCName].OneAnim:Play()
- local function StopLoopedSound()
- PathRobots[NPCName].OneAnim:Stop()
- end
- task.delay(Scatter:NextInteger(1, 3), StopLoopedSound)
- OneAnim:Play()
- end
- else
- TwoAnim:Play()
- end
- elseif Weapon.Name ~= "Pistol" then
- TwoAnim:Play()
- end
- -- Enable Gun Flash
- if GunFlashChilds then
- for i, emit in ipairs(GunFlashChilds) do
- emit.Enabled = true
- end
- end
- -- Apply Recoil
- BodyGyro.CFrame = CFrame.lookAt(MyPosition - Vector3.new(0, StatusForNPCs[NPCName]["RecoilImage"], 0), EnemyRootPart.Position)
- -- Set Up Projectile
- local Projectile
- if Weapon.Name ~= "FireAxe" and GunFlash then
- local toTarget = EnemyRootPart.Position - GunFlash.Position
- Projectile = MyObjectCache:GetPart(CFrame.new(GunFlash.Position + toTarget / 1.9, GunFlash.Position))
- local BulletWidth = Weapon.Name == "TrenchShotgun" and .6 or .1
- Projectile.Size = Vector3.new(BulletWidth,BulletWidth,Distance)
- elseif Weapon.Name == "FireAxe" then
- Weapon.SlashTrail.Enabled = true
- local function DisableSlashTrail()
- Weapon.SlashTrail.Enabled = false
- end
- task.delay(.25, DisableSlashTrail)
- end
- -- Apply Damage
- local HasHumanoid = TargetModel:FindFirstChild("Humanoid")
- if HasHumanoid then
- HasHumanoid:TakeDamage(StatusForNPCs[NPCName]["Damage"])
- -- Hit Sound
- local NewHitFade = PathRobots[NPCName].sHitFade:Clone()
- Debris:AddItem(NewHitFade,NewHitFade.TimeLength + 1)
- NewHitFade.Parent = EnemyRootPart
- NewHitFade:Play()
- end
- local function HideProjectile()
- -- Return Projectile
- if Weapon.Name ~= "FireAxe" and Projectile then
- MyObjectCache:ReturnPart(Projectile)
- end
- -- Disable GunFlash
- if GunFlashChilds then
- for i, emit in ipairs(GunFlashChilds) do
- emit.Enabled = false
- end
- end
- end
- task.delay(.2, HideProjectile)
- end
- end
- else -- No Enemy to Target
- BodyGyro.MaxTorque = InActiveGyro
- end
- end
- end
- end
- elseif StatusForNPCs[NPCName][_SearchHunt] == true then -- Search Curiously
- if (HumanoidRootPart.Velocity.Magnitude < 0.5) and Waypoints and #Waypoints <= 0 and StatusForNPCs[NPCName][_CurrentWaypoint] and StatusForNPCs[NPCName][_CurrentWaypoint] >= #Waypoints then -- Not Moving and Completed All Waypoints.
- if EnemyRootPart then -- Found Enemy
- NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, EnemyRootPart.Position)
- else
- local Target = ClosestPlayer(HumanoidRootPart)
- if Target then
- NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, Target)
- end
- end
- end
- if CurrentClock - StatusForNPCs[NPCName][_LastSearchTime] > RSettings.SearchHuntTime then -- Search Time
- StatusForNPCs[NPCName][_SearchHunt] = false
- end
- elseif State ~= Dead then -- No Harm Found
- StatusForNPCs[NPCName][_State] = Roaming
- end
- -- Reaction
- if State == Hostile and not SwitchStates then
- StatusForNPCs[NPCName][_SwitchStates] = true
- Humanoid.WalkSpeed = RSettings.AgroWalkSpeed
- local Target, Distance = ClosestPlayer(HumanoidRootPart)
- if Target then
- NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, Target)
- end
- -- Play Idle Anim
- local Weapon = PathRobots[NPCName].Weapon
- if Weapon.Name ~= "FireAxe" then
- PathRobots[NPCName].OneAnim:Play()
- end
- PathRobots[NPCName].sEquip:Play()
- -- Show Weapon
- --Weapon.Transparency = 0
- --Weapon.CastShadow = true
- elseif State == Roaming and SwitchStates then
- StatusForNPCs[NPCName][_SwitchStates] = false
- Humanoid.WalkSpeed = RSettings.RoamWalkSpeed
- local Destination = NewGoalpoint(NPCName, Humanoid, HumanoidRootPart)
- NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, Destination)
- -- Hide Weapon
- local Weapon = PathRobots[NPCName].Weapon
- Weapon.Transparency = 1
- Weapon.CastShadow = false
- if StatusForNPCs[NPCName][_FirstSpawn] then
- local Weapon = PathRobots[NPCName].Weapon
- if Weapon.Name ~= "FireAxe" then
- PathRobots[NPCName].OneAnim:Stop()
- end
- HumanoidRootPart.RotateToTarget.MaxTorque = InActiveGyro
- PathRobots[NPCName].sUnequip:Play()
- end
- StatusForNPCs[NPCName][_FirstSpawn] = true
- end
- StatusForNPCs[NPCName][_LastHealth] = HealthNow
- elseif State ~= Dead then -- Dead
- -- print(StatusForNPCs[NPCName][_NPCType])
- StatusForNPCs[NPCName][_State] = Dead
- task.spawn(OnDeath, NPC, NPCName, Humanoid, Head)
- end
- elseif State ~= Dead then -- Fell in Void
- StatusForNPCs[NPCName][_State] = Dead
- task.spawn(OnDeath, NPC, NPCName, Humanoid, Head)
- end
- end
- end
- ConnectionPool.Track(script, AddToConnectionPool, RSettings.ProcessorSpeed)
Advertisement
Add Comment
Please, Sign In to add comment