DevGabe

Zombies Random Movement - ControlZombies ServerScript

Sep 1st, 2026
13
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 50.35 KB | None | 0 0
  1. -- Either use ConnectionPool Multi-Functional Module
  2. -- Or Keep the ConnectionPool Simplified Module
  3. -- Get Rid of .Track and add RemoteMessenger Back.
  4.  
  5. -- Delete the GoalPoints Folder in InfoRobots.
  6.  
  7. -- By DevGabe
  8.  
  9. -- Ragdolls and :Destroy() Cause Major Unnecessary Physics Lag and Delays! I'm Not Using It!
  10. -- Humanoid Never Dies to Avoid Laggy :Destroy() and Cloning
  11.  
  12. -- When Making a New Character Appearance:
  13. -- * Make Humanoid DisplayDistanceType = "None" So It Hides Real Health
  14. -- *** Also, Set Humanoid.BreakJointsOnDeath = false
  15. -- *** You must Add a Happy and Hurt Sound in the Head of the Character.
  16. -- *** Make All Humanoid Max Health 1000000 with Health 1000000. This is for Fake Death, CFrame Far Away.
  17. -- *** Hide the Models that you Add, out of the Map in Workspace Before Putting them in Replicated Storage.
  18. -- * Make RSettings.MaxHealth Their Actual Health. You can Find it Below.
  19.  
  20. -- *** (GAME CHANGER OF NO LAG) Finally, Set All the Parts Under the Characters to a Density of .1 (Not Too Low)
  21. -- and Everything Else to 0 To not Slip in CustomPhysicalProperties
  22. -- = In the Properties of Each Part. Use 'is:basepart' in Explorer Search Bar to Speed Up the Process.
  23.  
  24. -- * Look For Hidden Damage Scripts in the Models from Toolbox.
  25.  
  26. -- Press CTRL + F to Find Certain Words
  27. -- Search StopLoopedSound()
  28. -- Delete this Function if you Change the TypeOneSwingAnimation
  29.  
  30. local Players = game.Players
  31. local RepStorage = game.ReplicatedStorage
  32. local Debris = game.Debris
  33.  
  34. local PathfindingService = game:GetService("PathfindingService")
  35. local TweenService = game:GetService("TweenService")
  36. local ContentProvider = game:GetService("ContentProvider")
  37.  
  38. local ObjectCache = require(RepStorage.ObjectCache)
  39. --local GetNetworkOwnerEvent = RepStorage.GetNetworkOwnerEvent
  40. local ConnectionPool = require(RepStorage.ConnectionPool)
  41.  
  42. local GetIdleAnim = script:WaitForChild("IdleAnimation")
  43. local GetAttackAnim = script:WaitForChild("AttackAnimation")
  44. local GetToolNoneAnim = script:WaitForChild("ToolNoneAnimation")
  45. local GetTypeOneSwingAnim = script:WaitForChild("Swinging"):WaitForChild("TypeOneSwingAnimation")
  46. local GetTypeTwoSwingAnim = script:WaitForChild("Swinging"):WaitForChild("TypeTwoSwingAnimation")
  47.  
  48. -- Storage Robots
  49. local StorageRobots = RepStorage.StorageRobots
  50. local StorageModels = StorageRobots.Models
  51. local Models = StorageModels:GetChildren()
  52. local GetWeapons = StorageRobots.Weapons
  53.  
  54. local CurrentClock = os.clock()
  55.  
  56. local M16 = GetWeapons.M16
  57. local M16Dmg = .1--1
  58. local M16Firerate = 3
  59. local M16Range = 50
  60. local M16RecoilImage = 4
  61. local M16RightHandOffset = CFrame.new(.6,-1,-.1) * CFrame.Angles(math.rad(180),0,math.rad(-20))
  62. local M16StopMovingDistanceToFire = 40 -- Stop Moving When Close to Target [With Respect to Gun Range]
  63.  
  64. local TrenchShotgun = GetWeapons.TrenchShotgun
  65. local TrenchShotgunDmg = .1--7
  66. local TrenchShotgunFirerate = 4
  67. local TrenchShotgunRange = 40
  68. local TrenchShotgunRecoilImage = 10
  69. local TrenchShotgunRightHandOffset = CFrame.new(.2,0,.1) * CFrame.Angles(math.rad(270),math.rad(-20),0)
  70. local TrenchShotgunStopMovingDistanceToFire = 20
  71.  
  72. -- Special Equip
  73. local FireAxe = GetWeapons.FireAxe
  74. local FireAxeDmg = .1--4
  75. local FireAxeFirerate = 2
  76. local FireAxeRange = 15
  77. local FireAxeRecoilImage = 10
  78. local FireAxeRightHandOffset = CFrame.new(0,0,-1) * CFrame.Angles(math.rad(270),math.rad(90),0)
  79. local FireAxeStopMovingDistanceToFire = 7
  80.  
  81. -- Special Equip
  82. local Pistol = GetWeapons.Pistol
  83. local PistolDmg = .1--5
  84. local PistolFirerate = 4
  85. local PistolRange = 55
  86. local PistolRecoilImage = 4
  87. local PistolRightHandOffset = CFrame.new(0,-.4,0) * CFrame.Angles(math.rad(180),0,0)
  88. local PistolStopMovingDistanceToFire = 45
  89.  
  90. local Sniper = GetWeapons.Sniper
  91. local SniperDmg = .1--10
  92. local SniperFirerate = 7
  93. local SniperRange = 90
  94. local SniperRecoilImage = 8
  95. local SniperRightHandOffset = CFrame.Angles(math.rad(270),math.rad(-10),0)
  96. local SniperStopMovingDistanceToFire = 70
  97.  
  98. -- Body Gyro Types [Body Gyro Allows Robot To Turn towards Target]
  99. local ActiveGyro = Vector3.new(math.huge,math.huge,math.huge)
  100. local InActiveGyro = Vector3.new(0,0,0)
  101.  
  102. local Scatter = Random.new()
  103.  
  104. local NPCCorpseCaches = {} -- Table for NPC Corpse Body Parts
  105. local NPCTypeCounts = {} -- Table for Duplicating Count for Each Corpse
  106. local PathRobots = {} -- Table for Paths and Happy Sound and Sad Sound
  107. local AllAnimationsTable = {} -- Load Animations Prior
  108. local CurrentAnimTracksTable = {} -- Track Current Animation
  109. local StatusForNPCs = {} -- Status For NPCs
  110.  
  111. -- Info Robots
  112. local InfoRobots = workspace:WaitForChild("InfoRobots")
  113. local AllRobots = InfoRobots:WaitForChild("AllRobots")
  114. local SpawnPoints = InfoRobots:WaitForChild("SpawnPoints"):GetChildren()
  115.  
  116. -- Robot Settings
  117. local RSettings = {
  118. ProcessorSpeed = .1; -- Performance Reliance
  119. TargetSpeed = .25; -- Targetting Speed [With Respect to Smallest Firerate]
  120. AmountRobots = 35; -- Amount of Robots
  121. AgroDistance = 100; -- Detection Radius
  122. MaxPathFindingDistance = 1000; -- Max PathFinding Distance
  123. HalfGap = 40; -- Move More Precise to Target this Close
  124. ClosingGap = 25; -- Fluently Move to Target this Close
  125. RoamWalkSpeed = 12; -- WalkSpeed When Roaming
  126. AgroWalkSpeed = 18; -- WalkSpeed When Attacking
  127. NearWaypoint = 10; -- Accept Waypoint if this Close
  128. UnstuckPower = 40; -- Get Unstuck Leap Power
  129. CorpseTime = 20; -- Dead Body Time (Time Fade Out Should not be Higher than Corpse Time)
  130. TimeFadeIn = 1; -- Fade In When Respawning Time
  131. TimeFadeOut = 2; -- Fade Out When Being Hidden Time
  132. SearchHuntTime = 10; -- Time to Search for Targets
  133. HealthRegenAmount = 1; -- Health Regeneration Amount
  134. HealthRegenSpeed = 1; -- Health Regeneration Speed
  135. ReplaysHurtAfterRegenAmount = 10; -- Health Regen Amount Needed to Replay Hurt Sound
  136. NPCMaxHealth = 50; -- NPC Max Health
  137. DeathSoundID = "rbxassetid://24902294"; -- Death Sound ID
  138. SecondDeathSoundID = "rbxassetid://24902268";
  139. ThirdDeathSoundID = ""; -- Quiet
  140. IdleAnimDelayTime = .5; -- Delay Before Playing Idle Animation
  141. DistancePlusForNetworkOwnership = 200; -- Distance Plus to Get Network Ownership
  142. MinWaitZombieSound = 60; -- Min Wait Zombie Sound
  143. MaxWaitZombieSound = 200; -- Max Wait Zombie Sound
  144. RoamingRadius = 20; -- Roaming Random Radius
  145. MinStandStillDoNothing = 1; -- Min Stand Still Do Nothing
  146. MaxStandStillDoNothing = 15; -- Max Stand Still do Nothing
  147. }
  148.  
  149. -- Stats Names
  150. local _State = "State"
  151. local _CurrentWaypoint = "CurrentWaypoint"
  152. local _LastHealth = "LastHealth"
  153. local _LastClock = "LastClock"
  154. local _LastGap = "LastGap"
  155. local _Strikes = "Strikes"
  156. local _SwitchStates = "SwitchStates"
  157. local _SearchHunt = "SearchHunt"
  158. local _LastSearchTime = "LastSearchTime"
  159. local _FirstSpawn = "FirstSpawn"
  160. local _LastHealthRegen = "LastHealthRegen"
  161. local _sHurtStrikes = "sHurtStrikes"
  162.  
  163. local _LastTargetTime = "LastTargetTime"
  164. local _LastGunFirerate = "LastGunFirerate"
  165.  
  166. local _Range = "Range"
  167. local _Damage = "Damage"
  168. local _Firerate = "Firerate"
  169. local _RecoilImage = "RecoilImage"
  170. local _StopMovingDistanceToFire = "StopMovingDistanceToFire"
  171.  
  172. local _CurrentAnim = "CurrentAnim"
  173. local _FallSpeed = "FallSpeed"
  174. local _CurrentState = "CurrentState"
  175. local _IdleAnimDelay = "IdleAnimDelay"
  176. local _JumpingNow = "JumpingNow"
  177.  
  178. local _NPCType = "NPCType"
  179.  
  180. local _LastZombieSounds = "ZombieSounds"
  181. local _DoNothingTime = "DoNothingTime"
  182. local _ChosenDoNothingTime = "ChosenDoNothingTime"
  183.  
  184. -- Robot States
  185. local Roaming = "Roaming"
  186. local Hostile = "Hostile"
  187. local Dead = "Dead"
  188.  
  189. local KingFPS = 0
  190. local LowestDistance = RSettings.MaxPathFindingDistance
  191.  
  192. -- Robot Animations R15 (Works with R6 Ids)
  193. local Animations = {
  194. idleAnimation = "http://www.roblox.com/asset/?id=507766388",--"http://www.roblox.com/asset/?id=507766666",
  195. walkAnimation = "http://www.roblox.com/asset/?id=507777826",
  196. jumpAnimation = "http://www.roblox.com/asset/?id=507765000",
  197. fallAnimation = "http://www.roblox.com/asset/?id=507767968",
  198. climbAnimation = "http://www.roblox.com/asset/?id=507765644",
  199. sitAnimation = "http://www.roblox.com/asset/?id=2506281703",
  200. }
  201.  
  202. local ProjectileTemplate = Instance.new("Part")
  203. ProjectileTemplate.Name = "Bullet"
  204. ProjectileTemplate.Anchored = true
  205. ProjectileTemplate.CanCollide = false
  206. ProjectileTemplate.BrickColor = BrickColor.Yellow()
  207. ProjectileTemplate.Material = Enum.Material.Neon
  208. local MyObjectCache = ObjectCache.new(ProjectileTemplate, RSettings.AmountRobots + 5, workspace)
  209.  
  210. -- [[ Storage ]] --
  211.  
  212. -- Set Network Owner for NPC's Client Side Kingship from the Best FPS.
  213. local function SetNetworkOwnerForNPCs(Player, FPS)
  214. -- Check if Network Owner is Gone
  215. local CurrentFPSKing
  216. for i, NPCTable in ipairs(PathRobots) do
  217. local TargetHumRootPart = NPCTable.GetHumanoidRootPart
  218. if TargetHumRootPart and TargetHumRootPart.Parent and TargetHumRootPart:CanSetNetworkOwnership() and TargetHumRootPart:GetNetworkOwner() ~= Player then
  219. if TargetHumRootPart:GetNetworkOwner() ~= nil then
  220. CurrentFPSKing = true
  221. end
  222. end
  223. end
  224. if not CurrentFPSKing then
  225. KingFPS = 0
  226. end
  227. if FPS > KingFPS then
  228. KingFPS = FPS
  229.  
  230. local CharHumRootPart = Player.Character and Player.Character:FindFirstChild("HumanoidRootPart")
  231. if CharHumRootPart then
  232. local HumRootPartPos = CharHumRootPart.Position
  233.  
  234. local Distances = {}
  235.  
  236. -- Collect Magnitudes
  237. for i, NPCTable in ipairs(PathRobots) do
  238. local TargetHumRootPart = NPCTable.GetHumanoidRootPart
  239. if TargetHumRootPart and TargetHumRootPart.Parent then
  240. local Mag = (HumRootPartPos - TargetHumRootPart.Position).Magnitude
  241. table.insert(Distances, Mag)
  242. end
  243. end
  244.  
  245. if #Distances > 0 then
  246. -- Sort Distances
  247. table.sort(Distances)
  248.  
  249. -- Get the Median Index
  250. local Count = #Distances
  251. local Result
  252. if Count % 2 == 1 then -- Odd
  253. Result = Distances[math.ceil(Count / 2)]
  254. else -- Even: Average the 2 Middle Numbers to Get the True Median Magnitude
  255. Result = (Distances[Count / 2] + Distances[(Count / 2) + 1]) / 2
  256. end
  257.  
  258. -- Get a Centered Person for Network Owner Ship
  259. if Result <= LowestDistance + RSettings.DistancePlusForNetworkOwnership and Result < RSettings.MaxPathFindingDistance then
  260. LowestDistance = Result
  261.  
  262. -- Set Network Owner
  263. for i, NPCTable in ipairs(PathRobots) do
  264. local TargetHumRootPart = NPCTable.GetHumanoidRootPart
  265. if TargetHumRootPart and TargetHumRootPart.Parent and TargetHumRootPart:CanSetNetworkOwnership() and TargetHumRootPart:GetNetworkOwner() ~= Player then
  266. TargetHumRootPart:SetNetworkOwner(Player)
  267. end
  268. end
  269. end
  270. end
  271. end
  272. end
  273. end
  274. ConnectionPool.AddListener("GetNetworkOwner", script, SetNetworkOwnerForNPCs)
  275. --GetNetworkOwnerEvent.OnServerEvent:Connect(SetNetworkOwnerForNPCs)
  276.  
  277. -- Stop All Animations
  278. local function StopAllAnimations(NPCName)
  279. if CurrentAnimTracksTable[NPCName] then
  280. CurrentAnimTracksTable[NPCName]:Stop()
  281. CurrentAnimTracksTable[NPCName]:Destroy()
  282. CurrentAnimTracksTable[NPCName] = nil
  283. end
  284. end
  285.  
  286. -- Play Animation By Name
  287. local function PlayAnimation(NPC, NPCName, Humanoid, Animator, AnimName)
  288. if AnimName == StatusForNPCs[NPCName][_CurrentAnim] then return end
  289. StopAllAnimations(NPCName)
  290. StatusForNPCs[NPCName][_CurrentAnim] = AnimName
  291. local FindThisInTable = AllAnimationsTable[NPCName]
  292. if AllAnimationsTable[NPCName] and AllAnimationsTable[NPCName][AnimName] then
  293. CurrentAnimTracksTable[NPCName] = Animator:LoadAnimation(AllAnimationsTable[NPCName][AnimName])
  294. CurrentAnimTracksTable[NPCName]:Play()
  295. if AnimName == "walkAnimation" and Humanoid.WalkSpeed >= RSettings.AgroWalkSpeed then
  296. CurrentAnimTracksTable[NPCName]:AdjustSpeed(1) -- Default Animation Speed
  297. else
  298. CurrentAnimTracksTable[NPCName]:AdjustSpeed(.5) -- Walking Speed
  299. end
  300. end
  301. end
  302.  
  303. -- Get Distance Farthest or Shortest
  304. local function GetDistance(HumanoidRootPart, Folder, Decision)
  305. local Result, Other
  306. local Distance = Decision == "Farthest" and 0 or RSettings.AgroDistance
  307. for i, v in ipairs(Folder) do
  308. local Measurement = (HumanoidRootPart.Position - v.Position).Magnitude
  309. if Decision == "Farthest" and Measurement >= Distance then
  310. Distance = Measurement
  311. Result, Other = v, i
  312. elseif Decision == "Shortest" and Measurement <= Distance then
  313. Distance = Measurement
  314. Result, Other = v, Distance
  315. end
  316. end
  317. return Result, Other
  318. end
  319.  
  320. -- Get Closest Player
  321. local function ClosestPlayer(HumanoidRootPart, GetPlayer)
  322. local Chosen, Distance
  323. local AllPlayers = Players:GetPlayers()
  324. if #AllPlayers ~= 0 then
  325. local PlyrPositions = {}
  326. for i, player in ipairs(AllPlayers) do
  327. local pChar = player.Character
  328. if pChar then
  329. local pHumanoid = pChar:FindFirstChild("Humanoid")
  330. if pHumanoid and pHumanoid.Health > 0 and pHumanoid.RootPart then
  331. table.insert(PlyrPositions, pHumanoid.RootPart)
  332. end
  333. end
  334. end
  335. Chosen, Distance = GetDistance(HumanoidRootPart,PlyrPositions,"Shortest")
  336. end
  337. if GetPlayer then -- Get Player Object
  338. return Chosen, Distance
  339. elseif not Chosen then -- Walk Randomly
  340. Chosen = HumanoidRootPart.CFrame * CFrame.new(Scatter:NextInteger(-50, 50), 0, Scatter:NextInteger(-50, 50))
  341. end -- Get Player Position
  342. return Chosen.Position, Distance
  343. end
  344.  
  345. --(( NPC Functions
  346.  
  347. -- Fade In NPC When Respawning or FadeOut NPC When Dead or Make NPC Invisible
  348. local function FadeNPC(NPC, Time, FadeType)
  349. for i, v in pairs(NPC:GetDescendants()) do
  350. if v:IsA("BasePart") and v.Name ~= "HumanoidRootPart" and v.Name ~= "GunFlash" and not v:FindFirstChild("Fire") then
  351. if FadeType == "Invisible" then
  352. v.Transparency = 1
  353. else
  354. local Fade = TweenService:Create(v,TweenInfo.new(Time),{Transparency = FadeType})
  355. Fade:Play()
  356. end
  357. end
  358. end
  359. end
  360.  
  361. -- Create NPC
  362. local function CreateNPC(NPCName, HasNPCTypeName)
  363. local ClockNow = os.clock()
  364. local ScatterClock = Random.new(ClockNow)
  365.  
  366. local NPC = HasNPCTypeName and StorageModels[HasNPCTypeName]:Clone() or Models[ScatterClock:NextInteger(1,#Models)]:Clone()
  367. local NPCTypeName = HasNPCTypeName or NPC.Name
  368. local Head = NPC.Head
  369. local Humanoid = NPC.Humanoid
  370. local Animator = Humanoid.Animator
  371. local HumanoidRootPart = NPC.HumanoidRootPart
  372. local RightHand = NPC.RightHand
  373.  
  374. -- Count For Each NPC Type
  375. if NPCTypeCounts then
  376. for Index, NPCModel in pairs(Models) do -- Add Count in Tables
  377. if NPCModel.Name == NPCTypeName then
  378. NPCTypeCounts[NPCTypeName] = NPCTypeCounts[NPCTypeName] + 1
  379. end
  380. end
  381. end
  382.  
  383. StatusForNPCs[NPCName] = {}
  384. StatusForNPCs[NPCName][_NPCType] = NPCTypeName -- Save NPC Type
  385.  
  386. NPC.Name = NPCName
  387.  
  388. Humanoid.MaxHealth = 100000 -- Fake Death = Big Number
  389. Humanoid.Health = 100000 -- Match Max Health
  390. Humanoid.WalkSpeed = RSettings.RoamWalkSpeed
  391. HumanoidRootPart.CFrame = SpawnPoints[ScatterClock:NextInteger(1,#SpawnPoints)].CFrame
  392. FadeNPC(NPC, nil, "Invisible") -- Make Invisible
  393.  
  394. local Path = PathfindingService:CreatePath()
  395. PathRobots[NPCName] = {MyPath = Path,
  396. GetHumanoid = Humanoid,
  397. GetHumanoidRootPart = HumanoidRootPart,
  398. GetHead = Head,
  399. GetRightHand = RightHand,
  400. GetAnimator = Animator,
  401. sHappy = Head.Happy, sHurt = Head.Hurt}
  402.  
  403. StatusForNPCs[NPCName][_State] = Roaming
  404. StatusForNPCs[NPCName][_LastHealth] = NPC.Humanoid.Health
  405. StatusForNPCs[NPCName][_Strikes] = 0
  406. StatusForNPCs[NPCName][_SwitchStates] = true
  407. StatusForNPCs[NPCName][_LastClock] = ClockNow
  408. StatusForNPCs[NPCName][_LastGap] = ClockNow
  409. StatusForNPCs[NPCName][_SearchHunt] = false
  410. StatusForNPCs[NPCName][_LastSearchTime] = ClockNow
  411. StatusForNPCs[NPCName][_LastHealthRegen] = ClockNow
  412. StatusForNPCs[NPCName][_sHurtStrikes] = 0
  413.  
  414. StatusForNPCs[NPCName][_LastTargetTime] = ClockNow
  415. StatusForNPCs[NPCName][_LastGunFirerate] = ClockNow
  416.  
  417. StatusForNPCs[NPCName][_CurrentAnim] = "idleAnimation"
  418. StatusForNPCs[NPCName][_FallSpeed] = 0
  419. StatusForNPCs[NPCName][_CurrentState] = ""
  420. StatusForNPCs[NPCName][_JumpingNow] = false
  421. StatusForNPCs[NPCName][_IdleAnimDelay] = 0
  422.  
  423. StatusForNPCs[NPCName][_LastZombieSounds] = ClockNow
  424. StatusForNPCs[NPCName][_DoNothingTime] = ClockNow
  425. StatusForNPCs[NPCName][_ChosenDoNothingTime] = 0
  426.  
  427. -- Animations
  428. AllAnimationsTable[NPCName] = {}
  429. local ArrayAnimTable = {}
  430.  
  431. -- Preload Animations
  432. for AnimName, AnimId in pairs(Animations) do
  433. local AnimObject = Instance.new("Animation")
  434. AnimObject.Name = AnimName
  435. AnimObject.AnimationId = AnimId
  436. AllAnimationsTable[NPCName][AnimName] = AnimObject
  437. table.insert(ArrayAnimTable, AnimObject)
  438. end
  439.  
  440. -- Preload Animations
  441. pcall(function()
  442. game:GetService("ContentProvider"):PreloadAsync(ArrayAnimTable)
  443. end)
  444. ArrayAnimTable = nil
  445.  
  446. -- Sounds
  447. local function NewSound(SoundName, SoundID)
  448. local GetSound = Instance.new("Sound")
  449. GetSound.SoundId = SoundID
  450. GetSound.Name = SoundName
  451. GetSound.Parent = Head
  452. return GetSound
  453. end
  454.  
  455. local sGettingUp = NewSound("GettingUp", "rbxasset://sounds/action_get_up.mp3")
  456. local sFreeFalling = NewSound("FreeFalling", "rbxasset://sounds/action_falling.mp3")
  457. local sJumping = NewSound("Jumping", "rbxasset://sounds/action_jump.mp3")
  458. local sLanding = NewSound("Landing", "rbxasset://sounds/action_jump_land.mp3")
  459. local sSplash = NewSound("Splash", "rbxasset://sounds/impact_water.mp3")
  460. local sRunning = NewSound("Running", "rbxasset://sounds/action_footsteps_plastic.mp3")
  461. sRunning.Looped = true
  462. local sSwimming = NewSound("Swimming", "rbxasset://sounds/action_swim.mp3")
  463. sSwimming.PlaybackSpeed = 1.6
  464. sSwimming.Looped = true
  465. local sClimbing = NewSound("Climbing", "rbxasset://sounds/action_footsteps_plastic.mp3")
  466. sClimbing.Looped = true
  467.  
  468. -- Rotate To Target BodyGyro
  469. local BodyGyro = Instance.new("BodyGyro")
  470. BodyGyro.Name = "RotateToTarget"
  471. BodyGyro.D = 4000
  472. BodyGyro.P = 300000
  473. BodyGyro.MaxTorque = InActiveGyro
  474. BodyGyro.Parent = HumanoidRootPart
  475.  
  476. NPC.Parent = AllRobots
  477. FadeNPC(NPC, RSettings.TimeFadeIn, 0) -- Fade In
  478.  
  479. local Weapon
  480.  
  481. --[[
  482. local RandNum = ScatterClock:NextInteger(1, 5)
  483. if RandNum == 1 then
  484. -- Weapon
  485. Weapon = M16:Clone()
  486. -- Position On Hand
  487. Weapon.CFrame = RightHand.CFrame * M16RightHandOffset
  488. -- Stats
  489. StatusForNPCs[NPCName][_Range] = M16Range
  490. StatusForNPCs[NPCName][_Damage] = M16Dmg
  491. StatusForNPCs[NPCName][_Firerate] = M16Firerate
  492. StatusForNPCs[NPCName][_RecoilImage] = M16RecoilImage
  493. StatusForNPCs[NPCName][_StopMovingDistanceToFire] = M16StopMovingDistanceToFire
  494. elseif RandNum == 2 then
  495. -- Weapon
  496. Weapon = TrenchShotgun:Clone()
  497. -- Position On Hand
  498. Weapon.CFrame = RightHand.CFrame * TrenchShotgunRightHandOffset
  499. -- Stats
  500. StatusForNPCs[NPCName][_Range] = TrenchShotgunRange
  501. StatusForNPCs[NPCName][_Damage] = TrenchShotgunDmg
  502. StatusForNPCs[NPCName][_Firerate] = TrenchShotgunFirerate
  503. StatusForNPCs[NPCName][_RecoilImage] = TrenchShotgunRecoilImage
  504. StatusForNPCs[NPCName][_StopMovingDistanceToFire] = TrenchShotgunStopMovingDistanceToFire
  505. elseif RandNum == 3 then
  506. ]]--
  507. -- Weapon
  508. Weapon = FireAxe:Clone()
  509. -- Position On Hand
  510. Weapon.CFrame = RightHand.CFrame * FireAxeRightHandOffset
  511. -- Stats
  512. StatusForNPCs[NPCName][_Range] = FireAxeRange
  513. StatusForNPCs[NPCName][_Damage] = FireAxeDmg
  514. StatusForNPCs[NPCName][_Firerate] = FireAxeFirerate
  515. StatusForNPCs[NPCName][_RecoilImage] = FireAxeRecoilImage
  516. StatusForNPCs[NPCName][_StopMovingDistanceToFire] = FireAxeStopMovingDistanceToFire
  517. --[[
  518. elseif RandNum == 4 then
  519. -- Weapon
  520. Weapon = Pistol:Clone()
  521. -- Position On Hand
  522. Weapon.CFrame = RightHand.CFrame * PistolRightHandOffset
  523. -- Stats
  524. StatusForNPCs[NPCName][_Range] = PistolRange
  525. StatusForNPCs[NPCName][_Damage] = PistolDmg
  526. StatusForNPCs[NPCName][_Firerate] = PistolFirerate
  527. StatusForNPCs[NPCName][_RecoilImage] = PistolRecoilImage
  528. StatusForNPCs[NPCName][_StopMovingDistanceToFire] = PistolStopMovingDistanceToFire
  529. elseif RandNum == 5 then
  530. -- Weapon
  531. Weapon = Sniper:Clone()
  532. -- Position On Hand
  533. Weapon.CFrame = RightHand.CFrame * SniperRightHandOffset
  534. -- Stats
  535. StatusForNPCs[NPCName][_Range] = SniperRange
  536. StatusForNPCs[NPCName][_Damage] = SniperDmg
  537. StatusForNPCs[NPCName][_Firerate] = SniperFirerate
  538. StatusForNPCs[NPCName][_RecoilImage] = SniperRecoilImage
  539. StatusForNPCs[NPCName][_StopMovingDistanceToFire] = SniperStopMovingDistanceToFire
  540. end
  541. ]]--
  542.  
  543. -- Load Animations
  544. local function SetGunFlash()
  545. local GunFlash = Weapon.GunFlash
  546. PathRobots[NPCName].GunFlash = GunFlash
  547. PathRobots[NPCName].GunFlashChilds = GunFlash:GetChildren()
  548. end
  549.  
  550. local SetOneAnim, SetTwoAnim
  551. if Weapon.Name == "FireAxe" then -- Swinging
  552. SetOneAnim = Animator:LoadAnimation(GetTypeOneSwingAnim)
  553. SetTwoAnim = Animator:LoadAnimation(GetTypeTwoSwingAnim)
  554. elseif Weapon.Name == "Pistol" then -- Tool None Anim
  555. SetOneAnim = Animator:LoadAnimation(GetToolNoneAnim)
  556.  
  557. SetGunFlash()
  558. else
  559. SetOneAnim = Animator:LoadAnimation(GetIdleAnim)
  560. SetTwoAnim = Animator:LoadAnimation(GetAttackAnim)
  561.  
  562. SetGunFlash()
  563. end
  564.  
  565. PathRobots[NPCName].OneAnim = SetOneAnim
  566. PathRobots[NPCName].TwoAnim = SetTwoAnim
  567.  
  568. PathRobots[NPCName].Weapon = Weapon
  569. PathRobots[NPCName].sEquip = Weapon.Equip
  570. PathRobots[NPCName].sFire = Weapon.Fire
  571. PathRobots[NPCName].sUnequip = Weapon.Unequip
  572. PathRobots[NPCName].sHitFade = Weapon.HitFade
  573.  
  574. PathRobots[NPCName].sSplash = sSplash
  575.  
  576.  
  577. -- Hide Weapon
  578. Weapon.Transparency = 1
  579. Weapon.CastShadow = false
  580.  
  581. local WeldConstraint = Weapon:FindFirstChild("HoldGun") or Instance.new("WeldConstraint")
  582. WeldConstraint.Name = "HoldGun"
  583. WeldConstraint.Part0 = Weapon
  584. WeldConstraint.Part1 = RightHand
  585. WeldConstraint.Parent = Weapon
  586.  
  587. Weapon.Parent = NPC
  588. end
  589.  
  590. -- Get Unstuck by Leaping Forward
  591. local function GetUnstuck(NPCName, Humanoid, HumanoidRootPart)
  592. -- warn("Getting Unstuck: ", Humanoid.Parent.Name)
  593. Humanoid.Jump = true
  594. StatusForNPCs[NPCName][_JumpingNow] = true
  595. task.wait(.25)
  596. HumanoidRootPart.Velocity = HumanoidRootPart.CFrame.LookVector * RSettings.UnstuckPower
  597. end
  598.  
  599. local rayLength = -100
  600.  
  601. -- Cast Ray Down to Hit Ground and Ignore Players
  602. local function CastAtOffset(originVector, offsetX, offsetZ)
  603. local CastParams = RaycastParams.new()
  604. CastParams.FilterType = Enum.RaycastFilterType.Exclude
  605.  
  606. -- Ignore All Players and NPCs
  607. local IgnoreList = {}
  608. for i, ObjectCache in pairs(workspace:GetChildren()) do
  609. if ObjectCache.Name == "ObjectCache" then
  610. table.insert(IgnoreList, ObjectCache)
  611. end
  612. end
  613. for i, GetNPC in pairs(AllRobots:GetChildren()) do
  614. table.insert(IgnoreList, GetNPC)
  615. end
  616. for i, GetPlayer in pairs(Players:GetPlayers()) do
  617. if GetPlayer.Character then
  618. table.insert(IgnoreList, GetPlayer.Character)
  619. end
  620. end
  621.  
  622. --CastParams.FilterDescendantsInstances = IgnoreList
  623. CastParams:AddToFilter(IgnoreList)
  624.  
  625. -- Shift the Starting X and Z Spots While Keeping a Safe High Y Start
  626. local RayOrigin = Vector3.new(originVector.X + offsetX, originVector.Y, originVector.Z + offsetZ)
  627. local RayDirection = Vector3.new(0, rayLength, 0)
  628.  
  629. local Result = workspace:Raycast(RayOrigin, RayDirection, CastParams)
  630. return Result
  631. end
  632.  
  633. -- Detect On Death
  634. local function OnDeath(NPC, NPCName, Humanoid, Head)
  635. Humanoid.BreakJointsOnDeath = false
  636.  
  637. -- NPC Corpse Cache: Reveal Corpse and Hide Real NPC
  638. local Corpse
  639. local NPCType = StatusForNPCs[NPCName][_NPCType]
  640. if Humanoid.RootPart then
  641. Corpse = NPCCorpseCaches[NPCType]:GetPart(Humanoid.RootPart.CFrame)
  642. Corpse.AssemblyLinearVelocity = Vector3.zero
  643. Corpse.AssemblyAngularVelocity = Vector3.zero
  644. Corpse.DiedSound:Play() -- Play Death Sound
  645. local BasePartsTaken = {}
  646. -- Make Corpse Fall Apart While Anchored
  647. for i, BasePart in pairs(Corpse.Parent:GetDescendants()) do
  648. if BasePart:IsA("BasePart") and BasePart.Name ~= "HumanoidRootPart" and not table.find(BasePartsTaken, BasePart) then
  649. table.insert(BasePartsTaken, BasePart)
  650. BasePart.Transparency = 0
  651. BasePart.CastShadow = true
  652. local NewPos = Corpse.Position
  653. if NPC:FindFirstChild(BasePart.Name) then
  654. BasePart.CFrame = NPC[BasePart.Name].CFrame
  655. NewPos = NPC[BasePart.Name].Position
  656. end
  657. local HitSpot = CastAtOffset(NewPos, Scatter:NextInteger(-5, 5), Scatter:NextInteger(-5, 5))
  658. if HitSpot then
  659. local function SlowlyMoveCorpseParts()
  660. for Index = 0, 1, 0.2 do
  661. BasePart.Position = NewPos:Lerp(HitSpot.Position, Index)
  662. task.wait(.01)
  663. end
  664. end
  665. task.spawn(SlowlyMoveCorpseParts)
  666. else
  667. BasePart.Transparency = 1
  668. BasePart.CastShadow = false
  669. end
  670. end
  671. end
  672. BasePartsTaken = nil
  673.  
  674. -- Hide Real NPC
  675. Humanoid.RootPart.Anchored = true
  676. Humanoid.RootPart.CFrame = Humanoid.RootPart.CFrame * CFrame.new(0, 100000, 0)
  677. end
  678.  
  679. -- Stop All Sounds and Play Death Sound
  680. if Head and Head.Parent then
  681. for _,Child in pairs(Head:GetChildren())do
  682. if Child and Child.ClassName == "Sound" then
  683. if Child.Name == "Died" then
  684. Child:Play()
  685. elseif Child.Name ~= "Landed" then
  686. Child:Stop()
  687. end
  688. end
  689. end
  690. end
  691.  
  692. task.wait(RSettings.CorpseTime - RSettings.TimeFadeOut)
  693.  
  694. if Corpse then
  695. FadeNPC(Corpse.Parent, RSettings.TimeFadeOut, 1) -- Fade Out
  696. task.wait(RSettings.TimeFadeOut)
  697. for i, BasePart in pairs(Corpse.Parent:GetDescendants()) do
  698. if BasePart:IsA("BasePart") then
  699. BasePart.Transparency = 1
  700. BasePart.CastShadow = false
  701. end
  702. end
  703. NPCCorpseCaches[NPCType]:ReturnPart(Corpse)
  704. else
  705. task.wait(RSettings.TimeFadeOut)
  706. end
  707.  
  708. -- Respawn NPC
  709. if #AllRobots:GetChildren() <= RSettings.AmountRobots then
  710. -- Revive NPC
  711. if Humanoid.RootPart then
  712. -- Hide Weapon
  713. local Weapon = PathRobots[NPCName].Weapon
  714. --Weapon.Transparency = 1
  715. --Weapon.CastShadow = false
  716.  
  717. Humanoid.Health = Humanoid.MaxHealth
  718. StatusForNPCs[NPCName][_State] = Roaming
  719. Humanoid.RootPart.Anchored = false
  720. Humanoid.RootPart.CFrame = SpawnPoints[Random.new(os.clock()):NextInteger(1,#SpawnPoints)].CFrame
  721.  
  722. FadeNPC(NPC, nil, "Invisible") -- Make Invisible
  723. FadeNPC(NPC, RSettings.TimeFadeIn, 0) -- Fade In
  724.  
  725. else -- If NPC is Missing from 'Void' then Respawn NPC
  726. NPC:Destroy()
  727. -- Clear Tables
  728. local HasNPCType = StatusForNPCs[NPCName][_NPCType]
  729. PathRobots[NPCName] = nil
  730. StatusForNPCs[NPCName] = nil
  731. AllAnimationsTable[NPCName] = nil
  732. CurrentAnimTracksTable[NPCName] = nil
  733. CreateNPC(NPCName, HasNPCType)
  734. end
  735. end
  736. end
  737.  
  738. --))
  739.  
  740. --(( PathFinding Functions
  741.  
  742. -- Get Random Waypoint from NPC Position
  743. local function NewGoalpoint(NPCName, Humanoid, HumanoidRootPart)
  744. if Humanoid.WalkSpeed <= 0 then return end
  745.  
  746. -- Stand Still and Do Nothing for Random Time
  747. if CurrentClock - StatusForNPCs[NPCName][_DoNothingTime] >= StatusForNPCs[NPCName][_ChosenDoNothingTime] then
  748. StatusForNPCs[NPCName][_DoNothingTime] = CurrentClock
  749. StatusForNPCs[NPCName][_ChosenDoNothingTime] = Scatter:NextInteger(RSettings.MinStandStillDoNothing, RSettings.MaxStandStillDoNothing)
  750. else -- Do Nothing
  751. return
  752. end
  753.  
  754. -- Get Random Point In Circle
  755. local CenterPosition = HumanoidRootPart.Position
  756. local Radius = math.sqrt(Scatter:NextNumber()) * RSettings.RoamingRadius
  757. local Angle = Scatter:NextNumber(0, math.pi * 2)
  758. local X = CenterPosition.X + Radius * math.cos(Angle)
  759. local Z = CenterPosition.Z + Radius * math.sin(Angle)
  760.  
  761. -- Random Position
  762. local BasePosition = Vector3.new(X, CenterPosition.Y + Scatter:NextNumber(-RSettings.RoamingRadius, RSettings.RoamingRadius), Z)
  763.  
  764. -- Go Up 100 Studs
  765. local RayOrigin = BasePosition + Vector3.new(0, 100, 0)
  766.  
  767. -- Ignore All Robots When Casting Ray
  768. local RaycastParamsInstance = RaycastParams.new()
  769. RaycastParamsInstance.FilterDescendantsInstances = AllRobots:GetChildren()
  770. RaycastParamsInstance.FilterType = Enum.RaycastFilterType.Exclude
  771.  
  772. -- Starts at 0, ends at 40, Increments by 2 Each Time Creating a Cone Direction Down.
  773. for i = 0, 40, 2 do
  774. -- Randomly Choose 1 or -1 for X and Z Directions
  775. local SignX = (Scatter:NextInteger(1, 2) == 1) and 1 or -1
  776. local SignZ = (Scatter:NextInteger(1, 2) == 1) and 1 or -1
  777.  
  778. -- Cast Ray 200 Studs Down with Spread
  779. local RayDirection = Vector3.new(i * SignX, -200, i * SignZ)
  780.  
  781. -- Perform the Raycast
  782. local RaycastResult = workspace:Raycast(RayOrigin, RayDirection, RaycastParamsInstance)
  783.  
  784. -- Return the Hit Ground Position or Original Base Position
  785. if RaycastResult then
  786. return RaycastResult.Position
  787. end
  788. end
  789. return BasePosition
  790. end
  791.  
  792. -- New Path
  793. local function NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, DestinationPos)
  794. if not DestinationPos or Humanoid.WalkSpeed <= 0 then --[[warn("Destination Not Found")]] return end
  795. local Path = PathRobots[NPCName].MyPath
  796.  
  797. -- Target Walk Towards Without PathFinding
  798. local function TargetWithoutPathFinding(Target)
  799. Humanoid:MoveTo(Target) -- Move Without PathFinding.
  800.  
  801. if (HumanoidRootPart.Velocity.Magnitude < 0.5) then -- Not Moving.
  802. task.spawn(GetUnstuck, NPCName, Humanoid, HumanoidRootPart)
  803. end
  804. end
  805.  
  806. -- Move Without PathFinding
  807. local function MoveWithoutPathFinding()
  808. warn("Path Failed: "..NPCName)
  809.  
  810. local EnemyRootPart = ClosestPlayer(HumanoidRootPart, true)
  811. if EnemyRootPart then
  812. TargetWithoutPathFinding(EnemyRootPart.Position)
  813. else
  814. local Target = ClosestPlayer(HumanoidRootPart)
  815. if Target then
  816. TargetWithoutPathFinding(Target)
  817. end
  818. end
  819. end
  820.  
  821. -- On Path Compute
  822. local function OnPathCompute()
  823. if not DestinationPos then return end
  824.  
  825. local Distance = (DestinationPos - HumanoidRootPart.Position).Magnitude
  826. if Distance < RSettings.MaxPathFindingDistance then
  827. Path:ComputeAsync(HumanoidRootPart.Position, DestinationPos)
  828. if Path.Status == Enum.PathStatus.Success then
  829. local Waypoints = Path:GetWaypoints()
  830. if Waypoints[1] then
  831. StatusForNPCs[NPCName][_CurrentWaypoint] = 1
  832. Humanoid:MoveTo(Waypoints[1].Position)
  833. else
  834. StatusForNPCs[NPCName][_CurrentWaypoint] = nil
  835. end
  836. else
  837. MoveWithoutPathFinding()
  838. end
  839. else -- Too Far.
  840. MoveWithoutPathFinding()
  841. end
  842. end
  843. task.spawn(OnPathCompute)
  844. end
  845.  
  846. -- Reset Waypoint
  847. local function ResetWaypoint(NPC, NPCName, Humanoid, HumanoidRootPart)
  848. if Humanoid.WalkSpeed <= 0 then return end
  849. local newWaypoint
  850. local MyState = StatusForNPCs[NPCName][_State]
  851. if MyState == Roaming then
  852. newWaypoint = NewGoalpoint(NPCName, Humanoid, HumanoidRootPart)
  853. elseif MyState == Hostile then
  854. newWaypoint = ClosestPlayer(HumanoidRootPart)
  855. end
  856. NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, newWaypoint)
  857. StatusForNPCs[NPCName][_Strikes] = 0
  858. end
  859.  
  860. -- On Waypoint Completed
  861. local function OnWaypointCompleted(NPC, NPCName, Humanoid, HumanoidRootPart, Waypoints)
  862. if Humanoid.WalkSpeed <= 0 then return end
  863. local IdxCurrent = StatusForNPCs[NPCName][_CurrentWaypoint]
  864. if IdxCurrent then
  865. if IdxCurrent < #Waypoints then -- Next Waypoint
  866. local NewIdx = IdxCurrent + 1
  867. StatusForNPCs[NPCName][_CurrentWaypoint] = NewIdx
  868. local NextWaypoint = Waypoints[NewIdx]
  869. if NextWaypoint.Action == Enum.PathWaypointAction.Jump then
  870. Humanoid.Jump = true
  871. StatusForNPCs[NPCName][_JumpingNow] = true
  872. end
  873. Humanoid:MoveTo(NextWaypoint.Position)
  874. StatusForNPCs[NPCName][_Strikes] = 0
  875. else -- Completed All Waypoints
  876. ResetWaypoint(NPC, NPCName, Humanoid, HumanoidRootPart)
  877. end
  878. end
  879. end
  880.  
  881. -- Play One Sound
  882. local function PlayOneSound(SoundName, Head)
  883. local GetSound
  884. for _, Child in pairs(Head:GetChildren()) do
  885. if Child and Child.ClassName == "Sound" then
  886. if Child.Name == SoundName then
  887. Child:Play()
  888. GetSound = Child
  889. elseif Child.Name ~= "Landing" then
  890. Child:Stop()
  891. end
  892. end
  893. end
  894. return GetSound
  895. end
  896.  
  897. --))
  898.  
  899. -- [[ Connections ]] --
  900. for i, NPCModel in pairs(Models) do -- Define Tables
  901. NPCTypeCounts[NPCModel.Name] = 0
  902. end
  903. for i = 1, RSettings.AmountRobots do
  904. CreateNPC(i.."-AI")
  905. task.wait(.1) -- For proper randomization seeds
  906. end
  907. for i, NPCModel in pairs(Models) do -- Create Cache for Each NPC Type
  908. local FakeCorpse = NPCModel:Clone()
  909. FakeCorpse.Humanoid:Destroy()
  910. local DeathSound = Instance.new("Sound")
  911.  
  912. local ChosenDeathID
  913. local GetRandomSound = Scatter:NextInteger(1, 3)
  914. if GetRandomSound == 1 then
  915. ChosenDeathID = RSettings.DeathSoundID
  916. elseif GetRandomSound == 2 then
  917. ChosenDeathID = RSettings.SecondDeathSoundID
  918. else
  919. ChosenDeathID = RSettings.ThirdDeathSoundID
  920. end
  921.  
  922. DeathSound.SoundId = ChosenDeathID
  923. DeathSound.Name = "DiedSound"
  924. DeathSound.Volume = 1
  925. DeathSound.Parent = FakeCorpse.PrimaryPart
  926. for i, BasePart in pairs(FakeCorpse:GetDescendants()) do
  927. if BasePart:IsA("BasePart") then
  928. BasePart.Anchored = true
  929. BasePart.CanCollide = false
  930. end
  931. end
  932. NPCCorpseCaches[NPCModel.Name] = ObjectCache.new(FakeCorpse, NPCTypeCounts[NPCModel.Name] + 3, workspace)
  933. end
  934. NPCTypeCounts = nil
  935.  
  936. -- Update All Robot Status
  937. local function AddToConnectionPool()
  938. CurrentClock = os.clock()
  939. for i, NPC in pairs(AllRobots:GetChildren()) do
  940. local NPCName = NPC.Name
  941. local LastHealth = StatusForNPCs[NPCName][_LastHealth]
  942. -- Path
  943. local Waypoints = PathRobots[NPCName].MyPath:GetWaypoints()
  944. local CurrentWaypointIndex = StatusForNPCs[NPCName][_CurrentWaypoint]
  945. -- Reoccuring Values
  946. local State = StatusForNPCs[NPCName][_State]
  947. local SwitchStates = StatusForNPCs[NPCName][_SwitchStates]
  948. local Strikes = StatusForNPCs[NPCName][_Strikes]
  949. local sHurtStrikes = StatusForNPCs[NPCName][_sHurtStrikes]
  950.  
  951. local Humanoid = PathRobots[NPCName].GetHumanoid
  952. local HumanoidRootPart = PathRobots[NPCName].GetHumanoidRootPart
  953. local Head = PathRobots[NPCName].GetHead
  954. local Animator = PathRobots[NPCName].GetAnimator
  955. if Humanoid and Humanoid.Parent and HumanoidRootPart and HumanoidRootPart.Parent and Head and Head.Parent and Animator and Animator.Parent then
  956. local HealthNow = Humanoid.Health
  957. if HealthNow > 0 and RSettings.NPCMaxHealth - (Humanoid.MaxHealth - HealthNow) > 0 then
  958.  
  959. -- Zombie Sounds
  960. if CurrentClock - StatusForNPCs[NPCName][_LastZombieSounds] >= Scatter:NextInteger(RSettings.MinWaitZombieSound, RSettings.MaxWaitZombieSound) then
  961. StatusForNPCs[NPCName][_LastZombieSounds] = CurrentClock
  962. local ChooseOne = Scatter:NextInteger(1, 2)
  963. if ChooseOne == 1 then
  964. local sHappy = PathRobots[NPCName].sHappy
  965. if sHappy and sHappy.Parent and not sHappy.IsPlaying then
  966. sHappy:Play()
  967. end
  968. else
  969. local sHurt = PathRobots[NPCName].sHurt
  970. if sHurt and sHurt.Parent and sHurt.IsPlaying then
  971. sHurt:Play()
  972. end
  973. end
  974. end
  975.  
  976. -- Track Animations and Sounds
  977. local HumanoidState = Humanoid:GetState()
  978. local StateSpeed = HumanoidRootPart.AssemblyLinearVelocity.Magnitude
  979.  
  980. if StatusForNPCs[NPCName][_JumpingNow] then
  981. StatusForNPCs[NPCName][_JumpingNow] = false
  982. PlayAnimation(NPC, NPCName, Humanoid, Animator, "jumpAnimation")
  983.  
  984. -- Jumping Sound
  985. local JumpingSound = PlayOneSound("Jumping", Head)
  986. end
  987.  
  988. local IsFallingState = (HumanoidState == Enum.HumanoidStateType.FallingDown or HumanoidState == Enum.HumanoidStateType.Freefall)
  989. if IsFallingState and StatusForNPCs[NPCName][_CurrentState] ~= "FallingDown" then
  990. StatusForNPCs[NPCName][_CurrentState] = "FallingDown"
  991.  
  992. local IsMovingDownward = Head.AssemblyLinearVelocity.Y < -5 -- Detects true downward falling
  993. if IsMovingDownward then
  994.  
  995. PlayAnimation(NPC, NPCName, Humanoid, Animator, "fallAnimation")
  996.  
  997. -- Free Falling Sound Setup
  998. local FreeFallingSound = PlayOneSound("FreeFalling", Head)
  999. FreeFallingSound.Volume = 0
  1000.  
  1001. local ElapsedTime = 0
  1002. local SoundConnection
  1003. if StatusForNPCs[NPCName]["SoundConnection"] then
  1004. StatusForNPCs[NPCName]["SoundConnection"]:Disconnect()
  1005. StatusForNPCs[NPCName]["SoundConnection"] = nil
  1006. end
  1007. StatusForNPCs[NPCName]["SoundConnection"] = ConnectionPool.Track(script, function(DT)
  1008. ElapsedTime = ElapsedTime + DT
  1009.  
  1010. -- Linear volume fade calculations
  1011. local Vol = math.clamp(ElapsedTime - 0.3, 0, 1)
  1012. if FreeFallingSound and FreeFallingSound.Parent then
  1013. FreeFallingSound.Volume = Vol
  1014. end
  1015.  
  1016. -- Automatically clean up the task once 1.5 seconds passes
  1017. if ElapsedTime >= 1.5 then
  1018. StatusForNPCs[NPCName]["SoundConnection"]:Disconnect()
  1019. end
  1020. end)
  1021.  
  1022. -- Tracks maximum falling speed using modern AssemblyLinearVelocity
  1023. StatusForNPCs[NPCName][_FallSpeed] = math.max(StatusForNPCs[NPCName][_FallSpeed], math.abs(Head.AssemblyLinearVelocity.Y))
  1024. end
  1025. elseif HumanoidState == Enum.HumanoidStateType.Swimming and StatusForNPCs[NPCName][_CurrentState] ~= "Swimming" then -- Swimming
  1026. StatusForNPCs[NPCName][_CurrentState] = "Swimming"
  1027.  
  1028. PlayAnimation(NPC, NPCName, Humanoid, Animator, "walkAnimation")
  1029.  
  1030. if StateSpeed > .1 then
  1031. local Vol = math.min(1.0, StateSpeed / 350)
  1032. local SplashSound = PathRobots[NPCName].sSplash
  1033. if SplashSound and SplashSound.Parent then
  1034. SplashSound.Volume = Vol
  1035. SplashSound:Play()
  1036. end
  1037. end
  1038. local SwimmingSound = PlayOneSound("Swimming", Head)
  1039.  
  1040. elseif HumanoidState == Enum.HumanoidStateType.Landed then -- Landed
  1041. if StatusForNPCs[NPCName][_FallSpeed] > .1 then
  1042. local Vol = math.min(1.0, math.max(0.0, (StatusForNPCs[NPCName][_FallSpeed] - 50) / 110))
  1043. local sLanding = PathRobots[NPCName].sLanding
  1044. if sLanding and sLanding.Parent then
  1045. sLanding.Volume = Vol
  1046. sLanding:Play()
  1047. end
  1048. StatusForNPCs[NPCName][_FallSpeed] = 0
  1049. end
  1050.  
  1051. elseif HumanoidState == Enum.HumanoidStateType.Running or HumanoidState == Enum.HumanoidStateType.None then -- Running
  1052. if StateSpeed > 0.2 and StatusForNPCs[NPCName][_CurrentState] ~= "Running" and Humanoid.WalkSpeed > 0 then
  1053. StatusForNPCs[NPCName][_CurrentState] = "Running"
  1054.  
  1055. StatusForNPCs[NPCName][_IdleAnimDelay] = CurrentClock
  1056.  
  1057. PlayAnimation(NPC, NPCName, Humanoid, Animator, "walkAnimation")
  1058.  
  1059. -- Running Sound
  1060. local RunningSound = PlayOneSound("Running", Head)
  1061. RunningSound.Pitch = StateSpeed / 8
  1062.  
  1063. elseif StateSpeed <= 0.2 and StatusForNPCs[NPCName][_CurrentState] ~= "Idle" and CurrentClock - StatusForNPCs[NPCName][_IdleAnimDelay] >= RSettings.IdleAnimDelayTime then -- Idle
  1064. StatusForNPCs[NPCName][_CurrentState] = "Idle"
  1065.  
  1066. StatusForNPCs[NPCName][_IdleAnimDelay] = CurrentClock
  1067.  
  1068. PlayAnimation(NPC, NPCName, Humanoid, Animator, "idleAnimation")
  1069.  
  1070. -- No Sound
  1071. PlayOneSound("", Head)
  1072. end
  1073.  
  1074. elseif HumanoidState == Enum.HumanoidStateType.Climbing then -- Climbing
  1075. if math.abs(StateSpeed) > 0.2 then
  1076. if StatusForNPCs[NPCName][_CurrentState] ~= "Climbing" then
  1077. StatusForNPCs[NPCName][_CurrentState] = "Climbing"
  1078.  
  1079. PlayAnimation(NPC, NPCName, Humanoid, Animator, "climbAnimation")
  1080.  
  1081. -- Climbing Sound
  1082. if StateSpeed > .01 then
  1083. local ClimbingSound = PlayOneSound("Climbing", Head)
  1084. ClimbingSound.PlaybackSpeed = StateSpeed / 5.5
  1085. else
  1086. PlayOneSound("", Head)
  1087. end
  1088. elseif CurrentAnimTracksTable[NPCName] then
  1089. CurrentAnimTracksTable[NPCName]:AdjustSpeed(1)
  1090. end
  1091. elseif CurrentAnimTracksTable[NPCName] then
  1092. CurrentAnimTracksTable[NPCName]:AdjustSpeed(0)
  1093. end
  1094.  
  1095. elseif HumanoidState == Enum.HumanoidStateType.Seated and StatusForNPCs[NPCName][_CurrentState] ~= "Seated" then -- Seated
  1096. StatusForNPCs[NPCName][_CurrentState] = "Seated"
  1097.  
  1098. PlayAnimation(NPC, NPCName, Humanoid, Animator, "sitAnimation")
  1099.  
  1100. elseif HumanoidState == Enum.HumanoidStateType.GettingUp then -- Getting Up
  1101. local GettingUpSound = PlayOneSound("GettingUp", Head)
  1102.  
  1103. end
  1104.  
  1105. -- Checks If Velocity Has Gone Below 0.5 (Not Moving and Not Close to Target)
  1106. if StatusForNPCs[NPCName][_State] == Hostile then
  1107. if (HumanoidRootPart.Velocity.Magnitude < 0.5) and Humanoid.WalkSpeed > 0 then
  1108. Strikes += 1
  1109. if Strikes <= 25 and CurrentClock - StatusForNPCs[NPCName][_LastClock] >= 3 then
  1110. StatusForNPCs[NPCName][_LastClock] = CurrentClock
  1111. Humanoid.Jump = true
  1112. StatusForNPCs[NPCName][_JumpingNow] = true
  1113. if Waypoints then
  1114. OnWaypointCompleted(NPC, NPCName, Humanoid, HumanoidRootPart, Waypoints)
  1115. end
  1116. elseif Strikes > 25 then
  1117. StatusForNPCs[NPCName][_LastClock] = CurrentClock
  1118. Strikes = 0
  1119. task.spawn(GetUnstuck, NPCName, Humanoid, HumanoidRootPart)
  1120. ResetWaypoint(NPC, NPCName, Humanoid, HumanoidRootPart)
  1121. end
  1122. StatusForNPCs[NPCName][_Strikes] = Strikes
  1123. end
  1124. else -- Roaming
  1125. Strikes = 0
  1126. StatusForNPCs[NPCName][_Strikes] = 0
  1127. StatusForNPCs[NPCName][_LastClock] = CurrentClock
  1128. end
  1129. -- Custom MoveToFinished Indicator
  1130. if Waypoints and #Waypoints > 0 and CurrentWaypointIndex and Waypoints[CurrentWaypointIndex] and HumanoidRootPart then
  1131. local Finishwaypoint = (HumanoidRootPart.Position - Waypoints[CurrentWaypointIndex].Position).Magnitude
  1132. if Finishwaypoint <= RSettings.NearWaypoint then
  1133. OnWaypointCompleted(NPC, NPCName, Humanoid, HumanoidRootPart, Waypoints)
  1134. end
  1135. end
  1136. -- Health Regen if Not MaxHealth
  1137. if HealthNow < Humanoid.MaxHealth and CurrentClock - StatusForNPCs[NPCName][_LastHealthRegen] >= RSettings.HealthRegenSpeed then
  1138. StatusForNPCs[NPCName][_LastHealthRegen] = CurrentClock
  1139. StatusForNPCs[NPCName][_sHurtStrikes] = StatusForNPCs[NPCName][_sHurtStrikes] + 1
  1140. Humanoid.Health += RSettings.HealthRegenAmount
  1141.  
  1142. if Humanoid.Health >= Humanoid.MaxHealth then -- Reached Max Health
  1143. PathRobots[NPCName].sHappy:Play()
  1144. end
  1145. end
  1146. -- Patrol
  1147. local EnemyRootPart, Distance = ClosestPlayer(HumanoidRootPart, true)
  1148. if Distance and Distance <= RSettings.AgroDistance or HealthNow < LastHealth then -- Harm Found
  1149. if State ~= Dead then
  1150. StatusForNPCs[NPCName][_State] = Hostile
  1151. end
  1152. StatusForNPCs[NPCName][_SearchHunt] = true
  1153. StatusForNPCs[NPCName][_LastSearchTime] = CurrentClock
  1154.  
  1155. if HealthNow < LastHealth and StatusForNPCs[NPCName][_sHurtStrikes] >= RSettings.ReplaysHurtAfterRegenAmount then -- Damage Taken
  1156. StatusForNPCs[NPCName][_sHurtStrikes] = 0
  1157. PathRobots[NPCName].sHurt:Play()
  1158. end
  1159.  
  1160. if Distance then
  1161. if Distance > 15 then -- Not Right next to Target
  1162. local LastGap = StatusForNPCs[NPCName][_LastGap]
  1163. if Distance <= RSettings.ClosingGap and CurrentClock - LastGap >= 1
  1164. or Distance <= RSettings.HalfGap and CurrentClock - LastGap >= 2 then -- Move more Fluently near Target
  1165. StatusForNPCs[NPCName][_LastGap] = CurrentClock
  1166. ResetWaypoint(NPC, NPCName, Humanoid, HumanoidRootPart)
  1167. end
  1168. end
  1169.  
  1170. -- Attack
  1171. if CurrentClock - StatusForNPCs[NPCName][_LastTargetTime] >= RSettings.TargetSpeed and EnemyRootPart then
  1172. StatusForNPCs[NPCName][_LastTargetTime] = CurrentClock
  1173.  
  1174. local RightHand = PathRobots[NPCName].GetRightHand
  1175. if RightHand and RightHand.Parent then -- Give Weapon
  1176. local Weapon = PathRobots[NPCName].Weapon
  1177.  
  1178. local GunFlash = PathRobots[NPCName].GunFlash
  1179. local GunFlashChilds = PathRobots[NPCName].GunFlashChilds
  1180.  
  1181. -- Animations
  1182. local OneAnim = PathRobots[NPCName].OneAnim
  1183. local TwoAnim = PathRobots[NPCName].TwoAnim
  1184.  
  1185. -- Rotate To Target BodyGyro
  1186. local BodyGyro = HumanoidRootPart.RotateToTarget
  1187.  
  1188. -- Stop Moving When Too Close To Target
  1189. if Distance <= StatusForNPCs[NPCName][_StopMovingDistanceToFire] then
  1190. if Humanoid.WalkSpeed ~= 0 then
  1191. Humanoid.WalkSpeed = 0
  1192. end
  1193. elseif Humanoid.WalkSpeed ~= RSettings.AgroWalkSpeed then
  1194. Humanoid.WalkSpeed = RSettings.AgroWalkSpeed
  1195. end
  1196.  
  1197. if Distance <= StatusForNPCs[NPCName]["Range"] then
  1198. -- Create A Ray so NPC Can't Attack Through Walls
  1199. local RayParams = RaycastParams.new()
  1200. RayParams.FilterDescendantsInstances = {NPC}
  1201. RayParams.FilterType = Enum.RaycastFilterType.Exclude
  1202.  
  1203. local Result = workspace:Raycast(HumanoidRootPart.Position, (EnemyRootPart.Position - HumanoidRootPart.Position).Unit * 500, RayParams)
  1204.  
  1205. local TargetModel = EnemyRootPart.Parent
  1206. if Result and Result.Instance and Result.Instance:IsDescendantOf(TargetModel) then
  1207.  
  1208. local MyPosition = HumanoidRootPart.Position
  1209. -- Turn Body To Face Target
  1210. BodyGyro.MaxTorque = ActiveGyro
  1211. BodyGyro.CFrame = CFrame.lookAt(MyPosition, EnemyRootPart.Position)
  1212.  
  1213. -- Check if Correctly Facing Target to Attack Considering Firerate
  1214. local FaceofMyCharacter = (EnemyRootPart.Position - MyPosition).Unit -- Unit Converts Numbers to Vector3
  1215. local DotProduct = FaceofMyCharacter:Dot(HumanoidRootPart.CFrame.LookVector) -- Gets the Orientation from 1, the Players Look Direction to -1, Behind the Head
  1216.  
  1217. -- Consider Last Gun Firerate
  1218. if DotProduct > .95 and CurrentClock - StatusForNPCs[NPCName][_LastGunFirerate] >= StatusForNPCs[NPCName][_Firerate] then -- I am Facing Target
  1219. StatusForNPCs[NPCName][_LastGunFirerate] = CurrentClock
  1220. PathRobots[NPCName].sFire:Play()
  1221. -- Attack Animation
  1222. if Weapon.Name == "FireAxe" then
  1223. local RandNum = Scatter:NextInteger(1, 2)
  1224. if RandNum == 1 then
  1225. if not PathRobots[NPCName].OneAnim.IsPlaying then
  1226. PathRobots[NPCName].OneAnim:Play()
  1227.  
  1228. local function StopLoopedSound()
  1229. PathRobots[NPCName].OneAnim:Stop()
  1230. end
  1231. task.delay(Scatter:NextInteger(1, 3), StopLoopedSound)
  1232. OneAnim:Play()
  1233. end
  1234. else
  1235. TwoAnim:Play()
  1236. end
  1237. elseif Weapon.Name ~= "Pistol" then
  1238. TwoAnim:Play()
  1239. end
  1240. -- Enable Gun Flash
  1241. if GunFlashChilds then
  1242. for i, emit in ipairs(GunFlashChilds) do
  1243. emit.Enabled = true
  1244. end
  1245. end
  1246. -- Apply Recoil
  1247. BodyGyro.CFrame = CFrame.lookAt(MyPosition - Vector3.new(0, StatusForNPCs[NPCName]["RecoilImage"], 0), EnemyRootPart.Position)
  1248. -- Set Up Projectile
  1249. local Projectile
  1250. if Weapon.Name ~= "FireAxe" and GunFlash then
  1251. local toTarget = EnemyRootPart.Position - GunFlash.Position
  1252. Projectile = MyObjectCache:GetPart(CFrame.new(GunFlash.Position + toTarget / 1.9, GunFlash.Position))
  1253. local BulletWidth = Weapon.Name == "TrenchShotgun" and .6 or .1
  1254. Projectile.Size = Vector3.new(BulletWidth,BulletWidth,Distance)
  1255. elseif Weapon.Name == "FireAxe" then
  1256. Weapon.SlashTrail.Enabled = true
  1257. local function DisableSlashTrail()
  1258. Weapon.SlashTrail.Enabled = false
  1259. end
  1260. task.delay(.25, DisableSlashTrail)
  1261. end
  1262.  
  1263. -- Apply Damage
  1264. local HasHumanoid = TargetModel:FindFirstChild("Humanoid")
  1265. if HasHumanoid then
  1266. HasHumanoid:TakeDamage(StatusForNPCs[NPCName]["Damage"])
  1267. -- Hit Sound
  1268. local NewHitFade = PathRobots[NPCName].sHitFade:Clone()
  1269. Debris:AddItem(NewHitFade,NewHitFade.TimeLength + 1)
  1270. NewHitFade.Parent = EnemyRootPart
  1271. NewHitFade:Play()
  1272. end
  1273. local function HideProjectile()
  1274. -- Return Projectile
  1275. if Weapon.Name ~= "FireAxe" and Projectile then
  1276. MyObjectCache:ReturnPart(Projectile)
  1277. end
  1278. -- Disable GunFlash
  1279. if GunFlashChilds then
  1280. for i, emit in ipairs(GunFlashChilds) do
  1281. emit.Enabled = false
  1282. end
  1283. end
  1284. end
  1285. task.delay(.2, HideProjectile)
  1286. end
  1287. end
  1288. else -- No Enemy to Target
  1289. BodyGyro.MaxTorque = InActiveGyro
  1290. end
  1291. end
  1292. end
  1293. end
  1294. elseif StatusForNPCs[NPCName][_SearchHunt] == true then -- Search Curiously
  1295.  
  1296. 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.
  1297. if EnemyRootPart then -- Found Enemy
  1298. NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, EnemyRootPart.Position)
  1299. else
  1300. local Target = ClosestPlayer(HumanoidRootPart)
  1301. if Target then
  1302. NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, Target)
  1303. end
  1304. end
  1305. end
  1306. if CurrentClock - StatusForNPCs[NPCName][_LastSearchTime] > RSettings.SearchHuntTime then -- Search Time
  1307. StatusForNPCs[NPCName][_SearchHunt] = false
  1308. end
  1309.  
  1310. elseif State ~= Dead then -- No Harm Found
  1311. StatusForNPCs[NPCName][_State] = Roaming
  1312. end
  1313. -- Reaction
  1314. if State == Hostile and not SwitchStates then
  1315. StatusForNPCs[NPCName][_SwitchStates] = true
  1316. Humanoid.WalkSpeed = RSettings.AgroWalkSpeed
  1317. local Target, Distance = ClosestPlayer(HumanoidRootPart)
  1318. if Target then
  1319. NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, Target)
  1320. end
  1321.  
  1322. -- Play Idle Anim
  1323. local Weapon = PathRobots[NPCName].Weapon
  1324. if Weapon.Name ~= "FireAxe" then
  1325. PathRobots[NPCName].OneAnim:Play()
  1326. end
  1327. PathRobots[NPCName].sEquip:Play()
  1328.  
  1329. -- Show Weapon
  1330. --Weapon.Transparency = 0
  1331. --Weapon.CastShadow = true
  1332.  
  1333. elseif State == Roaming and SwitchStates then
  1334. StatusForNPCs[NPCName][_SwitchStates] = false
  1335. Humanoid.WalkSpeed = RSettings.RoamWalkSpeed
  1336. local Destination = NewGoalpoint(NPCName, Humanoid, HumanoidRootPart)
  1337. NewPath(NPC, NPCName, Humanoid, HumanoidRootPart, Destination)
  1338.  
  1339. -- Hide Weapon
  1340. local Weapon = PathRobots[NPCName].Weapon
  1341. Weapon.Transparency = 1
  1342. Weapon.CastShadow = false
  1343.  
  1344. if StatusForNPCs[NPCName][_FirstSpawn] then
  1345. local Weapon = PathRobots[NPCName].Weapon
  1346. if Weapon.Name ~= "FireAxe" then
  1347. PathRobots[NPCName].OneAnim:Stop()
  1348. end
  1349. HumanoidRootPart.RotateToTarget.MaxTorque = InActiveGyro
  1350. PathRobots[NPCName].sUnequip:Play()
  1351. end
  1352. StatusForNPCs[NPCName][_FirstSpawn] = true
  1353. end
  1354. StatusForNPCs[NPCName][_LastHealth] = HealthNow
  1355. elseif State ~= Dead then -- Dead
  1356. -- print(StatusForNPCs[NPCName][_NPCType])
  1357. StatusForNPCs[NPCName][_State] = Dead
  1358. task.spawn(OnDeath, NPC, NPCName, Humanoid, Head)
  1359. end
  1360. elseif State ~= Dead then -- Fell in Void
  1361. StatusForNPCs[NPCName][_State] = Dead
  1362. task.spawn(OnDeath, NPC, NPCName, Humanoid, Head)
  1363. end
  1364. end
  1365. end
  1366. ConnectionPool.Track(script, AddToConnectionPool, RSettings.ProcessorSpeed)
Advertisement
Add Comment
Please, Sign In to add comment