Auto script
Key Required

Auto script

Airport Tycoon✈️nuggetjiffnuggetjiff 433 views 3.1K executesUpdated Aug 3, 2026
Unrated
00
Lua Script•1094 lines (40550 chars)
-- ╔══════════════════════════════════════════════════╗
-- ║  Airport Tycoon Manager v4.0                     ║
-- ║  by buildermEn — refactored by ENI               ║
-- ╚══════════════════════════════════════════════════╝

-- Services
local Players           = game:GetService("Players")
local Workspace         = game:GetService("Workspace")
local VirtualUser       = game:GetService("VirtualUser")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local player    = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local hrp       = character:WaitForChild("HumanoidRootPart")

-- Character respawn handler
local savedWalkSpeed = 16
local function onCharacterAdded(newCharacter)
    character = newCharacter
    hrp = newCharacter:WaitForChild("HumanoidRootPart")
    -- Reapply walk speed
    local humanoid = newCharacter:WaitForChild("Humanoid")
    if humanoid and savedWalkSpeed ~= 16 then
        humanoid.WalkSpeed = savedWalkSpeed
    end
end
player.CharacterAdded:Connect(onCharacterAdded)

-- Runtime discovery
local runtime = Workspace:WaitForChild("AirportTycoonClientRuntime")
local tycoonNumber = nil

for _, v in ipairs(runtime:GetChildren()) do
    if v.Name ~= "Guide" and v.Name ~= "Planes" and v.Name ~= "TycoonTemplate" then
        tycoonNumber = v.Name
        break
    end
end

if not tycoonNumber then
    warn("[ATM v4] Tycoon not found!")
    return
end

local buttonFolder = runtime[tycoonNumber]:WaitForChild("Buttons")
local leaderstats  = player:WaitForChild("leaderstats")
local moneyStat    = leaderstats:WaitForChild("Money")

-- Upgrade remote
local Event = ReplicatedStorage
    .Packages
    ._Index["leifstout_networker@0.3.1"]
    .networker
    ._remotes
    .Upgrades
    .RemoteEvent

-- Passengers remote (for starting security lane operations)
local PassengerEvent = ReplicatedStorage
    .Packages
    ._Index["leifstout_networker@0.3.1"]
    .networker
    ._remotes
    .Passengers
    .RemoteEvent

-- ── State ──────────────────────────────────────────
local toggles = {
    autoCollect  = false,
    autoTrash    = false,
    autoBuy      = false,
    autoRebirth  = false,
    antiAfk      = false,
    autoUpgrade  = false,
    autoOps      = false,
}

local config = {
    collectDelay    = 0.3,
    trashDelay      = 0.5,
    buyDelay        = 0.5,
    rebirthDelay    = 2,
    upgradeDelay    = 5,
    upgradeFireCount = 4,
    opsDelay        = 2,
    buyStrategy     = "Smart",
}

local stats = {
    money          = 0,
    rebirthCost    = 0,
    totalUpgrades  = 0,
    upgradesAttempted = 0,
    itemsBought    = 0,
    trashCollected = 0,
    sessionStart   = os.clock(),
}

-- ── Color Constants for Smart Mode ─────────────────
-- Royal Purple = money-making buildings (priority 1)
-- Bright Blue  = security & checkin desks (priority 2)
local ROYAL_PURPLE = BrickColor.new("Royal purple")
local BRIGHT_BLUE  = BrickColor.new("Bright blue")

-- ╔══════════════════════════════════════════════════╗
-- ║  UTILITIES                                        ║
-- ╚══════════════════════════════════════════════════╝

local function formatMoney(n)
    if n >= 1e9 then return string.format("%.2fB", n / 1e9)
    elseif n >= 1e6 then return string.format("%.2fM", n / 1e6)
    elseif n >= 1e3 then return string.format("%.1fK", n / 1e3)
    end
    return tostring(math.floor(n))
end

local function formatUptime(seconds)
    local h = math.floor(seconds / 3600)
    local m = math.floor((seconds % 3600) / 60)
    local s = math.floor(seconds % 60)
    return string.format("%02d:%02d:%02d", h, m, s)
end

local function getHRP()
    local char = player.Character
    if not char then return nil end
    return char:FindFirstChild("HumanoidRootPart")
end

--- Classify a button's priority based on its Touch part color
local function getButtonPriority(button)
    local touch = button:FindFirstChild("Touch")
    if not touch or not touch:IsA("BasePart") then return 3 end

    local brick = touch.BrickColor
    if brick == ROYAL_PURPLE then
        return 1 -- money makers first
    elseif brick == BRIGHT_BLUE then
        return 2 -- security / checkin second
    end
    return 3 -- everything else last
end

--- Returns purchasable buttons sorted by current strategy
local function getButtons()
    local validButtons = {}
    for _, child in ipairs(buttonFolder:GetChildren()) do
        local devProduct = child:GetAttribute("DevProductId")
        local gamepass   = child:GetAttribute("GamepassId")
        if (devProduct == 0 or devProduct == nil)
        and (gamepass == 0 or gamepass == nil) then
            local touch = child:FindFirstChild("Touch")
            if touch then
                table.insert(validButtons, child)
            end
        end
    end

    if config.buyStrategy == "Smart" then
        -- Sort by priority tier first, then cheapest within each tier
        table.sort(validButtons, function(a, b)
            local prioA = getButtonPriority(a)
            local prioB = getButtonPriority(b)
            if prioA ~= prioB then
                return prioA < prioB
            end
            local costA = a:GetAttribute("Cost") or math.huge
            local costB = b:GetAttribute("Cost") or math.huge
            return costA < costB
        end)
    elseif config.buyStrategy == "Most Expensive First" then
        table.sort(validButtons, function(a, b)
            local costA = a:GetAttribute("Cost") or math.huge
            local costB = b:GetAttribute("Cost") or math.huge
            return costA > costB
        end)
    else -- Cheapest First
        table.sort(validButtons, function(a, b)
            local costA = a:GetAttribute("Cost") or math.huge
            local costB = b:GetAttribute("Cost") or math.huge
            return costA < costB
        end)
    end

    return validButtons
end

local function getRebirthRequirement()
    local ok, result = pcall(function()
        local playerGui = player:WaitForChild("PlayerGui", 5)
        if not playerGui then return math.huge end
        -- Exact path: PlayerGui.UI.Menus.Rebirth.Requirements.Details.Money
        local ui = playerGui:FindFirstChild("UI")
        if not ui then return math.huge end
        local menus = ui:FindFirstChild("Menus")
        if not menus then return math.huge end
        local rebirth = menus:FindFirstChild("Rebirth")
        if not rebirth then return math.huge end
        local requirements = rebirth:FindFirstChild("Requirements")
        if not requirements then return math.huge end
        local details = requirements:FindFirstChild("Details")
        if not details then return math.huge end
        local moneyLabel = details:FindFirstChild("Money")
        if not moneyLabel then return math.huge end

        -- Format: "Price: $currentCash/$225K"
        -- We want the number after the /
        local text = moneyLabel.Text
        local required = text:match("/(%$[%d%.]+[KMBkmb]?)")
        if not required then return math.huge end

        -- Strip the $ sign
        required = required:gsub("%$", "")
        local num    = tonumber(required:match("([%d%.]+)")) or 0
        local suffix = required:upper():match("([KMB])") or ""
        if suffix == "K" then num = num * 1e3
        elseif suffix == "M" then num = num * 1e6
        elseif suffix == "B" then num = num * 1e9 end
        return num
    end)
    return ok and result or math.huge
end

-- ── Upgrade System (Proximity Prompt based) ────────
local upgradePrompts = {} -- { { prompt = ProximityPrompt, id = string, modelName = string } }

local function refreshUpgradePrompts()
    upgradePrompts = {}
    pcall(function()
        local Models = runtime[tycoonNumber]:WaitForChild("Models", 5)
        if not Models then return end
        for _, descendant in pairs(Models:GetDescendants()) do
            if descendant:IsA("ProximityPrompt") and descendant.ActionText == "View Upgrades" then
                local id = string.gsub(descendant.ObjectText, " ", "")
                table.insert(upgradePrompts, {
                    prompt = descendant,
                    id     = id,
                })
            end
        end
    end)
    stats.totalUpgrades = #upgradePrompts
    return #upgradePrompts
end

local function doUpgradePass()
    if not toggles.autoUpgrade then return 0 end
    if #upgradePrompts == 0 then return 0 end

    local fired = 0
    for _, entry in ipairs(upgradePrompts) do
        if not toggles.autoUpgrade then break end
        for i = 1, config.upgradeFireCount do
            pcall(function()
                Event:FireServer("requestUpgrade", tycoonNumber, entry.id)
            end)
            fired += 1
            stats.upgradesAttempted += 1
        end
    end
    return fired
end

-- ╔══════════════════════════════════════════════════╗
-- ║  UI SETUP                                         ║
-- ╚══════════════════════════════════════════════════╝

local WindUI = loadstring(game:HttpGet(
    "https://github.com/Footagesus/WindUI/releases/latest/download/main.lua"
))()

local Window = WindUI:CreateWindow({
    Title = "Airport Tycoon Manager",
    Icon  = "plane",
    Author = "by buildermEn",
    Folder = "AirportTycoon",
    Size    = UDim2.fromOffset(580, 490),
    Theme          = "Dark",
    Transparent    = true,
    SideBarWidth   = 200,
    HideSearchBar  = true,
    ScrollBarEnabled = true,
    Acrylic        = true,
    TabTransition  = true,
    User = {
        Enabled = true,
        Anonymous = true,
    },
    OpenButton = {
        Title = "ATM v4",
        CornerRadius = UDim.new(1, 0),
        StrokeThickness = 2,
        Enabled = true,
        Color = ColorSequence.new(
            Color3.fromRGB(85, 170, 255),
            Color3.fromRGB(0, 255, 127)
        ),
    },
})

local function notify(title, content, icon, duration)
    pcall(function()
        WindUI:Notify({
            Title    = title,
            Content  = content or "",
            Icon     = icon or "info",
            Duration = duration or 3,
        })
    end)
end

-- ── Sections & Tabs ────────────────────────────────
local MainSection  = Window:Section({ Title = "Main",  Opened = true })
local ToolsSection = Window:Section({ Title = "Tools", Opened = true })
local InfoSection  = Window:Section({ Title = "Info",  Opened = true })

local HomeTab     = MainSection:Tab({ Title = "Home",       Icon = "home" })
local AutoTab     = MainSection:Tab({ Title = "Automation", Icon = "robot" })
local UpgradesTab = ToolsSection:Tab({ Title = "Upgrades",  Icon = "arrow-up-circle" })
local ExtrasTab   = ToolsSection:Tab({ Title = "Extras",    Icon = "wrench" })
local StatsTab    = InfoSection:Tab({ Title = "Statistics",  Icon = "bar-chart" })
local SettingsTab = InfoSection:Tab({ Title = "Settings",    Icon = "settings-2" })

-- ╔══════════════════════════════════════════════════╗
-- ║  HOME TAB                                         ║
-- ╚══════════════════════════════════════════════════╝

HomeTab:Paragraph({
    Title = "Welcome to ATM v4",
    Desc  = "Airport Tycoon Manager — automate your airport empire.",
    Image = "plane",
    ImageSize = 24,
    Color = Color3.fromRGB(85, 170, 255),
})

HomeTab:Divider()

local homeMoneyParagraph    = HomeTab:Paragraph({ Title = "Money: $0", Desc = "Loading..." })
local homeRebirthParagraph  = HomeTab:Paragraph({ Title = "Rebirth Progress: 0%", Desc = "Calculating..." })
local homeUptimeParagraph   = HomeTab:Paragraph({ Title = "Session Uptime: 00:00:00", Desc = "" })

HomeTab:Divider()

HomeTab:Paragraph({
    Title = "Smart Buy Mode",
    Desc  = "Prioritizes Royal Purple buttons (money makers) first, then Bright Blue (security/checkin), then everything else. Enable it in Automation.",
    Image = "zap",
    ImageSize = 18,
    Color = Color3.fromRGB(255, 200, 50),
})

-- ╔══════════════════════════════════════════════════╗
-- ║  AUTOMATION TAB                                   ║
-- ╚══════════════════════════════════════════════════╝

AutoTab:Section({ Title = "Income", Icon = "coins" })

AutoTab:Toggle({
    Title = "Auto Collect ATM",
    Icon  = "banknote",
    Desc  = "Collects money from ATMs automatically",
    Value = false,
    Callback = function(state)
        toggles.autoCollect = state
        if state then
            notify("Auto Collect", "ATM collection enabled", "banknote")
            task.spawn(function()
                while toggles.autoCollect do
                    task.wait(config.collectDelay)
                    local charHrp = getHRP()
                    if not charHrp then continue end
                    local accumulators = Workspace:FindFirstChild("AirportTycoonAccumulatorTouches")
                    if not accumulators then continue end
                    for _, v in ipairs(accumulators:GetChildren()) do
                        if v:IsA("BasePart") and v:FindFirstChild("TouchInterest") then
                            pcall(function()
                                firetouchinterest(charHrp, v, 0)
                                firetouchinterest(charHrp, v, 1)
                            end)
                        end
                    end
                end
            end)
        end
    end
})

AutoTab:Slider({
    Title = "Collect Speed", Desc = "Delay between cycles (s)",
    Value = { Min = 0.1, Max = 2, Default = 0.3 },
    Callback = function(v) config.collectDelay = v end,
})

AutoTab:Toggle({
    Title = "Auto Pickup Trash",
    Icon  = "trash-2",
    Desc  = "Teleports to trash and collects it",
    Value = false,
    Callback = function(state)
        toggles.autoTrash = state
        if state then
            notify("Auto Trash", "Trash collection enabled", "trash-2")
            task.spawn(function()
                while toggles.autoTrash do
                    task.wait(config.trashDelay)
                    local trashFolder = Workspace:FindFirstChild("AirportTycoonTrash")
                    if not trashFolder then continue end
                    for _, child in ipairs(trashFolder:GetChildren()) do
                        if not toggles.autoTrash then break end
                        if #child:GetChildren() == 0 then continue end
                        local sphere = child:FindFirstChild("Sphere")
                        if not sphere then continue end
                        local prompt = sphere:FindFirstChild("CleanTrashPrompt")
                        if not prompt or not prompt:IsA("ProximityPrompt") then continue end
                        local charHrp = getHRP()
                        if not charHrp then continue end
                        local originalCFrame = charHrp.CFrame
                        pcall(function()
                            charHrp.CFrame = sphere.CFrame + Vector3.new(0, 3, 0)
                            task.wait(0.1)
                            fireproximityprompt(prompt)
                            task.wait(0.2)
                            charHrp.CFrame = originalCFrame
                        end)
                        stats.trashCollected += 1
                    end
                end
            end)
        end
    end
})

AutoTab:Slider({
    Title = "Trash Speed", Desc = "Delay between cycles (s)",
    Value = { Min = 0.2, Max = 3, Default = 0.5 },
    Callback = function(v) config.trashDelay = v end,
})

AutoTab:Section({ Title = "Purchasing", Icon = "shopping-cart" })

AutoTab:Toggle({
    Title = "Auto Buy Buttons",
    Icon  = "shopping-bag",
    Desc  = "Purchases available buttons automatically",
    Value = false,
    Callback = function(state)
        toggles.autoBuy = state
        if state then
            notify("Auto Buy", "Purchasing: " .. config.buyStrategy, "shopping-bag")
            task.spawn(function()
                while toggles.autoBuy do
                    task.wait(config.buyDelay)
                    local charHrp = getHRP()
                    if not charHrp then continue end
                    local availableButtons = getButtons()
                    local boughtSomething = false
                    for _, button in ipairs(availableButtons) do
                        if not toggles.autoBuy then break end
                        local currentMoney = moneyStat.Value
                        local cost = button:GetAttribute("Cost") or math.huge
                        if currentMoney >= cost then
                            local touch = button:FindFirstChild("Touch")
                            if touch and touch:FindFirstChild("TouchInterest") then
                                pcall(function()
                                    firetouchinterest(charHrp, touch, 0)
                                    firetouchinterest(charHrp, touch, 1)
                                end)
                                boughtSomething = true
                                stats.itemsBought += 1
                                task.wait(0.3)
                            end
                        end
                    end
                    if not boughtSomething then task.wait(1) end
                end
            end)
        end
    end
})

AutoTab:Dropdown({
    Title  = "Buy Strategy",
    Desc   = "How buttons are prioritized",
    Values = { "Smart", "Cheapest First", "Most Expensive First" },
    Value  = "Smart",
    Callback = function(selected)
        config.buyStrategy = selected
        notify("Strategy", "Buy order: " .. selected, "shuffle")
    end,
})

AutoTab:Paragraph({
    Title = "Smart Mode Priority",
    Desc  = "1. Royal Purple (money makers)\n2. Bright Blue (security/checkin)\n3. Everything else\nCheapest first within each tier.",
    Image = "list-ordered",
    ImageSize = 16,
    Color = Color3.fromRGB(170, 85, 255),
})

AutoTab:Section({ Title = "Rebirth", Icon = "refresh-cw" })

AutoTab:Toggle({
    Title = "Auto Rebirth",
    Icon  = "refresh-cw",
    Desc  = "Rebirths when you can afford it",
    Value = false,
    Callback = function(state)
        toggles.autoRebirth = state
        if state then
            notify("Auto Rebirth", "Will rebirth when affordable", "refresh-cw")
            task.spawn(function()
                local RebirthEvent = ReplicatedStorage
                    .Packages
                    ._Index["leifstout_networker@0.3.1"]
                    .networker
                    ._remotes
                    .Rebirths
                    .RemoteEvent

                while toggles.autoRebirth do
                    task.wait(config.rebirthDelay)
                    local requirement  = getRebirthRequirement()
                    local currentMoney = moneyStat.Value
                    if currentMoney >= requirement and requirement ~= math.huge then
                        pcall(function()
                            RebirthEvent:FireServer("requestRebirth")
                        end)
                        task.wait(1)
                        -- Confirm it worked by checking if money dropped
                        if moneyStat.Value < currentMoney then
                            notify("Rebirth!", "Successfully rebirthed!", "refresh-cw", 5)
                            task.wait(3)
                        end
                    end
                end
            end)
        end
    end
})

AutoTab:Section({ Title = "Operations", Icon = "scan" })

AutoTab:Toggle({
    Title = "Auto Start Security Lanes",
    Icon  = "scan",
    Desc  = "Engage → 10s work → 1s disengage for collections → recheck",
    Value = false,
    Callback = function(state)
        toggles.autoOps = state
        if state then
            -- Pause trash to avoid teleport conflicts
            toggles._trashWasOn = toggles.autoTrash
            if toggles.autoTrash then
                toggles.autoTrash = false
                notify("Auto Ops", "Trash paused while active", "pause")
            end
            notify("Auto Ops", "Monitoring security lanes", "scan")
            task.spawn(function()
                while toggles.autoOps do
                    -- SCAN: find lanes with visible Caution warning
                    local lanesToStart = {}
                    pcall(function()
                        local Models = runtime[tycoonNumber].Models
                        for _, model in pairs(Models:GetChildren()) do
                            if not model.Name:find("SecurityLane") then continue end

                            local caution = nil
                            pcall(function()
                                caution = model.Level1.Core.Information.Caution
                            end)
                            if not caution then continue end

                            local isVisible = false
                            pcall(function() isVisible = caution.Visible end)
                            if not isVisible then continue end

                            -- Has visible warning — grab the interaction Part
                            local targetPart = nil
                            pcall(function() targetPart = model.Level1.Core.Part end)
                            if targetPart then
                                table.insert(lanesToStart, {
                                    name = model.Name,
                                    part = targetPart,
                                })
                            end
                        end
                    end)

                    if #lanesToStart > 0 then
                        local charHrp = getHRP()
                        if charHrp then
                            local homeCFrame = charHrp.CFrame

                            -- ENGAGE: teleport to each lane and fire its prompt
                            for _, lane in ipairs(lanesToStart) do
                                if not toggles.autoOps then break end
                                pcall(function()
                                    charHrp.CFrame = lane.part.CFrame + Vector3.new(0, 3, 0)
                                    task.wait(0.2)
                                    for _, child in pairs(lane.part:GetChildren()) do
                                        if child:IsA("ProximityPrompt") then
                                            fireproximityprompt(child)
                                            break
                                        end
                                    end
                                    task.wait(0.2)
                                end)
                                pcall(function()
                                    PassengerEvent:FireServer(
                                        "requestStartOperation",
                                        tycoonNumber,
                                        lane.name
                                    )
                                end)
                            end

                            -- HOLD: stay engaged ~10 seconds
                            local held = 0
                            while held < 10 and toggles.autoOps do
                                task.wait(1)
                                held += 1
                            end

                            -- DISENGAGE: teleport home for 1s so auto-collect can fire
                            if toggles.autoOps then
                                pcall(function()
                                    charHrp = getHRP()
                                    if charHrp then
                                        charHrp.CFrame = homeCFrame
                                    end
                                end)
                                task.wait(1) -- collection window
                            end
                        end
                    else
                        -- No lanes need help, chill before next scan
                        task.wait(config.opsDelay)
                    end
                    -- Loop back to SCAN — rechecks if any lanes still have issues
                end
            end)
        else
            -- Restore trash if it was on before
            if toggles._trashWasOn then
                toggles.autoTrash = true
                toggles._trashWasOn = false
                notify("Auto Ops", "Trash collection resumed", "play")
                task.spawn(function()
                    while toggles.autoTrash do
                        task.wait(config.trashDelay)
                        local trashFolder = Workspace:FindFirstChild("AirportTycoonTrash")
                        if not trashFolder then continue end
                        for _, child in ipairs(trashFolder:GetChildren()) do
                            if not toggles.autoTrash then break end
                            if #child:GetChildren() == 0 then continue end
                            local sphere = child:FindFirstChild("Sphere")
                            if not sphere then continue end
                            local prompt = sphere:FindFirstChild("CleanTrashPrompt")
                            if not prompt or not prompt:IsA("ProximityPrompt") then continue end
                            local charHrp = getHRP()
                            if not charHrp then continue end
                            local originalCFrame = charHrp.CFrame
                            pcall(function()
                                charHrp.CFrame = sphere.CFrame + Vector3.new(0, 3, 0)
                                task.wait(0.1)
                                fireproximityprompt(prompt)
                                task.wait(0.2)
                                charHrp.CFrame = originalCFrame
                            end)
                            stats.trashCollected += 1
                        end
                    end
                end)
            end
        end
    end
})

AutoTab:Slider({
    Title = "Ops Check Delay", Desc = "Seconds between lane checks",
    Value = { Min = 0.5, Max = 10, Default = 2 },
    Callback = function(v) config.opsDelay = v end,
})

-- ╔══════════════════════════════════════════════════╗
-- ║  UPGRADES TAB (Proximity Prompt system)           ║
-- ╚══════════════════════════════════════════════════╝

UpgradesTab:Section({ Title = "Auto Upgrade", Icon = "zap" })

UpgradesTab:Paragraph({
    Title = "How It Works",
    Desc  = "Scans your tycoon models for ProximityPrompts with ActionText 'View Upgrades'. Reads ObjectText (spaces stripped) as the upgrade ID, then fires requestUpgrade on the remote for each one.",
    Image = "arrow-up-circle",
    ImageSize = 18,
    Color = Color3.fromRGB(255, 170, 0),
})

UpgradesTab:Toggle({
    Title = "Auto Upgrade",
    Icon  = "zap",
    Desc  = "Continuously fires upgrade remotes every cycle",
    Value = false,
    Callback = function(state)
        toggles.autoUpgrade = state
        if state then
            notify("Auto Upgrade", "Running continuously", "zap")
            task.spawn(function()
                while toggles.autoUpgrade do
                    refreshUpgradePrompts()
                    if #upgradePrompts > 0 then
                        local fired = doUpgradePass()
                    end
                    task.wait(config.upgradeDelay)
                end
            end)
        end
    end
})

UpgradesTab:Slider({
    Title = "Fires Per ID", Desc = "How many times to fire each upgrade ID per cycle",
    Value = { Min = 1, Max = 10, Default = 4 },
    Callback = function(v) config.upgradeFireCount = v end,
})

UpgradesTab:Slider({
    Title = "Cycle Delay", Desc = "Seconds between each upgrade cycle",
    Value = { Min = 1, Max = 30, Default = 5 },
    Callback = function(v) config.upgradeDelay = v end,
})

UpgradesTab:Button({
    Title = "Refresh Upgrade Prompts",
    Icon  = "search",
    Desc  = "Rescan for ComponentUpgradePrompt instances",
    Callback = function()
        local count = refreshUpgradePrompts()
        notify("Prompts Found", count .. " upgrade prompts detected", "search")
    end
})

UpgradesTab:Button({
    Title = "Run Single Pass Now",
    Icon  = "play",
    Desc  = "Fire upgrade remote for all discovered IDs once",
    Callback = function()
        refreshUpgradePrompts()
        if #upgradePrompts == 0 then
            notify("No Prompts", "No ComponentUpgradePrompt found", "alert-triangle")
            return
        end
        task.spawn(function()
            local upgraded = doUpgradePass()
            notify("Manual Pass", "Fired " .. upgraded .. " prompts", "check")
        end)
    end
})

UpgradesTab:Section({ Title = "Detected Prompts", Icon = "activity" })

local upgradeCountParagraph = UpgradesTab:Paragraph({
    Title = "Upgrade Prompts: 0",
    Desc  = "Hit Refresh to scan",
})

-- ╔══════════════════════════════════════════════════╗
-- ║  EXTRAS TAB                                       ║
-- ╚══════════════════════════════════════════════════╝

ExtrasTab:Section({ Title = "UI Cleanup", Icon = "eye-off" })

ExtrasTab:Paragraph({
    Title = "Remove Game UI",
    Desc  = "Hide annoying popups and shop menus from the game's default interface.",
})

ExtrasTab:Button({
    Title = "Remove Currency Popups",
    Icon  = "x-circle",
    Desc  = "Hides PlayerGui.Currency.Popups",
    Callback = function()
        pcall(function()
            local currency = player.PlayerGui:FindFirstChild("Currency")
            if currency then
                local p = currency:FindFirstChild("Popups")
                if p then p:Destroy(); notify("Removed", "Currency Popups destroyed", "check")
                else notify("Not Found", "Popups not found inside Currency", "alert-triangle") end
            else notify("Not Found", "Currency GUI not found", "alert-triangle") end
        end)
    end
})

ExtrasTab:Button({
    Title = "Remove Shop Menu",
    Icon  = "x-circle",
    Desc  = "Hides PlayerGui.UI.Menus.Shop",
    Callback = function()
        pcall(function()
            local ui = player.PlayerGui:FindFirstChild("UI")
            if ui then
                local menus = ui:FindFirstChild("Menus")
                if menus then
                    local shop = menus:FindFirstChild("Shop")
                    if shop then shop:Destroy(); notify("Removed", "Shop menu destroyed", "check")
                    else notify("Not Found", "Shop not found", "alert-triangle") end
                else notify("Not Found", "Menus folder not found", "alert-triangle") end
            else notify("Not Found", "UI GUI not found", "alert-triangle") end
        end)
    end
})

ExtrasTab:Button({
    Title = "Remove Both",
    Icon  = "trash",
    Desc  = "Currency Popups + Shop Menu at once",
    Callback = function()
        local removed = 0
        pcall(function()
            local c = player.PlayerGui:FindFirstChild("Currency")
            if c then local p = c:FindFirstChild("Popups"); if p then p:Destroy(); removed += 1 end end
        end)
        pcall(function()
            local u = player.PlayerGui:FindFirstChild("UI")
            if u then local m = u:FindFirstChild("Menus")
                if m then local s = m:FindFirstChild("Shop"); if s then s:Destroy(); removed += 1 end end
            end
        end)
        notify("Cleanup", "Removed " .. removed .. "/2 elements", "check")
    end
})

-- ╔══════════════════════════════════════════════════╗
-- ║  STATISTICS TAB                                   ║
-- ╚══════════════════════════════════════════════════╝

StatsTab:Section({ Title = "Financial", Icon = "dollar-sign" })

local statMoney = StatsTab:Paragraph({ Title = "Money: $0", Desc = "" })

local statRebirthBar = StatsTab:ProgressBar({
    Title = "Rebirth Progress",
    Desc  = "How close to next rebirth",
    Value = { Min = 0, Max = 100, Default = 0 },
    Format = function(v, pct) return string.format("%.1f%%", pct) end,
})

local statRebirthCost = StatsTab:Paragraph({ Title = "Rebirth Cost: N/A", Desc = "" })

StatsTab:Section({ Title = "Session", Icon = "clock" })

local statUptime   = StatsTab:Paragraph({ Title = "Uptime: 00:00:00", Desc = "" })
local statBought   = StatsTab:Paragraph({ Title = "Items Bought: 0", Desc = "" })
local statTrash    = StatsTab:Paragraph({ Title = "Trash Collected: 0", Desc = "" })

StatsTab:Section({ Title = "Upgrades", Icon = "trending-up" })

local statPrompts      = StatsTab:Paragraph({ Title = "Upgrade Prompts: 0", Desc = "" })
local statUpgradesFired = StatsTab:Paragraph({ Title = "Upgrades Attempted: 0", Desc = "" })

-- ── Stats updater ──────────────────────────────────
local function updateAllStats()
    stats.money       = moneyStat.Value
    stats.rebirthCost = getRebirthRequirement()

    pcall(function()
        -- Home tab
        homeMoneyParagraph:SetTitle("Money: $" .. formatMoney(stats.money))
        homeMoneyParagraph:SetDesc("Raw: " .. stats.money)

        local progress = 0
        if stats.rebirthCost > 0 and stats.rebirthCost ~= math.huge then
            progress = math.min(100, (stats.money / stats.rebirthCost) * 100)
        end
        homeRebirthParagraph:SetTitle("Rebirth Progress: " .. math.floor(progress) .. "%")
        homeRebirthParagraph:SetDesc("Cost: $" .. (stats.rebirthCost == math.huge and "N/A" or formatMoney(stats.rebirthCost)))

        local uptime = os.clock() - stats.sessionStart
        homeUptimeParagraph:SetTitle("Session Uptime: " .. formatUptime(uptime))

        -- Stats tab
        statMoney:SetTitle("Money: $" .. formatMoney(stats.money))
        statMoney:SetDesc("Raw: " .. stats.money)
        statRebirthBar:Set(progress)
        statRebirthCost:SetTitle("Rebirth Cost: $" .. (stats.rebirthCost == math.huge and "N/A" or formatMoney(stats.rebirthCost)))
        statUptime:SetTitle("Uptime: " .. formatUptime(uptime))
        statBought:SetTitle("Items Bought: " .. stats.itemsBought)
        statTrash:SetTitle("Trash Collected: " .. stats.trashCollected)
        statPrompts:SetTitle("Upgrade Prompts: " .. #upgradePrompts)
        statUpgradesFired:SetTitle("Upgrades Attempted: " .. stats.upgradesAttempted)

        -- Upgrades tab prompt count
        upgradeCountParagraph:SetTitle("Upgrade Prompts: " .. #upgradePrompts)
        upgradeCountParagraph:SetDesc(#upgradePrompts > 0
            and "Ready to upgrade"
            or "No prompts found — hit Refresh")
    end)
end

-- ╔══════════════════════════════════════════════════╗
-- ║  SETTINGS TAB                                     ║
-- ╚══════════════════════════════════════════════════╝

SettingsTab:Section({ Title = "Connection", Icon = "wifi" })

SettingsTab:Toggle({
    Title = "Anti AFK",
    Icon  = "shield",
    Desc  = "Prevents being kicked for inactivity",
    Value = false,
    Callback = function(state)
        toggles.antiAfk = state
        if state then
            notify("Anti AFK", "AFK prevention enabled", "shield")
            task.spawn(function()
                while toggles.antiAfk do
                    task.wait(120)
                    if not toggles.antiAfk then break end
                    pcall(function()
                        VirtualUser:CaptureController()
                        VirtualUser:ClickButton2(Vector2.new(0, 0))
                    end)
                end
            end)
        end
    end
})

SettingsTab:Section({ Title = "Player Controls", Icon = "user" })

SettingsTab:Slider({
    Title = "Walk Speed", Desc = "Default is 16",
    Value = { Min = 16, Max = 200, Default = 16 },
    Callback = function(v)
        savedWalkSpeed = v
        pcall(function()
            local char = player.Character
            if char then
                local humanoid = char:FindFirstChildOfClass("Humanoid")
                if humanoid then humanoid.WalkSpeed = v end
            end
        end)
    end,
})

-- Fly state
local flying = false
local flySpeed = 50
local flyBodyVelocity = nil
local flyBodyGyro = nil

SettingsTab:Toggle({
    Title = "Flight",
    Icon  = "wind",
    Desc  = "Hold jump to fly, WASD to steer",
    Value = false,
    Callback = function(state)
        flying = state
        local char = player.Character
        if not char then return end
        local charHrp = char:FindFirstChild("HumanoidRootPart")
        local humanoid = char:FindFirstChildOfClass("Humanoid")
        if not charHrp or not humanoid then return end

        if state then
            -- Create flight movers
            flyBodyVelocity = Instance.new("BodyVelocity")
            flyBodyVelocity.MaxForce = Vector3.new(math.huge, math.huge, math.huge)
            flyBodyVelocity.Velocity = Vector3.new(0, 0, 0)
            flyBodyVelocity.Parent = charHrp

            flyBodyGyro = Instance.new("BodyGyro")
            flyBodyGyro.MaxTorque = Vector3.new(math.huge, math.huge, math.huge)
            flyBodyGyro.P = 9e4
            flyBodyGyro.Parent = charHrp

            notify("Flight", "Enabled — use WASD + Space/Shift", "wind")

            task.spawn(function()
                local UIS = game:GetService("UserInputService")
                while flying do
                    task.wait()
                    if not flying then break end
                    local cam = Workspace.CurrentCamera
                    local moveDir = Vector3.new(0, 0, 0)

                    if UIS:IsKeyDown(Enum.KeyCode.W) then
                        moveDir = moveDir + cam.CFrame.LookVector
                    end
                    if UIS:IsKeyDown(Enum.KeyCode.S) then
                        moveDir = moveDir - cam.CFrame.LookVector
                    end
                    if UIS:IsKeyDown(Enum.KeyCode.A) then
                        moveDir = moveDir - cam.CFrame.RightVector
                    end
                    if UIS:IsKeyDown(Enum.KeyCode.D) then
                        moveDir = moveDir + cam.CFrame.RightVector
                    end
                    if UIS:IsKeyDown(Enum.KeyCode.Space) then
                        moveDir = moveDir + Vector3.new(0, 1, 0)
                    end
                    if UIS:IsKeyDown(Enum.KeyCode.LeftShift) then
                        moveDir = moveDir - Vector3.new(0, 1, 0)
                    end

                    if moveDir.Magnitude > 0 then
                        moveDir = moveDir.Unit * flySpeed
                    end

                    flyBodyVelocity.Velocity = moveDir
                    flyBodyGyro.CFrame = cam.CFrame
                end
            end)
        else
            -- Clean up flight movers
            if flyBodyVelocity then flyBodyVelocity:Destroy(); flyBodyVelocity = nil end
            if flyBodyGyro then flyBodyGyro:Destroy(); flyBodyGyro = nil end
            notify("Flight", "Disabled", "wind")
        end
    end
})

SettingsTab:Slider({
    Title = "Fly Speed", Desc = "How fast you fly",
    Value = { Min = 10, Max = 300, Default = 50 },
    Callback = function(v) flySpeed = v end,
})

SettingsTab:Section({ Title = "UI Controls", Icon = "sliders" })

SettingsTab:Keybind({
    Title = "Toggle UI",
    Desc  = "Show/hide the window",
    Value = "RightControl",
    Callback = function()
        pcall(function() Window:Toggle() end)
    end
})

SettingsTab:Button({
    Title = "Refresh Everything",
    Icon  = "refresh-cw",
    Desc  = "Reload buttons, prompts, and stats",
    Callback = function()
        refreshUpgradePrompts()
        updateAllStats()
        notify("Refreshed", "All data reloaded", "refresh-cw")
    end
})

local DestroyDialog
DestroyDialog = Window:Dialog({
    Title   = "Destroy UI",
    Icon    = "alert-triangle",
    Content = "Close the script? All automation stops.",
    Buttons = {
        {
            Title = "Yes, Close",
            Variant = "Primary",
            Callback = function()
                for key, _ in pairs(toggles) do toggles[key] = false end
                Window:Destroy()
            end
        },
        {
            Title = "Cancel",
            Callback = function()
                DestroyDialog:Close()
            end
        }
    }
})

SettingsTab:Button({
    Title = "Destroy UI",
    Icon  = "x",
    Desc  = "Close the script (with confirmation)",
    Callback = function() DestroyDialog:Show() end
})

-- ╔══════════════════════════════════════════════════╗
-- ║  INIT                                             ║
-- ╚══════════════════════════════════════════════════╝

refreshUpgradePrompts()
updateAllStats()

task.spawn(function()
    while task.wait(2) do
        pcall(updateAllStats)
    end
end)

notify("Script Loaded", "ATM v4 ready! Smart mode + prompt upgrades", "plane", 5)

Features & Information

Auto buy buttons smart mode Auto rebirth Auto Collect Auto manual security (S.M.A.R.T.) Auto pickup trash Auto upgrade remove popups and shop statistics antiafk walk speed flying flyspeed

Community Comments (0)

No comments yet for this script.

More Scripts for Airport Tycoon✈️