local HIT_Y        = 555
local FIRE_EARLY   = 0
local DIRECTION    = "down"   -- locked
local HOLD_MIN_H   = 70

--// DUEL ENGINE
local FORGE_TIME   = true
local PRESS_LEAD   = 0.02
local RING_X       = 0.28
local APPROACH     = 1.7
local JITTER_VAR   = 0.012

--// CAMO
local CAMO_ON      = true
local CAMO_N       = 3

--// CLICK FARM
local FARM_ON      = false
local FARM_RATE    = 5
local FARM_MODE    = "walk"

--// FLAGS
local DEBUG        = true
local INPUT_MODE   = "remote"
local ANTI_AFK     = true
local ANTI_KICK    = true
local HOLD_NOTES   = true
local MAX_HOLD     = 6
local SHIELD_ON    = true

--// ZONES (lanes)
local ZONES = { D = { 0.5, 0.95 } }
local AUTO_LEARN = true
local ZONE_PAD   = 0.08

--// DUEL asset → direction
local IMG_DIR = {
    ["126490284927469"] = "Up",
    ["100668880801499"] = "Down",
    ["81598601074836"]  = "Left",
    ["100659830896052"] = "Right",
}
local KEY_FOR_DIR = {
    Up = Enum.KeyCode.W, Down = Enum.KeyCode.S,
    Left = Enum.KeyCode.A, Right = Enum.KeyCode.D,
}
local DIR_MAP = { W = "Up", S = "Down", A = "Left", D = "Right" }

--// LIBRARY
local Library
for _, url in ipairs({
    "https://raw.githubusercontent.com/mstudio45/LinoriaLib/main/Library.lua",
    "https://raw.githubusercontent.com/violin-suzutsuki/LinoriaLib/main/Library.lua",
}) do
    local ok, lib = pcall(function() return loadstring(game:HttpGet(url))() end)
    if ok and lib then Library = lib break end
end
assert(Library, "[aura] Linoria failed to load — both repos unreachable")

local okW, Window = pcall(function()
    return Library:CreateWindow({ Title = "Aura // Highway", ToggleKey = Enum.KeyCode.RightShift, AutoShow = true })
end)
if not okW then Window = Library:CreateWindow("Aura // Highway", Enum.KeyCode.RightShift) end

--// SERVICES + STATE
local Replicated  = game:GetService("ReplicatedStorage")
local Players     = game:GetService("Players")
local RunService  = game:GetService("RunService")
local UIS         = game:GetService("UserInputService")
local VIM         = game:GetService("VirtualInputManager")
local LP          = Players.LocalPlayer
local gui         = LP:WaitForChild("PlayerGui")
local highway     = gui:WaitForChild("AuraLanes"):WaitForChild("Deck"):WaitForChild("Highway")

local enabled = true
local fired   = {}
local prevY   = {}
local count   = 0
local farmWalking = false

--// REMOTES
local function getRemote(name)
    local ok, ev = pcall(function() return Replicated.Events.Game[name] end)
    return ok and ev or nil
end

local function serverNow()
    local ok, t = pcall(function() return workspace:GetServerTimeNow() end)
    return ok and t or os.time()
end

--// INPUT HELPERS
local function noteLetterOf(note)
    local badge  = note:FindFirstChild("KeyBadge", true)
    local letter = badge and badge:FindFirstChild("Letter", true)
    return letter and letter.Text or nil
end

local function keyCodeOf(name)
    local ok, code = pcall(function() return Enum.KeyCode[name:upper()] end)
    return ok and code or nil
end

local function keyTap(code)
    pcall(function()
        VIM:SendKeyEvent(true, code, false, game)
        task.wait(0.03)
        VIM:SendKeyEvent(false, code, false, game)
    end)
end

local function setFarmWalk(on)
    if farmWalking == on then return end
    farmWalking = on
    pcall(function()
        VIM:SendKeyEvent(on, Enum.KeyCode.W, false, game)
    end)
end

--// CAMO MISS ENGINE
local roundNotes   = 0
local lastNoteSeen = 0
local missSlots    = {}

local function sampleMissSlots(n)
    local slots, prev = {}, 1
    for i = 1, n do
        local lo = (i == 1) and 2 or (prev + 8)
        local hi = (i == 1) and 4 or (prev + 30)
        prev = math.random(lo, hi)
        slots[prev] = true
    end
    return slots
end

missSlots = sampleMissSlots(CAMO_N)

local function isCamoMiss()
    roundNotes = roundNotes + 1
    lastNoteSeen = os.clock()
    return missSlots[roundNotes] == true
end

task.spawn(function()
    while true do
        task.wait(3)
        if roundNotes > 0 and os.clock() - lastNoteSeen > 10 then
            roundNotes = 0
            missSlots = sampleMissSlots(CAMO_N)
            if DEBUG then print("[aura] camo: new round, slots resampled") end
        end
    end
end)

--// HOLD ENGINE
local HOLDS = {}

local function startHold(key, note, code)
    if not HOLD_NOTES then return end
    local h = HOLDS[key]
    if not h then
        h = { notes = {}, startedAt = os.clock(), keyDown = false, code = code }
        HOLDS[key] = h
        if INPUT_MODE == "key" and code then
            pcall(function() VIM:SendKeyEvent(true, code, false, game) end)
            h.keyDown = true
        end
        if DEBUG then print("[aura] hold:", key) end
    end
    h.notes[note] = true
end

local function releaseAllHolds()
    for key, h in pairs(HOLDS) do
        if h.keyDown and h.code then
            pcall(function() VIM:SendKeyEvent(false, h.code, false, game) end)
        end
        HOLDS[key] = nil
    end
end

--// PRESS DELIVERY
local function firePress(dir, timestamp, isHold)
    local duel = getRemote("AuraDuel")
    if duel then
        pcall(function() duel:FireServer("Press", dir, timestamp) end)
        return
    end
    local code = KEY_FOR_DIR[dir]
    if code then
        if isHold then
            pcall(function() VIM:SendKeyEvent(true, code, false, game) end)
        else
            keyTap(code)
        end
    end
end

local function pressNote(letter, isHold)
    local dir  = DIR_MAP[letter] or DIR_MAP[letter:upper()]
    local duel = (INPUT_MODE == "remote") and getRemote("AuraDuel") or nil
    if duel and dir then
        pcall(function()
            duel:FireServer("Press", dir, serverNow())
        end)
        return
    end
    local code = keyCodeOf(letter)
    if code then
        if isHold then
            pcall(function() VIM:SendKeyEvent(true, code, false, game) end)
        else
            keyTap(code)
        end
    end
end

--// BUTTON COMPAT
local function addButtonCompat(group, idx, text, func)
    local tries = {
        function() return group:AddButton(idx, { Text = text, Func = func }) end,
        function() return group:AddButton({ Text = text, Func = func }) end,
        function() return group:AddButton(text, func) end,
    }
    for _, t in ipairs(tries) do
        local ok, res = pcall(t)
        if ok then return res end
    end
    return nil
end

--// ANTI-KICK
local oldNamecall
local function kickHook(self, ...)
    local method = getnamecallmethod()
    if ANTI_KICK and method == "Kick" and self == LP then
        if DEBUG then print("[aura] anti-kick: blocked Kick:", ...) end
        return nil
    end
    return oldNamecall(self, ...)
end

do
    local wrap = newcclosure or function(f) return f end
    local ok = pcall(function()
        oldNamecall = hookmetamethod(game, "__namecall", wrap(kickHook))
    end)
    if not ok then
        pcall(function()
            local mt = getrawmetatable(game)
            setreadonly(mt, false)
            oldNamecall = hookfunction(mt.__namecall, wrap(kickHook))
        end)
    end
    if oldNamecall then print("[aura] anti-kick hook armed") end
end

--// ANTI-AFK
LP.Idled:Connect(function()
    if not ANTI_AFK then return end
    pcall(function()
        local vu = game:GetService("VirtualUser")
        vu:CaptureController()
        vu:ClickButton2(Vector2.new())
    end)
    pcall(function()
        VIM:SendMouseMoveEvent(Vector2.new(math.random(100, 400), math.random(100, 400)))
    end)
end)

task.spawn(function()
    while true do
        task.wait(60 + math.random(0, 30))
        if ANTI_AFK then
            pcall(function()
                VIM:SendMouseMoveEvent(Vector2.new(math.random(100, 400), math.random(100, 400)))
            end)
        end
    end
end)

--// TROLL SHIELD
local VICTIM_GUIS = { "TrollEffects", "TrollSplats", "BlindEffectGui" }
local shieldConns = {}

local function shieldSweep()
    for _, name in ipairs(VICTIM_GUIS) do
        local g = gui:FindFirstChild(name)
        if g then
            if name == "BlindEffectGui" then
                g:Destroy()
            else
                g:ClearAllChildren()
            end
        end
    end
    local blur = game:GetService("Lighting"):FindFirstChild("BlindBlur")
    if blur then blur.Size = 0 blur:Destroy() end
end

local function setShield(on)
    for _, c in ipairs(shieldConns) do pcall(function() c:Disconnect() end) end
    shieldConns = {}
    SHIELD_ON = on
    if not on then return end
    table.insert(shieldConns, gui.ChildAdded:Connect(function(c)
        if table.find(VICTIM_GUIS, c.Name) then task.defer(shieldSweep) end
    end))
    for _, name in ipairs(VICTIM_GUIS) do
        local g = gui:FindFirstChild(name)
        if g then
            table.insert(shieldConns, g.ChildAdded:Connect(function() task.defer(shieldSweep) end))
        end
    end
    task.spawn(function()
        while SHIELD_ON do
            shieldSweep()
            task.wait(0.75)
        end
    end)
    shieldSweep()
end

--// CLICK FARM
task.spawn(function()
    while true do
        if FARM_ON then
            local Click = getRemote("Click")
            if Click then pcall(function() Click:FireServer() end) end
            task.wait(1 / FARM_RATE + math.random() * 0.03)
        else
            setFarmWalk(false)
            task.wait(0.5)
        end
    end
end)

--// TOOLKIT — serializer
local function fmt(v, d)
    d = d or 0
    local t = typeof(v)
    if t == "Instance" then return v:GetFullName() end
    if t == "table" and d < 4 then
        local parts = {}
        if #v > 0 then
            for i = 1, math.min(#v, 40) do parts[i] = fmt(v[i], d + 1) end
        else
            for k, val in pairs(v) do
                table.insert(parts, tostring(k) .. "=" .. fmt(val, d + 1))
            end
        end
        return "{" .. table.concat(parts, ", ") .. "}"
    end
    return tostring(v)
end

--// TOOLKIT — listen
_G.Listen = function(seconds)
    local conns, n = {}, 0
    for _, d in ipairs(Replicated.Events.Game:GetDescendants()) do
        if d:IsA("RemoteEvent") then
            n = n + 1
            table.insert(conns, d.OnClientEvent:Connect(function(...)
                print("[listen<] " .. d.Name .. " " .. fmt({ ... }))
            end))
        end
    end
    task.delay(seconds or 10, function()
        for _, c in ipairs(conns) do pcall(function() c:Disconnect() end) end
        print("[listen] off (" .. n .. " remotes)")
    end)
    print("[listen] armed on " .. n .. " Game remotes for " .. (seconds or 10) .. "s")
end

--// TOOLKIT — race prober
_G.ProbeRace = function(mode)
    local Race = getRemote("Race")
    if not Race then return print("[probe] Race missing") end
    local conn
    conn = Race.OnClientEvent:Connect(function(payload)
        print("[probe<] Race: " .. fmt(payload))
    end)
    task.delay(5, function() if conn then conn:Disconnect() end end)
    pcall(function() Race:FireServer({ Mode = tostring(mode) }) end)
    print("[probe>] Race:FireServer({Mode='" .. tostring(mode) .. "'}) — listening 5s")
end

--// TOOLKIT — troll prober v3
local KIND_WORDS = {
    ["Trow Tomato"] = "Throw", ["Slip Them"]     = "Slip",
    ["Drop Bomb"]   = "Bomb",  ["Blind Them"]    = "Blind",
    ["KeySwap Them"] = "KeySwap", ["Freeze Them"] = "Freeze",
    ["Kill Them"]   = "Kill",  ["Drop Nuke"]     = "Nuke",
}

_G.ProbeTroll = function(targetName, troll)
    troll = troll or "Trow Tomato"
    local Troll = getRemote("Troll")
    local target = targetName and Players:FindFirstChild(targetName)
    if not Troll or not target then
        return print("[troll] need: _G.ProbeTroll('PlayerName', 'Trow Tomato')")
    end
    local expect = KIND_WORDS[troll] or "Throw"
    local word = troll:match("(%a+)$")
    local shapes = {
        function(t) Troll:FireServer(t, troll) end,
        function(t) Troll:FireServer(troll, t) end,
        function(t) Troll:FireServer("Throw", troll, t) end,
        function(t) Troll:FireServer(t, "Throw", word) end,
        function(t) Troll:FireServer(t, "Throw", troll) end,
    }
    local hit = false
    local conn = Troll.OnClientEvent:Connect(function(pl)
        if type(pl) == "table" and (pl.Kind == expect
            or (pl.Asset and pl.Asset:find(word, 1, true))
            or pl.Target == target) then
            hit = true
        end
    end)
    for i, shape in ipairs(shapes) do
        hit = false
        pcall(shape, target)
        local t0 = os.clock()
        while not hit and os.clock() - t0 < 1.2 do task.wait(0.05) end
        if hit then
            print("[troll] shape #" .. i .. " confirmed for '" .. troll .. "'")
            conn:Disconnect()
            return i
        end
    end
    conn:Disconnect()
    print("[troll] no shape confirmed — run the namecall spy, click one troll, send me the line")
end

_G.TrollAll = function(troll, interval)
    troll = troll or "Trow Tomato"
    interval = interval or 1.5
    local Troll = getRemote("Troll")
    if not Troll then return print("[troll] no remote") end
    task.spawn(function()
        for _, p in ipairs(Players:GetPlayers()) do
            if p ~= LP then
                pcall(function() Troll:FireServer(p, troll) end)
                task.wait(interval)
            end
        end
        print("[troll] barrage done")
    end)
end

--// TOOLKIT — equip prober
_G.ProbeEquip = function(sort, name)
    local ev = getRemote(sort)
    if not ev then return print("[equip] no remote named " .. tostring(sort)) end
    local conn = ev.OnClientEvent:Connect(function(...)
        print("[equip<] " .. sort .. " " .. fmt({ ... }))
    end)
    task.delay(6, function() conn:Disconnect() end)
    pcall(function() ev:FireServer(name) end)
    pcall(function() ev:FireServer("Equip", name) end)
    pcall(function() ev:FireServer("Buy", name) end)
    pcall(function() ev:FireServer({ Action = "Equip", Name = name }) end)
    print("[equip>] fired 4 shapes for " .. sort .. " '" .. tostring(name) .. "' — watching 6s")
end

--// INTEL — chart sync logger
_G.ChartLog = function(seconds)
    local duel = getRemote("AuraDuel")
    if not duel then return print("[chart] AuraDuel missing") end
    local conn = duel.OnClientEvent:Connect(function(...)
        local args = { ... }
        print("[chart<] broadcast, " .. #args .. " args:")
        for i, a in ipairs(args) do
            if type(a) == "table" and #a > 0 then
                print(string.format("[chart]   arg %d = array of %d:", i, #a))
                for j, n in ipairs(a) do
                    if type(n) == "table" then
                        print(string.format("[chart]     [%d] %s", j, fmt(n, 1)))
                    end
                end
            else
                print(string.format("[chart]   arg %d = %s", i, tostring(a)))
            end
        end
    end)
    task.delay(seconds or 30, function() conn:Disconnect() print("[chart] off") end)
    print("[chart] listening — START A DUEL NOW")
end

--// INTEL — live note array from memory
_G.DumpNotes = function()
    if not getreg or not getupvalues then
        return print("[dump] executor lacks getreg/getupvalues — use _G.ChartLog instead")
    end
    local seen, found = {}, {}
    for _, f in ipairs(getreg()) do
        if type(f) == "function" then
            local ok, upv = pcall(getupvalues, f)
            if ok and type(upv) == "table" then
                for _, v in pairs(upv) do
                    if type(v) == "table" and not seen[v]
                        and type(v[1]) == "table" and v[1].Time and v[1].Direction then
                        seen[v] = true
                        table.insert(found, v)
                    end
                end
            end
        end
    end
    if #found == 0 then return print("[dump] no live chart found — run this DURING a duel") end
    for ai, arr in ipairs(found) do
        print(string.format("[dump] chart #%d — %d live notes", ai, #arr))
        for i, n in ipairs(arr) do
            print(string.format("  [%s] Dir=%s Time=%.3f Hold=%s Done=%s",
                tostring(n.Index), tostring(n.Direction),
                tonumber(n.Time) or -1, tostring(n.Hold), tostring(n.Done)))
        end
    end
end

--// INTEL — press log, both directions
_G.PressLog = function(seconds)
    local duel = getRemote("AuraDuel")
    if not duel then return print("[press] AuraDuel missing") end
    duel.OnClientEvent:Connect(function(...)
        print("[press<] " .. fmt({ ... }))
    end)
    local old
    old = hookmetamethod(game, "__namecall", function(self, ...)
        local m = getnamecallmethod()
        if m == "FireServer" and self == duel then
            print("[press>] FireServer(" .. fmt({ ... }) .. ")")
        end
        return old(self, ...)
    end)
    task.delay(seconds or 30, function() print("[press] off (hook stays, it's inert)") end)
    print("[press] PLAY A FEW NOTES BY HAND NOW — mix perfects and misses")
end

--// INTEL — full UI tree
_G.DumpUI = function()
    local function dump(inst, depth)
        if depth > 6 then return end
        local extra = ""
        if inst:IsA("GuiObject") then
            local p, s = inst.Position, inst.Size
            extra = string.format(" pos=(%.3f,%.3f)+(%.0f,%.0f) size=(%.3f,%.3f)+(%.0f,%.0f)",
                p.X.Scale, p.Y.Scale, p.X.Offset, p.Y.Offset,
                s.X.Scale, s.Y.Scale, s.X.Offset, s.Y.Offset)
        end
        if inst:IsA("TextLabel") or inst:IsA("TextButton") then
            extra = extra .. " text=" .. string.format("%q", tostring(inst.Text))
        end
        if inst:IsA("ImageLabel") or inst:IsA("ImageButton") then
            extra = extra .. " img=" .. tostring(inst.Image)
        end
        print(string.rep("  ", depth) .. inst.Name .. " [" .. inst.ClassName .. "]" .. extra)
        for _, c in ipairs(inst:GetChildren()) do dump(c, depth + 1) end
    end
    local lanes = gui:FindFirstChild("AuraLanes")
    if lanes then print("== AURALANES ==") dump(lanes, 0) end
    local dance = gui:FindFirstChild("AuraDance")
    if dance then
        print("== AURADANCE ==")
        local track = dance:FindFirstChild("Root") and dance.Root:FindFirstChild("Track")
        dump(track or dance, 0)
    end
    print("== done ==")
end

--// PANEL
local Main  = Window:AddTab("Main")
local Left  = Main:AddLeftGroupbox("Autofire")
local Farm  = Main:AddLeftGroupbox("Click Farm")
local Right = Main:AddRightGroupbox("Status")

Left:AddToggle("AutoFire", { Text = "Autofire", Default = true,
    Callback = function(v) enabled = v; releaseAllHolds() end })
Left:AddToggle("ForgeTime", { Text = "Forge timestamps (duel)", Default = FORGE_TIME,
    Callback = function(v) FORGE_TIME = v end })
Left:AddToggle("CamoMiss", { Text = "Camo misses", Default = CAMO_ON,
    Callback = function(v) CAMO_ON = v end })
Left:AddSlider("CamoCount", { Text = "Misses per song", Min = 1, Max = 5, Default = CAMO_N,
    Round = 0, Rounding = 0, Decimals = 0,
    Callback = function(v)
        CAMO_N = math.floor(v + 0.5)
        missSlots = sampleMissSlots(CAMO_N)
        roundNotes = 0
    end })
Left:AddToggle("HoldNotes", { Text = "Hold notes", Default = HOLD_NOTES,
    Callback = function(v) HOLD_NOTES = v; if not v then releaseAllHolds() end end })
Left:AddToggle("AntiAfk", { Text = "Anti-AFK", Default = ANTI_AFK,
    Callback = function(v) ANTI_AFK = v end })
Left:AddToggle("AntiKick", { Text = "Anti-Kick", Default = ANTI_KICK,
    Callback = function(v) ANTI_KICK = v end })
Left:AddToggle("Shield", { Text = "Troll shield", Default = true,
    Callback = function(v) setShield(v) end })
Left:AddSlider("FireEarly", { Text = "Fire early (lanes)", Min = 0, Max = 100, Default = FIRE_EARLY, Suffix = "px",
    Round = 0, Rounding = 0, Decimals = 0,
    Callback = function(v) FIRE_EARLY = math.floor(v + 0.5) end })
Left:AddDropdown("InputMode", { Text = "Input mode", Values = { "remote", "key" }, Default = INPUT_MODE,
    Callback = function(v) INPUT_MODE = v end })
Left:AddToggle("Debug", { Text = "Debug prints", Default = DEBUG,
    Callback = function(v) DEBUG = v end })
addButtonCompat(Left, "PrintZones", "Print learned zones", function()
    for l, z in pairs(ZONES) do
        print(string.format("[aura] zone %s: [%.3f, %.3f]", l, z[1], z[2]))
    end
end)

Farm:AddToggle("FarmOn", { Text = "Farm clicks", Default = FARM_ON,
    Callback = function(v)
        FARM_ON = v
        setFarmWalk(v and FARM_MODE == "walk")
        print("[aura] farm " .. (v and "ON" or "OFF") .. " @ " .. FARM_RATE .. "/s " .. FARM_MODE)
    end })
Farm:AddSlider("FarmRate", { Text = "Rate", Min = 1, Max = 30, Default = FARM_RATE, Suffix = "/s",
    Round = 0, Rounding = 0, Decimals = 0,
    Callback = function(v) FARM_RATE = math.floor(v + 0.5) end })
Farm:AddDropdown("FarmMode", { Text = "Mode", Values = { "walk", "static" }, Default = FARM_MODE,
    Callback = function(v)
        FARM_MODE = v
        setFarmWalk(FARM_ON and v == "walk")
    end })

local lastLabel, countLabel
pcall(function()
    lastLabel  = Right:AddLabel("waiting for notes...")
    countLabel = Right:AddLabel("notes fired: 0")
end)
local function setLast(t)  if lastLabel  then pcall(function() lastLabel:SetText(t)  end) end end
local function setCount(t) if countLabel then pcall(function() countLabel:SetText(t) end) end end

--// HOTKEY
UIS.InputBegan:Connect(function(input, gp)
    if gp then return end
    if input.KeyCode == Enum.KeyCode.RightControl then
        enabled = not enabled
        releaseAllHolds()
        pcall(function() Toggles.AutoFire:SetValue(enabled) end)
        print("[aura] autofire " .. (enabled and "ON" or "OFF"))
    end
end)

--// SETTINGS TAB
pcall(function()
    local base = "https://raw.githubusercontent.com/mstudio45/LinoriaLib/main/addons/"
    local ThemeManager = loadstring(game:HttpGet(base .. "ThemeManager.lua"))()
    local SaveManager  = loadstring(game:HttpGet(base .. "SaveManager.lua"))()
    local SettingsTab = Window:AddTab("Settings")
    ThemeManager:SetLibrary(Library)
    SaveManager:SetLibrary(Library)
    SaveManager:IgnoreThemeSettings()
    ThemeManager:SetFolder("AuraBattle")
    SaveManager:SetFolder("AuraBattle/autofire")
    SaveManager:BuildConfigSection(SettingsTab)
    SaveManager:ApplyToTab(SettingsTab)
    ThemeManager:ApplyToTab(SettingsTab)
end)

--// DUEL ENGINE
local function arrowDirection(arrow)
    local glyph  = arrow:FindFirstChild("Glyph")
    local colour = glyph and glyph:FindFirstChild("Colour")
    if colour then
        local id = tostring(colour.Image):match("(%d+)$")
        if id and IMG_DIR[id] then return IMG_DIR[id] end
    end
    return nil
end

local function duelStep()
    local dance = gui:FindFirstChild("AuraDance")
    local root  = dance and dance:FindFirstChild("Root")
    local track = root and root:FindFirstChild("Track")
    if not track then return end
    local now = serverNow()
    for _, arrow in ipairs(track:GetChildren()) do
        if arrow.Name:match("^Arrow%d+") and arrow:IsA("GuiObject") then
            if not fired[arrow] then
                local dir = arrowDirection(arrow)
                if dir then
                    local xs = arrow.Position.X.Scale
                    local noteTime = now + (xs - RING_X) * APPROACH / 0.72
                    if now >= noteTime - PRESS_LEAD then
                        fired[arrow] = true
                        if CAMO_ON and isCamoMiss() then
                            setLast("camo miss @ note " .. roundNotes)
                            if DEBUG then print("[aura] camo miss (duel) note " .. roundNotes) end
                        else
                            local t = (FORGE_TIME and noteTime or now)
                            if JITTER_VAR > 0 then t = t + (math.random() - 0.5) * JITTER_VAR end
                            local idx  = arrow.Name:match("^Arrow(%d+)")
                            local tail = HOLD_NOTES and idx and track:FindFirstChild("HoldTail" .. idx)
                            firePress(dir, t, tail ~= nil)
                            if tail then startHold(dir, arrow, KEY_FOR_DIR[dir]) end
                            count = count + 1
                            setLast("last: " .. dir .. (tail and " (hold)" or "") .. " dt="
                                .. string.format("%.0f", (now - noteTime) * 1000) .. "ms")
                            setCount("notes fired: " .. count)
                            if DEBUG then
                                print(string.format("[aura] duel %s%s dt=%dms", dir, tail and "+hold" or "",
                                    (now - noteTime) * 1000))
                            end
                        end
                    end
                end
            elseif arrow.Position.X.Scale > RING_X + 0.3 then
                fired[arrow] = nil
            end
        end
    end
end

--// LANES ENGINE
local function learnZone(letter, xs)
    if not AUTO_LEARN or not letter or ZONES[letter] then return end
    ZONES[letter] = { xs - ZONE_PAD, xs + ZONE_PAD }
    print(string.format("[aura] learned zone %s: [%.3f, %.3f]", letter, xs - ZONE_PAD, xs + ZONE_PAD))
end

local function lanesStep()
    local threshold = (DIRECTION == "down") and (HIT_Y - FIRE_EARLY) or (HIT_Y + FIRE_EARLY)
    for _, note in ipairs(highway:GetChildren()) do
        if note.Name:match("^Note%d+") and note:IsA("GuiObject") then
            local badge  = note:FindFirstChild("KeyBadge", true)
            local letter = badge and badge:FindFirstChild("Letter", true)
            letter = letter and letter.Text or nil
            if letter then
                local xs = (note.AbsolutePosition.X - highway.AbsolutePosition.X + note.AbsoluteSize.X * 0.5)
                    / math.max(highway.AbsoluteSize.X, 1)
                local y = note.AbsolutePosition.Y - highway.AbsolutePosition.Y
                learnZone(letter, xs)
                local zone = ZONES[letter]
                local inZone = zone and (xs >= zone[1] - 0.02 and xs <= zone[2] + 0.02)
                local p = prevY[note]
                prevY[note] = y
                local crossed = p and (
                    (DIRECTION == "down" and p < threshold and y >= threshold) or
                    (DIRECTION == "up"   and p > threshold and y <= threshold))
                if crossed and inZone and not fired[note] then
                    fired[note] = true
                    if CAMO_ON and isCamoMiss() then
                        setLast("camo miss @ note " .. roundNotes)
                        if DEBUG then print("[aura] camo miss (lanes) note " .. roundNotes) end
                    else
                        local isHold = HOLD_NOTES and (note.AbsoluteSize.Y >= HOLD_MIN_H)
                        pressNote(letter, isHold)
                        if isHold then startHold(letter, note, keyCodeOf(letter)) end
                        count = count + 1
                        setLast("last: " .. letter .. (isHold and " (hold)" or "") .. " y=" .. y)
                        setCount("notes fired: " .. count)
                        if DEBUG then
                            print(string.format("[aura] lanes %s%s y=%d->%d", letter, isHold and "+hold" or "", p, y))
                        end
                    end
                elseif fired[note] and (DIRECTION == "down") and (y < HIT_Y - 150) then
                    fired[note] = nil
                elseif fired[note] and (DIRECTION == "up") and (y > HIT_Y + 150) then
                    fired[note] = nil
                end
            end
        end
    end
end

--// MAIN LOOP
RunService.RenderStepped:Connect(function()
    if not enabled then return end
    duelStep()
    lanesStep()

    if HOLD_NOTES then
        local now = os.clock()
        for key, h in pairs(HOLDS) do
            for n in pairs(h.notes) do
                if not n:IsDescendantOf(game) then
                    h.notes[n] = nil
                end
            end
            local empty = true
            for _ in pairs(h.notes) do empty = false break end
            if empty or (now - h.startedAt > MAX_HOLD) then
                if h.keyDown and h.code then
                    pcall(function() VIM:SendKeyEvent(false, h.code, false, game) end)
                end
                HOLDS[key] = nil
            end
        end
    end
end)

task.spawn(function()
    while true do
        task.wait(2)
        for k in pairs(prevY) do
            if not k:IsDescendantOf(highway) then
                prevY[k] = nil
                fired[k] = nil
            end
        end
    end
end)

setShield(true)
Aura Dance Battles🔥 Aura Dance Battles🔥anti afk auto bot auto play #auto
Mobile Friendly
652 views
2 weeks ago

Aura Dance Battles🔥anti afk auto bot auto play #auto

WORKING
Free

Description

Auto play auto bot anti afk anti kick working new unpatched #auto #bot #antiafk #anti #antikick #working #new #unpatched #notpatched #auto #bypass

Related Scripts