NEW  SCRIPT
Key Required

NEW SCRIPT

[SEASON 1 🌟] Car Sales 2 🏎️1_qx3i1_qx3i 1.6K views 2.9K executesUpdated Jun 25, 2026
Unrated
00
Lua Script•1240 lines (60635 chars)
local Players          = game:GetService("Players")
local RunService       = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local SoundService     = game:GetService("SoundService")
local lp               = Players.LocalPlayer
local playerGui        = lp:WaitForChild("PlayerGui")

if playerGui:FindFirstChild("CarESP_GUI") then playerGui.CarESP_GUI:Destroy() end

local screenGui = Instance.new("ScreenGui")
screenGui.Name            = "CarESP_GUI"
screenGui.ResetOnSpawn    = false
screenGui.ZIndexBehavior  = Enum.ZIndexBehavior.Sibling
screenGui.IgnoreGuiInset  = true
screenGui.Parent          = playerGui

-- ══════════════════════════════════════════
-- THEME
-- ══════════════════════════════════════════
local C = {
    bg0        = Color3.fromRGB(8,8,14),
    bg1        = Color3.fromRGB(14,14,22),
    bg2        = Color3.fromRGB(22,20,36),
    accent     = Color3.fromRGB(255,180,0),
    accent2    = Color3.fromRGB(200,130,255),
    green      = Color3.fromRGB(0,220,100),
    blue       = Color3.fromRGB(80,180,255),
    red        = Color3.fromRGB(255,60,60),
    gold       = Color3.fromRGB(255,215,0),
    text       = Color3.fromRGB(230,230,240),
    subtext    = Color3.fromRGB(140,140,160),
    white      = Color3.fromRGB(255,255,255),
    plateGreen = Color3.fromRGB(0,130,62),
    plateDark  = Color3.fromRGB(10,30,10),
    plateGold  = Color3.fromRGB(220,180,0),
    purple     = Color3.fromRGB(140,60,255),
    orange     = Color3.fromRGB(255,120,0),
}

local function glassFrame(parent, size, pos, alpha, radius)
    local f = Instance.new("Frame", parent)
    f.Size = size f.Position = pos
    f.BackgroundColor3 = C.bg1
    f.BackgroundTransparency = alpha or 0.82
    f.BorderSizePixel = 0
    Instance.new("UICorner", f).CornerRadius = UDim.new(0, radius or 14)
    return f
end
local function makeStroke(parent, color, thickness, transparency)
    local s = Instance.new("UIStroke", parent)
    s.Color = color or C.accent
    s.Thickness = thickness or 1.5
    s.Transparency = transparency or 0
    return s
end
local function makeLabel(parent, text, color, font, size, xa, ya)
    local l = Instance.new("TextLabel", parent)
    l.Text = text l.TextColor3 = color or C.text
    l.Font = font or Enum.Font.GothamBold
    l.TextSize = size or 14 l.TextScaled = not size
    l.BackgroundTransparency = 1 l.BorderSizePixel = 0
    l.TextXAlignment = xa or Enum.TextXAlignment.Left
    l.TextYAlignment = ya or Enum.TextYAlignment.Center
    return l
end
local function makeButton(parent, text, bg, tc, radius)
    local b = Instance.new("TextButton", parent)
    b.Text = text b.BackgroundColor3 = bg or C.bg2
    b.TextColor3 = tc or C.white b.Font = Enum.Font.GothamBold
    b.TextScaled = true b.BorderSizePixel = 0 b.AutoButtonColor = false
    Instance.new("UICorner", b).CornerRadius = UDim.new(0, radius or 8)
    return b
end
local function addHover(btn, n, h)
    btn.MouseEnter:Connect(function() btn.BackgroundColor3 = h end)
    btn.MouseLeave:Connect(function() btn.BackgroundColor3 = n end)
end

-- ══════════════════════════════════════════
-- STATE
-- ══════════════════════════════════════════
local lang           = "EN"
local espEnabled     = true
local scanning       = false
local stopRequested  = false
local minimized      = false
local sortMode       = "score"
local persistedData  = {}

-- Feature states
local alertPlate     = ""      -- plate string to watch for
local alertTriggered = {}      -- track which plates already alerted this session
local autoBuyEnabled = false   -- auto-buy toggle
local autoBuyThreshold = 80    -- score needed to trigger auto-buy
local autoRescanEnabled = false
local autoRescanMins    = 5
local autoRescanTimer   = 0    -- counts up in heartbeat

local filters = { maxPrice=nil, maxMiles=nil, dealOnly=false, dealThreshold=70 }
local PRICE_GREAT = 80000
local MILES_BAD   = 150000

local T_TABLE = {
    EN = {
        title="🚗 Car Sales 2 ESP v5", scan="▶ SCAN ALL CARS", rescan="🔄 RESCAN",
        scanning="Scanning", done="Done!", scanned="scanned", cars="cars",
        plate="Plate", noOwner="No Owner", pressToScan="Press SCAN to begin",
        stop="⏹ STOP", bestDeal="🏆 BEST DEAL", dealFound="deals found!",
        copied="✓ Copied!", justNow="just now", minsAgo="m ago",
        alertSection="🔔 PLATE ALERT", alertPlaceholder="e.g. BGS 183",
        autoBuySection="🎯 AUTO-BUY", autoRescanSection="⏰ AUTO-RESCAN",
        rescanEvery="Rescan every (mins):", minScore="Min score to buy:",
        autoBuyOff="AUTO-BUY: OFF", autoBuyOn="AUTO-BUY: ON",
        autoRescanOff="RESCAN: OFF", autoRescanOn="RESCAN: ON",
        alertHit="🔔 ALERT: Plate found!", autoBought="🎯 Auto-bought!",
        nextRescan="Next rescan in:",
    },
    AR = {
        title="🚗 ESP السيارات v5", scan="▶ فحص الكل", rescan="🔄 إعادة",
        scanning="جاري الفحص", done="تم!", scanned="تم فحصها", cars="سيارات",
        plate="اللوحة", noOwner="بدون مالك", pressToScan="اضغط فحص للبدء",
        stop="⏹ إيقاف", bestDeal="🏆 أفضل صفقة", dealFound="صفقات!",
        copied="✓ نسخ!", justNow="الآن", minsAgo="د",
        alertSection="🔔 تنبيه لوحة", alertPlaceholder="مثال: BGS 183",
        autoBuySection="🎯 شراء تلقائي", autoRescanSection="⏰ إعادة فحص تلقائي",
        rescanEvery="إعادة كل (دقائق):", minScore="أدنى نقاط:",
        autoBuyOff="شراء: إيقاف", autoBuyOn="شراء: تشغيل",
        autoRescanOff="فحص: إيقاف", autoRescanOn="فحص: تشغيل",
        alertHit="🔔 تنبيه: تم العثور على اللوحة!", autoBought="🎯 تم الشراء!",
        nextRescan="الفحص التالي خلال:",
    }
}
local function T(k) return T_TABLE[lang][k] or k end

-- ══════════════════════════════════════════
-- HELPERS
-- ══════════════════════════════════════════
local function dealScore(price, mile)
    if not price or not mile then return nil end
    local p = tonumber(tostring(price):gsub("[^%d]","")) or 0
    local m = tonumber(tostring(mile):gsub("[^%d]",""))  or 0
    return math.floor(math.clamp(1-(m/MILES_BAD),0,1)*60 + math.clamp(p/PRICE_GREAT,0,1)*40)
end
local function getDealColor(score)
    if score >= 85 then return C.gold
    elseif score >= 70 then return C.green
    elseif score >= 50 then return C.blue
    else return C.subtext end
end
local function fmt(n)
    if not n then return "---" end
    local clean = tostring(n):gsub("[^%d]","")
    if clean=="" then return "---" end
    local s = tostring(math.floor(tonumber(clean) or 0))
    return s:reverse():gsub("(%d%d%d)","%1,"):reverse():gsub("^,","")
end
local function timeSince(ts)
    if not ts then return "---" end
    local diff = math.floor(os.clock()-ts)
    if diff < 60 then return T("justNow")
    else return math.floor(diff/60)..T("minsAgo") end
end
local function passesFilter(data)
    local price = tonumber(tostring(data.price or ""):gsub("[^%d]",""))
    local mile  = tonumber(tostring(data.mile  or ""):gsub("[^%d]",""))
    if filters.maxPrice and price and price > filters.maxPrice then return false end
    if filters.maxMiles and mile  and mile  > filters.maxMiles  then return false end
    if filters.dealOnly then
        local sc = dealScore(data.price,data.mile)
        if not sc or sc < filters.dealThreshold then return false end
    end
    return true
end

-- ══════════════════════════════════════════
-- SAUDI PLATE BUILDER
-- ══════════════════════════════════════════
local function parsePlate(plateData)
    local en = plateData and plateData.en or "???"
    local ar = plateData and plateData.ar or ""
    local letters,numbers = en:match("^(%a+)%s*(%d+)$")
    if not letters then letters=en numbers="" end
    local arLetters = ar:match("^(.-)%s*%d") or ar
    return letters,numbers,arLetters
end
local function buildSaudiPlate(parent, plateData, isBig)
    for _,c in ipairs(parent:GetChildren()) do c:Destroy() end
    local letters,numbers,arLetters = parsePlate(plateData)
    local bg = Instance.new("Frame",parent)
    bg.Size=UDim2.new(1,0,1,0) bg.BackgroundColor3=Color3.fromRGB(255,255,255) bg.BorderSizePixel=0
    Instance.new("UICorner",bg).CornerRadius=UDim.new(0,isBig and 7 or 4)
    local pb=Instance.new("UIStroke",bg) pb.Color=Color3.fromRGB(200,200,200) pb.Thickness=1

    local stripe=Instance.new("Frame",bg)
    stripe.Size=UDim2.new(0.18,0,1,0) stripe.BackgroundColor3=C.plateGreen stripe.BorderSizePixel=0
    Instance.new("UICorner",stripe).CornerRadius=UDim.new(0,isBig and 7 or 4)
    local sf=Instance.new("Frame",stripe)
    sf.Size=UDim2.new(0.5,0,1,0) sf.Position=UDim2.new(0.5,0,0,0)
    sf.BackgroundColor3=C.plateGreen sf.BorderSizePixel=0

    local ksaL=Instance.new("TextLabel",stripe)
    ksaL.Size=UDim2.new(1,0,0.45,0) ksaL.Position=UDim2.new(0,0,0.04,0)
    ksaL.BackgroundTransparency=1 ksaL.TextColor3=C.white
    ksaL.TextScaled=true ksaL.Font=Enum.Font.GothamBold ksaL.Text="KSA"

    local iconL=Instance.new("TextLabel",stripe)
    iconL.Size=UDim2.new(1,0,0.4,0) iconL.Position=UDim2.new(0,0,0.52,0)
    iconL.BackgroundTransparency=1 iconL.TextColor3=C.plateGold
    iconL.TextScaled=true iconL.Font=Enum.Font.GothamBold iconL.Text="🌴"

    local content=Instance.new("Frame",bg)
    content.Size=UDim2.new(0.80,0,1,0) content.Position=UDim2.new(0.20,0,0,0)
    content.BackgroundTransparency=1 content.BorderSizePixel=0

    local arL=Instance.new("TextLabel",content)
    arL.Size=UDim2.new(1,-4,0.45,0) arL.Position=UDim2.new(0,2,0,0)
    arL.BackgroundTransparency=1 arL.TextColor3=C.plateDark arL.TextScaled=true
    arL.Font=Enum.Font.GothamBold arL.TextXAlignment=Enum.TextXAlignment.Right
    arL.Text=(arLetters~="" and arLetters~="???") and arLetters or letters

    local numL=Instance.new("TextLabel",content)
    numL.Size=UDim2.new(0.55,-2,0.48,0) numL.Position=UDim2.new(0,2,0.52,0)
    numL.BackgroundTransparency=1 numL.TextColor3=C.plateDark numL.TextScaled=true
    numL.Font=Enum.Font.GothamBold numL.TextXAlignment=Enum.TextXAlignment.Left numL.Text=numbers

    local enL=Instance.new("TextLabel",content)
    enL.Size=UDim2.new(0.43,-2,0.48,0) enL.Position=UDim2.new(0.57,0,0.52,0)
    enL.BackgroundTransparency=1 enL.TextColor3=C.plateDark enL.TextScaled=true
    enL.Font=Enum.Font.GothamBold enL.TextXAlignment=Enum.TextXAlignment.Right enL.Text=letters
end

-- ══════════════════════════════════════════
-- ALERTS & SOUNDS
-- ══════════════════════════════════════════
local function playSound(id, vol)
    local snd=Instance.new("Sound",SoundService)
    snd.SoundId="rbxassetid://"..tostring(id) snd.Volume=vol or 0.6 snd:Play()
    game:GetService("Debris"):AddItem(snd,4)
end
local function flashScreen(color, times, alpha)
    local flash=Instance.new("Frame",screenGui)
    flash.Size=UDim2.new(1,0,1,0) flash.BackgroundColor3=color
    flash.BackgroundTransparency=alpha or 0.5 flash.BorderSizePixel=0 flash.ZIndex=100
    for i=1,times or 4 do
        flash.BackgroundTransparency=(alpha or 0.5)+(i*0.12) task.wait(0.07)
    end
    flash:Destroy()
end

local function playDealAlert()
    task.spawn(function() flashScreen(C.gold,4,0.5) end)
    playSound(4612359885, 0.6)
end

-- 🔔 Plate alert — fires when a specific plate text is detected
local function checkPlateAlert(name, data)
    if alertPlate=="" then return end
    if alertTriggered[name] then return end
    local en = data.plate and data.plate.en:lower() or ""
    local ar = data.plate and data.plate.ar:lower() or ""
    local query = alertPlate:lower()
    if en:find(query,1,true) or ar:find(query,1,true) then
        alertTriggered[name]=true
        task.spawn(function()
            flashScreen(C.accent2,6,0.35)
            playSound(4612359885,0.8)
            playSound(4612359885,0.8)
        end)
        -- Toast notification
        local toast=Instance.new("Frame",screenGui)
        toast.Size=UDim2.new(0,320,0,60) toast.BackgroundColor3=Color3.fromRGB(60,0,120)
        toast.BackgroundTransparency=0.1 toast.BorderSizePixel=0 toast.ZIndex=200
        toast.Position=UDim2.new(0.5,-160,0,-70)
        Instance.new("UICorner",toast).CornerRadius=UDim.new(0,12)
        makeStroke(toast,C.accent2,2)
        local tl=makeLabel(toast,T("alertHit").." → "..( data.plate and data.plate.en or ""),C.white,Enum.Font.GothamBold,nil,Enum.TextXAlignment.Center)
        tl.Size=UDim2.new(1,0,0.5,0) tl.Position=UDim2.new(0,0,0,4) tl.ZIndex=201
        local tl2=makeLabel(toast,"Score: "..(dealScore(data.price,data.mile) and tostring(dealScore(data.price,data.mile)) or "?").."/100  |  "..( data.price and ("$"..fmt(data.price)) or "?"),C.accent2,Enum.Font.Gotham,nil,Enum.TextXAlignment.Center)
        tl2.Size=UDim2.new(1,0,0.5,0) tl2.Position=UDim2.new(0,0,0.5,0) tl2.ZIndex=201
        -- Slide in
        local goal=UDim2.new(0.5,-160,0,10)
        toast.Position=UDim2.new(0.5,-160,0,-70)
        local t0=tick()
        local conn RunService.Heartbeat:Connect(function()
            local p=math.min((tick()-t0)/0.3,1)
            toast.Position=UDim2.new(0.5,-160,0,-70+(80*p))
            if p>=1 then conn:Disconnect() end
        end)
        task.wait(4)
        toast:Destroy()
    end
end

-- 🎯 Auto-buy a car (teleport + fire buy prompt)
local function tryAutoBuy(car, slot)
    if not autoBuyEnabled then return end
    local data = require ~= nil and nil or nil  -- placeholder reset
    -- find data for this car
    local cdata
    for _,d in pairs(require ~= nil and {} or {}) do end  -- unused
    -- direct lookup
    for name,d in pairs(carData or {}) do
        if d.car==car then cdata=d break end
    end
    if not cdata then return end
    local score=dealScore(cdata.price,cdata.mile)
    if not score or score<autoBuyThreshold then return end

    local char=lp.Character if not char then return end
    local hrp=char:FindFirstChild("HumanoidRootPart") if not hrp then return end

    -- Find buy prompt in slot
    local buyPrompt=nil
    local npcSlot=slot:FindFirstChild("NpcSlot")
    if npcSlot then
        -- Look for buy/purchase prompt
        for _,obj in ipairs(npcSlot:GetDescendants()) do
            if obj:IsA("ProximityPrompt") and
               (obj.Name:lower():find("buy") or obj.Name:lower():find("purchase") or obj.Name:lower():find("confirm")) then
                buyPrompt=obj break
            end
        end
        -- Fallback: use the interaction prompt
        if not buyPrompt then buyPrompt=npcSlot:FindFirstChild("Interaction") end
    end
    if not buyPrompt then return end

    local root=car.PrimaryPart or car:FindFirstChildWhichIsA("BasePart")
    if root then
        pcall(function() hrp.CFrame=root.CFrame*CFrame.new(0,0,4) end)
        task.wait(0.6)
        pcall(function() fireproximityprompt(buyPrompt) end)
        task.wait(0.3)
        -- Try to confirm any buy dialog
        for _,gui in ipairs(playerGui:GetChildren()) do
            if gui:IsA("ScreenGui") and gui.Enabled and gui.Name~="CarESP_GUI" then
                local cb=gui:FindFirstChild("Confirm",true) or gui:FindFirstChild("Buy",true)
                        or gui:FindFirstChild("Purchase",true) or gui:FindFirstChild("Yes",true)
                if cb and cb:IsA("TextButton") then
                    pcall(function() cb.MouseButton1Click:Fire() end)
                end
            end
        end
        -- Toast
        local toast=Instance.new("Frame",screenGui)
        toast.Size=UDim2.new(0,280,0,50) toast.Position=UDim2.new(0.5,-140,0,10)
        toast.BackgroundColor3=Color3.fromRGB(0,80,30) toast.BackgroundTransparency=0.1
        toast.BorderSizePixel=0 toast.ZIndex=200
        Instance.new("UICorner",toast).CornerRadius=UDim.new(0,10)
        makeStroke(toast,C.green,2)
        local tl=makeLabel(toast,T("autoBought").." "..( cdata.plate and cdata.plate.en or ""),C.green,Enum.Font.GothamBold,nil,Enum.TextXAlignment.Center)
        tl.Size=UDim2.new(1,0,1,0) tl.ZIndex=201
        task.delay(3,function() toast:Destroy() end)
        flashScreen(C.green,3,0.6)
        playSound(4612359885,0.5)
    end
end

-- ══════════════════════════════════════════
-- HOVER POPUP
-- ══════════════════════════════════════════
local popup=Instance.new("Frame",screenGui)
popup.Name="HoverPopup" popup.Size=UDim2.new(0,248,0,178)
popup.BackgroundColor3=C.bg0 popup.BackgroundTransparency=0.08
popup.BorderSizePixel=0 popup.Visible=false popup.ZIndex=60
Instance.new("UICorner",popup).CornerRadius=UDim.new(0,14)
makeStroke(popup,C.accent,1.5)
local popGrad=Instance.new("UIGradient",popup)
popGrad.Color=ColorSequence.new({
    ColorSequenceKeypoint.new(0,Color3.fromRGB(20,18,34)),
    ColorSequenceKeypoint.new(1,Color3.fromRGB(10,10,18))
}) popGrad.Rotation=135

local popupPlateHolder=Instance.new("Frame",popup)
popupPlateHolder.Name="PlateHolder" popupPlateHolder.Size=UDim2.new(1,-16,0,46)
popupPlateHolder.Position=UDim2.new(0,8,0,8) popupPlateHolder.BackgroundTransparency=1 popupPlateHolder.ZIndex=61

local function popRow(name,icon,color,y)
    local l=makeLabel(popup,icon.." ---",color,Enum.Font.Gotham,nil,Enum.TextXAlignment.Left)
    l.Name=name l.Size=UDim2.new(1,-16,0,22) l.Position=UDim2.new(0,8,0,y) l.ZIndex=61
    return l
end
local popPrice = popRow("PopPrice","💰 Price:",  C.green,  60)
local popMiles = popRow("PopMiles","🛣️ Miles:",  C.blue,   84)
local popScore = popRow("PopScore","⭐ Deal:",   C.gold,  108)
local popOwner = popRow("PopOwner","👤 Owner:",  C.subtext,132)
local popTime  = popRow("PopTime", "🕐 Scanned:",C.subtext,154)
popTime.TextSize=11

local popClose=makeButton(popup,"✕",C.red,C.white,5)
popClose.Size=UDim2.new(0,20,0,20) popClose.Position=UDim2.new(1,-24,0,4) popClose.ZIndex=62
popClose.MouseButton1Click:Connect(function() popup.Visible=false end)

local popupCurrentCar=nil
local function showPopup(data,absPos)
    popupCurrentCar=data
    buildSaudiPlate(popupPlateHolder,data.plate,true)
    local score=dealScore(data.price,data.mile)
    popPrice.Text="💰 Price:   "..(data.price and ("$"..fmt(data.price)) or "---")
    popMiles.Text="🛣️ Miles:   "..(data.mile and fmt(data.mile) or "---")
    if score then popScore.Text="⭐ Deal:    "..score.."/100" popScore.TextColor3=getDealColor(score)
    else popScore.Text="⭐ Deal:    ---" popScore.TextColor3=C.subtext end
    local owner=data.car and data.car:GetAttribute("Owner")
    popOwner.Text="👤 Owner:   "..(owner and owner~="" and owner or T("noOwner"))
    popTime.Text ="🕐 Scanned: "..timeSince(data.timestamp)
    local vp=workspace.CurrentCamera.ViewportSize
    popup.Position=UDim2.new(0,math.clamp(absPos.X+8,4,vp.X-252),0,math.clamp(absPos.Y-80,4,vp.Y-182))
    popup.Visible=true
end

-- ══════════════════════════════════════════
-- MAIN PANEL
-- ══════════════════════════════════════════
local PANEL_W=348
local PANEL_H=620   -- slightly taller for new section
local TITLE_H=50
local BAR_H=30

local main=Instance.new("Frame",screenGui)
main.Name="Main" main.Size=UDim2.new(0,PANEL_W,0,PANEL_H)
main.Position=UDim2.new(0,14,0.5,-PANEL_H/2)
main.BackgroundColor3=C.bg0 main.BackgroundTransparency=0.06 main.BorderSizePixel=0
Instance.new("UICorner",main).CornerRadius=UDim.new(0,18)
makeStroke(main,C.accent,1.5,0.2)
local mainGrad=Instance.new("UIGradient",main)
mainGrad.Color=ColorSequence.new({
    ColorSequenceKeypoint.new(0,Color3.fromRGB(16,14,26)),
    ColorSequenceKeypoint.new(1,Color3.fromRGB(8,8,14))
}) mainGrad.Rotation=140

-- Title bar
local titleBar=Instance.new("Frame",main)
titleBar.Size=UDim2.new(1,0,0,TITLE_H) titleBar.BackgroundColor3=Color3.fromRGB(20,14,36)
titleBar.BackgroundTransparency=0.1 titleBar.BorderSizePixel=0
Instance.new("UICorner",titleBar).CornerRadius=UDim.new(0,18)
local tbFix=Instance.new("Frame",titleBar)
tbFix.Size=UDim2.new(1,0,0.5,0) tbFix.Position=UDim2.new(0,0,0.5,0)
tbFix.BackgroundColor3=Color3.fromRGB(20,14,36) tbFix.BackgroundTransparency=0.1 tbFix.BorderSizePixel=0
local tbGrad=Instance.new("UIGradient",titleBar)
tbGrad.Color=ColorSequence.new({
    ColorSequenceKeypoint.new(0,Color3.fromRGB(255,190,0)),
    ColorSequenceKeypoint.new(0.5,Color3.fromRGB(220,120,0)),
    ColorSequenceKeypoint.new(1,Color3.fromRGB(180,80,0))
}) tbGrad.Rotation=90
tbGrad.Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,0),NumberSequenceKeypoint.new(1,0.3)})

local titleLabel=makeLabel(titleBar,T("title"),C.white,Enum.Font.GothamBold)
titleLabel.Size=UDim2.new(1,-160,1,0) titleLabel.Position=UDim2.new(0,14,0,0)
titleLabel.TextScaled=true titleLabel.ZIndex=2

local function tbBtn(text,bg,x,w)
    local b=makeButton(titleBar,text,bg,C.white,7)
    b.Size=UDim2.new(0,w or 34,0,28) b.Position=UDim2.new(1,x,0.5,-14) b.ZIndex=3
    return b
end
local espToggleBtn = tbBtn("ESP✓",  Color3.fromRGB(0,150,60),  -154,46)
local minBtn       = tbBtn("—",     Color3.fromRGB(50,50,80),  -104,28)
local langBtn      = tbBtn("AR",    Color3.fromRGB(30,30,60),  -72, 32)
local closeBtn2    = tbBtn("✕",     C.red,                     -36, 30)
closeBtn2.MouseButton1Click:Connect(function() screenGui:Destroy() end)

-- Scan + Stop row
local scanRow=Instance.new("Frame",main)
scanRow.Size=UDim2.new(1,-16,0,38) scanRow.Position=UDim2.new(0,8,0,TITLE_H+6)
scanRow.BackgroundTransparency=1 scanRow.BorderSizePixel=0

local scanBtn=makeButton(scanRow,T("scan"),Color3.fromRGB(0,170,60),C.white,10)
scanBtn.Size=UDim2.new(1,-46,1,0) scanBtn.Font=Enum.Font.GothamBold
local scanGrad=Instance.new("UIGradient",scanBtn)
scanGrad.Color=ColorSequence.new({
    ColorSequenceKeypoint.new(0,Color3.fromRGB(0,210,80)),
    ColorSequenceKeypoint.new(1,Color3.fromRGB(0,140,50))
}) scanGrad.Rotation=90
addHover(scanBtn,Color3.fromRGB(0,170,60),Color3.fromRGB(0,200,70))

local stopBtn=makeButton(scanRow,"⏹",Color3.fromRGB(160,40,40),C.white,10)
stopBtn.Size=UDim2.new(0,38,1,0) stopBtn.Position=UDim2.new(1,-38,0,0) stopBtn.Visible=false
addHover(stopBtn,Color3.fromRGB(160,40,40),Color3.fromRGB(200,50,50))
stopBtn.MouseButton1Click:Connect(function() stopRequested=true stopBtn.Text="..." end)

-- Stats bar
local statsBar=glassFrame(main,UDim2.new(1,-16,0,BAR_H),UDim2.new(0,8,0,TITLE_H+50),0.6,8)
makeStroke(statsBar,Color3.fromRGB(60,50,90),1,0.5)
local statsLabel=makeLabel(statsBar,"",C.subtext,Enum.Font.Gotham)
statsLabel.Size=UDim2.new(1,-10,1,0) statsLabel.Position=UDim2.new(0,8,0,0)
statsLabel.TextScaled=true statsLabel.TextXAlignment=Enum.TextXAlignment.Left

local dealBadge=Instance.new("Frame",statsBar)
dealBadge.Size=UDim2.new(0,96,0,22) dealBadge.Position=UDim2.new(1,-100,0.5,-11)
dealBadge.BackgroundColor3=C.gold dealBadge.BackgroundTransparency=0.2
dealBadge.BorderSizePixel=0 dealBadge.Visible=false
Instance.new("UICorner",dealBadge).CornerRadius=UDim.new(0,6)
local dealBadgeLbl=makeLabel(dealBadge,"",Color3.fromRGB(20,15,0),Enum.Font.GothamBold)
dealBadgeLbl.Size=UDim2.new(1,0,1,0) dealBadgeLbl.TextXAlignment=Enum.TextXAlignment.Center dealBadgeLbl.TextScaled=true

-- Sort + Filter row
local sortFilterRow=Instance.new("Frame",main)
sortFilterRow.Size=UDim2.new(1,-16,0,26) sortFilterRow.Position=UDim2.new(0,8,0,TITLE_H+86)
sortFilterRow.BackgroundTransparency=1 sortFilterRow.BorderSizePixel=0

local sortBtn=makeButton(sortFilterRow,"⭐ Sort: Score",Color3.fromRGB(30,20,55),C.accent2,8)
sortBtn.Size=UDim2.new(0.46,-2,1,0) makeStroke(sortBtn,C.accent2,1)
addHover(sortBtn,Color3.fromRGB(30,20,55),Color3.fromRGB(50,35,80))

local filterToggleBtn=makeButton(sortFilterRow,"🔍 Filters ▼",Color3.fromRGB(22,18,44),C.subtext,8)
filterToggleBtn.Size=UDim2.new(0.54,-2,1,0) filterToggleBtn.Position=UDim2.new(0.46,4,0,0)
makeStroke(filterToggleBtn,Color3.fromRGB(80,60,140),1)
addHover(filterToggleBtn,Color3.fromRGB(22,18,44),Color3.fromRGB(34,28,60))

sortBtn.MouseButton1Click:Connect(function()
    if sortMode=="score" then sortMode="name" sortBtn.Text="🔤 Sort: Name"
    elseif sortMode=="name" then sortMode="price" sortBtn.Text="💰 Sort: Price"
    else sortMode="score" sortBtn.Text="⭐ Sort: Score" end
end)

-- Filter panel
local FILTER_PANEL_H=142
local filterPanel=glassFrame(main,UDim2.new(1,-16,0,FILTER_PANEL_H),UDim2.new(0,8,0,TITLE_H+118),0.5,10)
filterPanel.Visible=false makeStroke(filterPanel,Color3.fromRGB(80,60,160),1,0.3)
local fpad=Instance.new("UIPadding",filterPanel)
fpad.PaddingLeft=UDim.new(0,8) fpad.PaddingRight=UDim.new(0,8)
fpad.PaddingTop=UDim.new(0,6) fpad.PaddingBottom=UDim.new(0,6)
local fLayout=Instance.new("UIListLayout",filterPanel) fLayout.Padding=UDim.new(0,5)

local function makeFilterRow(lTxt,ph,def)
    local row=Instance.new("Frame",filterPanel)
    row.Size=UDim2.new(1,0,0,26) row.BackgroundTransparency=1 row.BorderSizePixel=0
    local lbl=makeLabel(row,lTxt,Color3.fromRGB(180,160,255),Enum.Font.Gotham) lbl.Size=UDim2.new(0.55,0,1,0)
    local box=Instance.new("TextBox",row)
    box.Size=UDim2.new(0.43,0,0.85,0) box.Position=UDim2.new(0.57,0,0.075,0)
    box.BackgroundColor3=Color3.fromRGB(18,14,32) box.TextColor3=C.white
    box.PlaceholderText=ph box.PlaceholderColor3=C.subtext
    box.Text=def or "" box.TextScaled=true box.Font=Enum.Font.Gotham
    box.BorderSizePixel=0 box.ClearTextOnFocus=false
    Instance.new("UICorner",box).CornerRadius=UDim.new(0,6) makeStroke(box,Color3.fromRGB(80,60,160),1)
    return box
end

local maxPriceBox=makeFilterRow("Max Price ($)","no limit")
local maxMilesBox=makeFilterRow("Max Miles","no limit")
local dealRow2=Instance.new("Frame",filterPanel)
dealRow2.Size=UDim2.new(1,0,0,26) dealRow2.BackgroundTransparency=1 dealRow2.BorderSizePixel=0
local dlbl=makeLabel(dealRow2,"🔥 Best Deals Only",C.gold,Enum.Font.GothamBold) dlbl.Size=UDim2.new(0.65,0,1,0)
local dealToggle=makeButton(dealRow2,"OFF",Color3.fromRGB(35,30,55),C.white,6)
dealToggle.Size=UDim2.new(0,44,0,22) dealToggle.Position=UDim2.new(1,-44,0.5,-11)
local dsBox=makeFilterRow("Deal Score ≥ (0-100)","70","70") dsBox.TextColor3=C.gold

local filterOpen=false

-- ══════════════════════════════════════════
-- ── NEW PANEL: Plate Alert + Auto-Buy + Auto-Rescan ──
-- ══════════════════════════════════════════
local AUTO_PANEL_H = 148
local autoPanel=glassFrame(main,UDim2.new(1,-16,0,AUTO_PANEL_H),UDim2.new(0,8,0,TITLE_H+118),0.5,10)
autoPanel.Visible=false makeStroke(autoPanel,C.purple,1,0.3)
local apPad=Instance.new("UIPadding",autoPanel)
apPad.PaddingLeft=UDim.new(0,8) apPad.PaddingRight=UDim.new(0,8)
apPad.PaddingTop=UDim.new(0,6) apPad.PaddingBottom=UDim.new(0,6)
local apLayout=Instance.new("UIListLayout",autoPanel) apLayout.Padding=UDim.new(0,5)

local function makeAutoRow(lTxt,ph,def)
    local row=Instance.new("Frame",autoPanel)
    row.Size=UDim2.new(1,0,0,26) row.BackgroundTransparency=1 row.BorderSizePixel=0
    local lbl=makeLabel(row,lTxt,Color3.fromRGB(190,170,255),Enum.Font.Gotham) lbl.Size=UDim2.new(0.55,0,1,0)
    local box=Instance.new("TextBox",row)
    box.Size=UDim2.new(0.43,0,0.85,0) box.Position=UDim2.new(0.57,0,0.075,0)
    box.BackgroundColor3=Color3.fromRGB(18,14,32) box.TextColor3=C.white
    box.PlaceholderText=ph box.PlaceholderColor3=C.subtext
    box.Text=def or "" box.TextScaled=true box.Font=Enum.Font.Gotham
    box.BorderSizePixel=0 box.ClearTextOnFocus=false
    Instance.new("UICorner",box).CornerRadius=UDim.new(0,6) makeStroke(box,C.purple,1)
    return box
end

-- 🔔 Plate alert row
local alertRow=Instance.new("Frame",autoPanel)
alertRow.Size=UDim2.new(1,0,0,26) alertRow.BackgroundTransparency=1 alertRow.BorderSizePixel=0
local alertLbl=makeLabel(alertRow,"🔔 Alert Plate:",C.accent2,Enum.Font.GothamBold)
alertLbl.Size=UDim2.new(0.40,0,1,0)
local alertBox=Instance.new("TextBox",alertRow)
alertBox.Size=UDim2.new(0.58,0,0.85,0) alertBox.Position=UDim2.new(0.42,0,0.075,0)
alertBox.BackgroundColor3=Color3.fromRGB(18,14,32) alertBox.TextColor3=C.accent2
alertBox.PlaceholderText=T("alertPlaceholder") alertBox.PlaceholderColor3=C.subtext
alertBox.Text="" alertBox.TextScaled=true alertBox.Font=Enum.Font.GothamBold
alertBox.BorderSizePixel=0 alertBox.ClearTextOnFocus=false
Instance.new("UICorner",alertBox).CornerRadius=UDim.new(0,6) makeStroke(alertBox,C.accent2,1)
alertBox.FocusLost:Connect(function()
    alertPlate=alertBox.Text:lower():gsub("%s+","")
    alertTriggered={}  -- reset so it can alert again
end)

-- 🎯 Auto-buy row
local autoBuyRow=Instance.new("Frame",autoPanel)
autoBuyRow.Size=UDim2.new(1,0,0,26) autoBuyRow.BackgroundTransparency=1 autoBuyRow.BorderSizePixel=0
local abToggle=makeButton(autoBuyRow,T("autoBuyOff"),Color3.fromRGB(35,20,60),C.white,6)
abToggle.Size=UDim2.new(0.50,-2,1,0) makeStroke(abToggle,C.purple,1)
addHover(abToggle,Color3.fromRGB(35,20,60),Color3.fromRGB(60,30,100))
local abScoreBox=Instance.new("TextBox",autoBuyRow)
abScoreBox.Size=UDim2.new(0.20,-2,0.85,0) abScoreBox.Position=UDim2.new(0.52,2,0.075,0)
abScoreBox.BackgroundColor3=Color3.fromRGB(18,14,32) abScoreBox.TextColor3=C.purple
abScoreBox.Text="80" abScoreBox.PlaceholderText="score" abScoreBox.TextScaled=true
abScoreBox.Font=Enum.Font.Gotham abScoreBox.BorderSizePixel=0 abScoreBox.ClearTextOnFocus=false
Instance.new("UICorner",abScoreBox).CornerRadius=UDim.new(0,6) makeStroke(abScoreBox,C.purple,1)
local abLabel=makeLabel(autoBuyRow,"Min score",Color3.fromRGB(150,130,200),Enum.Font.Gotham)
abLabel.Size=UDim2.new(0.28,-2,1,0) abLabel.Position=UDim2.new(0.72,4,0,0) abLabel.TextScaled=true
abToggle.MouseButton1Click:Connect(function()
    autoBuyEnabled=not autoBuyEnabled
    abToggle.Text=autoBuyEnabled and T("autoBuyOn") or T("autoBuyOff")
    abToggle.BackgroundColor3=autoBuyEnabled and Color3.fromRGB(80,0,150) or Color3.fromRGB(35,20,60)
end)
abScoreBox.FocusLost:Connect(function()
    autoBuyThreshold=math.clamp(tonumber(abScoreBox.Text) or 80,0,100)
end)

-- ⏰ Auto-rescan row
local arRow=Instance.new("Frame",autoPanel)
arRow.Size=UDim2.new(1,0,0,26) arRow.BackgroundTransparency=1 arRow.BorderSizePixel=0
local arToggle=makeButton(arRow,T("autoRescanOff"),Color3.fromRGB(20,20,50),C.white,6)
arToggle.Size=UDim2.new(0.50,-2,1,0) makeStroke(arToggle,C.blue,1)
addHover(arToggle,Color3.fromRGB(20,20,50),Color3.fromRGB(30,40,90))
local arMinsBox=Instance.new("TextBox",arRow)
arMinsBox.Size=UDim2.new(0.18,-2,0.85,0) arMinsBox.Position=UDim2.new(0.52,2,0.075,0)
arMinsBox.BackgroundColor3=Color3.fromRGB(18,14,32) arMinsBox.TextColor3=C.blue
arMinsBox.Text="5" arMinsBox.PlaceholderText="mins" arMinsBox.TextScaled=true
arMinsBox.Font=Enum.Font.Gotham arMinsBox.BorderSizePixel=0 arMinsBox.ClearTextOnFocus=false
Instance.new("UICorner",arMinsBox).CornerRadius=UDim.new(0,6) makeStroke(arMinsBox,C.blue,1)
local arLabel=makeLabel(arRow,"min interval",Color3.fromRGB(120,160,200),Enum.Font.Gotham)
arLabel.Size=UDim2.new(0.30,-2,1,0) arLabel.Position=UDim2.new(0.70,4,0,0) arLabel.TextScaled=true
arToggle.MouseButton1Click:Connect(function()
    autoRescanEnabled=not autoRescanEnabled
    autoRescanTimer=0  -- reset countdown
    arToggle.Text=autoRescanEnabled and T("autoRescanOn") or T("autoRescanOff")
    arToggle.BackgroundColor3=autoRescanEnabled and Color3.fromRGB(20,60,120) or Color3.fromRGB(20,20,50)
end)
arMinsBox.FocusLost:Connect(function()
    autoRescanMins=math.max(1,tonumber(arMinsBox.Text) or 5)
    autoRescanTimer=0
end)

-- Auto panel countdown label
local arCountdown=makeLabel(autoPanel,"",C.subtext,Enum.Font.Gotham)
arCountdown.Size=UDim2.new(1,0,0,20) arCountdown.TextScaled=true arCountdown.TextXAlignment=Enum.TextXAlignment.Center

-- Auto panel toggle button (next to filters)
local autoPanelToggleBtn=makeButton(main,"⚙ AUTO ▼",Color3.fromRGB(50,20,80),C.accent2,8)
autoPanelToggleBtn.Size=UDim2.new(1,-16,0,24)
autoPanelToggleBtn.Position=UDim2.new(0,8,0,TITLE_H+118+FILTER_PANEL_H+8)  -- will be repositioned
makeStroke(autoPanelToggleBtn,C.purple,1)
addHover(autoPanelToggleBtn,Color3.fromRGB(50,20,80),Color3.fromRGB(70,30,110))

local autoPanelOpen=false

-- Layout rebuild
local function rebuildLayout()
    local fy=TITLE_H+118
    local filterExtraH=filterOpen and (FILTER_PANEL_H+4) or 0
    local autoToggleY=fy+28+filterExtraH
    autoPanelToggleBtn.Position=UDim2.new(0,8,0,autoToggleY)
    autoPanel.Position=UDim2.new(0,8,0,autoToggleY+28)
    local autoExtraH=autoPanelOpen and (AUTO_PANEL_H+4) or 0
    local headerY=autoToggleY+28+autoExtraH
    local scrollY=headerY+24
    if main:FindFirstChild("HeaderFrame") then
        main.HeaderFrame.Position=UDim2.new(0,8,0,headerY)
    end
    if main:FindFirstChild("Scroll") then
        main.Scroll.Position=UDim2.new(0,8,0,scrollY)
        main.Scroll.Size=UDim2.new(1,-16,0,PANEL_H-scrollY-8)
    end
end

filterToggleBtn.MouseButton1Click:Connect(function()
    filterOpen=not filterOpen filterPanel.Visible=filterOpen
    filterToggleBtn.Text=filterOpen and "🔍 Filters ▲" or "🔍 Filters ▼"
    rebuildLayout()
end)
autoPanelToggleBtn.MouseButton1Click:Connect(function()
    autoPanelOpen=not autoPanelOpen autoPanel.Visible=autoPanelOpen
    autoPanelToggleBtn.Text=autoPanelOpen and "⚙ AUTO ▲" or "⚙ AUTO ▼"
    rebuildLayout()
end)
dealToggle.MouseButton1Click:Connect(function()
    filters.dealOnly=not filters.dealOnly
    dealToggle.Text=filters.dealOnly and "ON" or "OFF"
    dealToggle.BackgroundColor3=filters.dealOnly and Color3.fromRGB(180,120,0) or Color3.fromRGB(35,30,55)
end)
maxPriceBox.FocusLost:Connect(function() filters.maxPrice=tonumber(maxPriceBox.Text:gsub("[^%d]","")) or nil end)
maxMilesBox.FocusLost:Connect(function() filters.maxMiles=tonumber(maxMilesBox.Text:gsub("[^%d]","")) or nil end)
dsBox.FocusLost:Connect(function() local v=tonumber(dsBox.Text) if v then filters.dealThreshold=math.clamp(v,0,100) end end)

-- Column headers
local headerFrame=glassFrame(main,UDim2.new(1,-16,0,22),UDim2.new(0,8,0,0),0.7,6)
headerFrame.Name="HeaderFrame" makeStroke(headerFrame,C.accent,1,0.6)
local function hdr(name,txt,col,xa,szx,posx)
    local l=makeLabel(headerFrame,txt,col,Enum.Font.GothamBold)
    l.Name=name l.Size=UDim2.new(szx,0,1,0) l.Position=UDim2.new(posx,4,0,0)
    l.TextXAlignment=xa or Enum.TextXAlignment.Left l.TextScaled=true return l
end
hdr("HPlate",T("plate"),C.accent,nil,0.50,0)
hdr("HStar","⭐",C.gold,Enum.TextXAlignment.Center,0.14,0.50)
hdr("HInfo","👁",C.accent2,Enum.TextXAlignment.Center,0.16,0.64)
hdr("HTP","🚀",C.blue,Enum.TextXAlignment.Center,0.20,0.80)

-- Scroll
local scroll=Instance.new("ScrollingFrame",main)
scroll.Name="Scroll" scroll.BackgroundTransparency=1 scroll.BorderSizePixel=0
scroll.ScrollBarThickness=4 scroll.ScrollBarImageColor3=C.accent
scroll.CanvasSize=UDim2.new(0,0,0,0) scroll.AutomaticCanvasSize=Enum.AutomaticSize.Y
scroll.ScrollingDirection=Enum.ScrollingDirection.Y scroll.ElasticBehavior=Enum.ElasticBehavior.Always
local listLayout=Instance.new("UIListLayout",scroll)
listLayout.SortOrder=Enum.SortOrder.LayoutOrder listLayout.Padding=UDim.new(0,4)
local scrollPad=Instance.new("UIPadding",scroll)
scrollPad.PaddingTop=UDim.new(0,2) scrollPad.PaddingBottom=UDim.new(0,8)

rebuildLayout()

-- Minimize
local minimizedH=TITLE_H+4
minBtn.MouseButton1Click:Connect(function()
    minimized=not minimized minBtn.Text=minimized and "□" or "—"
    main.Size=UDim2.new(0,PANEL_W,0,minimized and minimizedH or PANEL_H)
    for _,n in ipairs({"Scroll","HeaderFrame"}) do local f=main:FindFirstChild(n) if f then f.Visible=not minimized end end
    scanRow.Visible=not minimized statsBar.Visible=not minimized
    sortFilterRow.Visible=not minimized filterPanel.Visible=not minimized and filterOpen
    autoPanelToggleBtn.Visible=not minimized autoPanel.Visible=not minimized and autoPanelOpen
end)

-- Drag
local dragging,dragStart,startPos
titleBar.InputBegan:Connect(function(i)
    if i.UserInputType==Enum.UserInputType.MouseButton1 then dragging=true dragStart=i.Position startPos=main.Position end
end)
titleBar.InputEnded:Connect(function(i)
    if i.UserInputType==Enum.UserInputType.MouseButton1 then dragging=false end
end)
UserInputService.InputChanged:Connect(function(i)
    if dragging and i.UserInputType==Enum.UserInputType.MouseMovement then
        local d=i.Position-dragStart
        main.Position=UDim2.new(startPos.X.Scale,startPos.X.Offset+d.X,startPos.Y.Scale,startPos.Y.Offset+d.Y)
    end
end)

-- ══════════════════════════════════════════
-- CAR DATA
-- ══════════════════════════════════════════
carData = {}  -- define here so auto-buy closure can see it

local function getPlate(car)
    for _,plateName in ipairs({"Plate1","Plate2"}) do
        local plate=car:FindFirstChild(plateName,true)
        if plate then
            local sq=plate:FindFirstChild("Square_Plate",true)
            if sq then
                local lt=sq:FindFirstChild("LowerText") local ln=sq:FindFirstChild("LowerNumber")
                local ut=sq:FindFirstChild("UpperText")
                local letters=lt and lt.Text or "" local numbers=ln and tostring(ln.Text) or ""
                local arabic=ut and ut.Text or ""
                if letters~="" or numbers~="" then return {en=letters.." "..numbers,ar=arabic.." "..numbers} end
            end
        end
    end
    return {en="??? 000",ar="؟؟؟ 000"}
end

local function teleportToCar(car)
    local char=lp.Character if not char then return end
    local hrp=char:FindFirstChild("HumanoidRootPart") if not hrp then return end
    local root=car.PrimaryPart or car:FindFirstChildWhichIsA("BasePart") if not root then return end
    local ok=pcall(function() hrp.CFrame=root.CFrame*CFrame.new(0,0,5) end)
    if not ok then local hum=char:FindFirstChildOfClass("Humanoid") if hum then hum:MoveTo(root.Position+Vector3.new(0,0,5)) end end
end

-- Best deal banner
local bestDealBanner=Instance.new("Frame",scroll)
bestDealBanner.Name="BestDealBanner" bestDealBanner.Size=UDim2.new(1,0,0,50)
bestDealBanner.BackgroundColor3=Color3.fromRGB(40,30,0) bestDealBanner.BorderSizePixel=0
bestDealBanner.LayoutOrder=0 bestDealBanner.Visible=false
Instance.new("UICorner",bestDealBanner).CornerRadius=UDim.new(0,10) makeStroke(bestDealBanner,C.gold,2)
local bannerGrad=Instance.new("UIGradient",bestDealBanner)
bannerGrad.Color=ColorSequence.new({ColorSequenceKeypoint.new(0,Color3.fromRGB(60,44,0)),ColorSequenceKeypoint.new(1,Color3.fromRGB(30,22,0))}) bannerGrad.Rotation=90

local bannerPlateHolder=Instance.new("Frame",bestDealBanner)
bannerPlateHolder.Size=UDim2.new(0.50,-6,0,36) bannerPlateHolder.Position=UDim2.new(0,4,0.5,-18)
bannerPlateHolder.BackgroundTransparency=1 bannerPlateHolder.BorderSizePixel=0

local bannerLabel=makeLabel(bestDealBanner,"🏆 BEST DEAL",C.gold,Enum.Font.GothamBold)
bannerLabel.Size=UDim2.new(0.30,0,0.5,0) bannerLabel.Position=UDim2.new(0.51,0,0,2) bannerLabel.TextScaled=true
local bannerScore=makeLabel(bestDealBanner,"",C.gold,Enum.Font.GothamBold)
bannerScore.Size=UDim2.new(0.30,0,0.5,0) bannerScore.Position=UDim2.new(0.51,0,0.5,-2) bannerScore.TextScaled=true
local bannerTP=makeButton(bestDealBanner,"🚀",Color3.fromRGB(30,100,200),C.white,7)
bannerTP.Size=UDim2.new(0.17,-4,0.72,0) bannerTP.Position=UDim2.new(0.83,2,0.14,0)
local bestDealCarName=nil
bannerTP.MouseButton1Click:Connect(function()
    if bestDealCarName and carData[bestDealCarName] and carData[bestDealCarName].car then
        teleportToCar(carData[bestDealCarName].car)
        bannerTP.BackgroundColor3=C.green
        task.delay(0.6,function() if bannerTP and bannerTP.Parent then bannerTP.BackgroundColor3=Color3.fromRGB(30,100,200) end end)
    end
end)

local function makeEntry(name,plateData)
    if scroll:FindFirstChild(name) then return scroll:FindFirstChild(name) end
    local entry=glassFrame(scroll,UDim2.new(1,0,0,46),UDim2.new(0,0,0,0),0.55,9)
    entry.Name=name entry.LayoutOrder=9999
    local es=makeStroke(entry,Color3.fromRGB(50,44,70),1,0.3) es.Name="EntryStroke"

    local pc=Instance.new("Frame",entry) pc.Name="PlateContainer"
    pc.Size=UDim2.new(0.50,-6,0,34) pc.Position=UDim2.new(0,4,0.5,-17)
    pc.BackgroundTransparency=1 pc.BorderSizePixel=0
    buildSaudiPlate(pc,plateData,false)

    local plateBtn=makeButton(entry,"",Color3.fromRGB(0,0,0),C.white,4)
    plateBtn.BackgroundTransparency=1 plateBtn.Size=UDim2.new(0.50,-6,0,34)
    plateBtn.Position=UDim2.new(0,4,0.5,-17) plateBtn.ZIndex=5
    local copyLabel=makeLabel(entry,"",C.green,Enum.Font.GothamBold)
    copyLabel.Size=UDim2.new(0.50,-6,0,34) copyLabel.Position=UDim2.new(0,4,0.5,-17)
    copyLabel.TextXAlignment=Enum.TextXAlignment.Center copyLabel.TextScaled=true
    copyLabel.ZIndex=6 copyLabel.Visible=false

    local carName=name
    plateBtn.MouseButton1Click:Connect(function()
        local d=carData[carName] if not d or not d.plate then return end
        pcall(function() setclipboard(d.plate.en) end)
        copyLabel.Text=T("copied") copyLabel.Visible=true
        task.delay(1.2,function() if copyLabel and copyLabel.Parent then copyLabel.Visible=false end end)
    end)

    local db=makeLabel(entry,"-",C.gold,Enum.Font.GothamBold) db.Name="Deal"
    db.Size=UDim2.new(0.14,-2,0.65,0) db.Position=UDim2.new(0.51,2,0.175,0)
    db.TextXAlignment=Enum.TextXAlignment.Center db.TextScaled=true

    local infoBtn=makeButton(entry,"👁",Color3.fromRGB(50,35,90),C.white,7) infoBtn.Name="InfoBtn"
    infoBtn.Size=UDim2.new(0.16,-4,0.72,0) infoBtn.Position=UDim2.new(0.65,2,0.14,0)
    makeStroke(infoBtn,C.accent2,1) addHover(infoBtn,Color3.fromRGB(50,35,90),Color3.fromRGB(80,55,130))
    infoBtn.MouseButton1Click:Connect(function()
        local data=carData[carName] if not data then return end
        if popup.Visible and popupCurrentCar==data then popup.Visible=false return end
        showPopup(data,infoBtn.AbsolutePosition)
    end)

    local tpBtn=makeButton(entry,"🚀",Color3.fromRGB(25,90,190),C.white,7) tpBtn.Name="TPBtn"
    tpBtn.Size=UDim2.new(0.19,-4,0.72,0) tpBtn.Position=UDim2.new(0.81,2,0.14,0)
    makeStroke(tpBtn,C.blue,1) addHover(tpBtn,Color3.fromRGB(25,90,190),Color3.fromRGB(40,120,220))
    tpBtn.MouseButton1Click:Connect(function()
        local data=carData[carName]
        if data and data.car and data.car.Parent then
            teleportToCar(data.car)
            tpBtn.BackgroundColor3=C.green
            task.delay(0.6,function() if tpBtn and tpBtn.Parent then tpBtn.BackgroundColor3=Color3.fromRGB(25,90,190) end end)
        end
    end)
    return entry
end

-- Billboard
local function makeBillboard(car,plateData)
    local root=car.PrimaryPart or car:FindFirstChildWhichIsA("BasePart") if not root then return end
    local existing=root:FindFirstChild("ESP_Tag") if existing then existing:Destroy() end
    local bb=Instance.new("BillboardGui") bb.Name="ESP_Tag" bb.Adornee=root
    bb.Size=UDim2.new(0,290,0,136) bb.StudsOffset=Vector3.new(0,5,0)
    bb.AlwaysOnTop=true bb.MaxDistance=200 bb.Enabled=espEnabled bb.Parent=root
    local f=glassFrame(bb,UDim2.new(1,0,1,0),UDim2.new(0,0,0,0),0.12,10)
    f.BackgroundColor3=C.bg0
    local bs=makeStroke(f,C.accent,2) bs.Name="BillStroke"
    local ph=Instance.new("Frame",f) ph.Name="PlateHolder"
    ph.Size=UDim2.new(1,-8,0,48) ph.Position=UDim2.new(0,4,0,4)
    ph.BackgroundTransparency=1 ph.BorderSizePixel=0
    buildSaudiPlate(ph,plateData,true)
    local p=makeLabel(f,"💰 ---",C.green,Enum.Font.GothamBold) p.Name="P"
    p.Size=UDim2.new(0.5,-4,0,26) p.Position=UDim2.new(0,4,0,56) p.TextScaled=true
    local m=makeLabel(f,"🛣️ ---",C.blue,Enum.Font.Gotham) m.Name="M"
    m.Size=UDim2.new(0.5,-4,0,26) m.Position=UDim2.new(0.5,0,0,56) m.TextScaled=true
    local dl=makeLabel(f,"",C.gold,Enum.Font.GothamBold) dl.Name="DealL"
    dl.Size=UDim2.new(1,-8,0,22) dl.Position=UDim2.new(0,4,0,84) dl.TextScaled=true
    local o=makeLabel(f,"",C.subtext,Enum.Font.Gotham) o.Name="O"
    o.Size=UDim2.new(1,-8,0,20) o.Position=UDim2.new(0,4,0,108) o.TextScaled=true
    local owner=car:GetAttribute("Owner")
    o.Text="👤 "..(owner and owner~="" and owner or T("noOwner"))
end

-- ══════════════════════════════════════════
-- READ SALE UI
-- ══════════════════════════════════════════
local function readSaleData()
    local price,mile=nil,nil
    for _,gui in ipairs(playerGui:GetChildren()) do
        if gui:IsA("ScreenGui") and gui.Enabled and gui.Name~="CarESP_GUI" then
            for _,lbl in ipairs(gui:GetDescendants()) do
                if lbl:IsA("TextLabel") then
                    local n=lbl.Name:lower()
                    if not price and (n:find("price") or n:find("sell") or n:find("value")) then
                        local t=lbl.Text:gsub("[^%d]","") if t~="" and #t>=3 then price=t end
                    end
                    if not mile and (n:find("mile") or n:find("odometer") or n:find("km")) then
                        local t=lbl.Text:gsub("[^%d]","") if t~="" then mile=t end
                    end
                end
            end
        end
    end
    local saleUI=playerGui:FindFirstChild("SaleUI")
    if saleUI and saleUI.Enabled and not mile then
        local ml=saleUI:FindFirstChild("Mileage",true)
        if ml and ml:IsA("TextLabel") then local t=ml.Text:gsub("[^%d]","") if t~="" then mile=t end end
    end
    local saleUI2=playerGui:FindFirstChild("SaleUI2")
    if saleUI2 and saleUI2.Enabled then
        if not price then local sp=saleUI2:FindFirstChild("SellPrice",true)
            if sp and sp:IsA("TextLabel") then local t=sp.Text:gsub("[^%d]","") if t~="" then price=t end end end
        if not mile then local ml2=saleUI2:FindFirstChild("Mileage",true)
            if ml2 and ml2:IsA("TextLabel") then local t=ml2.Text:gsub("[^%d]","") if t~="" then mile=t end end end
    end
    return price,mile
end

-- ══════════════════════════════════════════
-- SETUP CARS
-- ══════════════════════════════════════════
local slots=workspace:WaitForChild("Slots",10)
local slotList={}
if slots then
    for _,slot in ipairs(slots:GetChildren()) do
        table.insert(slotList,slot)
        for _,car in ipairs(slot:GetChildren()) do
            if car:IsA("Model") and car.Name:match("Car$") then
                local pd=getPlate(car)
                local saved=persistedData[car.Name]
                makeBillboard(car,pd)
                makeEntry(car.Name,pd)
                carData[car.Name]={car=car,price=saved and saved.price,mile=saved and saved.mile,plate=pd,slot=slot,timestamp=saved and saved.timestamp}
            end
        end
        slot.ChildAdded:Connect(function(car)
            task.wait(0.5)
            if car:IsA("Model") and car.Name:match("Car$") then
                local pd=getPlate(car) local saved=persistedData[car.Name]
                makeBillboard(car,pd) makeEntry(car.Name,pd)
                carData[car.Name]={car=car,price=saved and saved.price,mile=saved and saved.mile,plate=pd,slot=slot,timestamp=saved and saved.timestamp}
            end
        end)
    end
end

local function applyEspVisibility()
    for _,data in pairs(carData) do
        local car=data.car if car and car.Parent then
            local root=car.PrimaryPart or car:FindFirstChildWhichIsA("BasePart")
            if root then local tag=root:FindFirstChild("ESP_Tag") if tag then tag.Enabled=espEnabled end end
        end
    end
end
espToggleBtn.MouseButton1Click:Connect(function()
    espEnabled=not espEnabled
    espToggleBtn.Text=espEnabled and "ESP✓" or "ESP✗"
    espToggleBtn.BackgroundColor3=espEnabled and Color3.fromRGB(0,150,60) or Color3.fromRGB(120,30,30)
    applyEspVisibility()
end)

local function updateLanguage()
    titleLabel.Text=T("title") scanBtn.Text=T("scan") langBtn.Text=lang=="EN" and "AR" or "EN"
    alertBox.PlaceholderText=T("alertPlaceholder")
    for name,data in pairs(carData) do
        if data.plate then
            local entry=scroll:FindFirstChild(name)
            if entry then local pc=entry:FindFirstChild("PlateContainer") if pc then buildSaudiPlate(pc,data.plate,false) end end
            local car=data.car if car and car.Parent then
                local root=car.PrimaryPart or car:FindFirstChildWhichIsA("BasePart")
                if root then local tag=root:FindFirstChild("ESP_Tag") if tag then local ph=tag:FindFirstChild("PlateHolder",true) if ph then buildSaudiPlate(ph,data.plate,true) end end end
            end
        end
    end
end
langBtn.MouseButton1Click:Connect(function() lang=lang=="EN" and "AR" or "EN" updateLanguage() end)

local function getClosestCar()
    local char=lp.Character if not char or not char:FindFirstChild("HumanoidRootPart") then return nil end
    local hrp=char.HumanoidRootPart
    local closest,closestDist=nil,25
    for name,data in pairs(carData) do
        local car=data.car if car and car.Parent then
            local root=car.PrimaryPart or car:FindFirstChildWhichIsA("BasePart")
            if root then local dist=(hrp.Position-root.Position).Magnitude if dist<closestDist then closestDist=dist closest=name end end
        end
    end
    return closest
end

-- ══════════════════════════════════════════
-- SCAN LOGIC (shared between manual + auto-rescan)
-- ══════════════════════════════════════════
local function closeAllSaleUIs()
    for _,uiName in ipairs({"SaleUI","SaleUI2"}) do
        local ui=playerGui:FindFirstChild(uiName)
        if ui and ui.Enabled then
            local cb=ui:FindFirstChild("Cancel",true) or ui:FindFirstChild("Close",true) or ui:FindFirstChild("Back",true)
            if cb and cb:IsA("TextButton") then cb.MouseButton1Click:Fire() end
        end
    end
    for _,gui in ipairs(playerGui:GetChildren()) do
        if gui:IsA("ScreenGui") and gui.Enabled and gui.Name~="CarESP_GUI" then
            local cb=gui:FindFirstChild("Cancel",true) or gui:FindFirstChild("Close",true)
                   or gui:FindFirstChild("Back",true) or gui:FindFirstChild("CloseButton",true)
            if cb and cb:IsA("TextButton") then pcall(function() cb.MouseButton1Click:Fire() end) end
        end
    end
end

local function runScan(isAutoRescan)
    if scanning then return end
    scanning=true stopRequested=false
    scanBtn.BackgroundColor3=Color3.fromRGB(120,80,0)
    scanBtn.Text= isAutoRescan and "⏰ Auto-scanning..." or "⏳ Scanning..."
    stopBtn.Visible=true stopBtn.Text="⏹"

    local char=lp.Character
    local hrp=char and char:FindFirstChild("HumanoidRootPart")
    if not hrp then scanning=false stopBtn.Visible=false return end

    local origPos=hrp.CFrame
    local scanned,total=0,0

    for _,slot in ipairs(slotList) do
        if stopRequested then break end
        local npcSlot=slot:FindFirstChild("NpcSlot") if not npcSlot then continue end
        local prompt=npcSlot:FindFirstChild("Interaction")
        if not prompt or not prompt:IsA("ProximityPrompt") then continue end
        local car=nil
        for _,obj in ipairs(slot:GetChildren()) do
            if obj:IsA("Model") and obj.Name:match("Car$") then car=obj break end
        end
        if not car then continue end
        total=total+1

        local pText=carData[car.Name] and carData[car.Name].plate and carData[car.Name].plate.en or car.Name
        local entry=scroll:FindFirstChild(car.Name)
        if entry then
            entry.BackgroundColor3=Color3.fromRGB(30,22,5)
            local es=entry:FindFirstChild("EntryStroke") if es then es.Color=C.accent end
        end

        local teleportCFrame=nil
        local npcObject=npcSlot:FindFirstChild("ObjectValue")
        if npcObject and npcObject.Value then
            local npcModel=npcObject.Value
            local npcRoot=npcModel:FindFirstChild("HumanoidRootPart") or npcModel:FindFirstChildWhichIsA("BasePart")
            if npcRoot then teleportCFrame=npcRoot.CFrame*CFrame.new(0,0,3.5) end
        end
        if not teleportCFrame then
            local root=car.PrimaryPart or car:FindFirstChildWhichIsA("BasePart")
            if root then teleportCFrame=root.CFrame*CFrame.new(4,0,0) end
        end
        if teleportCFrame then pcall(function() hrp.CFrame=teleportCFrame end) end
        task.wait(0.8)
        pcall(function() fireproximityprompt(prompt) end)

        local price,mile=nil,nil local waited=0 local SCAN_WAIT=11
        repeat
            task.wait(0.3) waited=waited+0.3 price,mile=readSaleData()
            statsLabel.Text=T("scanning").." "..pText.." ⏱"..math.ceil(SCAN_WAIT-waited).."s"
        until (price and mile) or waited>=SCAN_WAIT or stopRequested

        if price or mile then
            scanned=scanned+1
            if price then carData[car.Name].price=price persistedData[car.Name]=persistedData[car.Name] or {} persistedData[car.Name].price=price end
            if mile  then carData[car.Name].mile=mile   persistedData[car.Name]=persistedData[car.Name] or {} persistedData[car.Name].mile=mile end
            carData[car.Name].timestamp=os.clock()
            if persistedData[car.Name] then persistedData[car.Name].timestamp=os.clock() end
            if entry then
                entry.BackgroundColor3=Color3.fromRGB(6,20,8)
                local es=entry:FindFirstChild("EntryStroke") if es then es.Color=C.green es.Thickness=1.5 end
            end
            -- 🔔 Plate alert check
            checkPlateAlert(car.Name,carData[car.Name])
            -- 🎯 Auto-buy check
            if autoBuyEnabled then task.spawn(function() tryAutoBuy(car,slot) end) end
        else
            if entry then
                entry.BackgroundColor3=Color3.fromRGB(22,6,6)
                local es=entry:FindFirstChild("EntryStroke") if es then es.Color=C.red end
            end
        end
        closeAllSaleUIs()
        task.wait(0.5)
    end

    pcall(function() hrp.CFrame=origPos end)
    scanning=false stopRequested=false stopBtn.Visible=false
    scanGrad.Color=ColorSequence.new({
        ColorSequenceKeypoint.new(0,Color3.fromRGB(0,210,80)),
        ColorSequenceKeypoint.new(1,Color3.fromRGB(0,140,50))
    })
    scanBtn.BackgroundColor3=Color3.fromRGB(0,170,60)
    scanBtn.Text=T("rescan")

    local dealCount=0 local bestScore,bestName=0,nil
    for name,data in pairs(carData) do
        local sc=dealScore(data.price,data.mile)
        if sc and sc>=filters.dealThreshold then dealCount=dealCount+1 end
        if sc and sc>bestScore then bestScore=sc bestName=name end
    end
    statsLabel.Text=T("done").." "..scanned.."/"..total.." "..T("scanned")
    if dealCount>0 then
        dealBadge.Visible=true
        dealBadgeLbl.Text="🔥 "..dealCount.." "..T("dealFound")
        if bestScore>=80 then playDealAlert() end
    end
    if bestName and bestScore>0 then
        bestDealCarName=bestName
        buildSaudiPlate(bannerPlateHolder,carData[bestName].plate,false)
        bannerScore.Text="Score: "..bestScore.."/100"
        bannerScore.TextColor3=getDealColor(bestScore)
        bestDealBanner.Visible=true
    end
    -- Reset auto-rescan timer
    autoRescanTimer=0
end

scanBtn.MouseButton1Click:Connect(function() runScan(false) end)

-- ══════════════════════════════════════════
-- HEARTBEAT
-- ══════════════════════════════════════════
local hbDelta=0
RunService.Heartbeat:Connect(function(dt)
    -- Auto-rescan timer
    if autoRescanEnabled and not scanning then
        autoRescanTimer=autoRescanTimer+dt
        local totalSecs=autoRescanMins*60
        local remaining=math.max(0,math.ceil(totalSecs-autoRescanTimer))
        local mins=math.floor(remaining/60)
        local secs=remaining%60
        arCountdown.Text=T("nextRescan").." "..string.format("%d:%02d",mins,secs)
        if autoRescanTimer>=totalSecs then
            autoRescanTimer=0
            task.spawn(function() runScan(true) end)
        end
    else
        if not autoRescanEnabled then arCountdown.Text="" end
    end

    -- Passive data grab
    local price,mile=readSaleData()
    if price or mile then
        local closest=getClosestCar()
        if closest and carData[closest] then
            if price then carData[closest].price=price persistedData[closest]=persistedData[closest] or {} persistedData[closest].price=price end
            if mile  then carData[closest].mile=mile   persistedData[closest]=persistedData[closest] or {} persistedData[closest].mile=mile end
            if not carData[closest].timestamp then
                carData[closest].timestamp=os.clock()
                if persistedData[closest] then persistedData[closest].timestamp=os.clock() end
            end
            checkPlateAlert(closest,carData[closest])
        end
    end

    local count,scannedCount=0,0
    for name,data in pairs(carData) do
        count=count+1 if data.price then scannedCount=scannedCount+1 end

        if data.car and data.car.Parent then
            local newPlate=getPlate(data.car)
            if newPlate.en~=(data.plate and data.plate.en) then
                data.plate=newPlate
                local entry=scroll:FindFirstChild(name)
                if entry then local pc=entry:FindFirstChild("PlateContainer") if pc then buildSaudiPlate(pc,newPlate,false) end end
                local root=data.car.PrimaryPart or data.car:FindFirstChildWhichIsA("BasePart")
                if root then local tag=root:FindFirstChild("ESP_Tag") if tag then local ph=tag:FindFirstChild("PlateHolder",true) if ph then buildSaudiPlate(ph,newPlate,true) end end end
            end
        end

        local score=dealScore(data.price,data.mile)
        local isDeal=score and score>=filters.dealThreshold
        local visible=passesFilter(data)
        local order
        if sortMode=="score" then order=score and (1000-score) or 2000
        elseif sortMode=="name" then
            local en=data.plate and data.plate.en or "zzz" order=0
            for i=1,math.min(#en,4) do order=order+string.byte(en,i)*(256^(4-i)) end
        elseif sortMode=="price" then
            local p=tonumber(tostring(data.price or ""):gsub("[^%d]","")) or 0 order=10000000-p
        end

        local entry=scroll:FindFirstChild(name)
        if entry then
            entry.Visible=visible entry.LayoutOrder=(order or 2000)+1
            local dL=entry:FindFirstChild("Deal") local es=entry:FindFirstChild("EntryStroke")
            if dL then
                if score then dL.Text=tostring(score) dL.TextColor3=getDealColor(score)
                else dL.Text="-" dL.TextColor3=C.subtext end
            end
            if not scanning and es then
                if isDeal and score>=85 then es.Color=C.gold es.Thickness=2 entry.BackgroundColor3=Color3.fromRGB(28,20,4)
                elseif isDeal then es.Color=C.green es.Thickness=1.5 entry.BackgroundColor3=Color3.fromRGB(6,20,8) end
            end
        end

        local car=data.car
        if car and car.Parent then
            local root=car.PrimaryPart or car:FindFirstChildWhichIsA("BasePart")
            if root then
                local tag=root:FindFirstChild("ESP_Tag")
                if tag then
                    tag.Enabled=espEnabled
                    local p=tag:FindFirstChild("P",true) local m=tag:FindFirstChild("M",true)
                    local o=tag:FindFirstChild("O",true) local dl=tag:FindFirstChild("DealL",true)
                    local bs=tag:FindFirstChild("BillStroke",true)
                    if p then p.Text=data.price and ("💰$"..fmt(data.price)) or "💰---" end
                    if m then m.Text=data.mile  and ("🛣️"..fmt(data.mile))  or "🛣️---" end
                    if o then local owner=car:GetAttribute("Owner") o.Text="👤 "..(owner and owner~="" and owner or T("noOwner")) end
                    if dl then
                        if score then dl.Text=(score>=85 and "🔥 DEAL " or score>=70 and "⭐ " or "").."Score: "..score.."/100" dl.TextColor3=getDealColor(score)
                        else dl.Text="" end
                    end
                    if bs then
                        if isDeal and score>=85 then bs.Color=C.gold bs.Thickness=2.5
                        elseif isDeal then bs.Color=C.green bs.Thickness=2
                        else bs.Color=C.accent bs.Thickness=1.5 end
                    end
                end
            end
        end
    end

    if popup.Visible and popupCurrentCar then
        local d=popupCurrentCar local score=dealScore(d.price,d.mile)
        popPrice.Text="💰 Price:   "..(d.price and ("$"..fmt(d.price)) or "---")
        popMiles.Text="🛣️ Miles:   "..(d.mile and fmt(d.mile) or "---")
        if score then popScore.Text="⭐ Deal:    "..score.."/100" popScore.TextColor3=getDealColor(score)
        else popScore.Text="⭐ Deal:    ---" popScore.TextColor3=C.subtext end
        local owner=d.car and d.car:GetAttribute("Owner")
        popOwner.Text="👤 Owner:   "..(owner and owner~="" and owner or T("noOwner"))
        popTime.Text ="🕐 Scanned: "..timeSince(d.timestamp)
    end

    if not scanning then
        statsLabel.Text="🚗 "..count.." "..T("cars").." | ✅ "..scannedCount.." "..T("scanned")
    end
end)

print("✅ ESP v5 Loaded! — Plate Alert + Auto-Buy + Auto-Rescan active")

Features & Information

🚗 NEW Car Sales 2 Script 🚗 🔥 First Release Out Now! ✅ Smooth ✅ Easy To Use ✅ More Updates Coming Soon Join the Discord and be part of the community! ⭐ Nitro Hub | Season 1

Community Comments (0)

No comments yet for this script.

More Scripts for [SEASON 1 🌟] Car Sales 2 🏎️