-- ==================================================================== -- 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%!")