local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local events = ReplicatedStorage:WaitForChild("Events")
local spawnTowerEvent = events:WaitForChild("SpawnTower")
local animateTowerEvent = events:WaitForChild("AnimateTower")
local Functions = ReplicatedStorage:WaitForChild("Functions")
local requestTowerfunction = Functions:WaitForChild("RequestTower")
local maxTowers = 15
local tower = {}
function FindNearestTarget(newTower, range)
local nearestTarget = nil
for i, target in ipairs(workspace.Mobs:GetChildren()) do
local distance = (target.HumanoidRootPart.Position - newTower.HumanoidRootPart.Position).Magnitude
if distance < range then
nearestTarget = target
range = distance
end
end
return nearestTarget
end
function tower.Attack(newTower, player)
local Config = newTower.Config
local target = FindNearestTarget(newTower, Config.Range.Value)
if target and target:FindFirstChild("Humanoid") and target.Humanoid.Health > 0 then
local targetCFame = CFrame.lookAt(newTower.HumanoidRootPart.Position, target.HumanoidRootPart.Position)
newTower.HumanoidRootPart.BodyGyro.CFrame = targetCFame
animateTowerEvent:FireAllClients(newTower, "Attack")
target.Humanoid:TakeDamage(Config.Damage.Value)
if target.Humanoid.Health <= 0 then
player.Gold.Value += target.Humanoid.MaxHealth
end
task.wait(Config.Cooldown.Value)
end
task.wait(0.1)
tower.Attack(newTower, player)
end
function tower.Spawn(player, name, cframe)
local allowedToSpawn = tower.CheckSpawn(player, name)
if allowedToSpawn then
local newTower = ReplicatedStorage.Towers[name]:Clone()
newTower.HumanoidRootPart.CFrame = cframe
newTower.Parent = workspace.Towers
newTower.HumanoidRootPart:SetNetworkOwner(nil)
local bodyGyro = Instance.new("BodyGyro")
bodyGyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
bodyGyro.D = 0
bodyGyro.CFrame = newTower.HumanoidRootPart.CFrame
bodyGyro.Parent = newTower.HumanoidRootPart
for i, object in ipairs(newTower:GetDescendants()) do
if object:IsA("BasePart") then
PhysicsService:SetPartCollisionGroup(object, "Tower")
end
end
player.Gold.Value -= newTower.Config.Price.Value
player.PlacedTowers.Value += 1
coroutine.wrap(tower.Attack)(newTower, player)
else
warn("Requested tower does not exist", name)
end
end
spawnTowerEvent.OnServerEvent:Connect(tower.Spawn)
function tower.CheckSpawn(player, name)
local towerExists = ReplicatedStorage.Towers:FindFirstChild(name)
if towerExists then
if towerExists.Config.Price.Value <= player.Gold.Value then
if player.PlacedTowers.Value < maxTowers then
return true
else
warn("Player has reached the max Limit")
end
else
warn("Player cannot afford tower")
end
else
warn("Tower Does Not Exist")
end
return false
end
requestTowerfunction.OnServerInvoke = tower.CheckSpawn
return tower
I cannot conclude a direct reason as of now. But why do you set NetworkOwner to nil?
I do that because otherwise the Titans on path start jittering when your further away so Iām keeping it on client side.