local RunService = game:GetService("RunService") local UserInputService = game:GetService("UserInputService") local Tower = require(script.Parent.Tower) local Waves = require(script.Parent.Waves) local towerTypes = { { name = "Basic", model = workspace.BasicTowerModel, range = 20, damage = 10, fireRate = 1, }, { name = "Slow", model = workspace.SlowTowerModel, range = 15, damage = 5, fireRate = 0.5, effect = {name = "slow", params = {duration = 2, value = 0.5}} }, { name = "Fire", model = workspace.FireTowerModel, range = 18, damage = 8, fireRate = 1, effect = {name = "burn", params = {duration = 3, tick = 1, value = 2}} }, { name = "Freeze", model = workspace.FreezeTowerModel, range = 12, damage = 0, fireRate = 0.5, effect = {name = "freeze", params = {duration = 1}} } } local waypoints = { -- Fill with your waypoint Parts workspace.Waypoint1, workspace.Waypoint2, workspace.Waypoint3, -- etc. } local selectedTowerType = towerTypes[1] local enemies = {} -- Table to hold TrackEnemy objects local towers = {} local placingTower = false local rangeIndicator = nil function selectTowerType(index) selectedTowerType = towerTypes[index] end local function spawnWave(waveData) coroutine.wrap(function() for _, group in ipairs(waveData) do for i = 1, group.count do local enemyModel = group.model:Clone() enemyModel.Parent = workspace local enemy = TrackEnemy:new(enemyModel, group.name, group.health, group.speed) table.insert(enemies, enemy) end if group.delay and group.delay > 0 then wait(group.delay) end end end)() end spawnWave(Waves[1]) local function isOnTrack(position) for _, waypoint in ipairs(waypoints) do if (waypoint.Position - position).Magnitude < 5 then -- 5 studs return true end end return false end local function showRangeIndicator(position, range) if not rangeIndicator then rangeIndicator = Instance.new("Part") rangeIndicator.Name = "RangeIndicator" rangeIndicator.Shape = Enum.PartType.Cylinder rangeIndicator.Anchored = true rangeIndicator.CanCollide = false rangeIndicator.Transparency = 0.6 rangeIndicator.Color = Color3.fromRGB(100, 200, 255) rangeIndicator.Material = Enum.Material.Neon rangeIndicator.Size = Vector3.new(range * 2, 0.2, range * 2) rangeIndicator.Parent = workspace -- Rotate so cylinder is flat rangeIndicator.Orientation = Vector3.new(0, 0, 90) end rangeIndicator.Size = Vector3.new(range * 2, 0.2, range * 2) rangeIndicator.Position = Vector3.new(position.X, position.Y + 0.1, position.Z) rangeIndicator.Visible = true end local function hideRangeIndicator() if rangeIndicator then rangeIndicator:Destroy() rangeIndicator = nil end end RunService.RenderStepped:Connect(function () if placingTower then local mouse = game.Players.LocalPlayer:GetMouse() local position = mouse.Hit.p showRangeIndicator(position, selectedTowerType.range) else hideRangeIndicator() end end) UserInputService.InputBegan:Connect(function(input, gameProcessed) if gameProcessed then return end if input.KeyCode == Enum.KeyCode.T then placingTower = not placingTower print("Tower Placing Mode:", placingTower and "ON" or "OFF") if not placingTower then hideRangeIndicator() end end end) UserInputService.InputBegan:Connect(function (input, gameProcessed) if gameProcessed then return end if input.UserInputType == Enum.UserInputType.MouseButton1 and placingTower then local mouse = game.Players.LocalPlayer():GetMouse() local position = mouse.Hit.p if not isOnTrack(position) then local tower = Tower:new( selectedTowerType.model, position, selectedTowerType.range, selectedTowerType.damage, selectedTowerType.fireRate, selectedTowerType.effect ) table.insert(towers, tower) hideRangeIndicator() end end end) RunService.Heartbeat:Connect(function(dt) for _, tower in ipairs(towers) do tower:attack(enemies, dt) end end) RunService.Heartbeat:Connect(function(dt) for i, enemy in ipairs(enemies) do if enemy.alive then enemy:moveToWaypoints(waypoints, dt) end end end)