Skip to content

Instantly share code, notes, and snippets.

@Aerodos12
Created January 29, 2018 23:33
Show Gist options
  • Save Aerodos12/39e1c2941d5022f8a320721abed399bc to your computer and use it in GitHub Desktop.
Save Aerodos12/39e1c2941d5022f8a320721abed399bc to your computer and use it in GitHub Desktop.
Mob System
local Mob = {}
Mob.__index = Mob
local MobService = require(game.ServerScriptService.MobFunctions)
local ASMClass = require(script.Parent.AnimationStateMachine)
local MEMClass = require(script.Parent.MobEquipmentManager)
local RagdollGenerator = require(script.Parent.RagdollGenerator)
local XPManager = require(script.Parent.XPManager)
local ProgressionService = require(game.ReplicatedStorage.ProgressionService)
local CollectionService = game:GetService("CollectionService")
local HttpService = game:GetService("HttpService")
local DamageTag = require(game.ReplicatedStorage.DamageTag)
local HUGE = math.huge
local RAY = Ray.new
local V3 = Vector3.new
local CF = CFrame.new
local FFC = game.FindFirstChild
local RayCast = workspace.FindPartOnRayWithIgnoreList
local TICK = tick
Mob.EnemyTies = {
["Good"] = "Evil";
["Evil"] = "Good";
};
function Mob.new(...)
local args = {...}
local mobObj = {}
mobObj.Character = args[1]
local disabledState = {
Enum.HumanoidStateType.Swimming;
Enum.HumanoidStateType.Flying;
Enum.HumanoidStateType.StrafingNoPhysics;
};
local climbingDisabled = args[2]
if climbingDisabled then
disabledState[#disabledState+1] = Enum.HumanoidStateType.Climbing;
end
mobObj.Humanoid = mobObj.Character:FindFirstChildOfClass("Humanoid")
mobObj.Pathfinder = MobService.Pathfinder.new(mobObj.Character.PrimaryPart,mobObj.Humanoid,mobObj.Character);
mobObj.Torso = mobObj.Character.Torso
mobObj.ASM = ASMClass.new(mobObj.Humanoid,disabledState,{
RightShoulder = mobObj.Torso:FindFirstChild("Right Shoulder");
LeftShoulder = mobObj.Torso:FindFirstChild("Left Shoulder");
LeftHip = mobObj.Torso:FindFirstChild("Left Hip");
RightHip = mobObj.Torso:FindFirstChild("Right Hip");
})
if mobObj.Character:FindFirstChild("BOT") then
mobObj.Bot = require(mobObj.Character.BOT)
end
mobObj.MEM = MEMClass.new(mobObj.Character,mobObj.Bot.ArmorName,mobObj.Bot.WeaponName)
mobObj.RagdollGenerator = RagdollGenerator.new(mobObj.Character)
CollectionService:AddTag(mobObj.Character,HttpService:GenerateGUID(false))
mobObj.XPM = XPManager.new(mobObj.Bot.Credits,mobObj.Bot.XP,mobObj.Humanoid)
mobObj.Mana = mobObj.Bot.Mana
mobObj.Character.Name = mobObj.Bot.MobName
mobObj.Connections = {}
mobObj.Humanoid.Health = mobObj.Humanoid.MaxHealth
mobObj.FightRoutine = nil
mobObj.CombatState = "Offense"
mobObj.Target = nil
mobObj.RNG = Random.new()
mobObj.RoleUpdateFuncs = {}
mobObj.BindableService = require(game.ReplicatedStorage.BindingService)()
mobObj.Patrolling = false
mobObj.InCombatStage = false
mobObj.SightedEnemy = false
mobObj.GrenadeThrow = true
mobObj.FlightControls = nil
mobObj.IgnoreList = {}
return setmetatable(mobObj,Mob)
end
function Mob:GetWeapon()
return self.MEM.Weapon
end
function Mob:Init(...)
local args = {...}
self.Connections[#self.Connections+1] = self.Humanoid.Died:connect(function()
coroutine.yield(self.FightRoutine)
spawn(function()
self.MEM:Unequip()
end)
self.XPM:CollectTags()
self.XPM:CalculateHealth()
self.XPM:Sort()
self.XPM:SendFirstTagToKillFeed()
if self.Bot.Role ~= "FighterPilot" then
self.XPM:Distribute(function(tag)
end)
elseif self.Bot.Role == "FighterPilot" then
self.XPM:Distribute(function(tag)
ProgressionService:AddXP(tag.Killer,25,"starfighter")
end)
end
spawn(function()
self.Bot.Loot:Calculate()
self.Bot.Loot:Distribute(self.Character)
end)
for _, c in pairs(self.Connections) do
c:Disconnect()
end
spawn(function()
self.RagdollGenerator()
self.MEM:NecroEquip(self.Character,self.Bot.ArmorName)
end)
self.ASM:Destroy()
repeat wait() until not self.Character
setmetatable(self,nil)
end)
self.IgnoreList[#self.IgnoreList+1] = self.Character
if self.Bot.Role ~= "FighterPilot" then
self.Connections[#self.Connections+1] = self.Humanoid.HealthChanged:connect(function(health)
if self.MEM.CurrentHealth > health and health ~= 0 then
if self:GetWeapon() then
self.SightedEnemy = true
local tags = game.CollectionService:GetTags(self.Humanoid)
for _, tagStr in pairs(tags) do
local tag = DamageTag.ParseTag(tagStr)
if tag then
if tag:GetKiller() then
if tag:GetKiller():FindFirstChildOfClass("Humanoid") then
self.Character.SetTarget:Fire(tag:GetKiller():FindFirstChildOfClass("Humanoid"))
elseif tag:GetKiller():IsA("Player") then
self.Character.SetTarget:Fire(tag:GetKiller().Character:FindFirstChildOfClass("Humanoid"))
end
self.Character.SetState:Fire("Defense")
end
end
end
wait(2.5)
if self.Humanoid.Health > 0 then
self.SightedEnemy = false
end
end
end
self.MEM.CurrentHealth = health
end)
self.Connections[#self.Connections+1] = self.Humanoid.Running:connect(function(Speed)
if Speed > 0 and self:GetWeapon() then
self:GetWeapon().TargetCFrame.Value = CF(self.Character.Head.CFrame.p + (((self.Humanoid.WalkToPoint - self.Character.Head.CFrame.p).unit * V3(1,0,1)) * 200))
end
end)
self.IgnoreList[#self.IgnoreList+1] = self.Character.Parent
end
self.ASM:Init()
self.ASM:Start()
self.MEM:Equip(self.Bot.Role)
self:AddRole("Standard",function(mob)
mob.InCombatStage = true
if math.random(1,16) == 16 then
local PatrolPoint = mob:GetPatrollingPoint()
if PatrolPoint then
mob.Pathfinder.Target = PatrolPoint.p
local status = self.Pathfinder:ComputePath(true)
if status == Enum.PathStatus.Success then
mob.Patrolling = true
mob.Humanoid.WalkSpeed = 25
mob.Patrolling = true
mob.Pathfinder:Start(1,function()
mob:SearchForTarget()
end)
repeat wait() until ((PatrolPoint.p - mob:GetCFrame().p).magnitude <= 5) or mob.Target
end
end
if not mob then
return
end
mob.Patrolling = false
if not mob:TargetIsValid() then
mob:SearchForTarget()
end
if not mob then
return
end
if mob:TargetIsValid() and mob.CombatState == "Offense" then
mob.Pathfinder.Target = mob:GetTargetCFrame().p
local Distance = (mob:GetTargetCFrame().p - mob:GetCFrame().p).magnitude
if mob:HasClearLineOfSightForPoint(mob:GetTargetCFrame().p) then
mob.Humanoid.WalkSpeed = 25
mob.Humanoid:MoveTo(mob:GetTargetCFrame().p)
local range = mob.RNG:NextNumber(mob.Bot.ShootRange.Min,mob.Bot.ShootRange.Max)
if mob:TargetIsValid() and (((mob:GetTargetCFrame().p - mob:GetCFrame().p).magnitude <= range)) and mob:HasClearLineOfSight() then
mob.SightedEnemy = true
mob:SetShooting(true)
mob.Humanoid.WalkSpeed = 0
mob:SetAimed(true)
spawn(function()
if mob.RNG:NextInteger(1,16) == 16 and mob.GrenadeThrow then
mob.GrenadeThrow = false
mob:SetShooting(false)
mob:GetWeapon().throwGrenade:Fire(1)
mob:SetShooting(true)
wait(32)
mob.GrenadeThrow = true
end
end)
repeat
mob:GetWeapon().TargetCFrame.Value = mob:GetTargetCFrame()
if mob.CombatState ~= "Offense" then
break
end
wait()
until
(not mob:IsAlive()) or (not mob:TargetIsValid()) or (mob:GetTargetCFrame().p - mob:GetCFrame().p).magnitude > range
mob:SetAimed(false)
mob.Humanoid.WalkSpeed = 16
mob:SetShooting(false)
mob.SightedEnemy = false
end
else
local status = mob.Pathfinder:ComputePath(false)
if status == Enum.PathStatus.Success then
mob.Humanoid.WalkSpeed = 25
mob.Pathfinder:Start(1,function()
local range = mob.RNG:NextNumber(mob.Bot.ShootRange.Min,mob.Bot.ShootRange.Max)
if mob:TargetIsValid() and (((mob:GetTargetCFrame().p - mob:GetCFrame().p).magnitude <= range)) and mob:HasClearLineOfSight() then
mob.SightedEnemy = true
mob:SetShooting(true)
mob.Humanoid.WalkSpeed = 0
mob.Pathfinder:Stop("EnemySighted")
mob:SetAimed(true)
spawn(function()
if mob.RNG:NextInteger(1,16) == 16 and mob.GrenadeThrow then
mob.GrenadeThrow = false
mob:SetShooting(false)
mob:GetWeapon().throwGrenade:Fire(1)
mob:SetShooting(true)
wait(32)
mob.GrenadeThrow = true
end
end)
repeat
mob:GetWeapon().TargetCFrame.Value = mob:GetTargetCFrame()
if mob.CombatState ~= "Offense" then
break
end
wait()
until
(not mob:IsAlive()) or (not mob:TargetIsValid()) or (mob:GetTargetCFrame().p - mob:GetCFrame().p).magnitude > range
mob:SetAimed(false)
mob.Humanoid.WalkSpeed = 16
mob:SetShooting(false)
mob.SightedEnemy = false
end
end)
end
end
elseif mob.CombatState == "Defense" then
mob.SightedEnemy = true
mob:SetShooting(true)
mob.Humanoid.WalkSpeed = 0
mob:SetAimed(true)
spawn(function()
if mob.RNG:NextInteger(1,16) == 16 and mob.GrenadeThrow then
mob.GrenadeThrow = false
mob:SetShooting(false)
mob:GetWeapon().throwGrenade:Fire(1)
mob:SetShooting(true)
wait(32)
mob.GrenadeThrow = true
end
end)
repeat
mob:GetWeapon().TargetCFrame.Value = mob:GetTargetCFrame()
wait()
until
(not mob:IsAlive()) or (not mob:TargetIsValid()) or mob.CombatState ~= "Defense" or (mob:GetTargetCFrame().p - mob:GetCFrame().p).magnitude > 180
mob:SetAimed(false)
mob.Humanoid.WalkSpeed = 25
mob:SetShooting(false)
mob.SightedEnemy = false
end
if not mob then
return
end
end
mob.CombatState = "Offense"
mob.InCombatStage = false
end)
self:AddRole("Sniper",function(mob)
mob:SearchForTarget()
if mob:TargetIsValid() then
local Distance = (mob:GetTargetCFrame().p - mob:GetCFrame().p).magnitude
if mob:HasClearLineOfSight() then
mob:SetAimed(true)
mob.SightedEnemy = true
repeat
mob:GetWeapon().TargetCFrame.Value = mob:GetTargetCFrame()
wait()
until
mob.Humanoid.Health <= 0 or mob:HasClearLineOfSight() or (mob:GetTargetCFrame().p - mob:GetCFrame().p).magnitude > mob:GetMaximumDetectionDistance()
if mob:HasClearLineOfSight() then
mob:GetWeapon().Activate:Fire()
wait(2)
end
mob:SetAimed(false)
mob.SightedEnemy = false
end
end
end)
if self.Bot.Role == "FighterPilot" then
self.Humanoid.Seated:wait()
self.FlightControls = self.Humanoid.SeatPart.GetController:Invoke()
self:AddRole("FighterPilot",function(mob)
local PPoint = mob:GetRandomPoint()
mob.FlightControls:SetDirection(PPoint)
mob.FlightControls:SetVelocity(50)
for i = 1 , 4 do
mob.FlightControls:SetVelocity(50)
wait(1)
end
mob:SearchForTarget(false)
if mob:TargetIsValid() then
mob.FlightControls:SetDirection(mob:GetTargetCFrame().p)
mob.FlightControls:SetVelocity(50)
mob:SetShooting(true)
mob.SightedEnemy = true
repeat
mob.FlightControls:SetDirection(mob:GetTargetCFrame().p)
mob.FlightControls:SetVelocity(50)
wait(1/60)
until
(not mob:IsAlive()) or (not mob:TargetIsValid()) or (mob:GetTargetCFrame().p - mob:GetCFrame().p).magnitude < 200 or (not mob:HasClearLineOfSight())
mob.SightedEnemy = false
mob:SetShooting(false)
end
end)
end
self.FightRoutine = coroutine.create(function()
self:InitializeBehaviors()
while self:IsAlive() do
self:Update()
repeat wait() until (not self.InCombatStage) or (not self:IsAlive())
wait()
end
end)
if self.FlightControls then
self.FlightControls:StartEngine()
self.FlightControls:SetVelocity(150)
end
coroutine.resume(self.FightRoutine)
end
function Mob:GetCFrame()
local humanoidRootPart = FFC(self.Character,'Torso')
if humanoidRootPart ~= nil and humanoidRootPart:IsA('BasePart') then
return humanoidRootPart.CFrame
else
return CF()
end
end
function Mob:GetRandomPoint()
return V3(self.RNG:NextNumber(-500,500),self.RNG:NextNumber(900,1000),self.RNG:NextNumber(-500,500))
end
function Mob:SetShooting(shooting)
self.Character.Shooting.Value = shooting
end
function Mob:SetAimed(aimed)
self.Character.SetAimed:Fire(aimed)
end
function Mob:GetMaximumDetectionDistance()
-- Returns the maximum detection distance
local setting = self.Bot.ChaseRange
if setting < 0 then
return HUGE
else
return setting
end
end
function Mob:GetTargetCFrame()
local targetHumanoid = self.Target
if self:TargetIsValid() then
if targetHumanoid.Parent.PrimaryPart then
return targetHumanoid.Parent.PrimaryPart.CFrame
else
return CF()
end
else
return CF()
end
end
function Mob:AddRole(name,actions)
self.RoleUpdateFuncs[name] = actions
end
function Mob:GetClosestEnemies()
local result = {}
local enemyAIs = workspace.Mobs:GetChildren()
-- local Tanks = workspace.Tanks:GetChildren()
local fighters
if self.Bot.Role == "FighterPilot" then
fighters = workspace.Fighters:FindFirstChild(Mob.EnemyTies[self.Bot.Allegiance]):GetChildren()
for i, enemy in next, fighters, nil do
if enemy then
if enemy:FindFirstChild("Human",true) then
local enemy2 = enemy:FindFirstChild("Human",true).Parent
if require(enemy2.BOT).Allegiance ~= self.Bot.Allegiance and enemy2.PrimaryPart then
local distance = (enemy2.PrimaryPart.CFrame.p - self:GetCFrame().p).magnitude
if distance < self:GetMaximumDetectionDistance() then
result[#result+1] = enemy2
end
end
end
end
end
end
local enemyPlayers = self.BindableService.fetch("PlayerList")
for i = 1, #enemyAIs do
local enemy = enemyAIs[i]
if enemy then
if enemy:FindFirstChildOfClass("Humanoid") then
if require(enemy.BOT).Allegiance ~= self.Bot.Allegiance and enemy.PrimaryPart then
local distance = (enemy.PrimaryPart.CFrame.p - self:GetCFrame().p).magnitude
if distance < self:GetMaximumDetectionDistance() then
result[#result+1] = enemy
end
end
end
end
end
-- for i, enemy in next, Tanks, nil do
-- if enemy then
-- if enemy:FindFirstChild("Human") then
-- if require(enemy.BOT).Allegiance ~= Bot.Allegiance and enemy.PrimaryPart then
-- local distance = (enemy.PrimaryPart.CFrame.p - Monster:GetCFrame().p).magnitude
-- if distance < Monster:GetMaximumDetectionDistance() then
-- result[#result+1] = enemy
-- end
-- end
-- end
-- end
-- end
for i = 1, #enemyPlayers do
local enemy = enemyPlayers[i]
if enemy then
if enemy.Character and enemy.Character:FindFirstChildOfClass("Humanoid")then
if enemy.Allegiance.Value ~= self.Bot.Allegiance and enemy.Character.PrimaryPart then
local distance = (enemy.Character.PrimaryPart.CFrame.p - self:GetCFrame().p).magnitude
if distance < self:GetMaximumDetectionDistance() then
result[#result+1] = enemy.Character
local squadMates = enemy.playerArmy.Value:GetChildren()
for j = 1, #squadMates do
local secondEnemy = squadMates[j]
if secondEnemy:FindFirstChildOfClass("Humanoid") and secondEnemy.PrimaryPart then
local distance = (secondEnemy.PrimaryPart.CFrame.p - self:GetCFrame().p).magnitude
if distance < self:GetMaximumDetectionDistance() then
result[#result+1] = secondEnemy
end
end
end
end
end
end
end
end
return result
end
function Mob:IsAlive()
return self.Humanoid.Health > 0 and self.Humanoid.Torso ~= nil
end
function Mob:SearchForTarget(randomized)
-- Finds the closest player and sets the target
local npcs = self:GetClosestEnemies()
local closestCharacter, closestCharacterDistance
for i, npc in next, npcs, nil do
if npc:FindFirstChild("BOT") then
local npcBOT = require(npc.BOT)
if npcBOT.Allegiance ~= self.Bot.Allegiance then
if npc ~= nil and npc.PrimaryPart and npc:FindFirstChild('Human') ~= nil and (npc.Human:IsA('Humanoid') or npc:FindFirstChild("TankManager")) then
local distance = (npc.PrimaryPart.CFrame.p - self:GetCFrame().p).magnitude
if distance < self:GetMaximumDetectionDistance() then
if closestCharacter == nil then
closestCharacter, closestCharacterDistance = npc, distance
else
if closestCharacterDistance > distance then
closestCharacter, closestCharacterDistance = npc, distance
end
end
end
end
end
else
local player = game.Players:GetPlayerFromCharacter(npc)
if player then
if player.Allegiance.Value ~= self.Bot.Allegiance then
if npc ~= nil and npc.PrimaryPart and npc:FindFirstChild('Humanoid') ~= nil and (npc.Humanoid:IsA('Humanoid')) then
local distance = (npc.PrimaryPart.CFrame.p - self:GetCFrame().p).magnitude
if distance < self:GetMaximumDetectionDistance() then
if closestCharacter == nil then
closestCharacter, closestCharacterDistance = npc, distance
else
if closestCharacterDistance > distance then
closestCharacter, closestCharacterDistance = npc, distance
end
end
end
end
end
end
end
end
if closestCharacter ~= nil then
self.Target = closestCharacter:FindFirstChildOfClass("Humanoid")
end
end
function Mob:Update()
if self:IsAlive() then
self.RoleUpdateFuncs[self.Bot.Role](self)
end
end
function Mob:TargetIsValid()
local targetHumanoid = self.Target
if targetHumanoid and targetHumanoid:IsA 'Humanoid' and not targetHumanoid:IsDescendantOf(workspace.CorpseIgnore) and targetHumanoid.Parent then
return true
else
return false
end
end
function Mob:HasClearLineOfSight()
-- Going to cast a ray to see if I can just see my target
local myPos, targetPos = self:GetCFrame().p, self:GetTargetCFrame().p
local hit, pos = RayCast(workspace,
RAY(
myPos,
targetPos - myPos
),
{
self.Character
}
)
return hit ~= nil and hit:IsDescendantOf(self.Target.Parent)
end
function Mob:HasClearLineOfSightForPoint(point)
-- Going to cast a ray to see if I can just see my target
local myPos, targetPos = self:GetCFrame().p, point
local hit, pos = RayCast(workspace,
RAY(
myPos,
targetPos - myPos
),
{
self.Character
}
)
return hit == nil
end
function Mob:IsReachable(point)
local PathFS = game:GetService("PathfindingService")
local Path = PathFS:FindPathAsync(self:GetCFrame().p,point.CFrame.p)
return Path.Status == Enum.PathStatus.Success
end
function Mob:IsReachableCFrame(point)
local PathFS = game:GetService("PathfindingService")
local Path = PathFS:FindPathAsync(self:GetCFrame().p,point.p)
return Path.Status == Enum.PathStatus.Success
end
function Mob:GetPatrollingPoint ()
local points = {}
local result = nil
local PatrollingPoints = self.BindableService.fetch("GetPatrolPoints")
for _, point in pairs(PatrollingPoints) do
if self:IsReachableCFrame(point) then
points[#points+1] = point
end
end
if #points > 0 then
result = points[self.RNG:NextInteger(1,#points)]
end
return result
end
function Mob:InitializeBehaviors()
self.Character.GetTarget.OnInvoke = function()
return self.Target
end
self.Character.SetTarget.Event:connect(function(target)
self.Target = target
end)
self.Character.SetState.Event:connect(function(STATE)
self.CombatState = STATE
end)
if self.Bot.Role == "Sniper" then
self:GetWeapon().ChangeStance:Fire("Prone")
end
end
--[[
local PFinding = game:GetService("PathfindingService")
local ITT = Mob.Transport.Value
if ITT then
function getSeat()
local seats = {}
for _, item in pairs(ITT:GetChildren()) do
if item.Name == "SeatPlacement" then
seats[#seats+1] = item
end
end
return seats[Mob.ID.Value]
end
local Path = PFinding:FindPathAsync(Mob.Torso.CFrame.p,ITT.EntryPart.CFrame.p)
if Path.Status == Enum.PathStatus.Success then
local points = Path:GetWaypoints()
for _, point in pairs(points) do
if point.Action == Enum.PathWaypointAction.Jump then
Humanoid.Jump = true
end
Humanoid:MoveTo(point.Position)
Humanoid.MoveToFinished:wait()
end
end
local Path = PFinding:FindPathAsync(Mob.Torso.CFrame.p,ITT.EntryPart2.CFrame.p)
if Path.Status == Enum.PathStatus.Success then
local points = Path:GetWaypoints()
for _, point in pairs(points) do
if point.Action == Enum.PathWaypointAction.Jump then
Humanoid.Jump = true
end
Humanoid:MoveTo(point.Position)
Humanoid.MoveToFinished:wait()
end
end
if (getSeat().CFrame.p - Mob.Torso.CFrame.p).magnitude> 5 then
local Path = PFinding:FindPathAsync(Mob.Torso.CFrame.p,ITT.EntryPart3.CFrame.p)
if Path.Status == Enum.PathStatus.Success then
local points = Path:GetWaypoints()
for _, point in pairs(points) do
if point.Action == Enum.PathWaypointAction.Jump then
Humanoid.Jump = true
end
Humanoid:MoveTo(point.Position)
Humanoid.MoveToFinished:wait()
end
end
end
if (getSeat().CFrame.p - Mob.Torso.CFrame.p).magnitude > 5 then
local Path = PFinding:FindPathAsync(Mob.Torso.CFrame.p,ITT.EntryPart4.CFrame.p)
if Path.Status == Enum.PathStatus.Success then
local points = Path:GetWaypoints()
for _, point in pairs(points) do
if point.Action == Enum.PathWaypointAction.Jump then
Humanoid.Jump = true
end
Humanoid:MoveTo(point.Position)
Humanoid.MoveToFinished:wait()
end
end
end
local Path = PFinding:FindPathAsync(Mob.Torso.CFrame.p,getSeat().CFrame.p)
if Path.Status == Enum.PathStatus.Success then
local points = Path:GetWaypoints()
for _, point in pairs(points) do
if point.Action == Enum.PathWaypointAction.Jump then
Humanoid.Jump = true
end
Humanoid:MoveTo(point.Position)
Humanoid.MoveToFinished:wait()
end
end
end]]--
return Mob
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment