-- TowerIdeas
--Mayhem, Rage, Violence, Malice, Malevolence -- 0 Stars (Starter Tower)
--Chaos, Destruction, Havoc, Depredation, Despoliation -- 2000 Stars
-- Purity, Holy, Angelic, Heavenly, Godlike -- 1500 Stars
-- Corruption, Vanta-X, Dark, Black, VOID -- 1500 Stars
-- MobIdeas
-- ORB (7500 HP)
-- UnitsIdeas
-- ShopServer
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local DataStoreService = game:GetService("DataStoreService")
local MarketplaceService = game:GetService("MarketplaceService")
local DataStore = DataStoreService:GetDataStore("fanum")
local towers = require(ReplicatedStorage:WaitForChild("TowerShop"))
local UpdateInventoryEvent = ReplicatedStorage:WaitForChild("UpdateInventory")
local maxSelectedTowers = 5
local data = {}
local function LoadData(player)
local success = nil
local playerData = nil
local attempt = 1
local leaderstats = Instance.new("Folder", player)
leaderstats.Name = "leaderstats"
repeat
success, playerData = pcall(function()
return DataStore:GetAsync(player.UserId)
end)
attempt += 1
if not success then
warn(playerData)
task.wait()
end
until success or attempt == 5
if success then
if not playerData then
playerData = {
["Stars"] = 0,
["Level"] = 1,
["Experience"] = 0,
["RequiredExperience"] = 10,
["SelectedTowers"] = {"Mayhem"},
["OwnedTowers"] = {"Mayhem", "Sword Novice"},
["OwnedSkins"] = {},
["EquippedSkins"] = {},
["SkinsHave"] = {},
["KilledEnemies"] = {},
}
end
local function GamepassCheck(GamepassID, TowerName)
local UserID = player.UserId
if MarketplaceService:UserOwnsGamePassAsync(UserID, GamepassID) then
if not table.find(playerData.OwnedTowers, TowerName) then
table.insert(playerData.OwnedTowers, TowerName)
else
return print(TowerName)
end
end
end
if not playerData.KilledEnemies then
playerData.KilledEnemies = {}
end
data[player.UserId] = playerData
local Stars = Instance.new("NumberValue", leaderstats)
Stars.Name = "Stars"
Stars.Value = playerData.Stars
local Level = Instance.new("NumberValue", leaderstats)
Level.Name = "Level"
Level.Value = playerData.Level
print(playerData.OwnedTowers)
while wait() do
if playerData.Level and playerData.Experience and playerData.RequiredExperience then
if playerData.Experience >= playerData.RequiredExperience then
playerData.Experience -= playerData.RequiredExperience
playerData.Level += 1
playerData.RequiredExperience = playerData.Level * 10
end
else
wait(playerData.Level and playerData.Experience and playerData.RequiredExperience)
if playerData.Experience >= playerData.RequiredExperience then
playerData.Experience -= playerData.RequiredExperience
playerData.Level += 1
playerData.RequiredExperience = playerData.Level * 10
end
end
end
data[player.UserId].Stars:Changed(function()
player.leaderstats.Stars.Value = data[player.UserId].Stars
end)
data[player.UserId].Level:Changed(function()
player.leaderstats.Level.Value = data[player.UserId].Level
end)
else
player:Kick("There was a problem getting your data, try again.")
end
end
Players.PlayerAdded:Connect(LoadData)
local function SaveData(player)
if data[player.UserId] then
local success = nil
local playerData = nil
local attempt = 1
repeat
success, playerData = pcall(function()
return DataStore:UpdateAsync(player.UserId, function()
return data[player.UserId]
end)
end)
attempt += 1
if not success then
warn(playerData)
task.wait()
end
until success or attempt == 5
if success then
print("Data saved successfully!")
else
warn("Unable to save data for", player.UserId)
end
else
warn("No session data for", player.UserId)
end
end
Players.PlayerRemoving:Connect(function(player)
SaveData(player)
data[player.UserId] = nil
end)
game:BindToClose(function()
if not RunService:IsStudio() then
for index, player in pairs(Players:GetPlayers()) do
task.spawn(function()
SaveData(player)
end)
end
else
print("Shutting down inside studio.")
end
end)
local function getItemStatus(player, itemName)
local playerData = data[player.UserId]
if table.find(playerData.SelectedTowers, itemName) then
return "Equipped"
elseif table.find(playerData.OwnedTowers, itemName) then
return "Owned"
else
return "Locked"
end
end
ReplicatedStorage.InteractItem.OnServerInvoke = function(player, itemName)
ReplicatedStorage.UpdateInventory:FireClient(player)
local shopItem = towers[itemName]
local playerData = data[player.UserId]
if shopItem and playerData then
local status = getItemStatus(player, itemName)
if status == "Locked" and shopItem.Price <= playerData.Stars then
playerData.Stars -= shopItem.Price
table.insert(playerData.OwnedTowers, shopItem.Name)
elseif status == "Owned" then
table.insert(playerData.SelectedTowers, shopItem.Name)
if #playerData.SelectedTowers > maxSelectedTowers then
table.remove(playerData.SelectedTowers, 1)
end
elseif status == "Equipped" then
if #playerData.SelectedTowers > 0 then
local towerToRemove = table.find(playerData.SelectedTowers, itemName)
table.remove(playerData.SelectedTowers, towerToRemove)
end
end
return playerData
else
warn("Tower/player data does not exist")
end
return false
end
ReplicatedStorage.InteractItemInventory.OnServerInvoke = function(player, itemName)
ReplicatedStorage.UpdateInventory:FireClient(player)
local shopItem = towers[itemName]
local playerData = data[player.UserId]
if shopItem and playerData then
local status = getItemStatus(player, itemName)
if status == "Locked" and shopItem.Price <= playerData.Stars then
playerData.Stars -= shopItem.Price
table.insert(playerData.OwnedTowers, shopItem.Name)
elseif status == "Owned" then
table.insert(playerData.SelectedTowers, shopItem.Name)
if #playerData.SelectedTowers > maxSelectedTowers then
table.remove(playerData.SelectedTowers, 1)
end
elseif status == "Equipped" then
if #playerData.SelectedTowers > 0 then
local towerToRemove = table.find(playerData.SelectedTowers, itemName)
table.remove(playerData.SelectedTowers, towerToRemove)
end
end
return playerData
else
warn("Tower/player data does not exist")
end
return false
end
ReplicatedStorage.GetData.OnServerEvent = function(player)
return data[player.UserId]
end
ReplicatedStorage.LevelData.GetLevelData.OnInvoke = function(player)
return data[player.UserId]
end
--ShopClient
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local towers = require(ReplicatedStorage:WaitForChild("TowerShop"))
local getDataFunction = ReplicatedStorage:WaitForChild("GetData")
local interactItemFunction = ReplicatedStorage:WaitForChild("InteractItem")
local gui = script.Parent
local Container = gui.Container
local exit = Container.Exit
local stars = Container.Stars
local limit = Container.Limit
local itemsFrame = Container.ItemsFrame
local itemBuyTFrame = Container.ItemBuyTower
local playerData = {}
local function getItemStatus(itemName)
if table.find(playerData.SelectedTowers, itemName) then
return "Equipped"
elseif table.find(playerData.OwnedTowers, itemName) then
return "Owned"
else
return "Locked"
end
end
local function interactItem(itemName)
local data = interactItemFunction:InvokeServer(itemName)
if data then
playerData = data
updateItems()
print(playerData.SelectedTowers)
end
end
function updateItems()
stars.Text = "★" .. playerData.Stars
limit.Text = #playerData.SelectedTowers .. "/5"
for i, tower in pairs(towers) do
local oldButton = itemsFrame:FindFirstChild(tower.Name)
if oldButton then
oldButton:Destroy()
end
local oldPldButton = itemBuyTFrame:GetChildren()
for x, o in pairs(oldPldButton) do
if not o:IsA("UICorner") or not o:IsA("UIAspectRatioConstraint") then
if o:IsA("TextButton") and o.Visible == true then
o:Destroy()
end
end
end
local newButton = itemsFrame.Template:Clone()
newButton.Name = tower.Name
newButton.TowerName.Text = tower.Name
newButton.Visible = true
newButton.Parent = itemsFrame
if tower.Level > playerData.Level then
newButton.Locked.Visible = true
newButton.Locked.Level.Text = "Lvl. " .. tower.Level
else
newButton.Locked.Visible = false
end
local RSTower = ReplicatedStorage:WaitForChild("Towers"):FindFirstChild(tower.Name):Clone()
RSTower.Parent = newButton.ViewportFrame.WorldModel
RSTower.PrimaryPart.CFrame = CFrame.new(0, 0, -3) * CFrame.Angles(0 , math.rad(-180), 0)
local Animations = RSTower:WaitForChild("Animations")
local Animator = RSTower:FindFirstChild("Humanoid"):FindFirstChildOfClass("Animator") or Instance.new("Animator", RSTower:FindFirstChild("Humanoid"))
local IdleAnimationTrack = Animator:LoadAnimation(Animations.Idle)
local WingAnimationTrack = Animator:LoadAnimation(Animations.WingAnim)
if IdleAnimationTrack then
IdleAnimationTrack:Play()
end
if WingAnimationTrack then
WingAnimationTrack:Play()
end
newButton.Activated:Connect(function()
if tower.Level > playerData.Level then
return
end
itemBuyTFrame.Visible = true
local oldPlButton = itemBuyTFrame:FindFirstChild(tower.Name)
if oldPlButton then
oldPlButton:Destroy()
end
local oldPldButton = itemBuyTFrame:GetChildren()
for x, o in pairs(oldPldButton) do
if not o:IsA("UICorner") or not o:IsA("UIAspectRatioConstraint") then
if o:IsA("TextButton") and o.Visible == true then
o:Destroy()
end
end
end
local PldButton = itemBuyTFrame.Template:Clone()
PldButton.Name = tower.Name
PldButton.TowerName.Text = tower.Name
PldButton.Desc.Text = tower.Description
PldButton.LayoutOrder = tower.Price
PldButton.Visible = true
PldButton.Parent = itemBuyTFrame
local RSTower2 = ReplicatedStorage:WaitForChild("Towers"):FindFirstChild(tower.Name):Clone()
RSTower2.Parent = PldButton.ViewportFrame.WorldModel
RSTower2.PrimaryPart.CFrame = CFrame.new(0, 0, -3) * CFrame.Angles(0 , math.rad(-180), 0)
local Animations = RSTower2:WaitForChild("Animations")
local Animator = RSTower2:FindFirstChild("Humanoid"):FindFirstChildOfClass("Animator") or Instance.new("Animator", RSTower2:FindFirstChild("Humanoid"))
local IdleAnimationTrack = Animator:LoadAnimation(Animations.Idle)
local WingAnimationTrack = Animator:LoadAnimation(Animations.WingAnim)
if IdleAnimationTrack then
IdleAnimationTrack:Play()
end
if WingAnimationTrack then
WingAnimationTrack:Play()
end
local status = getItemStatus(tower.Name)
print(status)
if status == "Locked" then
PldButton.Status.Cost.Text = "Stars ★: " .. tower.Price
PldButton.Status.BackgroundColor3 = Color3.new(0.9, 0, 0)
elseif status == "Equipped" then
PldButton.Status.Cost.Text = "Unequip"
PldButton.Status.BackgroundColor3 = Color3.new(0, 0.5, 0)
elseif status == "Owned" then
PldButton.Status.Cost.Text = "Equip"
PldButton.Status.BackgroundColor3 = Color3.new(0, 0.6666667, 1)
end
PldButton.Status.Activated:Connect(function()
interactItem(tower.Name)
end)
end)
end
end
local function TweenShopOut()
Container:TweenSizeAndPosition(UDim2.new(0.8, 0, 0.8, 0), UDim2.new(0.5, 0, 0.5, 0), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 1)
end
local function TweenShopIn()
Container:TweenSizeAndPosition(UDim2.new(0, 0, 0, 0), UDim2.new(0, 0, 0, 0), Enum.EasingDirection.In, Enum.EasingStyle.Quad, 1)
end
local function toggleShop()
Container.Visible = not Container.Visible
if Container.Visible then
itemBuyTFrame.Visible = false
playerData = getDataFunction:InvokeServer()
updateItems()
end
end
local function setupShop()
local prompty = Instance.new("ProximityPrompt", workspace.Map.Shop:WaitForChild("ShopPart"))
prompty.RequiresLineOfSight = false
prompty.ActionText = "Shop"
prompty.Triggered:Connect(toggleShop)
exit.Activated:Connect(toggleShop)
gui.Buttons.Shop.Activated:Connect(toggleShop)
end
setupShop()
--LoadoutClient
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local getDataFunction = ReplicatedStorage:WaitForChild("GetData")
local UpdateInventoryEvent = ReplicatedStorage:WaitForChild("UpdateInventory")
local gui = script.Parent
local function updateLoadout()
for i, button in ipairs(gui.Towers:GetDescendants()) do
if button:IsA("ImageButton") and button.Name ~= "Template" then
button:Destroy()
end
end
local playerData
repeat
playerData = getDataFunction:InvokeServer()
until playerData ~= nil
gui.Towers.Limit.Text = "Towers: " .. #playerData.SelectedTowers .. " / 5"
for i, t in pairs(playerData.SelectedTowers) do
local function Comma(Amount)
while true do
local digit
Amount, digit = string.gsub(Amount, "(-?%d+)(%d%d%d)", "%1,%2")
if (digit == 0) then
break
end
end
return Amount
end
local Towers = ReplicatedStorage:WaitForChild("Towers")
local Tower = Towers:FindFirstChild(t)
if Tower then
local button = gui.Towers.Template:Clone()
local config = Tower:WaitForChild("Config")
local ClonedTower = Tower:Clone()
button.Name = Tower.Name
button.TowerName.Text = Tower.Name
button.TowerName.TextColor3 = ClonedTower.Ring.Color
button.Visible = true
button.LayoutOrder = i
button.KeybindText.Text = i
button.Parent = gui.Towers
button.Cost.Text = "$" .. Comma(config.Price.Value)
ClonedTower.Parent = button.ViewportFrame.WorldModel
ClonedTower.PrimaryPart.CFrame = CFrame.new(0, 0, -3) * CFrame.Angles(0 , math.rad(-180), 0)
local Animations = ClonedTower:WaitForChild("Animations")
local Animator = ClonedTower:FindFirstChild("Humanoid"):FindFirstChildOfClass("Animator") or Instance.new("Animator", ClonedTower:FindFirstChild("Humanoid"))
local IdleAnimationTrack = Animator:LoadAnimation(Animations.Idle)
local WingAnimationTrack = Animator:LoadAnimation(Animations.WingAnim)
if IdleAnimationTrack then
IdleAnimationTrack:Play()
end
if WingAnimationTrack then
WingAnimationTrack:Play()
end
end
end
end
UpdateInventoryEvent.OnClientEvent:Connect(function()
updateLoadout()
end)
local playerData = getDataFunction:InvokeServer()
if playerData then
updateLoadout()
else
warn("No player data yet.")
repeat
task.wait()
local playerData = getDataFunction:InvokeServer()
until playerData
print("Successfully retrieved player data.")
updateLoadout()
end
--ButtonClient
local gui = script.Parent
local buttons = gui.Buttons
local InventoryFrame = gui.Inventory
local TopFrame = InventoryFrame.Top
local InventoryButton = buttons.Inventory
TopFrame.Exit.Activated:Connect(function()
InventoryFrame.Visible = false
end)
--InventoryClient
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local getDataFunction = ReplicatedStorage:WaitForChild("GetData")
local interactItemFunction = ReplicatedStorage:WaitForChild("InteractItem")
local gui = script.Parent
local InventoryFrame = gui.Inventory
local buttons = gui.Buttons
local stars = InventoryFrame.Stars
local Level = InventoryFrame.Level
local ExperienceBar = InventoryFrame.ExperienceBar
local ReqExp = ExperienceBar.RequiredExperience
local CurrExp = ExperienceBar.CurrentExperience
local InventoryButton = buttons.Inventory
local Player = game.Players.LocalPlayer
local playerData = getDataFunction:InvokeServer()
local function getItemStatus(itemName)
if table.find(playerData.SelectedTowers, itemName) then
return "Equipped"
elseif table.find(playerData.OwnedTowers, itemName) then
return "Owned"
else
return "Locked"
end
end
local function interactItem(itemName)
local data = interactItemFunction:InvokeServer(itemName)
if data then
playerData = data
updateInventory()
print(playerData.SelectedTowers)
end
end
function updateInventory()
if playerData ~= nil then
stars.Text = "★" .. playerData.Stars
Level.Text = playerData.Level
CurrExp.Text = playerData.Experience
ReqExp.Text = playerData.RequiredExperience
local percentage = playerData.Experience / playerData.RequiredExperience
ExperienceBar.Experience.Size = UDim2.new(percentage, 0, 1, 0)
for i, towerName in pairs(playerData.OwnedTowers) do
local tower = ReplicatedStorage.Towers:FindFirstChild(towerName)
if tower then
local status = getItemStatus(tower.Name)
local oldPlButton = InventoryFrame.Towers:FindFirstChild(tower.Name)
if oldPlButton then
oldPlButton:Destroy()
end
--[[local oldPldButton = InventoryFrame.Towers:GetChildren()
for x, o in pairs(oldPldButton) do
if not o:IsA("UICorner") or not o:IsA("UIAspectRatioConstraint") then
if o:IsA("TextButton") and o.Visible == true then
o:Destroy()
end
end
end]]
local button = InventoryFrame.Towers.Template:Clone()
local ClonedTower = tower:Clone()
ClonedTower.Parent = button.ViewportFrame.WorldModel
ClonedTower.PrimaryPart.CFrame = CFrame.new(0, 0, -3) * CFrame.Angles(0 , math.rad(-180), 0)
button.Visible = true
button.Name = tower.Name
button.TowerName.Text = tower.Name
button.LayoutOrder = i
button.Parent = InventoryFrame.Towers
if status == "Equipped" then
button.Status.Text = "Unequip"
button.BackgroundColor3 = Color3.new(0, 0.5, 0)
elseif status == "Owned" then
button.Status.Text = "Equip"
button.BackgroundColor3 = Color3.new(0, 0.6666667, 1)
end
local Animations = ClonedTower:WaitForChild("Animations")
local Animator = ClonedTower:FindFirstChild("Humanoid"):FindFirstChildOfClass("Animator") or Instance.new("Animator", ClonedTower:FindFirstChild("Humanoid"))
local IdleAnimationTrack = Animator:LoadAnimation(Animations.Idle)
local WingAnimationTrack = Animator:LoadAnimation(Animations.WingAnim)
if IdleAnimationTrack then
IdleAnimationTrack:Play()
end
if WingAnimationTrack then
WingAnimationTrack:Play()
end
button.Activated:Connect(function()
interactItem(towerName)
end)
end
end
else
repeat
task.wait(1)
playerData = getDataFunction:InvokeServer()
until playerData ~= nil
updateInventory()
end
end
updateInventory()
local function toggleShop()
InventoryFrame.Visible = not InventoryFrame.Visible
if InventoryFrame.Visible then
updateInventory()
end
end
InventoryButton.Activated:Connect(function()
toggleShop()
end)
--TowersModule
local PhysicsService = game:GetService("PhysicsService")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local events = ReplicatedStorage:WaitForChild("Events")
local towers = ReplicatedStorage:WaitForChild("Towers")
local animateTowerEvent = events:WaitForChild("AnimateTower")
local functions = ReplicatedStorage:WaitForChild("Functions")
local spawnTowerFunction = functions:WaitForChild("SpawnTower")
local requestTowerFunction = functions:WaitForChild("RequestTower")
local sellTowerFunction = functions:WaitForChild("SellTower")
local changeTowerModeFunction = functions:WaitForChild("ChangeTowerMode")
local maxTowers = 30
local tower = {}
function tower.FindTarget(newTower, range, mode)
local bestTarget = nil
local bestWaypoint = nil
local bestDistance = nil
local bestHealth = nil
local map = workspace.Maps:FindFirstChildOfClass("Folder")
for i, mob in ipairs(workspace.Mobs:GetChildren()) do
local distanceToMob = (mob.HumanoidRootPart.Position - newTower.HumanoidRootPart.Position).Magnitude
local distanceToWaypoint = (mob.HumanoidRootPart.Position - map.Waypoints[mob.MovingTo.Value].Position).Magnitude
if distanceToMob <= range then
if mode == "Near" then
range = distanceToMob
bestTarget = mob
elseif mode == "First" then
if not bestWaypoint or mob.MovingTo.Value >= bestWaypoint then
bestWaypoint = mob.MovingTo.Value
if not bestDistance or distanceToWaypoint < bestDistance then
bestDistance = distanceToWaypoint
bestTarget = mob
end
end
elseif mode == "Last" then
if not bestWaypoint or mob.MovingTo.Value <= bestWaypoint then
bestWaypoint = mob.MovingTo.Value
if not bestDistance or distanceToWaypoint > bestDistance then
bestDistance = distanceToWaypoint
bestTarget = mob
end
end
elseif mode == "Strong" then
if not bestHealth or mob.Humanoid.Health > bestHealth then
bestHealth = mob.Humanoid.Health
bestTarget = mob
end
elseif mode == "Weak" then
if not bestHealth or mob.Humanoid.Health < bestHealth then
bestHealth = mob.Humanoid.Health
bestTarget = mob
end
end
end
end
return bestTarget
end
function tower.Attack(newTower, player)
local towerConfig = newTower.Config
local target = tower.FindTarget(newTower, towerConfig.Range.Value, towerConfig.TargetMode.Value)
local Damage = towerConfig.Damage
local Cooldown = towerConfig.Cooldown
if target and target:FindFirstChild("Humanoid") and target.Humanoid.Health > 0 then
if target.Humanoid.Health < Damage.Value then
player.Stardust.Value += target.Humanoid.Health
else
if target:FindFirstChild("Armor") then
player.Stardust.Value = player.Stardust.Value + (Damage.Value - (Damage.Value * target:FindFirstChild("Armor").DamageReduction.Value))
else
player.Stardust.Value += Damage.Value
end
end
local targetCFrame = CFrame.lookAt(newTower.HumanoidRootPart.Position, target.HumanoidRootPart.Position)
newTower.HumanoidRootPart.BodyGyro.CFrame = targetCFrame
animateTowerEvent:FireAllClients(newTower, "Attack", target)
if target:FindFirstChild("Armor") then
target.Humanoid:TakeDamage(Damage.Value - (Damage.Value * target:FindFirstChild("Armor").DamageReduction.Value))
else
target.Humanoid:TakeDamage(Damage.Value)
end
if target.Humanoid.Health <= 0 then
player.Kills.Value += 1
end
task.wait(Cooldown.Value)
end
task.wait(1/60)
if newTower and newTower.Parent then
tower.Attack(newTower, player)
end
end
function tower.ChangeMode(player, model)
if model and model:FindFirstChild("Config") then
local targetMode = model.Config.TargetMode
local modes = {"First", "Last", "Near", "Strong", "Weak"}
local modeIndex = table.find(modes, targetMode.Value)
if modeIndex < #modes then
targetMode.Value = modes[modeIndex + 1]
else
targetMode.Value = modes[1]
end
return true
else
warn("Unable to change tower mode")
return false
end
end
changeTowerModeFunction.OnServerInvoke = tower.ChangeMode
function tower.Sell(player, model)
if model and model:FindFirstChild("Config") then
if model.Config.Owner.Value == player.Name then
player.PlacedTowers.Value -= 1
player.Stardust.Value += model.Config.Price.Value / 2
model:Destroy()
return true
end
end
warn("Unable to sell this tower")
return false
end
sellTowerFunction.OnServerInvoke = tower.Sell
function tower.Spawn(player, name, cframe, previous)
local allowedToSpawn = tower.CheckSpawn(player, name, previous)
if allowedToSpawn then
local newTower
local oldMode = nil
if previous then
oldMode = previous.Config.TargetMode.Value
previous:Destroy()
newTower = towers.Upgrades[name]:Clone()
towers.Upgrades[name]:FindFirstChild("Config"):FindFirstChild("InGame").Value = true
else
newTower = towers[name]:Clone()
player.PlacedTowers.Value += 1
towers[name]:FindFirstChild("Config"):FindFirstChild("InGame").Value = true
end
if not workspace.Towers[towers[name]] then
towers[name]:FindFirstChild("Config"):FindFirstChild("InGame").Value = false
elseif not workspace.Towers[towers.Upgrades[name]] then
towers.Upgrades[name]:FindFirstChild("Config"):FindFirstChild("InGame").Value = false
end
local ownerValue = Instance.new("StringValue", newTower.Config)
ownerValue.Name = "Owner"
ownerValue.Value = player.Name
local targetMode = Instance.new("StringValue", newTower.Config)
targetMode.Name = "TargetMode"
targetMode.Value = oldMode or "First"
newTower.HumanoidRootPart.CFrame = cframe
newTower.Parent = workspace.Towers
newTower.HumanoidRootPart:SetNetworkOwner(nil)
local bodyGyro = Instance.new("BodyGyro", newTower.HumanoidRootPart)
bodyGyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
bodyGyro.D = 0
bodyGyro.CFrame = newTower.HumanoidRootPart.CFrame
for i, object in ipairs(newTower:GetDescendants()) do
if object:IsA("BasePart") then
PhysicsService:SetPartCollisionGroup(object, "Towers")
end
end
local height = (newTower.PrimaryPart.Size.Y / 2) + newTower["Left Leg"].Size.Y
local offset = Vector3.new(0, -height, 0)
if newTower.Config:FindFirstChild("Boundary") then
local p = Instance.new("Part", newTower)
p.Name = "Boundary"
p.Shape = Enum.PartType.Cylinder
p.Transparency = 0.6
p.BrickColor = BrickColor.new("Persimmon")
p.Size = Vector3.new(0.5, newTower.Config.Boundary.Value, newTower.Config.Boundary.Value)
p.Material = Enum.Material.Neon
p.TopSurface = Enum.SurfaceType.Smooth
p.BottomSurface = Enum.SurfaceType.Smooth
p.Position = newTower.PrimaryPart.Position + offset
p.Orientation = Vector3.new(0, 90, 90)
p.CanCollide = false
p.CanQuery = true
p.Anchored = true
end
player.Stardust.Value -= newTower.Config.Price.Value
coroutine.wrap(tower.Attack)(newTower, player)
return newTower
else
warn("Requested tower does not exist:", name)
return false
end
end
spawnTowerFunction.OnServerInvoke = tower.Spawn
function tower.CheckSpawn(player, name, towerToSpawn, previous)
local towerExists = ReplicatedStorage.Towers:FindFirstChild(name, true)
if towerExists then
if towerExists.Config.Price.Value <= player.Stardust.Value then
if previous and towerToSpawn then
if player.PlacedTowers.Value < maxTowers then
return true
else
warn("Player has reached max limit")
end
else
warn("No tower selected")
end
else
warn("Player cannot afford")
end
else
warn("That tower doesn't exist")
end
return false
end
requestTowerFunction.OnServerInvoke = tower.CheckSpawn
return tower
--MobModule
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local RunService = game:GetService("RunService")
local PhysicsService = game:GetService("PhysicsService")
local TweenService = game:GetService("TweenService")
local functions = ReplicatedStorage:WaitForChild("Functions")
local modules = ReplicatedStorage:WaitForChild("Modules")
local getDataFunction = functions:WaitForChild("GetData")
local bindables = ServerStorage:WaitForChild("Bindables")
local updateBaseHealthEvent = bindables:WaitForChild("UpdateBaseHealth")
local Interpolation = require(modules.Interpolation)
local mob = {}
local playerData = {}
function mob.Optimize(mobToOptimize)
local humanoid = mobToOptimize:WaitForChild("Humanoid")
if mobToOptimize:FindFirstChild("HumanoidRootPart") then
mobToOptimize.HumanoidRootPart:SetNetworkOwner(nil)
elseif mobToOptimize.PrimaryPart ~= nil then
mobToOptimize.PrimaryPart:SetNetworkOwner(nil)
end
if not humanoid then
return
end
humanoid:SetStateEnabled(Enum.HumanoidStateType.Seated, false)
humanoid:SetStateEnabled(Enum.HumanoidStateType.Jumping, false)
humanoid:SetStateEnabled(Enum.HumanoidStateType.Running, false)
humanoid:SetStateEnabled(Enum.HumanoidStateType.GettingUp, false)
humanoid:SetStateEnabled(Enum.HumanoidStateType.Climbing, false)
humanoid:SetStateEnabled(Enum.HumanoidStateType.Landed, false)
humanoid:SetStateEnabled(Enum.HumanoidStateType.Ragdoll, false)
humanoid:SetStateEnabled(Enum.HumanoidStateType.Freefall, false)
end
function mob.LerpTo(newEnemy, target, Offset)
local alpha = 0
local startPos = newEnemy.PrimaryPart.Position
local loop = nil
local reachedTarget = Instance.new("BindableEvent")
local distance = (newEnemy.PrimaryPart.Position - target).Magnitude
loop = RunService.Heartbeat:Connect(function(delta)
if newEnemy and newEnemy:FindFirstChild("Humanoid") then
local speed = newEnemy.Humanoid.WalkSpeed
local relativeSpeed = distance / speed
local goalPos = startPos:Lerp(target, alpha)
TweenService:Create(newEnemy.PrimaryPart, TweenInfo.new(0.75, Enum.EasingStyle.Sine), {CFrame = CFrame.lookAt(newEnemy.PrimaryPart.Position, Vector3.new(target.X, target.Y, target.Z))}):Play()
newEnemy.PrimaryPart.Position = goalPos
alpha += delta / relativeSpeed
if alpha >= 1 then
loop:Disconnect()
reachedTarget:Fire()
end
else
loop:Disconnect()
end
end)
reachedTarget.Event:Wait()
end
function mob.Move(mobToMove, map, old)
local humanoid = mobToMove:WaitForChild("Humanoid")
local waypoints = map.Waypoints
local waypoint = 1
if old then
waypoint = old.MovingTo.Value
end
for wp = waypoint, #waypoints:GetChildren() do
if mobToMove.PrimaryPart == nil or mobToMove == nil then
return
end
local offset = Vector3.new(math.random(-100,100)/100, 0, math.random(-100,100)/100)
mobToMove.MovingTo.Value = wp
local mobPosVector = mobToMove.PrimaryPart.Position * Vector3.new(1, 0, 1)
local waypointPosVector = waypoints[wp].Position * Vector3.new(1, 0, 1)
local mobDistance = (mobPosVector - waypointPosVector).Magnitude
local waypointVector = Vector3.new(waypoints[wp].Position.X, waypoints[wp].Position.Y, waypoints[wp].Position.Z)
local reached = false
repeat task.wait(0.05)
if not humanoid or humanoid.Health <= 0 then
return
end
humanoid:MoveTo(waypointPosVector + offset)
mobPosVector = mobToMove.PrimaryPart.Position * Vector3.new(1, 0, 1)
waypointPosVector = waypoints[wp].CFrame.Position * Vector3.new(1, 0, 1)
mobDistance = (mobPosVector - waypointPosVector).Magnitude
if mobDistance <= 0.7 then
reached = true
end
until humanoid.MoveToFinished:Wait()
end
mobToMove:Destroy()
map.Base.Humanoid:TakeDamage(humanoid.Health)
end
--[[function mob.Move(newMob, map, Offset, RandomPos)
local Root = newMob.PrimaryPart
local Waypoints = map.Waypoints
local newPos
for waypoint = 1, #Waypoints:GetChildren() do
newMob.MovingTo.Value = waypoint
if waypoint == 1 then
else
if Waypoints[waypoint]:FindFirstChild("A") and Waypoints[waypoint]:FindFirstChild("B") then
for t = 0, 1, 0.1 do
local Waypoint1 = Waypoints[waypoint].Position
local Waypoint2 = Waypoints[waypoint].A.Position
local Waypoint3 = Waypoints[waypoint].B.Position
newPos = Interpolation.QuadBezier(Waypoint1, Waypoint2, Waypoint3, t)
mob.LerpTo(newMob, Vector3.new(newPos.X + RandomPos, newPos.Y + Offset, newPos.Z + RandomPos))
end
else
newPos = Waypoints[waypoint].Position
mob.LerpTo(newMob, Vector3.new(newPos.X + RandomPos, newPos.Y + Offset, newPos.Z + RandomPos))
end
end
end
newMob:Destroy()
end]]
function mob.Mystery(model, map)
local mysteryMobs = nil
if workspace.Info.Gamemode.Value == "Normal" then
mysteryMobs = {
["Mystery"] = "Zombie", "Speedy Zombie", "Slow Zombie"
}
end
if mysteryMobs then
if mysteryMobs[model.Name] then
local mysteryMob = mysteryMobs[mysteryMobs]
local rng = math.random(1, #mysteryMobs)
mob.Spawn(mysteryMobs[rng], 1, 0, map, model)
end
end
end
function mob.Spawn(name, quantity, waittime, map, old, status)
if not status then
status = "None"
end
local mobExists = ServerStorage.Mobs:FindFirstChild(name)
local statusExists = ServerStorage.Status:FindFirstChild(status)
if mobExists and statusExists then
for i = 1, quantity do
task.wait(waittime)
local newMob = mobExists:Clone()
local newStatusAilment = statusExists:Clone()
print(newStatusAilment.Name)
if old then
newMob.HumanoidRootPart.CFrame = old.HumanoidRootPart.CFrame
else
newMob.HumanoidRootPart.CFrame = map.Start.CFrame
end
newMob.Parent = workspace.Mobs
newMob.HumanoidRootPart:SetNetworkOwner(nil)
local movingTo = Instance.new("IntValue", newMob)
movingTo.Name = "MovingTo"
local RandomPosition = Random.new():NextNumber(-0.5, 0.5)
mob.Optimize(newMob)
--// STATUS AILMENTS \\--
if newStatusAilment.Name == "None" then
-- Do nothing
end
if newStatusAilment.Name == "Bloated" then
newMob.Humanoid.MaxHealth *= 2
newMob.Humanoid.Health *= 2
end
if newStatusAilment.Name == "Nimble" then
newMob.Humanoid.WalkSpeed *= 2
end
local hum = newMob.Humanoid
local animator = hum:FindFirstChild("Animator") or Instance.new("Animator", hum)
local Animations = newMob:WaitForChild("Animations")
local Died = Animations:WaitForChild("Died")
for i, object in ipairs(newMob:GetDescendants()) do
if object:IsA("BasePart") then
PhysicsService:SetPartCollisionGroup(object, "Mobs")
end
end
hum.BreakJointsOnDeath = false
hum.Died:Connect(function()
if newMob:FindFirstChild("Mystery") then
mob.Mystery(newMob, map)
end
if hum.Health <= 0 and newMob.Name ~= "Mystery" and newMob.Name ~= "Mystery Boss" then
hum.WalkSpeed = 0
local deathAnimation = animator:LoadAnimation(Died)
deathAnimation:Play()
wait(deathAnimation.Length)
newMob:Destroy()
end
newMob:Destroy()
end)
coroutine.wrap(mob.Move)(newMob, map, old)
end
else
warn("Requested mob does not exist:", name)
end
end
return mob
--RoundModule
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
local TweenService = game:GetService("TweenService")
local events = ReplicatedStorage:WaitForChild("Events")
local TextEvent = events:WaitForChild("TextEvent")
local mob = require(script.Parent.Mob)
local info = workspace.Info
local round = {}
local votes = {}
function round.StartGame()
if info.GameRunning.Value then return end
local waves = nil
local map = round.LoadMap()
local mode
if map then
mode = round.LoadMode()
end
if not mode then
mode = "Normal"
print(mode)
end
if not waves then
waves = 20
print(waves)
end
if mode == "Normal" then
waves = 20
elseif mode == "Anomalous" then
waves = 25
end
info.GameRunning.Value = true
for i = 3, 0, -1 do
info.Message.Value = "Game starting in..." .. i
task.wait(1)
end
for wave = 1, waves do
info.Wave.Value = wave
info.Message.Value = ""
local playersInGame = #game.Players:GetPlayers()
if mode == "Normal" then
round.GetNormal(wave, map)
elseif mode == "Anomalous" then
round.GetAnomalous(wave, map)
end
repeat
task.wait(1)
until #workspace.Mobs:GetChildren() == 0 or not info.GameRunning.Value
if info.GameRunning.Value and wave == waves then
info.Message.Value = "VICTORY"
elseif info.GameRunning.Value then
local reward
if mode == "Normal" then
reward = (45 - ((playersInGame - 1) * 5)) + wave * (135 - ((playersInGame - 1) * 15)) -- wave 1 = $180 if 1 player
elseif mode == "Anomalous" then
reward = 80 * math.round(wave / 2)
end
for i, player in ipairs(Players:GetPlayers()) do
player.Stardust.Value += reward
TextEvent:FireClient(player, "Money", "Wave Reward: $" .. math.round(reward))
end
task.wait(1)
for i=5, 0, -1 do
info.Message.Value = "Next wave starting in..." .. i
task.wait(1)
end
else
break
end
end
end
function round.LoadMap()
local votedMap = round.ToggleVoting()
local mapFolder = ServerStorage.Maps:FindFirstChild(votedMap)
if not mapFolder then
mapFolder = ServerStorage.Maps.Grassland
end
local newMap = mapFolder:Clone()
newMap.Parent = workspace.Maps
workspace.SpawnBox.Floor:Destroy()
newMap.Base.Humanoid.HealthChanged:Connect(function(health)
if health <= 0 then
info.GameRunning.Value = false
info.Message.Value = "GAME OVER"
end
end)
return newMap
end
function round.LoadMode()
local votedMode = round.ToggleModeVoting()
local modeValue = ServerStorage.Modes:FindFirstChild(votedMode)
if not modeValue then
modeValue = ServerStorage.Modes.Normal
end
info.Gamemode.Value = modeValue.Name
return modeValue.Name
end
function round.ToggleVoting()
local maps = ServerStorage.Maps:GetChildren()
votes = {}
for i, map in ipairs(maps) do
votes[map.Name] = {}
end
info.Voting.Value = true
for i=5, 1, -1 do
info.Message.Value = "Map voting (" .. i .. ")"
task.wait(1)
end
local winVote = nil
local winScore = 0
for name, map in pairs(votes) do
if #map > winScore then
winScore = #map
winVote = name
end
end
if not winVote then
local n = math.random(#maps)
winVote = maps[n].Name
end
info.Voting.Value = false
return winVote
end
function round.ToggleModeVoting()
local modes = ServerStorage.Modes:GetChildren()
votes = {}
for i, mode in ipairs(modes) do
votes[mode.Name] = {}
end
info.GamemodeVoting.Value = true
for i=5, 1, -1 do
info.Message.Value = "Mode voting (" .. i .. ")"
task.wait(1)
end
local winVote = nil
local winScore = 0
for name, mode in pairs(votes) do
if #mode > winScore then
winScore = #mode
winVote = name
end
end
if not winVote then
local n = math.random(#modes)
winVote = modes[n].Name
end
info.GamemodeVoting.Value = false
return winVote
end
function round.ProcessVote(player, vote)
for name, mapVotes in pairs(votes) do
local oldVote = table.find(mapVotes, player.UserId)
if oldVote then
table.remove(mapVotes, oldVote)
print("Old vote found", oldVote)
break
end
end
print("Processed vote for", vote)
table.insert(votes[vote], player.UserId)
events:WaitForChild("UpdateVoteCount"):FireAllClients(votes)
end
events:WaitForChild("VoteForMap").OnServerEvent:Connect(round.ProcessVote)
function round.GetNormal(wave, map)
if wave < 2 then
mob.Spawn("Mystery", 3 + wave, 0.5, map)
elseif wave == 2 then
mob.Spawn("Speedy Zombie", 2, 0.5, map)
mob.Spawn("Zombie", 3, 0.5, map)
elseif wave == 3 then
mob.Spawn("Zombie", 4, 0.5, map)
mob.Spawn("Speedy Zombie", 3, 0.5, map)
elseif wave == 4 then
mob.Spawn("Slow Zombie", 6, 0.5, map)
elseif wave == 5 then
mob.Spawn("Speedy Zombie", 3, 0.5, map)
mob.Spawn("Zombie", 7, 0.5, map)
mob.Spawn("Slow Zombie", 4, 0.5, map)
mob.Spawn("Speedy Zombie", 6, 0.5, map)
elseif wave < 7 and wave > 5 then
mob.Spawn("Zombie", 3 + wave, 0.5, map)
mob.Spawn("Speedy Zombie", wave, 0.5, map)
mob.Spawn("Slow Zombie", math.round(wave / 2), 0.5, map)
mob.Spawn("Zombie", math.round(wave / 1.5), 0.5, map)
elseif wave == 7 then
mob.Spawn("Zombie", 10, 0.5, map)
mob.Spawn("Speedy Zombie", 8, 0.2, map)
mob.Spawn("Slow Zombie", wave, 0.5, map)
mob.Spawn("Boss Zombie", 1, 0.5, map)
elseif wave == 8 then
mob.Spawn("Speedy Zombie", 8, 0.2, map)
mob.Spawn("Zombie", 10, 0.5, map)
mob.Spawn("Slow Zombie", 6, 1, map)
elseif wave == 9 then
mob.Spawn("Boss Zombie", 1, 1, map)
mob.Spawn("Zombie", 10, 0.5, map)
mob.Spawn("Speedy Zombie", 10, 0.1, map)
elseif wave == 10 then
mob.Spawn("Boss Zombie", 2, 1, map)
mob.Spawn("Zombie", 10, 0.5, map)
mob.Spawn("Slow Zombie", 4, 0.5, map)
elseif wave == 11 then
mob.Spawn("Mystery", 4, 0.4, map)
mob.Spawn("Speedy Zombie", 10, 0.1, map)
end
end
function round.GetAnomalous(wave, map)
if wave < 4 then
mob.Spawn("Zombie", 4 + wave, 0.5, map)
elseif wave < 5 and wave > 3 then
mob.Spawn("Zombie", 2 * wave, 0.5, map)
elseif wave == 5 then
mob.Spawn("Speedy Zombie", 6, 0.35, map)
elseif wave == 6 then
mob.Spawn("Zombie", 7, 0.5, map)
mob.Spawn("Speedy Zombie", 5, 0.5, map)
end
end
return round
--EnemyModule
return function(registry)
local enemyType = registry.Cmdr.Util.MakeEnumType("enemyName",
{
"Zombie";
"Speedy Zombie";
"Slow Zombie";
"Boss Zombie";
"Hidden";
"Mystery";
}
)
registry:RegisterType("enemy", enemyType)
end
--Datastore
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local ServerStorage = game:GetService("ServerStorage")
local bindables = ServerStorage:WaitForChild("Bindables")
local database = DataStoreService:GetDataStore("fanum")
local functions = ReplicatedStorage:WaitForChild("Functions")
local events = ReplicatedStorage:WaitForChild("Events")
local getDataFunc = functions:WaitForChild("GetData")
local exitEvent = events:WaitForChild("ExitGame")
local MAX_SELECTED_TOWERS = 5
local data = {}
-- Load the players data
local function LoadData(player)
local success = nil
local playerData = nil
local attempt = 1
repeat
success, playerData = pcall(function()
return database:GetAsync(player.UserId)
end)
attempt += 1
if not success then
warn(playerData)
task.wait()
end
until success or attempt == 5
if success then
print("Connection success")
if not playerData then
print("New player, giving default data")
playerData = {
["Stars"] = 0,
["Level"] = 1,
["Experience"] = 0,
["RequiredExperience"] = 10,
["SelectedTowers"] = {"Mayhem"},
["OwnedTowers"] = {"Mayhem", "Purity", "Sword Novice"},
["OwnedSkins"] = {},
["EquippedSkins"] = {},
["SkinsHave"] = {},
["KilledEnemies"] = {},
}
end
print(playerData.KilledEnemies)
if not playerData.KilledEnemies then
playerData.KilledEnemies = {}
end
print(playerData.KilledEnemies)
data[player.UserId] = playerData
else
warn("Unable to get data for player", player.UserId)
player:Kick("There was a problem getting your data")
end
end
Players.PlayerAdded:Connect(LoadData)
-- Save the players data
local function SaveData(player)
if data[player.UserId] then
local success = nil
local playerData = nil
local attempt = 1
local info = workspace.Info
local stars = math.round(info.Wave.Value * 10 / 2)
local experience = math.round(info.Wave.Value * 10 / 5)
if info.Gamemode.Value == "Normal" and info.Message.Value == "VICTORY" then
stars = 125
experience = 50
end
data[player.UserId].Stars += stars
data[player.UserId].Experience += experience
repeat
success, playerData = pcall(function()
return database:UpdateAsync(player.UserId, function()
return data[player.UserId]
end)
end)
attempt += 1
if not success then
warn(playerData)
task.wait()
end
until success or attempt == 5
if success then
print("Data saved successfully")
else
warn("Unable to save data for", player.UserId)
end
else
warn("No session data for", player.UserId)
end
end
exitEvent.OnServerEvent:Connect(function(player)
SaveData(player)
data[player.UserId] = nil
end)
game:BindToClose(function()
if not RunService:IsStudio() then
for index, player in pairs(Players:GetPlayers()) do
task.spawn(function()
SaveData(player)
end)
end
else
print("Shutting down inside studio")
end
end)
getDataFunc.OnServerInvoke = function(player)
return data[player.UserId]
end
--GameController(long)
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local Debris = game:GetService("Debris")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local PhysicsService = game:GetService("PhysicsService")
local localPlayer = Players.LocalPlayer
local Stardust = localPlayer:WaitForChild("Stardust")
local map = workspace.Maps:FindFirstChildOfClass("Folder")
local events = ReplicatedStorage:WaitForChild("Events")
local functions = ReplicatedStorage:WaitForChild("Functions")
local modules = ReplicatedStorage:WaitForChild("Modules")
local towers = ReplicatedStorage:WaitForChild("Towers")
local Misc = ReplicatedStorage:WaitForChild("Misc")
local Range = Misc:WaitForChild("Range")
local HighlightHover = Misc:WaitForChild("HighlightHover")
local health = require(modules:WaitForChild("Health"))
local TextEvent = events:WaitForChild("TextEvent")
local requestTowerFunction = functions:WaitForChild("RequestTower")
local spawnTowerFunction = functions:WaitForChild("SpawnTower")
local sellTowerFunction = functions:WaitForChild("SellTower")
local changeTowerModeFunction = functions:WaitForChild("ChangeTowerMode")
local getDataFunction = functions:WaitForChild("GetData")
local gui = script.Parent
local Sounds = gui.Sounds
local Selection = gui.Selection; Selection.Visible = false
local MobHoverGui = gui:WaitForChild("MobHoverGui")
local BossUI = gui:WaitForChild("BossUI")
local Action = Selection.Action
local LevelStat = Selection.LevelStat
local TotalStats = Selection.TotalStats
local NextLevelText = LevelStat.NextLevel
local NextLevelFrame = LevelStat.NextLevelFrame
local DamageFrame = NextLevelFrame.Damage
local RangeFrame = NextLevelFrame.Range
local CooldownFrame = NextLevelFrame.Cooldown
local TitleFrame = Selection.Title
local LevelText = TitleFrame.Level.LevelText
local StatWindow = Selection:WaitForChild("StatWindow")
local StatsFrame = StatWindow.Stats
local Upgrade = Action.Upgrade
local Sell = Action.Sell
local Target = Action.Target
local wrldModel = Selection.Title.ViewportFrame.WorldModel
local HealthFrame = MobHoverGui:WaitForChild("HealthFrame")
local StatusAilments = HealthFrame:WaitForChild("StatusAilments")
local mobCurrentHealth = HealthFrame:WaitForChild("CurrentHealth")
local info = workspace:WaitForChild("Info")
local camera = workspace.CurrentCamera
local hoveredInstance = nil
local selectedTower = nil
local towerToSpawn = nil
local previousHighlight = nil
local canPlace = false
local hoverHandled = false
local rotation = 0
local placedTowers = 0
local maxTowers = 30
local lastTouch = tick()
local mobsAlive
local towersAlive
local unitsAlive
local function Comma(Amount)
while true do
local digit
Amount, digit = string.gsub(Amount, "(-?%d+)(%d%d%d)", "%1,%2")
if (digit == 0) then
break
end
end
return Amount
end
local function EnemyIndexFunction(mode)
local enemies = {}
if mode == "Normal" then
enemies = {"Zombie", "Speedy Zombie", "Slow Zombie", "Boss Zombie", "Hidden", "Mystery", "Normal Orb"}
end
end
local function MouseRaycast(blacklist)
local mousePosition = UserInputService:GetMouseLocation()
local mouseRay = camera:ViewportPointToRay(mousePosition.X, mousePosition.Y)
local raycastParams = RaycastParams.new()
if blacklist then
raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
raycastParams.FilterDescendantsInstances = blacklist
end
local raycastResult = workspace:Raycast(mouseRay.Origin, mouseRay.Direction * 1000, raycastParams)
return raycastResult, mousePosition
end
local function Texts(typ, text)
if typ == "Money" then
Sounds.MoneyAlert:Play()
local Template = gui.MoneyAlert.Template:Clone()
Template.Parent = gui.MoneyAlert.MoneyAlerts
Template.Text = text
Template.Font = Enum.Font.JosefinSans
Template.Visible = true
local tweenInfo1 = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)
local property1 = {
Size = UDim2.new(1, 0, 1, 0)
}
local Tween1 = TweenService:Create(Template, tweenInfo1, property1)
Tween1:Play()
task.wait(1)
local tweenInfo2 = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)
local property2 = {
Size = UDim2.new(1, 0, 0, 0)
}
local Tween2 = TweenService:Create(Template, tweenInfo2, property2)
Tween2:Play()
Tween2.Completed:Wait()
Template:Destroy()
elseif typ == "Error" then
Sounds.Error:Play()
local Template = gui.Error.Template:Clone()
Template.Parent = gui.Error.Errors
Template.Text = text
Template.Font = Enum.Font.JosefinSans
Template.Visible = true
local tweenInfo1 = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)
local property1 = {
Size = UDim2.new(1, 0, 1, 0)
}
local Tween1 = TweenService:Create(Template, tweenInfo1, property1)
Tween1:Play()
task.wait(1)
local tweenInfo2 = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.InOut)
local property2 = {
Size = UDim2.new(1, 0, 0, 0)
}
local Tween2 = TweenService:Create(Template, tweenInfo2, property2)
Tween2:Play()
Tween2.Completed:Wait()
Template:Destroy()
end
end
local function CreateRangeCircle(tower, placeholder)
local range = tower.Config.Range.Value
local height = (tower.PrimaryPart.Size.Y) + tower.Humanoid.HipHeight
local offset = CFrame.new(0, -height, 0)
local p = Instance.new("Part")
p.Name = "Range"
p.Shape = Enum.PartType.Cylinder
p.Material = Enum.Material.Neon
p.Transparency = 0.9
p.Size = Vector3.new(0.25, range * 2, range * 2)
p.TopSurface = Enum.SurfaceType.Smooth
p.BottomSurface = Enum.SurfaceType.Smooth
p.CFrame = tower.PrimaryPart.CFrame * offset * CFrame.Angles(0, 0, math.rad(90))
p.CanCollide = false
if placeholder then
p.Anchored = false
local weldConstraint = Instance.new("WeldConstraint", p)
weldConstraint.Part0 = p
weldConstraint.Part1 = tower.PrimaryPart
p.Parent = tower
else
p.Anchored = true
p.Parent = workspace.CurrentCamera
p:Destroy()
end
end
local function HoverOverMob(result, mousePosition)
local mobHumanoid = result.Instance.Parent:FindFirstChild("Humanoid") or result.Instance.Parent.Parent:FindFirstChild("Humanoid")
if mobHumanoid then
local mobChar = mobHumanoid.Parent
local currentColor = mobCurrentHealth.Color
local percent = mobHumanoid.Health / mobHumanoid.MaxHealth
mobCurrentHealth.Size = UDim2.new(percent, 0, 1, 0)
HealthFrame.Health.Text = math.round(mobHumanoid.Health) .. "/" .. math.round(mobHumanoid.MaxHealth)
MobHoverGui.Title.Text = mobChar.Name
MobHoverGui.Position = UDim2.new(0, mousePosition.X, 0, mousePosition.Y)
MobHoverGui.Visible = true
--// STATUS AILMENTS \\--
if mobChar:FindFirstChild("Nimble") then
StatusAilments.Nimble.Visible = true
else
StatusAilments.Nimble.Visible = false
end
if mobChar:FindFirstChild("Bloated") then
StatusAilments.Bloated.Visible = true
else
StatusAilments.Bloated.Visible = false
end
if mobChar:FindFirstChild("Armor") then
StatusAilments.Armor.Visible = true
StatusAilments.Armor.Title.Text = mobChar:FindFirstChild("Armor").DamageReduction.Value * 100 .. "%"
else
StatusAilments.Armor.Visible = false
end
if mobChar:FindFirstChild("Boss") then
StatusAilments.Boss.Visible = true
mobCurrentHealth.Color = Color3.fromRGB(228, 173, 200)
else
StatusAilments.Boss.Visible = false
mobCurrentHealth.Color = currentColor
end
end
end
local function BossGui(mob)
if mob:FindFirstChild("Boss") then
local hum = mob:FindFirstChild("Humanoid")
local percent = hum.Health / hum.MaxHealth
local healthFrame = BossUI.Health
healthFrame.Size = UDim2.new(percent, 0, 1, 0)
healthFrame.Title.Text = mob.Name
healthFrame.Health.Text = Comma(hum.Health) .. "/" .. Comma(hum.MaxHealth)
BossUI.Visible = true
end
end
local function RemovePlaceholderTower()
if towerToSpawn then
towerToSpawn:Destroy()
towerToSpawn = nil
rotation = 0
if map then
for i, BoundaryTower in pairs(workspace.Towers:GetChildren()) do
for i, Part in pairs(BoundaryTower:GetChildren()) do
if Part.Name == "Boundary" then
Part.Transparency = 1
end
end
end
end
end
gui.Controls.Visible = false
end
local function AddPlaceholderTower(name)
local towerExists = towers:FindFirstChild(name)
if towerExists then
RemovePlaceholderTower()
towerToSpawn = towerExists:Clone()
towerToSpawn.Parent = workspace.Towers
if map then
for i, BoundaryTower in pairs(workspace.Towers:GetChildren()) do
for i, Part in pairs(BoundaryTower:GetChildren()) do
if Part.Name == "Boundary" then
Part.Transparency = 0.8
end
end
end
end
CreateRangeCircle(towerToSpawn, true)
for i, object in ipairs(towerToSpawn:GetDescendants()) do
if object:IsA("BasePart") then
PhysicsService:SetPartCollisionGroup(object, "Towers")
if object.Name ~= "Range" then
object.Material = Enum.Material.ForceField
object.Transparency = 0.3
elseif object:IsA("ParticleEmitter") or object:IsA("Trail") then
object.Enabled = false
end
end
end
gui.Controls.Visible = true
end
end
local function ColorPlaceholderTower(color)
for i, object in ipairs(towerToSpawn:GetDescendants()) do
if object:IsA("BasePart") then
object.Color = color
end
end
end
local function toggleTowerInfo()
camera:ClearAllChildren()
gui.Towers.Limit.Text = "Towers: " .. placedTowers .. "/" .. maxTowers
if selectedTower then
CreateRangeCircle(selectedTower)
local ClonedSelectionTower = selectedTower:Clone()
Selection.Visible = true
local configuration = selectedTower.Config
Range.Position = selectedTower.HumanoidRootPart.Position + Vector3.new(0, -0.8, 0)
Range.Parent = workspace.Range
local range = configuration.Range.Value
local tweenInfo = TweenInfo.new(0.3, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out)
local TweenTransparency = {Transparency = 0}
local tT2 = {Transparency = 0.7}
local TweenSize = {Size = Vector3.new(0.25, range * 2, range * 2)}
local TweenSi = TweenService:Create(Range, tweenInfo, TweenSize)
local TweenTr1 = TweenService:Create(Range.C, tweenInfo, tT2)
local TweenTr2 = TweenService:Create(Range.D, tweenInfo, TweenTransparency)
TweenSi:Play()
TweenTr1:Play()
TweenTr2:Play()
Selection.Stats.Damage.Value.Text = configuration.Damage.Value
Selection.Stats.Range.Value.Text = configuration.Range.Value
Selection.Stats.Cooldown.Value.Text = configuration.Cooldown.Value
Selection.Title.TowerName.Text = selectedTower.Name
Selection.Title.OwnerName.Text = configuration.Owner.Value .. "'s"
Target.Title.Text = "Target: " .. configuration.TargetMode.Value
StatsFrame.Cooldown.Title.Text = configuration.Cooldown.Value
StatsFrame.Damage.Title.Text = configuration.Damage.Value
StatsFrame.Range.Title.Text = configuration.Range.Value
LevelText.Text = configuration.Level.Value
if ClonedSelectionTower then
local SampleScript = script.SampleScript:Clone()
SampleScript.Parent = ClonedSelectionTower
while #wrldModel:GetChildren() >= 1 do
for i, v in pairs(wrldModel:GetChildren()) do
if v:IsA("Model") then
v:Destroy()
end
end
end
ClonedSelectionTower.Parent = wrldModel
ClonedSelectionTower:SetPrimaryPartCFrame(CFrame.new(0.5, 0.125, 0) * CFrame.Angles(0, math.rad(-180), 0))
ClonedSelectionTower:ScaleTo(0.25)
end
if not selectedTower then
ClonedSelectionTower:Destroy()
end
if configuration.Owner.Value == localPlayer.Name then
Action.Visible = true
local upgradeTower = configuration:FindFirstChild("Upgrade")
if upgradeTower then
NextLevelFrame.Visible = true
NextLevelText.Visible = true
local upgradedTower = upgradeTower.Value
local upgradedTowerConfiguration = upgradedTower.Config
Upgrade.Visible = true
Upgrade.Title.Text = "Upgrade: $" .. Comma(upgradedTowerConfiguration.Price.Value)
if configuration.Level.Value == upgradedTowerConfiguration.Level.Value then
NextLevelText.Visible = false
else
NextLevelText.Visible = true
NextLevelText.Text = "Lvl. " .. upgradedTowerConfiguration.Level.Value
end
if configuration.Damage.Value == upgradedTowerConfiguration.Damage.Value then
DamageFrame.Visible = false
else
DamageFrame.Visible = true
DamageFrame.Title.Text = configuration.Damage.Value .. " -> " .. upgradedTowerConfiguration.Damage.Value
end
if configuration.Cooldown.Value == upgradedTowerConfiguration.Cooldown.Value then
CooldownFrame.Visible = false
else
CooldownFrame.Visible = true
CooldownFrame.Title.Text = configuration.Cooldown.Value .. " -> " .. upgradedTowerConfiguration.Cooldown.Value
end
if configuration.Range.Value == upgradedTowerConfiguration.Range.Value then
RangeFrame.Visible = false
else
RangeFrame.Visible = true
RangeFrame.Title.Text = configuration.Range.Value .. " -> " .. upgradedTowerConfiguration.Range.Value
end
else
NextLevelFrame.Visible = false
NextLevelText.Visible = false
Upgrade.Title.Text = "MAXED"
end
else
Action.Visible = false
end
else
Selection.Visible = false
local tweenInfo = TweenInfo.new(0.3, Enum.EasingStyle.Exponential, Enum.EasingDirection.In)
local TweenTransparency = {Transparency = 1}
local TweenSize = {Size = Vector3.new(0, 0, 0)}
local TweenSi = TweenService:Create(Range, tweenInfo, TweenSize)
local TweenTr1 = TweenService:Create(Range.C, tweenInfo, TweenTransparency)
local TweenTr2 = TweenService:Create(Range.D, tweenInfo, TweenTransparency)
TweenSi:Play()
TweenTr1:Play()
TweenTr2:Play()
if selectedTower then
for i, v in pairs(wrldModel:GetChildren()) do
if v:IsA("Model") then
v:Destroy()
end
end
end
end
end
local function ShakeCamera(length, intensity)
local startTime = tick()
while true do
if tick() - startTime >= length then
break
end
local x = math.random(-intensity, intensity) / 10
local y = math.random(-intensity, intensity) / 10
local z = math.random(-intensity, intensity) / 10
for i, player in ipairs(Players:GetPlayers()) do
player.Character.Humanoid.CameraOffset = Vector3.new(x, y, z)
end
workspace.CurrentCamera.CFrame = CFrame.Angles(x / 100, y / 100, z / 100)
wait()
end
script.Parent.Humanoid.CameraOffset = Vector3.new(0, 0, 0)
end
local function SpawnNewTower()
if canPlace then
local placedTower = spawnTowerFunction:InvokeServer(towerToSpawn.Name, towerToSpawn.PrimaryPart.CFrame)
if placedTower then
placedTowers += 1
RemovePlaceholderTower()
toggleTowerInfo()
Sounds.Place:Play()
end
else
end
end
local function UpgradeTower()
if selectedTower then
local upgrade = selectedTower.Config:FindFirstChild("Upgrade")
if upgrade then
local upgradeTower = upgrade.Value
if upgradeTower then
local upgradeSuccess = spawnTowerFunction:InvokeServer(upgradeTower.Name, selectedTower.PrimaryPart.CFrame, selectedTower)
if upgradeSuccess then
selectedTower = upgradeSuccess
toggleTowerInfo()
Sounds.Upgrade:Play()
else
--Error("You can't upgrade this!", Enum.Font.Jura)
end
end
else
end
--[[else
Error("This tower cannot be upgraded anymore!", Enum.Font.Jura)]]
end
end
local function SetTarget()
if selectedTower then
local modeChangeSuccess = changeTowerModeFunction:InvokeServer(selectedTower)
if modeChangeSuccess then
toggleTowerInfo()
end
end
end
local function SellTower()
if selectedTower then
local soldTower = sellTowerFunction:InvokeServer(selectedTower)
if soldTower then
selectedTower = nil
placedTowers -= 1
toggleTowerInfo()
end
end
end
local function KeybindTower(number)
local playerData = getDataFunction:InvokeServer()
for i, v in ipairs(playerData.SelectedTowers) do
if i == number and workspace.Maps:FindFirstChildOfClass("Folder") then
local tower = towers:FindFirstChild(v)
if tower then
local allowedToSpawn = requestTowerFunction:InvokeServer(tower.Name, towerToSpawn)
if allowedToSpawn then
AddPlaceholderTower(tower.Name)
end
end
end
end
end
gui.Controls.Cancel.Activated:Connect(RemovePlaceholderTower)
Target.Activated:Connect(function()
SetTarget()
end)
Upgrade.Activated:Connect(function()
UpgradeTower()
end)
Sell.Activated:Connect(function()
SellTower()
end)
UserInputService.InputBegan:Connect(function(input, processed)
if processed then
return
end
if towerToSpawn then
if input.UserInputType == Enum.UserInputType.MouseButton1 then
SpawnNewTower()
elseif input.UserInputType == Enum.UserInputType.Touch then
local timeSinceLastTouch = tick() - lastTouch
if timeSinceLastTouch <= 0.25 then
SpawnNewTower()
end
lastTouch = tick()
elseif input.KeyCode == Enum.KeyCode.R then
rotation += 90
elseif input.KeyCode == Enum.KeyCode.Q then
RemovePlaceholderTower()
end
elseif hoveredInstance and (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then
local model = hoveredInstance:FindFirstAncestorOfClass("Model")
if model and model.Parent == workspace.Towers then
selectedTower = model
else
selectedTower = nil
end
toggleTowerInfo()
elseif input.KeyCode == Enum.KeyCode.One then
KeybindTower(1)
elseif input.KeyCode == Enum.KeyCode.Two then
KeybindTower(2)
elseif input.KeyCode == Enum.KeyCode.Three then
KeybindTower(3)
elseif input.KeyCode == Enum.KeyCode.Four then
KeybindTower(4)
elseif input.KeyCode == Enum.KeyCode.Five then
KeybindTower(5)
elseif input.KeyCode == Enum.KeyCode.E then
UpgradeTower()
elseif input.KeyCode == Enum.KeyCode.X then
SellTower()
end
end)
RunService.RenderStepped:Connect(function()
if towerToSpawn then
local result = MouseRaycast({towerToSpawn})
if result and result.Instance then
if result.Instance.Parent.Name == "GroundPlacement" and towerToSpawn.Config:FindFirstChild("GroundTower") and not towerToSpawn.Config:FindFirstChild("CliffTower") then
canPlace = true
ColorPlaceholderTower(Color3.new(0, 0.666667, 1))
elseif result.Instance.Parent.Parent.Name == "CliffPlacement" and not towerToSpawn.Config:FindFirstChild("GroundTower") and towerToSpawn.Config:FindFirstChild("CliffTower") then
canPlace = true
ColorPlaceholderTower(Color3.new(0, 0.2, 1))
else
canPlace = false
ColorPlaceholderTower(Color3.new(.8, 0, 0))
end
local x = result.Position.X
local y = result.Position.Y + towerToSpawn.Humanoid.HipHeight + (towerToSpawn.PrimaryPart.Size.Y * 1.25)
local z = result.Position.Z
local cframe = CFrame.new(x, y, z) * CFrame.Angles(0, math.rad(rotation), 0)
towerToSpawn:SetPrimaryPartCFrame(cframe)
end
else
local result, mousePos = MouseRaycast()
if result and result.Instance and mousePos then
hoveredInstance = result.Instance
if result.Instance.Parent.Parent and result.Instance.Parent.Parent.Name == "Mobs" then
HoverOverMob(result, mousePos)
BossGui(result.Instance.Parent)
elseif result.Instance.Parent.Parent.Parent and result.Instance.Parent.Parent.Parent.Name == "Mobs" then
HoverOverMob(result, mousePos)
BossGui(result.Instance.Parent)
else
MobHoverGui.Visible = false
end
else
MobHoverGui.Visible = false
end
end
end)
local function DisplayEndScreen(status)
local screen = gui.EndScreen
if status == "GAME OVER" then
screen.Failure:Play()
screen.Content.Title.TextColor3 = Color3.new(1, 0, 0)
screen.ImageColor3 = Color3.new(0, 0, 0)
screen.Content.Subtitle.Text = "Better luck next time"
elseif status == "VICTORY" then
screen.Victory:Play()
screen.Content.Title.TextColor3 = Color3.new(0, 1, 0)
screen.ImageColor3 = Color3.new(0.6, 1, 0.4)
screen.Content.Subtitle.Text = "Victory!!!! YAyAAYyayAYY!"
end
local info = workspace.Info
local stars = math.round(info.Wave.Value * 10 / 2)
local experience = math.round(info.Wave.Value * 10 / 5)
if info.Wave.Value >= 20 and info.Gamemode.Value == "Normal" and status == "VICTORY" then
stars = 125
experience = 50
end
screen.Content.Title.Text = status
screen.Stats.Wave.Text = "Wave: " .. workspace.Info.Wave.Value
screen.Stats.Stars.Text = "Stars: " .. stars
screen.Stats.Kills.Text = "Kills: " .. Players.LocalPlayer.Kills.Value
screen.Size = UDim2.new(0,0,0,0)
screen.Visible = true
local tweenStyle = TweenInfo.new(0.5, Enum.EasingStyle.Back, Enum.EasingDirection.Out, 0, false, 0)
local zoomTween = TweenService:Create(screen, tweenStyle, {Size = UDim2.new(1,0,1,0)})
zoomTween:Play()
local events = ReplicatedStorage:WaitForChild("Events")
local exitEvent = events:WaitForChild("ExitGame")
local clicked
clicked = screen.Exit.Activated:Connect(function()
clicked:Disconnect()
exitEvent:FireServer()
screen.Visible = false
end)
end
local function SetupGameGui()
if not info.GameRunning.Value then
return
end
TextEvent.OnClientEvent:Connect(Texts)
gui.Voting.Visible = false
gui.ModeVoting.Visible = false
gui.Info.Health.Visible = true
gui.Info.Stats.Visible = true
gui.Towers.Visible = true
local map = workspace.Maps:FindFirstChildOfClass("Folder")
if map then
health.Setup(map:WaitForChild("Base"), gui.Info.Health)
else
workspace.Maps.ChildAdded:Connect(function(newMap)
health.Setup(newMap:WaitForChild("Base"), gui.Info.Health)
end)
end
workspace.Units.ChildAdded:Connect(function(unit)
health.Setup(unit)
end)
info.Message.Changed:Connect(function(change)
gui.Info.Message.Text = change
if change == "" then
gui.Info.Message.Visible = false
else
gui.Info.Message.Visible = true
end
end)
info.Wave.Changed:Connect(function(change)
gui.Info.Stats.Wave.Text = "Wave: " .. change
end)
Stardust.Changed:Connect(function(change)
gui.Info.Stats.Stardust.Text = Stardust.Value
end)
gui.Info.Stats.Stardust.Text = Stardust.Value
gui.Towers.Limit.Text = "Towers: " .. placedTowers .. "/" .. maxTowers
local playerData = getDataFunction:InvokeServer()
for i, tower in pairs(playerData.SelectedTowers) do
print(playerData)
local tower = towers:FindFirstChild(tower)
if tower then
local button = gui.Towers.TowersFrame.Template:Clone()
local config = tower:WaitForChild("Config")
button.Name = tower.Name
button.TowerName.Text = tower.Name
button.TowerName.TextColor3 = tower.Ring.Color
button.Visible = true
button.Parent = gui.Towers.TowersFrame
button.LayoutOrder = i
button.KeybindText.Text = i
button.Cost.Text = "$" .. Comma(math.round(config.Price.Value))
local clonedTower = tower:Clone()
local SampleScript = script.SampleScript:Clone()
SampleScript.Parent = clonedTower
clonedTower.Parent = button.ViewportFrame.WorldModel
clonedTower:SetPrimaryPartCFrame(CFrame.new(0, 0, -3) * CFrame.Angles(0 , math.rad(-180), 0))
button.Activated:Connect(function()
local allowedToSpawn = requestTowerFunction:InvokeServer(tower.Name, towerToSpawn)
if allowedToSpawn then
AddPlaceholderTower(tower.Name)
else
end
end)
end
end
end
local function SetupVoteMapGui()
if not info.Voting.Value then
return
end
gui.Voting.Visible = true
local events = ReplicatedStorage:WaitForChild("Events")
local voteEvent = events:WaitForChild("VoteForMap")
local voteCountUpdate = events:WaitForChild("UpdateVoteCount")
local maps = gui.Voting.Maps:GetChildren()
for i, button in ipairs(maps) do
if button:IsA("ImageButton") then
button.Activated:Connect(function()
voteEvent:FireServer(button.Name)
end)
end
end
voteCountUpdate.OnClientEvent:Connect(function(mapScores)
for name, voteInfo in pairs(mapScores) do
local button = gui.Voting.Maps:FindFirstChild(name)
if button then
button.Vote.Text = #voteInfo
end
end
end)
end
local function SetupVoteModeGui()
if not info.GamemodeVoting.Value then
return
end
gui.Voting.Visible = false
gui.ModeVoting.Visible = true
local events = ReplicatedStorage:WaitForChild("Events")
local voteEvent = events:WaitForChild("VoteForMap")
local voteCountUpdate = events:WaitForChild("UpdateVoteCount")
local maps = gui.ModeVoting.Modes:GetChildren()
for i, button in ipairs(maps) do
if button:IsA("ImageButton") then
button.Activated:Connect(function()
voteEvent:FireServer(button.Name)
end)
end
end
voteCountUpdate.OnClientEvent:Connect(function(mapScores)
for name, voteInfo in pairs(mapScores) do
local button = gui.ModeVoting.Modes:FindFirstChild(name)
if button then
button.Vote.Text = #voteInfo
end
end
end)
end
local function ChangeStardustValue()
gui.Info.Stats.Stardust.Text = Comma(math.round(localPlayer.Stardust.Value))
end
local function LoadGui()
gui.Info.Message.Text = info.Message.Value
info.Message.Changed:Connect(function(change)
gui.Info.Message.Text = change
if change == "" then
gui.Info.Message.Visible = false
else
gui.Info.Message.Visible = true
if change == "VICTORY" or change == "GAME OVER" then
DisplayEndScreen(change)
end
end
end)
SetupVoteMapGui()
SetupGameGui()
ChangeStardustValue()
info.GameRunning.Changed:Connect(SetupGameGui)
info.Voting.Changed:Connect(SetupVoteMapGui)
info.GamemodeVoting.Changed:Connect(SetupVoteModeGui)
localPlayer.Stardust.Changed:Connect(ChangeStardustValue)
end
LoadGui()
--AnimationClient
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")
local TweenService = game:GetService("TweenService")
local events = ReplicatedStorage:WaitForChild("Events")
local animateTowerEvent = events:WaitForChild("AnimateTower")
local function fireProjectile(tower, target)
local config = tower:WaitForChild("Config")
local projectile = config:FindFirstChild("Projectile")
if projectile then
local newProjectile = projectile:Clone()
local distance = (tower.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
newProjectile.CFrame = tower["Right Arm"].CFrame
newProjectile.Anchored = true
newProjectile.Parent = workspace.CurrentCamera
newProjectile.Transparency = 0
local WantedSize = projectile:GetAttribute("WantedSize")
local ReturningSize = projectile:GetAttribute("ReturningSize")
local Color = newProjectile:GetAttribute("Color")
local TweenInformation = TweenInfo.new(0.25, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out)
local Properties = {
Position = target.HumanoidRootPart.Position,
Size = WantedSize
}
newProjectile.Color = Color
local Tween = TweenService:Create(newProjectile, TweenInformation, Properties)
Tween:Play()
Debris:AddItem(newProjectile, 0.5)
Tween.Completed:Connect(function()
local Tween2 = TweenService:Create(newProjectile, TweenInformation, {Size = ReturningSize})
Tween2:Play()
end)
end
end
local function setAnimation(object, animName)
local humanoid = object:WaitForChild("Humanoid")
local animationsFolder = object:WaitForChild("Animations")
if humanoid and animationsFolder then
local animationObject = animationsFolder:WaitForChild(animName)
if animationObject then
local animator = humanoid:FindFirstChild("Animator") or Instance.new("Animator", humanoid)
local playingTracks = animator:GetPlayingAnimationTracks()
for i, track in pairs(playingTracks) do
if track.Name == animName then
return track
end
end
local animationTrack = animator:LoadAnimation(animationObject)
return animationTrack
end
end
end
local function playAnimation(object, animName)
local animationTrack = setAnimation(object, animName)
if animationTrack then
animationTrack:Play()
else
warn("Animation track does not exist")
return
end
end
workspace.Mobs.ChildAdded:Connect(function(object)
playAnimation(object, "Walk")
end)
workspace.Towers.ChildAdded:Connect(function(object)
playAnimation(object, "Idle")
if object.Animations:FindFirstChild("WingAnim") then
playAnimation(object, "WingAnim")
end
end)
workspace.Units.ChildAdded:Connect(function(object)
playAnimation(object, "Walk")
end)
animateTowerEvent.OnClientEvent:Connect(function(tower, animName, target)
playAnimation(tower, animName)
if target then
fireProjectile(tower, target)
end
if tower.HumanoidRootPart:FindFirstChild("Attack") then
tower.HumanoidRootPart.Attack:Play()
end
end)
To embed this project on your website, copy the following code and paste it into your website's HTML: