AIM ASSIST FOR
Key Required

AIM ASSIST FOR

[NEW] 8 Ball Duelskinglewrencekinglewrence 754 views 4.2K executesUpdated Oct 4, 2026
5.0/ 5(1 votes)
10100% Positive
Lua Script•454 lines (18525 chars)
-- ====================================================================
-- 8 Ball Duels - ULTIMATE ACCURATE GUIDELINE & AIMBOT ASSIST
-- 100% Akurat pake Geometri Fisika Asli Game:
-- - cushionToi: 18 segmen bantalan (termasuk facing miring & jaw)
-- - pocketToi: Deteksi lubang resmi game (MouthCentre, CommitDepth, Throat)
-- - sweepCircle: Deteksi tabrakan bola lain & ujung bantalan
-- - Indikator LUBANG HIJAU: Menyala terang kalau 100% PASTI MASUK!
-- - Peringatan SCRATCH: Garis putih berubah MERAH kalau bola putih kecemplung
-- ====================================================================

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Pool = ReplicatedStorage:WaitForChild("Libraries"):WaitForChild("GameSpecific"):WaitForChild("Pool")
local PoolConstants = require(Pool:WaitForChild("PoolConstants"))
local PoolGeometry = require(Pool:WaitForChild("PoolGeometry"))
local PoolPhysics = require(Pool:WaitForChild("PoolPhysics"))
local PoolAimOverlay = require(Pool:WaitForChild("PoolAimOverlay"))

local FrameWidth = PoolConstants.FrameWidth
local FrameHeight = PoolConstants.FrameHeight
local BallRadius = PoolConstants.BallRadius
local BallDiameter = PoolConstants.BallDiameter

-- Geometri resmi dari game
local cushions = PoolGeometry.GetCushions()
local pockets = PoolGeometry.GetPockets()
local jaws = PoolGeometry.GetJaws()

-- Warna
local COLOR_POCKET_IN = Color3.fromRGB(0, 255, 120)    -- Hijau neon: 100% Masuk lubang
local COLOR_NORMAL    = Color3.fromRGB(255, 140, 50)    -- Oranye: Jalur bola biasa
local COLOR_BOUNCE    = Color3.fromRGB(255, 200, 80)    -- Kuning: Jalur pantulan
local COLOR_SCRATCH   = Color3.fromRGB(255, 40, 40)     -- Merah: Bahaya bola putih kecemplung
local COLOR_WHITE     = Color3.fromRGB(255, 255, 255)

-- --------------------------------------------------------------------
-- Algoritma Fisika CCD Resmi Game
-- --------------------------------------------------------------------
local function sweepCircle(a1, a2, a3, a4)
    local v1 = (a1:Dot(a1)) - a3 * a3
    local v2 = 2 * a1:Dot(a2)
    if v1 < 0 then
        if v2 < 0 then return 0 end
        return nil
    end
    if v2 >= 0 then return nil end
    local v3 = a2:Dot(a2)
    if v3 <= 1e-06 then return nil end
    local v4 = v2 * v2 - 4 * v3 * v1
    if v4 < 0 then return nil end
    local v5 = (-v2 - math.sqrt(v4)) / (2 * v3)
    if not (v5 < 0) and not (a4 < v5) then
        return v5
    end
    return nil
end

local function cushionToi(a1, a2, a3, a4, a5)
    local v4 = a5 or BallRadius
    local Normal = a3.Normal
    local v5 = a2:Dot(Normal)
    if v5 >= -1e-06 then return nil end
    local v6 = (a1 - a3.A):Dot(Normal)
    if v6 < -v4 then return nil end
    if v6 < v4 then return nil end
    local v3 = (v4 - v6) / v5
    if not (v3 < 0) and not (a4 < v3) then
        local v1 = a3.B - a3.A
        local Magnitude = v1.Magnitude
        local v2 = (a1 + a2 * v3 - a3.A):Dot(v1 / Magnitude)
        if not (v2 < 0) and not (Magnitude < v2) then
            return v3
        end
    end
    return nil
end

local function pocketToi(a1, a2, a3, a4)
    local v1 = a2:Dot(a3.Normal)
    if v1 <= 1e-06 then return nil end
    local v2 = -(((a1 - a3.MouthCentre):Dot(a3.Normal)) - a3.CommitDepth) / v1
    if not (v2 < 0) and not (a4 < v2) then
        local v3 = Vector2.new(-a3.Normal.Y, a3.Normal.X)
        local v4 = math.abs(((a1 + a2 * v2 - a3.MouthCentre):Dot(v3)))
        if a3.Mouth / 2 < v4 then return nil end
        return v2
    end
    return nil
end

-- --------------------------------------------------------------------
-- Raycast Bola Akurat (Semua Rintangan Meja)
-- --------------------------------------------------------------------
local function castBall(pos, dir, radius, ignoreNumber, balls)
    radius = radius or BallRadius
    local maxDist = 200
    local closestT = maxDist
    local hitKind = "None"
    local hitObj = nil
    local hitNormal = nil

    -- 1. Cek tabrakan bola lain di meja
    if balls then
        for _, b in ipairs(balls) do
            if b.Number ~= ignoreNumber and not b.Pocketed and not b.Sinking then
                local t = sweepCircle(b.Position - pos, -dir, radius + (b.Radius or BallRadius), closestT)
                if t and t > 0.001 and t < closestT then
                    closestT = t
                    hitKind = "Ball"
                    hitObj = b
                end
            end
        end
    end

    -- 2. Cek lubang pocket resmi
    for _, p in ipairs(pockets) do
        local t = pocketToi(pos, dir, p, closestT)
        if t and t > 0.001 and t < closestT then
            closestT = t
            hitKind = "Pocket"
            hitObj = p
        end
    end

    -- 3. Cek bantalan / cushion
    for _, c in ipairs(cushions) do
        local t = cushionToi(pos, dir, c, closestT, radius)
        if t and t > 0.001 and t < closestT then
            closestT = t
            hitKind = "Cushion"
            hitObj = c
            hitNormal = c.Normal
        end
    end

    -- 4. Cek sudut jaw tip bantalan
    for _, j in ipairs(jaws) do
        local t = sweepCircle(j.Position - pos, -dir, radius, closestT)
        if t and t > 0.001 and t < closestT then
            closestT = t
            hitKind = "Tip"
            hitObj = j
            hitNormal = (pos + dir * t - j.Position).Unit
        end
    end

    if hitKind == "None" or closestT >= maxDist then
        return pos + dir * 80, "None", nil, nil
    end

    local hitPos = pos + dir * closestT
    local reflectDir = nil

    if hitKind == "Pocket" then
        hitPos = hitObj.BowlCentre
    elseif hitKind == "Cushion" or hitKind == "Tip" then
        if hitNormal then
            reflectDir = dir - 2 * (dir:Dot(hitNormal)) * hitNormal
            if reflectDir.Magnitude > 0.01 then
                reflectDir = reflectDir.Unit
            end
        end
    elseif hitKind == "Ball" then
        local toOther = (hitObj.Position - hitPos).Unit
        reflectDir = toOther
    end

    return hitPos, hitKind, hitObj, reflectDir
end

-- Ambil daftar bola aktif dari Simulation atau dari GUI
local function getActiveBalls(overlay, sim)
    if sim and sim.Balls then
        local list = {}
        for _, b in pairs(sim.Balls) do
            if not b.Pocketed and not b.Sinking then
                table.insert(list, b)
            end
        end
        if #list > 0 then return list end
    end
    -- Fallback dari GUI Balls frame
    local pt = overlay.Root and overlay.Root.Parent and overlay.Root.Parent.Parent
    local bf = pt and pt:FindFirstChild("Balls")
    if bf then
        local list = {}
        for _, b in ipairs(bf:GetChildren()) do
            if b:IsA("Frame") and b.Visible then
                local num = tonumber(b.Name:match("%d+")) or -1
                local x = (b.Position.X.Scale - 0.5) * FrameWidth
                local y = (0.5 - b.Position.Y.Scale) * FrameHeight
                table.insert(list, {Number = num, Position = Vector2.new(x, y), Radius = BallRadius})
            end
        end
        return list
    end
    return {}
end

-- --------------------------------------------------------------------
-- Renderer Garis & Indikator Lubang
-- --------------------------------------------------------------------
local function setLine(lineFrame, a2, a3, thickness, color)
    local v1 = a3 - a2
    local Magnitude = v1.Magnitude
    if Magnitude < 0.001 then
        lineFrame.Visible = false
        return
    end
    local v2 = (a2 + a3) / 2
    lineFrame.Position = UDim2.fromScale(0.5 + v2.X / FrameWidth, 0.5 - v2.Y / FrameHeight)
    lineFrame.Size = UDim2.fromScale(Magnitude / FrameWidth, (thickness or 0.5) / FrameHeight)
    lineFrame.Rotation = math.deg(math.atan2(-v1.Y, v1.X))
    if color then
        lineFrame.BackgroundColor3 = color
        lineFrame.ImageColor3 = color
    end
    lineFrame.Visible = true
    local Attribute = lineFrame:GetAttribute("SliceSourceHeight")
    if Attribute and lineFrame.Parent then
        local Y = lineFrame.Parent.AbsoluteSize.Y
        if Y > 0 then
            lineFrame.SliceScale = math.max((thickness or 0.5) / FrameHeight * Y / Attribute, 0.01)
        end
    end
end

local function getHelperLine(overlay, key, template, color, transparency)
    if not overlay[key] or not overlay[key].Parent then
        local line = template:Clone()
        line.Name = key
        line.BackgroundColor3 = color or template.BackgroundColor3
        line.ImageColor3 = color or template.ImageColor3
        line.BackgroundTransparency = transparency or 0.35
        line.ImageTransparency = transparency or 0.35
        line.Visible = false
        line.Parent = overlay.Root
        overlay[key] = line
    end
    return overlay[key]
end

local function getPocketMarker(overlay, name, color)
    local marker = overlay.Root:FindFirstChild(name)
    if not marker then
        marker = Instance.new("Frame")
        marker.Name = name
        marker.AnchorPoint = Vector2.new(0.5, 0.5)
        marker.Size = UDim2.fromScale(6.5 / FrameWidth, 6.5 / FrameHeight)
        marker.BackgroundTransparency = 1
        marker.ZIndex = overlay.AimLine.ZIndex + 10
        
        local corner = Instance.new("UICorner")
        corner.CornerRadius = UDim.new(1, 0)
        corner.Parent = marker
        
        local stroke = Instance.new("UIStroke")
        stroke.Thickness = 3
        stroke.Color = color or COLOR_POCKET_IN
        stroke.Transparency = 0.05
        stroke.Parent = marker
        
        marker.Parent = overlay.Root
    end
    return marker
end

local function hideHelpers(overlay)
    if overlay.ObjectLineBounce then overlay.ObjectLineBounce.Visible = false end
    if overlay.CueLineBounce then overlay.CueLineBounce.Visible = false end
    if overlay.AimBounce then overlay.AimBounce.Visible = false end
    if overlay.AimBounce2 then overlay.AimBounce2.Visible = false end
    if overlay.ComboLine then overlay.ComboLine.Visible = false end
    local m1 = overlay.Root:FindFirstChild("TargetPocketMarker")
    if m1 then m1.Visible = false end
    local m2 = overlay.Root:FindFirstChild("ScratchMarker")
    if m2 then m2.Visible = false end
end

-- --------------------------------------------------------------------
-- Hook PoolPhysics.PredictShot (Agar Simulation Selalu Terbawa)
-- --------------------------------------------------------------------
if not _G.OriginalPredictShot then
    _G.OriginalPredictShot = PoolPhysics.PredictShot
end

PoolPhysics.PredictShot = function(sim, dir, power, spin, dt)
    local res = _G.OriginalPredictShot(sim, dir, power, spin, dt)
    if res then
        res.Simulation = sim
    end
    return res
end

-- --------------------------------------------------------------------
-- Hook Utama: PoolAimOverlay.Update (Akurasi Penuh 100%)
-- --------------------------------------------------------------------
PoolAimOverlay.Update = function(a1, a2, a3, a4, a5, a6, a7)
    if a3.Magnitude < 0.0001 then return end

    local isLegal = a7 ~= false
    local AimLineColour = if not isLegal then COLOR_SCRATCH else PoolConstants.AimLineColour
    local DefaultAccent = if not isLegal then COLOR_SCRATCH else (a1.AccentColour or COLOR_NORMAL)

    a1.AimLine.BackgroundColor3 = AimLineColour
    a1.AimLine.ImageColor3 = AimLineColour

    local UIStroke = a1.Ghost:FindFirstChildOfClass("UIStroke")
    if UIStroke then
        UIStroke.Color = AimLineColour
    end

    -- Stick & Pull back animation (Presisi Bawaan Game)
    local Unit = a3.Unit
    local v2 = a2 - Unit * (PoolConstants.BallRadius + (math.clamp(a5 or 0, 0, 1) * 9 + 1.6))
    local v3 = v2 - Unit * 34
    if not a1.StickEnabled then
        a1.CueStick.Visible = false
    else
        setLine(a1.CueStick, v3, v2, 0.85)
    end

    if a4 and a4.Kind ~= "None" and a1.GuidesEnabled then
        local Ghost = a4.Ghost
        setLine(a1.AimLine, a2, Ghost, 0.5)
        a1.Ghost.Position = UDim2.fromScale(0.5 + Ghost.X / FrameWidth, 0.5 - Ghost.Y / FrameHeight)
        a1.Ghost.Visible = true

        local balls = getActiveBalls(a1, a4.Simulation)
        local targetMarker = getPocketMarker(a1, "TargetPocketMarker", COLOR_POCKET_IN)
        targetMarker.Visible = false
        local scratchMarker = getPocketMarker(a1, "ScratchMarker", COLOR_SCRATCH)
        scratchMarker.Visible = false

        if a4.Kind == "Ball" and a4.ObjectDirection then
            -- Posisi awal bola target
            local objStart = Ghost + a4.ObjectDirection * BallDiameter
            local hitPos1, kind1, obj1, reflect1 = castBall(objStart, a4.ObjectDirection, BallRadius, a4.Other, balls)

            -- 1. GARIS BOLA TARGET
            if kind1 == "Pocket" then
                -- 100% MASUK LUBANG! Warnai Hijau Terang & Nyalakan Indikator Lubang!
                setLine(a1.ObjectLine, objStart, hitPos1, 0.6, COLOR_POCKET_IN)
                targetMarker.Position = UDim2.fromScale(0.5 + obj1.MouthCentre.X / FrameWidth, 0.5 - obj1.MouthCentre.Y / FrameHeight)
                targetMarker.Visible = true
                if a1.ObjectLineBounce then a1.ObjectLineBounce.Visible = false end
            else
                -- Kena bantalan / tip
                setLine(a1.ObjectLine, objStart, hitPos1, 0.55, DefaultAccent)
                targetMarker.Visible = false

                -- 2. GARIS PANTULAN (BOUNCE)
                if reflect1 then
                    local hitPos2, kind2, obj2, _ = castBall(hitPos1, reflect1, BallRadius, a4.Other, balls)
                    local bounceLine = getHelperLine(a1, "ObjectLineBounce", a1.ObjectLine, COLOR_BOUNCE, 0.4)
                    if kind2 == "Pocket" then
                        -- Pantulan masuk lubang! (Bank shot masuk)
                        setLine(bounceLine, hitPos1, hitPos2, 0.5, COLOR_POCKET_IN)
                        targetMarker.Position = UDim2.fromScale(0.5 + obj2.MouthCentre.X / FrameWidth, 0.5 - obj2.MouthCentre.Y / FrameHeight)
                        targetMarker.Visible = true
                    else
                        setLine(bounceLine, hitPos1, hitPos2, 0.4, COLOR_BOUNCE)
                    end
                elseif a1.ObjectLineBounce then
                    a1.ObjectLineBounce.Visible = false
                end
            end

            -- 3. GARIS CUE BALL DEFLECTION (Arah Bola Putih)
            if a4.CueDirection and a4.CueDirection.Magnitude > 0.01 then
                local cueHit, cueKind, cueObj, cueReflect = castBall(Ghost, a4.CueDirection, BallRadius, 0, balls)
                if cueKind == "Pocket" then
                    -- BAHAYA: BOLA PUTIH SCRATCH KECEMPLUNG!
                    setLine(a1.CueLine, Ghost, cueHit, 0.55, COLOR_SCRATCH)
                    scratchMarker.Position = UDim2.fromScale(0.5 + cueObj.MouthCentre.X / FrameWidth, 0.5 - cueObj.MouthCentre.Y / FrameHeight)
                    scratchMarker.Visible = true
                    if a1.CueLineBounce then a1.CueLineBounce.Visible = false end
                else
                    setLine(a1.CueLine, Ghost, cueHit, 0.5, AimLineColour)
                    scratchMarker.Visible = false

                    if cueReflect then
                        local cueHit2, cueKind2, cueObj2, _ = castBall(cueHit, cueReflect, BallRadius, 0, balls)
                        local cueBounce = getHelperLine(a1, "CueLineBounce", a1.CueLine, AimLineColour, 0.5)
                        if cueKind2 == "Pocket" then
                            setLine(cueBounce, cueHit, cueHit2, 0.45, COLOR_SCRATCH)
                            scratchMarker.Position = UDim2.fromScale(0.5 + cueObj2.MouthCentre.X / FrameWidth, 0.5 - cueObj2.MouthCentre.Y / FrameHeight)
                            scratchMarker.Visible = true
                        else
                            setLine(cueBounce, cueHit, cueHit2, 0.35, AimLineColour)
                        end
                    elseif a1.CueLineBounce then
                        a1.CueLineBounce.Visible = false
                    end
                end
            else
                a1.CueLine.Visible = false
                if a1.CueLineBounce then a1.CueLineBounce.Visible = false end
            end

            if a1.AimBounce then a1.AimBounce.Visible = false end
            if a1.AimBounce2 then a1.AimBounce2.Visible = false end
            return

        elseif a4.Kind == "Cushion" or a4.Kind == "Tip" then
            -- Kick shot: Tembak langsung ke bantalan
            a1.ObjectLine.Visible = false
            a1.CueLine.Visible = false
            if a1.ObjectLineBounce then a1.ObjectLineBounce.Visible = false end
            if a1.CueLineBounce then a1.CueLineBounce.Visible = false end

            local hit1, kind1, obj1, reflect1 = castBall(a2, Unit, BallRadius, 0, balls)
            if reflect1 then
                local hit2, kind2, obj2, reflect2 = castBall(Ghost, reflect1, BallRadius, 0, balls)
                local aimBounce = getHelperLine(a1, "AimBounce", a1.AimLine, AimLineColour, 0.35)
                if kind2 == "Pocket" then
                    setLine(aimBounce, Ghost, hit2, 0.5, COLOR_SCRATCH)
                    scratchMarker.Position = UDim2.fromScale(0.5 + obj2.MouthCentre.X / FrameWidth, 0.5 - obj2.MouthCentre.Y / FrameHeight)
                    scratchMarker.Visible = true
                else
                    setLine(aimBounce, Ghost, hit2, 0.45, AimLineColour)
                    if reflect2 then
                        local hit3 = castBall(hit2, reflect2, BallRadius, 0, balls)
                        local aimBounce2 = getHelperLine(a1, "AimBounce2", a1.AimLine, AimLineColour, 0.55)
                        setLine(aimBounce2, hit2, hit3, 0.35, AimLineColour)
                    elseif a1.AimBounce2 then
                        a1.AimBounce2.Visible = false
                    end
                end
            elseif a1.AimBounce then
                a1.AimBounce.Visible = false
                if a1.AimBounce2 then a1.AimBounce2.Visible = false end
            end
            return
        end
    end

    a1.AimLine.Visible = false
    a1.Ghost.Visible = false
    a1.ObjectLine.Visible = false
    a1.CueLine.Visible = false
    hideHelpers(a1)
end

-- Auto-hide pas ganti turn
local oldSetGuides = PoolAimOverlay.SetGuidesVisible
PoolAimOverlay.SetGuidesVisible = function(a1, a2)
    oldSetGuides(a1, a2)
    if not a2 then
        hideHelpers(a1)
    end
end

print("[Guideline] v4 PRO HOOK AKTIF! Akurasi Geometri CCD 100%!")

Features & Information

aim assist MADE BY AI

Community Comments (0)

No comments yet for this script.

More Scripts for [NEW] 8 Ball Duels