I’m trying to get it so that the boss attacks the player as soon as they get too close, maybe like 50 yards away. But for some reason it doesn’t attack unless the player attacks first, and then after 1 or 2 attacks it just stops. How would I be able to fix this?
-- Directory
local NetworkUtility = require(game:GetService("ReplicatedStorage"):WaitForChild("Shared"):WaitForChild("Modules"):WaitForChild("Utilities"):WaitForChild("Network"))
local GameUtility = require(game:GetService("ReplicatedStorage"):WaitForChild("Shared"):WaitForChild("Modules"):WaitForChild("Utilities"):WaitForChild("Game"))
local ObserverUtility = require(game:GetService("ServerStorage"):WaitForChild("Modules"):WaitForChild("Utilities"):WaitForChild("Observer"))
local MobStructures = require(game:GetService("ServerStorage"):WaitForChild("Modules"):WaitForChild("Structures"):WaitForChild("Mob"))
--local DataUtility = require(game:GetService("ServerStorage"):WaitForChild("Modules"):WaitForChild("Utilities"):WaitForChild("Data"))
local PhysicsService = game:GetService("PhysicsService")
local ServerStorage = game:GetService("ServerStorage")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
-- Assets
local ServerAssets = ServerStorage:WaitForChild("Assets")
local MobAssets = ServerAssets:WaitForChild("Mobs")
local BossAssets = MobAssets:WaitForChild("Bosses")
local BossAdditionals = BossAssets:WaitForChild("Additionals")
local BossModels = BossAssets:WaitForChild("Models")
local BossTools = BossAdditionals:WaitForChild("Tools")
local WorkspaceBosses = workspace:WaitForChild("Bosses")
local WorkspaceBossEntrances = workspace:WaitForChild("BossEntrances")
-- Variables
local Module = {}
Module.__index = Module
Module["Bosses"] = {} -- {[Zone] = BossData,}
Module["AttackingPlayers"] = {} -- {[Zone] = BossData,}
Module["ActiveBossesData"] = {} -- {[Zone] = {[BossName] = {[Health] = {}, [AttackingPlayers] = {[UserId] = {Damage, Coins, Gems}, [GeneralData] = {} }
local AllBosses= Module["Bosses"]
local AttackingPlayers = Module["AttackingPlayers"]
local ActiveBossesData = Module["ActiveBossesData"]
local MobPrototypes = MobStructures["Prototypes"]
local BossPrototypes = MobPrototypes["Bosses"]
local MobInitializers = MobStructures["Initializers"]
local BossInitializers = MobInitializers["Bosses"]
-- Settings
local BossOrientationMaximumValue = Vector3.new(400000, 400000, 400000)
local MobCollisionGroupName = "MobGroup"
local DisabledHumanoidStates = {
Enum.HumanoidStateType.StrafingNoPhysics,
Enum.HumanoidStateType.PlatformStanding,
Enum.HumanoidStateType.RunningNoPhysics,
Enum.HumanoidStateType.FallingDown,
Enum.HumanoidStateType.GettingUp,
Enum.HumanoidStateType.Climbing,
Enum.HumanoidStateType.Swimming,
Enum.HumanoidStateType.Jumping,
Enum.HumanoidStateType.Running,
Enum.HumanoidStateType.Ragdoll,
Enum.HumanoidStateType.Physics,
Enum.HumanoidStateType.Flying,
Enum.HumanoidStateType.Seated,
Enum.HumanoidStateType.Dead,
}
local MobStates = {
"Idle",
"Dead",
"Moving",
"Attacking"
}
-- Main
local function SetupBossModel(MobModel, MobInformation, MobInstances)
local MobHealth = MobInformation["Health"]
do
local MobDescendants = MobModel:GetDescendants()
for Index = 1, #MobDescendants do
local Part = MobDescendants[Index]
if Part:IsA("BasePart") then
PhysicsService:SetPartCollisionGroup(Part, MobCollisionGroupName)
end
if Part:IsA("BillboardGui") then
MobInstances["Interface"] = Part
end
end
end
do
local MobHumanoid = MobModel:FindFirstChild("Humanoid")
local MobRootPart = MobHumanoid.RootPart
local MobOrientation = MobRootPart:FindFirstChild("Orientation")
local MobAnimations = MobModel:FindFirstChild("Animations")
do
MobInstances["Humanoid"] = MobHumanoid
MobInstances["RootPart"] = MobRootPart
MobInstances["Orientation"] = MobOrientation
MobInstances["Animations"] = MobAnimations
end
end
end
local function RewardBossPlayerAttacks(PlayersAttacking, BossZone)
for UserId, PlayersAttackData in next, PlayersAttacking do
local PlayerData = PlayersAttackData["PlayerData"]
local Player = PlayerData["Player"]
if Player and Players:FindFirstChild(Player.Name) then
if type(PlayerData) == "table" and getmetatable(PlayerData) then
local Coins = PlayersAttackData["Coins"]
local Gems = PlayersAttackData["Gems"]
PlayerData:IncrementUserstatsValue("Coins", Coins)
PlayerData:IncrementUserstatsValue("Gems", Gems)
NetworkUtility.FireRemoteEvent("UpdateUserstats", false, Player, "RewardUserstatsValue", PlayerData["Data"]["Userstats"], {"Coins", Coins})
NetworkUtility.FireRemoteEvent("UpdateUserstats", false, Player, "RewardUserstatsValue", PlayerData["Data"]["Userstats"], {"Gems", Gems})
NetworkUtility.FireRemoteEvent("UpdateOthers", false, Player, "TeleportBossPlayers", PlayerData["Data"]["Others"], BossZone)
do
PlayersAttackData["Damage"] = 0
PlayersAttackData["Coins"] = 0
PlayersAttackData["Gems"] = 0
end
else
PlayersAttackData[UserId] = nil
end
end
end
end
function Module.InitializeBosses()
for ZoneName, ZoneBossData in next, BossInitializers do
local Name = ZoneBossData["Name"]
local Position = ZoneBossData["Position"]
local BossPrototype = GameUtility.CloneTable(BossPrototypes[Name])
local BossInformation = BossPrototype["Information"]
local BossInstances = BossPrototype["Instances"]
local BossTemplate = BossModels:FindFirstChild(Name)
local ToolTemplate = BossTools:FindFirstChild(BossInformation["Tool"]["Name"])
if BossTemplate and ToolTemplate then
BossInstances["BossTemplate"] = BossTemplate
BossInstances["ToolTemplate"] = ToolTemplate
BossInformation["Position"] = Position
BossInformation["Zone"] = ZoneName
do
local BossParent = WorkspaceBosses:FindFirstChild(ZoneName)
if not BossParent then
local Folder = Instance.new("Folder")
Folder.Name = ZoneName
Folder.Parent = WorkspaceBosses
BossParent = Folder
end
BossInstances["Parent"] = BossParent
end
AllBosses[ZoneName] = {}
AllBosses[ZoneName][Name] = BossPrototype
AttackingPlayers[ZoneName] = {}
ActiveBossesData[ZoneName] = {}
ActiveBossesData[ZoneName][Name] = {
["Health"] = BossInformation["Health"],
["AttackingPlayers"] = {},
["Status"] = true,
["GeneralData"] = {
["Damage"] = BossInformation["Damage"],
},
}
setmetatable(BossPrototype, Module)
BossPrototype:AutoUpdate()
BossPrototype:Respawn()
end
end
end
function Module.GetBoss(Zone, Name)
local ZoneBosses = AllBosses[Zone]
if ZoneBosses then
return ZoneBosses[Name]
end
end
--// Functionalities //--
function Module:Respawn()
local BossInformation = self["Information"]
local BossInstances = self["Instances"]
self:Despawn()
do
local BossTemplate = BossInstances["BossTemplate"]
local SpawnPosition = BossInformation["Position"]
local Parent = BossInstances["Parent"]
do -- Boss Model
local BossModel = BossTemplate:Clone()
BossModel.Parent = Parent
BossInstances["Boss"] = BossModel
SetupBossModel(BossModel, BossInformation, BossInstances)
BossModel:MoveTo(SpawnPosition)
BossInformation["State"] = MobStates[1]
BossInformation["Health"][1] = BossInformation["Health"][2]
self:EquipTool()
end
end
end
function Module:Despawn()
local BossInformation = self["Information"]
local BossInstances = self["Instances"]
self:ResetState()
self:UnequipTool()
do
BossInformation["State"] = MobStates[2]
if BossInstances["Boss"] then
BossInstances["Boss"]:Destroy()
BossInstances["Boss"] = nil
end
end
end
function Module:EquipTool()
local BossInformation = self["Information"]
local BossInstances = self["Instances"]
self:UnequipTool()
do
local ToolTemplate = BossInstances["ToolTemplate"]
local ToolData = BossInformation["Tool"]
local BossModel = BossInstances["Boss"]
if BossModel then
local Tool = ToolTemplate:Clone()
do
local ToolDescendants = Tool:GetDescendants()
for Index = 1, #ToolDescendants do
local Part = ToolDescendants[Index]
if Part:IsA("BasePart") then
PhysicsService:SetPartCollisionGroup(Part, MobCollisionGroupName)
end
end
end
Tool.Parent = BossModel
BossInstances["Tool"] = Tool
GameUtility.WeldToolToCharacterAttachment(BossModel, Tool, ToolData["Limb"], ToolData["Attachment"])
end
end
end
function Module:UnequipTool()
local BossInformation = self["Information"]
local BossInstances = self["Instances"]
local Tool = BossInstances["Tool"]
local BossModel = BossInstances["Boss"]
local BossHumanoid = BossInstances["Humanoid"]
if Tool and BossModel and BossHumanoid then
BossInstances["Tool"]:Destroy()
BossInstances["Tool"] = nil
BossHumanoid:UnequipTools()
end
end
function Module:ResetState()
local BossInformation = self["Information"]
local BossInstances = self["Instances"]
local MobOrientation = BossInstances["Orientation"]
local BossHumanoid = BossInstances["Humanoid"]
local BossRootPart = BossInstances["RootPart"]
if BossHumanoid and BossRootPart and MobOrientation then
do -- Reset Mob Movement
local PlayingAnimations = BossHumanoid:GetPlayingAnimationTracks()
for Index = 1, #PlayingAnimations do
PlayingAnimations[Index]:Stop()
end
BossHumanoid:MoveTo(BossRootPart.Position)
BossInstances["ActiveAnimationTrack"] = nil
end
do
MobOrientation.MaxTorque = Vector3.new(0, 0, 0)
BossInformation["IsUpdating"] = false
BossInformation["State"] = MobStates[3]
end
end
end
function Module:AutoUpdate()
local BossStimulationThread = coroutine.create(function()
while true do GameUtility.Yield()
local BossInformation = self["Information"]
local BossInstances = self["Instances"]
local State = BossInformation["State"]
local Zone = BossInformation["Zone"]
local ZoneAttackingPlayers = AttackingPlayers[Zone]
local AmountOfPlayers = #ZoneAttackingPlayers
do
if AmountOfPlayers > 0 and BossInformation["State"] ~= MobStates[4] then
self:ResetState()
BossInformation["State"] = MobStates[4]
else
if BossInformation["State"] == MobStates[4] and AmountOfPlayers == 0 then
self:ResetState()
end
end
end
if State == MobStates[1] and not BossInformation["IsUpdating"] and AmountOfPlayers == 0 then
local IdleThread = coroutine.wrap(function()
self:Idle()
end)
IdleThread()
end
if State == MobStates[3] and not BossInformation["IsUpdating"] and AmountOfPlayers == 0 then
local WanderThread = coroutine.wrap(function()
self:Wander()
end)
WanderThread()
end
if State == MobStates[4] and not BossInformation["IsUpdating"] and AmountOfPlayers > 0 then
--print("DOiii")
--spawn(function()
self:Attack()
--end)
end
end
end)
coroutine.resume(BossStimulationThread)
end
function Module:TakeDamage(PlayerData)
local BossInformation = self["Information"]
local BossInstances = self["Instances"]
local BossHealth = BossInformation["Health"]
local BossModel = BossInstances["Boss"]
local Player = PlayerData["Player"]
if BossModel and BossInformation["State"] == MobStates[4] then
local Zone = BossInformation["Zone"]
local Name = BossInformation["Name"]
local UserId = tostring(Player.UserId)
local ActiveBossData = ActiveBossesData[Zone][Name]
local BossAttackingPlayers = ActiveBossData["AttackingPlayers"]
if BossHealth[1] > 0 then
local DamageValue = (BossHealth[1] - 1) >= 0 and 1 or BossHealth[1]
BossHealth[1] = BossHealth[1] - DamageValue
do
local AttackingPlayerData = BossAttackingPlayers[UserId]
if not AttackingPlayerData then
BossAttackingPlayers[UserId] = {
["Coins"] = 0,
["Gems"] = 0,
["Damage"] = 0,
["PlayerData"] = PlayerData
}
AttackingPlayerData = BossAttackingPlayers[UserId]
end
do
local Mutlipliers = PlayerData["Data"]["Others"]["Multipliers"]
AttackingPlayerData["Damage"] = AttackingPlayerData["Damage"] + DamageValue
AttackingPlayerData["Coins"] = AttackingPlayerData["Coins"] + (BossInformation["Reward"]["Coins"] * Mutlipliers["Coins"])
AttackingPlayerData["Gems"] = AttackingPlayerData["Gems"] + (BossInformation["Reward"]["Gems"] * Mutlipliers["Gems"])
ActiveBossData["Health"][1] = BossHealth[1]
ActiveBossData["Health"][2] = BossHealth[2]
end
NetworkUtility.FireRemoteEvent("UpdateUserstats", true, "UpdateBosses", Zone, Name, ActiveBossData)
end
end
if BossHealth[1] == 0 then
local BossGeneralData = ActiveBossData["GeneralData"]
RewardBossPlayerAttacks(BossAttackingPlayers, Zone)
self:Despawn()
local BossCountdown = BossGeneralData["RespawnCountdown"]
local CountDownStart = os.time()
ActiveBossData["Status"] = false
NetworkUtility.FireRemoteEvent("UpdateUserstats", true, "UpdateBosses", Zone, Name, ActiveBossData)
do
local BossEntrace = WorkspaceBossEntrances:FindFirstChild(Zone)
local DisplayPart = BossEntrace:FindFirstChild("Display")
local Interface = DisplayPart:FindFirstChildOfClass("BillboardGui")
local ValueLabel = Interface:FindFirstChild("Value")
ValueLabel.TextColor3 = Color3.fromRGB(255, 0, 0)
while not ActiveBossData["Status"] do
local OffsetSeconds = 300 - (os.time() - CountDownStart)
local FormattedTime = GameUtility.ConvertSecondsToTime(OffsetSeconds)
ValueLabel.Text = FormattedTime["Hours"]..":"..FormattedTime["Minutes"]..":"..FormattedTime["Seconds"]
if OffsetSeconds <= 0 then
ValueLabel.TextColor3 = Color3.fromRGB(0, 255, 0)
ValueLabel.Text = "Ready for battle!"
ActiveBossData["Status"] = true
end
GameUtility.yi()
end
end
self:Respawn()
end
end
end
--// States //--
function Module:Idle()
local BossInformation = self["Information"]
local BossInstances = self["Instances"]
local BossModel = BossInstances["Boss"]
if BossModel then
local Zone = BossInformation["Zone"]
local BossHumanoid = BossInstances["Humanoid"]
local BossRootPart = BossInstances["RootPart"]
local BossAnmations = BossInstances["Animations"]
do -- Reset Mob Movement
local PlayingAnimations = BossHumanoid:GetPlayingAnimationTracks()
for Index = 1, #PlayingAnimations do
PlayingAnimations[Index]:Stop()
end
BossHumanoid:MoveTo(BossRootPart.Position)
BossInstances["ActiveAnimationTrack"] = nil
end
do
local IdleAnimations = BossAnmations:FindFirstChild("Idle")
if IdleAnimations then
BossInformation["IsUpdating"] = true
local IdleAnimationChildren = IdleAnimations:GetChildren()
local SelectedAnimation = IdleAnimationChildren[math.random(1, #IdleAnimationChildren)]
do
local AnimationTrack = BossHumanoid:LoadAnimation(SelectedAnimation)
AnimationTrack.Looped = true
BossInstances["ActiveAnimationTrack"] = AnimationTrack
local IdleLength = math.random(12, 25)
local IdleStartTime = tick()
AnimationTrack:Play()
while (tick() - IdleStartTime) <= IdleLength and BossInformation["IsUpdating"] do
GameUtility.Yield()
end
do
AnimationTrack:Stop()
BossInstances["ActiveAnimationTrack"] = nil
end
if BossInformation["State"] == MobStates[1] and BossInformation["IsUpdating"] then
BossInformation["State"] = MobStates[3]
end
BossInformation["IsUpdating"] = false
end
end
end
end
end
function Module:Wander()
local BossInformation = self["Information"]
local BossInstances = self["Instances"]
local BossModel = BossInstances["Boss"]
if BossModel then
local BossHumanoid = BossInstances["Humanoid"]
local BossRootPart = BossInstances["RootPart"]
local BossAnmations = BossInstances["Animations"]
local Zone = BossInformation["Zone"]
do -- Reset Mob Movement
local PlayingAnimations = BossHumanoid:GetPlayingAnimationTracks()
for Index = 1, #PlayingAnimations do
PlayingAnimations[Index]:Stop()
end
BossHumanoid:MoveTo(BossRootPart.Position)
BossInstances["ActiveAnimationTrack"] = nil
end
do -- Movement
local WalkAnimations = BossAnmations:FindFirstChild("Walk")
local OriginalPosition = BossInformation["Position"]
if WalkAnimations then
BossInformation["IsUpdating"] = true
local WalkAnimationChildren = WalkAnimations:GetChildren()
local PositionX, PositionZ = GameUtility.CalculateRandomCirclePoint(OriginalPosition, 18)
local MovementPosition = Vector3.new(PositionX, OriginalPosition.Y, PositionZ)
local SelectedAnimation = WalkAnimationChildren[math.random(1, #WalkAnimationChildren)]
do
local AnimationTrack = BossHumanoid:LoadAnimation(SelectedAnimation)
AnimationTrack.Looped = true
AnimationTrack:Play()
local MobDebouncePosition = Vector3.new(0, 0, 0)
local MobDebounceTimer = tick()
BossInstances["ActiveAnimationTrack"] = AnimationTrack
while BossInstances["ActiveAnimationTrack"] == AnimationTrack and BossInformation["IsUpdating"] do
BossHumanoid:MoveTo(MovementPosition)
BossHumanoid.MoveToFinished:Wait()
BossInstances["ActiveAnimationTrack"] = nil
AnimationTrack:Stop()
end
if BossInformation["State"] == MobStates[3] and BossInformation["IsUpdating"] then
BossInformation["State"] = MobStates[1]
end
BossInformation["IsUpdating"] = false
end
end
end
end
end
function Module:Attack(Player)
local BossInformation = self["Information"]
local BossInstances = self["Instances"]
local BossModel = BossInstances["Boss"]
local ToolModel = BossInstances["Tool"]
local Zone = BossInformation["Zone"]
if BossModel and ToolModel then
local BossAnimations = BossInstances["Animations"]
local BossOrientation = BossInstances["Orientation"]
local Position = BossInformation["Position"]
local ZoneAttackingPlayers = AttackingPlayers[Zone]
local ToolAnimations = ToolModel:FindFirstChild("Animations")
local AmountOfPlayers = #ZoneAttackingPlayers
if AmountOfPlayers == 0 then return end
do
local SelectedPlayerData = ZoneAttackingPlayers[math.random(1, AmountOfPlayers)]
local SelectedPlayer = SelectedPlayerData["Player"]
local Character = SelectedPlayer.Character or SelectedPlayer.CharacterAdded:Wait()
if ToolAnimations then
local HumanoidRootPart = Character:FindFirstChild("HumanoidRootPart")
local BossHumanoid = BossInstances["Humanoid"]
local BossRootPart = BossInstances["RootPart"]
if GameUtility.CheckPointOnCircle(Position, HumanoidRootPart.Position, 18) then
BossInformation["IsUpdating"] = true
local ToolAnimations = ToolModel:FindFirstChild("Animations")
local ActivationAnimations = ToolAnimations:FindFirstChild("Activation")
do -- Reset Mob Movement
local PlayingAnimations = BossHumanoid:GetPlayingAnimationTracks()
for Index = 1, #PlayingAnimations do
PlayingAnimations[Index]:Stop()
end
BossHumanoid:MoveTo(BossRootPart.Position)
BossInstances["ActiveAnimationTrack"] = nil
end
local ActivationAnimationChildren = ActivationAnimations:GetChildren()
local SelectedAnimation = ActivationAnimationChildren[math.random(1, #ActivationAnimationChildren)]
do
local AnimationTrack = BossHumanoid:LoadAnimation(SelectedAnimation)
BossOrientation.MaxTorque = BossOrientationMaximumValue
BossInstances["ActiveAnimationTrack"] = AnimationTrack
local OrientationThread = coroutine.wrap(function()
while BossInstances["ActiveAnimationTrack"] and BossInformation["IsUpdating"] do
local Direction = ((HumanoidRootPart.Position - BossRootPart.Position) * Vector3.new(1, 0, 1))
local ResultOrientation = CFrame.new(BossRootPart.Position, BossRootPart.Position + Direction)
BossOrientation.CFrame = ResultOrientation
GameUtility.Yield()
end
end)
OrientationThread()
if #ZoneAttackingPlayers == 0 then return end
AnimationTrack:Play()
AnimationTrack.Stopped:Wait(); GameUtility.Yield(.5)
ObserverUtility.FireObserverEvent("BossAttack", BossInformation, SelectedPlayer)
BossOrientation.MaxTorque = Vector3.new(0, 0, 0)
BossInformation["IsUpdating"] = false
end
end
end
end
end
end
return Module